Remove unused error codes.
[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 statedefines = ""
12
13 h_template = """/* Generated from adventure.yaml - do not hand-hack! */
14 #ifndef NEWDB_H
15 #define NEWDB_H
16
17 #include <stdio.h>
18 #include <stdbool.h>
19
20 #define SILENT  -1      /* no sound */
21
22 /* Symbols for cond bits */
23 #define COND_LIT        0       /* Light */
24 #define COND_OILY       1       /* If bit 2 is on: on for oil, off for water */
25 #define COND_FLUID      2       /* Liquid asset, see bit 1 */
26 #define COND_NOARRR     3       /* Pirate doesn't go here unless following */
27 #define COND_NOBACK     4       /* Cannot use "back" to move away */
28 #define COND_ABOVE      5
29 #define COND_DEEP       6       /* Deep - e.g where dwarves are active */
30 #define COND_FOREST     7       /* In the forest */
31 #define COND_FORCED     8       /* Only one way in or out of here */
32 /* Bits past 10 indicate areas of interest to "hint" routines */
33 #define COND_HBASE      10      /* Base for location hint bits */
34 #define COND_HCAVE      11      /* Trying to get into cave */
35 #define COND_HBIRD      12      /* Trying to catch bird */
36 #define COND_HSNAKE     13      /* Trying to deal with snake */
37 #define COND_HMAZE      14      /* Lost in maze */
38 #define COND_HDARK      15      /* Pondering dark room */
39 #define COND_HWITT      16      /* At Witt's End */
40 #define COND_HCLIFF     17      /* Cliff with urn */
41 #define COND_HWOODS     18      /* Lost in forest */
42 #define COND_HOGRE      19      /* Trying to deal with ogre */
43 #define COND_HJADE      20      /* Found all treasures except jade */
44
45 typedef struct {{
46   const char* inventory;
47   bool is_treasure;
48   const char** longs;
49   const char** sounds;
50   const char** texts;
51 }} object_description_t;
52
53 typedef struct {{
54   const char* small;
55   const char* big;
56 }} descriptions_t;
57
58 typedef struct {{
59   descriptions_t description;
60   const long sound;
61   const bool loud;
62 }} location_t;
63
64 typedef struct {{
65   const char* query;
66   const char* yes_response;
67 }} obituary_t;
68
69 typedef struct {{
70   const int threshold;
71   const int point_loss;
72   const char* message;
73 }} turn_threshold_t;
74
75 typedef struct {{
76   const int threshold;
77   const char* message;
78 }} class_t;
79
80 typedef struct {{
81   const int number;
82   const int turns;
83   const int penalty;
84   const char* question;
85   const char* hint;
86 }} hint_t;
87
88 extern const location_t locations[];
89 extern const object_description_t object_descriptions[];
90 extern const const char* arbitrary_messages[];
91 extern const const class_t classes[];
92 extern const turn_threshold_t turn_thresholds[];
93 extern const obituary_t obituaries[];
94 extern const hint_t hints[];
95 extern long conditions[];
96
97 #define NLOCATIONS              {}
98 #define NOBJECTS        {}
99 #define NHINTS          {}
100 #define NCLASSES        {}
101 #define NDEATHS         {}
102 #define NTHRESHOLDS     {}
103
104 enum arbitrary_messages_refs {{
105 {}
106 }};
107
108 enum locations_refs {{
109 {}
110 }};
111
112 enum object_descriptions_refs {{
113 {}
114 }};
115
116 /* State definitions */
117
118 {}
119 #endif /* end NEWDB_H */
120 """
121
122 c_template = """/* Generated from adventure.yaml - do not hand-hack! */
123
124 #include "common.h"
125 #include "{}"
126
127 const char* arbitrary_messages[] = {{
128 {}
129 }};
130
131 const class_t classes[] = {{
132 {}
133 }};
134
135 const turn_threshold_t turn_thresholds[] = {{
136 {}
137 }};
138
139 const location_t locations[] = {{
140 {}
141 }};
142
143 const object_description_t object_descriptions[] = {{
144 {}
145 }};
146
147 const obituary_t obituaries[] = {{
148 {}
149 }};
150
151 const hint_t hints[] = {{
152 {}
153 }};
154
155 long conditions[] = {{
156 {}
157 }};
158
159 /* end */
160 """
161
162 def make_c_string(string):
163     """Render a Python string into C string literal format."""
164     if string == None:
165         return "NULL"
166     string = string.replace("\n", "\\n")
167     string = string.replace("\t", "\\t")
168     string = string.replace('"', '\\"')
169     string = string.replace("'", "\\'")
170     string = '"' + string + '"'
171     return string
172
173 def get_refs(l):
174     reflist = [x[0] for x in l]
175     ref_str = ""
176     for ref in reflist:
177         ref_str += "    {},\n".format(ref)
178     ref_str = ref_str[:-1] # trim trailing newline
179     return ref_str
180
181 def get_arbitrary_messages(arb):
182     template = """    {},
183 """
184     arb_str = ""
185     for item in arb:
186         arb_str += template.format(make_c_string(item[1]))
187     arb_str = arb_str[:-1] # trim trailing newline
188     return arb_str
189
190 def get_class_messages(cls):
191     template = """    {{
192         .threshold = {},
193         .message = {},
194     }},
195 """
196     cls_str = ""
197     for item in cls:
198         threshold = item["threshold"]
199         message = make_c_string(item["message"])
200         cls_str += template.format(threshold, message)
201     cls_str = cls_str[:-1] # trim trailing newline
202     return cls_str
203
204 def get_turn_thresholds(trn):
205     template = """    {{
206         .threshold = {},
207         .point_loss = {},
208         .message = {},
209     }},
210 """
211     trn_str = ""
212     for item in trn:
213         threshold = item["threshold"]
214         point_loss = item["point_loss"]
215         message = make_c_string(item["message"])
216         trn_str += template.format(threshold, point_loss, message)
217     trn_str = trn_str[:-1] # trim trailing newline
218     return trn_str
219
220 def get_locations(loc):
221     template = """    {{
222         .description = {{
223             .small = {},
224             .big = {},
225         }},
226         .sound = {},
227         .loud = {},
228     }},
229 """
230     loc_str = ""
231     for item in loc:
232         short_d = make_c_string(item[1]["description"]["short"])
233         long_d = make_c_string(item[1]["description"]["long"])
234         sound = item[1].get("sound", "SILENT")
235         loud = "true" if item[1].get("loud") else "false"
236         loc_str += template.format(short_d, long_d, sound, loud)
237     loc_str = loc_str[:-1] # trim trailing newline
238     return loc_str
239
240 def get_object_descriptions(obj):
241     template = """    {{
242         .inventory = {},
243         .is_treasure = {},
244         .longs = (const char* []) {{
245 {}
246         }},
247         .sounds = (const char* []) {{
248 {}
249         }},
250         .texts = (const char* []) {{
251 {}
252         }},
253     }},
254 """
255     obj_str = ""
256     for item in obj:
257         i_msg = make_c_string(item[1]["inventory"])
258         longs_str = ""
259         if item[1]["longs"] == None:
260             longs_str = " " * 12 + "NULL,"
261         else:
262             labels = []
263             for l_msg in item[1]["longs"]:
264                 if not isinstance(l_msg, str):
265                     labels.append(l_msg)
266                     l_msg = l_msg[1]
267                 longs_str += " " * 12 + make_c_string(l_msg) + ",\n"
268             longs_str = longs_str[:-1] # trim trailing newline
269             if labels:
270                 global statedefines
271                 statedefines += "/* States for %s */\n" % item[0]
272                 for (i, (label, message)) in enumerate(labels):
273                     if len(message) >= 45:
274                         message = message[:45] + "..."
275                     statedefines += "#define %s\t%d /* %s */\n" % (label, i, message)
276                 statedefines += "\n"
277         sounds_str = ""
278         if item[1].get("sounds") == None:
279             sounds_str = " " * 12 + "NULL,"
280         else:
281              for l_msg in item[1]["sounds"]:
282                  sounds_str += " " * 12 + make_c_string(l_msg) + ",\n"
283              sounds_str = sounds_str[:-1] # trim trailing newline
284         texts_str = ""
285         if item[1].get("texts") == None:
286             texts_str = " " * 12 + "NULL,"
287         else:
288              for l_msg in item[1]["texts"]:
289                  texts_str += " " * 12 + make_c_string(l_msg) + ",\n"
290              texts_str = texts_str[:-1] # trim trailing newline
291         treasure = "true" if item[1].get("treasure") else "false"
292         obj_str += template.format(i_msg, treasure, longs_str, sounds_str, texts_str)
293     obj_str = obj_str[:-1] # trim trailing newline
294     return obj_str
295
296 def get_obituaries(obit):
297     template = """    {{
298         .query = {},
299         .yes_response = {},
300     }},
301 """
302     obit_str = ""
303     for o in obit:
304         query = make_c_string(o["query"])
305         yes = make_c_string(o["yes_response"])
306         obit_str += template.format(query, yes)
307     obit_str = obit_str[:-1] # trim trailing newline
308     return obit_str
309
310 def get_hints(hnt, arb):
311     template = """    {{
312         .number = {},
313         .penalty = {},
314         .turns = {},
315         .question = {},
316         .hint = {},
317     }},
318 """
319     hnt_str = ""
320     md = dict(arb)
321     for member in hnt:
322         item = member["hint"]
323         number = item["number"]
324         penalty = item["penalty"]
325         turns = item["turns"]
326         question = make_c_string(md[item["question"]])
327         hint = make_c_string(md[item["hint"]])
328         hnt_str += template.format(number, penalty, turns, question, hint)
329     hnt_str = hnt_str[:-1] # trim trailing newline
330     return hnt_str
331
332 def get_condbits(locations):
333     cnd_str = ""
334     for (name, loc) in locations:
335         conditions = loc["conditions"]
336         hints = loc.get("hints") or []
337         flaglist = []
338         for flag in conditions:
339             if conditions[flag]:
340                 flaglist.append(flag)
341         line = "|".join([("(1<<COND_%s)" % f) for f in flaglist])
342         trail = "|".join([("(1<<COND_H%s)" % f['name']) for f in hints])
343         if trail:
344             line += "|" + trail
345         if line.startswith("|"):
346             line = line[1:]
347         if not line:
348             line = "0"
349         cnd_str += "    " + line + ",\t// " + name + "\n"
350     return cnd_str
351
352 if __name__ == "__main__":
353     with open(yaml_name, "r") as f:
354         db = yaml.load(f)
355
356     c = c_template.format(
357         h_name,
358         get_arbitrary_messages(db["arbitrary_messages"]),
359         get_class_messages(db["classes"]),
360         get_turn_thresholds(db["turn_thresholds"]),
361         get_locations(db["locations"]),
362         get_object_descriptions(db["object_descriptions"]),
363         get_obituaries(db["obituaries"]),
364         get_hints(db["hints"], db["arbitrary_messages"]),
365         get_condbits(db["locations"]),
366     )
367
368     h = h_template.format(
369         len(db["locations"]),
370         len(db["object_descriptions"]),
371         len(db["hints"]),
372         len(db["classes"]),
373         len(db["obituaries"]),
374         len(db["turn_thresholds"]),
375         get_refs(db["arbitrary_messages"]),
376         get_refs(db["locations"]),
377         get_refs(db["object_descriptions"]),
378         statedefines,
379     )
380
381     with open(h_name, "w") as hf:
382         hf.write(h)
383
384     with open(c_name, "w") as cf:
385         cf.write(c)
386
387 # end