jumprun_tile als packed struct für mehr Speicher.
[hackover2013-badge-firmware.git] / mock / tools / level-converter.cc
1 extern "C" {
2 #include <jumpnrun/levels.h>
3 #include <jumpnrun/items.h>
4 #include <jumpnrun/tiles.h>
5 #include <jumpnrun/enemies.h>
6 }
7
8 #include <boost/spirit/include/qi_symbols.hpp>
9
10 #include <algorithm>
11 #include <fstream>
12 #include <iostream>
13 #include <map>
14 #include <numeric>
15 #include <sstream>
16 #include <stdexcept>
17 #include <string>
18 #include <vector>
19
20 enum {
21 LEVEL_LINE_COUNT = 14
22 };
23
24 #define PATH_PREFIX "../badge/jumpnrun/"
25
26 namespace jnrcpp {
27 struct descriptors {
28 descriptors() {
29 tiles.add
30 ("tube_top_left" , JUMPNRUN_TILE_TYPE_TUBE_TOP_LEFT )
31 ("tube_top_right", JUMPNRUN_TILE_TYPE_TUBE_TOP_RIGHT)
32 ("tube_left" , JUMPNRUN_TILE_TYPE_TUBE_LEFT )
33 ("tube_right" , JUMPNRUN_TILE_TYPE_TUBE_RIGHT )
34 ("brick" , JUMPNRUN_TILE_TYPE_BRICK )
35 ("square" , JUMPNRUN_TILE_TYPE_SQUARE )
36 ("spike_up" , JUMPNRUN_TILE_TYPE_SPIKE_UP )
37 ("spike_right" , JUMPNRUN_TILE_TYPE_SPIKE_RIGHT )
38 ("spike_down" , JUMPNRUN_TILE_TYPE_SPIKE_DOWN )
39 ("spike_left" , JUMPNRUN_TILE_TYPE_SPIKE_LEFT )
40 ;
41
42 items.add
43 ("doc" , JUMPNRUN_ITEM_TYPE_DOCUMENT )
44 ("checkpoint" , JUMPNRUN_ITEM_TYPE_CHECKPOINT )
45 ("key" , JUMPNRUN_ITEM_TYPE_KEY )
46 ("doc_encrypted", JUMPNRUN_ITEM_TYPE_ENCRYPTED_DOCUMENT)
47 ;
48
49 enemies.add
50 ("cat" , JUMPNRUN_ENEMY_TYPE_CAT )
51 ("mushroom" , JUMPNRUN_ENEMY_TYPE_MUSHROOM )
52 ("bunny" , JUMPNRUN_ENEMY_TYPE_BUNNY )
53 ("kaninchen" , JUMPNRUN_ENEMY_TYPE_BUNNY ) // legacy
54 ("snake" , JUMPNRUN_ENEMY_TYPE_SNAKE )
55 ("spiral" , JUMPNRUN_ENEMY_TYPE_SPIRAL )
56 ("rotor" , JUMPNRUN_ENEMY_TYPE_ROTOR )
57 ("dog" , JUMPNRUN_ENEMY_TYPE_DOG )
58 ("giraffe" , JUMPNRUN_ENEMY_TYPE_GIRAFFE )
59 ("bird" , JUMPNRUN_ENEMY_TYPE_BIRD )
60 ("bird_straight", JUMPNRUN_ENEMY_TYPE_BIRD_STRAIGHT)
61 ("bird_dip" , JUMPNRUN_ENEMY_TYPE_BIRD_DIP )
62 ;
63 }
64
65 boost::spirit::qi::symbols<char, unsigned> tiles;
66 boost::spirit::qi::symbols<char, unsigned> items;
67 boost::spirit::qi::symbols<char, unsigned> enemies;
68 } const desc;
69
70 struct level_name_map {
71 level_name_map() {
72 std::ifstream in(PATH_PREFIX "levels.txt");
73
74 if(!in) {
75 throw std::logic_error(PATH_PREFIX "levels.txt konnte nicht geöffnet werden.");
76 }
77
78 std::string name;
79 while(std::getline(in, name)) {
80 if(name != "") {
81 names.push_back(name);
82 }
83 }
84 }
85
86 std::vector<std::string> names;
87 } const level_names;
88
89 class level {
90 public:
91 level(std::string const &name)
92 : name(name),
93 level_lines(LEVEL_LINE_COUNT)
94 {
95 std::ifstream in((PATH_PREFIX + name + ".lv").c_str());
96
97 if(!in) {
98 throw std::invalid_argument("Could not open file: " + name + ".lv");
99 }
100
101 for(std::size_t i = 0; i < level_lines.size(); ++i) {
102 std::getline(in, level_lines[i]);
103 }
104
105 std::string line;
106 std::string type_prefix;
107 std::map<char, std::string> *objmap = 0;
108
109 while(std::getline(in, line)) {
110 if(line[0] == '[') {
111 if(line == "[tiles]") {
112 objmap = &tile_types;
113 } else if(line == "[items]") {
114 objmap = &item_types;
115 } else if(line == "[enemies]") {
116 objmap = &enemy_types;
117 } else if(line == "[parameters]") {
118 objmap = &level_params;
119 } else {
120 throw std::invalid_argument("Unkown type: " + line);
121 }
122 } else if(line != "") {
123 char c;
124 std::string tok;
125 std::istringstream parser(line);
126
127 if(parser >> c >> tok) {
128 if(objmap) {
129 (*objmap)[c] = tok;
130 }
131 } else {
132 throw std::invalid_argument("Line not parseable: " + line);
133 }
134 }
135 }
136 }
137
138 std::size_t length() const {
139 std::size_t level_length = 0;
140
141 for(std::size_t i = 0; i < level_lines.size(); ++i) {
142 level_length = std::max(level_length, level_lines[i].size());
143 }
144
145 return level_length;
146 }
147
148 unsigned find_type(boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &type, std::string const &error) const {
149 unsigned const *p = types.find(type);
150 if(!p) throw std::invalid_argument(error + type);
151 return *p;
152 }
153
154 std::size_t count_things(std::map<char, std::string> const &objmap) const {
155 std::size_t len = length();
156 std::size_t i = 0;
157
158 for(std::size_t x = 0; x < len; ++x) {
159 for(std::size_t y = 0; y < level_lines.size(); ++y) {
160 if(x < level_lines[y].size()) {
161 auto iter = objmap.find(level_lines[y][x]);
162
163 if(iter != objmap.end()) {
164 ++i;
165 }
166 }
167 }
168 }
169
170 return i;
171 }
172
173 std::size_t count_tiles () const { return count_things(tile_types ); }
174 std::size_t count_items () const { return count_things(item_types ); }
175 std::size_t count_enemies() const { return count_things(enemy_types); }
176
177 void dump_things(std::ostream &dest, std::map<char, std::string> const &objmap, boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &error) const {
178 std::size_t len = length();
179
180 for(std::size_t x = 0; x < len; ++x) {
181 for(std::size_t y = 0; y < level_lines.size(); ++y) {
182 if(level_lines[y].size() < x) continue;
183
184 auto iter = objmap.find(level_lines[y][x]);
185
186 if(iter != objmap.end()) {
187 unsigned char buf[3];
188 buf[0] = static_cast<uint8_t>(y) << 4 | static_cast<uint8_t>(x >> 8);
189 buf[1] = static_cast<uint8_t>(x);
190 buf[2] = static_cast<uint8_t>(find_type(types, iter->second, error));
191
192 dest.write(static_cast<char const*>(static_cast<void*>(&buf[0])), sizeof(buf));
193 }
194 }
195 }
196 }
197
198 void dump_tiles (std::ostream &dest) const { dump_things(dest, tile_types, desc.tiles , "Unbekannter Tile-Typ: "); }
199 void dump_items (std::ostream &dest) const { dump_things(dest, item_types, desc.items , "Unbekannter Item-Typ: "); }
200 void dump_enemies(std::ostream &dest) const { dump_things(dest, enemy_types, desc.enemies, "Unbekannter Enemy-Typ: "); }
201
202 std::pair<std::size_t, std::size_t> starting_position() const {
203 std::pair<std::size_t, std::size_t> player_pos(0, 0);
204
205 for(std::size_t y = 0; y < level_lines.size(); ++y) {
206 std::size_t x = level_lines[y].find('P');
207
208 if(x != std::string::npos) {
209 player_pos.first = x;
210 player_pos.second = y;
211 break;
212 }
213 }
214
215 return player_pos;
216 }
217
218 void generate_header(jumpnrun_level *dest) const {
219 dest->header.tile_count = count_tiles ();
220 dest->header.item_count = count_items ();
221 dest->header.enemy_count = count_enemies();
222 }
223
224 void dump(std::ostream &dest) const {
225 jumpnrun_level dummy;
226
227 generate_header(&dummy);
228 uint16_t head[3] = {
229 static_cast<uint16_t>(dummy.header. tile_count),
230 static_cast<uint16_t>(dummy.header. item_count),
231 static_cast<uint16_t>(dummy.header.enemy_count)
232 };
233
234 std::pair<std::size_t, std::size_t> player_pos = starting_position();
235
236 uint16_t spos[2] = {
237 static_cast<uint16_t>(player_pos.first),
238 static_cast<uint16_t>(player_pos.second)
239 };
240
241 uint8_t lives = 3;
242 {
243 std::map<char, std::string>::const_iterator iter = level_params.find('L');
244 if(iter != level_params.end()) {
245 unsigned x;
246 std::istringstream parser(iter->second);
247 if(parser >> x) {
248 lives = static_cast<uint8_t>(x);
249 }
250 }
251 }
252
253 dest.write(static_cast<char const *>(static_cast<void const *>(head )), sizeof(head ));
254 dest.write(static_cast<char const *>(static_cast<void const *>(spos )), sizeof(spos ));
255 dest.write(static_cast<char const *>(static_cast<void const *>(&lives)), sizeof(lives));
256
257 dump_tiles(dest);
258 dump_items(dest);
259 dump_enemies(dest);
260 }
261
262 private:
263 std::string name;
264 std::vector<std::string> level_lines;
265 std::map<char, std::string> tile_types;
266 std::map<char, std::string> item_types;
267 std::map<char, std::string> enemy_types;
268 std::map<char, std::string> level_params;
269 };
270 }
271
272 void jumpnrun_level_dump(size_t level) {
273 std::string name = jnrcpp::level_names.names[level];
274 jnrcpp::level lv(name);
275 std::ofstream out((PATH_PREFIX + name + ".lvl").c_str());
276
277 lv.dump(out);
278 }
279
280 void jumpnrun_levels_dump(void) {
281 for(size_t i = 0; i < jnrcpp::level_names.names.size(); ++i) {
282 jumpnrun_level_dump(i);
283 }
284 }
285
286 int main() {
287 jumpnrun_levels_dump();
288 }
This page took 0.057824 seconds and 5 git commands to generate.