Abolish HNTMAX and HNTSIZ in favor of HINT_COUNT.
[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 = """/* Generated from adventure.yaml - do not hand-hack! */
12 #ifndef NEWDB_H
13 #define NEWDB_H
14
15 #include <stdio.h>
16
17 typedef struct {{
18   const char* inventory;
19   const char** longs;
20 }} object_description_t;
21
22 typedef struct {{
23   const char* small;
24   const char* big;
25 }} descriptions_t;
26
27 typedef struct {{
28   descriptions_t description;
29 }} location_t;
30
31 typedef struct {{
32   const char* query;
33   const char* yes_response;
34 }} obituary_t;
35
36 typedef struct {{
37   const int threshold;
38   const int point_loss;
39   const char* message;
40 }} turn_threshold_t;
41
42 typedef struct {{
43   const int threshold;
44   const char* message;
45 }} class_t;
46
47 typedef struct {{
48   const int number;
49   const int turns;
50   const int penalty;
51   const char* question;
52   const char* hint;
53 }} hint_t;
54
55 extern location_t locations[];
56 extern object_description_t object_descriptions[];
57 extern const char* arbitrary_messages[];
58 extern const class_t classes[];
59 extern turn_threshold_t turn_thresholds[];
60 extern obituary_t obituaries[];
61 extern hint_t hints[];
62
63 extern const size_t CLSSES;
64 extern const int maximum_deaths;
65 extern const int turn_threshold_count;
66 #define HINT_COUNT {}
67
68 enum arbitrary_messages_refs {{
69 {}
70 }};
71
72 enum locations_refs {{
73 {}
74 }};
75
76 enum object_descriptions_refs {{
77 {}
78 }};
79
80 #endif /* end NEWDB_H */
81 """
82
83 c_template = """/* Generated from adventure.yaml - do not hand-hack! */
84
85 #include "{}"
86
87 const char* arbitrary_messages[] = {{
88 {}
89 }};
90
91 const class_t classes[] = {{
92 {}
93 }};
94
95 turn_threshold_t turn_thresholds[] = {{
96 {}
97 }};
98
99 location_t locations[] = {{
100 {}
101 }};
102
103 object_description_t object_descriptions[] = {{
104 {}
105 }};
106
107 obituary_t obituaries[] = {{
108 {}
109 }};
110
111 hint_t hints[] = {{
112 {}
113 }};
114
115 const size_t CLSSES = {};
116 const int maximum_deaths = {};
117 const int turn_threshold_count = {};
118
119 /* end */
120 """
121
122 def make_c_string(string):
123     """Render a Python string into C string literal format."""
124     if string == None:
125         return "NULL"
126     string = string.replace("\n", "\\n")
127     string = string.replace("\t", "\\t")
128     string = string.replace('"', '\\"')
129     string = string.replace("'", "\\'")
130     string = '"' + string + '"'
131     return string
132
133 def get_refs(l):
134     reflist = [x[0] for x in l]
135     ref_str = ""
136     for ref in reflist:
137         ref_str += "    {},\n".format(ref)
138     ref_str = ref_str[:-1] # trim trailing newline
139     return ref_str
140
141 def get_arbitrary_messages(arb):
142     template = """    {},
143 """
144     arb_str = ""
145     for item in arb:
146         arb_str += template.format(make_c_string(item[1]))
147     arb_str = arb_str[:-1] # trim trailing newline
148     return arb_str
149
150 def get_class_messages(cls):
151     template = """    {{
152         .threshold = {},
153         .message = {},
154     }},
155 """
156     cls_str = ""
157     for item in cls:
158         threshold = item["threshold"]
159         message = make_c_string(item["message"])
160         cls_str += template.format(threshold, message)
161     cls_str = cls_str[:-1] # trim trailing newline
162     return cls_str
163
164 def get_turn_thresholds(trn):
165     template = """    {{
166         .threshold = {},
167         .point_loss = {},
168         .message = {},
169     }},
170 """
171     trn_str = ""
172     for item in trn:
173         threshold = item["threshold"]
174         point_loss = item["point_loss"]
175         message = make_c_string(item["message"])
176         trn_str += template.format(threshold, point_loss, message)
177     trn_str = trn_str[:-1] # trim trailing newline
178     return trn_str
179
180 def get_locations(loc):
181     template = """    {{
182         .description = {{
183             .small = {},
184             .big = {},
185         }},
186     }},
187 """
188     loc_str = ""
189     for item in loc:
190         short_d = make_c_string(item[1]["description"]["short"])
191         long_d = make_c_string(item[1]["description"]["long"])
192         loc_str += template.format(short_d, long_d)
193     loc_str = loc_str[:-1] # trim trailing newline
194     return loc_str
195
196 def get_object_descriptions(obj):
197     template = """    {{
198         .inventory = {},
199         .longs = (const char* []) {{
200 {}
201         }},
202     }},
203 """
204     obj_str = ""
205     for item in obj:
206         i_msg = make_c_string(item[1]["inventory"])
207         longs_str = ""
208         if item[1]["longs"] == None:
209             longs_str = " " * 12 + "NULL,"
210         else:
211             for l_msg in item[1]["longs"]:
212                 longs_str += " " * 12 + make_c_string(l_msg) + ",\n"
213             longs_str = longs_str[:-1] # trim trailing newline
214         obj_str += template.format(i_msg, longs_str)
215     obj_str = obj_str[:-1] # trim trailing newline
216     return obj_str
217
218 def get_obituaries(obit):
219     template = """    {{
220         .query = {},
221         .yes_response = {},
222     }},
223 """
224     obit_str = ""
225     for o in obit:
226         query = make_c_string(o["query"])
227         yes = make_c_string(o["yes_response"])
228         obit_str += template.format(query, yes)
229     obit_str = obit_str[:-1] # trim trailing newline
230     return obit_str
231
232 def get_hints(hnt, arb):
233     template = """    {{
234         .number = {},
235         .penalty = {},
236         .turns = {},
237         .question = {},
238         .hint = {},
239     }},
240 """
241     hnt_str = ""
242     md = dict(arb)
243     for item in hnt:
244         number = item["number"]
245         penalty = item["penalty"]
246         turns = item["turns"]
247         question = make_c_string(md[item["question"]])
248         hint = make_c_string(md[item["hint"]])
249         hnt_str += template.format(number, penalty, turns, question, hint)
250     hnt_str = hnt_str[:-1] # trim trailing newline
251     return hnt_str
252
253
254 if __name__ == "__main__":
255     with open(yaml_name, "r") as f:
256         db = yaml.load(f)
257
258     h = h_template.format(
259         len(db["hints"]),
260         get_refs(db["arbitrary_messages"]),
261         get_refs(db["locations"]),
262         get_refs(db["object_descriptions"]),
263     )
264
265     c = c_template.format(
266         h_name,
267         get_arbitrary_messages(db["arbitrary_messages"]),
268         get_class_messages(db["classes"]),
269         get_turn_thresholds(db["turn_thresholds"]),
270         get_locations(db["locations"]),
271         get_object_descriptions(db["object_descriptions"]),
272         get_obituaries(db["obituaries"]),
273         get_hints(db["hints"], db["arbitrary_messages"]),
274         len(db["classes"]),
275         len(db["obituaries"]),
276         len(db["turn_thresholds"]),
277     )
278
279     with open(h_name, "w") as hf:
280         hf.write(h)
281
282     with open(c_name, "w") as cf:
283         cf.write(c)
284
285 # end