1 //  Copyright (C) 2007 Ole Laursen
2 //  Copyright (C) 2007-2010, 2014, 2015, 2017, 2020 Ben Asselstine
3 //
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.
8 //
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.
13 //
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
17 //  02110-1301, USA.
18 
19 #include <config.h>
20 
21 #include <assert.h>
22 
23 #include "editorbigmap.h"
24 
25 #include "army.h"
26 #include "stacklist.h"
27 #include "stack.h"
28 #include "stacktile.h"
29 #include "citylist.h"
30 #include "city.h"
31 #include "ruinlist.h"
32 #include "ruin.h"
33 #include "signpostlist.h"
34 #include "signpost.h"
35 #include "templelist.h"
36 #include "temple.h"
37 #include "bridgelist.h"
38 #include "bridge.h"
39 #include "portlist.h"
40 #include "port.h"
41 #include "roadlist.h"
42 #include "road.h"
43 #include "stonelist.h"
44 #include "stone.h"
45 #include "playerlist.h"
46 #include "defs.h"
47 #include "File.h"
48 #include "GameMap.h"
49 #include "Configuration.h"
50 #include "rewardlist.h"
51 #include "ImageCache.h"
52 #include "armysetlist.h"
53 #include "CreateScenario.h"
54 #include "Backpack.h"
55 #include "MapBackpack.h"
56 #include "backpack-editor-dialog.h"
57 #include "citysetlist.h"
58 #include "cityset.h"
59 #include "tileset.h"
60 #include "font-size.h"
61 
EditorBigMap()62 EditorBigMap::EditorBigMap()
63  : BigMap(false)
64 {
65   mouse_pos = Vector<int>(-1, -1);
66   prev_mouse_pos = Vector<int>(0, 0);
67 
68   moving_objects_from = Vector<int>(-1,-1);
69   mouse_state = NONE;
70   input_locked = false;
71   pointer = POINTER;
72   pointer_size = 1;
73   pointer_terrain = Tile::GRASS;
74   pointer_tile_style_id = -1;
75   moving_bag = NULL;
76 }
77 
set_pointer(Pointer p,int size,Tile::Type t,int tile_style_id)78 void EditorBigMap::set_pointer(Pointer p, int size, Tile::Type t,
79 			       int tile_style_id)
80 {
81     bool redraw = false;
82     if (pointer != p || pointer_size != size ||
83 	pointer_tile_style_id != tile_style_id)
84       redraw = true;
85     pointer = p;
86     pointer_terrain = t;
87     pointer_size = size;
88     pointer_tile_style_id = tile_style_id;
89 
90     moving_objects_from = Vector<int>(-1,-1);
91     if (redraw)
92       draw();
93 
94 }
95 
mouse_button_event(MouseButtonEvent e)96 void EditorBigMap::mouse_button_event(MouseButtonEvent e)
97 {
98   if (input_locked)
99     return;
100 
101   mouse_pos = e.pos;
102 
103   if (e.button == MouseButtonEvent::LEFT_BUTTON
104       && e.state == MouseButtonEvent::PRESSED &&
105       mouse_state == NONE)
106     change_map_under_cursor();
107   else if (e.button == MouseButtonEvent::LEFT_BUTTON &&
108            e.state == MouseButtonEvent::RELEASED &&
109            mouse_state == MOVE_DRAGGING && pointer == MOVE)
110     {
111       mouse_state = NONE;
112       change_map_under_cursor();
113     }
114   else if (e.button == MouseButtonEvent::RIGHT_BUTTON
115            && e.state == MouseButtonEvent::PRESSED)
116     bring_up_details();
117   return;
118 }
119 
mouse_motion_event(MouseMotionEvent e)120 void EditorBigMap::mouse_motion_event(MouseMotionEvent e)
121 {
122     if (input_locked)
123 	return;
124 
125     bool redraw = false;
126 
127     mouse_pos = e.pos;
128     Vector<int> new_tile = mouse_pos_to_tile(mouse_pos);
129     if (new_tile != mouse_pos_to_tile(prev_mouse_pos))
130     {
131 	mouse_on_tile.emit(new_tile);
132 	redraw = true;
133     }
134 
135     // draw with left mouse button
136     if (e.pressed[MouseMotionEvent::LEFT_BUTTON] &&
137         pointer != MOVE)
138       change_map_under_cursor();
139 
140     // drag with right mouse button
141     if (e.pressed[MouseMotionEvent::RIGHT_BUTTON]
142 	&& (mouse_state == NONE || mouse_state == DRAGGING))
143     {
144 	Vector<int> delta = -(mouse_pos - prev_mouse_pos);
145 
146 	// ignore very small drags to ensure that a shaking mouse does not
147 	// prevent the user from making right clicks
148 	if (mouse_state == NONE && length(delta) <= 2)
149 	    return;
150 
151 	// FIXME: show a drag cursor
152 
153 	int ts = GameMap::getInstance()->getTileSize();
154 	Vector<int> screen_dim(image.get_width(), image.get_height());
155 	view_pos = clip(Vector<int>(0, 0),
156 			view_pos + delta,
157 			GameMap::get_dim() * ts - screen_dim);
158 
159 	// calculate new view position in tiles, rounding up
160 	Vector<int> new_view = (view_pos + Vector<int>(ts - 1, ts - 1)) / ts;
161 
162 	bool redraw_buffer = false;
163 
164 	if (new_view != view.pos)
165 	{
166 	    view.x = new_view.x;
167 	    view.y = new_view.y;
168 	    view_changed.emit(view);
169 	    redraw_buffer = true;
170 	}
171 
172 	draw(redraw_buffer);
173 	redraw = false;
174 	mouse_state = DRAGGING;
175     }
176     else if (e.pressed[MouseMotionEvent::LEFT_BUTTON] &&
177              (mouse_state == NONE || mouse_state == MOVE_DRAGGING) &&
178              pointer == MOVE)
179       mouse_state = MOVE_DRAGGING;
180 
181     if (redraw && pointer != POINTER)
182 	draw();
183 
184     prev_mouse_pos = mouse_pos;
185 }
186 
mouse_leave_event()187 void EditorBigMap::mouse_leave_event()
188 {
189     mouse_pos.x = mouse_pos.y = -10000;
190     mouse_on_tile.emit(Vector<int>(-100, -100));
191     draw();
192 }
193 
get_screen_tiles()194 std::vector<Vector<int> > EditorBigMap::get_screen_tiles()
195 {
196     // find out which tiles are within bounds
197     std::vector<Vector<int> > tiles;
198 
199     for (int y = buffer_view.y; y < buffer_view.y + buffer_view.h; y++)
200       for (int x = buffer_view.x; x < buffer_view.x + buffer_view.w; x++)
201 	{
202 	    Vector<int> tile(x, y);
203 	    if (tile.x >= 0 && tile.x < GameMap::getWidth() &&
204 		tile.y >= 0 && tile.y < GameMap::getHeight())
205 		tiles.push_back(tile);
206 	}
207 
208     return tiles;
209 }
210 
get_cursor_tiles()211 std::vector<Vector<int> > EditorBigMap::get_cursor_tiles()
212 {
213     // find out which cursor tiles are within bounds
214     std::vector<Vector<int> > tiles;
215 
216     Vector<int> current_tile = mouse_pos_to_tile(mouse_pos);
217 
218     for (int y = 0; y < pointer_size; ++y)
219 	for (int x = 0; x < pointer_size; ++x)
220 	{
221 	    int offset = - (pointer_size - 1) / 2;
222 	    Vector<int> tile(x + offset, y + offset);
223 	    tile += current_tile;
224 
225 	    if (tile.x >= 0 && tile.x < GameMap::getWidth() &&
226 		tile.y >= 0 && tile.y < GameMap::getHeight())
227 		tiles.push_back(tile);
228 	}
229 
230     return tiles;
231 }
232 
get_cursor_rectangle()233 LwRectangle EditorBigMap::get_cursor_rectangle()
234 {
235     // find out which cursor tiles are within bounds
236     std::vector<Vector<int> > tiles;
237 
238     Vector<int> current_tile = mouse_pos_to_tile(mouse_pos);
239     int offset = (pointer_size - 1) / 2;
240     Vector<int> tile = current_tile - Vector<int>(offset, offset);
241 
242     return LwRectangle (tile.x, tile.y, pointer_size, pointer_size);
243 }
244 
tile_to_bridge_type(Vector<int> t)245 int EditorBigMap::tile_to_bridge_type(Vector<int> t)
246 {
247     // examine neighbour tiles to discover whether there's a road on them
248     bool u = Roadlist::getInstance()->getObjectAt(t + Vector<int>(0, -1));
249     bool b = Roadlist::getInstance()->getObjectAt(t + Vector<int>(0, 1));
250     bool l = Roadlist::getInstance()->getObjectAt(t + Vector<int>(-1, 0));
251     bool r = Roadlist::getInstance()->getObjectAt(t + Vector<int>(1, 0));
252 
253     // then translate this to the type
254     int type = 0;
255     if (!u && !b && !l && !r)
256 	type = 0;
257     else if (u && b && l && r)
258 	type = 0;
259     else if (!u && b && l && r)
260 	type = 0;
261     else if (u && !b && l && r)
262 	type = 0;
263     else if (u && b && !l && r)
264 	type = 1;
265     else if (u && b && l && !r)
266 	type = 1;
267     else if (u && b && !l && !r)
268 	type = 1;
269     else if (!u && !b && l && r)
270 	type = 0;
271     else if (u && !b && l && !r)
272 	type = 0;
273     else if (u && !b && !l && r)
274 	type = 2;
275     else if (!u && b && l && !r)
276 	type = 0;
277     else if (!u && b && !l && r)
278 	type = 2;
279     else if (u && !b && !l && !r)
280 	type = 3;
281     else if (!u && b && !l && !r)
282 	type = 1;
283     else if (!u && !b && l && !r)
284 	type = 0;
285     else if (!u && !b && !l && r)
286 	type = 2;
287     return type;
288 }
289 
change_map_under_cursor()290 void EditorBigMap::change_map_under_cursor()
291 {
292   Player* active = Playerlist::getInstance()->getActiveplayer();
293   std::vector<Vector<int> > tiles = get_cursor_tiles();
294 
295   if (tiles.size() == 0)
296     return;
297   Vector<int> tile = tiles.front();
298   LwRectangle changed_tiles(tile, Vector<int>(-1, -1));
299   Maptile* maptile = GameMap::getInstance()->getTile(tile);
300   switch (pointer)
301     {
302     case POINTER:
303       bring_up_details();
304       break;
305 
306     case TERRAIN:
307 
308       changed_tiles = GameMap::getInstance()->putTerrain(get_cursor_rectangle(), pointer_terrain, pointer_tile_style_id, true);
309       if (pointer_terrain == Tile::WATER)
310         map_water_changed.emit();
311       break;
312 
313     case MOVE:
314       if (moving_objects_from == Vector<int>(-1,-1))
315         {
316           if (GameMap::getInstance()->getBuilding(tile) != Maptile::NONE ||
317               GameMap::getStack(tile) != NULL ||
318               GameMap::getBackpack(tile)->empty() == false)
319             {
320               moving_objects_from = tile;
321               if (GameMap::getBackpack(tile)->empty() == false)
322                 moving_bag = GameMap::getBackpack (tile);
323             }
324         }
325       else
326         {
327           if (mouse_state == MOVE_DRAGGING)
328             break;
329           Vector<int> from = moving_objects_from;
330           //here we go with the move!
331           GameMap *gm = GameMap::getInstance();
332           if (gm->getStack(from) != NULL)
333             {
334               Stack *s = gm->getStack(from);
335               if (!s)
336                 s = gm->getStack(from);
337               auto enemy_stacks = gm->getEnemyStacks(tile, s->getOwner());
338               if (gm->canPutStack(s->size(), s->getOwner(), tile) == true &&
339                   enemy_stacks.empty() == true)
340                 {
341                   std::vector<Stack*> friendly_stacks = gm->getFriendlyStacks(tile, s->getOwner());
342                   if (friendly_stacks.empty() == true)
343                     gm->moveStack(s, tile);
344                   else
345                     {
346                       gm->moveStack(s, tile);
347                       gm->groupStacks(tile, s->getOwner());
348                       //big hack here.
349                       //apparently the stacktile state is all messed up after
350                       //we group a stack.
351                       //the signals in the game make the game state work
352                       //but we don't to do all that signalling, so we cheat.
353                       gm->clearStackPositions();
354                       gm->updateStackPositions();
355                       //also we need to clear the active stack to have it show.
356                       gm->getStack(tile)->getOwner()->setActivestack(0);
357                     }
358                   changed_tiles = LwRectangle (s->getPos ());
359                 }
360             }
361           else if (gm->getBackpack(from)->empty() == false)
362             {
363               if (gm->canDropBag (tile))
364                 {
365                   if (moving_bag->getPos () != tile)
366                     {
367                       gm->moveBackpack(moving_bag, tile);
368                       changed_tiles = LwRectangle (tile);
369                     }
370                   moving_bag = NULL;
371                 }
372               else
373                 break;
374             }
375           else if (gm->getBuilding(from) != Maptile::NONE)
376             {
377               guint32 s = gm->getBuildingSize(from);
378               if (gm->canPutBuilding
379                   (gm->getBuilding(from), s, tile, false) == true)
380                 {
381                   gm->moveBuilding(from, tile);
382                   changed_tiles = LwRectangle (tile);
383                 }
384               else
385                 {
386                   if (gm->getLocation(from)->contains(tile) ||
387                       LocationBox(tile, s).contains(from))
388                     {
389                       gm->moveBuilding(from, tile);
390                       changed_tiles = LwRectangle (tile);
391                     }
392                 }
393             }
394           moving_objects_from = Vector<int>(-1,-1);
395         }
396       break;
397     case ERASE:
398       // check if there is a building or a stack there and remove it
399       if (GameMap::getInstance()->eraseTile(tile))
400         changed_tiles = LwRectangle (tile);
401       break;
402 
403     case STACK:
404       if (GameMap::getInstance()->getStack(tile) != NULL)
405         {
406           map_selection_seq seq;
407           Stack *s = GameMap::getStack(tile);
408           if (s)
409             seq.push_back(s);
410 
411           if (!seq.empty())
412             objects_selected.emit(seq);
413         }
414       else if (GameMap::getInstance()->canPutStack(1, active, tile) == true)
415         {
416           // Create a new dummy stack. As we don't want to have empty
417           // stacks hanging around, it's assumed that the default armyset
418           // has at least one entry.
419           Stack* s = new Stack(active, tile);
420           const Armysetlist* al = Armysetlist::getInstance();
421           Army* a = new Army(*al->getArmy(active->getArmyset(), 0), active);
422           s->add(a);
423           GameMap::getInstance()->putStack(s);
424           //if we're on a city, change the allegiance of the stack
425           //and it's armies to that of the city
426           changed_tiles = LwRectangle (s->getPos ());
427           if (GameMap::getInstance()->getBuilding(s->getPos()) == Maptile::CITY)
428             {
429               City *c = GameMap::getCity(s->getPos());
430               if (c->getOwner() != active)
431                 {
432                   GameMap::getStacks(s->getPos())->leaving(s);
433                   s = Stacklist::changeOwnership(s, c->getOwner());
434                   GameMap::getStacks(s->getPos())->arriving(s);
435                 }
436             }
437         }
438 
439       break;
440 
441     case CITY:
442       if (GameMap::getInstance()->getBuilding(tile) == Maptile::CITY)
443         {
444           map_selection_seq seq;
445           City *c = GameMap::getCity(tile);
446           if (c)
447             seq.push_back(c);
448 
449           if (!seq.empty())
450             objects_selected.emit(seq);
451         }
452       else
453         {
454           GameMap::getInstance()->putNewCity(tile);
455           changed_tiles = LwRectangle (tile);
456         }
457       break;
458 
459     case RUIN:
460       if (GameMap::getInstance()->getBuilding(tile) == Maptile::RUIN)
461         {
462           map_selection_seq seq;
463           Ruin *r = GameMap::getRuin(tile);
464           if (r)
465             seq.push_back(r);
466 
467           if (!seq.empty())
468             objects_selected.emit(seq);
469         }
470       else
471         {
472           GameMap::getInstance()->putNewRuin(tile);
473           changed_tiles = LwRectangle (tile);
474         }
475       break;
476 
477     case TEMPLE:
478       if (GameMap::getInstance()->getBuilding(tile) == Maptile::TEMPLE)
479         {
480           map_selection_seq seq;
481           Temple *t = GameMap::getTemple(tile);
482           if (t)
483             seq.push_back(t);
484 
485           if (!seq.empty())
486             objects_selected.emit(seq);
487         }
488       else
489         {
490           GameMap::getInstance()->putNewTemple(tile);
491           changed_tiles = LwRectangle (tile);
492         }
493       break;
494 
495     case SIGNPOST:
496         {
497           if (GameMap::getInstance()->getBuilding(tile) == Maptile::SIGNPOST)
498             {
499               map_selection_seq seq;
500               Signpost *s = GameMap::getSignpost(tile);
501               if (s)
502                 seq.push_back(s);
503 
504               if (!seq.empty())
505                 objects_selected.emit(seq);
506             }
507           else
508             {
509               bool signpost_placeable = GameMap::getInstance()->canPutBuilding
510                 (Maptile::SIGNPOST, 1, tile);
511               if (!signpost_placeable)
512                 break;
513               Signpost *s = new Signpost(tile);
514               GameMap::getInstance()->putSignpost(s);
515               changed_tiles = LwRectangle (tile);
516             }
517           break;
518         }
519 
520     case PORT:
521         {
522           bool port_placeable = GameMap::getInstance()->canPutBuilding
523             (Maptile::PORT, 1, tile);
524           if (!port_placeable)
525             break;
526           Port *p = new Port(tile);
527           GameMap::getInstance()->putPort(p);
528           changed_tiles = LwRectangle (tile);
529           break;
530         }
531 
532     case BRIDGE:
533         {
534           if (GameMap::getBridge(tile))
535             {
536               GameMap::getInstance()->removeBridge(tile);
537               Bridge *b = new Bridge(tile, tile_to_bridge_type (tile));
538               GameMap::getInstance()->putBridge(b);
539               changed_tiles = LwRectangle (tile);
540               break;
541             }
542           bool bridge_placeable = GameMap::getInstance()->canPutBuilding
543             (Maptile::BRIDGE, 1, tile);
544           if (!bridge_placeable)
545             break;
546           Bridge *b = new Bridge(tile, tile_to_bridge_type (tile));
547           GameMap::getInstance()->putBridge(b);
548           changed_tiles = LwRectangle (tile);
549           break;
550         }
551 
552     case ROAD:
553         {
554           Maptile::Building bldg =
555             GameMap::getInstance()->getTile(tile)->getBuilding();
556           switch (bldg)
557             {
558             case Maptile::ROAD:
559             case Maptile::STONE:
560             case Maptile::NONE:
561                 {
562                   bool had_stone = GameMap::getStone(tile) != NULL;
563                   if (GameMap::getRoad(tile) != NULL)
564                     GameMap::getInstance()->removeRoad(tile);
565 
566                   int type = CreateScenario::calculateRoadType(tile);
567                   Road *r = new Road(tile, type);
568                   GameMap::getInstance()->putRoad(r);
569                   if (had_stone)
570                     {
571                       Stone *s = new Stone (tile, Road::Type(r->getType()));
572                       GameMap::getInstance()->putStone(s);
573                     }
574 
575                   changed_tiles.pos -= Vector<int>(1, 1);
576                   changed_tiles.dim = Vector<int>(3, 3);
577                 }
578               break;
579             case Maptile::CITY:
580             case Maptile::RUIN:
581             case Maptile::TEMPLE:
582             case Maptile::SIGNPOST:
583             case Maptile::PORT:
584             case Maptile::BRIDGE:
585               break;
586             }
587           break;
588         }
589     case BAG:
590       if (maptile->getType() != Tile::WATER)
591         bag_selected.emit(tile);
592       break;
593 
594     case FIGHT:
595         {
596           Stack *s = GameMap::getStack(tile);
597           if (s)
598             stack_selected_for_battle_calculator.emit(s);
599         }
600       break;
601     case STONE:
602         {
603           if (GameMap::getStone(tile) != NULL)
604             {
605               map_selection_seq seq;
606               seq.push_back(GameMap::getStone(tile));
607               objects_selected.emit(seq);
608             }
609           else
610             {
611               int type = Stone::ROAD_E_AND_W_STONE_N;
612               Road *r = GameMap::getRoad(tile);
613               if (r)
614                 type = Stone::getRandomType(Road::Type(r->getType()));
615               Stone *s = new Stone(tile, type);
616               GameMap::getInstance()->putStone(s);
617               changed_tiles = LwRectangle (tile);
618             }
619         }
620       break;
621     }
622 
623   if (changed_tiles.w > 0 && changed_tiles.h > 0)
624     map_tiles_changed.emit(changed_tiles);
625 
626   draw();
627   return ;
628 }
629 
bring_up_details()630 void EditorBigMap::bring_up_details()
631 {
632   Vector<int> tile = mouse_pos_to_tile(mouse_pos);
633   map_selection_seq seq;
634 
635   if (Stack* s = GameMap::getStack(tile))
636     seq.push_back(s);
637   if (City* c = GameMap::getCity(tile))
638     seq.push_back(c);
639   if (Ruin* r = GameMap::getRuin(tile))
640     seq.push_back(r);
641   if (Signpost* s = GameMap::getSignpost(tile))
642     seq.push_back(s);
643   if (Temple* t = GameMap::getTemple(tile))
644     seq.push_back(t);
645   if (Road* rd = GameMap::getRoad(tile))
646     seq.push_back(rd);
647   MapBackpack *b = GameMap::getInstance()->getTile(tile)->getBackpack();
648   if (b->empty() == false)
649     seq.push_back(b);
650   if (Stone * st = GameMap::getStone(tile))
651     seq.push_back(st);
652 
653   if (!seq.empty())
654     objects_selected.emit(seq);
655 }
656 
smooth_view()657 void EditorBigMap::smooth_view()
658 {
659   GameMap::getInstance()->applyTileStyles(view.y, view.x, view.y+view.h,
660 					  view.x+view.w, true);
661   CreateScenario::updateRoadsBridgesAndStones ();
662   draw();
663 }
664 
display_moving_building(Vector<int> src,Vector<int> dest)665 void EditorBigMap::display_moving_building(Vector<int> src, Vector<int> dest)
666 {
667   PixMask *pic = NULL;
668   double scale = GameMap::getCityset()->get_scale ();
669   switch (GameMap::getInstance()->getBuilding(src))
670     {
671     case Maptile::CITY:
672       pic = ImageCache::getInstance()->getCityPic (GameMap::getCity (src));
673       break;
674     case Maptile::RUIN:
675       pic = ImageCache::getInstance()->getRuinPic (GameMap::getRuin (src));
676       break;
677     case Maptile::TEMPLE:
678       pic = ImageCache::getInstance()->getTemplePic (GameMap::getTemple (src));
679       break;
680     case Maptile::SIGNPOST:
681       pic = ImageCache::getInstance()->getSignpostPic ();
682       break;
683     case Maptile::ROAD:
684       pic = ImageCache::getInstance()->getRoadPic (GameMap::getRoad (src));
685       break;
686     case Maptile::STONE:
687       pic = GameMap::getTileset()->getStoneImage (GameMap::getStone (src)->getType());
688       scale = GameMap::getTileset()->get_scale ();
689       break;
690     case Maptile::PORT:
691       pic = ImageCache::getInstance()->getPortPic ();
692       break;
693     case Maptile::BRIDGE:
694       pic = ImageCache::getInstance()->getBridgePic (GameMap::getBridge (src));
695       break;
696     default:
697       break;
698     }
699   if (pic)
700     {
701       PixMask *p = pic->copy ();
702       double new_height = p->get_unscaled_height () * scale;
703       int new_width =
704         ImageCache::calculate_width_from_adjusted_height (p, new_height);
705       PixMask::scale (p, new_width, new_height);
706       p->blit(buffer, dest);
707       delete p;
708     }
709   if (GameMap::getInstance()->getBuilding(src) == Maptile::ROAD)
710     {
711       if (GameMap::getStone(src))
712         {
713           PixMask *stone = GameMap::getTileset()->getStoneImage (GameMap::getStone (src)->getType());
714           if (stone)
715             {
716               PixMask *p = stone->copy ();
717               double new_height = p->get_unscaled_height () * scale;
718               int new_width =
719                 ImageCache::calculate_width_from_adjusted_height
720                 (p, new_height);
721               PixMask::scale (p, new_width, new_height);
722               p->blit(buffer, dest);
723               delete p;
724             }
725         }
726     }
727 }
728 
blit(PixMask * src,Cairo::RefPtr<Cairo::Surface> dest,Vector<int> pos,double scale)729 void EditorBigMap::blit (PixMask *src, Cairo::RefPtr<Cairo::Surface> dest, Vector<int> pos, double scale)
730 {
731   PixMask *p = src->copy ();
732   double new_height = p->get_unscaled_height () * scale;
733   int new_width =
734     ImageCache::calculate_width_from_adjusted_height (p, new_height);
735   PixMask::scale (p, new_width, new_height);
736   p->blit(dest, pos);
737   delete p;
738 }
739 
after_draw()740 void EditorBigMap::after_draw()
741 {
742   guint32 army_set_id = Playerlist::getActiveplayer()->getArmyset();
743   Armyset *armyset = Armysetlist::getInstance()->get(army_set_id);
744 
745   int tilesize = GameMap::getInstance()->getTileSize();
746   std::vector<Vector<int> > tiles;
747 
748   if (mouse_pos == Vector<int>(-1,-1))
749     return;
750 
751   // we need to draw a drawing cursor on the map
752   tiles = get_cursor_tiles();
753   // draw each tile
754 
755   Gdk::RGBA terrain_box_color = Gdk::RGBA();
756   terrain_box_color.set_rgba(200.0/255.0, 200.0/255.0, 200.0/255.0);
757   Gdk::RGBA erase_box_color = Gdk::RGBA();
758   erase_box_color.set_rgba(1.0, 1.0, 1.0);
759   Gdk::RGBA move_box_color = Gdk::RGBA();
760   move_box_color.set_rgba(50.0/255.0, 200.0/255.0, 50.0/255.0);
761   Gdk::RGBA moving_box_color = Gdk::RGBA();
762   moving_box_color.set_rgba(250.0/255.0, 250.0/255.0, 0.0/255.0);
763   for (std::vector<Vector<int> >::iterator i = tiles.begin(),
764        end = tiles.end(); i != end; ++i)
765     {
766       Vector<int> pos = tile_to_buffer_pos(*i);
767 
768       PixMask *pic;
769 
770 
771       switch (pointer)
772         {
773         case POINTER:
774           break;
775 
776         case TERRAIN:
777           buffer_gc->set_source_rgb(terrain_box_color.get_red(),
778                                     terrain_box_color.get_green(),
779                                     terrain_box_color.get_blue());
780           buffer_gc->move_to(pos.x+1, pos.y+1);
781           buffer_gc->rel_line_to(tilesize-2, 0);
782           buffer_gc->rel_line_to(0, tilesize-2);
783           buffer_gc->rel_line_to(-tilesize +2, 0);
784           buffer_gc->rel_line_to(0, -tilesize+2);
785           buffer_gc->set_line_width(1.0);
786           buffer_gc->unset_dash ();
787           buffer_gc->stroke();
788           break;
789 
790         case ERASE:
791           buffer_gc->set_source_rgb(erase_box_color.get_red(),
792                                     erase_box_color.get_green(),
793                                     erase_box_color.get_blue());
794           buffer_gc->move_to(pos.x+1, pos.y+1);
795           buffer_gc->rel_line_to(tilesize-2, 0);
796           buffer_gc->rel_line_to(0, tilesize-2);
797           buffer_gc->rel_line_to(-tilesize +2, 0);
798           buffer_gc->rel_line_to(0, -tilesize+2);
799           buffer_gc->set_line_width(1.0);
800             {
801               std::vector<double> dashes;
802               dashes.push_back (tilesize / 7);
803               dashes.push_back (tilesize / 7);
804               buffer_gc->set_dash (dashes, 0);
805             }
806           buffer_gc->stroke();
807           break;
808 
809         case MOVE:
810 
811           buffer_gc->unset_dash ();
812           if (moving_objects_from != Vector<int>(-1,-1))
813             {
814               Vector<int> tile = *i;
815               buffer_gc->set_source_rgb(moving_box_color.get_red(),
816                                         moving_box_color.get_green(),
817                                         moving_box_color.get_blue());
818               GameMap *gm = GameMap::getInstance();
819               Vector<int> from = moving_objects_from;
820               if (gm->getStack(from) != NULL)
821                 {
822                   Stack *s = gm->getStack(from);
823                   if (!s)
824                     s = gm->getStack(from);
825                   std::vector<Stack *> enemy_stacks =
826                     gm->getEnemyStacks(tile, s->getOwner());
827                   if (gm->canPutStack(s->size(), s->getOwner(), tile) == true &&
828                       enemy_stacks.empty() == true)
829                     {
830                       Playerlist *plist = Playerlist::getInstance();
831                       pic = ImageCache::getInstance()->getArmyPic
832                         (s->getOwner()->getArmyset(), 0,
833                          s->getOwner (), NULL, true, 0);
834                       blit (pic, buffer, pos, armyset->get_scale ());
835                       Player *o = plist->getActiveplayer ();
836                       plist->setActiveplayer (s->getOwner());
837                       pic = ImageCache::getInstance()->getFlagPic
838                         (gm->countArmyUnits(s->getPos()),
839                          s->getOwner ());
840                       plist->setActiveplayer (o);
841                       blit (pic, buffer, pos, gm->getTileset()->get_scale ());
842                     }
843                 }
844               else if (gm->getBackpack(from)->empty() == false)
845                 {
846                   pic = ImageCache::getInstance()->getBagPic();
847                   blit (pic, buffer, pos, armyset->get_scale ());
848                 }
849               else if (gm->getBuilding(from) != Maptile::NONE)
850                 {
851                   guint32 s = gm->getBuildingSize(from);
852                   bool same = false;
853                   if (gm->getLocation(from)->contains(tile) ||
854                       LocationBox(tile, s).contains(from))
855                     same = true;
856                   if (gm->canPutBuilding
857                       (gm->getBuilding(from), s, tile, false) == true ||
858                       same)
859                     display_moving_building (from, pos);
860                 }
861             }
862           else
863             buffer_gc->set_source_rgb(move_box_color.get_red(),
864                                       move_box_color.get_green(),
865                                       move_box_color.get_blue());
866           buffer_gc->move_to(pos.x+1, pos.y+1);
867           buffer_gc->rel_line_to(tilesize-2, 0);
868           buffer_gc->rel_line_to(0, tilesize-2);
869           buffer_gc->rel_line_to(-tilesize +2, 0);
870           buffer_gc->rel_line_to(0, -tilesize+2);
871           buffer_gc->set_line_width(1.0);
872           buffer_gc->stroke();
873           break;
874 
875         case STACK:
876           pic = ImageCache::getInstance()->getArmyPic
877             (Playerlist::getInstance()->getActiveplayer()->getArmyset(), 0,
878              Playerlist::getInstance()->getActiveplayer(), NULL, true, 0);
879 
880           blit (pic, buffer, pos, armyset->get_scale ());
881           break;
882 
883         case CITY:
884           pic = ImageCache::getInstance()->getCityPic(0, Playerlist::getInstance()->getActiveplayer(), GameMap::getInstance()->getCitysetId());
885           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
886           break;
887 
888         case RUIN:
889           pic = ImageCache::getInstance()->getRuinPic(0, GameMap::getInstance()->getCitysetId());
890           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
891           break;
892 
893         case TEMPLE:
894           pic = ImageCache::getInstance()->getTemplePic(0, GameMap::getInstance()->getCitysetId());
895           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
896           break;
897 
898         case SIGNPOST:
899           pic = ImageCache::getInstance()->getSignpostPic();
900           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
901           break;
902 
903         case ROAD:
904             {
905               Road *r = GameMap::getRoad(*i);
906               if (r)
907                 pic = ImageCache::getInstance()->getRoadPic(r->getType());
908               else
909                 pic = ImageCache::getInstance()->getRoadPic(CreateScenario::calculateRoadType(*i));
910               blit (pic, buffer, pos, GameMap::getTileset()->get_scale ());
911             }
912           break;
913         case STONE:
914             {
915               Tileset *t = GameMap::getTileset();
916               Stone *s = GameMap::getStone(*i);
917               if (s)
918                 pic = t->getStoneImage(s->getType());
919               else
920                 {
921                   Road *r = GameMap::getRoad(*i);
922                   if (r)
923                     pic = t->getStoneImage(Stone::getRandomType
924                                            (Road::Type(r->getType())));
925                   else
926                     pic = t->getStoneImage
927                       (Stone::ROAD_ALL_DIRECTIONS_STONES_NW_NE_SW_SE);
928                 }
929               if (pic)
930                 blit (pic, buffer, pos, GameMap::getTileset()->get_scale ());
931             }
932           break;
933         case PORT:
934           pic = ImageCache::getInstance()->getPortPic();
935           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
936           break;
937         case BRIDGE:
938           pic = ImageCache::getInstance()->getBridgePic(tile_to_bridge_type(*i));
939           blit (pic, buffer, pos, GameMap::getCityset()->get_scale ());
940           break;
941         case BAG:
942             {
943               pic = ImageCache::getInstance()->getBagPic();
944               //Vector<int> offset = Vector<int>(tilesize,tilesize) -
945                 //Vector<int>(pic->get_width(), pic->get_height());
946               blit (pic, buffer, pos, armyset->get_scale ());
947             }
948           break;
949         case FIGHT:
950             {
951               pic =
952                 ImageCache::getInstance()->getCursorPic
953                 (ImageCache::SWORD, FontSize::getInstance ()->get_height ());
954               PixMask *copy = pic->copy();
955               PixMask::scale (copy, tilesize * 0.66, tilesize * 0.66);
956               copy->blit_centered(buffer, pos +
957                          Vector<int>(tilesize /2, tilesize /2));
958               delete copy;
959             }
960           break;
961         }
962     }
963   return;
964 }
965