Lange Level richtig laden.
[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 {
118 throw std::invalid_argument("Unkown type: " + line);
119 }
120 } else if(line != "") {
121 char c;
122 std::string tok;
123 std::istringstream parser(line);
124
125 if(parser >> c >> tok) {
126 if(objmap) {
127 (*objmap)[c] = tok;
128 }
129 } else {
130 throw std::invalid_argument("Line not parseable: " + line);
131 }
132 }
133 }
134 }
135
136 std::size_t length() const {
137 std::size_t level_length = 0;
138
139 for(std::size_t i = 0; i < level_lines.size(); ++i) {
140 level_length = std::max(level_length, level_lines[i].size());
141 }
142
143 return level_length;
144 }
145
146 unsigned find_type(boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &type, std::string const &error) const {
147 unsigned const *p = types.find(type);
148 if(!p) throw std::invalid_argument(error + type);
149 return *p;
150 }
151
152 std::size_t count_things(std::map<char, std::string> const &objmap) const {
153 std::size_t len = length();
154 std::size_t i = 0;
155
156 for(std::size_t x = 0; x < len; ++x) {
157 for(std::size_t y = 0; y < level_lines.size(); ++y) {
158 if(x < level_lines[y].size()) {
159 auto iter = objmap.find(level_lines[y][x]);
160
161 if(iter != objmap.end()) {
162 ++i;
163 }
164 }
165 }
166 }
167
168 return i;
169 }
170
171 std::size_t count_tiles () const { return count_things(tile_types ); }
172 std::size_t count_items () const { return count_things(item_types ); }
173 std::size_t count_enemies() const { return count_things(enemy_types); }
174
175 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 {
176 std::size_t len = length();
177
178 for(std::size_t x = 0; x < len; ++x) {
179 for(std::size_t y = 0; y < level_lines.size(); ++y) {
180 if(level_lines[y].size() < x) continue;
181
182 auto iter = objmap.find(level_lines[y][x]);
183
184 if(iter != objmap.end()) {
185 unsigned char buf[3];
186 buf[0] = static_cast<uint8_t>(y) << 4 | static_cast<uint8_t>(x >> 8);
187 buf[1] = static_cast<uint8_t>(x);
188 buf[2] = static_cast<uint8_t>(find_type(types, iter->second, error));
189
190 dest.write(static_cast<char const*>(static_cast<void*>(&buf[0])), sizeof(buf));
191 }
192 }
193 }
194 }
195
196 void dump_tiles (std::ostream &dest) const { dump_things(dest, tile_types, desc.tiles , "Unbekannter Tile-Typ: "); }
197 void dump_items (std::ostream &dest) const { dump_things(dest, item_types, desc.items , "Unbekannter Item-Typ: "); }
198 void dump_enemies(std::ostream &dest) const { dump_things(dest, enemy_types, desc.enemies, "Unbekannter Enemy-Typ: "); }
199
200 std::pair<std::size_t, std::size_t> starting_position() const {
201 std::pair<std::size_t, std::size_t> player_pos(0, 0);
202
203 for(std::size_t y = 0; y < level_lines.size(); ++y) {
204 std::size_t x = level_lines[y].find('P');
205
206 if(x != std::string::npos) {
207 player_pos.first = x;
208 player_pos.second = y;
209 break;
210 }
211 }
212
213 return player_pos;
214 }
215
216 void generate_header(jumpnrun_level *dest) const {
217 dest->header.tile_count = count_tiles ();
218 dest->header.item_count = count_items ();
219 dest->header.enemy_count = count_enemies();
220 }
221
222 void dump(std::ostream &dest) const {
223 jumpnrun_level dummy;
224
225 generate_header(&dummy);
226 uint16_t head[3] = {
227 static_cast<uint16_t>(dummy.header. tile_count),
228 static_cast<uint16_t>(dummy.header. item_count),
229 static_cast<uint16_t>(dummy.header.enemy_count)
230 };
231
232 std::pair<std::size_t, std::size_t> player_pos = starting_position();
233
234 uint16_t spos[2] = {
235 static_cast<uint16_t>(player_pos.first),
236 static_cast<uint16_t>(player_pos.second)
237 };
238
239 dest.write(static_cast<char const *>(static_cast<void const *>(head)), sizeof(head));
240 dest.write(static_cast<char const *>(static_cast<void const *>(spos)), sizeof(spos));
241
242 dump_tiles(dest);
243 dump_items(dest);
244 dump_enemies(dest);
245 }
246
247 private:
248 std::string name;
249 std::vector<std::string> level_lines;
250 std::map<char, std::string> tile_types;
251 std::map<char, std::string> item_types;
252 std::map<char, std::string> enemy_types;
253 };
254 }
255
256 void jumpnrun_level_dump(size_t level) {
257 std::string name = jnrcpp::level_names.names[level];
258 jnrcpp::level lv(name);
259 std::ofstream out((PATH_PREFIX + name + ".lvl").c_str());
260
261 lv.dump(out);
262 }
263
264 void jumpnrun_levels_dump(void) {
265 for(size_t i = 0; i < jnrcpp::level_names.names.size(); ++i) {
266 jumpnrun_level_dump(i);
267 }
268 }
269
270 int main() {
271 jumpnrun_levels_dump();
272 }
This page took 0.06278 seconds and 5 git commands to generate.