1 // Copyright (C) 2003 Michael Bartl
2 // Copyright (C) 2003, 2004, 2005, 2006, 2007 Ulf Lorenz
3 // Copyright (C) 2004, 2005 Bryan Duff
4 // Copyright (C) 2004, 2005, 2006 Andrea Paternesi
5 // Copyright (C) 2006, 2007, 2008, 2009, 2010, 2014, 2015, 2016, 2017,
6 // 2020 Ben Asselstine
7 // Copyright (C) 2007 Ole Laursen
8 //
9 //  This program is free software; you can redistribute it and/or modify
10 //  it under the terms of the GNU General Public License as published by
11 //  the Free Software Foundation; either version 3 of the License, or
12 //  (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU Library General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 //  02110-1301, USA.
23 
24 #include <config.h>
25 
26 #include <assert.h>
27 
28 #include "bigmap.h"
29 
30 #include "army.h"
31 #include "Item.h"
32 #include "stacklist.h"
33 #include "stack.h"
34 #include "city.h"
35 #include "ruin.h"
36 #include "signpost.h"
37 #include "temple.h"
38 #include "port.h"
39 #include "bridge.h"
40 #include "road.h"
41 #include "stone.h"
42 #include "playerlist.h"
43 #include "File.h"
44 #include "stacktile.h"
45 #include "GameMap.h"
46 #include "ImageCache.h"
47 #include "MapRenderer.h"
48 #include "FogMap.h"
49 #include "MapBackpack.h"
50 #include "GameScenarioOptions.h"
51 #include "tileset.h"
52 
53 #include <iostream>
54 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
55 #define debug(x)
56 
57 bool BigMap::s_show_hidden_ruins;
58 
BigMap(bool headless)59 BigMap::BigMap(bool headless)
60     : d_headless (headless), d_renderer(0), buffer(0), d_fighting(LocationBox(Vector<int>(-1,-1)))
61 {
62     // note: we are not fully initialized before set_view is called
63     view.x = view.y = 0;
64     view.w = 0;
65     view.h = 0;
66     deltax = 0;
67     deltay = 0;
68     view_pos = Vector<int>(0,0);
69     input_locked = false;
70     d_grid_toggled = false;
71 
72     blank_screen = false;
73     image = Gtk::Allocation(0, 0, 320, 200);
74 }
75 
~BigMap()76 BigMap::~BigMap()
77 {
78     if (buffer)
79       buffer.clear();
80 
81     delete d_renderer;
82 }
83 
set_view(LwRectangle new_view)84 void BigMap::set_view(LwRectangle new_view)
85 {
86     int tilesize = GameMap::getInstance()->getTileSize();
87 
88     int width = image.get_width();
89     int height = image.get_height();
90     if (view.dim == new_view.dim && buffer && image.get_width() == width && image.get_height() == height)
91     {
92 	// someone wants us to move the view, not resize it, no need to
93 	// construct new surfaces and all that stuff
94 	//
95 	// fixme: if we're moving the view, maybe there's some pixmap in common
96 	// between this view and the new view.  why render?
97 
98 	view = new_view;
99 	Vector<int> new_view_pos = get_view_pos_from_view();
100 
101 	if (view_pos != new_view_pos)
102 	{
103 	    view_pos = new_view_pos;
104 	    draw();
105 	}
106 
107 	return;
108     }
109 
110     view = new_view;
111     view_pos = get_view_pos_from_view();
112 
113     // now create a buffer surface which is two maptiles wider and
114     // higher than the screen you actually see. That is how smooth scrolling
115     // becomes comparatively easy. You just blit from the extended screen to
116     // the screen with some offset.
117     // this represents a 1 tile border around the outside of the picture.
118     // it gets rid of the black border.
119 
120     if (buffer)
121       buffer.clear();
122 
123     buffer_view.dim = view.dim + Vector<int>(2, 2);
124 
125     Cairo::RefPtr<Cairo::Surface> empty = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, buffer_view.w *tilesize, buffer_view.h * tilesize);
126     buffer = Cairo::Surface::create (empty, Cairo::CONTENT_COLOR_ALPHA, buffer_view.w * tilesize, buffer_view.h * tilesize);
127     buffer_gc = Cairo::Context::create(buffer);
128 
129     //now create the part that will go out to the gtk::image
130     if (outgoing)
131       outgoing.clear();
132     outgoing = Cairo::Surface::create(buffer, Cairo::CONTENT_COLOR_ALPHA, image.get_width(), image.get_height());
133 
134 
135     if (d_renderer)
136         delete d_renderer;
137     // now set the MapRenderer so that it draws on the buffer
138     d_renderer = new MapRenderer(buffer);
139 }
140 
clip_viewable_buffer(Cairo::RefPtr<Cairo::Surface> pixmap,Vector<int> pos,Cairo::RefPtr<Cairo::Surface> out)141 void BigMap::clip_viewable_buffer(Cairo::RefPtr<Cairo::Surface> pixmap, Vector<int> pos, Cairo::RefPtr<Cairo::Surface> out)
142 {
143   Cairo::RefPtr<Cairo::Context> out_gc = Cairo::Context::create(out);
144   out_gc->rectangle(0, 0, image.get_width(), image.get_height());
145   out_gc->clip();
146   out_gc->save();
147   out_gc->set_source(pixmap, -pos.x, -pos.y);
148   out_gc->rectangle (0, 0, image.get_width(), image.get_height());
149   out_gc->clip();
150   out_gc->paint();
151   out_gc->restore();
152   return;
153 }
154 
draw(bool redraw_buffer)155 void BigMap::draw(bool redraw_buffer)
156 {
157     // no size and buffer yet, return
158     if (!buffer || d_headless)
159         return;
160     //Playerlist::getInstance()->setViewingplayer(player);
161 
162     int tilesize = GameMap::getInstance()->getTileSize();
163 
164     // align the buffer view
165     Vector<int> new_buffer_view = clip(
166 	Vector<int>(0, 0),
167 	view.pos - Vector<int>(1, 1),
168 	GameMap::get_dim() - buffer_view.dim + Vector<int>(1, 1));
169     buffer_view.pos = new_buffer_view;
170 
171     // redraw the buffer
172     if (redraw_buffer)
173       draw_buffer();
174 
175     // blit the visible part of buffer to the screen
176     Vector<int> p = view_pos - (buffer_view.pos * tilesize);
177     outgoing.clear();
178     outgoing = Cairo::Surface::create(buffer, Cairo::CONTENT_COLOR_ALPHA, image.get_width(), image.get_height());
179     clip_viewable_buffer(buffer, p, outgoing);
180 
181     if (blank_screen)
182       {
183 	int width = image.get_width();
184 	int height = image.get_height();
185 	Cairo::RefPtr<Cairo::Context> outgoing_gc = Cairo::Context::create(outgoing);
186 	outgoing_gc->set_source_rgba(FOG_COLOUR.get_red(), FOG_COLOUR.get_green(), FOG_COLOUR.get_blue(), FOG_COLOUR.get_alpha());
187 	outgoing_gc->rectangle(0, 0, width, height);
188 	outgoing_gc->fill();
189       }
190     map_changed.emit(outgoing);
191 }
192 
screen_size_changed(Gtk::Allocation box)193 void BigMap::screen_size_changed(Gtk::Allocation box)
194 {
195     int ts = GameMap::getInstance()->getTileSize();
196 
197     LwRectangle new_view = view;
198 
199     new_view.w = box.get_width() / ts;
200     new_view.h = box.get_height() / ts;
201 
202     if (new_view.w <= GameMap::getWidth() && new_view.h <= GameMap::getHeight()
203 	&& new_view.w >= 0 && new_view.h >= 0)
204       {
205 	new_view.pos = clip(Vector<int>(0,0), new_view.pos,
206 			    GameMap::get_dim() - new_view.dim);
207 	image = box;
208 	set_view(new_view);
209 	view_changed.emit(view);
210       }
211     image = box;
212 }
213 
get_view_pos_from_view()214 Vector<int> BigMap::get_view_pos_from_view()
215 {
216     Vector<int> screen_dim(image.get_width(), image.get_height());
217     int ts = GameMap::getInstance()->getTileSize();
218 
219     // clip to make sure we don't see a black border at the bottom and right
220     return clip(Vector<int>(0, 0), view.pos * ts,
221 		GameMap::get_dim() * ts - screen_dim);
222 }
223 
tile_to_buffer_pos(Vector<int> tile)224 Vector<int> BigMap::tile_to_buffer_pos(Vector<int> tile)
225 {
226     int ts = GameMap::getInstance()->getTileSize();
227     return (tile - buffer_view.pos) * ts;
228 }
229 
mouse_pos_to_tile(Vector<int> pos)230 Vector<int> BigMap::mouse_pos_to_tile(Vector<int> pos)
231 {
232     int ts = GameMap::getInstance()->getTileSize();
233     return (view_pos + pos) / ts;
234 }
235 
mouse_pos_to_tile_offset(Vector<int> pos)236 Vector<int> BigMap::mouse_pos_to_tile_offset(Vector<int> pos)
237 {
238     int ts = GameMap::getInstance()->getTileSize();
239     return (view_pos + pos) % ts;
240 }
241 
map_tip_position(Vector<int> tile)242 MapTipPosition BigMap::map_tip_position(Vector<int> tile)
243 {
244   return map_tip_position (LwRectangle(tile.x, tile.y, 1, 1));
245 }
246 
map_tip_position(LwRectangle tile_area)247 MapTipPosition BigMap::map_tip_position(LwRectangle tile_area)
248 {
249     // convert area to pixels on the screen
250     int tilesize = GameMap::getInstance()->getTileSize();
251 
252     LwRectangle area(tile_area.pos * tilesize - view_pos,
253 		   tile_area.dim * tilesize);
254 
255     // calculate screen edge distances
256     int left, right, top, bottom;
257 
258     left = area.x;
259     right = image.get_width() - (area.x + area.w);
260     top = area.y;
261     bottom = image.get_height() - (area.y + area.h);
262 
263     int const MARGIN = 2;
264 
265     // then set the position
266     MapTipPosition m;
267     if (right >= left && right >= top && right >= bottom)
268     {
269 	m.pos.x = area.x + area.w + MARGIN;
270 	m.pos.y = area.y;
271 	m.justification = MapTipPosition::LEFT;
272     }
273     else if (left >= top && left >= bottom)
274     {
275 	m.pos.x = area.x - MARGIN;
276 	m.pos.y = area.y;
277 	m.justification = MapTipPosition::RIGHT;
278     }
279     else if (bottom >= top)
280     {
281 	m.pos.x = area.x;
282 	m.pos.y = area.y + area.h + MARGIN;
283 	m.justification = MapTipPosition::TOP;
284     }
285     else
286     {
287 	m.pos.x = area.x;
288 	m.pos.y = area.y - MARGIN;
289 	m.justification = MapTipPosition::BOTTOM;
290     }
291 
292     return m;
293 }
294 
blit_object(const Location & obj,Vector<int> tile,PixMask * im,Cairo::RefPtr<Cairo::Surface> surface)295 void BigMap::blit_object(const Location &obj, Vector<int> tile, PixMask *im, Cairo::RefPtr<Cairo::Surface> surface)
296 {
297   Vector<int> diff = tile - obj.getPos();
298   int tilesize = GameMap::getInstance()->getTileSize();
299   Vector<int> p = tile_to_buffer_pos(tile);
300   im->blit(diff, tilesize, surface, p);
301 }
302 
draw_stack(Stack * s,Cairo::RefPtr<Cairo::Surface> surface)303 void BigMap::draw_stack(Stack *s, Cairo::RefPtr<Cairo::Surface> surface)
304 {
305   //this routine is for drawing the active stack.
306   //for all other stacks see ImageCache::draw_tile_pic
307   Vector<int> p = s->getPos();
308   Player *player = s->getOwner();
309   int tilesize = GameMap::getInstance()->getTileSize();
310 
311   // check if the object lies in the viewed part of the map
312   // otherwise we shouldn't draw it
313   if (is_inside(buffer_view, p) && !s->getDeleting())
314     {
315       if (s->empty())
316 	{
317 	  std::cerr << "WARNING: empty stack found" << std::endl;
318 	  return;
319 	}
320 
321       p = tile_to_buffer_pos(p);
322 
323       // draw stack
324 
325       bool show_army = true;
326       //we don't show the army or the flag if we're in fortified tent.
327       if (s->hasShip())
328 	{
329           PixMask *ship = ImageCache::getInstance()->getShipPic(player)->copy();
330           ship->scale (ship, tilesize, tilesize);
331           ship->blit(surface, p);
332           delete ship;
333 	}
334       else
335 	{
336 	  if (s->getFortified() == true)
337 	    {
338 	      //We don't show the active stack here.
339 	      if (player->getStacklist()->getActivestack() != s &&
340 		  player == Playerlist::getActiveplayer())
341 		show_army = false;
342 	      Maptile *tile = GameMap::getInstance()->getTile(s->getPos());
343 	      if (tile->getBuilding() != Maptile::CITY &&
344 		  tile->getBuilding() != Maptile::RUIN &&
345 		  tile->getBuilding() != Maptile::TEMPLE)
346                 {
347                   PixMask *tower = ImageCache::getInstance()->getTowerPic(player)->copy();
348                   tower->scale (tower, tilesize, tilesize);
349                   tower->blit(surface, p);
350                   delete tower;
351                 }
352 	      else
353 		show_army = true;
354 	    }
355 
356 	  if (show_army == true)
357 	    {
358 	      Army *a = *s->begin();
359 	      PixMask *armypic = ImageCache::getInstance()->getArmyPic(a)->copy();
360               armypic->scale (armypic, tilesize, tilesize);
361               armypic->blit(surface, p);
362               delete armypic;
363 	    }
364 	}
365 
366       if (show_army)
367         {
368           //does our position have us on that stacktile?
369           /*
370            * sometimes the stack tile isn't updated right away.
371            */
372           StackTile *st = GameMap::getStacks(s->getPos());
373           guint32 stacksize;
374           if (!st->contains(s->getId()))
375             stacksize = st->countNumberOfArmies(player) + s->size();
376           else
377             stacksize = st->countNumberOfArmies(player);
378           if (stacksize > MAX_STACK_SIZE)
379             stacksize = MAX_STACK_SIZE;
380           if (stacksize > 0)
381             {
382               PixMask *flag = ImageCache::getInstance()->getFlagPic(stacksize, player)->copy();
383               flag->scale (flag, tilesize, tilesize);
384               flag->blit(surface, p);
385               delete flag;
386 
387             }
388         }
389     }
390 }
391 
draw_buffer()392 void BigMap::draw_buffer()
393 {
394   draw_buffer (buffer_view, buffer);
395   // if we're hidden map this is hosed.
396   after_draw();
397   if (blank_screen == false)
398     {
399       ImageCache *gc = ImageCache::getInstance();
400       int tilesize = GameMap::getInstance()->getTileSize();
401       if (d_fighting.getPos() != Vector<int>(-1,-1))
402         {
403           Vector<int> p = tile_to_buffer_pos(d_fighting.getPos());
404           PixMask *tmp = gc->getExplosionPic()->copy();
405           if (d_fighting.getSize() > 1)
406             {
407               PixMask::scale(tmp, d_fighting.getSize() * tilesize,
408                              d_fighting.getSize() * tilesize);
409             }
410           tmp->blit(buffer, p);
411           delete tmp;
412         }
413     }
414 }
415 
saveAsBitmap(Glib::ustring filename)416 bool BigMap::saveAsBitmap(Glib::ustring filename)
417 {
418   int tilesize = GameMap::getInstance()->getTileSize();
419   int width = GameMap::getWidth() * tilesize;
420   int height = GameMap::getHeight() * tilesize;
421   Cairo::RefPtr<Cairo::Surface> empty = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, width, height);
422   Cairo::RefPtr<Cairo::Surface> surf = Cairo::Surface::create (empty, Cairo::CONTENT_COLOR_ALPHA, width, height);
423 
424   bool orig_grid = d_grid_toggled;
425   d_grid_toggled = false;
426   draw_buffer(LwRectangle (0, 0, GameMap::getWidth(), GameMap::getHeight()), surf);
427   d_grid_toggled = orig_grid;
428   Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create(surf, 0, 0, width, height);
429   pixbuf->save (filename, "png");
430   return true;
431 }
432 
draw_buffer_tile(Vector<int> tile,Cairo::RefPtr<Cairo::Surface> surface)433 void BigMap::draw_buffer_tile(Vector<int> tile, Cairo::RefPtr<Cairo::Surface> surface)
434 {
435   guint32 tilesize = GameMap::getInstance()->getTileSize();
436   Player *viewing = Playerlist::getViewingplayer();
437   ImageCache *gc = ImageCache::getInstance();
438   int tile_style_id = GameMap::getInstance()->getTile(tile)->getTileStyle()->getId();
439   int fog_type_id = 0;
440   if (Playerlist::getViewingplayer()->getType() != Player::HUMAN &&
441       GameScenarioOptions::s_hidden_map == true)
442     fog_type_id = FogMap::ALL;
443   else
444     fog_type_id = viewing->getFogMap()->getShadeTile(tile);
445 
446   bool has_bag = false;
447   bool has_standard = false;
448   guint32 player_standard_id = 0;
449   int stack_size = -1;
450   int stack_player_id = -1;
451   int army_type_id = -1;
452   bool has_ship = false;
453   bool has_tower = false;
454   auto building_type = GameMap::getInstance()->getTile(tile)->getBuilding();
455   Vector<int> building_tile = Vector<int>(-1,-1);
456   int building_subtype = -1;
457   int building_player_id = -1;
458   int stone_type = -1;
459 
460   if (fog_type_id == FogMap::ALL)
461     {
462       //short circuit.  the tile is completely fogged.
463       PixMask *pixmask =
464 	gc->getTilePic(tile_style_id, fog_type_id, has_bag, has_standard,
465 		       player_standard_id, stack_size, stack_player_id,
466 		       army_type_id, has_tower, has_ship, building_type,
467 		       building_subtype, building_tile, building_player_id,
468 		       tilesize, d_grid_toggled, stone_type);
469       pixmask->blit(surface, tile_to_buffer_pos(tile));
470       return;
471     }
472   MapBackpack *backpack = GameMap::getInstance()->getTile(tile)->getBackpack();
473   if (backpack && backpack->empty() == false)
474     {
475       bool standard_planted = false;
476       Item *flag = backpack->getFirstPlantedItem();
477       if (flag)
478 	standard_planted = true;
479 
480       //only show one of the bag or the flag
481       if (standard_planted && flag)
482 	{
483 	  has_standard = true;
484 	  player_standard_id = flag->getPlantableOwner()->getId();
485 	}
486       else
487 	has_bag = true;
488     }
489 
490   Stack *stack = GameMap::getStrongestStack(tile);
491   if (stack)
492     {
493       if (viewing->getFogMap()->isCompletelyObscuredFogTile(tile) == false)
494 	{
495 	  //selected stack gets drawn in gamebigmap
496 	  if (Playerlist::getActiveplayer()->getActivestack() != stack)
497 	    {
498 	      stack_player_id = stack->getOwner()->getId();
499 	      Maptile *m = GameMap::getInstance()->getTile(tile);
500 	      if (stack->getFortified() == true &&
501 		  m->getBuilding() != Maptile::CITY &&
502 		  m->getBuilding() != Maptile::RUIN &&
503 		  m->getBuilding() != Maptile::TEMPLE)
504 		has_tower = true;
505 	      else if (stack->hasShip() == true)
506                 {
507                   has_ship = true;
508                   stack_size = GameMap::getStacks(stack->getPos())->countNumberOfArmies(Playerlist::getInstance()->getPlayer(stack_player_id));
509                   if (stack_size > 0 && (guint)stack_size > MAX_STACK_SIZE)
510                     stack_size = stack->size();
511                   //here we show the number of armies on the tile.
512                   //instead of the number of armies in the stack.
513                   //so that stacks appear whole before we click on them.
514                   //and that a stack of 1 can't hide a stack of 7.
515                 }
516 	      else
517 		{
518 		  army_type_id = (*stack->begin())->getTypeId();
519                   stack_size = GameMap::getStacks(stack->getPos())->countNumberOfArmies(Playerlist::getInstance()->getPlayer(stack_player_id));
520                   if (stack_size > 0 && (guint)stack_size > MAX_STACK_SIZE)
521                     stack_size = stack->size();
522 		}
523 	    }
524 	}
525     }
526 
527   if (building_type != Maptile::NONE)
528     {
529       switch (building_type)
530 	{
531 	case Maptile::CITY:
532 	    {
533 	      City *city = GameMap::getCity(tile);
534 	      building_player_id = city->getOwner()->getId();
535 	      building_tile = tile - city->getPos();
536 	      if (city->isBurnt())
537 		building_subtype = -1;
538 	      else
539 		building_subtype = 0;
540 	    }
541 	  break;
542 	case Maptile::RUIN:
543 	    {
544 	      Ruin *ruin = GameMap::getRuin(tile);
545 	      if (ruin->isHidden() == true && ruin->getOwner() == viewing)
546 		{
547 		  building_tile = tile - ruin->getPos();
548 		  building_subtype = ruin->getType();
549 		}
550 	      else if (ruin->isHidden() == false)
551 		{
552 		  building_tile = tile - ruin->getPos();
553 		  building_subtype = ruin->getType();
554 		}
555               else if (s_show_hidden_ruins)
556                 {
557 		  building_tile = tile - ruin->getPos();
558 		  building_subtype = ruin->getType();
559                 }
560 	      else
561 		building_type = Maptile::NONE;
562 	    }
563 	  break;
564 	case Maptile::TEMPLE:
565 	    {
566 	      Temple *temple = GameMap::getTemple(tile);
567 	      building_tile = tile - temple->getPos();
568 	      building_subtype = temple->getType();
569 	    }
570 	  break;
571 	case Maptile::SIGNPOST:
572 	    {
573 	      Signpost *signpost = GameMap::getSignpost(tile);
574 	      building_tile = tile - signpost->getPos();
575 	    }
576 	  break;
577 	case Maptile::ROAD:
578 	    {
579 	      Road *road = GameMap::getRoad(tile);
580 	      building_tile = tile - road->getPos();
581 	      building_subtype = road->getType();
582               Stone *stone = GameMap::getStone(tile);
583               if (stone)
584                 stone_type = stone->getType();
585 	    }
586 	  break;
587 	case Maptile::STONE:
588 	    {
589               Stone *stone = GameMap::getStone(tile);
590 	      building_tile = tile - stone->getPos();
591 	      building_subtype = stone->getType();
592               stone_type = stone->getType();
593 	    }
594 	  break;
595 	case Maptile::PORT:
596 	    {
597 	      Port *port = GameMap::getPort(tile);
598 	      building_tile = tile - port->getPos();
599 	    }
600 	  break;
601 	case Maptile::BRIDGE:
602 	    {
603 	      Bridge *bridge = GameMap::getBridge(tile);
604 	      building_tile = tile - bridge->getPos();
605 	      building_subtype = bridge->getType();
606 	    }
607 	  break;
608 	case Maptile::NONE: default:
609 	  break;
610 	}
611     }
612   if (GameMap::getTileset()->getStonesFilename().empty() == true)
613     stone_type = -1;
614   PixMask *pixmask =
615     gc->getTilePic(tile_style_id, fog_type_id, has_bag, has_standard,
616 		   player_standard_id, stack_size, stack_player_id,
617 		   army_type_id, has_tower, has_ship, building_type,
618 		   building_subtype, building_tile, building_player_id,
619 		   tilesize, d_grid_toggled, stone_type);
620   pixmask->blit(surface, tile_to_buffer_pos(tile));
621 }
622 
draw_buffer_tiles(LwRectangle map_view,Cairo::RefPtr<Cairo::Surface> surface)623 void BigMap::draw_buffer_tiles(LwRectangle map_view, Cairo::RefPtr<Cairo::Surface> surface)
624 {
625   for (int i = map_view.x; i < map_view.x + map_view.w; i++)
626     for (int j = map_view.y; j < map_view.y + map_view.h; j++)
627       if (i < GameMap::getWidth() && j < GameMap::getHeight())
628 	draw_buffer_tile(Vector<int>(i,j), surface);
629 }
630 
draw_buffer(LwRectangle map_view,Cairo::RefPtr<Cairo::Surface> surface)631 void BigMap::draw_buffer(LwRectangle map_view, Cairo::RefPtr<Cairo::Surface> surface)
632 {
633   draw_buffer_tiles(map_view, surface);
634 }
635 
toggle_grid()636 void BigMap::toggle_grid()
637 {
638   d_grid_toggled = !d_grid_toggled;
639   draw(true);
640 }
641 
blank(bool on)642 void BigMap::blank(bool on)
643 {
644   blank_screen = on;
645   draw (Playerlist::getViewingplayer());
646 }
647 
scroll(GdkEventScroll * event)648 bool BigMap::scroll(GdkEventScroll *event)
649 {
650   if (input_locked)
651     return true;
652   LwRectangle n = view;
653   switch (event->direction)
654     {
655     case GDK_SCROLL_SMOOTH:
656         {
657           double dx, dy;
658           if (gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy))
659             {
660               if (event->state & GDK_SHIFT_MASK)
661                 {
662                   dx*=-1;
663                   dy*=-1;
664                 }
665               if (event->state & GDK_CONTROL_MASK)
666                 {
667                   double swap;
668                   swap = dx;
669                   dx = dy;
670                   dy = swap;
671                 }
672               deltax += dx;
673               deltay += dy;
674               if (deltax <= -1.0 || deltax >= 1.0)
675                 {
676                   n.x += deltax;
677                   deltax += (int)deltax * -1;
678                 }
679               if (deltay <= -1.0 || deltay >= 1.0)
680                 {
681                   n.y += deltay;
682                   deltay += (int)deltay * -1;
683                 }
684             }
685         }
686       break;
687     default:
688       break;
689     }
690   if (n.x < 0)
691     n.x = 0;
692   else if (n.x > GameMap::getWidth()-1)
693     n.x = GameMap::getWidth()-1;
694   if (n.y < 0)
695     n.y = 0;
696   else if (n.y > GameMap::getHeight()-1)
697     n.y = GameMap::getHeight()-1;
698   set_view(n);
699   view_changed.emit(view);
700   return true;
701 }
702 
get_default_zoom_scale(int screen_height)703 double BigMap::get_default_zoom_scale (int screen_height)
704 {
705   //aiming for 40 pixels on a 768 height
706   double target_ts = (double) screen_height * 0.05208333;
707   guint32 ts = GameMap::getInstance ()->getUnscaledTileSize ();
708   return (double)target_ts / (double) ts;
709 }
710