12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199 |
- #!/usr/bin/env python3
- import fileinput
- import io, os, re, datetime
- import hashlib
- import variables
- verbose = False
- #verbose = True
- skipMode = 0
- #skipMode = -1
- verbose_i = 20
- error_counter = 1
- regex_parts = {}
- regex_parts['operator_assign'] = r'=|\+=|-='
- regex_parts['parameter'] = r"\$ARGS\[\d+\]"
- regex_parts['var'] = r"\$?[a-z]+\w*"
- regex_parts['functioncall'] = r"\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\)"
- regex_parts['integer'] = r"\d+"
- regex_parts['string'] = r"""'\w'|"""+ r'''"\w"'''
- regex_parts['value_literal'] = "|".join([regex_parts['integer'],regex_parts['string']])
- regex_parts['value'] = "|".join([regex_parts['parameter'],regex_parts['var'],regex_parts['functioncall'],regex_parts['value_literal'] ])
- regex_parts['statement'] = '?'
- regex_parts['assignment'] = f"\s*({regex_parts['var']})\s*({regex_parts['operator_assign']})\s*({regex_parts['value']})\s*"
- def pv(desc,line):
- if(verbose):
- print(desc.ljust(verbose_i, ' ')+line)
- def convert_calculation(right):
- pv("START CALCULATION:",right)
- brackets_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
- #brackets_regex = r"""(?<![a-zA-Z0-9])(?:min|rand|max|mid)\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
- calculations = []
- #print(right)
- while b_match := re.search(brackets_regex,right):
- complete_match = b_match.group(0)
- calculation_raw = b_match.group(1)
- operator = b_match.group(2)
- if operator == 'mod':
- calculation_raw = calculation_raw.replace('mod','%')
- calculation = convert_literal(calculation_raw)
- index = f"$CALC_HELPER_{len(calculations)}"
- right = right.replace(complete_match,index)
- calculations.append(calculation)
- right = convert_literal(right)
- #function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""
- #while function_name_match := re.search(function_name_regex,right):
- # complete_match = function_name_match.group(0)
- # index = f"$LIT_HELPER_{len(calculations)}"
- # right = right.replace(complete_match,index)
- # calculations.append(complete_match)
- while len(calculations) > 0:
- calculation = calculations.pop()
- index = f"$CALC_HELPER_{len(calculations)}"
- right = right.replace(index,f"({calculation})")
- pv("IS CALCULATION:",right)
- return right
- def convert_command(command_raw):
- command = command_raw.strip()
- #if (command.startswith('<') or and command.endswith('>'):
- # return command
- split_by_and = command.split(' & ')
- if len(split_by_and) > 1:
- return ' '.join([convert_command(s) for s in split_by_and])
- assign_operators = ['=','-=','+=']
- for assign_operator in assign_operators:
- split_by_assign = command.split(assign_operator,1)
- if len(split_by_assign) > 1:
- left = split_by_assign[0]
- if left.startswith('set '):
- left = left[4:]
- right = split_by_assign[1]
- right = convert_calculation(right)
- pv("IS ASSIGNMENT:",right)
- return f'<<set {convert_literal(left)} {assign_operator} {right}>>'
- if match := re.match(r"^(?:set\s*)?(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command):
- return f'<<set {convert_literal(match.group(1))} {match.group(2)} {convert_literal(match.group(3))}>>'
- if match := re.match(r"""^(x?gt|gs)([\s'"].+)$""",command):
- arguments = match.group(2)
- pv('GS OR GT:',command)
- i = 0
- replaces = []
- while brackets_match := re.search(r"""\(([^\(^\)]*?,[^\(^\)]*?)\)""",arguments):
- original = brackets_match.group(1)
- pv("REPLACE:",original)
- indentifier = f'$BRACKET_HELER_{i}'
- arguments = arguments.replace(original,indentifier)
- replaces.append(original)
- i += 1
- arguments = " ".join([convert_literal(l) for l in arguments.split(',')])
- while len(replaces) > 0:
- original = replaces.pop()
- indentifier = f'$BRACKET_HELER_{len(replaces)}'
- arguments = arguments.replace(indentifier,original)
- return f'<<{match.group(1)} {arguments}>>'
- if match := re.match(r"""^msg\s*(.+)$""",command,re.I):
- return f"<<msg {match.group(1)}>>"
- if match := re.match(r"""^dynamic \$(.*)$""",command,re.I):
- arguments = match.group(1).replace(',',' ')
- return f"<<{arguments}>>"
- pv("NO COMMAND MATCH:",command)
- return ''
- def convert_condition(condition_raw):
- condition = condition_raw.strip()
- if(re.match(r"dyneval\(",condition)):
- return condition
- #condition = convert_calculation(condition)
- #print(condition)
- subconditions = []
- bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+)\s*\)"""
- bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*and|or|xor\s*)[^\)^\(]+)\s*\)"""
- while match := re.search(bracket_search_regex,condition):
- fullmatch = match.group(0)
- subcondition = match.group(1)
- subcondition_converted = convert_condition(subcondition)
- subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
- condition = condition.replace(fullmatch,subcondition_ident)
- subconditions.append(subcondition_converted)
- #print(condition)
- if len(subconditions) > 0:
- condition = convert_condition(condition)
- while len(subconditions) > 0:
- subcondition = subconditions.pop()
- subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
- condition = condition.replace(subcondition_ident,f"({subcondition})")
- #print(condition)
- return condition
- split_by_or = condition.split(' or ')
- if len(split_by_or) > 1:
- return ' or '.join([convert_condition(s) for s in split_by_or])
- split_by_xor = condition.split(' xor ')
- if len(split_by_xor) > 1:
- return ' xor '.join([convert_condition(s) for s in split_by_xor])
- split_by_and = condition.split(' and ')
- if len(split_by_and) > 1:
- return ' and '.join([convert_condition(s) for s in split_by_and])
- #match = re.match(r"(\$ARGS\[\d+\]|\$?\w+)\s*([=><]+)\s*('?\w+'?)",condition)
- #match = re.match(r"(\S+)\s*([=><]+)\s*(\S+)",condition)
- if(len(condition) >= 2 and condition[0] == '(' and condition[-1] == ')'):
- condition = condition[1:-1]
- #print(condition)
- match = re.match(r"([^<^>^=^!]+)\s*([=><!]+)\s*([^<^>^=^!]+)",condition)
- if match:
- left = convert_literal(convert_calculation(match.group(1)))
- right = convert_literal(match.group(3))
- operator = match.group(2)
- if operator == '=':
- operator = '=='
- elif operator == '!':
- operator = '!='
- elif operator == '=>':
- operator = '>='
- elif operator == '=<':
- operator = '<='
- return ' '.join([left,operator,right])
- return f'ERROR: FAILED TO CONVERT CONDITION: {condition}'
- def convert_literal(literal_raw):
- literal = literal_raw.strip()
- pv("START LITERAL:",literal)
- if not literal:
- return ''
- subliterals = []
- bracket_search_regex = r"""\[\s*([^\]^\[]+)\s*\]"""
- while match := re.search(bracket_search_regex,literal):
- fullmatch = match.group(0)
- subcondition = match.group(1)
- subcondition_converted = convert_literal(subcondition)
- subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
- literal = literal.replace(fullmatch,subcondition_ident)
- subliterals.append(subcondition_converted)
- #print(condition)
- if len(subliterals) > 0:
- literal = convert_literal(literal)
- while len(subliterals) > 0:
- subcondition = subliterals.pop()
- subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
- literal = literal.replace(subcondition_ident,f"[{subcondition}]")
- #print(condition)
- return literal
- #brackets_regex = r"""\(\s*([^\)^\(]+)\s*\)"""
- #function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""
- #calculations = []
- #while b_match := re.search(brackets_regex,literal):
- # complete_match = b_match.group(0)
- # calculation_raw = b_match.group(1)
- # calculation_parts = calculation_raw.split(',')
- # calculation = ','.join([convert_literal(s) for s in calculation_parts])
- # index = f"$LIT_HELPER_{len(calculations)}"
- # literal = literal.replace(complete_match,index)
- # calculations.append(calculation)
- #while function_name_match := re.search(function_name_regex,literal):
- # complete_match = function_name_match.group(0)
- # index = f"$LIT_HELPER_{len(calculations)}"
- # literal = literal.replace(complete_match,index)
- # calculations.append(complete_match)
- #if len(calculations) > 0:
- # literal = convert_literal(literal)
- # while len(calculations) > 0:
- # calculation = calculations.pop()
- # index = f"$LIT_HELPER_{len(calculations)}"
- # literal = literal.replace(index,f"({calculation})")
- # pv("LITERAL AFTER BRACKETS:",literal)
- if(re.match(r"dyneval\(",literal)):
- return literal
- if literal == "''" or literal == '""':
- return literal
- if(literal.isnumeric() or (literal.startswith('-') and literal[1:].isnumeric())):
- pv("IS NUMERIC",literal)
- return literal
- if(literal.startswith('(') and len(literal) > 1):
- return '('+literal[1:]
- if(literal.endswith(')') and len(literal) > 1):
- return literal[:-1]+')'
- #array_braces = False
- #while match:=re.match(r"\$?([a-z][a-z0-9\-_{}'\+]*)(\['(.*?<<.*?>>'*?)'\])",literal,re.I):
- # value = match.group(3)
- # if not value.startswith("<"):
- # value = value.replace("<<","'+")
- # else:
- # value = value.replace("<<","")#
- #
- # if not value.endswith(">"):
- # value = value.replace(">>","+'")
- # else:
- # value = value.replace(">>","")
- # literal = literal.replace(match.group(2),r"{{"+value+r"}}")
- # array_braces = True
- #if array_braces:
- # literal = literal.replace(r'{{','[').replace(r'}}',']')
- if(len(literal)>= 3 and ((literal[0] == '\'' and literal[-1] == '\'') or (literal[0] == '"' and literal[-1] == '"') )):
- literal = literal.replace('<<','')
- literal = literal.replace('>>','')
- literal = literal.replace("''","'")
- return literal
- if(match := re.match(r"^arrsize\(\s*'(\$?)([a-z]+\w*)'\s*\)$",literal)):
- return f"${match.group(2)}.length"
- if(match := re.match(r"^killvar\s+'(\$?)([a-z]+\w*)'$",literal,re.I)):
- return f"<<set ${match.group(2)} to null>>"
- if(match := re.match(r'^\$ARGS\[(\d+)\]$',literal,re.I)):
- #ARGS
- return f'$location_var[$here][{match.group(1)}]'
- if(match := re.match(r'^\$ARGS(LIT_HELPER_\d+)$',literal,re.I)):
- #ARGS
- return f'$location_var[$here]'+match.group(1)
- if(match := re.match(r"^(\$?)[a-zA-z]+\w*(\[('\w*'|\d+)\])?$",literal)):
- if match.group(1):
- return literal
- return '$'+literal
- if(match := re.match(r"^(\$?)([a-zA-z]+\w*)\[(.+)\]$",literal)):
- #if match.group(1):
- # return f"${match.group(2)}[{convert_literal(match.group(3))}]"
- return f"${match.group(2)}[{convert_literal(match.group(3))}]"
- #print(literal)
- if(match := re.match(r'^(\w+)\s*\((\s*\w+\s*(?:,\s*\w*\s*)*)\)$',literal)):
- function_name = match.group(1)
- function_parameters = match.group(2)
- return f'{function_name}({convert_literal(function_parameters)})'
- while(match := re.search(r'<<(\$\w+)>>',literal)):
- literal = literal.replace(match.group(0),match.group(1))
- #Arithmetic Operations
- arith_operations = ['*','/','-','+','%',',','mod']
- for arith_operation in arith_operations:
- split_by_arith = literal.split(arith_operation)
- if len(split_by_arith) > 1:
- if arith_operation == 'mod':
- arith_operation = '%'
- return f' {arith_operation} '.join([convert_literal(s) for s in split_by_arith])
- if literal.startswith('wait '):
- return f'<<{literal}>>'
- if(match := re.match(r"""^killvar\s+['"]\$?(.*)['"]$""",literal)):
- return f'<<set ${match.group(1)} = 0>>'
- if literal.startswith('jump '):
- jump_san = literal.replace('"','').replace("'","")
- return f"<<warn 'JUMP COMMAND ENCOUNTERED: {jump_san}'>>"
- if literal.startswith(':'):
- return f"<<warn 'JUMP MARKER ENCOUNTERED: {literal}'>>"
- if literal == "'" or literal == '"':
- return ''
- if re.match(r"""^['"\w\s\?\.!\(\)\$]+$""",literal):
- pv("Plain String",literal)
- return literal
- #return literal
- return f'ERROR: FAILED TO CONVERT LITERAL: """{literal}"""'
- function_name_conversions = []
- def convert_lineblock(lines,location_identifier=''):
- outputs = []
- nesting = []
- commenting = False
- isfunction = False
- functionlines = []
- functionlines_temp = []
- function_name = ''
- subpassages = {}
- subpassage = ''
- for line_raw in lines:
- #line_raw = lines[line_num]
- line = line_raw.strip()
- original = line
- pv("START:",line)
- if len(line) == 0:
- continue
- whitespace_count = len(nesting)
- # Subpassages
- if len(subpassage) > 0:
- if line.startswith('~$'):
- endSubpassageName = line[2:]
- gtOrGs = 'gt'
- if endSubpassageName.startswith('gs:'):
- gtOrGs = 'gs'
- endSubpassageName = endSubpassageName[3:]
- if endSubpassageName == subpassage:
- outputs.append( whitespace_count * '\t' + f"<<{gtOrGs} '{subpassage}' $location_var[$here][0] $location_var[$here][1] $location_var[$here][2] $location_var[$here][3] $location_var[$here][4]>>\n")
- subpassage = ''
- continue
- subpassages[subpassage].append(line)
- continue
- if len(subpassage) == 0:
- if line.startswith('~^'):
- startSubpassageName = line[2:]
- subpassage = startSubpassageName
- subpassages[subpassage] = []
- continue
- for preparation in preparations:
- if len(preparation) > 2:
- line = re.sub(preparation[0],preparation[1],line,0,preparation[2])
- else:
- line = re.sub(preparation[0],preparation[1],line)
- line_output = ''
- purges = [
- 'CLOSE ALL',
- 'close all',
- '*clr & cla',
- 'killall',
- 'showstat 0','showstat 1',
- 'showobjs 0','showobjs 1',
- 'showinput 0','showinput 1'
- ]
- for purge in purges:
- line = line.replace(purge,'')
- pv("AFTER PURGES:",line)
- #line = line.replace(" mod "," % ")
- #while match := re.match(r"iif\s*\((.+),(.*),(.*)\)",line):
- # line = line.replace(match.group(0),f"({convert_condition(match.group(1))}) ? {convert_literal(match.group(2))} : {convert_literal(match.group(3))}")
- # FUNCTIONS
- if isfunction:
- if line.endswith('}'):
- isfunction = False
- functionname_sanatized = function_name.replace('$','').replace('[','').replace(']','').replace("'",'')
- functionlines.append(f':: {functionname_sanatized}_macro[widget]\n<<widget "{functionname_sanatized}">>\n')
- functionlines_temp = convert_lineblock(functionlines_temp)
- for fl in functionlines_temp:
- functionlines.append(f'\t{fl}')
- functionlines.append(f'<</widget>>\n')
- function_name_conversions.append([function_name,functionname_sanatized])
- else:
- functionlines_temp.append(line)
- continue
- if match := re.match(r"""(\$[a-z][a-z0-9\-_'"\[\]]+)\s*=\s*{""",line,re.I):
- isfunction = True
- #functionlines.append(f'<<widget "{match.group(1)}">>')
- function_name = match.group(1)
- functionlines_temp = []
- continue
- pv("AFTER FUNCTIONS:",line)
- while fuckyoumatch := re.search(r"""\[["']([^\]]*?)<<(.*?)>>(.*?)["']\]""",line):
- index = f'${fuckyoumatch.group(2)}'
- #left = ''
- if fuckyoumatch.group(1):
- index = f"'{fuckyoumatch.group(1)}'+" + index
- #right = ''
- if fuckyoumatch.group(3):
- index = index + f"+'{fuckyoumatch.group(3)}'"
- # right = fuckyoumatch.group(3)
- #index = f"'{left}'+${fuckyoumatch.group(2)}+'{right}'"
- #print(index)
- line = line.replace(fuckyoumatch.group(0),f"[{index}]")
- #print("MATCH")
- pv("AFTER ARRAY []:",line)
- while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*(<<.*?)'\s*\)""",line):
- fullmatch = dynevalmatch.group(0)
- varname = dynevalmatch.group(1)
- varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
- varname = "State.getVar('$"+varname.replace('<<',"'+").replace('>>',"+'")+"')"
- line = line.replace(fullmatch,varname)
- #print(line)
- pv("AFTER DYNEVAL:",line)
- while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*\$?(.*?)'\s*\)""",line):
- fullmatch = dynevalmatch.group(0)
- varname = "$"+dynevalmatch.group(1)
- varname = varname.replace('<<',"'+").replace('>>',"+'")
- #varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
- varname = varname.replace("['+","[").replace(r"+']",r"]")
- varname = varname.replace('$$',"$")
- line = line.replace(fullmatch,varname)
- pv("AFTER DYNEVAL2:",line)
- if line.startswith('!{') or line.startswith('!!{') or line == '!!{':
- line_output = '<!-- ' + line
- if line.endswith('}'):
- line_output += ' -->'
- else:
- commenting = True
- pv("IS COMMENT:",line_output)
- elif line.endswith('}') and commenting:
- line_output = line+' -->'
- commenting = False
- pv("IS COMMENT:",line_output)
- elif commenting:
- line_output = line.replace('--','-')
- pv("IS COMMENT:",line_output)
- elif line.lower() == 'end' or line.lower().startswith('end &!'):
- whitespace_count -= 1
- if len(nesting) > 0:
- end_command = nesting.pop()
- if end_command == 'if':
- #file.write('<</if>>\n')
- line_output = '<</if>>'
- elif end_command == 'while':
- #file.write('<</while>>\n')
- line_output = '<</while>>'
- elif end_command == 'act':
- #file.write('<</act>>\n')
- line_output = '<</act>>'
- else:
- print(f'ERROR: UNKNOWN NESTRING: {end_command}')
- else:
- line_output = '<</END>>'
- pv("IS END:",line_output)
- elif line.startswith('!'):
- line_output = '<!-- ' + line + '-->'
- pv("IS COMMENT:",line_output)
- elif line.lower() == 'else':
- #file.write('<<else>>\n')
- line_output = '<<else>>'
- whitespace_count -= 1
- pv("IS ELSE:",line_output)
- elif line.lower() == 'cls':
- line_output = ''
- pv("IS CLS:",line_output)
- elif line.lower() == '*nl':
- #file.write('\n')
- line_output = ''
- pv("IS NL:",line_output)
- elif line[0:3] == '---':
- line_output = ''
- pv("IS EOF:",line_output)
- elif match := re.match(r"^\s*msg\s*'(.*)'\s*$",line,re.I):
- msg = match.group(1).replace("'",'"')
- line_output = f"""<<msg '{msg}'>>"""
- pv("IS MSG:",line_output)
- elif match := re.match(r"""act\s*'(.*?)\s*\(<font color="red"><<will_cost>> Willpower</font>\)':\s*'<br><font color="red">You don''t have enough willpower to use this action.</font>'""",line,re.I):
- label = match.group(1).replace("'",'"')
- line_output = f"<<act `'{label} ('+$will_cost+')'`>><font color=red><br/>You don`t have enough willpower to use this action.</font><</act>>"
- elif match := re.match(r"""^'(?:<center>)?<img\s+(?:<<\$?\w+>>\s+)src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/center>)?'""",line,re.I):
- #Images
- if match.group(2):
- line_output = f'''<<image "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
- else:
- line_output = f'''<<image "{match.group(1)}{match.group(3)}">>'''
- pv("IS IMAGE:",line_output)
- elif match := re.match(r"""^'?(?:<center>)?<video\s+(?:<<\$?\w+>>\s+)*(?:\s*autoplay\s*|\s*loop\s*)*src="images\/([\w\/\.]+)(?:'\s*\+\s*rand\((\d+,\d+)\)\s*\+\s*')?([\w\/\.]+)"\s*>(?:<\/video>)?(?:<\/center>)?'?""",line,re.I):
- #Images
- if match.group(2):
- line_output = f'''<<video "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
- else:
- line_output = f'''<<video "{match.group(1)}{match.group(3)}">>'''
- pv("IS VIDEO:",line_output)
- elif line.startswith('<') and line.endswith('>'):
- line_output = line
- pv("IS HTML:",line_output)
- elif line.startswith("'<") and line.endswith(">'"):
- line_output = line[1:-1]
- pv("IS COMMENTED HTML:",line_output)
- elif match := re.match(r"""^'[\w<>\s=:'"\/\.\(\),\*]+'$""",line):
- #Plain HTML
- line_output = line[1:-1]
- if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",line_output):
- #line_output = #line_output.replace(link_match[0],"moep")
- #print("moep")
- #print(link_match)
- for lmatch in link_match:
- line_output = line_output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
- pv("IS PLAIN HTML:",line_output)
- elif match := re.match(r"^\s*(if|while)\s+([^:]+):(.*)",line,re.I):
- command = match.group(1).lower()
- line_w = f'<<{command} {convert_condition(match.group(2))}>>'
- if match.group(3):
- #if com := convert_command(match.group(3)):
- # line_w += '\n' + (whitespace_count+1) * '\t' + com
- #else:
- # line_w += '\n' + (whitespace_count+1) * '\t' + convert_literal(match.group(3))
- converted = convert_lineblock([match.group(3)])
- if len(converted)>0 and converted[0]:
- line_w += '\n' + (whitespace_count+1) * '\t' + converted[0]
- line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
- else:
- nesting.append(command)
- #file.write(line_w)
- line_output = line_w
- pv("IS IF:",line_output)
- elif match := re.match(r"\s*(act)\s*(.+):(.*)",line,re.I):
- # Act-Command
- command = match.group(1).lower()
- line_w = f'<<{command} {convert_literal(match.group(2))}>>'
- if match.group(3):
- line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
- line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
- else:
- nesting.append(command)
- #file.write(line_w)
- line_output = line_w
- pv("IS ACT:",line_output)
- elif match := re.match(r"\s*(elseif)\s+([^:]+):(.*)",line,re.I):
- # ElseIf
- command = match.group(1).lower()
- line_w = f'<<{command} {convert_condition(match.group(2))}>>'
- whitespace_count -= 1
- if match.group(3):
- #line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
- line_w += '\n' + whitespace_count * '\t'+f'<</if>>'
- #nesting.pop()
- #file.write(line_w)
- line_output = line_w
- pv("IS ELSEIF:",line_output)
- #elif match := re.match(r"^dynamic\s+'(.*)'$",line,re.I):
- # out = match.group(1).replace('<<',"'+").replace('>>',"+'")
- # line_output = f"<<dynamic {out}>>"
- elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
- left = match.group(1)
- right = match.group(3)
- operator = match.group(2)
- left = left.replace(r"[''",r"['").replace(r"'']",r"']")
- left = left.replace(r"['+",r"[").replace(r"+']",r"]")
- left = left.replace('<<',"'+").replace('>>',"+'")
- left = left.replace('$$',"$")
- right = right.replace(r"[''",r"['").replace(r"'']",r"']")
- right = right.replace(r"['+",r"[").replace(r"+']",r"]")
- right = right.replace('<<',"").replace('>>',"")
- right = right.replace('$$',"$")
- right = convert_literal(right)
- line_output = f'<<set {left} {operator} {right}>>'
- pv("IS DYNAMIC:",line_output)
- #elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
- elif match := re.match(r"^dynamic\s*\$([a-zA-Z]\w+)$",line,re.I):
- line_output = f'<<{match.group(1)}>>'
- elif match := re.match(r"""^([^\$])*<a\s+href\s*=\s*"exec:\s*(?:minut\s*\+=\s*(\d+)\s*&\s*)?gt(.*)?"\s*>(.*?)</a>.*$""",line,re.I):
- while link_match := re.search(r"""<a\s+href\s*=\s*"exec:\s*(?:minut\s*\+=\s*(\d+)\s*&\s*)?gt(.*)?"\s*>(.*?)</a>""",line,re.I):
- full_match = link_match.group(0)
- time = ""
- if link_match.group(1):
- time = f"<<set $minut += {link_match.group(1)}>>"
- goto = link_match.group(2)
- goto = goto.replace(","," ").replace(r"''",r"'")
- label = link_match.group(3)
- link = f"<<link '{label}'>>{time}<<gt {goto}>><</link>>"
- line = line.replace(full_match,link)
- line_output = line
- elif match := convert_command(line):
- line_output = match
- pv("IS COMMAND:",line_output)
- else:
- line_output = convert_literal(line)
- if len(line_output) >= 2 and line_output[0] == '\'' and line_output[-1] == '\'':
- line_output = f'<p>{line_output[1:-1]}</p>'
- pv("IS LITERAL:",line_output)
- whitespace = whitespace_count * '\t'
- output = f'{whitespace}{line_output}\n'
- if output.strip():
- #file.write(cleanUpTheMess(output))
- output = cleanUpTheMess(output)
- if "ERROR:" in output:
- global error_counter
- output = f'{whitespace}<!-- FAILED TO CONVERT\n{whitespace}\t{original}\n{whitespace}-----\n\t{output}\n{whitespace}-->\n{whitespace}<<warn "CONVERSION ERROR {(hashlib.md5(original.encode())).hexdigest()}">>\n'
- error_counter += 1
- outputs.append(output)
- for subpassId in subpassages:
- subpass = subpassages[subpassId]
- subpassageLines = convert_lineblock(subpass)
- outputs.append(f'\n:: {subpassId}\n')
- for subpassageLine in subpassageLines:
- outputs.append(subpassageLine)
- if len(functionlines) > 0:
- #outputs.append(f'::{location_identifier}_widgets[widget]\n')
- for functionline in functionlines:
- functionline = functionline.replace('$ARGS','_args').replace('$location_var[$here][','_args[')
- outputs.append(functionline)
- return outputs
- def convert_file(filename,skipIfNotExplicit=0,defaultsubfolder=False):
- skip = skipIfNotExplicit
- qsp_filename = filename+".qsrc"
- qsp_filepath = os.path.join(qsp_sources_path,qsp_filename)
- tw_filename = filename+".tw"
- tw_filepath = os.path.join(tw_sources_path,tw_filename)
- if defaultsubfolder:
- os.makedirs(os.path.join(tw_sources_path,defaultsubfolder),exist_ok =True)
- tw_filepath = os.path.join(tw_sources_path,defaultsubfolder,tw_filename)
- try:
- with open(qsp_filepath) as file:
- lines = [line.rstrip() for line in file]
- except:
- try:
- with open(qsp_filepath, encoding="utf-8") as file:
- lines = [line.rstrip() for line in file]
- except:
- return f"FAILED: {qsp_filename}"
- location_identifier = ''
- ignore_recusions = 0
- if match := re.match(r"^\s*!!\s*(FOLDER\s*:\s*\w+)?\s*(SKIP\s*:\s*-?\d)?\s*(IGNORERECURSIONS\s*:\s*-?\d)?\s*$",lines[0],re.I):
- if match.group(1):
- parts = match.group(1).split(':')
- new_path = os.path.join(tw_sources_path,parts[1].strip())
- os.makedirs(new_path,exist_ok =True)
- tw_filepath = os.path.join(new_path,tw_filename)
- if match.group(2):
- parts = match.group(2).split(':')
- arg = int(parts[1])
- if arg == 1:
- skip = 1
- elif arg == 0:
- skip = 0
- elif arg == -1:
- skip = -1
- if match.group(3):
- parts = match.group(3).split(':')
- arg = int(parts[1])
- if arg == 1:
- ignore_recusions = 1
- elif arg == 0:
- ignore_recusions = 0
- if skip == 1:
- return
- if skip == -1 and os.path.exists(tw_filepath):
- modification_time_delta = os.path.getmtime(qsp_filepath) - os.path.getmtime(tw_filepath)
- if modification_time_delta <= 0:
- return
- identifier_line = 0
- for line_num in range(0,len(lines)-1):
- line_raw = lines[line_num]
- line = line_raw.strip()
- match = re.match(r"#\s*(\S+)", line)
- if match:
- location_identifier = match.group(1)
- identifier_line = line_num
- break
- with open(tw_filepath, 'w') as file:
- #file.write(f'<!-- GENERATED: {datetime.datetime.now()} -->\n')
- file.write(f':: {location_identifier}\n')
- file.write(f"<<set $here = '{location_identifier}'>>\n<<set $ARGS = $location_var[$here]>>\n")
- if ignore_recusions == 1:
- file.write(f'<<set _ts to Math.floor(Date.now() / 10000)>>\n')
- file.write(f'<<setinit $gt_history[_ts][$here] = 0>>\n')
- #for line_num in range(identifier_line+1,len(lines)-1):
- outputs = convert_lineblock(lines[identifier_line+1:],location_identifier)
- for output in outputs:
- file.write(output)
- with open(tw_filepath, 'r') as file:
- data = file.read()
- with open(tw_filepath, 'w') as file:
- regex1 = r"""<<gs 'willpower' ([\s'\w]*)>>\s*<<if \$will_cost <= \$pc\.pcs_willpwr>>\s*<<act '([\w\s]*?)\s*\(will_cost Willpower\)'>>"""
- while match := re.search(regex1,data,re.I):
- blockStart = match.end()
- regex_close = r"""<<else>>\s*<<act `?'"""+match.group(2)+r""".*?<</act>>\s*<</if>>"""
- if close_match := re.search(regex_close,data,re.I):
- blockEnd = close_match.start()
- block = data[blockStart:blockEnd]
- # Remove the re-calculation of the willpower-cost
- newBlock = block
- newBlock = newBlock.replace("<<gs 'willpower' "+match.group(1)+">>",'')
- newBlock = re.sub(r"""<<gs 'willpower' 'pay' ([\s'\w]*)>>""","",newBlock)
- data = data.replace(block,newBlock)
- data = data.replace(close_match.group(0),"")
- arguments = match.group(1).replace(' ',',')
- data = data.replace(match.group(0),"<<act '"+match.group(2)+"' `{willpower:["+arguments+"]}`>>")
- else:
- print("FAIL: "+match.group(0))
- break
- file.write(data)
- print(f"Completed {filename}")
- return tw_filepath
- FTCL = [r'ERROR: FAILED TO CONVERT LITERAL:\s*"""',r'"""']
- VAR = r"""\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)"""
- preparations = [
- [
- r"""\$week\[""",
- r"$week_name["
- ],
- [
- r"""pcs_pubecol\[""",
- r"pcs_pubecol_num["
- ],
- [
- r"""pcs_pubes\[""",
- r"pcs_pubes_num["
- ],
- [
- r"""^PLAY\s*.*""",
- r""
- ],
- [
- r"""^\s*pl\s+(.*)$""",
- r"\1"
- ]
- #[
- # r"""(</?(?:table|center|th|tr|td))([^>]*=[^>]*)(>)""",
- # r'\1\3',
- # re.I
- #]
- ]
- replaces = [
- [
- r"ERROR: FAILED TO CONVERT CONDITION: func\(",
- r"func("
- ],
- [
- r"ERROR: FAILED TO CONVERT CONDITION: \$?([a-zA-Z])",
- r"$\1"
- ],
- [
- FTCL[0]+r"killvar\s*'"+VAR+r"'"+FTCL[1],
- r"<<set $\1 to undefined>>"
- ],
- [
- r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"\)\(),\s]+]*)>>)?(\.[^"]+)">""",
- r"<<image `'\2\3\5'`>>"
- ],
- [
- r"""'([\w\/]+)<<\s*rand\s*\(\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)\s*>>([^']*)'""",
- r"""'\1'+rand(\2,\3)+'\4'"""
- ],
- [
- r"""<<set \$?([a-zA-Z][a-zA-Z0-9-_'"]+]*\[.*)>>""",
- r"""<<setinit $\1>>"""
- ],
- [
- # <<set $gopnikbandQW += -1>> -> <<setn $gopnikbandQW += -1>>
- r"""<<set (\$[^>]*?)\s([+-]=)\s*(-?\d+)>>""",
- r"""<<setn \1 \2 \3>>""",
- 1
- ],
- [
- # asd
- r"""<<set (\$[^>]*?)\s(\+=)\s*(["'][^>]*?)>>""",
- r"""<<sets \1 \2 \3>>""",
- 1
- ],
- [
- r"""(\+)\s+=""",
- r"""\1="""
- ],
- [
- r"(I|you|You|he|He|she|She|it|It|we|We|they|They|can|Can|don|Don)''(m|re|s|ll|ve|t)",
- r"\1'\2"
- ],
- #[
- # r"^(.*"+FTCL[0]+r"(.*)"+FTCL[1]+r".*)$",
- # r"<!-- \1 -->\n<<warn 'FTCL: \1'>>"
- #],
- [
- r"=\s*\$(mid|MID)\s*\(",
- r"= mid("
- ],
- [
- r"(<<set\s*.*?\[)([a-zA-Z].*?)(\]\s*=.*>>)",
- r"\1$\2\3"
- ],
- [
- r"(<<act\s*'.*)(\$.*?\])(.*'>>)",
- r"\1'+\2+'\3"
- ],
- [
- r"\[([a-zA-Z]\w*)\]",
- r"[$\1]"
- ],
- [
- r"([\+\-])\s+=",
- r"\1="
- ],
- [
- r"<<setinit\s*(.*)\[\]\s*=\s*(.*)>>",
- r"""<<setinitpush "\1" \2>>"""
- ],
- [
- r"\s+min\(",
- r" Math.min("
- ],
- [
- r"\s+max\(",
- r" Math.max("
- ],
- [
- r"""<<set (.*) to null>>\s*,\s*(.*)(\s*)""",
- r"<<set \1[\2] to null>>\3"
- ]
- ,
- [
- r"""\$arrsize\(""",
- r"arrsize("
- ],
- [
- r"""<<set(?:init)?\s+\$?(?P<name>\w+)\[arrsize\('\$?(?P=name)'\)\]\s*=\s*(.*)\s*>>""",
- r"<<run $\1.push(\2)>>"
- ],
- [
- r"""<center><(?:h\d|b)><font color="maroon">(.*)</font></(?:h\d|b)></center>""",
- r"<h2>\1</h2>"
- ],
- [
- r"""(<<act '[^']*)'([^']*'>>)""",
- r"\1`\2"
- ],
- # NPC-Stuff Start
- [
- r"""\$npc_(\w*?)\[([^\]]*?)\]""",
- r"$npcs.get(\2,'\1')",
- 1
- ],
- # Fix for Sub-Arrays
- [
- r"""\$npcs\.get\((.*?),('\w*')\)(\[[^\]]*\]+?)\]""",
- r"$npcs.get(\1]\3,\2)",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*=\s*(.*?)>>""",
- r"<<run $npcs.set(\1,\2)>>",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*\+=\s*(.*?)>>""",
- r"<<run $npcs.inc(\1,\2)>>",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*-=\s*(.*?)>>""",
- r"<<run $npcs.dec(\1,\2)>>",
- 1
- ],
- # NPC-Stuff END
- [
- r"""(\$\w+(?:\['\w+'\])?)\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
- r"""getvar("\1") \2 \3""",
- 1
- ],
- [
- #Example: $property_construction_status[$i] == 0 -> getvar("$property_construction_status["+$i+"]") == 0
- r"""(\$\w+)(?:\[(\$\w+)\])\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
- r"""getvar("\1["+\2+"]") \3 \4""",
- 1
- ],
- [
- r"""\*?\s*\$\s*cl[ar]\s*$""",
- r""
- ],
- [
- r"""<<gs 'clothing' 'wear'\s*(.*?)\s+(.*?)>>""",
- r"<<run $wardrobe.wear_clothes_legacy('clothes',\1,\2)>>"
- ],
- [
- r"""<<gs 'shoes' 'wear'\s+(.*?)\s+(.*?)>>""",
- r"<<run $wardrobe.wear('shoes',\1,\2)>>"
- ],
- [
- r"""<<gs\s+'shoes'\s+'wear'\s+'last_worn'\s*>>""",
- r"<<run $wardrobe.wear_last('shoes')>>"
- ],
- [
- r"""<<gs\s+'bras'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
- r"<<run $wardrobe.wear('bra',\1,\2)>>"
- ],
- [
- r"""<<gs\s+'panties'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
- r"<<run $wardrobe.wear('panties',\1,\2)>>"
- ],
- [
- r"""<<gs\s+'coats'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
- r"<<run $wardrobe.wear('coat',\1,\2)>>"
- ],
- [
- r"""<<gs\s+'bras'\s+'wear'\s*>>""",
- r"<<run $wardrobe.wear_last('bra')>>"
- ],
- [
- r"""<<gs\s+'panties'\s+'wear'\s*>>""",
- r"<<run $wardrobe.wear_last('panties')>>"
- ],
- [
- r"""iif\(([^)]*?)\s*==?\s*'',""",
- r"iif(!\1,",
- 1
- ],
- # Rand in gs Fix
- [
- r"""<<g([st].*?)\srand\((.*?)\)(.*?)>>""",
- r"<<g\1 `rand(\2)`\3>>",
- 1
- ],
- # Pain
- [
- r"""(<<(?:else)?if\s+|and\s+|x?or\s+)(?:getvar\(")\$pain\[('\w+')\](?:"\))(.*?>>)""",
- r"\1$pc.pain(\2)\3",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*\+=\s*(.*?)>>""",
- r"<<run $pc.painInc(\1,\2)>>",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*-=\s*(.*?)>>""",
- r"<<run $pc.painDec(\1,\2)>>",
- 1
- ],
- [
- r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*=\s*(.*?)>>""",
- r"<<run $pc.painSet(\1,\2)>>",
- 1
- ],
- #Cum
- [
- r"""\$cumloc\[(\d+)\]""",
- r"$pc.cumAtLocation(\1)",
- 1
- ],
- ]
- purge_messes=[
- r"""<<set(init)? \$npc_selfie\[""",
- r'''<<set(init)? \$npcGo\[''', # We need to replace this by another function,
- r'''<<set(init)? \$npcGoSchool\['''
- ]
- def cleanUpTheMess(output):
- for purge_mess in purge_messes:
- if match := re.search(purge_mess,output):
- return ''
- for replace in replaces:
- if len(replace) > 2:
- if replace[2] == 1:
- while(re.search(replace[0],output)):
- output = re.sub(replace[0],replace[1],output)
- else:
- output = re.sub(replace[0],replace[1],output)
- if warnmatch := re.search(r"""<<warn '(.*)'>>""",output):
- return output.replace(warnmatch.group(1),warnmatch.group(1).replace("'",'"'))
- if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",output):
- for lmatch in link_match:
- output = output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
- output = re.sub(r"""\$result""","$result",output,0,re.I)
- while image_match := re.match(r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)>>)?\.[^"]+">""",output):
- if len(image_match.group(3)) == 0:
- break
- output = output.replace(image_match.group(3),f'"+${image_match.group(4)}+"')
- while match := re.search(r"""<<set(?:init)?[^=]+=\s*'([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+)('([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+))+'>>""",output):
- output = output.replace(match.group(2),f"`{match.group(3)}")
- # NPCs: add print to all get-calls which are not inside a macro
- if(not output.strip().startswith('<<')):
- output = re.sub(r"(?<!=)(\$npcs\.get\(.*?\))",r"<<=\1>>",output)
- for variable_replacement in variables.variable_replacements:
- if len(variable_replacement) > 2:
- if variable_replacement[2] == 1:
- output = re.sub(variable_replacement[0],variable_replacement[1],output)
- else:
- output = output.replace(variable_replacement[0],variable_replacement[1])
- else:
- output = output.replace(variable_replacement[0],variable_replacement[1])
- output = output.replace("$location_var[$here][0] == ''","!$location_var[$here][0]")
- return output
- test_line = ''
- #test_line = """gs 'npc_relationship', 'socialgroup_setting', 0, 0, -10, 10, -10, -10"""
- if len(test_line) > 0:
- verbose = True
- print(test_line)
- result = convert_lineblock([test_line])
- if len(result) > 0:
- print(result[0])
- else:
- print("EMPTY RESULT")
- exit()
- qsp_sources_path = "locations"
- tw_sources_path = os.path.join("sugarcube","src","autogenerated")
- output_files = []
- os.makedirs(tw_sources_path, exist_ok=True)
- #for replace in replaces:
- # print(replace[0])
- restrictfiles = []
- #restrictfiles = ['LakeBoyDy']
- for file in os.listdir(qsp_sources_path):
- if len(restrictfiles) == 0 or (os.path.splitext(file)[0] in restrictfiles):
- if file.endswith(".qsrc"):
- output_files.append(convert_file(os.path.splitext(file)[0],skipMode,'unsorted'))
- print(len(function_name_conversions))
- #for output_file in output_files:
- # for line in fileinput.input(output_file, inplace=True):
- #
- # for function_name_conversion in function_name_conversions:
- #
- #
- # if fileinput.filelineno() == 10:
- # print(('10'+line), end='')
- # break
|