#!/usr/bin/python2 import sys from HTMLParser import HTMLParser ''' twine2rpy is for storyboarding/testing Ren'py scripts in Twine and converting the Twine source file to .rpy. This example was made for use with Twine 2, which exports directly to HTML. It only supports simple narrator speech and flow control: Variables, conditionals, images, and even markup are not supported. It should not be hard to extend this script (unless you're using HTML inside the dialog blocks). THIS FILE IS PROVIDED AS-IS, WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, EXCEPT WHERE OTHERWISE REQUIRED BY LAW. PS. This script version is not meant for production use. From the command line: twine2rpy_2.py source.txt ''' ####################################################################### # Open Twine source file # This function will (in an expensive manner) find the tuples we want # on HTML argument list. def dl_getkey(array, key): for k in array: if k[0] == key: return k[1] # Receive arguments from commandline try: file_name = sys.argv[1] except IndexError: print("Usage: ./converter.py ") print("") print("Made with Harlowe2 syntax. Use other syntaxes at your own risk!") exit(0) # Receives a HTML file open_file = open(file_name) txt_file = open_file.read() txt_file = txt_file.replace(""", "\"").replace("'", "\'") # Prepare the Ren'Py file renpy_file = "t2_" + file_name[:file_name.find(".")].rstrip() + ".txt" rpy_file = open(renpy_file, "w") # Global dictionaries # TLT : Top Level Tag (what we're examining right now). TLT="html" LABELS={} INMENU=False PARSE=False BREAK=False # Parse data # The "data" is received as-is; As long that it doesn't uses HTML, # It should not break. def parse(basedata): global TLT, LABELS, INMENU, BREAK data=basedata.split("\n") # Convert stuff for d in data: # regexes (or anything which would break this) d=d.replace("\"", "\\\"") d=d.strip() # Exceptions: Do not add empty dialog boxes if d == "": if BREAK: rpy_file.write(" next;\n") #rpy_file.write(" mesn;\n") BREAK=False rpy_file.write("\n") continue # Handle comments if (d.startswith("//")): rpy_file.write(" %s\n" % d) continue # Here is an example of how simple menus could be handed: if (d.startswith("[[") and not INMENU): d=d.replace("[[", "").replace("]]", "") INMENU=True rpy_file.write(" menu\n") target=LABELS[d] rpy_file.write(" l(\"%s\"), L_%s" % (d, target)) elif (d.startswith("[[") and INMENU): d=d.replace("[[", "").replace("]]", "") target=LABELS[d] rpy_file.write(",\n l(\"%s\"), L_%s" % (d, target)) elif INMENU: INMENU=False rpy_file.write(";\n") else: # Save it as a narrator speech block; # It will ignore other markdown and comments, too, but thankfully, # it is not very difficult to add regexes and replaces for them. rpy_file.write(" mesq l(\"%s\");\n" % d) BREAK=True # HTML Magic # create a subclass and override the default handler methods class MyHTMLParser(HTMLParser): def handle_starttag(self, tag, attrs): global TLT, LABELS, PARSE # Set on TLT variable what tag we're in # FIXME: You probably don't want to redefine TLT after # it has been set to tw-passagedata; Instead, you'll want # handle_endtag() to unset this. This is necessary if you plan # in converting scripts with HTML code inside the passages. TLT=tag # A new passage! Lets get its name and pid. if tag == "tw-passagedata": labelname=dl_getkey(attrs, "name") labelid=dl_getkey(attrs, "pid") # Not writing file, lets register the label on the dict if not PARSE: LABELS[labelname]=labelid print("Register label: %s" % labelname) # If we're writing the file, then give it a safe label name else: rpy_file.write("L_%s:\n" % labelid) def handle_endtag(self, tag): global PARSE, INMENU # Ops, seems like we finished the passage! # To prevent implicit fallthroughs, lets call return if tag == "tw-passagedata" and PARSE: if not INMENU: rpy_file.write(" close;\n\n") else: INMENU=False rpy_file.write(";\n") rpy_file.write(" close;\n\n") def handle_data(self, data): global TLT, PARSE if (TLT in ["script", "style"] or not PARSE): # Silently ignore Twine stuff pass else: # We're writing and we're inside a passage, so call parse() on it if (TLT == "tw-passagedata"): parse(data) # Do a dry run. # This is needed to prepare LABELS dictionary parser = MyHTMLParser() parser.feed(txt_file) # Prepare the file PARSE=True parser.feed(txt_file) # Close files we opened open_file.close() rpy_file.close() # Report our success print("Success!")