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