Checkpoints.
[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 ;
46
47 enemies.add
48 ("cat" , JUMPNRUN_ENEMY_TYPE_CAT )
49 ("mushroom" , JUMPNRUN_ENEMY_TYPE_MUSHROOM )
50 ("bunny" , JUMPNRUN_ENEMY_TYPE_BUNNY )
51 ("kaninchen" , JUMPNRUN_ENEMY_TYPE_BUNNY ) // legacy
52 ("snake" , JUMPNRUN_ENEMY_TYPE_SNAKE )
53 ("spiral" , JUMPNRUN_ENEMY_TYPE_SPIRAL )
54 ("rotor" , JUMPNRUN_ENEMY_TYPE_ROTOR )
55 ("dog" , JUMPNRUN_ENEMY_TYPE_DOG )
56 ("giraffe" , JUMPNRUN_ENEMY_TYPE_GIRAFFE )
57 ("bird" , JUMPNRUN_ENEMY_TYPE_BIRD )
58 ("bird_straight", JUMPNRUN_ENEMY_TYPE_BIRD_STRAIGHT)
59 ("bird_dip" , JUMPNRUN_ENEMY_TYPE_BIRD_DIP )
60 ;
61 }
62
63 boost::spirit::qi::symbols<char, unsigned> tiles;
64 boost::spirit::qi::symbols<char, unsigned> items;
65 boost::spirit::qi::symbols<char, unsigned> enemies;
66 } const desc;
67
68 struct level_name_map {
69 level_name_map() {
70 std::ifstream in(PATH_PREFIX "levels.txt");
71
72 if(!in) {
73 throw std::logic_error(PATH_PREFIX "levels.txt konnte nicht geƶffnet werden.");
74 }
75
76 std::string name;
77 while(std::getline(in, name)) {
78 if(name != "") {
79 names.push_back(name);
80 }
81 }
82 }
83
84 std::vector<std::string> names;
85 } const level_names;
86
87 class level {
88 public:
89 level(std::string const &name)
90 : name(name),
91 level_lines(LEVEL_LINE_COUNT)
92 {
93 std::ifstream in((PATH_PREFIX + name + ".lv").c_str());
94
95 if(!in) {
96 throw std::invalid_argument("Could not open file: " + name + ".lv");
97 }
98
99 for(std::size_t i = 0; i < level_lines.size(); ++i) {
100 std::getline(in, level_lines[i]);
101 }
102
103 std::string line;
104 std::string type_prefix;
105 std::map<char, std::string> *objmap = 0;
106
107 while(std::getline(in, line)) {
108 if(line[0] == '[') {
109 if(line == "[tiles]") {
110 objmap = &tile_types;
111 } else if(line == "[items]") {
112 objmap = &item_types;
113 } else if(line == "[enemies]") {
114 objmap = &enemy_types;
115 } else {
116 throw std::invalid_argument("Unkown type: " + line);
117 }
118 } else if(line != "") {
119 char c;
120 std::string tok;
121 std::istringstream parser(line);
122
123 if(parser >> c >> tok) {
124 if(objmap) {
125 (*objmap)[c] = tok;
126 }
127 } else {
128 throw std::invalid_argument("Line not parseable: " + line);
129 }
130 }
131 }
132 }
133
134 std::size_t length() const {
135 std::size_t level_length = 0;
136
137 for(std::size_t i = 0; i < level_lines.size(); ++i) {
138 level_length = std::max(level_length, level_lines[i].size());
139 }
140
141 return level_length;
142 }
143
144 unsigned find_type(boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &type, std::string const &error) const {
145 unsigned const *p = types.find(type);
146 if(!p) throw std::invalid_argument(error + type);
147 return *p;
148 }
149
150 std::size_t count_things(std::map<char, std::string> const &objmap) const {
151 std::size_t len = length();
152 std::size_t i = 0;
153
154 for(std::size_t x = 0; x < len; ++x) {
155 for(std::size_t y = 0; y < level_lines.size(); ++y) {
156 if(x < level_lines[y].size()) {
157 auto iter = objmap.find(level_lines[y][x]);
158
159 if(iter != objmap.end()) {
160 ++i;
161 }
162 }
163 }
164 }
165
166 return i;
167 }
168
169 std::size_t count_tiles () const { return count_things(tile_types ); }
170 std::size_t count_items () const { return count_things(item_types ); }
171 std::size_t count_enemies() const { return count_things(enemy_types); }
172
173 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 {
174 std::size_t len = length();
175
176 for(std::size_t x = 0; x < len; ++x) {
177 for(std::size_t y = 0; y < level_lines.size(); ++y) {
178 if(level_lines[y].size() < x) continue;
179
180 auto iter = objmap.find(level_lines[y][x]);
181
182 if(iter != objmap.end()) {
183 unsigned char buf[3];
184 buf[0] = static_cast<uint8_t>(y) << 4 | static_cast<uint8_t>(x >> 8);
185 buf[1] = static_cast<uint8_t>(x);
186 buf[2] = static_cast<uint8_t>(find_type(types, iter->second, error));
187
188 dest.write(static_cast<char const*>(static_cast<void*>(&buf[0])), sizeof(buf));
189 }
190 }
191 }
192 }
193
194 void dump_tiles (std::ostream &dest) const { dump_things(dest, tile_types, desc.tiles , "Unbekannter Tile-Typ: "); }
195 void dump_items (std::ostream &dest) const { dump_things(dest, item_types, desc.items , "Unbekannter Item-Typ: "); }
196 void dump_enemies(std::ostream &dest) const { dump_things(dest, enemy_types, desc.enemies, "Unbekannter Enemy-Typ: "); }
197
198 std::pair<std::size_t, std::size_t> starting_position() const {
199 std::pair<std::size_t, std::size_t> player_pos(0, 0);
200
201 for(std::size_t y = 0; y < level_lines.size(); ++y) {
202 std::size_t x = level_lines[y].find('P');
203
204 if(x != std::string::npos) {
205 player_pos.first = x;
206 player_pos.second = y;
207 break;
208 }
209 }
210
211 return player_pos;
212 }
213
214 void generate_header(jumpnrun_level *dest) const {
215 dest->header.tile_count = count_tiles ();
216 dest->header.item_count = count_items ();
217 dest->header.enemy_count = count_enemies();
218 }
219
220 void dump(std::ostream &dest) const {
221 jumpnrun_level dummy;
222
223 generate_header(&dummy);
224 uint16_t head[3] = {
225 static_cast<uint16_t>(dummy.header. tile_count),
226 static_cast<uint16_t>(dummy.header. item_count),
227 static_cast<uint16_t>(dummy.header.enemy_count)
228 };
229
230 std::pair<std::size_t, std::size_t> player_pos = starting_position();
231
232 uint16_t spos[2] = {
233 static_cast<uint16_t>(player_pos.first),
234 static_cast<uint16_t>(player_pos.second)
235 };
236
237 dest.write(static_cast<char const *>(static_cast<void const *>(head)), sizeof(head));
238 dest.write(static_cast<char const *>(static_cast<void const *>(spos)), sizeof(spos));
239
240 dump_tiles(dest);
241 dump_items(dest);
242 dump_enemies(dest);
243 }
244
245 private:
246 std::string name;
247 std::vector<std::string> level_lines;
248 std::map<char, std::string> tile_types;
249 std::map<char, std::string> item_types;
250 std::map<char, std::string> enemy_types;
251 };
252 }
253
254 void jumpnrun_level_dump(size_t level) {
255 std::string name = jnrcpp::level_names.names[level];
256 jnrcpp::level lv(name);
257 std::ofstream out((PATH_PREFIX + name + ".lvl").c_str());
258
259 lv.dump(out);
260 }
261
262 void jumpnrun_levels_dump(void) {
263 for(size_t i = 0; i < jnrcpp::level_names.names.size(); ++i) {
264 jumpnrun_level_dump(i);
265 }
266 }
267
268 int main() {
269 jumpnrun_levels_dump();
270 }
This page took 0.096704 seconds and 5 git commands to generate.