1 #include "Directories.h"
2 #include "Font.h"
3 #include "HImage.h"
4 #include "Local.h"
5 #include "MapScreen.h"
6 #include "Radar_Screen.h"
7 #include "Line.h"
8 #include "RenderWorld.h"
9 #include "Isometric_Utils.h"
10 #include "Interface.h"
11 #include "Overhead.h"
12 #include "Soldier_Control.h"
13 #include "Timer_Control.h"
14 #include "SysUtil.h"
15 #include "Render_Dirty.h"
16 #include "Overhead_Map.h"
17 #include "Squads.h"
18 #include "MouseSystem.h"
19 #include "Text.h"
20 #include "Font_Control.h"
21 #include "VObject.h"
22 #include "Interface_Control.h"
23 #include "Game_Clock.h"
24 #include "Map_Screen_Interface_Map_Inventory.h"
25 #include "Environment.h"
26 #include "Meanwhile.h"
27 #include "StrategicMap.h"
28 #include "Animation_Data.h"
29 #include "JAScreens.h"
30 #include "Video.h"
31 #include "VSurface.h"
32 #include "Button_System.h"
33 #include "ScreenIDs.h"
34 #include "UILayout.h"
35
36 #include "FileMan.h"
37
38 #include "ContentManager.h"
39 #include "GameInstance.h"
40
41 #include <cmath>
42
43 extern INT32 iCurrentMapSectorZ;
44
45 // the squad list font
46 #define SQUAD_FONT COMPFONT
47
48 #define SQUAD_REGION_HEIGHT 2 * RADAR_WINDOW_HEIGHT
49 #define SQUAD_WINDOW_TM_Y RADAR_WINDOW_TM_Y + GetFontHeight( SQUAD_FONT )
50
51 // subtractor for squad list from size of radar view region height
52 #define SUBTRACTOR_FOR_SQUAD_LIST 0
53
54
55 static SGPVObject* gusRadarImage;
56 BOOLEAN fRenderRadarScreen = TRUE;
57 static INT16 sSelectedSquadLine = -1;
58
59 BOOLEAN gfRadarCurrentGuyFlash = FALSE;
60
61
62 static MOUSE_REGION gRadarRegionSquadList[NUMBER_OF_SQUADS];
63
64
65 static void RadarRegionButtonCallback(MOUSE_REGION* pRegion, INT32 iReason);
66 static void RadarRegionMoveCallback(MOUSE_REGION* pRegion, INT32 iReason);
67
68
InitRadarScreen()69 void InitRadarScreen()
70 {
71 // Add region for radar
72 UINT16 const x = RADAR_WINDOW_X;
73 UINT16 const y = RADAR_WINDOW_TM_Y;
74 UINT16 const w = RADAR_WINDOW_WIDTH;
75 UINT16 const h = RADAR_WINDOW_HEIGHT;
76 MOUSE_REGION* const r = &gRadarRegion;
77 MSYS_DefineRegion(r, x, y, x + w, y + h, MSYS_PRIORITY_HIGHEST, 0, RadarRegionMoveCallback, RadarRegionButtonCallback);
78 r->Disable();
79 }
80
81
LoadRadarScreenBitmap(const char * const filename)82 void LoadRadarScreenBitmap(const char* const filename)
83 {
84 ClearOutRadarMapImage();
85
86 // Grab the Map image
87 ST::string image_filename(GCM->getRadarMapResourceName(FileMan::replaceExtension(FileMan::getFileName(filename), "sti")));
88
89 SGPVObject* const radar = AddVideoObjectFromFile(image_filename.c_str());
90 gusRadarImage = radar;
91
92 // ATE: Add a shade table!
93 const SGPPaletteEntry* const pal = radar->Palette();
94 radar->pShades[0] = Create16BPPPaletteShaded(pal, 255, 255, 255, FALSE);
95 radar->pShades[1] = Create16BPPPaletteShaded(pal, 100, 100, 100, FALSE);
96
97 // Dirty interface
98 fInterfacePanelDirty = DIRTYLEVEL1;
99 }
100
101
ClearOutRadarMapImage(void)102 void ClearOutRadarMapImage( void )
103 {
104 // If we have loaded, remove old one
105 if (gusRadarImage)
106 {
107 DeleteVideoObject(gusRadarImage);
108 gusRadarImage = 0;
109 }
110 }
111
112
MoveRadarScreen()113 void MoveRadarScreen( )
114 {
115 // check if we are allowed to do anything?
116 if (!fRenderRadarScreen) return;
117
118 gRadarRegion.RegionTopLeftX = RADAR_WINDOW_X;
119 gRadarRegion.RegionTopLeftY = RADAR_WINDOW_TM_Y;
120 gRadarRegion.RegionBottomRightX = RADAR_WINDOW_X + RADAR_WINDOW_WIDTH;
121 gRadarRegion.RegionBottomRightY = RADAR_WINDOW_TM_Y + RADAR_WINDOW_HEIGHT;
122
123 }
124
125
126 static void AdjustWorldCenterFromRadarCoords(INT16 sRadarX, INT16 sRadarY);
127
128
RadarRegionMoveCallback(MOUSE_REGION * pRegion,INT32 iReason)129 static void RadarRegionMoveCallback(MOUSE_REGION* pRegion, INT32 iReason)
130 {
131 INT16 sRadarX, sRadarY;
132
133 // check if we are allowed to do anything?
134 if (!fRenderRadarScreen) return;
135
136 if (iReason == MSYS_CALLBACK_REASON_MOVE )
137 {
138 if ( pRegion->ButtonState & MSYS_LEFT_BUTTON )
139 {
140 // Use relative coordinates to set center of viewport
141 sRadarX = pRegion->RelativeXPos - ( RADAR_WINDOW_WIDTH / 2 );
142 sRadarY = pRegion->RelativeYPos - ( RADAR_WINDOW_HEIGHT / 2 );
143
144 AdjustWorldCenterFromRadarCoords( sRadarX, sRadarY );
145
146 SetRenderFlags(RENDER_FLAG_FULL);
147
148 }
149 }
150 }
151
152
RadarRegionButtonCallback(MOUSE_REGION * pRegion,INT32 iReason)153 static void RadarRegionButtonCallback(MOUSE_REGION* pRegion, INT32 iReason)
154 {
155 INT16 sRadarX, sRadarY;
156
157 // check if we are allowed to do anything?
158 if (!fRenderRadarScreen) return;
159
160 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
161 {
162 if ( !InOverheadMap( ) )
163 {
164 // Use relative coordinates to set center of viewport
165 sRadarX = pRegion->RelativeXPos - ( RADAR_WINDOW_WIDTH / 2 );
166 sRadarY = pRegion->RelativeYPos - ( RADAR_WINDOW_HEIGHT / 2 );
167
168 AdjustWorldCenterFromRadarCoords( sRadarX, sRadarY );
169 }
170 else
171 {
172 KillOverheadMap();
173 }
174 }
175 else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
176 {
177 if ( !InOverheadMap( ) )
178 {
179 GoIntoOverheadMap( );
180 }
181 else
182 {
183 KillOverheadMap();
184 }
185 }
186 }
187
188
189 static void CreateDestroyMouseRegionsForSquadList(void);
190 static void RenderSquadList(void);
191
192
RenderRadarScreen()193 void RenderRadarScreen()
194 {
195 // create / destroy squad list regions as nessacary
196 CreateDestroyMouseRegionsForSquadList();
197
198 // check if we are allowed to do anything?
199 if (!fRenderRadarScreen)
200 {
201 RenderSquadList();
202 return;
203 }
204
205 // in a meanwhile, don't render any map
206 if (AreInMeanwhile()) ClearOutRadarMapImage();
207
208 if (fInterfacePanelDirty == DIRTYLEVEL2 && gusRadarImage)
209 {
210 // If night time and on surface, darken the radarmap.
211 size_t const shade =
212 NightTime() &&
213 (
214 (guiCurrentScreen == MAP_SCREEN && iCurrentMapSectorZ == 0) ||
215 (guiCurrentScreen == GAME_SCREEN && gbWorldSectorZ == 0)
216 ) ? 1 : 0;
217 gusRadarImage->CurrentShade(shade);
218 BltVideoObject(guiSAVEBUFFER, gusRadarImage, 0, RADAR_WINDOW_X, RADAR_WINDOW_TM_Y);
219 }
220
221 // First delete what's there
222 RestoreExternBackgroundRect(RADAR_WINDOW_X, RADAR_WINDOW_TM_Y, RADAR_WINDOW_WIDTH + 1, RADAR_WINDOW_HEIGHT + 1);
223
224 {
225 SGPVSurface::Lock l(FRAME_BUFFER);
226
227 SetClippingRegionAndImageWidth(l.Pitch(), RADAR_WINDOW_X, RADAR_WINDOW_TM_Y, RADAR_WINDOW_WIDTH, RADAR_WINDOW_HEIGHT);
228 UINT16* const pDestBuf = l.Buffer<UINT16>();
229
230 // Cycle fFlash variable
231 if (COUNTERDONE(RADAR_MAP_BLINK))
232 {
233 RESETCOUNTER(RADAR_MAP_BLINK);
234 gfRadarCurrentGuyFlash = !gfRadarCurrentGuyFlash;
235 }
236
237 if (!fInMapMode)
238 {
239 RectangleDraw(TRUE,
240 RADAR_WINDOW_X + MAX(0, round((gsTopLeftWorldX - SCROLL_LEFT_PADDING) * gdScaleX)),
241 RADAR_WINDOW_TM_Y + MAX(0, round((gsTopLeftWorldY - SCROLL_TOP_PADDING) * gdScaleY)),
242 RADAR_WINDOW_X + MIN(round((gsBottomRightWorldX - SCROLL_RIGHT_PADDING - SCROLL_LEFT_PADDING) * gdScaleX - 1.0), RADAR_WINDOW_WIDTH - 1),
243 RADAR_WINDOW_TM_Y + MIN(round((gsBottomRightWorldY - SCROLL_BOTTOM_PADDING - SCROLL_TOP_PADDING) * gdScaleY - 1.0), RADAR_WINDOW_HEIGHT - 1),
244 Get16BPPColor(FROMRGB(0, 255, 0)), pDestBuf);
245
246 // Re-render radar
247 FOR_EACH_MERC(i)
248 {
249 SOLDIERTYPE const* const s = *i;
250
251 // Don't place guys in radar until visible!
252 if (s->bVisible == -1 &&
253 !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS) &&
254 !(s->ubMiscSoldierFlags & SOLDIER_MISC_XRAYED))
255 {
256 continue;
257 }
258
259 if (s->uiStatusFlags & SOLDIER_DEAD) continue;
260 if (s->ubBodyType == CROW) continue;
261 if (!GridNoOnVisibleWorldTile(s->sGridNo)) continue;
262
263 // Get fullscreen coordinate for guy's position
264 INT16 sXSoldScreen;
265 INT16 sYSoldScreen;
266 GetAbsoluteScreenXYFromMapPos(s->sGridNo, &sXSoldScreen, &sYSoldScreen);
267
268 // Get radar x and y postion and add starting relative to interface
269 const INT16 x = floor(DOUBLE(sXSoldScreen) * gdScaleX) + RADAR_WINDOW_X;
270 const INT16 y = floor(DOUBLE(sYSoldScreen) * gdScaleY) + RADAR_WINDOW_TM_Y;
271
272 UINT32 const line_colour =
273 /* flash selected merc */
274 s == GetSelectedMan() && gfRadarCurrentGuyFlash ? 0 :
275 /* on roof */
276 s->bTeam == OUR_TEAM && s->bLevel > 0 ? FROMRGB(150, 150, 0) :
277 /* unconscious enemy */
278 s->bTeam != OUR_TEAM && s->bLife < OKLIFE ? FROMRGB(128, 128, 128) :
279 /* hostile civilian */
280 s->bTeam == CIV_TEAM && !s->bNeutral && s->bSide != OUR_TEAM ? FROMRGB(255, 0, 0) :
281 gTacticalStatus.Team[s->bTeam].RadarColor;
282
283 RectangleDraw(TRUE, x, y, x + 1, y + 1, Get16BPPColor(line_colour), pDestBuf);
284 }
285 }
286 else if (fShowMapInventoryPool)
287 {
288 if (iCurrentlyHighLightedItem != -1)
289 {
290 INT32 const item_idx = iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT + iCurrentlyHighLightedItem;
291 WORLDITEM const& wi = pInventoryPoolList[item_idx];
292 if (wi.o.ubNumberOfObjects != 0 && wi.sGridNo != 0)
293 {
294 INT16 sXSoldScreen;
295 INT16 sYSoldScreen;
296 GetAbsoluteScreenXYFromMapPos(wi.sGridNo, &sXSoldScreen, &sYSoldScreen);
297
298 // Get radar x and y postion and add starting relative to interface
299 INT16 const x = sXSoldScreen * gdScaleX + RADAR_WINDOW_X;
300 INT16 const y = sYSoldScreen * gdScaleY + RADAR_WINDOW_TM_Y;
301
302 UINT16 const line_colour = fFlashHighLightInventoryItemOnradarMap ?
303 Get16BPPColor(FROMRGB( 0, 255, 0)) :
304 Get16BPPColor(FROMRGB(255, 255, 255));
305
306 RectangleDraw(TRUE, x, y, x + 1, y + 1, line_colour, pDestBuf);
307 }
308 }
309 InvalidateRegion(RADAR_WINDOW_X, RADAR_WINDOW_TM_Y, RADAR_WINDOW_X + RADAR_WINDOW_WIDTH, RADAR_WINDOW_TM_Y + RADAR_WINDOW_HEIGHT);
310 }
311 }
312 }
313
314
AdjustWorldCenterFromRadarCoords(INT16 sRadarX,INT16 sRadarY)315 static void AdjustWorldCenterFromRadarCoords(INT16 sRadarX, INT16 sRadarY)
316 {
317 const INT16 SCROLL_X_STEP = WORLD_TILE_X;
318 const INT16 SCROLL_Y_STEP = WORLD_TILE_Y * 2;
319
320 INT16 sScreenX, sScreenY;
321 INT16 sTempX_W, sTempY_W;
322 INT16 sNewCenterWorldX, sNewCenterWorldY;
323 INT16 sNumXSteps, sNumYSteps;
324
325 // Use radar scale values to get screen values, then convert ot map values, rounding to nearest middle tile
326 sScreenX = (INT16) ( sRadarX / gdScaleX );
327 sScreenY = (INT16) ( sRadarY / gdScaleY );
328
329 // Adjust to viewport start!
330 sScreenX -= ( g_ui.m_tacticalMapCenterX );
331 sScreenY -= ( g_ui.m_tacticalMapCenterY );
332
333 //Make sure these coordinates are multiples of scroll steps
334 sNumXSteps = sScreenX / SCROLL_X_STEP;
335 sNumYSteps = sScreenY / SCROLL_Y_STEP;
336
337 sScreenX = ( sNumXSteps * SCROLL_X_STEP );
338 sScreenY = ( sNumYSteps * SCROLL_Y_STEP );
339
340 // Adjust back
341 sScreenX += ( g_ui.m_tacticalMapCenterX );
342 sScreenY += ( g_ui.m_tacticalMapCenterY );
343
344 // Subtract world center
345 //sScreenX += gsCX;
346 //sScreenY += gsCY;
347
348 // Convert these into world coordinates
349 FromScreenToCellCoordinates( sScreenX, sScreenY, &sTempX_W, &sTempY_W );
350
351 // Adjust these to world center
352 sNewCenterWorldX = (INT16)(gCenterWorldX + sTempX_W);
353 sNewCenterWorldY = (INT16)(gCenterWorldY + sTempY_W);
354
355 SetRenderCenter( sNewCenterWorldX, sNewCenterWorldY );
356 }
357
358
ToggleRadarScreenRender(void)359 void ToggleRadarScreenRender( void )
360 {
361 fRenderRadarScreen = ! fRenderRadarScreen;
362 }
363
364
365 static void TacticalSquadListBtnCallBack(MOUSE_REGION* pRegion, INT32 iReason);
366 static void TacticalSquadListMvtCallback(MOUSE_REGION* pRegion, INT32 iReason);
367
368
369 // create destroy squad list regions as needed
CreateDestroyMouseRegionsForSquadList(void)370 static void CreateDestroyMouseRegionsForSquadList(void)
371 {
372 // will check the state of renderradarscreen flag and decide if we need to create mouse regions for
373 static BOOLEAN fCreated = FALSE;
374
375 if (!fRenderRadarScreen && !fCreated)
376 {
377 BltVideoObjectOnce(guiSAVEBUFFER, INTERFACEDIR "/squadpanel.sti", 0, 538, gsVIEWPORT_END_Y);
378 RestoreExternBackgroundRect(538, gsVIEWPORT_END_Y, 102, 120);
379
380 // create regions
381 INT16 const w = RADAR_WINDOW_WIDTH / 2 - 1;
382 INT16 const h = (SQUAD_REGION_HEIGHT - SUBTRACTOR_FOR_SQUAD_LIST) / (NUMBER_OF_SQUADS / 2);
383 for (UINT i = 0; i < NUMBER_OF_SQUADS; ++i)
384 {
385 // run through list of squads and place appropriatly
386 INT16 x = RADAR_WINDOW_X;
387 INT16 y = SQUAD_WINDOW_TM_Y;
388 if (i < NUMBER_OF_SQUADS / 2)
389 {
390 // left half of list
391 y += i * h;
392 }
393 else
394 {
395 // right half of list
396 x += RADAR_WINDOW_WIDTH / 2;
397 y += (i - NUMBER_OF_SQUADS / 2) * h;
398 }
399
400 MOUSE_REGION* const r = &gRadarRegionSquadList[i];
401 MSYS_DefineRegion(r, x, y, x + w, y + h, MSYS_PRIORITY_HIGHEST, 0, TacticalSquadListMvtCallback, TacticalSquadListBtnCallBack);
402 MSYS_SetRegionUserData(r, 0, i);
403 }
404
405 sSelectedSquadLine = -1;
406
407 fCreated = TRUE;
408 }
409 else if (fRenderRadarScreen && fCreated)
410 {
411 // destroy regions
412 for (UINT i = 0; i < NUMBER_OF_SQUADS; ++i)
413 {
414 MSYS_RemoveRegion(&gRadarRegionSquadList[i]);
415 }
416
417 if (guiCurrentScreen == GAME_SCREEN)
418 {
419 fInterfacePanelDirty = DIRTYLEVEL2;
420 MarkButtonsDirty();
421 RenderTacticalInterface();
422 RenderButtons();
423 RenderPausedGameBox();
424 }
425
426 fCreated = FALSE;
427 }
428 }
429
430
431 // show list of squads
RenderSquadList(void)432 static void RenderSquadList(void)
433 {
434 INT16 const dx = RADAR_WINDOW_X;
435 INT16 const dy = RADAR_WINDOW_TM_Y;
436
437 RestoreExternBackgroundRect(dx, dy, RADAR_WINDOW_WIDTH, SQUAD_REGION_HEIGHT);
438 ColorFillVideoSurfaceArea(FRAME_BUFFER, dx, dy, dx + RADAR_WINDOW_WIDTH, dy + SQUAD_REGION_HEIGHT, Get16BPPColor(FROMRGB(0, 0, 0)));
439
440 SetFont(SQUAD_FONT);
441 SetFontBackground(FONT_BLACK);
442
443 for (INT16 i = 0; i < NUMBER_OF_SQUADS; ++i)
444 {
445 const UINT8 colour =
446 sSelectedSquadLine == i ? FONT_WHITE : // highlight line?
447 !IsSquadOnCurrentTacticalMap(i) ? FONT_BLACK :
448 CurrentSquad() == i ? FONT_LTGREEN :
449 FONT_DKGREEN;
450 SetFontForeground(colour);
451
452 INT16 sX;
453 INT16 sY;
454 INT16 x = dx;
455 INT16 y = SQUAD_WINDOW_TM_Y;
456 INT16 const w = RADAR_WINDOW_WIDTH / 2 - 1;
457 INT16 const h = 2 * (SQUAD_REGION_HEIGHT - SUBTRACTOR_FOR_SQUAD_LIST) / NUMBER_OF_SQUADS;
458 if (i < NUMBER_OF_SQUADS / 2)
459 {
460 x += 2;
461 y += i * h;
462 }
463 else
464 {
465 x += RADAR_WINDOW_WIDTH / 2 - 2;
466 y += (i - NUMBER_OF_SQUADS / 2) * h;
467 }
468 FindFontCenterCoordinates(x, y, w, h, pSquadMenuStrings[i], SQUAD_FONT, &sX, &sY);
469 MPrint(x, sY, pSquadMenuStrings[i]);
470 }
471 }
472
473
TacticalSquadListMvtCallback(MOUSE_REGION * pRegion,INT32 iReason)474 static void TacticalSquadListMvtCallback(MOUSE_REGION* pRegion, INT32 iReason)
475 {
476 INT32 iValue = -1;
477
478 iValue = MSYS_GetRegionUserData( pRegion, 0 );
479
480 if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
481 {
482 if (IsSquadOnCurrentTacticalMap(iValue))
483 {
484 sSelectedSquadLine = ( INT16 )iValue;
485 }
486 }
487 if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
488 {
489 sSelectedSquadLine = -1;
490 }
491 }
492
493
TacticalSquadListBtnCallBack(MOUSE_REGION * pRegion,INT32 iReason)494 static void TacticalSquadListBtnCallBack(MOUSE_REGION* pRegion, INT32 iReason)
495 {
496 // btn callback handler for team list info region
497 INT32 iValue = 0;
498
499 iValue = MSYS_GetRegionUserData( pRegion, 0 );
500
501 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
502 {
503 // find out if this squad is valid and on this map..if so, set as selected
504 if (IsSquadOnCurrentTacticalMap(iValue))
505 {
506 // ok, squad is here, set as selected
507 SetCurrentSquad( iValue, FALSE );
508
509 // stop showing
510 fRenderRadarScreen = TRUE;
511 }
512 }
513 }
514