1 // Copyright (C) 2007 Ole Laursen
2 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Library General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "editorbigmap.h"
27 #include "stacklist.h"
33 #include "signpostlist.h"
35 #include "templelist.h"
37 #include "bridgelist.h"
43 #include "playerlist.h"
47 #include "Configuration.h"
48 #include "rewardlist.h"
49 #include "GraphicsCache.h"
50 #include "armysetlist.h"
51 #include "MapRenderer.h"
52 #include "CreateScenario.h"
54 #include "MapBackpack.h"
55 #include "backpack-editor-dialog.h"
58 EditorBigMap::EditorBigMap()
60 mouse_pos = prev_mouse_pos = Vector<int>(0, 0);
62 moving_objects_from = Vector<int>(-1,-1);
67 pointer_terrain = Tile::GRASS;
68 pointer_tile_style_id = -1;
69 show_tile_types_instead_of_tile_styles = false;
72 EditorBigMap::~EditorBigMap()
76 void EditorBigMap::set_pointer(Pointer p, int size, Tile::Type t,
80 if (pointer != p || pointer_size != size ||
81 pointer_tile_style_id != tile_style_id)
86 pointer_tile_style_id = tile_style_id;
88 moving_objects_from = Vector<int>(-1,-1);
90 draw(Playerlist::getViewingplayer());
94 void EditorBigMap::mouse_button_event(MouseButtonEvent e)
100 Vector<int> tile = mouse_pos_to_tile(mouse_pos);
102 if (e.button == MouseButtonEvent::LEFT_BUTTON
103 && e.state == MouseButtonEvent::PRESSED)
105 change_map_under_cursor();
108 else if (e.button == MouseButtonEvent::RIGHT_BUTTON
109 && e.state == MouseButtonEvent::PRESSED)
111 map_selection_seq seq;
113 if (Stack* s = GameMap::getStack(tile))
115 if (City* c = GameMap::getCity(tile))
117 if (Ruin* r = GameMap::getRuin(tile))
119 if (Signpost* s = GameMap::getSignpost(tile))
121 if (Temple* t = GameMap::getTemple(tile))
123 MapBackpack *b = GameMap::getInstance()->getTile(tile)->getBackpack();
124 if (b->empty() == false)
129 objects_selected.emit(seq);
133 void EditorBigMap::mouse_motion_event(MouseMotionEvent e)
141 Vector<int> new_tile = mouse_pos_to_tile(mouse_pos);
142 if (new_tile != mouse_pos_to_tile(prev_mouse_pos))
144 mouse_on_tile.emit(new_tile);
148 // draw with left mouse button
149 if (e.pressed[MouseMotionEvent::LEFT_BUTTON])
151 change_map_under_cursor();
154 // drag with right mouse button
155 if (e.pressed[MouseMotionEvent::RIGHT_BUTTON]
156 && (mouse_state == NONE || mouse_state == DRAGGING))
158 Vector<int> delta = -(mouse_pos - prev_mouse_pos);
160 // ignore very small drags to ensure that a shaking mouse does not
161 // prevent the user from making right clicks
162 if (mouse_state == NONE && length(delta) <= 2)
165 // FIXME: show a drag cursor
167 int ts = GameMap::getInstance()->getTileset()->getTileSize();
168 Vector<int> screen_dim(image.get_width(), image.get_height());
169 view_pos = clip(Vector<int>(0, 0),
171 GameMap::get_dim() * ts - screen_dim);
173 // calculate new view position in tiles, rounding up
174 Vector<int> new_view = (view_pos + Vector<int>(ts - 1, ts - 1)) / ts;
176 bool redraw_buffer = false;
178 if (new_view != view.pos)
182 view_changed.emit(view);
183 redraw_buffer = true;
186 draw(Playerlist::getViewingplayer(),redraw_buffer);
188 mouse_state = DRAGGING;
191 if (redraw && pointer != POINTER)
192 draw(Playerlist::getViewingplayer());
194 prev_mouse_pos = mouse_pos;
197 void EditorBigMap::mouse_leave_event()
199 mouse_pos.x = mouse_pos.y = -10000;
200 mouse_on_tile.emit(Vector<int>(-100, -100));
201 draw(Playerlist::getViewingplayer());
204 std::vector<Vector<int> > EditorBigMap::get_screen_tiles()
206 // find out which tiles are within bounds
207 std::vector<Vector<int> > tiles;
209 for (int y = buffer_view.y; y < buffer_view.y + buffer_view.h; y++)
210 for (int x = buffer_view.x; x < buffer_view.x + buffer_view.w; x++)
212 Vector<int> tile(x, y);
213 if (tile.x >= 0 && tile.x < GameMap::getWidth() &&
214 tile.y >= 0 && tile.y < GameMap::getHeight())
215 tiles.push_back(tile);
221 std::vector<Vector<int> > EditorBigMap::get_cursor_tiles()
223 // find out which cursor tiles are within bounds
224 std::vector<Vector<int> > tiles;
226 Vector<int> current_tile = mouse_pos_to_tile(mouse_pos);
228 for (int y = 0; y < pointer_size; ++y)
229 for (int x = 0; x < pointer_size; ++x)
231 int offset = - (pointer_size - 1) / 2;
232 Vector<int> tile(x + offset, y + offset);
233 tile += current_tile;
235 if (tile.x >= 0 && tile.x < GameMap::getWidth() &&
236 tile.y >= 0 && tile.y < GameMap::getHeight())
237 tiles.push_back(tile);
243 Rectangle EditorBigMap::get_cursor_rectangle()
245 // find out which cursor tiles are within bounds
246 std::vector<Vector<int> > tiles;
248 Vector<int> current_tile = mouse_pos_to_tile(mouse_pos);
249 int offset = (pointer_size - 1) / 2;
250 Vector<int> tile = current_tile - Vector<int>(offset, offset);
252 return Rectangle (tile.x, tile.y, pointer_size, pointer_size);
255 int EditorBigMap::tile_to_bridge_type(Vector<int> t)
257 // examine neighbour tiles to discover whether there's a road on them
258 bool u = Roadlist::getInstance()->getObjectAt(t + Vector<int>(0, -1));
259 bool b = Roadlist::getInstance()->getObjectAt(t + Vector<int>(0, 1));
260 bool l = Roadlist::getInstance()->getObjectAt(t + Vector<int>(-1, 0));
261 bool r = Roadlist::getInstance()->getObjectAt(t + Vector<int>(1, 0));
263 // then translate this to the type
265 if (!u && !b && !l && !r)
267 else if (u && b && l && r)
269 else if (!u && b && l && r)
271 else if (u && !b && l && r)
273 else if (u && b && !l && r)
275 else if (u && b && l && !r)
277 else if (u && b && !l && !r)
279 else if (!u && !b && l && r)
281 else if (u && !b && l && !r)
283 else if (u && !b && !l && r)
285 else if (!u && b && l && !r)
287 else if (!u && b && !l && r)
289 else if (u && !b && !l && !r)
291 else if (!u && b && !l && !r)
293 else if (!u && !b && l && !r)
295 else if (!u && !b && !l && r)
300 void EditorBigMap::change_map_under_cursor()
303 Player* active = Playerlist::getInstance()->getActiveplayer();
304 std::vector<Vector<int> > tiles = get_cursor_tiles();
305 Cityset* cs = GameMap::getInstance()->getCityset();
307 Vector<int> tile = tiles.front();
308 Rectangle changed_tiles(tile, Vector<int>(-1, -1));
309 Maptile* maptile = GameMap::getInstance()->getTile(tile);
317 // don't change terrain to water if there is a building underneath
318 if (maptile->getBuilding() != Maptile::NONE &&
319 pointer_terrain == Tile::WATER)
321 // don't change the terrain to anything else than grass if there is
323 if (maptile->getBuilding() == Maptile::CITY &&
324 pointer_terrain != Tile::GRASS)
327 changed_tiles = GameMap::getInstance()->putTerrain(get_cursor_rectangle(), pointer_terrain, pointer_tile_style_id, true);
331 if (moving_objects_from == Vector<int>(-1,-1))
333 if (GameMap::getInstance()->getBuilding(tile) !=
335 GameMap::getStack(tile) != NULL ||
336 GameMap::getBackpack(tile)->empty() == false)
337 moving_objects_from = tile;
341 Vector<int> from = moving_objects_from;
342 //here we go with the move!
343 GameMap *gm = GameMap::getInstance();
344 if (gm->getBuilding(from) != Maptile::NONE)
346 guint32 s = gm->getBuildingSize(from);
347 if (gm->canPutBuilding
348 (gm->getBuilding(from), s, tile, false) == true)
350 gm->moveBuilding(from, tile);
351 moving_objects_from = Vector<int>(-1,-1);
355 if (gm->getLocation(from)->contains(tile) ||
356 LocationBox(tile, s).contains(from))
358 gm->moveBuilding(from, tile);
359 moving_objects_from = Vector<int>(-1,-1);
363 else if (gm->getStack(from) != NULL)
365 Stack *s = gm->getFriendlyStack(from);
367 s = gm->getStack(from);
368 if (gm->canPutStack(s->size(), s->getOwner(), tile) == true)
370 gm->moveStack(s, tile);
371 moving_objects_from = Vector<int>(-1,-1);
374 else if (gm->getBackpack(from)->empty() == false)
376 gm->moveBackpack(from, tile);
377 moving_objects_from = Vector<int>(-1,-1);
382 // check if there is a building or a stack there and remove it
384 // first stack, it's above everything else
385 while (GameMap::getStack(tile) != NULL)
387 Stack *s = GameMap::getStack(tile);
388 GameMap::getInstance()->removeStack(s);
391 // ... or a temple ...
392 GameMap::getInstance()->removeTemple(tile);
395 GameMap::getInstance()->removePort(tile);
398 if (GameMap::getRuin(tile) != NULL)
400 Rewardlist *rl = Rewardlist::getInstance();
401 for (Rewardlist::iterator i = rl->begin(); i != rl->end(); i++)
403 if ((*i)->getType() == Reward::RUIN)
405 Reward_Ruin *rr = static_cast<Reward_Ruin*>(*i);
406 if (rr->getRuin()->getPos() == tile)
411 GameMap::getInstance()->removeRuin(tile);
414 GameMap::getInstance()->removeRoad(tile);
416 // ... or a bridge...
417 GameMap::getInstance()->removeBridge(tile);
419 // ... or a signpost ...
420 GameMap::getInstance()->removeSignpost(tile);
423 GameMap::getInstance()->removeCity(tile);
426 GameMap::getInstance()->getTile(tile)->getBackpack()->removeAllFromBackpack();
430 if (GameMap::getInstance()->canPutStack(1, active, tile) == true)
432 // Create a new dummy stack. As we don't want to have empty
433 // stacks hanging around, it's assumed that the default armyset
434 // has at least one entry.
435 Stack* s = new Stack(active, tile);
436 const Armysetlist* al = Armysetlist::getInstance();
437 Army* a = new Army(*al->getArmy(active->getArmyset(), 0),
440 GameMap::getInstance()->putStack(s);
441 //if we're on a city, change the allegiance of the stack
442 //and it's armies to that of the city
443 if (GameMap::getInstance()->getBuilding(s->getPos()) == Maptile::CITY)
445 City *c = GameMap::getCity(s->getPos());
446 Stacklist::changeOwnership(s, c->getOwner());
454 // check if we can place the city
455 bool city_placeable =
456 GameMap::getInstance()->canPutBuilding
457 (Maptile::CITY,cs->getCityTileWidth(), tile);
462 City *c = new City(tile, cs->getCityTileWidth());
463 GameMap::getInstance()->putCity(c);
469 bool ruin_placeable = GameMap::getInstance()->canPutBuilding
470 (Maptile::RUIN, cs->getRuinTileWidth(), tile);
473 Ruin *r = new Ruin(tile, cs->getRuinTileWidth());
474 GameMap::getInstance()->putRuin(r);
480 bool temple_placeable = GameMap::getInstance()->canPutBuilding
481 (Maptile::TEMPLE, cs->getRuinTileWidth(), tile);
482 if (!temple_placeable)
484 Temple *t = new Temple(tile, cs->getTempleTileWidth());
485 GameMap::getInstance()->putTemple(t);
491 bool signpost_placeable = GameMap::getInstance()->canPutBuilding
492 (Maptile::SIGNPOST, 1, tile);
493 if (!signpost_placeable)
495 Signpost *s = new Signpost(tile);
496 GameMap::getInstance()->putSignpost(s);
502 bool port_placeable = GameMap::getInstance()->canPutBuilding
503 (Maptile::PORT, 1, tile);
506 Port *p = new Port(tile);
507 GameMap::getInstance()->putPort(p);
513 bool bridge_placeable = GameMap::getInstance()->canPutBuilding
514 (Maptile::BRIDGE, 1, tile);
515 if (!bridge_placeable)
517 Bridge *b = new Bridge(tile, tile_to_bridge_type (tile));
518 GameMap::getInstance()->putBridge(b);
524 bool road_placeable = GameMap::getInstance()->canPutBuilding
525 (Maptile::ROAD, 1, tile);
528 //overwrite existing roads
529 if (GameMap::getRoad(tile) != NULL)
530 GameMap::getInstance()->removeRoad(tile);
535 int type = CreateScenario::calculateRoadType(tile);
536 Road *r = new Road(tile, type);
537 GameMap::getInstance()->putRoad(r);
539 changed_tiles.pos -= Vector<int>(1, 1);
540 changed_tiles.dim = Vector<int>(3, 3);
544 if (maptile->getMaptileType() != Tile::WATER)
548 GameMap::getInstance()->getTile(tile)->getBackpack();
549 BackpackEditorDialog d(dynamic_cast<Backpack*>(bag));
556 if (changed_tiles.w > 0 && changed_tiles.h > 0)
557 map_tiles_changed.emit(changed_tiles);
559 draw(Playerlist::getViewingplayer());
562 void EditorBigMap::smooth_view()
564 GameMap::getInstance()->applyTileStyles(view.y, view.x, view.y+view.h,
565 view.x+view.w, true);
566 draw(Playerlist::getViewingplayer());
569 void EditorBigMap::after_draw()
571 int tilesize = GameMap::getInstance()->getTileset()->getTileSize();
572 std::vector<Vector<int> > tiles;
574 if (show_tile_types_instead_of_tile_styles)
576 tiles = get_screen_tiles();
577 for (std::vector<Vector<int> >::iterator i = tiles.begin(),
578 end = tiles.end(); i != end; ++i)
580 Vector<int> pos = tile_to_buffer_pos(*i);
581 buffer_gc->set_rgb_fg_color(GameMap::getInstance()->getTile(*i)->getColor());
591 buffer->draw_rectangle (buffer_gc, true, x, y, ts, ts);
595 // we need to draw a drawing cursor on the map
596 tiles = get_cursor_tiles();
599 Gdk::Color terrain_box_color = Gdk::Color();
600 terrain_box_color.set_rgb_p(200.0/255.0, 200.0/255.0, 200.0/255.0);
601 Gdk::Color erase_box_color = Gdk::Color();
602 erase_box_color.set_rgb_p(200.0/255.0, 50.0/255.0, 50.0/255.0);
603 Gdk::Color move_box_color = Gdk::Color();
604 move_box_color.set_rgb_p(50.0/255.0, 200.0/255.0, 50.0/255.0);
605 Gdk::Color moving_box_color = Gdk::Color();
606 moving_box_color.set_rgb_p(50.0/255.0, 50.0/255.0, 200.0/255.0);
607 for (std::vector<Vector<int> >::iterator i = tiles.begin(),
608 end = tiles.end(); i != end; ++i)
610 Vector<int> pos = tile_to_buffer_pos(*i);
621 buffer_gc->set_rgb_fg_color (terrain_box_color);
622 buffer->draw_rectangle (buffer_gc, false, pos.x + 1, pos.y + 1,
623 tilesize - 1, tilesize -1);
627 buffer_gc->set_rgb_fg_color (erase_box_color);
628 buffer->draw_rectangle (buffer_gc, false, pos.x + 1, pos.y + 1,
629 tilesize - 1, tilesize -1);
633 if (moving_objects_from != Vector<int>(-1,-1))
634 buffer_gc->set_rgb_fg_color (moving_box_color);
636 buffer_gc->set_rgb_fg_color (move_box_color);
637 buffer->draw_rectangle (buffer_gc, false, pos.x + 1, pos.y + 1,
638 tilesize - 1, tilesize -1);
642 pic = GraphicsCache::getInstance()->getArmyPic
643 (Playerlist::getInstance()->getActiveplayer()->getArmyset(), 0,
644 Playerlist::getInstance()->getActiveplayer(), NULL);
645 pic->blit(buffer, pos);
649 pic = GraphicsCache::getInstance()->getCityPic(0, Playerlist::getInstance()->getActiveplayer(), GameMap::getInstance()->getCityset()->getId());
650 pic->blit(buffer, pos);
654 pic = GraphicsCache::getInstance()->getRuinPic(0, GameMap::getInstance()->getCityset()->getId());
655 pic->blit(buffer, pos);
659 pic = GraphicsCache::getInstance()->getTemplePic(0, GameMap::getInstance()->getCityset()->getId());
660 pic->blit(buffer, pos);
664 pic = GraphicsCache::getInstance()->getSignpostPic();
665 pic->blit(buffer, pos);
669 pic = GraphicsCache::getInstance()->getRoadPic(CreateScenario::calculateRoadType(*i));
670 pic->blit(buffer, pos);
673 pic = GraphicsCache::getInstance()->getPortPic();
674 pic->blit(buffer, pos);
677 pic = GraphicsCache::getInstance()->getBridgePic(tile_to_bridge_type(*i));
678 pic->blit(buffer, pos);
681 pic = GraphicsCache::getInstance()->getBagPic();
682 pic->blit(buffer, pos);