X-Git-Url: https://jxself.org/git/?p=open-adventure.git;a=blobdiff_plain;f=make_dungeon.py;h=03b5b04229fc60023a378208cc8525fb8873bb97;hp=e7e37ae2c6baeaa23177901de65824468e45d0c5;hb=e8a627f964a8337caf0c71dd87b1d7533f489f57;hpb=e05f959974ec2802362d25b8305a26e58d14a753 diff --git a/make_dungeon.py b/make_dungeon.py index e7e37ae..03b5b04 100755 --- a/make_dungeon.py +++ b/make_dungeon.py @@ -1,48 +1,11 @@ -#!/usr/bin/python3 +#!/usr/bin/env python -# This is the new open-adventure dungeon generator. It'll eventually -# replace the existing dungeon.c It currently outputs a .h and .c pair -# for C code. +# This is the open-adventure dungeon generator. It consumes a YAML description of +# the dungeon and outputs a dungeon.h and dungeon.c pair of C code files. # # The nontrivial part of this is the compilation of the YAML for # movement rules to the travel array that's actually used by -# playermove(). This program first compiles the YAML to a form -# identical to the data in section 3 of the old adventure.text file, -# then a second stage unpacks that data into the travel array. -# -# Here are the rules of the intermediate form: -# -# Each row of data contains a location number (X), a second -# location number (Y), and a list of motion numbers (see section 4). -# each motion represents a verb which will go to Y if currently at X. -# Y, in turn, is interpreted as follows. Let M=Y/1000, N=Y mod 1000. -# If N<=300 it is the location to go to. -# If 300500 message N-500 from section 6 is printed, -# and he stays wherever he is. -# Meanwhile, M specifies the conditions on the motion. -# If M=0 it's unconditional. -# If 0= 45: - message = message[:45] + "..." - statedefines += "#define %s\t%d /* %s */\n" % (label, i, message) + for (j, label) in enumerate(labels): + statedefines += "#define %s\t%d\n" % (label, j) statedefines += "\n" sounds_str = "" if attr.get("sounds") == None: @@ -447,14 +398,12 @@ def get_objects(obj): immovable = attr.get("immovable", False) try: if type(locs) == str: - locs = [locnames.index(locs), -1 if immovable else 0] - else: - locs = [locnames.index(x) for x in locs] + locs = [locs, -1 if immovable else 0] except IndexError: sys.stderr.write("dungeon: unknown object location in %s\n" % locs) sys.exit(1) treasure = "true" if attr.get("treasure") else "false" - obj_str += template.format(i, words_str, i_msg, locs[0], locs[1], treasure, descriptions_str, sounds_str, texts_str, changes_str) + obj_str += template.format(i, item[0], words_str, i_msg, locs[0], locs[1], treasure, descriptions_str, sounds_str, texts_str, changes_str) obj_str = obj_str[:-1] # trim trailing newline return obj_str @@ -538,40 +487,12 @@ def get_actions(actions): template = """ {{ .words = {}, .message = {}, + .noaction = {}, }}, """ act_str = "" for action in actions: contents = action[1] - - if contents["words"] == None: - words_str = get_string_group([]) - else: - words_str = get_string_group(contents["words"]) - - if contents["message"] == None: - message = "NO_MESSAGE" - else: - message = contents["message"] - - act_str += template.format(words_str, message) - global ignore - if contents.get("oldstyle", True) == False: - for word in contents["words"]: - if len(word) == 1: - ignore += word.upper() - act_str = act_str[:-1] # trim trailing newline - return act_str - -def get_specials(specials): - template = """ {{ - .words = {}, - .message = {}, - }}, -""" - spc_str = "" - for special in specials: - contents = special[1] if contents["words"] == None: words_str = get_string_group([]) @@ -583,14 +504,19 @@ def get_specials(specials): else: message = make_c_string(contents["message"]) - spc_str += template.format(words_str, message) + if contents.get("noaction") == None: + noaction = "false" + else: + noaction = "true" + + act_str += template.format(words_str, message, noaction) global ignore if contents.get("oldstyle", True) == False: for word in contents["words"]: if len(word) == 1: ignore += word.upper() - spc_str = spc_str[:-1] # trim trailing newline - return spc_str + act_str = act_str[:-1] # trim trailing newline + return act_str def bigdump(arr): out = "" @@ -604,6 +530,51 @@ def bigdump(arr): return out def buildtravel(locs, objs): + assert len(locs) <= 300 + assert len(objs) <= 100 + # THIS CODE IS WAAAY MORE COMPLEX THAN IT NEEDS TO BE. It's the + # result of a massive refactoring exercise that concentrated all + # the old nastiness in one spot. It hasn't been finally simplified + # because there's no need to do it until one of the asserions + # fails. Hint: if you try cleaning this up, the acceptance test is + # simple - the output dungeon.c must not change. + # + # This function first compiles the YAML to a form identical to the + # data in section 3 of the old adventure.text file, then a second + # stage unpacks that data into the travel array. Here are the + # rules of that intermediate form: + # + # Each row of data contains a location number (X), a second + # location number (Y), and a list of motion numbers (see section 4). + # each motion represents a verb which will go to Y if currently at X. + # Y, in turn, is interpreted as follows. Let M=Y/1000, N=Y mod 1000. + # If N<=300 it is the location to go to. + # If 300500 message N-500 from section 6 is printed, + # and he stays wherever he is. + # Meanwhile, M specifies the conditions on the motion. + # If M=0 it's unconditional. + # If 0 500: + desttype = "dest_speak"; + destval = msgnames[dest - 500] + else: + desttype = "dest_special"; + destval = locnames[dest - 300] + travel.append([len(tkey)-1, + locnames[len(tkey)-1], + rule.pop(0), + condtype, + condarg1, + condarg2, + desttype, + destval, + "true" if nodwarves else "false", + "false"]) + travel[-1][-1] = "true" return (travel, tkey) def get_travel(travel): - template = """ {{ + template = """ {{ // from {}: {} .motion = {}, - .cond = {}, - .dest = {}, + .condtype = {}, + .condarg1 = {}, + .condarg2 = {}, + .desttype = {}, + .destval = {}, + .nodwarves = {}, .stop = {}, }}, """ out = "" for entry in travel: - out += template.format(entry[0], entry[1], entry[2], entry[3]).lower() + out += template.format(*entry) out = out[:-1] # trim trailing newline return out @@ -742,6 +744,7 @@ if __name__ == "__main__": locnames = [x[0] for x in db["locations"]] msgnames = [el[0] for el in db["arbitrary_messages"]] objnames = [el[0] for el in db["objects"]] + motionnames = [el[0] for el in db["motions"]] (travel, tkey) = buildtravel(db["locations"], db["objects"]) @@ -758,12 +761,15 @@ if __name__ == "__main__": get_condbits(db["locations"]), get_motions(db["motions"]), get_actions(db["actions"]), - get_specials(db["specials"]), bigdump(tkey), get_travel(travel), ignore, ) + # 0-origin index of birds's last song. Bird should + # die after player hears this. + deathbird = len(dict(db["objects"])["BIRD"]["sounds"]) - 1 + h = h_template.format( len(db["locations"])-1, len(db["objects"])-1, @@ -773,15 +779,14 @@ if __name__ == "__main__": len(db["turn_thresholds"]), len(db["motions"]), len(db["actions"]), - len(db["specials"]), len(travel), len(tkey), + deathbird, get_refs(db["arbitrary_messages"]), get_refs(db["locations"]), get_refs(db["objects"]), get_refs(db["motions"]), get_refs(db["actions"]), - get_refs(db["specials"]), statedefines, )