GameScript: Move initialization out of constructor.
[gemrb.git] / gemrb / core / MapControl.cpp
blobd68c72887918bb9a6b69c1ce978962e4c75a6e5a
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 "win32def.h"
21 #include "MapControl.h"
22 #include "Interface.h"
23 #include "Video.h"
24 #include "Map.h"
25 #include "Game.h"
27 #define MAP_NO_NOTES 0
28 #define MAP_VIEW_NOTES 1
29 #define MAP_SET_NOTE 2
30 #define MAP_REVEAL 3
32 // Ratio between pixel sizes of an Area (Big map) and a Small map
34 static int MAP_DIV = 3;
35 static int MAP_MULT = 32;
37 typedef enum {black=0, gray, violet, green, orange, red, blue, darkblue, darkgreen} colorcode;
39 Color colors[]={
40 { 0x00, 0x00, 0x00, 0xff }, //black
41 { 0x60, 0x60, 0x60, 0xff }, //gray
42 { 0xa0, 0x00, 0xa0, 0xff }, //violet
43 { 0x00, 0xff, 0x00, 0xff }, //green
44 { 0xff, 0xff, 0x00, 0xff }, //orange
45 { 0xff, 0x00, 0x00, 0xff }, //red
46 { 0x00, 0x00, 0xff, 0xff }, //blue
47 { 0x00, 0x00, 0x80, 0xff }, //darkblue
48 { 0x00, 0x80, 0x00, 0xff } //darkgreen
51 #define MAP_TO_SCREENX(x) (XWin + XPos + XCenter - ScrollX + (x))
52 #define MAP_TO_SCREENY(y) (YWin + YPos + YCenter - ScrollY + (y))
53 // Omit [XY]Pos, since these macros are used in OnMouseDown(x, y), and x, y is
54 // already relative to control [XY]Pos there
55 #define SCREEN_TO_MAPX(x) ((x) - XCenter + ScrollX)
56 #define SCREEN_TO_MAPY(y) ((y) - YCenter + ScrollY)
58 #define GAME_TO_SCREENX(x) MAP_TO_SCREENX((int)((x) * MAP_DIV / MAP_MULT))
59 #define GAME_TO_SCREENY(y) MAP_TO_SCREENY((int)((y) * MAP_DIV / MAP_MULT))
61 #define SCREEN_TO_GAMEX(x) (SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV)
62 #define SCREEN_TO_GAMEY(y) (SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV)
64 MapControl::MapControl(void)
66 if (core->HasFeature(GF_IWD_MAP_DIMENSIONS) ) {
67 MAP_DIV=4;
68 MAP_MULT=32;
69 } else {
70 MAP_DIV=3;
71 MAP_MULT=32;
74 LinkedLabel = NULL;
75 ScrollX = 0;
76 ScrollY = 0;
77 NotePosX = 0;
78 NotePosY = 0;
79 mouseIsDown = false;
80 mouseIsDragging = false;
81 Changed = true;
82 convertToGame = true;
83 memset(Flag,0,sizeof(Flag) );
85 // initialize var and event callback to no-ops
86 VarName[0] = 0;
87 ResetEventHandler( MapControlOnPress );
88 ResetEventHandler( MapControlOnRightPress );
89 ResetEventHandler( MapControlOnDoublePress );
91 MyMap = core->GetGame()->GetCurrentArea();
92 if (MyMap->SmallMap) {
93 MapMOS = MyMap->SmallMap;
94 MapMOS->acquire();
95 } else
96 MapMOS = NULL;
99 MapControl::~MapControl(void)
101 Video *video = core->GetVideoDriver();
103 if (MapMOS) {
104 video->FreeSprite(MapMOS);
106 for(int i=0;i<8;i++) {
107 if (Flag[i]) {
108 video->FreeSprite(Flag[i]);
113 // Draw fog on the small bitmap
114 void MapControl::DrawFog(unsigned short XWin, unsigned short YWin)
116 Video *video = core->GetVideoDriver();
118 Region old_clip;
119 video->GetClipRect(old_clip);
121 Region r( XWin + XPos, YWin + YPos, Width, Height );
122 video->SetClipRect(&r);
124 // FIXME: this is ugly, the knowledge of Map and ExploredMask
125 // sizes should be in Map.cpp
126 int w = MyMap->GetWidth() / 2;
127 int h = MyMap->GetHeight() / 2;
129 for (int y = 0; y < h; y++) {
130 for (int x = 0; x < w; x++) {
131 Point p( (short) (MAP_MULT * x), (short) (MAP_MULT * y) );
132 bool visible = MyMap->IsVisible( p, true );
133 if (! visible) {
134 Region rgn = Region ( MAP_TO_SCREENX(MAP_DIV * x), MAP_TO_SCREENY(MAP_DIV * y), MAP_DIV, MAP_DIV );
135 video->DrawRect( rgn, colors[black] );
140 video->SetClipRect(&old_clip);
143 // To be called after changes in control's or screen geometry
144 void MapControl::Realize()
146 // FIXME: ugly!! How to get area size in pixels?
147 //Map *map = core->GetGame()->GetCurrentMap();
148 //MapWidth = map->GetWidth();
149 //MapHeight = map->GetHeight();
151 if (MapMOS) {
152 MapWidth = (short) MapMOS->Width;
153 MapHeight = (short) MapMOS->Height;
154 } else {
155 MapWidth = 0;
156 MapHeight = 0;
159 // FIXME: ugly hack! What is the actual viewport size?
160 ViewWidth = (short) (core->Width * MAP_DIV / MAP_MULT);
161 ViewHeight = (short) (core->Height * MAP_DIV / MAP_MULT);
163 XCenter = (short) (Width - MapWidth ) / 2;
164 YCenter = (short) (Height - MapHeight ) / 2;
165 if (XCenter < 0) XCenter = 0;
166 if (YCenter < 0) YCenter = 0;
169 void MapControl::RedrawMapControl(const char *VariableName, unsigned int Sum)
171 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
172 return;
174 Value = Sum;
175 Changed = true;
178 /** Draws the Control on the Output Display */
179 void MapControl::Draw(unsigned short XWin, unsigned short YWin)
181 if (!Width || !Height) {
182 return;
184 if (Owner->Visible!=WINDOW_VISIBLE) {
185 return;
188 if (Changed) {
189 Realize();
190 Changed = false;
193 // we're going to paint over labels/etc, so they need to repaint!
194 bool seen_this = false;
195 for (unsigned int i = 0; i < Owner->GetControlCount(); i++) {
196 Control *ctrl = Owner->GetControl(i);
197 if (!ctrl) continue;
199 // we could try working out which controls overlap,
200 // but the later controls are cheap to paint..
201 if (ctrl == this) { seen_this = true; continue; }
202 if (!seen_this) continue;
204 ctrl->Changed = true;
207 Video* video = core->GetVideoDriver();
208 Region r( XWin + XPos, YWin + YPos, Width, Height );
210 if (MapMOS) {
211 video->BlitSprite( MapMOS, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r );
214 if (core->FogOfWar&FOG_DRAWFOG)
215 DrawFog(XWin, YWin);
217 Region vp = video->GetViewport();
219 vp.x = GAME_TO_SCREENX(vp.x);
220 vp.y = GAME_TO_SCREENY(vp.y);
221 vp.w = ViewWidth;
222 vp.h = ViewHeight;
224 video->DrawRect( vp, colors[green], false, false );
226 int i;
227 // Draw PCs' ellipses
228 Game *game = core->GetGame();
229 i = game->GetPartySize(true);
230 while (i--) {
231 Actor* actor = game->GetPC( i, true );
232 if (MyMap->HasActor(actor) ) {
233 video->DrawEllipse( (short) GAME_TO_SCREENX(actor->Pos.x), (short) GAME_TO_SCREENY(actor->Pos.y), 3, 2, actor->Selected ? colors[green] : colors[darkgreen], false );
236 // Draw Map notes, could be turned off in bg2
237 // we use the common control value to handle it, because then we
238 // don't need another interface
239 if (Value!=MAP_NO_NOTES) {
240 i = MyMap -> GetMapNoteCount();
241 while (i--) {
242 MapNote * mn = MyMap -> GetMapNote(i);
243 Sprite2D *anim = Flag[mn->color&7];
244 Point pos = mn->Pos;
245 if (convertToGame) {
246 vp.x = GAME_TO_SCREENX(mn->Pos.x);
247 vp.y = GAME_TO_SCREENY(mn->Pos.y);
248 } else { //pst style
249 vp.x = MAP_TO_SCREENX(mn->Pos.x);
250 vp.y = MAP_TO_SCREENY(mn->Pos.y);
251 pos.x = pos.x * MAP_MULT / MAP_DIV;
252 pos.y = pos.y * MAP_MULT / MAP_DIV;
255 //Skip unexplored map notes
256 bool visible = MyMap->IsVisible( pos, true );
257 if (!visible)
258 continue;
260 if (anim) {
261 video->BlitSprite( anim, vp.x - anim->Width/2, vp.y - anim->Height/2, true, &r );
262 } else {
263 video->DrawEllipse( (short) vp.x, (short) vp.y, 6, 5, colors[mn->color&7], false );
269 /** Key Press Event */
270 void MapControl::OnKeyPress(unsigned char /*Key*/, unsigned short /*Mod*/)
274 /** Key Release Event */
275 void MapControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
277 switch (Key) {
278 case '\t':
279 //not GEM_TAB
280 printf( "TAB released\n" );
281 return;
282 case 'f':
283 if (Mod & GEM_MOD_CTRL)
284 core->GetVideoDriver()->ToggleFullscreenMode();
285 break;
286 default:
287 break;
289 if (!core->CheatEnabled()) {
290 return;
293 /** Mouse Over Event */
294 void MapControl::OnMouseOver(unsigned short x, unsigned short y)
296 if (mouseIsDown) {
297 ScrollX -= x - lastMouseX;
298 ScrollY -= y - lastMouseY;
300 if (ScrollX > MapWidth - Width)
301 ScrollX = MapWidth - Width;
302 if (ScrollY > MapHeight - Height)
303 ScrollY = MapHeight - Height;
304 if (ScrollX < 0)
305 ScrollX = 0;
306 if (ScrollY < 0)
307 ScrollY = 0;
310 if (mouseIsDragging) {
311 ViewHandle(x,y);
314 lastMouseX = x;
315 lastMouseY = y;
317 if (Value==MAP_VIEW_NOTES) {
318 Point mp;
319 unsigned int dist;
321 if (convertToGame) {
322 mp.x = (short) SCREEN_TO_GAMEX(x);
323 mp.y = (short) SCREEN_TO_GAMEY(y);
324 dist = 100;
325 } else {
326 mp.x = (short) SCREEN_TO_MAPX(x);
327 mp.y = (short) SCREEN_TO_MAPY(y);
328 dist = 16;
330 int i = MyMap -> GetMapNoteCount();
331 while (i--) {
332 MapNote * mn = MyMap -> GetMapNote(i);
333 if (Distance(mp, mn->Pos)<dist) {
334 if (LinkedLabel) {
335 LinkedLabel->SetText( mn->text );
337 NotePosX = mn->Pos.x;
338 NotePosY = mn->Pos.y;
339 return;
342 NotePosX = mp.x;
343 NotePosY = mp.y;
345 if (LinkedLabel) {
346 LinkedLabel->SetText( "" );
348 switch (Value) {
349 case MAP_REVEAL: //for farsee effect
350 Owner->Cursor = IE_CURSOR_CAST;
351 break;
352 case MAP_SET_NOTE:
353 Owner->Cursor = IE_CURSOR_GRAB;
354 break;
355 default:
356 Owner->Cursor = IE_CURSOR_NORMAL;
357 break;
361 /** Mouse Leave Event */
362 void MapControl::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
364 Owner->Cursor = IE_CURSOR_NORMAL;
367 void MapControl::ClickHandle(unsigned short Button)
369 core->GetDictionary()->SetAt( "MapControlX", NotePosX );
370 core->GetDictionary()->SetAt( "MapControlY", NotePosY );
371 switch(Button&GEM_MB_NORMAL) {
372 case GEM_MB_ACTION:
373 if (Button&GEM_MB_DOUBLECLICK) {
374 RunEventHandler( MapControlOnDoublePress );
375 printMessage("MapControl","Doubleclick detected\n",GREEN);
376 } else {
377 RunEventHandler( MapControlOnPress );
379 break;
380 case GEM_MB_MENU:
381 RunEventHandler( MapControlOnRightPress );
382 break;
383 default:
384 break;
388 void MapControl::ViewHandle(unsigned short x, unsigned short y)
390 short xp = (short) (SCREEN_TO_MAPX(x) - ViewWidth / 2);
391 short yp = (short) (SCREEN_TO_MAPY(y) - ViewHeight / 2);
393 if (xp + ViewWidth > MapWidth) xp = MapWidth - ViewWidth;
394 if (yp + ViewHeight > MapHeight) yp = MapHeight - ViewHeight;
395 if (xp < 0) xp = 0;
396 if (yp < 0) yp = 0;
398 core->timer->SetMoveViewPort( xp * MAP_MULT / MAP_DIV, yp * MAP_MULT / MAP_DIV, 0, false );
401 /** Mouse Button Down */
402 void MapControl::OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
403 unsigned short /*Mod*/)
405 switch((unsigned char) Button) {
406 case GEM_MB_SCRLUP:
407 OnSpecialKeyPress(GEM_UP);
408 return;
409 case GEM_MB_SCRLDOWN:
410 OnSpecialKeyPress(GEM_DOWN);
411 return;
412 case GEM_MB_ACTION:
413 if (Button & GEM_MB_DOUBLECLICK) {
414 ClickHandle(Button);
416 break;
417 default:
418 break;
421 mouseIsDown = true;
422 short xp = (short) (SCREEN_TO_GAMEX(x));
423 short yp = (short) (SCREEN_TO_GAMEY(y));
424 Region vp = core->GetVideoDriver()->GetViewport();
425 vp.w = vp.x+ViewWidth*MAP_MULT/MAP_DIV;
426 vp.h = vp.y+ViewHeight*MAP_MULT/MAP_DIV;
427 if ((xp>vp.x) && (xp<vp.w) && (yp>vp.y) && (yp<vp.h)) {
428 mouseIsDragging = true;
429 } else {
430 mouseIsDragging = false;
432 lastMouseX = x;
433 lastMouseY = y;
436 /** Mouse Button Up */
437 void MapControl::OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
438 unsigned short /*Mod*/)
440 if (!mouseIsDown) {
441 return;
444 mouseIsDown = false;
445 mouseIsDragging = false;
446 switch(Value) {
447 case MAP_REVEAL:
448 ViewHandle(x,y);
449 NotePosX = (short) SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV;
450 NotePosY = (short) SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV;
451 ClickHandle(Button);
452 return;
453 case MAP_NO_NOTES:
454 ViewHandle(x,y);
455 return;
456 case MAP_VIEW_NOTES:
457 //left click allows setting only when in MAP_SET_NOTE mode
458 if ((Button == GEM_MB_ACTION) ) {
459 ViewHandle(x,y);
461 ClickHandle(Button);
462 return;
463 default:
464 ClickHandle(Button);
465 return;
469 /** Special Key Press */
470 void MapControl::OnSpecialKeyPress(unsigned char Key)
472 switch (Key) {
473 case GEM_LEFT:
474 ScrollX -= 64;
475 break;
476 case GEM_UP:
477 ScrollY -= 64;
478 break;
479 case GEM_RIGHT:
480 ScrollX += 64;
481 break;
482 case GEM_DOWN:
483 ScrollY += 64;
484 break;
485 case GEM_ALT:
486 printf( "ALT pressed\n" );
487 break;
488 case GEM_TAB:
489 printf( "TAB pressed\n" );
490 break;
491 default:
492 break;
495 if (ScrollX > MapWidth - Width)
496 ScrollX = MapWidth - Width;
497 if (ScrollY > MapHeight - Height)
498 ScrollY = MapHeight - Height;
499 if (ScrollX < 0)
500 ScrollX = 0;
501 if (ScrollY < 0)
502 ScrollY = 0;
505 bool MapControl::SetEvent(int eventType, const char *handler)
507 Changed = true;
509 switch (eventType) {
510 case IE_GUI_MAP_ON_PRESS:
511 SetEventHandler( MapControlOnPress, handler );
512 break;
513 case IE_GUI_MAP_ON_RIGHT_PRESS:
514 SetEventHandler( MapControlOnRightPress, handler );
515 break;
516 case IE_GUI_MAP_ON_DOUBLE_PRESS:
517 SetEventHandler( MapControlOnDoublePress, handler );
518 break;
519 default:
520 return false;
523 return true;