1 #include <boost/algorithm/string/split.hpp>
2 #include <boost/algorithm/string.hpp>
3 #include <sstream>
4
5 #include "asserts.hpp"
6 #include "foreach.hpp"
7 #include "formula.hpp"
8 #include "hex_map.hpp"
9 #include "hex_object.hpp"
10 #include "hex_tile.hpp"
11 #include "json_parser.hpp"
12 #include "level.hpp"
13 #include "module.hpp"
14 #include "variant_utils.hpp"
15
16 namespace hex {
17
18 static const int HexTileSize = 72;
19
hex_map(variant node)20 hex_map::hex_map(variant node)
21 : zorder_(node["zorder"].as_int(-1000)),
22 x_(node["x"].as_int(0)),
23 y_(node["y"].as_int(0)), width_(0), height_(0)
24 {
25 std::vector<std::string> result;
26 std::string tile_str = node["tiles"].as_string();
27 boost::algorithm::erase_all(tile_str, "\t");
28 boost::algorithm::erase_all(tile_str, "\v");
29 boost::algorithm::erase_all(tile_str, " ");
30 boost::algorithm::erase_all(tile_str, "\r");
31 boost::algorithm::split(result, tile_str, std::bind2nd(std::equal_to<char>(), '\n'));
32 int x = x_;
33 int y = y_;
34 foreach(const std::string& row, result) {
35 if(row.empty()) {
36 y++;
37 x = x_;
38 continue;
39 }
40 std::vector<std::string> row_res;
41 boost::algorithm::split(row_res, row, std::bind2nd(std::equal_to<char>(), ','));
42 std::vector<hex_object_ptr> new_row;
43 foreach(const std::string& col, row_res) {
44 new_row.push_back(hex_object_ptr(new hex_object(col, x, y, this)));
45 x++;
46 }
47 y++;
48 x = x_;
49 tiles_.push_back(new_row);
50 width_ = std::max<size_t>(width_, tiles_.back().size());
51 }
52 height_ = tiles_.size();
53
54 #ifdef USE_GLES2
55 if(node.has_key("shader")) {
56 shader_.reset(new gles2::shader_program(node["shader"]));
57 } else {
58 shader_.reset();
59 }
60 #endif
61 }
62
draw() const63 void hex_map::draw() const
64 {
65 #if defined(USE_GLES2)
66 #ifndef NO_EDITOR
67 try {
68 #endif
69 gles2::manager manager(shader_);
70 #endif
71 foreach(const hex_tile_row& row, tiles_) {
72 foreach(const hex_object_ptr& col, row) {
73 col->draw();
74 }
75 }
76 #if defined(USE_GLES2) && !defined(NO_EDITOR)
77 } catch(validation_failure_exception& e) {
78 gles2::shader::set_runtime_error("HEX MAP SHADER ERROR: " + e.msg);
79 }
80 #endif
81 }
82
build()83 void hex_map::build()
84 {
85 foreach(const std::string& rule, hex_object::get_rules()) {
86 foreach(hex_tile_row& row, tiles_) {
87 foreach(hex_object_ptr& col, row) {
88 col->apply_rules(rule);
89 }
90 }
91 }
92 }
93
make_tile_string() const94 std::string hex_map::make_tile_string() const
95 {
96 std::ostringstream tiles;
97 foreach(const hex_tile_row& row, tiles_) {
98 for(hex_tile_row::const_iterator i = row.begin(); i != row.end(); ++i) {
99 tiles << (*i)->type() << ((i+1) == row.end() ? "\n" : ",");
100 }
101 }
102 return tiles.str();
103 }
104
write() const105 variant hex_map::write() const
106 {
107 variant_builder res;
108 res.add("x", x_);
109 res.add("y", y_);
110 res.add("zorder", zorder_);
111
112 res.add("tiles", make_tile_string());
113
114 #if defined(USE_GLES2)
115 if(shader_) {
116 res.add("shader", shader_->write());
117 }
118 #endif
119 return res.build();
120 }
121
get_hex_tile(direction d,int x,int y) const122 hex_object_ptr hex_map::get_hex_tile(direction d, int x, int y) const
123 {
124 int ox = x;
125 int oy = y;
126 x -= x_;
127 y -= y_;
128 if(d == NORTH) {
129 y -= 1;
130 } else if(d == SOUTH) {
131 y += 1;
132 } else if(d == NORTH_WEST) {
133 y -= (abs(ox)%2==0) ? 1 : 0;
134 x -= 1;
135 } else if(d == NORTH_EAST) {
136 y -= (abs(ox)%2==0) ? 1 : 0;
137 x += 1;
138 } else if(d == SOUTH_WEST) {
139 y += (abs(ox)%2) ? 1 : 0;
140 x -= 1;
141 } else if(d == SOUTH_EAST) {
142 y += (abs(ox)%2) ? 1 : 0;
143 x += 1;
144 } else {
145 ASSERT_LOG(false, "Unrecognised direction: " << d);
146 }
147 if(x < 0 || y < 0 || size_t(y) >= tiles_.size()) {
148 return hex_object_ptr();
149 }
150 if(size_t(x) >= tiles_[y].size()) {
151 return hex_object_ptr();
152 }
153 return tiles_[y][x];
154 }
155
get_value(const std::string & key) const156 variant hex_map::get_value(const std::string& key) const
157 {
158 if(key == "x_size") {
159 return variant(width());
160 } else if(key == "y_size") {
161 return variant(height());
162 } else if(key == "size") {
163 std::vector<variant> v;
164 v.push_back(variant(width()));
165 v.push_back(variant(height()));
166 return variant(&v);
167 } else if(key == "map") {
168 std::vector<variant> list;
169 foreach(const hex_tile_row& row, tiles_) {
170 std::vector<variant> rrow;
171 for(hex_tile_row::const_iterator i = row.begin(); i != row.end(); ++i) {
172 rrow.push_back(variant((*i).get()));
173 }
174 list.push_back(variant(&rrow));
175 }
176 return variant(&list);
177 } else if(key == "mapstring") {
178 return variant(make_tile_string());
179 } else if(key == "maplist") {
180 std::vector<variant> list;
181 foreach(const hex_tile_row& row, tiles_) {
182 std::vector<variant> rrow;
183 for(hex_tile_row::const_iterator i = row.begin(); i != row.end(); ++i) {
184 rrow.push_back(variant((*i)->type()));
185 }
186 list.push_back(variant(&rrow));
187 }
188 return variant(&list);
189 }
190 return variant();
191 }
192
set_value(const std::string & key,const variant & value)193 void hex_map::set_value(const std::string& key, const variant& value)
194 {
195 }
196
get_tile_pos_from_pixel_pos(int mx,int my)197 point hex_map::get_tile_pos_from_pixel_pos(int mx, int my)
198 {
199 const int tesselation_x_size = (3*HexTileSize)/2;
200 const int tesselation_y_size = HexTileSize;
201 const int x_base = (mx>=0) ? mx / tesselation_x_size * 2 : mx / tesselation_x_size * 2 - 2;
202 const int x_mod = (mx>=0) ? mx % tesselation_x_size : tesselation_x_size + (mx % tesselation_x_size);
203 const int y_base = (my>=0) ? my / tesselation_y_size : my / tesselation_y_size - 1;
204 const int y_mod = (my>=0) ? my % tesselation_y_size : tesselation_y_size + (my % tesselation_y_size);
205 const int m = 2;
206
207 int x_modifier = 0;
208 int y_modifier = 0;
209
210 if(y_mod < tesselation_y_size / 2) {
211 if((x_mod * m + y_mod) < (HexTileSize / 2)) {
212 x_modifier = -1;
213 y_modifier = -1;
214 } else if ((x_mod * m - y_mod) < (HexTileSize * 3 / 2)) {
215 x_modifier = 0;
216 y_modifier = 0;
217 } else {
218 x_modifier = 1;
219 y_modifier = -1;
220 }
221
222 } else {
223 if((x_mod * m - (y_mod - HexTileSize / 2)) < 0) {
224 x_modifier = -1;
225 y_modifier = 0;
226 } else if((x_mod * m + (y_mod - HexTileSize / 2)) < HexTileSize * 2) {
227 x_modifier = 0;
228 y_modifier = 0;
229 } else {
230 x_modifier = 1;
231 y_modifier = 0;
232 }
233 }
234 return point(x_base + x_modifier, y_base + y_modifier);
235 }
236
get_tile_from_pixel_pos(int mx,int my) const237 hex_object_ptr hex_map::get_tile_from_pixel_pos(int mx, int my) const
238 {
239 point p = get_tile_pos_from_pixel_pos(mx, my);
240 return get_tile_at(p.x, p.y);
241 }
242
get_pixel_pos_from_tile_pos(int x,int y)243 point hex_map::get_pixel_pos_from_tile_pos(int x, int y)
244 {
245 const int HexTileSizeHalf = HexTileSize/2;
246 const int HexTileSizeThreeQuarters = (HexTileSize*3)/4;
247 const int tx = x*HexTileSizeThreeQuarters;
248 const int ty = HexTileSize*y + (abs(x)%2)*HexTileSizeHalf;
249 return point(tx, ty);
250 }
251
get_tile_at(int x,int y) const252 hex_object_ptr hex_map::get_tile_at(int x, int y) const
253 {
254 x -= x_;
255 y -= y_;
256 if(x < 0 || y < 0 || size_t(y) >= tiles_.size()) {
257 return hex_object_ptr();
258 }
259 if(size_t(x) >= tiles_[y].size()) {
260 return hex_object_ptr();
261 }
262 return tiles_[y][x];
263 }
264
set_tile(int xx,int yy,const std::string & tile)265 bool hex_map::set_tile(int xx, int yy, const std::string& tile)
266 {
267 point p = get_tile_pos_from_pixel_pos(xx, yy);
268
269 // New tile position is outside current bounds, so enlarge.
270 if(p.y < y()) {
271 int needed_rows = y() - p.y;
272 y_ = p.y;
273 std::vector<hex_object_ptr> r;
274 tiles_.insert(tiles_.begin(), r);
275 }
276 if(p.x < x()) {
277 size_t needed_cols = x() - p.x;
278 int n = x_;
279 x_ = p.x;
280 for(size_t j = 0; j < tiles_.size(); ++j) {
281 for(size_t i = 0; i < needed_cols; ++i) {
282 tiles_[j].insert(tiles_[j].begin(), new hex_object("Xv", n + x(), j + y(), this));
283 --n;
284 }
285 }
286 }
287
288 const int tx = p.x - x();
289 const int ty = p.y - y();
290 bool changed = false;
291
292 int needed_rows = int(size_t(ty)+1 - tiles_.size());
293 changed |= (needed_rows > 0 );
294 while(needed_rows-- > 0) {
295 std::vector<hex_object_ptr> r;
296 tiles_.push_back(r);
297 }
298 int needed_cols = int(size_t(tx)+1 - tiles_[ty].size());
299 changed |= (needed_cols > 0 );
300 int n = tx;
301 while(needed_cols-- > 0) {
302 // Add Void
303 tiles_[ty].push_back(hex_object_ptr(new hex_object("Xv", n + x(), ty + y(), this)));
304 ++n;
305 }
306 if(tiles_[ty][tx] == NULL || tiles_[ty][tx]->type() != tile) {
307 tiles_[ty][tx].reset(new hex_object(tile, tx + x(), ty + y(), this));
308 changed = true;
309 }
310 return changed;
311 }
312
loc_in_dir(int x,int y,direction d)313 point hex_map::loc_in_dir(int x, int y, direction d)
314 {
315 int ox = x;
316 int oy = y;
317 if(d == NORTH) {
318 y -= 1;
319 } else if(d == SOUTH) {
320 y += 1;
321 } else if(d == NORTH_WEST) {
322 y -= (abs(ox)%2==0) ? 1 : 0;
323 x -= 1;
324 } else if(d == NORTH_EAST) {
325 y -= (abs(ox)%2==0) ? 1 : 0;
326 x += 1;
327 } else if(d == SOUTH_WEST) {
328 y += (abs(ox)%2) ? 1 : 0;
329 x -= 1;
330 } else if(d == SOUTH_EAST) {
331 y += (abs(ox)%2) ? 1 : 0;
332 x += 1;
333 } else {
334 ASSERT_LOG(false, "Unrecognised direction: " << d);
335 }
336 return point(x, y);
337 }
338
loc_in_dir(int x,int y,const std::string & s)339 point hex_map::loc_in_dir(int x, int y, const std::string& s)
340 {
341 if(s == "north" || s == "n") {
342 return loc_in_dir(x, y, NORTH);
343 } else if(s == "south" || s == "s") {
344 return loc_in_dir(x, y, SOUTH);
345 } else if(s == "north_west" || s == "nw" || s == "northwest") {
346 return loc_in_dir(x, y, NORTH_WEST);
347 } else if(s == "north_east" || s == "ne" || s == "northeast") {
348 return loc_in_dir(x, y, NORTH_EAST);
349 } else if(s == "south_west" || s == "sw" || s == "southwest") {
350 return loc_in_dir(x, y, SOUTH_WEST);
351 } else if(s == "south_east" || s == "se" || s == "southeast") {
352 return loc_in_dir(x, y, SOUTH_EAST);
353 }
354 ASSERT_LOG(false, "Unreognised direction " << s);
355 return point();
356 }
357
create_formula(const variant & v)358 game_logic::formula_ptr hex_map::create_formula(const variant& v)
359 {
360 return game_logic::formula_ptr(new game_logic::formula(v));
361 }
362
execute_command(const variant & var)363 bool hex_map::execute_command(const variant& var)
364 {
365 bool result = true;
366 if(var.is_null()) {
367 return result;
368 }
369
370 if(var.is_list()) {
371 const int num_elements = var.num_elements();
372 for(int n = 0; n != num_elements; ++n) {
373 if(var[n].is_null() == false) {
374 result = execute_command(var[n]) && result;
375 }
376 }
377 } else {
378 game_logic::command_callable* cmd = var.try_convert<game_logic::command_callable>();
379 if(cmd != NULL) {
380 cmd->execute(*this);
381 }
382 }
383 return result;
384 }
385
386 }
387