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