Refactored dungeon generator.
[open-adventure.git] / newdungeon.py
1 #!/usr/bin/python3
2
3 # 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.
4
5 import yaml
6
7 yaml_name = "adventure.yaml"
8 h_name = "newdb.h"
9 c_name = "newdb.c"
10
11 h_template = """#include <stdio.h>
12
13 typedef struct {{
14   const char* inventory;
15   const char** longs;
16 }} object_description_t;
17
18 typedef struct {{
19   const char* small;
20   const char* big;
21 }} descriptions_t;
22
23 typedef struct {{
24   descriptions_t description;
25 }} location_t;
26
27 typedef struct {{
28   const char* query;
29   const char* yes_response;
30 }} obituary_t;
31
32 extern location_t locations[];
33 extern object_description_t object_descriptions[];
34 extern const char* arbitrary_messages[];
35 extern const char* class_messages[];
36 extern const char* turn_threshold_messages[];
37 extern obituary_t obituaries[];
38
39 extern size_t CLSSES;
40 extern int maximum_deaths;
41
42 enum arbitrary_messages_refs {{
43 {}
44 }};
45
46 enum class_messages_refs {{
47 {}
48 }};
49
50 enum turn_threshold_messages_refs {{
51 {}
52 }};
53
54 enum locations_refs {{
55 {}
56 }};
57
58 enum object_descriptions_refs {{
59 {}
60 }};
61 """
62
63 c_template = """#include "{}"
64
65 const char* arbitrary_messages[] = {{
66 {}
67 }};
68
69 const char* class_messages[] = {{
70 {}
71 }};
72
73 const char* turn_threshold_messages[] = {{
74 {}
75 }};
76
77 location_t locations[] = {{
78 {}
79 }};
80
81 object_description_t object_descriptions[] = {{
82 {}
83 }};
84
85 obituary_t obituaries[] = {{
86 {}
87 }};
88
89 size_t CLSSES = {};
90 int maximum_deaths = {};
91 """
92
93 def make_c_string(string):
94     """Render a Python string into C string literal format."""
95     if string == None:
96         return "NULL"
97     string = string.replace("\n", "\\n")
98     string = string.replace("\t", "\\t")
99     string = string.replace('"', '\\"')
100     string = string.replace("'", "\\'")
101     string = '"' + string + '"'
102     return string
103
104 def get_refs(l):
105     reflist = [x[0] for x in l]
106     ref_str = ""
107     for ref in reflist:
108         ref_str += "    {},\n".format(ref)
109     ref_str = ref_str[:-1] # trim trailing newline
110     return ref_str
111
112 def get_arbitrary_messages(arb):
113     template = """    {},
114 """
115     arb_str = ""
116     for item in arb:
117         arb_str += template.format(make_c_string(item[1]))
118     arb_str = arb_str[:-1] # trim trailing newline
119     return arb_str
120
121 def get_class_messages(cls):
122     template = """    {},
123 """
124     cls_str = ""
125     for item in cls:
126         cls_str += template.format(make_c_string(item[1]))
127     cls_str = cls_str[:-1] # trim trailing newline
128     return cls_str    
129
130 def get_turn_threshold_messages(trn):
131     template = """    {},
132 """
133     trn_str = ""
134     for item in trn:
135         trn_str += template.format(make_c_string(item[1]))
136     trn_str = trn_str[:-1] # trim trailing newline
137     return trn_str
138
139 def get_locations(loc):
140     template = """    {{
141         .description = {{
142             .small = {},
143             .big = {},
144         }},
145     }},
146 """
147     loc_str = ""
148     for item in loc:
149         short_d = make_c_string(item[1]["description"]["short"])
150         long_d = make_c_string(item[1]["description"]["long"])
151         loc_str += template.format(short_d, long_d)
152     loc_str = loc_str[:-1] # trim trailing newline
153     return loc_str
154
155 def get_object_descriptions(obj):
156     template = """    {{
157         .inventory = {},
158         .longs = (const char* []) {{
159 {}
160         }},
161     }},
162 """
163     obj_str = ""
164     for item in obj:
165         i_msg = make_c_string(item[1]["inventory"])
166         longs_str = ""
167         if item[1]["longs"] == None:
168             longs_str = " " * 12 + "NULL,"
169         else:
170             for l_msg in item[1]["longs"]:
171                 longs_str += " " * 12 + make_c_string(l_msg) + ",\n"
172             longs_str = longs_str[:-1] # trim trailing newline
173         obj_str += template.format(i_msg, longs_str)
174     obj_str = obj_str[:-1] # trim trailing newline
175     return obj_str
176
177 def get_obituaries(obit):
178     template = """    {{
179         .query = {},
180         .yes_response = {},
181     }},
182 """
183     obit_str = ""
184     for o in obit:
185         query = make_c_string(o["query"])
186         yes = make_c_string(o["yes_response"])
187         obit_str += template.format(query, yes)
188     obit_str = obit_str[:-1] # trim trailing newline
189     return obit_str
190
191 with open(yaml_name, "r") as f:
192     db = yaml.load(f)
193
194 h = h_template.format(
195     get_refs(db["arbitrary_messages"]),
196     get_refs(db["class_messages"]),
197     get_refs(db["turn_threshold_messages"]),
198     get_refs(db["locations"]),
199     get_refs(db["object_descriptions"]),
200 )
201
202 c = c_template.format(
203     h_name,
204     get_arbitrary_messages(db["arbitrary_messages"]),
205     get_class_messages(db["class_messages"]),
206     get_turn_threshold_messages(db["turn_threshold_messages"]),
207     get_locations(db["locations"]),
208     get_object_descriptions(db["object_descriptions"]),
209     get_obituaries(db["obituaries"]),
210     len(db["class_messages"]),
211     len(db["obituaries"]),
212 )
213
214 with open(h_name, "w") as hf:
215     hf.write(h)
216
217 with open(c_name, "w") as cf:
218     cf.write(c)