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"
25 #include "Interface.h"
29 #define MAP_NO_NOTES 0
30 #define MAP_VIEW_NOTES 1
31 #define MAP_SET_NOTE 2
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
;
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
) ) {
82 mouseIsDragging
= false;
85 memset(Flag
,0,sizeof(Flag
) );
87 // initialize var and event callback to no-ops
89 ResetEventHandler( MapControlOnPress
);
90 ResetEventHandler( MapControlOnRightPress
);
91 ResetEventHandler( MapControlOnDoublePress
);
93 MyMap
= core
->GetGame()->GetCurrentArea();
94 if (MyMap
->SmallMap
) {
95 MapMOS
= MyMap
->SmallMap
;
101 MapControl::~MapControl(void)
103 Video
*video
= core
->GetVideoDriver();
106 video
->FreeSprite(MapMOS
);
108 for(int i
=0;i
<8;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();
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 );
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();
154 MapWidth
= (short) MapMOS
->Width
;
155 MapHeight
= (short) MapMOS
->Height
;
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
)) {
180 /** Draws the Control on the Output Display */
181 void MapControl::Draw(unsigned short XWin
, unsigned short YWin
)
183 if (!Width
|| !Height
) {
186 if (Owner
->Visible
!=WINDOW_VISIBLE
) {
195 // we're going to paint over labels/etc, so they need to repaint!
196 bool seen_this
= false;
198 for (i
= 0; i
< Owner
->GetControlCount(); i
++) {
199 Control
*ctrl
= Owner
->GetControl(i
);
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
);
214 video
->BlitSprite( MapMOS
, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r
);
217 if (core
->FogOfWar
&FOG_DRAWFOG
)
220 Region vp
= video
->GetViewport();
222 vp
.x
= GAME_TO_SCREENX(vp
.x
);
223 vp
.y
= GAME_TO_SCREENY(vp
.y
);
227 video
->DrawRect( vp
, colors
[green
], false, false );
229 // Draw PCs' ellipses
230 Game
*game
= core
->GetGame();
231 i
= game
->GetPartySize(true);
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();
244 MapNote
* mn
= MyMap
-> GetMapNote(i
);
245 Sprite2D
*anim
= Flag
[mn
->color
&7];
248 vp
.x
= GAME_TO_SCREENX(mn
->Pos
.x
);
249 vp
.y
= GAME_TO_SCREENY(mn
->Pos
.y
);
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 );
263 video
->BlitSprite( anim
, vp
.x
- anim
->Width
/2, vp
.y
- anim
->Height
/2, true, &r
);
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
)
282 printf( "TAB released\n" );
285 if (Mod
& GEM_MOD_CTRL
)
286 core
->GetVideoDriver()->ToggleFullscreenMode();
291 if (!core
->CheatEnabled()) {
295 /** Mouse Over Event */
296 void MapControl::OnMouseOver(unsigned short x
, unsigned short y
)
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
;
312 if (mouseIsDragging
) {
319 if (Value
==MAP_VIEW_NOTES
) {
324 mp
.x
= (short) SCREEN_TO_GAMEX(x
);
325 mp
.y
= (short) SCREEN_TO_GAMEY(y
);
328 mp
.x
= (short) SCREEN_TO_MAPX(x
);
329 mp
.y
= (short) SCREEN_TO_MAPY(y
);
332 int i
= MyMap
-> GetMapNoteCount();
334 MapNote
* mn
= MyMap
-> GetMapNote(i
);
335 if (Distance(mp
, mn
->Pos
)<dist
) {
337 LinkedLabel
->SetText( mn
->text
);
339 NotePosX
= mn
->Pos
.x
;
340 NotePosY
= mn
->Pos
.y
;
348 LinkedLabel
->SetText( "" );
351 case MAP_REVEAL
: //for farsee effect
352 Owner
->Cursor
= IE_CURSOR_CAST
;
355 Owner
->Cursor
= IE_CURSOR_GRAB
;
358 Owner
->Cursor
= IE_CURSOR_NORMAL
;
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
) {
375 if (Button
&GEM_MB_DOUBLECLICK
) {
376 RunEventHandler( MapControlOnDoublePress
);
377 printMessage("MapControl","Doubleclick detected\n",GREEN
);
379 RunEventHandler( MapControlOnPress
);
383 RunEventHandler( MapControlOnRightPress
);
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
;
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
) {
409 OnSpecialKeyPress(GEM_UP
);
411 case GEM_MB_SCRLDOWN
:
412 OnSpecialKeyPress(GEM_DOWN
);
415 if (Button
& GEM_MB_DOUBLECLICK
) {
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;
432 mouseIsDragging
= false;
438 /** Mouse Button Up */
439 void MapControl::OnMouseUp(unsigned short x
, unsigned short y
, unsigned short Button
,
440 unsigned short /*Mod*/)
447 mouseIsDragging
= false;
451 NotePosX
= (short) SCREEN_TO_MAPX(x
) * MAP_MULT
/ MAP_DIV
;
452 NotePosY
= (short) SCREEN_TO_MAPY(y
) * MAP_MULT
/ MAP_DIV
;
459 //left click allows setting only when in MAP_SET_NOTE mode
460 if ((Button
== GEM_MB_ACTION
) ) {
471 /** Special Key Press */
472 void MapControl::OnSpecialKeyPress(unsigned char Key
)
488 printf( "ALT pressed\n" );
491 printf( "TAB pressed\n" );
497 if (ScrollX
> MapWidth
- Width
)
498 ScrollX
= MapWidth
- Width
;
499 if (ScrollY
> MapHeight
- Height
)
500 ScrollY
= MapHeight
- Height
;
507 bool MapControl::SetEvent(int eventType
, const char *handler
)
512 case IE_GUI_MAP_ON_PRESS
:
513 SetEventHandler( MapControlOnPress
, handler
);
515 case IE_GUI_MAP_ON_RIGHT_PRESS
:
516 SetEventHandler( MapControlOnRightPress
, handler
);
518 case IE_GUI_MAP_ON_DOUBLE_PRESS
:
519 SetEventHandler( MapControlOnDoublePress
, handler
);