Improve test coverage.
[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 import sys
7
8 yaml_name = "adventure.yaml"
9 h_name = "newdb.h"
10 c_name = "newdb.c"
11
12 def c_escape(string):
13     """Add C escape sequences to a string."""
14     string = string.replace("\n", "\\n")
15     string = string.replace("\t", "\\t")
16     string = string.replace('"', '\\"')
17     string = string.replace("'", "\\'")
18     return string
19
20 def quotewrap(string):
21     """Wrap a string in double quotes."""
22     return '"' + string + '"'
23
24 def write_regular_messages(name, h, c):
25
26     h += "enum {}_refs {{\n".format(name)
27     for key, text in dungeon[name]:
28         h += "  {},\n".format(key)
29     h += "};\n\n"
30     
31     c += "const char* {}[] = {{\n".format(name)   
32     index = 0
33     for key, text in dungeon[name]:
34         if text == None:
35             c += "  NULL,\n"
36         else:
37             text = c_escape(text)
38             c += "  \"{}\",\n".format(text)
39         index += 1
40     c += "};\n\n"
41     
42     return (h, c)
43
44 with open(yaml_name, "r") as f:
45     dungeon = yaml.load(f)
46
47 h = """#include <stdio.h>
48
49 typedef struct {
50   const char* inventory;
51   const char** longs;
52 } object_description_t;
53
54 typedef struct {
55   const char* small;
56   const char* big;
57 } descriptions_t;
58
59 typedef struct {
60   descriptions_t description;
61 } location_t;
62
63 extern location_t locations[];
64 extern object_description_t object_descriptions[];
65 extern const char* arbitrary_messages[];
66 extern const char* class_messages[];
67 extern const char* turn_threshold_messages[];
68
69 extern size_t CLSSES;
70
71 """
72
73 c = """#include "{}"
74
75 """.format(h_name)
76
77 for name in [
78         "arbitrary_messages",
79         "class_messages",
80         "turn_threshold_messages",
81 ]:
82     h, c = write_regular_messages(name, h, c)
83
84 h += "enum locations_refs {\n"
85 c += "location_t locations[] = {\n"
86 for key, data in dungeon["locations"]:
87     h += "  {},\n".format(key)
88
89     try:
90         short = quotewrap(c_escape(data["description"]["short"]))
91     except AttributeError:
92         short = "NULL"
93     try:
94         long = quotewrap(c_escape(data["description"]["long"]))
95     except AttributeError:
96         long = "NULL"
97
98     c += """  {{
99     .description = {{
100       .small = {},
101       .big = {},
102     }},
103   }},
104 """.format(short, long)
105
106 c += "};\n\n"
107 h += "};\n\n"
108
109 h += "enum object_descriptions_refs {\n"
110 c += "object_description_t object_descriptions[] = {\n"
111 for key, data in dungeon["object_descriptions"]:
112     try:
113         data["inventory"] = "\"{}\"".format(c_escape(data["inventory"]))
114     except AttributeError:
115         data["inventory"] = "NULL"
116     h += "  {},\n".format(key)
117     c += "  {\n"
118     c += "    .inventory = {},\n".format(data["inventory"])
119     try:
120         data["longs"][0]
121         c += "    .longs = (const char* []) {\n"
122         for l in data["longs"]:
123             l = c_escape(l)
124             c += "      \"{}\",\n".format(l)
125         c += "    },\n"
126     except (TypeError, IndexError):
127         c += "    .longs = NULL,\n"
128     c += "  },\n"
129 h += "};"
130 c += "};"
131
132 c += """
133 size_t CLSSES = {};
134 """.format(len(dungeon["class_messages"]))
135
136 # finally, write out the files
137 d = {
138     h_name: h,
139     c_name: c,
140 }
141 for filename, string in d.items():
142     with open(filename, "w") as f:
143         f.write(string)
144