TickHook: Fix crash when TickHook isn't set.
[gemrb.git] / gemrb / core / GUI / WorldMapControl.cpp
bloba0591b0430cb6983af0d41bcdc14f3171d7ddb56
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (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 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 02110-1301, USA.
20 #include "GUI/WorldMapControl.h"
22 #include "win32def.h"
24 #include "Game.h"
25 #include "GameData.h"
26 #include "Interface.h"
27 #include "Video.h"
28 #include "WorldMap.h"
30 #define MAP_TO_SCREENX(x) XWin + XPos - ScrollX + (x)
31 #define MAP_TO_SCREENY(y) YWin + YPos - ScrollY + (y)
33 WorldMapControl::WorldMapControl(const char *font, int direction)
35 ScrollX = 0;
36 ScrollY = 0;
37 MouseIsDown = false;
38 Changed = true;
39 Area = NULL;
40 Value = direction;
41 Game* game = core->GetGame();
42 WorldMap* worldmap = core->GetWorldMap();
43 strncpy(currentArea, game->CurrentArea, 8);
44 int entry = core->GetAreaAlias(currentArea);
45 if (entry >= 0) {
46 WMPAreaEntry *m = worldmap->GetEntry(entry);
47 strncpy(currentArea, m->AreaResRef, 8);
50 //if there is no trivial area, look harder
51 if (!worldmap->GetArea(currentArea, (unsigned int &) entry) &&
52 core->HasFeature(GF_FLEXIBLE_WMAP) ) {
53 WMPAreaEntry *m = worldmap->FindNearestEntry(currentArea, (unsigned int &) entry);
54 if (m) {
55 strncpy(currentArea, m->AreaResRef, 8);
59 //this also updates visible locations
60 worldmap->CalculateDistances(currentArea, Value);
62 // alpha bit is unfortunately ignored
63 if (font[0]) {
64 ftext = core->GetFont(font);
65 } else {
66 ftext = NULL;
69 // initialize label colors
70 Color normal = { 0xf0, 0xf0, 0xf0, 0xff };
71 Color selected = { 0xf0, 0x80, 0x80, 0xff };
72 Color notvisited = { 0x80, 0x80, 0xf0, 0xff };
73 Color black = { 0x00, 0x00, 0x00, 0x00 };
75 pal_normal = core->CreatePalette ( normal, black );
76 pal_selected = core->CreatePalette ( selected, black );
77 pal_notvisited = core->CreatePalette ( notvisited, black );
80 ResetEventHandler( WorldMapControlOnPress );
81 ResetEventHandler( WorldMapControlOnEnter );
84 WorldMapControl::~WorldMapControl(void)
86 //Video *video = core->GetVideoDriver();
88 gamedata->FreePalette( pal_normal );
89 gamedata->FreePalette( pal_selected );
90 gamedata->FreePalette( pal_notvisited );
93 /** Draws the Control on the Output Display */
94 void WorldMapControl::Draw(unsigned short XWin, unsigned short YWin)
96 WorldMap* worldmap = core->GetWorldMap();
97 if (!Width || !Height) {
98 return;
100 if(!Changed)
101 return;
102 Changed = false;
103 Video* video = core->GetVideoDriver();
104 Region r( XWin+XPos, YWin+YPos, Width, Height );
105 Region clipbackup;
106 video->GetClipRect(clipbackup);
107 video->SetClipRect(&r);
108 video->BlitSprite( worldmap->GetMapMOS(), MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r );
110 unsigned int i;
111 unsigned int ec = worldmap->GetEntryCount();
112 for(i=0;i<ec;i++) {
113 WMPAreaEntry *m = worldmap->GetEntry(i);
114 if (! (m->GetAreaStatus() & WMP_ENTRY_VISIBLE)) continue;
116 int xOffs = MAP_TO_SCREENX(m->X);
117 int yOffs = MAP_TO_SCREENY(m->Y);
118 Sprite2D* icon = m->GetMapIcon(worldmap->bam);
119 if( icon ) {
120 video->BlitSprite( icon, xOffs, yOffs, true, &r );
121 video->FreeSprite( icon );
124 if (AnimPicture && !strnicmp(m->AreaResRef, currentArea, 8) ) {
125 core->GetVideoDriver()->BlitSprite( AnimPicture, xOffs, yOffs, true, &r );
129 // Draw WMP entry labels
130 if (ftext==NULL) {
131 video->SetClipRect(&clipbackup);
132 return;
134 for(i=0;i<ec;i++) {
135 WMPAreaEntry *m = worldmap->GetEntry(i);
136 if (! (m->GetAreaStatus() & WMP_ENTRY_VISIBLE)) continue;
137 Sprite2D *icon=m->GetMapIcon(worldmap->bam);
138 int h=0,w=0,xpos=0,ypos=0;
139 if (icon) {
140 h=icon->Height;
141 w=icon->Width;
142 xpos=icon->XPos;
143 ypos=icon->YPos;
144 video->FreeSprite( icon );
147 Region r2 = Region( MAP_TO_SCREENX(m->X-xpos), MAP_TO_SCREENY(m->Y-ypos), w, h );
148 if (!m->GetCaption())
149 continue;
151 int tw = ftext->CalcStringWidth( m->GetCaption() ) + 5;
152 int th = ftext->maxHeight;
154 Palette* text_pal = pal_normal;
156 if (Area == m) {
157 text_pal = pal_selected;
158 } else {
159 if (! (m->GetAreaStatus() & WMP_ENTRY_VISITED)) {
160 text_pal = pal_notvisited;
164 ftext->Print( Region( r2.x + (r2.w - tw)/2, r2.y + r2.h, tw, th ),
165 ( const unsigned char * ) m->GetCaption(), text_pal, 0, true );
167 video->SetClipRect(&clipbackup);
170 /** Key Release Event */
171 void WorldMapControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
173 switch (Key) {
174 case 'f':
175 if (Mod & GEM_MOD_CTRL)
176 core->GetVideoDriver()->ToggleFullscreenMode();
177 break;
178 default:
179 break;
182 void WorldMapControl::AdjustScrolling(short x, short y)
184 WorldMap* worldmap = core->GetWorldMap();
185 if (x || y) {
186 ScrollX += x;
187 ScrollY += y;
188 } else {
189 //center worldmap on current area
190 unsigned entry;
192 WMPAreaEntry *m = worldmap->GetArea(currentArea,entry);
193 if (m) {
194 ScrollX = m->X - Width/2;
195 ScrollY = m->Y - Height/2;
198 Sprite2D *MapMOS = worldmap->GetMapMOS();
199 if (ScrollX > MapMOS->Width - Width)
200 ScrollX = MapMOS->Width - Width;
201 if (ScrollY > MapMOS->Height - Height)
202 ScrollY = MapMOS->Height - Height;
203 if (ScrollX < 0)
204 ScrollX = 0;
205 if (ScrollY < 0)
206 ScrollY = 0;
207 Changed = true;
208 Area = NULL;
211 /** Mouse Over Event */
212 void WorldMapControl::OnMouseOver(unsigned short x, unsigned short y)
214 WorldMap* worldmap = core->GetWorldMap();
215 lastCursor = IE_CURSOR_GRAB;
217 if (MouseIsDown) {
218 AdjustScrolling(lastMouseX-x, lastMouseY-y);
221 lastMouseX = x;
222 lastMouseY = y;
224 if (Value!=(ieDword) -1) {
225 x =(ieWord) (x + ScrollX);
226 y =(ieWord) (y + ScrollY);
228 WMPAreaEntry *oldArea = Area;
229 Area = NULL;
231 unsigned int i;
232 unsigned int ec = worldmap->GetEntryCount();
233 for (i=0;i<ec;i++) {
234 WMPAreaEntry *ae = worldmap->GetEntry(i);
236 if ( (ae->GetAreaStatus() & WMP_ENTRY_WALKABLE)!=WMP_ENTRY_WALKABLE) {
237 continue; //invisible or inaccessible
239 if (!strnicmp(ae->AreaResRef, currentArea, 8) ) {
240 continue; //current area
243 Sprite2D *icon=ae->GetMapIcon(worldmap->bam);
244 int h=0,w=0;
245 if (icon) {
246 h=icon->Height;
247 w=icon->Width;
248 core->GetVideoDriver()->FreeSprite( icon );
250 if (ftext && ae->GetCaption()) {
251 int tw = ftext->CalcStringWidth( ae->GetCaption() ) + 5;
252 int th = ftext->maxHeight;
253 if(h<th)
254 h=th;
255 if(w<tw)
256 w=tw;
258 if (ae->X > x) continue;
259 if (ae->X + w < x) continue;
260 if (ae->Y > y) continue;
261 if (ae->Y + h < y) continue;
262 lastCursor = IE_CURSOR_NORMAL;
263 Area=ae;
264 if(oldArea!=ae) {
265 RunEventHandler(WorldMapControlOnEnter);
267 break;
271 Owner->Cursor = lastCursor;
274 /** Sets the tooltip to be displayed on the screen now */
275 void WorldMapControl::DisplayTooltip()
277 if (Area) {
278 int x = Owner->XPos+XPos+lastMouseX;
279 int y = Owner->YPos+YPos+lastMouseY-50;
280 core->DisplayTooltip( x, y, this );
281 } else {
282 core->DisplayTooltip( 0, 0, NULL );
286 /** Mouse Leave Event */
287 void WorldMapControl::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
289 Owner->Cursor = IE_CURSOR_NORMAL;
290 Area = NULL;
293 /** Mouse Button Down */
294 void WorldMapControl::OnMouseDown(unsigned short x, unsigned short y,
295 unsigned short Button, unsigned short /*Mod*/)
297 switch(Button) {
298 case GEM_MB_ACTION:
299 MouseIsDown = true;
300 lastMouseX = x;
301 lastMouseY = y;
302 break;
303 case GEM_MB_SCRLUP:
304 OnSpecialKeyPress(GEM_UP);
305 break;
306 case GEM_MB_SCRLDOWN:
307 OnSpecialKeyPress(GEM_DOWN);
308 break;
311 /** Mouse Button Up */
312 void WorldMapControl::OnMouseUp(unsigned short /*x*/, unsigned short /*y*/,
313 unsigned short Button, unsigned short /*Mod*/)
315 if (Button != GEM_MB_ACTION) {
316 return;
318 if (lastCursor==IE_CURSOR_NORMAL) {
319 RunEventHandler( WorldMapControlOnPress );
321 MouseIsDown = false;
324 /** Special Key Press */
325 void WorldMapControl::OnSpecialKeyPress(unsigned char Key)
327 WorldMap* worldmap = core->GetWorldMap();
328 switch (Key) {
329 case GEM_LEFT:
330 ScrollX -= 64;
331 break;
332 case GEM_UP:
333 ScrollY -= 64;
334 break;
335 case GEM_RIGHT:
336 ScrollX += 64;
337 break;
338 case GEM_DOWN:
339 ScrollY += 64;
340 break;
341 case GEM_ALT:
342 printf( "ALT pressed\n" );
343 break;
344 case GEM_TAB:
345 printf( "TAB pressed\n" );
346 break;
349 Sprite2D *MapMOS = worldmap->GetMapMOS();
350 if (ScrollX > MapMOS->Width - Width)
351 ScrollX = MapMOS->Width - Width;
352 if (ScrollY > MapMOS->Height - Height)
353 ScrollY = MapMOS->Height - Height;
354 if (ScrollX < 0)
355 ScrollX = 0;
356 if (ScrollY < 0)
357 ScrollY = 0;
360 bool WorldMapControl::SetEvent(int eventType, EventHandler handler)
362 Changed = true;
364 switch (eventType) {
365 case IE_GUI_WORLDMAP_ON_PRESS:
366 WorldMapControlOnPress = handler;
367 break;
368 case IE_GUI_MOUSE_ENTER_WORLDMAP:
369 WorldMapControlOnEnter = handler;
370 break;
371 default:
372 return false;
375 return true;
378 void WorldMapControl::SetColor(int which, Color color)
380 Color black = { 0x00, 0x00, 0x00, 0x00 };
381 switch (which) {
382 case IE_GUI_WMAP_COLOR_NORMAL:
383 gamedata->FreePalette( pal_normal );
384 pal_normal = core->CreatePalette( color, black );
385 break;
386 case IE_GUI_WMAP_COLOR_SELECTED:
387 gamedata->FreePalette( pal_selected );
388 pal_selected = core->CreatePalette( color, black );
389 break;
390 case IE_GUI_WMAP_COLOR_NOTVISITED:
391 gamedata->FreePalette( pal_notvisited );
392 pal_notvisited = core->CreatePalette( color, black );
393 break;
394 default:
395 break;
398 Changed = true;