4
1

qrsc_to_tw.py 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. #!/usr/bin/env python3
  2. import fileinput
  3. import io, os, re, datetime
  4. import hashlib
  5. import variables
  6. import time
  7. from concurrent.futures import ThreadPoolExecutor
  8. from concurrent.futures import as_completed
  9. qsp_sources_path = "locations"
  10. tw_sources_path = os.path.join("sugarcube","src","autogenerated")
  11. verbose = False
  12. #verbose = True
  13. skipMode = 0
  14. #skipMode = -1
  15. verbose_i = 20
  16. error_counter = 1
  17. regex_parts = {}
  18. regex_parts['operator_assign'] = r'=|\+=|-='
  19. regex_parts['parameter'] = r"\$ARGS\[\d+\]"
  20. regex_parts['var'] = r"\$?[a-z]+\w*"
  21. regex_parts['functioncall'] = r"\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\)"
  22. regex_parts['integer'] = r"\d+"
  23. regex_parts['string'] = r"""'\w'|"""+ r'''"\w"'''
  24. regex_parts['value_literal'] = "|".join([regex_parts['integer'],regex_parts['string']])
  25. regex_parts['value'] = "|".join([regex_parts['parameter'],regex_parts['var'],regex_parts['functioncall'],regex_parts['value_literal'] ])
  26. regex_parts['statement'] = '?'
  27. regex_parts['assignment'] = f"\s*({regex_parts['var']})\s*({regex_parts['operator_assign']})\s*({regex_parts['value']})\s*"
  28. def pv(desc,line):
  29. if(verbose):
  30. print(desc.ljust(verbose_i, ' ')+line)
  31. def convert_calculation(right):
  32. pv("START CALCULATION:",right)
  33. brackets_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
  34. #brackets_regex = r"""(?<![a-zA-Z0-9])(?:min|rand|max|mid)\(\s*([^\)^\(]+(\s*\-|mod|\+|/|\*\s*)[^\)^\(]+)\s*\)"""
  35. calculations = []
  36. #print(right)
  37. while b_match := re.search(brackets_regex,right):
  38. complete_match = b_match.group(0)
  39. calculation_raw = b_match.group(1)
  40. operator = b_match.group(2)
  41. if operator == 'mod':
  42. calculation_raw = calculation_raw.replace('mod','%')
  43. calculation = convert_literal(calculation_raw)
  44. index = f"$CALC_HELPER_{len(calculations)}"
  45. right = right.replace(complete_match,index)
  46. calculations.append(calculation)
  47. right = convert_literal(right)
  48. #function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""
  49. #while function_name_match := re.search(function_name_regex,right):
  50. # complete_match = function_name_match.group(0)
  51. # index = f"$LIT_HELPER_{len(calculations)}"
  52. # right = right.replace(complete_match,index)
  53. # calculations.append(complete_match)
  54. while len(calculations) > 0:
  55. calculation = calculations.pop()
  56. index = f"$CALC_HELPER_{len(calculations)}"
  57. right = right.replace(index,f"({calculation})")
  58. pv("IS CALCULATION:",right)
  59. return right
  60. def convert_command(command_raw):
  61. command = command_raw.strip()
  62. #if (command.startswith('<') or and command.endswith('>'):
  63. # return command
  64. split_by_and = command.split(' & ')
  65. if len(split_by_and) > 1:
  66. return ' '.join([convert_command(s) for s in split_by_and])
  67. assign_operators = ['=','-=','+=']
  68. for assign_operator in assign_operators:
  69. split_by_assign = command.split(assign_operator,1)
  70. if len(split_by_assign) > 1:
  71. left = split_by_assign[0]
  72. if left.startswith('set '):
  73. left = left[4:]
  74. right = split_by_assign[1]
  75. right = convert_calculation(right)
  76. pv("IS ASSIGNMENT:",right)
  77. return f'<<set {convert_literal(left)} {assign_operator} {right}>>'
  78. if match := re.match(r"^(?:set\s*)?(\$?\w+)\s*(\+=|-=|=)\s*([\$']?\w*'?|\w+\s*\(\s*\w+\s*(?:,\s*\w*\s*)*\))$",command):
  79. return f'<<set {convert_literal(match.group(1))} {match.group(2)} {convert_literal(match.group(3))}>>'
  80. if match := re.match(r"""^(x?gt|gs)([\s'"].+)$""",command):
  81. arguments = match.group(2)
  82. pv('GS OR GT:',command)
  83. i = 0
  84. replaces = []
  85. while brackets_match := re.search(r"""\(([^\(^\)]*?,[^\(^\)]*?)\)""",arguments):
  86. original = brackets_match.group(1)
  87. pv("REPLACE:",original)
  88. indentifier = f'$BRACKET_HELER_{i}'
  89. arguments = arguments.replace(original,indentifier)
  90. replaces.append(original)
  91. i += 1
  92. arguments = " ".join([convert_literal(l) for l in arguments.split(',')])
  93. while len(replaces) > 0:
  94. original = replaces.pop()
  95. indentifier = f'$BRACKET_HELER_{len(replaces)}'
  96. arguments = arguments.replace(indentifier,original)
  97. return f'<<{match.group(1)} {arguments}>>'
  98. if match := re.match(r"""^msg\s*(.+)$""",command,re.I):
  99. return f"<<msg {match.group(1)}>>"
  100. if match := re.match(r"""^dynamic \$(.*)$""",command,re.I):
  101. arguments = match.group(1).replace(',',' ')
  102. return f"<<{arguments}>>"
  103. pv("NO COMMAND MATCH:",command)
  104. return ''
  105. def convert_condition(condition_raw):
  106. condition = condition_raw.strip()
  107. if(re.match(r"dyneval\(",condition)):
  108. return condition
  109. #condition = convert_calculation(condition)
  110. #print(condition)
  111. subconditions = []
  112. bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+)\s*\)"""
  113. bracket_search_regex = r"""(?<![a-zA-Z0-9])\(\s*([^\)^\(]+(\s*and|or|xor\s*)[^\)^\(]+)\s*\)"""
  114. while match := re.search(bracket_search_regex,condition):
  115. fullmatch = match.group(0)
  116. subcondition = match.group(1)
  117. subcondition_converted = convert_condition(subcondition)
  118. subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
  119. condition = condition.replace(fullmatch,subcondition_ident)
  120. subconditions.append(subcondition_converted)
  121. #print(condition)
  122. if len(subconditions) > 0:
  123. condition = convert_condition(condition)
  124. while len(subconditions) > 0:
  125. subcondition = subconditions.pop()
  126. subcondition_ident = f"$CON_HELPER_{len(subconditions)} == 1"
  127. condition = condition.replace(subcondition_ident,f"({subcondition})")
  128. #print(condition)
  129. return condition
  130. split_by_or = condition.split(' or ')
  131. if len(split_by_or) > 1:
  132. return ' or '.join([convert_condition(s) for s in split_by_or])
  133. split_by_xor = condition.split(' xor ')
  134. if len(split_by_xor) > 1:
  135. return ' xor '.join([convert_condition(s) for s in split_by_xor])
  136. split_by_and = condition.split(' and ')
  137. if len(split_by_and) > 1:
  138. return ' and '.join([convert_condition(s) for s in split_by_and])
  139. #match = re.match(r"(\$ARGS\[\d+\]|\$?\w+)\s*([=><]+)\s*('?\w+'?)",condition)
  140. #match = re.match(r"(\S+)\s*([=><]+)\s*(\S+)",condition)
  141. if(len(condition) >= 2 and condition[0] == '(' and condition[-1] == ')'):
  142. condition = condition[1:-1]
  143. #print(condition)
  144. match = re.match(r"([^<^>^=^!]+)\s*([=><!]+)\s*([^<^>^=^!]+)",condition)
  145. if match:
  146. left = convert_literal(convert_calculation(match.group(1)))
  147. right = convert_literal(match.group(3))
  148. operator = match.group(2)
  149. if operator == '=':
  150. operator = '=='
  151. elif operator == '!':
  152. operator = '!='
  153. elif operator == '=>':
  154. operator = '>='
  155. elif operator == '=<':
  156. operator = '<='
  157. return ' '.join([left,operator,right])
  158. return f'ERROR: FAILED TO CONVERT CONDITION: {condition}'
  159. def convert_literal(literal_raw):
  160. literal = literal_raw.strip()
  161. pv("START LITERAL:",literal)
  162. if not literal:
  163. return ''
  164. subliterals = []
  165. bracket_search_regex = r"""\[\s*([^\]^\[]+)\s*\]"""
  166. while match := re.search(bracket_search_regex,literal):
  167. fullmatch = match.group(0)
  168. subcondition = match.group(1)
  169. subcondition_converted = convert_literal(subcondition)
  170. subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
  171. literal = literal.replace(fullmatch,subcondition_ident)
  172. subliterals.append(subcondition_converted)
  173. #print(condition)
  174. if len(subliterals) > 0:
  175. literal = convert_literal(literal)
  176. while len(subliterals) > 0:
  177. subcondition = subliterals.pop()
  178. subcondition_ident = f"LIT_HELPER_{len(subliterals)}"
  179. literal = literal.replace(subcondition_ident,f"[{subcondition}]")
  180. #print(condition)
  181. return literal
  182. #brackets_regex = r"""\(\s*([^\)^\(]+)\s*\)"""
  183. #function_name_regex = r"""(?<![a-zA-Z0-9])(min|rand|mid|max)\s*\$LIT_HELPER_(0)"""
  184. #calculations = []
  185. #while b_match := re.search(brackets_regex,literal):
  186. # complete_match = b_match.group(0)
  187. # calculation_raw = b_match.group(1)
  188. # calculation_parts = calculation_raw.split(',')
  189. # calculation = ','.join([convert_literal(s) for s in calculation_parts])
  190. # index = f"$LIT_HELPER_{len(calculations)}"
  191. # literal = literal.replace(complete_match,index)
  192. # calculations.append(calculation)
  193. #while function_name_match := re.search(function_name_regex,literal):
  194. # complete_match = function_name_match.group(0)
  195. # index = f"$LIT_HELPER_{len(calculations)}"
  196. # literal = literal.replace(complete_match,index)
  197. # calculations.append(complete_match)
  198. #if len(calculations) > 0:
  199. # literal = convert_literal(literal)
  200. # while len(calculations) > 0:
  201. # calculation = calculations.pop()
  202. # index = f"$LIT_HELPER_{len(calculations)}"
  203. # literal = literal.replace(index,f"({calculation})")
  204. # pv("LITERAL AFTER BRACKETS:",literal)
  205. if(re.match(r"dyneval\(",literal)):
  206. return literal
  207. if literal == "''" or literal == '""':
  208. return literal
  209. if(literal.isnumeric() or (literal.startswith('-') and literal[1:].isnumeric())):
  210. pv("IS NUMERIC",literal)
  211. return literal
  212. if(literal.startswith('(') and len(literal) > 1):
  213. return '('+literal[1:]
  214. if(literal.endswith(')') and len(literal) > 1):
  215. return literal[:-1]+')'
  216. #array_braces = False
  217. #while match:=re.match(r"\$?([a-z][a-z0-9\-_{}'\+]*)(\['(.*?<<.*?>>'*?)'\])",literal,re.I):
  218. # value = match.group(3)
  219. # if not value.startswith("<"):
  220. # value = value.replace("<<","'+")
  221. # else:
  222. # value = value.replace("<<","")#
  223. #
  224. # if not value.endswith(">"):
  225. # value = value.replace(">>","+'")
  226. # else:
  227. # value = value.replace(">>","")
  228. # literal = literal.replace(match.group(2),r"{{"+value+r"}}")
  229. # array_braces = True
  230. #if array_braces:
  231. # literal = literal.replace(r'{{','[').replace(r'}}',']')
  232. if(len(literal)>= 3 and ((literal[0] == '\'' and literal[-1] == '\'') or (literal[0] == '"' and literal[-1] == '"') )):
  233. literal = literal.replace('<<','')
  234. literal = literal.replace('>>','')
  235. literal = literal.replace("''","'")
  236. return literal
  237. if(match := re.match(r"^arrsize\(\s*'(\$?)([a-z]+\w*)'\s*\)$",literal)):
  238. return f"${match.group(2)}.length"
  239. if(match := re.match(r"^killvar\s+'(\$?)([a-z]+\w*)'$",literal,re.I)):
  240. return f"<<set ${match.group(2)} to null>>"
  241. if(match := re.match(r'^\$ARGS\[(\d+)\]$',literal,re.I)):
  242. #ARGS
  243. return f'$location_var[$here][{match.group(1)}]'
  244. if(match := re.match(r'^\$ARGS(LIT_HELPER_\d+)$',literal,re.I)):
  245. #ARGS
  246. return f'$location_var[$here]'+match.group(1)
  247. if(match := re.match(r"^(\$?)[a-zA-z]+\w*(\[('\w*'|\d+)\])?$",literal)):
  248. if match.group(1):
  249. return literal
  250. return '$'+literal
  251. if(match := re.match(r"^(\$?)([a-zA-z]+\w*)\[(.+)\]$",literal)):
  252. #if match.group(1):
  253. # return f"${match.group(2)}[{convert_literal(match.group(3))}]"
  254. return f"${match.group(2)}[{convert_literal(match.group(3))}]"
  255. #print(literal)
  256. if(match := re.match(r'^(\w+)\s*\((\s*\w+\s*(?:,\s*\w*\s*)*)\)$',literal)):
  257. function_name = match.group(1)
  258. function_parameters = match.group(2)
  259. return f'{function_name}({convert_literal(function_parameters)})'
  260. while(match := re.search(r'<<(\$\w+)>>',literal)):
  261. literal = literal.replace(match.group(0),match.group(1))
  262. #Arithmetic Operations
  263. arith_operations = ['*','/','-','+','%',',','mod']
  264. for arith_operation in arith_operations:
  265. split_by_arith = literal.split(arith_operation)
  266. if len(split_by_arith) > 1:
  267. if arith_operation == 'mod':
  268. arith_operation = '%'
  269. return f' {arith_operation} '.join([convert_literal(s) for s in split_by_arith])
  270. if literal.startswith('wait '):
  271. return f'<<{literal}>>'
  272. if(match := re.match(r"""^killvar\s+['"]\$?(.*)['"]$""",literal)):
  273. return f'<<set ${match.group(1)} = 0>>'
  274. if literal.startswith('jump '):
  275. jump_san = literal.replace('"','').replace("'","")
  276. return f"<<warn 'JUMP COMMAND ENCOUNTERED: {jump_san}'>>"
  277. if literal.startswith(':'):
  278. return f"<<warn 'JUMP MARKER ENCOUNTERED: {literal}'>>"
  279. if literal == "'" or literal == '"':
  280. return ''
  281. if re.match(r"""^['"\w\s\?\.!\(\)\$]+$""",literal):
  282. pv("Plain String",literal)
  283. return literal
  284. #return literal
  285. return f'ERROR: FAILED TO CONVERT LITERAL: """{literal}"""'
  286. function_name_conversions = []
  287. def convert_lineblock(lines,location_identifier=''):
  288. outputs = []
  289. nesting = []
  290. commenting = False
  291. isfunction = False
  292. functionlines = []
  293. functionlines_temp = []
  294. function_name = ''
  295. subpassages = {}
  296. subpassage = ''
  297. for line_raw in lines:
  298. #line_raw = lines[line_num]
  299. line = line_raw.strip()
  300. original = line
  301. pv("START:",line)
  302. if len(line) == 0:
  303. continue
  304. whitespace_count = len(nesting)
  305. # Subpassages
  306. if len(subpassage) > 0:
  307. if line.startswith('~$'):
  308. endSubpassageName = line[2:]
  309. gtOrGs = 'gt'
  310. if endSubpassageName.startswith('gs:'):
  311. gtOrGs = 'gs'
  312. endSubpassageName = endSubpassageName[3:]
  313. if endSubpassageName == subpassage:
  314. 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")
  315. subpassages[subpassage].append('<!-- END: '+subpassage+' -->')
  316. subpassage = ''
  317. continue
  318. subpassages[subpassage].append(line)
  319. continue
  320. if len(subpassage) == 0:
  321. if line.startswith('~^'):
  322. startSubpassageName = line[2:]
  323. subpassage = startSubpassageName
  324. subpassages[subpassage] = []
  325. continue
  326. for preparation in preparations:
  327. if len(preparation) > 2:
  328. line = re.sub(preparation[0],preparation[1],line,0,preparation[2])
  329. else:
  330. line = re.sub(preparation[0],preparation[1],line)
  331. line_output = ''
  332. purges = [
  333. 'CLOSE ALL',
  334. 'close all',
  335. '*clr & cla',
  336. 'killall',
  337. 'showstat 0','showstat 1',
  338. 'showobjs 0','showobjs 1',
  339. 'showinput 0','showinput 1',
  340. "gs 'stat'","gs'stat'",
  341. ]
  342. for purge in purges:
  343. line = line.replace(purge,'')
  344. pv("AFTER PURGES:",line)
  345. #line = line.replace(" mod "," % ")
  346. #while match := re.match(r"iif\s*\((.+),(.*),(.*)\)",line):
  347. # line = line.replace(match.group(0),f"({convert_condition(match.group(1))}) ? {convert_literal(match.group(2))} : {convert_literal(match.group(3))}")
  348. # FUNCTIONS
  349. if isfunction:
  350. if line.endswith('}'):
  351. isfunction = False
  352. functionname_sanatized = function_name.replace('$','').replace('[','').replace(']','').replace("'",'')
  353. functionlines.append(f':: {functionname_sanatized}_macro[widget]\n<<widget "{functionname_sanatized}">>\n')
  354. functionlines_temp = convert_lineblock(functionlines_temp)
  355. for fl in functionlines_temp:
  356. functionlines.append(f'\t{fl}')
  357. functionlines.append(f'<</widget>>\n')
  358. function_name_conversions.append([function_name,functionname_sanatized])
  359. else:
  360. functionlines_temp.append(line)
  361. continue
  362. if match := re.match(r"""(\$[a-z][a-z0-9\-_'"\[\]]+)\s*=\s*{""",line,re.I):
  363. isfunction = True
  364. #functionlines.append(f'<<widget "{match.group(1)}">>')
  365. function_name = match.group(1)
  366. functionlines_temp = []
  367. continue
  368. pv("AFTER FUNCTIONS:",line)
  369. while fuckyoumatch := re.search(r"""\[["']([^\]]*?)<<(.*?)>>(.*?)["']\]""",line):
  370. index = f'${fuckyoumatch.group(2)}'
  371. #left = ''
  372. if fuckyoumatch.group(1):
  373. index = f"'{fuckyoumatch.group(1)}'+" + index
  374. #right = ''
  375. if fuckyoumatch.group(3):
  376. index = index + f"+'{fuckyoumatch.group(3)}'"
  377. # right = fuckyoumatch.group(3)
  378. #index = f"'{left}'+${fuckyoumatch.group(2)}+'{right}'"
  379. #print(index)
  380. line = line.replace(fuckyoumatch.group(0),f"[{index}]")
  381. #print("MATCH")
  382. pv("AFTER ARRAY []:",line)
  383. while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*(<<.*?)'\s*\)""",line):
  384. fullmatch = dynevalmatch.group(0)
  385. varname = dynevalmatch.group(1)
  386. varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
  387. varname = "State.getVar('$"+varname.replace('<<',"'+").replace('>>',"+'")+"')"
  388. line = line.replace(fullmatch,varname)
  389. #print(line)
  390. pv("AFTER DYNEVAL:",line)
  391. while dynevalmatch := re.search(r"""dyneval\s*\(\s*'\s*RESULT\s*=\s*\$?(.*?)'\s*\)""",line):
  392. fullmatch = dynevalmatch.group(0)
  393. varname = "$"+dynevalmatch.group(1)
  394. varname = varname.replace('<<',"'+").replace('>>',"+'")
  395. #varname = varname.replace(r"[''",r"['").replace(r"'']",r"']")
  396. varname = varname.replace("['+","[").replace(r"+']",r"]")
  397. varname = varname.replace('$$',"$")
  398. line = line.replace(fullmatch,varname)
  399. pv("AFTER DYNEVAL2:",line)
  400. if line.startswith('!{') or line.startswith('!!{') or line == '!!{':
  401. line_output = '<!-- ' + line
  402. if line.endswith('}'):
  403. line_output += ' -->'
  404. else:
  405. commenting = True
  406. pv("IS COMMENT:",line_output)
  407. elif line.endswith('}') and commenting:
  408. line_output = line+' -->'
  409. commenting = False
  410. pv("IS COMMENT:",line_output)
  411. elif commenting:
  412. line_output = line.replace('--','-')
  413. pv("IS COMMENT:",line_output)
  414. elif line.lower() == 'end' or line.lower().startswith('end &!'):
  415. whitespace_count -= 1
  416. if len(nesting) > 0:
  417. end_command = nesting.pop()
  418. if end_command == 'if':
  419. #file.write('<</if>>\n')
  420. line_output = '<</if>>'
  421. elif end_command == 'while':
  422. #file.write('<</while>>\n')
  423. line_output = '<</while>>'
  424. elif end_command == 'act':
  425. #file.write('<</act>>\n')
  426. line_output = '<</act>>'
  427. else:
  428. print(f'ERROR: UNKNOWN NESTRING: {end_command}')
  429. else:
  430. line_output = '<</END>>'
  431. pv("IS END:",line_output)
  432. elif line.startswith('!'):
  433. line_output = '<!-- ' + line + '-->'
  434. pv("IS COMMENT:",line_output)
  435. elif line.lower() == 'else':
  436. #file.write('<<else>>\n')
  437. line_output = '<<else>>'
  438. whitespace_count -= 1
  439. pv("IS ELSE:",line_output)
  440. elif line.lower() == 'cls':
  441. line_output = ''
  442. pv("IS CLS:",line_output)
  443. elif line.lower() == '*nl':
  444. #file.write('\n')
  445. line_output = ''
  446. pv("IS NL:",line_output)
  447. elif line[0:3] == '---':
  448. line_output = ''
  449. pv("IS EOF:",line_output)
  450. elif match := re.match(r"^\s*msg\s*'(.*)'\s*$",line,re.I):
  451. msg = match.group(1).replace("'",'"')
  452. line_output = f"""<<msg '{msg}'>>"""
  453. pv("IS MSG:",line_output)
  454. 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):
  455. label = match.group(1).replace("'",'"')
  456. line_output = f"<<act `'{label} ('+$will_cost+')'`>><font color=red><br/>You don`t have enough willpower to use this action.</font><</act>>"
  457. 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):
  458. #Images
  459. if match.group(2):
  460. line_output = f'''<<image "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
  461. else:
  462. line_output = f'''<<image "{match.group(1)}{match.group(3)}">>'''
  463. pv("IS IMAGE:",line_output)
  464. 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):
  465. #Images
  466. if match.group(2):
  467. line_output = f'''<<video "{match.group(1)}#{match.group(3)}" {match.group(2).replace(',',' ')}>>'''
  468. else:
  469. line_output = f'''<<video "{match.group(1)}{match.group(3)}">>'''
  470. pv("IS VIDEO:",line_output)
  471. elif line.startswith('<') and line.endswith('>'):
  472. line_output = line
  473. pv("IS HTML:",line_output)
  474. elif line.startswith("'<") and line.endswith(">'"):
  475. line_output = line[1:-1]
  476. pv("IS COMMENTED HTML:",line_output)
  477. elif match := re.match(r"""^'[\w<>\s=:'"\/\.\(\),\*]+'$""",line):
  478. #Plain HTML
  479. line_output = line[1:-1]
  480. if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",line_output):
  481. #line_output = #line_output.replace(link_match[0],"moep")
  482. #print("moep")
  483. #print(link_match)
  484. for lmatch in link_match:
  485. line_output = line_output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
  486. pv("IS PLAIN HTML:",line_output)
  487. elif match := re.match(r"^\s*(if|while)\s+([^:]+):(.*)",line,re.I):
  488. command = match.group(1).lower()
  489. line_w = f'<<{command} {convert_condition(match.group(2))}>>'
  490. if match.group(3):
  491. #if com := convert_command(match.group(3)):
  492. # line_w += '\n' + (whitespace_count+1) * '\t' + com
  493. #else:
  494. # line_w += '\n' + (whitespace_count+1) * '\t' + convert_literal(match.group(3))
  495. converted = convert_lineblock([match.group(3)])
  496. if len(converted)>0 and converted[0]:
  497. line_w += '\n' + (whitespace_count+1) * '\t' + converted[0]
  498. line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
  499. else:
  500. nesting.append(command)
  501. #file.write(line_w)
  502. line_output = line_w
  503. pv("IS IF:",line_output)
  504. elif match := re.match(r"\s*(act)\s*(.+):(.*)",line,re.I):
  505. # Act-Command
  506. command = match.group(1).lower()
  507. line_w = f'<<{command} {convert_literal(match.group(2))}>>'
  508. if match.group(3):
  509. line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
  510. line_w += '\n' + whitespace_count * '\t'+f'<</{command}>>'
  511. else:
  512. nesting.append(command)
  513. #file.write(line_w)
  514. line_output = line_w
  515. pv("IS ACT:",line_output)
  516. elif match := re.match(r"\s*(elseif)\s+([^:]+):(.*)",line,re.I):
  517. # ElseIf
  518. command = match.group(1).lower()
  519. line_w = f'<<{command} {convert_condition(match.group(2))}>>'
  520. whitespace_count -= 1
  521. if match.group(3):
  522. #line_w += '\n' + (whitespace_count+1) * '\t'+convert_command(match.group(3))
  523. line_w += '\n' + whitespace_count * '\t'+f'<</if>>'
  524. #nesting.pop()
  525. #file.write(line_w)
  526. line_output = line_w
  527. pv("IS ELSEIF:",line_output)
  528. #elif match := re.match(r"^dynamic\s+'(.*)'$",line,re.I):
  529. # out = match.group(1).replace('<<',"'+").replace('>>',"+'")
  530. # line_output = f"<<dynamic {out}>>"
  531. elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
  532. left = match.group(1)
  533. right = match.group(3)
  534. operator = match.group(2)
  535. left = left.replace(r"[''",r"['").replace(r"'']",r"']")
  536. left = left.replace(r"['+",r"[").replace(r"+']",r"]")
  537. left = left.replace('<<',"'+").replace('>>',"+'")
  538. left = left.replace('$$',"$")
  539. right = right.replace(r"[''",r"['").replace(r"'']",r"']")
  540. right = right.replace(r"['+",r"[").replace(r"+']",r"]")
  541. right = right.replace('<<',"").replace('>>',"")
  542. right = right.replace('$$',"$")
  543. right = convert_literal(right)
  544. line_output = f'<<set {left} {operator} {right}>>'
  545. pv("IS DYNAMIC:",line_output)
  546. #elif match := re.match(r"^dynamic '\$?(.*?)\s*([\+\-]?=)\s*(.*?)\s*'$",line,re.I):
  547. elif match := re.match(r"^dynamic\s*\$([a-zA-Z]\w+)$",line,re.I):
  548. line_output = f'<<{match.group(1)}>>'
  549. elif match := re.match(r"""^([^\$])*<a\s+href\s*=\s*"exec:\s*(?:minut\s*\+=\s*(\d+)\s*&\s*)?gt(.*)?"\s*>(.*?)</a>.*$""",line,re.I):
  550. 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):
  551. full_match = link_match.group(0)
  552. time = ""
  553. if link_match.group(1):
  554. time = f"<<set $minut += {link_match.group(1)}>>"
  555. goto = link_match.group(2)
  556. goto = goto.replace(","," ").replace(r"''",r"'")
  557. label = link_match.group(3)
  558. link = f"<<link '{label}'>>{time}<<gt {goto}>><</link>>"
  559. line = line.replace(full_match,link)
  560. line_output = line
  561. elif match := convert_command(line):
  562. line_output = match
  563. pv("IS COMMAND:",line_output)
  564. else:
  565. line_output = convert_literal(line)
  566. if len(line_output) >= 2 and line_output[0] == '\'' and line_output[-1] == '\'':
  567. line_output = f'<p>{line_output[1:-1]}</p>'
  568. pv("IS LITERAL:",line_output)
  569. whitespace = whitespace_count * '\t'
  570. output = f'{whitespace}{line_output}\n'
  571. if output.strip():
  572. #file.write(cleanUpTheMess(output))
  573. output = cleanUpTheMess(output)
  574. if "ERROR:" in output:
  575. global error_counter
  576. 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'
  577. error_counter += 1
  578. outputs.append(output)
  579. for subpassId in subpassages:
  580. subpass = subpassages[subpassId]
  581. subpassageLines = convert_lineblock(subpass)
  582. outputs.append(f'\n:: {subpassId}\n')
  583. for subpassageLine in subpassageLines:
  584. outputs.append(subpassageLine)
  585. if len(functionlines) > 0:
  586. #outputs.append(f'::{location_identifier}_widgets[widget]\n')
  587. for functionline in functionlines:
  588. functionline = functionline.replace('$ARGS','_args').replace('$location_var[$here][','_args[')
  589. outputs.append(functionline)
  590. return outputs
  591. def convert_file(filename,skipIfNotExplicit=0,defaultsubfolder=False):
  592. skip = skipIfNotExplicit
  593. qsp_filename = filename+".qsrc"
  594. qsp_filepath = os.path.join(qsp_sources_path,qsp_filename)
  595. tw_filename = filename+".tw"
  596. tw_filepath = os.path.join(tw_sources_path,tw_filename)
  597. if defaultsubfolder:
  598. os.makedirs(os.path.join(tw_sources_path,defaultsubfolder),exist_ok =True)
  599. tw_filepath = os.path.join(tw_sources_path,defaultsubfolder,tw_filename)
  600. try:
  601. with open(qsp_filepath) as file:
  602. lines = [line.rstrip() for line in file]
  603. except:
  604. try:
  605. with open(qsp_filepath, encoding="utf-8") as file:
  606. lines = [line.rstrip() for line in file]
  607. except:
  608. return f"FAILED: {qsp_filename}"
  609. location_identifier = ''
  610. ignore_recusions = 0
  611. 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):
  612. if match.group(1):
  613. parts = match.group(1).split(':')
  614. new_path = os.path.join(tw_sources_path,parts[1].strip())
  615. os.makedirs(new_path,exist_ok =True)
  616. tw_filepath = os.path.join(new_path,tw_filename)
  617. if match.group(2):
  618. parts = match.group(2).split(':')
  619. arg = int(parts[1])
  620. if arg == 1:
  621. skip = 1
  622. elif arg == 0:
  623. skip = 0
  624. elif arg == -1:
  625. skip = -1
  626. if match.group(3):
  627. parts = match.group(3).split(':')
  628. arg = int(parts[1])
  629. if arg == 1:
  630. ignore_recusions = 1
  631. elif arg == 0:
  632. ignore_recusions = 0
  633. if skip == 1:
  634. return
  635. if skip == -1 and os.path.exists(tw_filepath):
  636. modification_time_delta = os.path.getmtime(qsp_filepath) - os.path.getmtime(tw_filepath)
  637. if modification_time_delta <= 0:
  638. return
  639. identifier_line = 0
  640. for line_num in range(0,len(lines)-1):
  641. line_raw = lines[line_num]
  642. line = line_raw.strip()
  643. match = re.match(r"#\s*(\S+)", line)
  644. if match:
  645. location_identifier = match.group(1)
  646. identifier_line = line_num
  647. break
  648. with open(tw_filepath, 'w') as file:
  649. #file.write(f'<!-- GENERATED: {datetime.datetime.now()} -->\n')
  650. file.write(f':: {location_identifier}\n')
  651. file.write(f"<<set $here = '{location_identifier}'>>\n<<set $ARGS = $location_var[$here]>>\n")
  652. if ignore_recusions == 1:
  653. file.write(f'<<set _ts to Math.floor(Date.now() / 10000)>>\n')
  654. file.write(f'<<setinit $gt_history[_ts][$here] = 0>>\n')
  655. #for line_num in range(identifier_line+1,len(lines)-1):
  656. outputs = convert_lineblock(lines[identifier_line+1:],location_identifier)
  657. for output in outputs:
  658. file.write(output)
  659. with open(tw_filepath, 'r') as file:
  660. data = file.read()
  661. with open(tw_filepath, 'w') as file:
  662. regex1 = r"""<<gs 'willpower' ([\s'\w]*)>>\s*<<if \$will_cost <= \$pc\.pcs_willpwr>>\s*<<act '([\w\s]*?)\s*\(will_cost Willpower\)'>>"""
  663. while match := re.search(regex1,data,re.I):
  664. blockStart = match.end()
  665. regex_close = r"""<<else>>\s*<<act `?'"""+match.group(2)+r""".*?<</act>>\s*<</if>>"""
  666. if close_match := re.search(regex_close,data,re.I):
  667. blockEnd = close_match.start()
  668. block = data[blockStart:blockEnd]
  669. # Remove the re-calculation of the willpower-cost
  670. newBlock = block
  671. newBlock = newBlock.replace("<<gs 'willpower' "+match.group(1)+">>",'')
  672. newBlock = re.sub(r"""<<gs 'willpower' 'pay' ([\s'\w]*)>>""","",newBlock)
  673. data = data.replace(block,newBlock)
  674. data = data.replace(close_match.group(0),"")
  675. arguments = match.group(1).replace(' ',',')
  676. data = data.replace(match.group(0),"<<act '"+match.group(2)+"' undefined `{willpower:["+arguments+"]}`>>")
  677. else:
  678. #print("FAIL: "+match.group(0))
  679. break
  680. data = data.replace('<<act ','<<actCLA ')
  681. data = data.replace('<</act>>','<</actCLA>>')
  682. file.write(data)
  683. with open(tw_filepath, 'r') as file:
  684. data = file.read()
  685. regex_split = r"""::\s*SPLIT:(\w+)"""
  686. while match := re.search(regex_split,data,re.I):
  687. identifier = match.group(1)
  688. regex_split_end = r"""<!-- END: SPLIT:"""+identifier+r"""\s*-->"""
  689. if end_match := re.search(regex_split_end,data,re.I):
  690. sub_filepath = os.path.join(new_path,identifier+'.tw')
  691. subdata = data[match.start():end_match.end()]
  692. subdata = subdata.replace("SPLIT:"+identifier,identifier,1)
  693. with open(sub_filepath, 'w') as subfile:
  694. subfile.write(subdata)
  695. data = data[:match.start()]+data[end_match.end():]
  696. data = data.replace("SPLIT:"+identifier,identifier,1)
  697. with open(tw_filepath, 'w') as file:
  698. file.write(data)
  699. return tw_filepath
  700. FTCL = [r'ERROR: FAILED TO CONVERT LITERAL:\s*"""',r'"""']
  701. VAR = r"""\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)"""
  702. preparations = [
  703. [
  704. r"""\$week\[""",
  705. r"$week_name["
  706. ],
  707. [
  708. r"""pcs_pubecol\[""",
  709. r"pcs_pubecol_num["
  710. ],
  711. [
  712. r"""pcs_pubes\[""",
  713. r"pcs_pubes_num["
  714. ],
  715. [
  716. r"""^PLAY\s*.*""",
  717. r""
  718. ],
  719. [
  720. r"""^\s*pl\s+(.*)$""",
  721. r"\1"
  722. ]
  723. #[
  724. # r"""(</?(?:table|center|th|tr|td))([^>]*=[^>]*)(>)""",
  725. # r'\1\3',
  726. # re.I
  727. #]
  728. ]
  729. skill_names = [
  730. [r"\$pcs_heels","highHeels"],
  731. [r"\$pcs_stren","strength"],
  732. [r"\$pcs_agil","agility"],
  733. [r"\$pcs_intel","intelligence"],
  734. [r"\$pcs_react","reaction"],
  735. [r"\$pcs_sprt","spirit"],
  736. [r"\$pcs_chrsm","charisma"],
  737. [r"\$pcs_prcptn","perception"],
  738. [r"\$pcs_humint","people"],
  739. [r"\$pcs_persuas","persuasion"],
  740. [r"\$pcs_observ","observation"],
  741. [r"\$pcs_jab","jabs"],
  742. [r"\$pcs_punch","punch"],
  743. [r"\$pcs_kick","kick"],
  744. [r"\$pcs_def","defense"],
  745. [r"\$pcs_run","run"],
  746. [r"\$pcs_vball","volleyball"],
  747. [r"\$pcs_ftbll","football"],
  748. [r"\$pcs_wrstlng","wrestling"],
  749. [r"\$pcs_shoot","shoot"],
  750. [r"\$pcs_bushcraft","bushcraft"],
  751. [r"\$pcs_chess","chess"],
  752. [r"\$pcs_icesktng","iceskating"],
  753. [r"\$pcs_gaming","gaming"],
  754. [r"\$pcs_makupskl","makeup"],
  755. [r"\$pcs_danc","dance"],
  756. [r"\$pcs_dancero","eroticdance"],
  757. [r"\$pcs_dancpol","poledance"],
  758. [r"\$pcs_cheer","cheerleading"],
  759. [r"\$pcs_mdlng","modelling"],
  760. [r"\$pcs_vokal","singing"],
  761. [r"\$pcs_instrmusic","playInstrument"],
  762. [r"\$pcs_photoskl","photo"],
  763. [r"\$pcs_artskls","art"],
  764. [r"\$pcs_compskl","computer"],
  765. [r"\$pcs_comphckng","hacking"],
  766. [r"\$pcs_hndiwrk","handyWork"],
  767. [r"\$pcs_sewng","sewing"],
  768. [r"\$pcs_servng","serving"],
  769. [r"\$pcs_medcn","medicine"],
  770. ]
  771. replaces = [
  772. [
  773. r"ERROR: FAILED TO CONVERT CONDITION: func\(",
  774. r"func("
  775. ],
  776. [
  777. r"ERROR: FAILED TO CONVERT CONDITION: \$?([a-zA-Z])",
  778. r"$\1"
  779. ],
  780. [
  781. FTCL[0]+r"killvar\s*'"+VAR+r"'"+FTCL[1],
  782. r"<<set $\1 to undefined>>"
  783. ],
  784. [
  785. r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"\)\(),\s]+]*)>>)?(\.[^"]+)">""",
  786. r"<<image `'\2\3\5'`>>"
  787. ],
  788. [
  789. r"""'([\w\/]+)<<\s*rand\s*\(\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)\s*>>([^']*)'""",
  790. r"""'\1'+rand(\2,\3)+'\4'"""
  791. ],
  792. [
  793. r"""<<set \$?([a-zA-Z][a-zA-Z0-9-_'"]+]*\[.*)>>""",
  794. r"""<<setinit $\1>>"""
  795. ],
  796. [
  797. # <<set $gopnikbandQW += -1>> -> <<setn $gopnikbandQW += -1>>
  798. r"""<<set (\$[^>]*?)\s([+-]=)\s*(-?\d+)>>""",
  799. r"""<<setn \1 \2 \3>>""",
  800. 1
  801. ],
  802. [
  803. # asd
  804. r"""<<set (\$[^>]*?)\s(\+=)\s*(["'][^>]*?)>>""",
  805. r"""<<sets \1 \2 \3>>""",
  806. 1
  807. ],
  808. [
  809. r"""(\+)\s+=""",
  810. r"""\1="""
  811. ],
  812. [
  813. r"(I|you|You|he|He|she|She|it|It|we|We|they|They|can|Can|don|Don)''(m|re|s|ll|ve|t)",
  814. r"\1'\2"
  815. ],
  816. #[
  817. # r"^(.*"+FTCL[0]+r"(.*)"+FTCL[1]+r".*)$",
  818. # r"<!-- \1 -->\n<<warn 'FTCL: \1'>>"
  819. #],
  820. [
  821. r"=\s*\$(mid|MID)\s*\(",
  822. r"= mid("
  823. ],
  824. [
  825. r"(<<set\s*.*?\[)([a-zA-Z].*?)(\]\s*=.*>>)",
  826. r"\1$\2\3"
  827. ],
  828. [
  829. r"(<<act\s*'.*)(\$.*?\])(.*'>>)",
  830. r"\1'+\2+'\3"
  831. ],
  832. [
  833. r"\[([a-zA-Z]\w*)\]",
  834. r"[$\1]"
  835. ],
  836. [
  837. r"([\+\-])\s+=",
  838. r"\1="
  839. ],
  840. [
  841. r"<<setinit\s*(.*)\[\]\s*=\s*(.*)>>",
  842. r"""<<setinitpush "\1" \2>>"""
  843. ],
  844. [
  845. r"\s+min\(",
  846. r" Math.min("
  847. ],
  848. [
  849. r"\s+max\(",
  850. r" Math.max("
  851. ],
  852. [
  853. r"""<<set (.*) to null>>\s*,\s*(.*)(\s*)""",
  854. r"<<set \1[\2] to null>>\3"
  855. ]
  856. ,
  857. [
  858. r"""\$arrsize\(""",
  859. r"arrsize("
  860. ],
  861. [
  862. r"""<<set(?:init)?\s+\$?(?P<name>\w+)\[arrsize\('\$?(?P=name)'\)\]\s*=\s*(.*)\s*>>""",
  863. r"<<run $\1.push(\2)>>"
  864. ],
  865. [
  866. r"""<center><(?:h\d|b)><font color="maroon">(.*)</font></(?:h\d|b)></center>""",
  867. r"<h2>\1</h2>"
  868. ],
  869. [
  870. r"""(<<act '[^']*)'([^']*'>>)""",
  871. r"\1`\2"
  872. ],
  873. # NPC-Stuff Start
  874. [
  875. r"""\$npc_(\w*?)\[([^\]]*?)\]""",
  876. r"$npcs.get(\2,'\1')",
  877. 1
  878. ],
  879. # Fix for Sub-Arrays
  880. [
  881. r"""\$npcs\.get\((.*?),('\w*')\)(\[[^\]]*\]+?)\]""",
  882. r"$npcs.get(\1]\3,\2)",
  883. 1
  884. ],
  885. [
  886. r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*=\s*(.*?)>>""",
  887. r"<<run $npcs.set(\1,\2)>>",
  888. 1
  889. ],
  890. [
  891. r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*\+=\s*(.*?)>>""",
  892. r"<<run $npcs.inc(\1,\2)>>",
  893. 1
  894. ],
  895. [
  896. r"""<<set(?:init)?\s+\$npcs\.get\((.*?)\)\s*-=\s*(.*?)>>""",
  897. r"<<run $npcs.dec(\1,\2)>>",
  898. 1
  899. ],
  900. # NPC-Stuff END
  901. [
  902. r"""(\$\w+(?:\['\w+'\])?)\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
  903. r"""getvar("\1") \2 \3""",
  904. 1
  905. ],
  906. [
  907. #Example: $property_construction_status[$i] == 0 -> getvar("$property_construction_status["+$i+"]") == 0
  908. r"""(\$\w+)(?:\[(\$\w+)\])\s*(==|>=?|<=?|!=)\s*(\-?\d+)""",
  909. r"""getvar("\1["+\2+"]") \3 \4""",
  910. 1
  911. ],
  912. [
  913. r"""\*?\s*\$\s*cl[ar]\s*$""",
  914. r""
  915. ],
  916. [
  917. r"""<<gs 'clothing' 'wear'\s*(.*?)\s+(.*?)>>""",
  918. r"<<run $wardrobe.wear_clothes_legacy('clothes',\1,\2)>>"
  919. ],
  920. [
  921. r"""<<gs 'shoes' 'wear'\s+(.*?)\s+(.*?)>>""",
  922. r"<<run $wardrobe.wear('shoes',\1,\2)>>"
  923. ],
  924. [
  925. r"""<<gs\s+'shoes'\s+'wear'\s+'last_worn'\s*>>""",
  926. r"<<run $wardrobe.wear_last('shoes')>>"
  927. ],
  928. [
  929. r"""<<gs\s+'bras'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
  930. r"<<run $wardrobe.wear('bra',\1,\2)>>"
  931. ],
  932. [
  933. r"""<<gs\s+'panties'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
  934. r"<<run $wardrobe.wear('panties',\1,\2)>>"
  935. ],
  936. [
  937. r"""<<gs\s+'coats'\s+'wear'\s+(.+?)\s+(.+?)\s*>>""",
  938. r"<<run $wardrobe.wear('coat',\1,\2)>>"
  939. ],
  940. [
  941. r"""<<gs\s+'bras'\s+'wear'\s*>>""",
  942. r"<<run $wardrobe.wear_last('bra')>>"
  943. ],
  944. [
  945. r"""<<gs\s+'panties'\s+'wear'\s*>>""",
  946. r"<<run $wardrobe.wear_last('panties')>>"
  947. ],
  948. [
  949. r"""iif\(([^)]*?)\s*==?\s*'',""",
  950. r"iif(!\1,",
  951. 1
  952. ],
  953. # Rand in gs Fix
  954. [
  955. r"""<<g([st].*?)\srand\((.*?)\)(.*?)>>""",
  956. r"<<g\1 `rand(\2)`\3>>",
  957. 1
  958. ],
  959. # Pain
  960. [
  961. r"""(<<(?:else)?if\s+|and\s+|x?or\s+)(?:getvar\(")\$pain\[('\w+')\](?:"\))(.*?>>)""",
  962. r"\1$pc.pain(\2)\3",
  963. 1
  964. ],
  965. [
  966. r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*\+=\s*(.*?)>>""",
  967. r"<<run $pc.painInc(\1,\2)>>",
  968. 1
  969. ],
  970. [
  971. r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*-=\s*(.*?)>>""",
  972. r"<<run $pc.painDec(\1,\2)>>",
  973. 1
  974. ],
  975. [
  976. r"""<<set(?:init)?\s+\$pain\[('\w+')\]\s*=\s*(.*?)>>""",
  977. r"<<run $pc.painSet(\1,\2)>>",
  978. 1
  979. ],
  980. #Cum
  981. [
  982. r"""\$cumloc\[(\d+)\]""",
  983. r"$pc.cumAtLocation(\1)",
  984. 1
  985. ],
  986. # Inner Thought
  987. [
  988. r"""(?:'?\s*\+\s*)?\$OpenInnerThought\s*\+\s*'(.*?)'\s*\+\s*\$CloseInnerThought(?:\s*\+\s*'?)?""",
  989. r"""<span class="innerThought">\1</span>""",
  990. 1
  991. ],
  992. # Group Membership
  993. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*1',r"$q.school.func('isGroupMember','cool')",1],
  994. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*2',r"$q.school.func('isGroupMember','jocks')",1],
  995. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*3',r"$q.school.func('isGroupMember','nerds')",1],
  996. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*4',r"$q.school.func('isGroupMember','gopniks')",1],
  997. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*5',r"$q.school.func('isGroupMember','outcasts')",1],
  998. [r'(?:getvar\(")?\$grupTipe(?:"\))?\s*==\s*6',r"$q.school.func('isGroupMember','teachers')",1],
  999. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*1>>',r"<<run $q.school.func('setGroupMembership','cool')>>",1],
  1000. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*2>>',r"<<run $q.school.func('setGroupMembership','jocks')>>",1],
  1001. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*3>>',r"<<run $q.school.func('setGroupMembership','nerds')>>",1],
  1002. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*4>>',r"<<run $q.school.func('setGroupMembership','gopniks')>>",1],
  1003. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*5>>',r"<<run $q.school.func('setGroupMembership','outcasts')>>",1],
  1004. [r'<<set(?:init)?\s+\$grupTipe(?:"\))?\s*=\s*6>>',r"<<run $q.school.func('setGroupMembership','teachers')>>",1],
  1005. ]
  1006. purge_messes=[
  1007. r"""<<set(init)? \$npc_selfie\[""",
  1008. r'''<<set(init)? \$npcGo\[''', # We need to replace this by another function,
  1009. r'''<<set(init)? \$npcGoSchool\['''
  1010. ]
  1011. def cleanUpTheMess(output):
  1012. for purge_mess in purge_messes:
  1013. if match := re.search(purge_mess,output):
  1014. return ''
  1015. for skill_name in skill_names:
  1016. oldSN = skill_name[0]
  1017. newSN = skill_name[1]
  1018. oldSN_without_prefix = oldSN.split('_')[1]
  1019. output = re.sub(r"<<set(?:init)?\s+"+oldSN+r"\s*=\s*(.*?)\s*>>",r"<<run $pc.skillSetLevel('"+newSN+r"',\1)>>",output)
  1020. output = re.sub(r"<<gs\s+'exp_gain'\s+('"+oldSN_without_prefix+r"')\s+`?(.*?)`?>>",r"<<run $pc.skillExperienceGain('"+newSN+r"',\2)>>",output)
  1021. output = re.sub(oldSN,'$pc.skillLevel("'+newSN+'")',output)
  1022. for replace in replaces:
  1023. if len(replace) > 2:
  1024. if replace[2] == 1:
  1025. while(re.search(replace[0],output)):
  1026. output = re.sub(replace[0],replace[1],output)
  1027. else:
  1028. output = re.sub(replace[0],replace[1],output)
  1029. if warnmatch := re.search(r"""<<warn '(.*)'>>""",output):
  1030. return output.replace(warnmatch.group(1),warnmatch.group(1).replace("'",'"'))
  1031. if link_match := re.findall(r"""(<a href="exec:([^"]+)">([^<]+)<\/a>)""",output):
  1032. for lmatch in link_match:
  1033. output = output.replace(lmatch[0],f"""<<link "{lmatch[2]}">>{convert_command(lmatch[1])}<</link>>""")
  1034. output = re.sub(r"""\$result""","$result",output,0,re.I)
  1035. while image_match := re.match(r"""<img\s+(<<\$set_imgh>>)?\s*src="([^<^\.]*)(<<\$?([a-zA-Z][a-zA-Z0-9-_\[\]'"]+]*)>>)?\.[^"]+">""",output):
  1036. if len(image_match.group(3)) == 0:
  1037. break
  1038. output = output.replace(image_match.group(3),f'"+${image_match.group(4)}+"')
  1039. while match := re.search(r"""<<set(?:init)?[^=]+=\s*'([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+)('([a-zA-Z0-9\.\?!<>"\s,`\-\(\)]+))+'>>""",output):
  1040. output = output.replace(match.group(2),f"`{match.group(3)}")
  1041. # NPCs: add print to all get-calls which are not inside a macro
  1042. if(not output.strip().startswith('<<')):
  1043. output = re.sub(r"(?<!=)(\$npcs\.get\(.*?\))",r"<<=\1>>",output)
  1044. # Arousal
  1045. while match := re.search(r"<<gs 'arousal' '(\w+)' (.*?)(\s.*?)?>>",output):
  1046. if match.group(3):
  1047. arguments = "`["+match.group(3).replace("' '","','").strip()+"]`"
  1048. else:
  1049. arguments = ''
  1050. output = output.replace(match.group(0),"<<arouse '"+match.group(1)+"' "+match.group(2)+" "+arguments+">>")
  1051. for variable_replacement in variables.variable_replacements:
  1052. if len(variable_replacement) > 2:
  1053. if variable_replacement[2] == 1:
  1054. output = re.sub(variable_replacement[0],variable_replacement[1],output)
  1055. else:
  1056. output = output.replace(variable_replacement[0],variable_replacement[1])
  1057. else:
  1058. output = output.replace(variable_replacement[0],variable_replacement[1])
  1059. output = output.replace('getvar("'+variable_replacement[1]+'")',variable_replacement[1])
  1060. # Inventory-Vars
  1061. for inventory_variable in variables.inventory_variables:
  1062. output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*=\s*(.*?)\s*>>",rf"<<run $inventory.set('{inventory_variable[1]}',\1)>>",output)
  1063. output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*-=\s*(.*?)\s*>>",rf"<<run $inventory.dec('{inventory_variable[1]}',\1)>>",output)
  1064. output = re.sub(rf"<<set(?:init)?\s+\${inventory_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run $inventory.inc('{inventory_variable[1]}',\1)>>",output)
  1065. output = re.sub(rf"<<{inventory_variable[0]}>>",rf"""$inventory.get("{inventory_variable[1]}")""",output)
  1066. output = re.sub(rf"""getvar\("\${inventory_variable[0]}"\)""",rf"""$inventory.get("{inventory_variable[1]}")""",output)
  1067. output = re.sub(rf"""\${inventory_variable[0]}([^\w])""",rf"""$inventory.get("{inventory_variable[1]}")\1""",output)
  1068. # Get Set Variables
  1069. for get_set_variable in variables.get_set_variables:
  1070. output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*=\s*(.*?)\s*>>",rf"<<run {get_set_variable[2]}>>",output)
  1071. if(len(get_set_variable) == 5):
  1072. output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run {get_set_variable[3]}>>",output)
  1073. output = re.sub(rf"<<set(?:init)?\s+{get_set_variable[0]}\s*\-=\s*(.*?)\s*>>",rf"<<run {get_set_variable[4]}>>",output)
  1074. #output = re.sub(rf"<<set(?:init)?\s+\${get_set_variable[0]}\s*-=\s*(.*?)\s*>>",rf"<<run $inventory.dec('{inventory_variable[1]}',\1)>>",output)
  1075. #output = re.sub(rf"<<set(?:init)?\s+\${get_set_variable[0]}\s*\+=\s*(.*?)\s*>>",rf"<<run $inventory.inc('{inventory_variable[1]}',\1)>>",output)
  1076. output = re.sub(rf"<<{get_set_variable[0]}>>",get_set_variable[1],output)
  1077. output = re.sub(rf"""getvar\("{get_set_variable[0]}"\)""",get_set_variable[1],output)
  1078. output = re.sub(rf"""{get_set_variable[0]}(?P<stuffToTheRight>[^\w])""",rf"""{get_set_variable[1]}\g<stuffToTheRight>""",output)
  1079. for pgsvr in variables.post_get_set_variables_replacements:
  1080. output = output.replace(pgsvr[0],pgsvr[1])
  1081. output = output.replace("$location_var[$here][0] == ''","!$location_var[$here][0]")
  1082. return output
  1083. def testConvertLine(line):
  1084. test_line = ''
  1085. #test_line = """gs 'npc_relationship', 'socialgroup_setting', 0, 0, -10, 10, -10, -10"""
  1086. if len(test_line) > 0:
  1087. verbose = True
  1088. print(test_line)
  1089. result = convert_lineblock([test_line])
  1090. if len(result) > 0:
  1091. print(result[0])
  1092. else:
  1093. print("EMPTY RESULT")
  1094. exit()
  1095. def convertFiles(restrictfiles=[]):
  1096. #output_files = []
  1097. os.makedirs(tw_sources_path, exist_ok=True)
  1098. #for replace in replaces:
  1099. # print(replace[0])
  1100. #restrictfiles = []
  1101. #restrictfiles = ['gschool_gopnik_chats']
  1102. files = os.listdir(qsp_sources_path)
  1103. file_counter = 0
  1104. last_displayed_percentage_time = time.time()
  1105. filesToDo = []
  1106. for file in files:
  1107. if len(restrictfiles) == 0 or (os.path.splitext(file)[0] in restrictfiles):
  1108. if file.endswith(".qsrc"):
  1109. filesToDo.append(os.path.splitext(file)[0])
  1110. #output_files.append(convert_file(os.path.splitext(file)[0],skipMode,'unsorted'))
  1111. with ThreadPoolExecutor(32) as executor:
  1112. # submit all tasks
  1113. futures = [executor.submit(convert_file, p, skipMode, 'unsorted') for p in filesToDo]
  1114. # process all results
  1115. for future in as_completed(futures):
  1116. # open the file and load the data
  1117. completedPath = future.result()
  1118. # report progress
  1119. #print(f'.loaded {filepath}')
  1120. file_counter += 1
  1121. if(last_displayed_percentage_time + 5 < time.time()):
  1122. print(str(round(file_counter/len(files)*100, 2))+"%")
  1123. last_displayed_percentage_time = time.time()
  1124. #for output_file in output_files:
  1125. # for line in fileinput.input(output_file, inplace=True):
  1126. #
  1127. # for function_name_conversion in function_name_conversions:
  1128. #
  1129. #
  1130. # if fileinput.filelineno() == 10:
  1131. # print(('10'+line), end='')
  1132. # break
  1133. if __name__ == "__main__":
  1134. convertFiles()