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