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.
21 #include "MapControl.h"
22 #include "Interface.h"
27 #define MAP_NO_NOTES 0
28 #define MAP_VIEW_NOTES 1
29 #define MAP_SET_NOTE 2
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
;
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
) ) {
80 mouseIsDragging
= false;
83 memset(Flag
,0,sizeof(Flag
) );
85 // initialize var and event callback to no-ops
87 ResetEventHandler( MapControlOnPress
);
88 ResetEventHandler( MapControlOnRightPress
);
89 ResetEventHandler( MapControlOnDoublePress
);
91 MyMap
= core
->GetGame()->GetCurrentArea();
92 if (MyMap
->SmallMap
) {
93 MapMOS
= MyMap
->SmallMap
;
99 MapControl::~MapControl(void)
101 Video
*video
= core
->GetVideoDriver();
104 video
->FreeSprite(MapMOS
);
106 for(int i
=0;i
<8;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();
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 );
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();
152 MapWidth
= (short) MapMOS
->Width
;
153 MapHeight
= (short) MapMOS
->Height
;
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
)) {
178 /** Draws the Control on the Output Display */
179 void MapControl::Draw(unsigned short XWin
, unsigned short YWin
)
181 if (!Width
|| !Height
) {
184 if (Owner
->Visible
!=WINDOW_VISIBLE
) {
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
);
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
);
211 video
->BlitSprite( MapMOS
, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r
);
214 if (core
->FogOfWar
&FOG_DRAWFOG
)
217 Region vp
= video
->GetViewport();
219 vp
.x
= GAME_TO_SCREENX(vp
.x
);
220 vp
.y
= GAME_TO_SCREENY(vp
.y
);
224 video
->DrawRect( vp
, colors
[green
], false, false );
227 // Draw PCs' ellipses
228 Game
*game
= core
->GetGame();
229 i
= game
->GetPartySize(true);
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();
242 MapNote
* mn
= MyMap
-> GetMapNote(i
);
243 Sprite2D
*anim
= Flag
[mn
->color
&7];
246 vp
.x
= GAME_TO_SCREENX(mn
->Pos
.x
);
247 vp
.y
= GAME_TO_SCREENY(mn
->Pos
.y
);
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 );
261 video
->BlitSprite( anim
, vp
.x
- anim
->Width
/2, vp
.y
- anim
->Height
/2, true, &r
);
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
)
280 printf( "TAB released\n" );
283 if (Mod
& GEM_MOD_CTRL
)
284 core
->GetVideoDriver()->ToggleFullscreenMode();
289 if (!core
->CheatEnabled()) {
293 /** Mouse Over Event */
294 void MapControl::OnMouseOver(unsigned short x
, unsigned short y
)
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
;
310 if (mouseIsDragging
) {
317 if (Value
==MAP_VIEW_NOTES
) {
322 mp
.x
= (short) SCREEN_TO_GAMEX(x
);
323 mp
.y
= (short) SCREEN_TO_GAMEY(y
);
326 mp
.x
= (short) SCREEN_TO_MAPX(x
);
327 mp
.y
= (short) SCREEN_TO_MAPY(y
);
330 int i
= MyMap
-> GetMapNoteCount();
332 MapNote
* mn
= MyMap
-> GetMapNote(i
);
333 if (Distance(mp
, mn
->Pos
)<dist
) {
335 LinkedLabel
->SetText( mn
->text
);
337 NotePosX
= mn
->Pos
.x
;
338 NotePosY
= mn
->Pos
.y
;
346 LinkedLabel
->SetText( "" );
349 case MAP_REVEAL
: //for farsee effect
350 Owner
->Cursor
= IE_CURSOR_CAST
;
353 Owner
->Cursor
= IE_CURSOR_GRAB
;
356 Owner
->Cursor
= IE_CURSOR_NORMAL
;
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
) {
373 if (Button
&GEM_MB_DOUBLECLICK
) {
374 RunEventHandler( MapControlOnDoublePress
);
375 printMessage("MapControl","Doubleclick detected\n",GREEN
);
377 RunEventHandler( MapControlOnPress
);
381 RunEventHandler( MapControlOnRightPress
);
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
;
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
) {
407 OnSpecialKeyPress(GEM_UP
);
409 case GEM_MB_SCRLDOWN
:
410 OnSpecialKeyPress(GEM_DOWN
);
413 if (Button
& GEM_MB_DOUBLECLICK
) {
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;
430 mouseIsDragging
= false;
436 /** Mouse Button Up */
437 void MapControl::OnMouseUp(unsigned short x
, unsigned short y
, unsigned short Button
,
438 unsigned short /*Mod*/)
445 mouseIsDragging
= false;
449 NotePosX
= (short) SCREEN_TO_MAPX(x
) * MAP_MULT
/ MAP_DIV
;
450 NotePosY
= (short) SCREEN_TO_MAPY(y
) * MAP_MULT
/ MAP_DIV
;
457 //left click allows setting only when in MAP_SET_NOTE mode
458 if ((Button
== GEM_MB_ACTION
) ) {
469 /** Special Key Press */
470 void MapControl::OnSpecialKeyPress(unsigned char Key
)
486 printf( "ALT pressed\n" );
489 printf( "TAB pressed\n" );
495 if (ScrollX
> MapWidth
- Width
)
496 ScrollX
= MapWidth
- Width
;
497 if (ScrollY
> MapHeight
- Height
)
498 ScrollY
= MapHeight
- Height
;
505 bool MapControl::SetEvent(int eventType
, const char *handler
)
510 case IE_GUI_MAP_ON_PRESS
:
511 SetEventHandler( MapControlOnPress
, handler
);
513 case IE_GUI_MAP_ON_RIGHT_PRESS
:
514 SetEventHandler( MapControlOnRightPress
, handler
);
516 case IE_GUI_MAP_ON_DOUBLE_PRESS
:
517 SetEventHandler( MapControlOnDoublePress
, handler
);