1 #include "Directories.h"
2 #include "Font.h"
3 #include "Interface.h"
4 #include "Local.h"
5 #include "Map_Screen_Interface_Bottom.h"
6 #include "Map_Screen_Interface_Border.h"
7 #include "MessageBoxScreen.h"
8 #include "Timer_Control.h"
9 #include "Types.h"
10 #include "VObject.h"
11 #include "VSurface.h"
12 #include "MouseSystem.h"
13 #include "Button_System.h"
14 #include "Message.h"
15 #include "MapScreen.h"
16 #include "StrategicMap.h"
17 #include "Font_Control.h"
18 #include "Radar_Screen.h"
19 #include "Game_Clock.h"
20 #include "SysUtil.h"
21 #include "Render_Dirty.h"
22 #include "Map_Screen_Interface.h"
23 #include "Map_Screen_Interface_Map.h"
24 #include "Text.h"
25 #include "Overhead.h"
26 #include "PreBattle_Interface.h"
27 #include "Options_Screen.h"
28 #include "Cursor_Control.h"
29 #include "GameLoop.h"
30 #include "AI.h"
31 #include "Tactical_Save.h"
32 #include "Campaign_Types.h"
33 #include "Finances.h"
34 #include "LaptopSave.h"
35 #include "Interface_Items.h"
36 #include "WordWrap.h"
37 #include "Dialogue_Control.h"
38 #include "Meanwhile.h"
39 #include "Map_Screen_Helicopter.h"
40 #include "Map_Screen_Interface_TownMine_Info.h"
41 #include "Merc_Contract.h"
42 #include "Map_Screen_Interface_Map_Inventory.h"
43 #include "Explosion_Control.h"
44 #include "Creature_Spreading.h"
45 #include "Soldier_Macros.h"
46 #include "GameSettings.h"
47 #include "SaveLoadScreen.h"
48 #include "Debug.h"
49 #include "JAScreens.h"
50 #include "ScreenIDs.h"
51 #include "UILayout.h"
52 
53 #include <string_theory/string>
54 
55 
56 #define MAP_BOTTOM_X (STD_SCREEN_X + 0)
57 #define MAP_BOTTOM_Y (STD_SCREEN_Y + 359)
58 
59 #define MESSAGE_BOX_X (STD_SCREEN_X +  17)
60 #define MESSAGE_BOX_Y (STD_SCREEN_Y + 377)
61 #define MESSAGE_BOX_W 301
62 #define MESSAGE_BOX_H  86
63 
64 #define MESSAGE_SCROLL_AREA_START_X (STD_SCREEN_X + 330)
65 #define MESSAGE_SCROLL_AREA_WIDTH    15
66 
67 #define MESSAGE_SCROLL_AREA_START_Y (STD_SCREEN_Y + 390)
68 #define MESSAGE_SCROLL_AREA_HEIGHT   59
69 
70 #define SLIDER_HEIGHT		11
71 #define SLIDER_WIDTH		11
72 
73 #define SLIDER_BAR_RANGE			( MESSAGE_SCROLL_AREA_HEIGHT - SLIDER_HEIGHT )
74 
75 
76 
77 #define MESSAGE_BTN_SCROLL_TIME 100
78 
79 // delay for paused flash
80 #define PAUSE_GAME_TIMER 500
81 
82 #define MAP_BOTTOM_FONT_COLOR ( 32 * 4 - 9 )
83 
84 // button enums
85 enum{
86 	MAP_SCROLL_MESSAGE_UP =0,
87 	MAP_SCROLL_MESSAGE_DOWN,
88 };
89 
90 enum{
91 	MAP_TIME_COMPRESS_MORE = 0,
92 	MAP_TIME_COMPRESS_LESS,
93 };
94 
95 
96 BOOLEAN fMapScreenBottomDirty = TRUE;
97 
98 static BOOLEAN fMapBottomDirtied = FALSE;
99 
100 //Used to flag the transition animation from mapscreen to laptop.
101 BOOLEAN gfStartMapScreenToLaptopTransition = FALSE;
102 
103 // leaving map screen
104 BOOLEAN fLeavingMapScreen = FALSE;
105 
106 // don't start transition from laptop to tactical stuff
107 BOOLEAN gfDontStartTransitionFromLaptop = FALSE;
108 
109 // exiting to laptop?
110 BOOLEAN fLapTop = FALSE;
111 
112 static BOOLEAN gfOneFramePauseOnExit = FALSE;
113 
114 // exit states
115 static ExitToWhere gbExitingMapScreenToWhere = MAP_EXIT_TO_INVALID;
116 
117 static UINT8 gubFirstMapscreenMessageIndex = 0;
118 
119 UINT32 guiCompressionStringBaseTime = 0;
120 
121 // graphics
122 static SGPVObject* guiMAPBOTTOMPANEL;
123 static SGPVObject* guiSliderBar;
124 
125 // buttons
126 GUIButtonRef        guiMapBottomExitButtons[3];
127 static GUIButtonRef guiMapBottomTimeButtons[2];
128 static GUIButtonRef guiMapMessageScrollButtons[2];
129 
130 // mouse regions
131 static MOUSE_REGION gMapMessageScrollBarRegion;
132 static MOUSE_REGION gMapPauseRegion;
133 
134 static MOUSE_REGION gTimeCompressionMask[3];
135 
136 
137 static void BtnLaptopCallback(GUI_BUTTON *btn, INT32 reason);
138 static void BtnTacticalCallback(GUI_BUTTON *btn, INT32 reason);
139 static void BtnOptionsFromMapScreenCallback(GUI_BUTTON *btn, INT32 reason);
140 
141 static void BtnTimeCompressMoreMapScreenCallback(GUI_BUTTON *btn, INT32 reason);
142 static void BtnTimeCompressLessMapScreenCallback(GUI_BUTTON *btn, INT32 reason);
143 
144 static void BtnMessageDownMapScreenCallback(GUI_BUTTON *btn, INT32 reason);
145 static void BtnMessageUpMapScreenCallback(GUI_BUTTON *btn, INT32 reason);
146 
147 
148 static void LoadMessageSliderBar(void);
149 
150 
HandleLoadOfMapBottomGraphics(void)151 void HandleLoadOfMapBottomGraphics( void )
152 {
153 	// will load the graphics needed for the mapscreen interface bottom
154 	// will create buttons for interface bottom
155 	guiMAPBOTTOMPANEL = AddVideoObjectFromFile(INTERFACEDIR "/map_screen_bottom.sti");
156 
157 	// load slider bar icon
158 	LoadMessageSliderBar( );
159 }
160 
161 
162 static void CreateButtonsForMapScreenInterfaceBottom(void);
163 static void CreateCompressModePause(void);
164 static void CreateMapScreenBottomMessageScrollBarRegion(void);
165 
166 
LoadMapScreenInterfaceBottom(void)167 void LoadMapScreenInterfaceBottom(void)
168 {
169 	CreateButtonsForMapScreenInterfaceBottom();
170 	CreateMapScreenBottomMessageScrollBarRegion( );
171 
172 	// create pause region
173 	CreateCompressModePause( );
174 }
175 
176 
177 static void DeleteMessageSliderBar(void);
178 
179 
DeleteMapBottomGraphics(void)180 void DeleteMapBottomGraphics( void )
181 {
182 	DeleteVideoObject(guiMAPBOTTOMPANEL);
183 	// delete slider bar icon
184 	DeleteMessageSliderBar( );
185 }
186 
187 
188 static void DeleteMapScreenBottomMessageScrollRegion(void);
189 static void DestroyButtonsForMapScreenInterfaceBottom();
190 static void RemoveCompressModePause(void);
191 
192 
DeleteMapScreenInterfaceBottom(void)193 void DeleteMapScreenInterfaceBottom( void )
194 {
195 	// will delete graphics loaded for the mapscreen interface bottom
196 
197 	DestroyButtonsForMapScreenInterfaceBottom( );
198 	DeleteMapScreenBottomMessageScrollRegion( );
199 
200 	// remove comrpess mode pause
201 	RemoveCompressModePause( );
202 }
203 
204 
205 static void DisplayCompressMode(void);
206 static void DisplayCurrentBalanceForMapBottom(void);
207 static void DisplayCurrentBalanceTitleForMapBottom(void);
208 static void DisplayProjectedDailyMineIncome(void);
209 static void DisplayScrollBarSlider(void);
210 static void DrawNameOfLoadedSector();
211 static void EnableDisableBottomButtonsAndRegions(void);
212 static void EnableDisableMessageScrollButtonsAndRegions(void);
213 
214 
RenderMapScreenInterfaceBottom(void)215 void RenderMapScreenInterfaceBottom( void )
216 {
217 	// will render the map screen bottom interface
218 	CHAR8 bFilename[ 32 ];
219 
220 
221 	// render whole panel
222 	if (fMapScreenBottomDirty)
223 	{
224 		BltVideoObject(guiSAVEBUFFER, guiMAPBOTTOMPANEL, 0, MAP_BOTTOM_X, MAP_BOTTOM_Y);
225 
226 		if (GetSectorFlagStatus(sSelMapX, sSelMapY, iCurrentMapSectorZ, SF_ALREADY_VISITED))
227 		{
228 			GetMapFileName(sSelMapX, sSelMapY, iCurrentMapSectorZ, bFilename, TRUE);
229 			LoadRadarScreenBitmap( bFilename );
230 		}
231 		else
232 		{
233 			ClearOutRadarMapImage();
234 		}
235 
236 		fInterfacePanelDirty = DIRTYLEVEL2;
237 
238 		// display title
239 		DisplayCurrentBalanceTitleForMapBottom( );
240 
241 		// dirty buttons
242 		MarkButtonsDirty( );
243 
244 		// invalidate region
245 		RestoreExternBackgroundRect(MAP_BOTTOM_X, MAP_BOTTOM_Y, SCREEN_WIDTH - MAP_BOTTOM_X, SCREEN_HEIGHT - MAP_BOTTOM_Y);
246 
247 		// re render radar map
248 		RenderRadarScreen( );
249 
250 		// reset dirty flag
251 		fMapScreenBottomDirty = FALSE;
252 		fMapBottomDirtied = TRUE;
253 	}
254 
255 	DisplayCompressMode( );
256 
257 	DisplayCurrentBalanceForMapBottom( );
258 	DisplayProjectedDailyMineIncome( );
259 
260 	// draw the name of the loaded sector
261 	DrawNameOfLoadedSector( );
262 
263 	// display slider on the scroll bar
264 	DisplayScrollBarSlider( );
265 
266 	// display messages that can be scrolled through
267 	DisplayStringsInMapScreenMessageList( );
268 
269 	EnableDisableMessageScrollButtonsAndRegions( );
270 
271 	EnableDisableBottomButtonsAndRegions( );
272 
273 	fMapBottomDirtied = FALSE;
274 }
275 
276 
MakeExitButton(INT32 off,INT32 on,INT16 x,INT16 y,GUI_CALLBACK click,const ST::string & help)277 static GUIButtonRef MakeExitButton(INT32 off, INT32 on, INT16 x, INT16 y, GUI_CALLBACK click, const ST::string& help)
278 {
279 	GUIButtonRef const btn = QuickCreateButtonImg(INTERFACEDIR "/map_border_buttons.sti", off, on, x, y, MSYS_PRIORITY_HIGHEST - 1, click);
280 	btn->SetFastHelpText(help);
281 	btn->SetCursor(MSYS_NO_CURSOR);
282 	return btn;
283 }
284 
285 
MakeArrowButton(INT32 grayed,INT32 off,INT32 on,INT16 x,INT16 y,GUI_CALLBACK click,const ST::string & help)286 static GUIButtonRef MakeArrowButton(INT32 grayed, INT32 off, INT32 on, INT16 x, INT16 y, GUI_CALLBACK click, const ST::string& help)
287 {
288 	GUIButtonRef const btn = QuickCreateButtonImg(INTERFACEDIR "/map_screen_bottom_arrows.sti", grayed, off, -1, on, -1, x, y, MSYS_PRIORITY_HIGHEST - 2, click);
289 	btn->SetFastHelpText(help);
290 	btn->SetCursor(MSYS_NO_CURSOR);
291 	return btn;
292 }
293 
294 
CreateButtonsForMapScreenInterfaceBottom(void)295 static void CreateButtonsForMapScreenInterfaceBottom(void)
296 {
297 	guiMapBottomExitButtons[MAP_EXIT_TO_LAPTOP]   = MakeExitButton( 6, 15, STD_SCREEN_X + 456, STD_SCREEN_Y + 410, BtnLaptopCallback,               pMapScreenBottomFastHelp[0]);
298 	guiMapBottomExitButtons[MAP_EXIT_TO_TACTICAL] = MakeExitButton( 7, 16, STD_SCREEN_X + 496, STD_SCREEN_Y + 410, BtnTacticalCallback,             pMapScreenBottomFastHelp[1]);
299 	guiMapBottomExitButtons[MAP_EXIT_TO_OPTIONS]  = MakeExitButton(18, 19, STD_SCREEN_X + 458, STD_SCREEN_Y + 372, BtnOptionsFromMapScreenCallback, pMapScreenBottomFastHelp[2]);
300 
301 	// time compression buttons
302 	guiMapBottomTimeButtons[MAP_TIME_COMPRESS_MORE] = MakeArrowButton(10, 1, 3, STD_SCREEN_X + 528, STD_SCREEN_Y + 456, BtnTimeCompressMoreMapScreenCallback, pMapScreenBottomFastHelp[3]);
303 	guiMapBottomTimeButtons[MAP_TIME_COMPRESS_LESS] = MakeArrowButton( 9, 0, 2, STD_SCREEN_X + 466, STD_SCREEN_Y + 456, BtnTimeCompressLessMapScreenCallback, pMapScreenBottomFastHelp[4]);
304 
305 	// scroll buttons
306 	guiMapMessageScrollButtons[MAP_SCROLL_MESSAGE_UP]   = MakeArrowButton(11, 4, 6, STD_SCREEN_X + 331, STD_SCREEN_Y + 371, BtnMessageUpMapScreenCallback,   pMapScreenBottomFastHelp[5]);
307 	guiMapMessageScrollButtons[MAP_SCROLL_MESSAGE_DOWN] = MakeArrowButton(12, 5, 7, STD_SCREEN_X + 331, STD_SCREEN_Y + 452, BtnMessageDownMapScreenCallback, pMapScreenBottomFastHelp[6]);
308 }
309 
310 
DestroyButtonsForMapScreenInterfaceBottom()311 static void DestroyButtonsForMapScreenInterfaceBottom()
312 {
313 	FOR_EACH(GUIButtonRef, i, guiMapBottomExitButtons)    RemoveButton(*i);
314 	FOR_EACH(GUIButtonRef, i, guiMapBottomTimeButtons)    RemoveButton(*i);
315 	FOR_EACH(GUIButtonRef, i, guiMapMessageScrollButtons) RemoveButton(*i);
316 	fMapScreenBottomDirty = TRUE;
317 }
318 
319 
BtnLaptopCallback(GUI_BUTTON * btn,INT32 reason)320 static void BtnLaptopCallback(GUI_BUTTON *btn, INT32 reason)
321 {
322 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
323 	{
324 		// redraw region
325 		if (btn->Area.uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
326 	}
327 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
328 	{
329 		RequestTriggerExitFromMapscreen(MAP_EXIT_TO_LAPTOP);
330 	}
331 }
332 
333 
BtnTacticalCallback(GUI_BUTTON * btn,INT32 reason)334 static void BtnTacticalCallback(GUI_BUTTON *btn, INT32 reason)
335 {
336 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
337 	{
338 		// redraw region
339 		if (btn->Area.uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
340 	}
341 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
342 	{
343 		RequestTriggerExitFromMapscreen(MAP_EXIT_TO_TACTICAL);
344 	}
345 }
346 
347 
BtnOptionsFromMapScreenCallback(GUI_BUTTON * btn,INT32 reason)348 static void BtnOptionsFromMapScreenCallback(GUI_BUTTON *btn, INT32 reason)
349 {
350 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
351 	{
352 		// redraw region
353 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
354 	}
355 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
356 	{
357 		fMapScreenBottomDirty = TRUE;
358 		RequestTriggerExitFromMapscreen(MAP_EXIT_TO_OPTIONS);
359 	}
360 }
361 
362 
DrawNameOfLoadedSector()363 static void DrawNameOfLoadedSector()
364 {
365 	SetFontDestBuffer(FRAME_BUFFER);
366 	SGPFont const font = COMPFONT;
367 	SetFontAttributes(font, 183);
368 
369 	ST::string buf = GetSectorIDString(sSelMapX, sSelMapY, iCurrentMapSectorZ, TRUE);
370 	buf = ReduceStringLength(buf, 80, font);
371 
372 	INT16 x;
373 	INT16 y;
374 	FindFontCenterCoordinates(STD_SCREEN_X + 548, STD_SCREEN_Y + 426, 80, 16, buf, font, &x, &y);
375 	MPrint(x, y, buf);
376 }
377 
378 
CompressModeClickCallback(MOUSE_REGION * pRegion,INT32 iReason)379 static void CompressModeClickCallback(MOUSE_REGION* pRegion, INT32 iReason)
380 {
381 	if( iReason & ( MSYS_CALLBACK_REASON_RBUTTON_UP | MSYS_CALLBACK_REASON_LBUTTON_UP ) )
382 	{
383 		if (CommonTimeCompressionChecks()) return;
384 
385 		RequestToggleTimeCompression();
386 	}
387 }
388 
389 
BtnTimeCompressMoreMapScreenCallback(GUI_BUTTON * btn,INT32 reason)390 static void BtnTimeCompressMoreMapScreenCallback(GUI_BUTTON *btn, INT32 reason)
391 {
392 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
393 	{
394 		if (CommonTimeCompressionChecks()) return;
395 		// redraw region
396 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
397 	}
398 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
399 	{
400 		fMapScreenBottomDirty = TRUE;
401 		RequestIncreaseInTimeCompression();
402 	}
403 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
404 	{
405 		CommonTimeCompressionChecks();
406 	}
407 }
408 
409 
BtnTimeCompressLessMapScreenCallback(GUI_BUTTON * btn,INT32 reason)410 static void BtnTimeCompressLessMapScreenCallback(GUI_BUTTON *btn, INT32 reason)
411 {
412 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
413 	{
414 		if (CommonTimeCompressionChecks()) return;
415 		// redraw region
416 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
417 	}
418 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
419 	{
420 		fMapScreenBottomDirty = TRUE;
421 		RequestDecreaseInTimeCompression();
422 	}
423 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
424 	{
425 		CommonTimeCompressionChecks();
426 	}
427 }
428 
429 
BtnMessageDownMapScreenCallback(GUI_BUTTON * btn,INT32 reason)430 static void BtnMessageDownMapScreenCallback(GUI_BUTTON *btn, INT32 reason)
431 {
432 	static INT32 iLastRepeatScrollTime = 0;
433 
434 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
435 	{
436 		// redraw region
437 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
438 		iLastRepeatScrollTime = 0;
439 	}
440 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
441 	{
442 		// redraw region
443 		if (btn ->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
444 		MapScreenMsgScrollDown(1);
445 	}
446 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT)
447 	{
448 		if (GetJA2Clock() - iLastRepeatScrollTime >= MESSAGE_BTN_SCROLL_TIME)
449 		{
450 			MapScreenMsgScrollDown(1);
451 			iLastRepeatScrollTime = GetJA2Clock();
452 		}
453 	}
454 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
455 	{
456 		// redraw region
457 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
458 		iLastRepeatScrollTime = 0;
459 	}
460 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_UP)
461 	{
462 		// redraw region
463 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
464 		MapScreenMsgScrollDown(MAX_MESSAGES_ON_MAP_BOTTOM);
465 	}
466 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_REPEAT)
467 	{
468 		if (GetJA2Clock() - iLastRepeatScrollTime >= MESSAGE_BTN_SCROLL_TIME)
469 		{
470 			MapScreenMsgScrollDown(MAX_MESSAGES_ON_MAP_BOTTOM);
471 			iLastRepeatScrollTime = GetJA2Clock();
472 		}
473 	}
474 }
475 
476 
BtnMessageUpMapScreenCallback(GUI_BUTTON * btn,INT32 reason)477 static void BtnMessageUpMapScreenCallback(GUI_BUTTON *btn, INT32 reason)
478 {
479 	static INT32 iLastRepeatScrollTime = 0;
480 
481 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_DWN)
482 	{
483 		// redraw region
484 		if (btn->Area.uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
485 		iLastRepeatScrollTime = 0;
486 	}
487 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
488 	{
489 		// redraw region
490 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
491 		MapScreenMsgScrollUp(1);
492 	}
493 	else if (reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT)
494 	{
495 		if (GetJA2Clock() - iLastRepeatScrollTime >= MESSAGE_BTN_SCROLL_TIME)
496 		{
497 			MapScreenMsgScrollUp(1);
498 			iLastRepeatScrollTime = GetJA2Clock();
499 		}
500 	}
501 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_DWN)
502 	{
503 		// redraw region
504 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
505 		iLastRepeatScrollTime = 0;
506 	}
507 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_UP)
508 	{
509 		// redraw region
510 		if (btn->uiFlags & MSYS_HAS_BACKRECT) fMapScreenBottomDirty = TRUE;
511 		MapScreenMsgScrollUp(MAX_MESSAGES_ON_MAP_BOTTOM);
512 	}
513 	else if (reason & MSYS_CALLBACK_REASON_RBUTTON_REPEAT)
514 	{
515 		if (GetJA2Clock() - iLastRepeatScrollTime >= MESSAGE_BTN_SCROLL_TIME)
516 		{
517 			MapScreenMsgScrollUp(MAX_MESSAGES_ON_MAP_BOTTOM);
518 			iLastRepeatScrollTime = GetJA2Clock();
519 		}
520 	}
521 }
522 
523 
EnableDisableMessageScrollButtonsAndRegions(void)524 static void EnableDisableMessageScrollButtonsAndRegions(void)
525 {
526 	UINT8 ubNumMessages;
527 
528 	ubNumMessages = GetRangeOfMapScreenMessages();
529 
530 	// if no scrolling required, or already showing the topmost message
531 	if( ( ubNumMessages <= MAX_MESSAGES_ON_MAP_BOTTOM ) || ( gubFirstMapscreenMessageIndex == 0 ) )
532 	{
533 		DisableButton( guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] );
534 		guiMapMessageScrollButtons[MAP_SCROLL_MESSAGE_UP]->uiFlags &= ~BUTTON_CLICKED_ON;
535 	}
536 	else
537 	{
538 		EnableButton( guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] );
539 	}
540 
541 	// if no scrolling required, or already showing the last message
542 	if( ( ubNumMessages <= MAX_MESSAGES_ON_MAP_BOTTOM ) ||
543 			( ( gubFirstMapscreenMessageIndex + MAX_MESSAGES_ON_MAP_BOTTOM ) >= ubNumMessages ) )
544 	{
545 		DisableButton( guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] );
546 		guiMapMessageScrollButtons[MAP_SCROLL_MESSAGE_DOWN]->uiFlags &= ~BUTTON_CLICKED_ON;
547 	}
548 	else
549 	{
550 		EnableButton( guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] );
551 	}
552 
553 	if( ubNumMessages <= MAX_MESSAGES_ON_MAP_BOTTOM )
554 	{
555 		gMapMessageScrollBarRegion.Disable();
556 	}
557 	else
558 	{
559 		gMapMessageScrollBarRegion.Enable();
560 	}
561 }
562 
563 
DisplayCompressMode(void)564 static void DisplayCompressMode(void)
565 {
566 	INT16 sX, sY;
567 	static UINT8 usColor = FONT_LTGREEN;
568 
569 	// get compress speed
570 	ST::string Time;
571 	if( giTimeCompressMode != NOT_USING_TIME_COMPRESSION )
572 	{
573 		Time = sTimeStrings[IsTimeBeingCompressed() ? giTimeCompressMode : 0];
574 	}
575 
576 	RestoreExternBackgroundRect( STD_SCREEN_X + 489, STD_SCREEN_Y + 457, 522 - 489, 467 - 454 );
577 	SetFontDestBuffer(FRAME_BUFFER);
578 
579 	if( GetJA2Clock() - guiCompressionStringBaseTime >= PAUSE_GAME_TIMER )
580 	{
581 		if( usColor == FONT_LTGREEN )
582 		{
583 			usColor = FONT_WHITE;
584 		}
585 		else
586 		{
587 			usColor = FONT_LTGREEN;
588 		}
589 
590 		guiCompressionStringBaseTime = GetJA2Clock();
591 	}
592 
593 	if (giTimeCompressMode != 0 && !GamePaused())
594 	{
595 		usColor = FONT_LTGREEN;
596 	}
597 
598 	SetFontAttributes(COMPFONT, usColor);
599 	FindFontCenterCoordinates(STD_SCREEN_X + 489, STD_SCREEN_Y + 457, 522 - 489, 467 - 454, Time, COMPFONT, &sX, &sY);
600 	MPrint(sX, sY, Time);
601 }
602 
603 
CreateCompressModePause(void)604 static void CreateCompressModePause(void)
605 {
606 	MSYS_DefineRegion( &gMapPauseRegion, 487, 456, 522, 467, MSYS_PRIORITY_HIGH,
607 							MSYS_NO_CURSOR, MSYS_NO_CALLBACK, CompressModeClickCallback );
608 	gMapPauseRegion.SetFastHelpText(pMapScreenBottomFastHelp[7]);
609 }
610 
611 
RemoveCompressModePause(void)612 static void RemoveCompressModePause(void)
613 {
614 	MSYS_RemoveRegion( &gMapPauseRegion );
615 }
616 
617 
LoadMessageSliderBar(void)618 static void LoadMessageSliderBar(void)
619 {
620 	// this function will load the message slider bar
621 	guiSliderBar = AddVideoObjectFromFile(INTERFACEDIR "/map_screen_bottom_arrows.sti");
622 }
623 
624 
DeleteMessageSliderBar(void)625 static void DeleteMessageSliderBar(void)
626 {
627 	// this function will delete message slider bar
628 	DeleteVideoObject(guiSliderBar);
629 }
630 
631 
MapScreenMessageBoxCallBack(MOUSE_REGION * pRegion,INT32 iReason)632 static void MapScreenMessageBoxCallBack(MOUSE_REGION* pRegion, INT32 iReason)
633 {
634 	if (iReason & MSYS_CALLBACK_REASON_WHEEL_UP)
635 	{
636 		MapScreenMsgScrollUp(3);
637 	}
638 	else if (iReason & MSYS_CALLBACK_REASON_WHEEL_DOWN)
639 	{
640 		MapScreenMsgScrollDown(3);
641 	}
642 }
643 
644 
645 static MOUSE_REGION MapMessageBoxRegion;
646 
647 
648 static void MapScreenMessageScrollBarCallBack(MOUSE_REGION* pRegion, INT32 iReason);
649 
650 
CreateMapScreenBottomMessageScrollBarRegion(void)651 static void CreateMapScreenBottomMessageScrollBarRegion(void)
652 {
653 	const INT8 prio = MSYS_PRIORITY_NORMAL;
654 	{
655 		const UINT16 x = MESSAGE_SCROLL_AREA_START_X;
656 		const UINT16 y = MESSAGE_SCROLL_AREA_START_Y;
657 		const UINT16 w = MESSAGE_SCROLL_AREA_WIDTH;
658 		const UINT16 h = MESSAGE_SCROLL_AREA_HEIGHT;
659 		MSYS_DefineRegion(&gMapMessageScrollBarRegion, x, y, x + w, y + h, prio, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, MapScreenMessageScrollBarCallBack);
660 	}
661 	{
662 		const UINT16 x = MESSAGE_BOX_X;
663 		const UINT16 y = MESSAGE_BOX_Y;
664 		const UINT16 w = MESSAGE_BOX_W;
665 		const UINT16 h = MESSAGE_BOX_H;
666 		MSYS_DefineRegion(&MapMessageBoxRegion, x, y, x + w, y + h, prio, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, MapScreenMessageBoxCallBack);
667 	}
668 }
669 
670 
DeleteMapScreenBottomMessageScrollRegion(void)671 static void DeleteMapScreenBottomMessageScrollRegion(void)
672 {
673 	MSYS_RemoveRegion( &gMapMessageScrollBarRegion );
674 	MSYS_RemoveRegion(&MapMessageBoxRegion);
675 }
676 
677 
MapScreenMessageScrollBarCallBack(MOUSE_REGION * pRegion,INT32 iReason)678 static void MapScreenMessageScrollBarCallBack(MOUSE_REGION* pRegion, INT32 iReason)
679 {
680 	UINT8	ubDesiredSliderOffset;
681 	UINT8 ubDesiredMessageIndex;
682 	UINT8 ubNumMessages;
683 
684 	if ( iReason & ( MSYS_CALLBACK_REASON_LBUTTON_DWN | MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) )
685 	{
686 		// how many messages are there?
687 		ubNumMessages = GetRangeOfMapScreenMessages();
688 
689 		// region is supposed to be disabled if there aren't enough messages to scroll.  Formulas assume this
690 		if ( ubNumMessages > MAX_MESSAGES_ON_MAP_BOTTOM )
691 		{
692 			const UINT8 ubMouseYOffset = pRegion->RelativeYPos;
693 
694 			// if clicking in the top 5 pixels of the slider bar
695 			if ( ubMouseYOffset < ( SLIDER_HEIGHT / 2 ) )
696 			{
697 				// scroll all the way to the top
698 				ubDesiredMessageIndex = 0;
699 			}
700 			// if clicking in the bottom 6 pixels of the slider bar
701 			else if ( ubMouseYOffset >= ( MESSAGE_SCROLL_AREA_HEIGHT - ( SLIDER_HEIGHT / 2 ) ) )
702 			{
703 				// scroll all the way to the bottom
704 				ubDesiredMessageIndex = ubNumMessages - MAX_MESSAGES_ON_MAP_BOTTOM;
705 			}
706 			else
707 			{
708 				// somewhere in between
709 				ubDesiredSliderOffset = ubMouseYOffset - ( SLIDER_HEIGHT / 2 );
710 
711 				Assert( ubDesiredSliderOffset <= SLIDER_BAR_RANGE );
712 
713 				// calculate what the index should be to place the slider at this offset (round fractions of .5+ up)
714 				ubDesiredMessageIndex = ( ( ubDesiredSliderOffset * ( ubNumMessages - MAX_MESSAGES_ON_MAP_BOTTOM ) ) + ( SLIDER_BAR_RANGE / 2 ) ) / SLIDER_BAR_RANGE;
715 			}
716 
717 			// if it's a change
718 			if ( ubDesiredMessageIndex != gubFirstMapscreenMessageIndex )
719 			{
720 				ChangeCurrentMapscreenMessageIndex( ubDesiredMessageIndex );
721 			}
722 		}
723 	}
724 	else if (iReason & MSYS_CALLBACK_REASON_WHEEL_UP)
725 	{
726 		MapScreenMsgScrollUp(3);
727 	}
728 	else if (iReason & MSYS_CALLBACK_REASON_WHEEL_DOWN)
729 	{
730 		MapScreenMsgScrollDown(3);
731 	}
732 }
733 
734 
DisplayScrollBarSlider(void)735 static void DisplayScrollBarSlider(void)
736 {
737 	// will display the scroll bar icon
738 	UINT8 ubNumMessages;
739 	UINT8 ubSliderOffset;
740 
741 	ubNumMessages = GetRangeOfMapScreenMessages();
742 
743 	// only show the slider if there are more messages than will fit on screen
744 	if ( ubNumMessages > MAX_MESSAGES_ON_MAP_BOTTOM )
745 	{
746 		// calculate where slider should be positioned
747 		ubSliderOffset = ( SLIDER_BAR_RANGE * gubFirstMapscreenMessageIndex ) / ( ubNumMessages - MAX_MESSAGES_ON_MAP_BOTTOM );
748 
749 		BltVideoObject(FRAME_BUFFER, guiSliderBar, 8, MESSAGE_SCROLL_AREA_START_X + 2, MESSAGE_SCROLL_AREA_START_Y + ubSliderOffset);
750 	}
751 }
752 
753 
754 static void EnableDisableTimeCompressButtons(void);
755 
756 
EnableDisableBottomButtonsAndRegions(void)757 static void EnableDisableBottomButtonsAndRegions(void)
758 {
759 	// this enables and disables the buttons MAP_EXIT_TO_LAPTOP, MAP_EXIT_TO_TACTICAL, and MAP_EXIT_TO_OPTIONS
760 	for (ExitToWhere iExitButtonIndex = MAP_EXIT_TO_LAPTOP; iExitButtonIndex <= MAP_EXIT_TO_OPTIONS; ++iExitButtonIndex)
761 	{
762 		EnableButton(guiMapBottomExitButtons[iExitButtonIndex], AllowedToExitFromMapscreenTo(iExitButtonIndex));
763 	}
764 
765 	// enable/disable time compress buttons and region masks
766 	EnableDisableTimeCompressButtons( );
767 	CreateDestroyMouseRegionMasksForTimeCompressionButtons( );
768 
769 
770 	// Enable/Disable map inventory panel buttons
771 
772 	// if in merc inventory panel
773 	if( fShowInventoryFlag )
774 	{
775 		// and an item is in the cursor
776 		EnableButton(giMapInvDoneButton, !fMapInventoryItem && !InKeyRingPopup() && !InItemStackPopup());
777 
778 		if( fShowDescriptionFlag )
779 		{
780 			ForceButtonUnDirty( giMapInvDoneButton );
781 		}
782 	}
783 }
784 
785 
EnableDisableTimeCompressButtons(void)786 static void EnableDisableTimeCompressButtons(void)
787 {
788 	if (!AllowedToTimeCompress())
789 	{
790 		DisableButton( guiMapBottomTimeButtons[ MAP_TIME_COMPRESS_MORE ] );
791 		DisableButton( guiMapBottomTimeButtons[ MAP_TIME_COMPRESS_LESS ] );
792 	}
793 	else
794 	{
795 		// disable LESS if time compression is at minimum or OFF
796 		EnableButton(guiMapBottomTimeButtons[MAP_TIME_COMPRESS_LESS], IsTimeCompressionOn() && giTimeCompressMode != TIME_COMPRESS_X0);
797 
798 		// disable MORE if we're not paused and time compression is at maximum
799 		// only disable MORE if we're not paused and time compression is at maximum
800 		EnableButton(guiMapBottomTimeButtons[MAP_TIME_COMPRESS_MORE], !IsTimeCompressionOn() || giTimeCompressMode != TIME_COMPRESS_60MINS);
801 	}
802 }
803 
804 
EnableDisAbleMapScreenOptionsButton(BOOLEAN fEnable)805 void EnableDisAbleMapScreenOptionsButton( BOOLEAN fEnable )
806 {
807 	EnableButton(guiMapBottomExitButtons[MAP_EXIT_TO_OPTIONS], fEnable);
808 }
809 
810 
AllowedToTimeCompress(void)811 BOOLEAN AllowedToTimeCompress( void )
812 {
813 	// if already leaving, disallow any other attempts to exit
814 	if ( fLeavingMapScreen )
815 	{
816 		return( FALSE );
817 	}
818 
819 	// if already going someplace
820 	if (gbExitingMapScreenToWhere != MAP_EXIT_TO_INVALID) return FALSE;
821 
822 	// if we're locked into paused time compression by some event that enforces that
823 	if ( PauseStateLocked() )
824 	{
825 		return( FALSE );
826 	}
827 
828 	// meanwhile coming up
829 	if ( gfMeanwhileTryingToStart )
830 	{
831 		return( FALSE );
832 	}
833 
834 	// someone has something to say
835 	if ( !DialogueQueueIsEmpty() )
836 	{
837 		return( FALSE );
838 	}
839 
840 	// moving / confirming movement
841 	if( ( bSelectedDestChar != -1 ) || fPlotForHelicopter || gfInConfirmMapMoveMode || fShowMapScreenMovementList )
842 	{
843 		return( FALSE );
844 	}
845 
846 	if (fShowAssignmentMenu || fShowTrainingMenu || fShowAttributeMenu || fShowSquadMenu || fShowContractMenu)
847 	{
848 		return( FALSE );
849 	}
850 
851 	if( fShowUpdateBox || fShowTownInfo || ( sSelectedMilitiaTown != 0 ) )
852 	{
853 		return( FALSE );
854 	}
855 
856 	// renewing contracts
857 	if ( gfContractRenewalSquenceOn )
858 	{
859 		return( FALSE );
860 	}
861 
862 	// disabled due to battle?
863 	if( ( fDisableMapInterfaceDueToBattle ) || ( fDisableDueToBattleRoster ) )
864 	{
865 		return( FALSE );
866 	}
867 
868 	// if holding an inventory item
869 	if ( fMapInventoryItem )
870 	{
871 		return( FALSE );
872 	}
873 
874 	// show the inventory pool?
875 	if( fShowMapInventoryPool )
876 	{
877 		// prevent time compress (items get stolen over time, etc.)
878 		return( FALSE );
879 	}
880 
881 	// no mercs have ever been hired
882 	if (!gfAtLeastOneMercWasHired) return FALSE;
883 
884 
885 	// no usable mercs on team!
886 	if ( !AnyUsableRealMercenariesOnTeam() )
887 	{
888 		return( FALSE );
889 	}
890 
891 		// must wait till bombs go off
892 	if ( ActiveTimedBombExists() )
893 	{
894 		return( FALSE );
895 	}
896 
897 	// hostile sector / in battle
898 	if( (gTacticalStatus.uiFlags & INCOMBAT ) || ( gTacticalStatus.fEnemyInSector ) )
899 	{
900 		return( FALSE );
901 	}
902 
903 	if( PlayerGroupIsInACreatureInfestedMine() )
904 	{
905 		return FALSE;
906 	}
907 
908 	// bloodcat ambush?
909 	if (gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE && HostileBloodcatsPresent())
910 	{
911 		return FALSE;
912 	}
913 
914 	return( TRUE );
915 }
916 
917 
DisplayCurrentBalanceTitleForMapBottom(void)918 static void DisplayCurrentBalanceTitleForMapBottom(void)
919 {
920 	ST::string sString;
921 	INT16 sFontX, sFontY;
922 
923 	SetFontDestBuffer(guiSAVEBUFFER);
924 	SetFontAttributes(COMPFONT, MAP_BOTTOM_FONT_COLOR);
925 
926 	sString = pMapScreenBottomText;
927 	FindFontCenterCoordinates(STD_SCREEN_X + 359, STD_SCREEN_Y + 387 - 14,  437 - 359, 10, sString, COMPFONT, &sFontX, &sFontY);
928 	MPrint(sFontX, sFontY, sString);
929 
930 	sString = zMarksMapScreenText[2];
931 	FindFontCenterCoordinates(STD_SCREEN_X + 359, STD_SCREEN_Y + 433 - 14,  437 - 359, 10, sString, COMPFONT, &sFontX, &sFontY);
932 	MPrint(sFontX, sFontY, sString);
933 
934 	SetFontDestBuffer(FRAME_BUFFER);
935 }
936 
937 
DisplayCurrentBalanceForMapBottom(void)938 static void DisplayCurrentBalanceForMapBottom(void)
939 {
940 	// show the current balance for the player on the map panel bottom
941 	INT16 sFontX, sFontY;
942 
943 	SetFontDestBuffer(FRAME_BUFFER);
944 	SetFontAttributes(COMPFONT, 183);
945 	ST::string sString = SPrintMoney(LaptopSaveInfo.iCurrentBalance);
946 	FindFontCenterCoordinates(STD_SCREEN_X + 359, STD_SCREEN_Y + 387 + 2,  437 - 359, 10, sString, COMPFONT, &sFontX, &sFontY);
947 	MPrint(sFontX, sFontY, sString);
948 }
949 
950 
951 static void CompressMaskClickCallback(MOUSE_REGION* pRegion, INT32 iReason);
952 
953 
CreateDestroyMouseRegionMasksForTimeCompressionButtons()954 void CreateDestroyMouseRegionMasksForTimeCompressionButtons()
955 {
956 	static bool created = false;
957 
958 	// Disable buttons, if not allowed to compress time.
959 	bool const disabled = fInMapMode && !AllowedToTimeCompress();
960 	if (disabled && !created)
961 	{
962 		// Mask over compress more, compress less and paus game buttons.
963 		MSYS_DefineRegion(&gTimeCompressionMask[0], STD_SCREEN_X + 528, STD_SCREEN_Y + 457, 528 + 13, 457 + 14, MSYS_PRIORITY_HIGHEST - 1, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, CompressMaskClickCallback);
964 		MSYS_DefineRegion(&gTimeCompressionMask[1], STD_SCREEN_X + 466, STD_SCREEN_Y + 457, 466 + 13, 457 + 14, MSYS_PRIORITY_HIGHEST - 1, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, CompressMaskClickCallback);
965 		MSYS_DefineRegion(&gTimeCompressionMask[2], STD_SCREEN_X + 487, STD_SCREEN_Y + 457, 487 + 35, 457 + 11, MSYS_PRIORITY_HIGHEST - 1, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, CompressMaskClickCallback);
966 		created = true;
967 	}
968 	else if (!disabled && created)
969 	{
970 		FOR_EACH(MOUSE_REGION, i, gTimeCompressionMask) MSYS_RemoveRegion(&*i);
971 		created = false;
972 	}
973 }
974 
975 
CompressMaskClickCallback(MOUSE_REGION * pRegion,INT32 iReason)976 static void CompressMaskClickCallback(MOUSE_REGION* pRegion, INT32 iReason)
977 {
978 	if( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP )
979 	{
980 		TellPlayerWhyHeCantCompressTime( );
981 	}
982 }
983 
984 
DisplayProjectedDailyMineIncome(void)985 static void DisplayProjectedDailyMineIncome(void)
986 {
987 	INT32 iRate = 0;
988 	static INT32 iOldRate = -1;
989 	INT16 sFontX, sFontY;
990 
991 	// grab the rate from the financial system
992 	iRate = GetProjectedTotalDailyIncome( );
993 
994 	if( iRate != iOldRate )
995 	{
996 		iOldRate = iRate;
997 		fMapScreenBottomDirty = TRUE;
998 
999 		// if screen was not dirtied, leave
1000 		if (!fMapBottomDirtied) return;
1001 	}
1002 
1003 	SetFontDestBuffer(FRAME_BUFFER);
1004 	SetFontAttributes(COMPFONT, 183);
1005 	ST::string sString = SPrintMoney(iRate);
1006 	FindFontCenterCoordinates(STD_SCREEN_X + 359, STD_SCREEN_Y + 433 + 2,  437 - 359, 10, sString, COMPFONT, &sFontX, &sFontY);
1007 	MPrint(sFontX, sFontY, sString);
1008 }
1009 
1010 
CommonTimeCompressionChecks(void)1011 BOOLEAN CommonTimeCompressionChecks( void )
1012 {
1013 	if (bSelectedDestChar != -1 || fPlotForHelicopter)
1014 	{
1015 		// abort plotting movement
1016 		AbortMovementPlottingMode( );
1017 		return( TRUE );
1018 	}
1019 
1020 	return( FALSE );
1021 }
1022 
1023 
AnyUsableRealMercenariesOnTeam()1024 bool AnyUsableRealMercenariesOnTeam()
1025 {
1026 	/* Check whether there is a merc on team, who is not a vehicle, robot, POW or
1027 		* EPC. */
1028 	CFOR_EACH_IN_TEAM(i, OUR_TEAM)
1029 	{
1030 		SOLDIERTYPE const& s = *i;
1031 		if (s.bLife <= 0)                            continue;
1032 		if (IsMechanical(s))                         continue;
1033 		if (s.bAssignment == ASSIGNMENT_POW)         continue;
1034 		if (s.bAssignment == ASSIGNMENT_DEAD)        continue;
1035 		if (s.ubWhatKindOfMercAmI == MERC_TYPE__EPC) continue;
1036 		return true;
1037 	}
1038 	return false;
1039 }
1040 
1041 
1042 
RequestTriggerExitFromMapscreen(ExitToWhere const bExitToWhere)1043 void RequestTriggerExitFromMapscreen(ExitToWhere const bExitToWhere)
1044 {
1045 	Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_SAVE ) );
1046 
1047 	// if allowed to do so
1048 	if ( AllowedToExitFromMapscreenTo( bExitToWhere ) )
1049 	{
1050 		//if the screen to exit to is the SAVE screen
1051 		if( bExitToWhere == MAP_EXIT_TO_SAVE )
1052 		{
1053 			//if the game CAN NOT be saved
1054 			if( !CanGameBeSaved() )
1055 			{
1056 				//Display a message saying the player cant save now
1057 				DoMapMessageBox( MSG_BOX_BASIC_STYLE, zNewTacticalMessages[ TCTL_MSG__IRON_MAN_CANT_SAVE_NOW ], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
1058 				return;
1059 			}
1060 			else if ( gGameOptions.ubGameSaveMode == DIF_DEAD_IS_DEAD )
1061 			{
1062 				//Display DiD message saying the player cant save now
1063 				DoMapMessageBox( MSG_BOX_BASIC_STYLE, zNewTacticalMessages[ TCTL_MSG__DEAD_IS_DEAD_CANT_SAVE_NOW ], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
1064 				return;
1065 			}
1066 		}
1067 
1068 		// permit it, and get the ball rolling
1069 		gbExitingMapScreenToWhere = bExitToWhere;
1070 
1071 		// delay until mapscreen has had a chance to render at least one full frame
1072 		gfOneFramePauseOnExit = TRUE;
1073 	}
1074 }
1075 
1076 
AllowedToExitFromMapscreenTo(ExitToWhere const bExitToWhere)1077 BOOLEAN AllowedToExitFromMapscreenTo(ExitToWhere const bExitToWhere)
1078 {
1079 	Assert( ( bExitToWhere >= MAP_EXIT_TO_LAPTOP ) && ( bExitToWhere <= MAP_EXIT_TO_SAVE ) );
1080 
1081 	// if already leaving, disallow any other attempts to exit
1082 	if ( fLeavingMapScreen )
1083 	{
1084 		return( FALSE );
1085 	}
1086 
1087 	// if already going someplace else
1088 	if (gbExitingMapScreenToWhere != MAP_EXIT_TO_INVALID &&
1089 			gbExitingMapScreenToWhere != bExitToWhere)
1090 	{
1091 		return( FALSE );
1092 	}
1093 
1094 	// someone has something to say
1095 	if ( !DialogueQueueIsEmpty() )
1096 	{
1097 		return( FALSE );
1098 	}
1099 
1100 	// meanwhile coming up
1101 	if ( gfMeanwhileTryingToStart )
1102 	{
1103 		return( FALSE );
1104 	}
1105 
1106 	// if we're locked into paused time compression by some event that enforces that
1107 	if ( PauseStateLocked() )
1108 	{
1109 		return( FALSE );
1110 	}
1111 
1112 	// if holding an inventory item
1113 	if (fMapInventoryItem) return FALSE;
1114 
1115 	if( fShowUpdateBox || fShowTownInfo || ( sSelectedMilitiaTown != 0 ) )
1116 	{
1117 		return( FALSE );
1118 	}
1119 
1120 	// renewing contracts
1121 	if( gfContractRenewalSquenceOn )
1122 	{
1123 		return( FALSE );
1124 	}
1125 
1126 	// battle about to occur?
1127 	if( ( fDisableDueToBattleRoster ) || ( fDisableMapInterfaceDueToBattle ) )
1128 	{
1129 		return( FALSE );
1130 	}
1131 
1132 	// the following tests apply to going tactical screen only
1133 	if ( bExitToWhere == MAP_EXIT_TO_TACTICAL )
1134 	{
1135 		// if in battle or bloodcat ambush, the ONLY sector we can go tactical in is the one that's loaded
1136 		BOOLEAN fBattleGoingOn = gTacticalStatus.uiFlags & INCOMBAT || gTacticalStatus.fEnemyInSector || (gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE && HostileBloodcatsPresent());
1137 		BOOLEAN fCurrentSectorSelected = sSelMapX == gWorldSectorX && sSelMapY == gWorldSectorY && ((UINT8)iCurrentMapSectorZ) == gbWorldSectorZ;
1138 		if (fBattleGoingOn && !fCurrentSectorSelected)
1139 		{
1140 			return( FALSE );
1141 		}
1142 
1143 		// must have some mercs there
1144 		if( !CanGoToTacticalInSector( sSelMapX, sSelMapY, ( UINT8 )iCurrentMapSectorZ ) )
1145 		{
1146 			return( FALSE );
1147 		}
1148 	}
1149 
1150 	//if we are map screen sector inventory
1151 	if( fShowMapInventoryPool )
1152 	{
1153 		//dont allow it
1154 		return( FALSE );
1155 	}
1156 
1157 	// OK to go there, passed all the checks
1158 	return( TRUE );
1159 }
1160 
1161 
HandleExitsFromMapScreen(void)1162 void HandleExitsFromMapScreen( void )
1163 {
1164 	// if going somewhere
1165 	if (gbExitingMapScreenToWhere == MAP_EXIT_TO_INVALID) return;
1166 
1167 	// delay all exits by one frame...
1168 	if (gfOneFramePauseOnExit)
1169 	{
1170 		gfOneFramePauseOnExit = FALSE;
1171 		return;
1172 	}
1173 
1174 	// make sure it's still legal to do this!
1175 	if ( AllowedToExitFromMapscreenTo( gbExitingMapScreenToWhere ) )
1176 	{
1177 		// see where we're trying to go
1178 		switch ( gbExitingMapScreenToWhere )
1179 		{
1180 			case MAP_EXIT_TO_LAPTOP:
1181 				fLapTop = TRUE;
1182 				SetPendingNewScreen(LAPTOP_SCREEN);
1183 
1184 				BltVideoSurface(guiEXTRABUFFER, FRAME_BUFFER, 0, 0, NULL);
1185 				gfStartMapScreenToLaptopTransition = TRUE;
1186 				break;
1187 
1188 			case MAP_EXIT_TO_TACTICAL:
1189 				SetCurrentWorldSector( sSelMapX, sSelMapY, ( UINT8 )iCurrentMapSectorZ );
1190 				break;
1191 
1192 			case MAP_EXIT_TO_OPTIONS:
1193 				guiPreviousOptionScreen = guiCurrentScreen;
1194 				SetPendingNewScreen( OPTIONS_SCREEN );
1195 				break;
1196 
1197 			case MAP_EXIT_TO_SAVE:
1198 			case MAP_EXIT_TO_LOAD:
1199 				gfCameDirectlyFromGame = TRUE;
1200 				guiPreviousOptionScreen = guiCurrentScreen;
1201 				SetPendingNewScreen( SAVE_LOAD_SCREEN );
1202 				break;
1203 
1204 			default:
1205 				// invalid exit type
1206 				Assert( FALSE );
1207 		}
1208 
1209 		// time compression during mapscreen exit doesn't seem to cause any problems, but turn it off as early as we can
1210 		StopTimeCompression();
1211 
1212 		// now leaving mapscreen
1213 		fLeavingMapScreen = TRUE;
1214 	}
1215 
1216 	// cancel exit, either we're on our way, or we're not allowed to go
1217 	gbExitingMapScreenToWhere = MAP_EXIT_TO_INVALID;
1218 }
1219 
1220 
1221 
MapScreenMsgScrollDown(UINT8 ubLinesDown)1222 void MapScreenMsgScrollDown( UINT8 ubLinesDown )
1223 {
1224 	UINT8 ubNumMessages;
1225 
1226 	ubNumMessages = GetRangeOfMapScreenMessages();
1227 
1228 	// check if we can go that far, only go as far as we can
1229 	if ( ( gubFirstMapscreenMessageIndex + MAX_MESSAGES_ON_MAP_BOTTOM + ubLinesDown ) > ubNumMessages )
1230 	{
1231 		ubLinesDown = ubNumMessages - gubFirstMapscreenMessageIndex - MIN( ubNumMessages, MAX_MESSAGES_ON_MAP_BOTTOM );
1232 	}
1233 
1234 	if ( ubLinesDown > 0 )
1235 	{
1236 		ChangeCurrentMapscreenMessageIndex( ( UINT8 ) ( gubFirstMapscreenMessageIndex + ubLinesDown ) );
1237 	}
1238 }
1239 
1240 
MapScreenMsgScrollUp(UINT8 ubLinesUp)1241 void MapScreenMsgScrollUp( UINT8 ubLinesUp )
1242 {
1243 	// check if we can go that far, only go as far as we can
1244 	if ( gubFirstMapscreenMessageIndex < ubLinesUp )
1245 	{
1246 		ubLinesUp = gubFirstMapscreenMessageIndex;
1247 	}
1248 
1249 	if ( ubLinesUp > 0 )
1250 	{
1251 		ChangeCurrentMapscreenMessageIndex( ( UINT8 ) ( gubFirstMapscreenMessageIndex - ubLinesUp ) );
1252 	}
1253 }
1254 
1255 
1256 
MoveToEndOfMapScreenMessageList(void)1257 void MoveToEndOfMapScreenMessageList( void )
1258 {
1259 	UINT8 ubDesiredMessageIndex;
1260 	UINT8 ubNumMessages;
1261 
1262 	ubNumMessages = GetRangeOfMapScreenMessages();
1263 
1264 	ubDesiredMessageIndex = ubNumMessages - MIN( ubNumMessages, MAX_MESSAGES_ON_MAP_BOTTOM );
1265 	ChangeCurrentMapscreenMessageIndex( ubDesiredMessageIndex );
1266 }
1267 
1268 
1269 
ChangeCurrentMapscreenMessageIndex(UINT8 ubNewMessageIndex)1270 void ChangeCurrentMapscreenMessageIndex( UINT8 ubNewMessageIndex )
1271 {
1272 	Assert( ubNewMessageIndex + MAX_MESSAGES_ON_MAP_BOTTOM <= MAX( MAX_MESSAGES_ON_MAP_BOTTOM, GetRangeOfMapScreenMessages() ) );
1273 
1274 	gubFirstMapscreenMessageIndex = ubNewMessageIndex;
1275 	gubCurrentMapMessageString = ( gubStartOfMapScreenMessageList + gubFirstMapscreenMessageIndex ) % 256;
1276 
1277 	// refresh screen
1278 	fMapScreenBottomDirty = TRUE;
1279 }
1280