Use the older "pragma" style of charset declaration for compatibility.
Use the older "pragma" style of charset declaration for compatibility.

File last commit:

4e0d93c1f71c
bb150f598011
Show More
genweb.py
319 lines | 9.4 KiB | text/x-python | PythonLexer
#!/usr/bin/env python
"""
Generate HTML from a subset of rpy
"""
import fileinput
import sys
quick_help_text = """
This is a 'kinetic visual novel'. To advance in the<br>
story, just click the screen. There are no decisions<br>
to make, items to collect, or minigames to play.
"""
container_text = """
<!doctype html>
<html>
<head>
<title>{title}</title>
<link rel="stylesheet" href="fullscreen.css">
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
<div class="viewport-container">
<iframe src="{filename}#frame_0" seamless="true"></iframe>
</div>
</body>
</html>
"""
header = """
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="vn.css">
<link rel="stylesheet" href="scenes.css">
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
<div class="viewport">
"""
character_names = ['pirogoeth']
images_used = [
"assets/character/pirogoeth/pirogoeth_pfront_crouching_m0.png",
"assets/character/pirogoeth/pirogoeth_pfront_crouching_m1.png",
"assets/character/pirogoeth/pirogoeth_pfront_lungingclose_m1.png",
"assets/character/pirogoeth/pirogoeth_pfront_lunging_m1.png",
"assets/character/pirogoeth/pirogoeth_pfront_nonplussed_m0.png",
"assets/character/pirogoeth/pirogoeth_pfront_nonplussed_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headdown_lookingaside_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headdown_lookingaside_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headdown_lookingfront_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headdown_lookingfront_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingaside_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingaside_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingfront_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingfront_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraightangry_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraight_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraight_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraightsadface_m1.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraightwideeyed_m0.png",
"assets/character/pirogoeth/pirogoeth_pleft_headstraight_lookingstraightwideeyed_m1.png",
"assets/character/pirogoeth/pirogoeth_pright_lookingoff_m1.png",
"assets/character/pirogoeth/pirogoeth_pright_lookingup_m0.png",
"assets/character/pirogoeth/pirogoeth_pright_lookingup_m1.png",
"assets/character/pirogoeth/pirogoeth_pright_turning_m0.png",
"assets/character/pirogoeth/pirogoeth_pright_turning_m1.png",
"assets/background/market_empty.jpg",
"assets/background/market_busy.jpg",
"assets/background/flashback/flashbackCamping.jpg",
"assets/background/flashback/flashbackDancing.jpg",
"assets/background/flashback/flashbackDarkBG.png",
"assets/background/flashback/flashbackDomina.jpg",
"assets/background/flashback/flashbackEscaping.jpg",
"assets/background/flashback/flashbackFalling.jpg",
"assets/background/flashback/flashbackHunting.jpg",
]
next_classes = None
scene = "black"
frame_count = 0
characters = {}
expressions = []
last_content = ""
last_scene = ""
last_expression = ""
audio_background = None
output_buffer = ''
current_file_num = 0
def format_filename(file_num):
t = fileinput.filename().replace('.webvn','')
if file_num != -1:
t += '_' + str(file_num)
t += '.htm'
return t
def output_append(string):
global output_buffer
output_buffer += string
def output_buffer_write(name):
global output_buffer
output_buffer = output_buffer.replace('_XXX_','')
with open(name, 'w') as out:
out.write(output_buffer)
output_buffer = ''
def output_replace_last_link(new_target):
global output_buffer
parts = output_buffer.split('_XXX_')
x = parts[:-1]
output_buffer = "_XXX_".join(x) + new_target + parts[-1]
def next_file():
global current_file_num
print_preload()
print_footer()
output_buffer_write(format_filename(current_file_num))
current_file_num += 1
output_append(header)
def wordbox(text):
return """
<div class="wordbox">
<div class="wordbox-content">
{0}
</div>
</div>
""".format(text)
def wordbubble(text):
return """
<div class="wordbubble">
<div class="wordbubble-content">
{0}
</div>
</div>
""".format(text)
def whitetext(text):
global scene
if scene != "black": return wordbox(text)
line_map = { 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five' }
line_count = len(text.splitlines())
return """
<div class="centered-white-text vertical-{0}-line">
{1}
</div>
""".format(line_map[line_count] if line_count in line_map else "one", text)
def switch_mouth(character, newmouth):
if '_m1' in characters[character]['pose']:
characters[character]['pose'] = characters[character]['pose'].replace('_m1','_'+newmouth)
elif '_m0' in characters[character]['pose']:
characters[character]['pose'] = characters[character]['pose'].replace('_m0','_'+newmouth)
def switch_pose(character, newpose):
if '_m1' in characters[character]['pose']:
characters[character]['pose'] = newpose + '_m1'
elif '_m0' in characters[character]['pose']:
characters[character]['pose'] = newpose + '_m0'
def characterbubble(character, text):
if text.startswith('"'): text = "m0 " + text
mouth, _, text = text.partition(" ")
if not (mouth == 'm1' or mouth == 'm0'):
switch_pose(character, mouth)
mouth, _, text = text.partition(" ")
text = eval(text)
switch_mouth(character, mouth)
return """
<div class="wordbubble-character">
<div class="wordbubble-content">
{0}
</div>
</div>
""".format(text)
def character(name, extra=None):
attributes = characters[name]
return """
<div class="{2}-character">
<img class="{0}" src="assets/character/{0}/{0}_{1}.png">
</div>
""".format(name, attributes['pose'], attributes['position'])
def make_expression(expression):
return """<div class="overlay {0}"></div>""".format(expression)
def stage(contents):
global scene, next_classes, characters, expressions, last_content, last_scene, last_expression
chars = ""
for k,v in characters.iteritems():
chars += character(k)
extra_classes = "scene-{0}".format(scene if scene else "black")
my_expressions = "\n".join([make_expression(x) for x in expressions])
out = """
<div class="stage {3}">
{4}
{7}
</div>
<div class="stage {0} {5}">
{1}
{6}
{2}
</div>
""".format(extra_classes, chars, "\n".join(contents), last_scene, last_content, next_classes if next_classes else "fade-in", my_expressions, last_expression)
last_content = chars + "\n".join(contents)
last_scene = extra_classes
last_expression = my_expressions
return out
def print_frame(content):
global frame_count
frame_count += 1
output_append("""
<div class="frame" id="frame_{1}">
{0}
<a target="_self" class="framelink" href="_XXX_#frame_{2}"></a>
</div>
""".format(content.strip(), frame_count - 1, frame_count))
def process(line):
global scene, next_classes, characters, expressions, audio_background
c, _, rest = line.strip().partition(" ")
if c == "#WEB:":
c, _, rest = rest.strip().partition(" ")
if line.strip().startswith('"'):
print_frame(stage([whitetext(eval(line.strip()))]))
elif c == "class":
next_classes = rest
elif c == "expression":
expressions = rest.split(" ")
elif c == "moh":
print_frame(stage([wordbubble(eval(rest))]))
elif c == "pirogoeth":
print_frame(stage([characterbubble("pirogoeth", rest)]))
elif c == "scene":
scene = rest.split()[-1]
characters.clear()
del expressions[:]
elif c == "pause":
# Can't pause, can insert an interstitial
print_frame(stage(["<!-- blank interstitial -->"]))
elif c == "show":
character = rest.split()[0].replace(":","")
if character not in character_names:
print >>sys.stderr, "Unknown character:", character
return
if character not in characters:
characters[character] = {'pose': None, 'position': 'center'}
attributes = rest.split()[1:]
if len(attributes) == 1 and attributes[0] == 'm1':
switch_mouth(character, 'm1')
return
if len(attributes) == 1 and attributes[0] == 'm0':
switch_mouth(character, 'm0')
return
if len(attributes) == 1 and not (attributes[0].endswith('_m1') or attributes[0].endswith('_m0')):
switch_pose(character, attributes[0])
return
if len(attributes) > 0:
characters[character]['pose'] = attributes[0]
if len(attributes) > 1:
characters[character]['position'] = attributes[1]
elif c == "hide":
character = rest.split()[0]
if character in characters:
del charactersc[character]
elif c == "music":
output_replace_last_link(format_filename(current_file_num + 1))
next_file()
if rest.split()[0] == 'stop':
audio_background = None
else:
audio_background = eval(rest)
def print_footer():
output_append("\n </div>\n")
if audio_background:
output_append("""
<audio autoplay="autoplay" loop="loop" src="{audio}" />
""".format(audio=audio_background))
output_append("""
</body>
</html>
""")
def print_preload():
output_append("""
</div>
<div id="preload">
{0}
""".format("\n".join(['<img src="{0}" width="1" height="1">'.format(x) for x in images_used])))
if __name__ == "__main__":
output_append(header)
scene = 'black'
text = whitetext(quick_help_text)
scene = 'splash'
expressions = ['screen-color-80']
print_frame(stage([text]))
for line in fileinput.input():
process(line)
next_file()
with open(format_filename(-1), 'w') as f:
f.write(container_text.format(title="Endgames: Persistance", filename=format_filename(0)))