Sort include order.
[gemrb.git] / gemrb / core / MapControl.cpp
blob076c51f40d1df2a1bfbd50cc9a8499f9f06843fa
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 "MapControl.h"
22 #include "win32def.h"
24 #include "Game.h"
25 #include "Interface.h"
26 #include "Map.h"
27 #include "Video.h"
29 #define MAP_NO_NOTES 0
30 #define MAP_VIEW_NOTES 1
31 #define MAP_SET_NOTE 2
32 #define MAP_REVEAL 3
34 // Ratio between pixel sizes of an Area (Big map) and a Small map
36 static int MAP_DIV = 3;
37 static int MAP_MULT = 32;
39 typedef enum {black=0, gray, violet, green, orange, red, blue, darkblue, darkgreen} colorcode;
41 Color colors[]={
42 { 0x00, 0x00, 0x00, 0xff }, //black
43 { 0x60, 0x60, 0x60, 0xff }, //gray
44 { 0xa0, 0x00, 0xa0, 0xff }, //violet
45 { 0x00, 0xff, 0x00, 0xff }, //green
46 { 0xff, 0xff, 0x00, 0xff }, //orange
47 { 0xff, 0x00, 0x00, 0xff }, //red
48 { 0x00, 0x00, 0xff, 0xff }, //blue
49 { 0x00, 0x00, 0x80, 0xff }, //darkblue
50 { 0x00, 0x80, 0x00, 0xff } //darkgreen
53 #define MAP_TO_SCREENX(x) (XWin + XPos + XCenter - ScrollX + (x))
54 #define MAP_TO_SCREENY(y) (YWin + YPos + YCenter - ScrollY + (y))
55 // Omit [XY]Pos, since these macros are used in OnMouseDown(x, y), and x, y is
56 // already relative to control [XY]Pos there
57 #define SCREEN_TO_MAPX(x) ((x) - XCenter + ScrollX)
58 #define SCREEN_TO_MAPY(y) ((y) - YCenter + ScrollY)
60 #define GAME_TO_SCREENX(x) MAP_TO_SCREENX((int)((x) * MAP_DIV / MAP_MULT))
61 #define GAME_TO_SCREENY(y) MAP_TO_SCREENY((int)((y) * MAP_DIV / MAP_MULT))
63 #define SCREEN_TO_GAMEX(x) (SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV)
64 #define SCREEN_TO_GAMEY(y) (SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV)
66 MapControl::MapControl(void)
68 if (core->HasFeature(GF_IWD_MAP_DIMENSIONS) ) {
69 MAP_DIV=4;
70 MAP_MULT=32;
71 } else {
72 MAP_DIV=3;
73 MAP_MULT=32;
76 LinkedLabel = NULL;
77 ScrollX = 0;
78 ScrollY = 0;
79 NotePosX = 0;
80 NotePosY = 0;
81 mouseIsDown = false;
82 mouseIsDragging = false;
83 Changed = true;
84 convertToGame = true;
85 memset(Flag,0,sizeof(Flag) );
87 // initialize var and event callback to no-ops
88 VarName[0] = 0;
89 ResetEventHandler( MapControlOnPress );
90 ResetEventHandler( MapControlOnRightPress );
91 ResetEventHandler( MapControlOnDoublePress );
93 MyMap = core->GetGame()->GetCurrentArea();
94 if (MyMap->SmallMap) {
95 MapMOS = MyMap->SmallMap;
96 MapMOS->acquire();
97 } else
98 MapMOS = NULL;
101 MapControl::~MapControl(void)
103 Video *video = core->GetVideoDriver();
105 if (MapMOS) {
106 video->FreeSprite(MapMOS);
108 for(int i=0;i<8;i++) {
109 if (Flag[i]) {
110 video->FreeSprite(Flag[i]);
115 // Draw fog on the small bitmap
116 void MapControl::DrawFog(unsigned short XWin, unsigned short YWin)
118 Video *video = core->GetVideoDriver();
120 Region old_clip;
121 video->GetClipRect(old_clip);
123 Region r( XWin + XPos, YWin + YPos, Width, Height );
124 video->SetClipRect(&r);
126 // FIXME: this is ugly, the knowledge of Map and ExploredMask
127 // sizes should be in Map.cpp
128 int w = MyMap->GetWidth() / 2;
129 int h = MyMap->GetHeight() / 2;
131 for (int y = 0; y < h; y++) {
132 for (int x = 0; x < w; x++) {
133 Point p( (short) (MAP_MULT * x), (short) (MAP_MULT * y) );
134 bool visible = MyMap->IsVisible( p, true );
135 if (! visible) {
136 Region rgn = Region ( MAP_TO_SCREENX(MAP_DIV * x), MAP_TO_SCREENY(MAP_DIV * y), MAP_DIV, MAP_DIV );
137 video->DrawRect( rgn, colors[black] );
142 video->SetClipRect(&old_clip);
145 // To be called after changes in control's or screen geometry
146 void MapControl::Realize()
148 // FIXME: ugly!! How to get area size in pixels?
149 //Map *map = core->GetGame()->GetCurrentMap();
150 //MapWidth = map->GetWidth();
151 //MapHeight = map->GetHeight();
153 if (MapMOS) {
154 MapWidth = (short) MapMOS->Width;
155 MapHeight = (short) MapMOS->Height;
156 } else {
157 MapWidth = 0;
158 MapHeight = 0;
161 // FIXME: ugly hack! What is the actual viewport size?
162 ViewWidth = (short) (core->Width * MAP_DIV / MAP_MULT);
163 ViewHeight = (short) (core->Height * MAP_DIV / MAP_MULT);
165 XCenter = (short) (Width - MapWidth ) / 2;
166 YCenter = (short) (Height - MapHeight ) / 2;
167 if (XCenter < 0) XCenter = 0;
168 if (YCenter < 0) YCenter = 0;
171 void MapControl::RedrawMapControl(const char *VariableName, unsigned int Sum)
173 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
174 return;
176 Value = Sum;
177 Changed = true;
180 /** Draws the Control on the Output Display */
181 void MapControl::Draw(unsigned short XWin, unsigned short YWin)
183 if (!Width || !Height) {
184 return;
186 if (Owner->Visible!=WINDOW_VISIBLE) {
187 return;
190 if (Changed) {
191 Realize();
192 Changed = false;
195 // we're going to paint over labels/etc, so they need to repaint!
196 bool seen_this = false;
197 unsigned int i;
198 for (i = 0; i < Owner->GetControlCount(); i++) {
199 Control *ctrl = Owner->GetControl(i);
200 if (!ctrl) continue;
202 // we could try working out which controls overlap,
203 // but the later controls are cheap to paint..
204 if (ctrl == this) { seen_this = true; continue; }
205 if (!seen_this) continue;
207 ctrl->Changed = true;
210 Video* video = core->GetVideoDriver();
211 Region r( XWin + XPos, YWin + YPos, Width, Height );
213 if (MapMOS) {
214 video->BlitSprite( MapMOS, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r );
217 if (core->FogOfWar&FOG_DRAWFOG)
218 DrawFog(XWin, YWin);
220 Region vp = video->GetViewport();
222 vp.x = GAME_TO_SCREENX(vp.x);
223 vp.y = GAME_TO_SCREENY(vp.y);
224 vp.w = ViewWidth;
225 vp.h = ViewHeight;
227 video->DrawRect( vp, colors[green], false, false );
229 // Draw PCs' ellipses
230 Game *game = core->GetGame();
231 i = game->GetPartySize(true);
232 while (i--) {
233 Actor* actor = game->GetPC( i, true );
234 if (MyMap->HasActor(actor) ) {
235 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 );
238 // Draw Map notes, could be turned off in bg2
239 // we use the common control value to handle it, because then we
240 // don't need another interface
241 if (Value!=MAP_NO_NOTES) {
242 i = MyMap -> GetMapNoteCount();
243 while (i--) {
244 MapNote * mn = MyMap -> GetMapNote(i);
245 Sprite2D *anim = Flag[mn->color&7];
246 Point pos = mn->Pos;
247 if (convertToGame) {
248 vp.x = GAME_TO_SCREENX(mn->Pos.x);
249 vp.y = GAME_TO_SCREENY(mn->Pos.y);
250 } else { //pst style
251 vp.x = MAP_TO_SCREENX(mn->Pos.x);
252 vp.y = MAP_TO_SCREENY(mn->Pos.y);
253 pos.x = pos.x * MAP_MULT / MAP_DIV;
254 pos.y = pos.y * MAP_MULT / MAP_DIV;
257 //Skip unexplored map notes
258 bool visible = MyMap->IsVisible( pos, true );
259 if (!visible)
260 continue;
262 if (anim) {
263 video->BlitSprite( anim, vp.x - anim->Width/2, vp.y - anim->Height/2, true, &r );
264 } else {
265 video->DrawEllipse( (short) vp.x, (short) vp.y, 6, 5, colors[mn->color&7], false );
271 /** Key Press Event */
272 void MapControl::OnKeyPress(unsigned char /*Key*/, unsigned short /*Mod*/)
276 /** Key Release Event */
277 void MapControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
279 switch (Key) {
280 case '\t':
281 //not GEM_TAB
282 printf( "TAB released\n" );
283 return;
284 case 'f':
285 if (Mod & GEM_MOD_CTRL)
286 core->GetVideoDriver()->ToggleFullscreenMode();
287 break;
288 default:
289 break;
291 if (!core->CheatEnabled()) {
292 return;
295 /** Mouse Over Event */
296 void MapControl::OnMouseOver(unsigned short x, unsigned short y)
298 if (mouseIsDown) {
299 ScrollX -= x - lastMouseX;
300 ScrollY -= y - lastMouseY;
302 if (ScrollX > MapWidth - Width)
303 ScrollX = MapWidth - Width;
304 if (ScrollY > MapHeight - Height)
305 ScrollY = MapHeight - Height;
306 if (ScrollX < 0)
307 ScrollX = 0;
308 if (ScrollY < 0)
309 ScrollY = 0;
312 if (mouseIsDragging) {
313 ViewHandle(x,y);
316 lastMouseX = x;
317 lastMouseY = y;
319 if (Value==MAP_VIEW_NOTES) {
320 Point mp;
321 unsigned int dist;
323 if (convertToGame) {
324 mp.x = (short) SCREEN_TO_GAMEX(x);
325 mp.y = (short) SCREEN_TO_GAMEY(y);
326 dist = 100;
327 } else {
328 mp.x = (short) SCREEN_TO_MAPX(x);
329 mp.y = (short) SCREEN_TO_MAPY(y);
330 dist = 16;
332 int i = MyMap -> GetMapNoteCount();
333 while (i--) {
334 MapNote * mn = MyMap -> GetMapNote(i);
335 if (Distance(mp, mn->Pos)<dist) {
336 if (LinkedLabel) {
337 LinkedLabel->SetText( mn->text );
339 NotePosX = mn->Pos.x;
340 NotePosY = mn->Pos.y;
341 return;
344 NotePosX = mp.x;
345 NotePosY = mp.y;
347 if (LinkedLabel) {
348 LinkedLabel->SetText( "" );
350 switch (Value) {
351 case MAP_REVEAL: //for farsee effect
352 Owner->Cursor = IE_CURSOR_CAST;
353 break;
354 case MAP_SET_NOTE:
355 Owner->Cursor = IE_CURSOR_GRAB;
356 break;
357 default:
358 Owner->Cursor = IE_CURSOR_NORMAL;
359 break;
363 /** Mouse Leave Event */
364 void MapControl::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
366 Owner->Cursor = IE_CURSOR_NORMAL;
369 void MapControl::ClickHandle(unsigned short Button)
371 core->GetDictionary()->SetAt( "MapControlX", NotePosX );
372 core->GetDictionary()->SetAt( "MapControlY", NotePosY );
373 switch(Button&GEM_MB_NORMAL) {
374 case GEM_MB_ACTION:
375 if (Button&GEM_MB_DOUBLECLICK) {
376 RunEventHandler( MapControlOnDoublePress );
377 printMessage("MapControl","Doubleclick detected\n",GREEN);
378 } else {
379 RunEventHandler( MapControlOnPress );
381 break;
382 case GEM_MB_MENU:
383 RunEventHandler( MapControlOnRightPress );
384 break;
385 default:
386 break;
390 void MapControl::ViewHandle(unsigned short x, unsigned short y)
392 short xp = (short) (SCREEN_TO_MAPX(x) - ViewWidth / 2);
393 short yp = (short) (SCREEN_TO_MAPY(y) - ViewHeight / 2);
395 if (xp + ViewWidth > MapWidth) xp = MapWidth - ViewWidth;
396 if (yp + ViewHeight > MapHeight) yp = MapHeight - ViewHeight;
397 if (xp < 0) xp = 0;
398 if (yp < 0) yp = 0;
400 core->timer->SetMoveViewPort( xp * MAP_MULT / MAP_DIV, yp * MAP_MULT / MAP_DIV, 0, false );
403 /** Mouse Button Down */
404 void MapControl::OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
405 unsigned short /*Mod*/)
407 switch((unsigned char) Button) {
408 case GEM_MB_SCRLUP:
409 OnSpecialKeyPress(GEM_UP);
410 return;
411 case GEM_MB_SCRLDOWN:
412 OnSpecialKeyPress(GEM_DOWN);
413 return;
414 case GEM_MB_ACTION:
415 if (Button & GEM_MB_DOUBLECLICK) {
416 ClickHandle(Button);
418 break;
419 default:
420 break;
423 mouseIsDown = true;
424 short xp = (short) (SCREEN_TO_GAMEX(x));
425 short yp = (short) (SCREEN_TO_GAMEY(y));
426 Region vp = core->GetVideoDriver()->GetViewport();
427 vp.w = vp.x+ViewWidth*MAP_MULT/MAP_DIV;
428 vp.h = vp.y+ViewHeight*MAP_MULT/MAP_DIV;
429 if ((xp>vp.x) && (xp<vp.w) && (yp>vp.y) && (yp<vp.h)) {
430 mouseIsDragging = true;
431 } else {
432 mouseIsDragging = false;
434 lastMouseX = x;
435 lastMouseY = y;
438 /** Mouse Button Up */
439 void MapControl::OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
440 unsigned short /*Mod*/)
442 if (!mouseIsDown) {
443 return;
446 mouseIsDown = false;
447 mouseIsDragging = false;
448 switch(Value) {
449 case MAP_REVEAL:
450 ViewHandle(x,y);
451 NotePosX = (short) SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV;
452 NotePosY = (short) SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV;
453 ClickHandle(Button);
454 return;
455 case MAP_NO_NOTES:
456 ViewHandle(x,y);
457 return;
458 case MAP_VIEW_NOTES:
459 //left click allows setting only when in MAP_SET_NOTE mode
460 if ((Button == GEM_MB_ACTION) ) {
461 ViewHandle(x,y);
463 ClickHandle(Button);
464 return;
465 default:
466 ClickHandle(Button);
467 return;
471 /** Special Key Press */
472 void MapControl::OnSpecialKeyPress(unsigned char Key)
474 switch (Key) {
475 case GEM_LEFT:
476 ScrollX -= 64;
477 break;
478 case GEM_UP:
479 ScrollY -= 64;
480 break;
481 case GEM_RIGHT:
482 ScrollX += 64;
483 break;
484 case GEM_DOWN:
485 ScrollY += 64;
486 break;
487 case GEM_ALT:
488 printf( "ALT pressed\n" );
489 break;
490 case GEM_TAB:
491 printf( "TAB pressed\n" );
492 break;
493 default:
494 break;
497 if (ScrollX > MapWidth - Width)
498 ScrollX = MapWidth - Width;
499 if (ScrollY > MapHeight - Height)
500 ScrollY = MapHeight - Height;
501 if (ScrollX < 0)
502 ScrollX = 0;
503 if (ScrollY < 0)
504 ScrollY = 0;
507 bool MapControl::SetEvent(int eventType, const char *handler)
509 Changed = true;
511 switch (eventType) {
512 case IE_GUI_MAP_ON_PRESS:
513 SetEventHandler( MapControlOnPress, handler );
514 break;
515 case IE_GUI_MAP_ON_RIGHT_PRESS:
516 SetEventHandler( MapControlOnRightPress, handler );
517 break;
518 case IE_GUI_MAP_ON_DOUBLE_PRESS:
519 SetEventHandler( MapControlOnDoublePress, handler );
520 break;
521 default:
522 return false;
525 return true;