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