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