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