1 #include "Directories.h"
2 #include "Font.h"
3 #include "GameLoop.h"
4 #include "HImage.h"
5 #include "Local.h"
6 #include "Timer_Control.h"
7 #include "Types.h"
8 #include "SaveLoadScreen.h"
9 #include "Video.h"
10 #include "Font_Control.h"
11 #include "Game_Clock.h"
12 #include "Render_Dirty.h"
13 #include "Text_Input.h"
14 #include "SaveLoadGame.h"
15 #include "WordWrap.h"
16 #include "StrategicMap.h"
17 #include "Finances.h"
18 #include "Cursors.h"
19 #include "VObject.h"
20 #include "Merc_Hiring.h"
21 #include "LaptopSave.h"
22 #include "Options_Screen.h"
23 #include "GameVersion.h"
24 #include "SysUtil.h"
25 #include "Overhead.h"
26 #include "GameScreen.h"
27 #include "GameSettings.h"
28 #include "Fade_Screen.h"
29 #include "English.h"
30 #include "Game_Init.h"
31 #include "Sys_Globals.h"
32 #include "Text.h"
33 #include "Message.h"
34 #include "Map_Screen_Interface.h"
35 #include "Multi_Language_Graphic_Utils.h"
36 #include "Campaign_Types.h"
37 #include "Button_System.h"
38 #include "Debug.h"
39 #include "JAScreens.h"
40 #include "VSurface.h"
41 #include "FileMan.h"
42 #include "Campaign_Init.h"
43 #include "UILayout.h"
44 #include "Handle_UI.h"
45 #include "Interface_Dialogue.h"
46 #include "Meanwhile.h"
47 #include "PreBattle_Interface.h"
48 #include "ContentManager.h"
49 #include "GameInstance.h"
50 
51 #include <string_theory/format>
52 #include <string_theory/string>
53 
54 #include <exception>
55 
56 
57 #define SAVE_LOAD_TITLE_FONT				FONT14ARIAL
58 #define SAVE_LOAD_TITLE_COLOR				FONT_MCOLOR_WHITE
59 
60 #define SAVE_LOAD_NORMAL_FONT				FONT12ARIAL
61 #define SAVE_LOAD_NORMAL_COLOR				2//FONT_MCOLOR_DKWHITE//2//FONT_MCOLOR_WHITE
62 #define SAVE_LOAD_NORMAL_SHADOW_COLOR			118//121//118//125
63 /*#define SAVE_LOAD_NORMAL_FONT			FONT12ARIAL
64 #define SAVE_LOAD_NORMAL_COLOR				FONT_MCOLOR_DKWHITE//2//FONT_MCOLOR_WHITE
65 #define SAVE_LOAD_NORMAL_SHADOW_COLOR			2//125*/
66 
67 #define SAVE_LOAD_QUICKSAVE_COLOR			2//FONT_MCOLOR_DKGRAY//FONT_MCOLOR_WHITE
68 #define SAVE_LOAD_QUICKSAVE_SHADOW_COLOR		189//248//2
69 
70 #define SAVE_LOAD_EMPTYSLOT_COLOR			2//125//FONT_MCOLOR_WHITE
71 #define SAVE_LOAD_EMPTYSLOT_SHADOW_COLOR		121//118
72 
73 #define SAVE_LOAD_HIGHLIGHTED_COLOR			FONT_MCOLOR_WHITE
74 #define SAVE_LOAD_HIGHLIGHTED_SHADOW_COLOR		2
75 
76 #define SAVE_LOAD_SELECTED_COLOR			2//145//FONT_MCOLOR_WHITE
77 #define SAVE_LOAD_SELECTED_SHADOW_COLOR		130//2
78 
79 
80 
81 #define SAVE_LOAD_NUMBER_FONT				FONT12ARIAL
82 #define SAVE_LOAD_NUMBER_COLOR				FONT_MCOLOR_WHITE
83 
84 #define SLG_SELECTED_COLOR				FONT_MCOLOR_WHITE
85 #define SLG_UNSELECTED_COLOR				FONT_MCOLOR_DKWHITE
86 
87 #define SLG_SAVELOCATION_WIDTH				605
88 #define SLG_SAVELOCATION_HEIGHT			30//46
89 #define SLG_FIRST_SAVED_SPOT_X				(STD_SCREEN_X + 17)
90 #define SLG_FIRST_SAVED_SPOT_Y				(STD_SCREEN_Y + 49)
91 #define SLG_GAP_BETWEEN_LOCATIONS			35//47
92 
93 
94 
95 #define SLG_DATE_OFFSET_X				13
96 #define SLG_DATE_OFFSET_Y				11
97 
98 #define SLG_SECTOR_OFFSET_X				95//105//114
99 #define SLG_SECTOR_WIDTH				98
100 
101 #define SLG_NUM_MERCS_OFFSET_X				196//190//SLG_DATE_OFFSET_X
102 
103 #define SLG_BALANCE_OFFSET_X				260//SLG_SECTOR_OFFSET_X
104 
105 #define SLG_SAVE_GAME_DESC_X				318//320//204
106 #define SLG_SAVE_GAME_DESC_Y				SLG_DATE_OFFSET_Y//SLG_DATE_OFFSET_Y + 7
107 
108 #define SLG_TITLE_POS_X				(STD_SCREEN_X)
109 #define SLG_TITLE_POS_Y				(STD_SCREEN_Y)
110 
111 #define SLG_SAVE_CANCEL_POS_X				(226 + STD_SCREEN_X)
112 #define SLG_LOAD_CANCEL_POS_X				(329 + STD_SCREEN_X)
113 #define SLG_SAVE_LOAD_BTN_POS_X				(123 + STD_SCREEN_X)
114 #define SLG_BTN_POS_Y					(438 + STD_SCREEN_Y)
115 
116 #define SLG_SELECTED_SLOT_GRAPHICS_NUMBER		3
117 #define SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER		2
118 
119 #define SLG_DOUBLE_CLICK_DELAY				500
120 
121 //defines for saved game version status
122 enum
123 {
124 	SLS_HEADER_OK,
125 	SLS_SAVED_GAME_VERSION_OUT_OF_DATE,
126 	SLS_GAME_VERSION_OUT_OF_DATE,
127 	SLS_BOTH_SAVE_GAME_AND_GAME_VERSION_OUT_OF_DATE,
128 };
129 
130 // enums for the selected Loadscreen Tab (used with giLoadscreenTab[])
131 enum
132 {
133 	SLS_TAB_NORMAL,
134 	SLS_TAB_DEAD_IS_DEAD,
135 	SLS_TAB_LENGTH,
136 };
137 
138 
139 static BOOLEAN gfSaveLoadScreenEntry = TRUE;
140 static BOOLEAN gfSaveLoadScreenExit	= FALSE;
141 BOOLEAN        gfRedrawSaveLoadScreen = TRUE;
142 
143 static ScreenID guiSaveLoadExitScreen = SAVE_LOAD_SCREEN;
144 
145 
146 //Contains the array of valid save game locations
147 static BOOLEAN gbSaveGameArray[NUM_SAVE_GAMES];
148 static BOOLEAN gbActiveSaveGameTabs[NUM_SAVE_GAMES_TABS];
149 
150 static BOOLEAN gfDoingQuickLoad = FALSE;
151 
152 //This flag is used to diferentiate between loading a game and saveing a game.
153 // gfSaveGame=TRUE		For saving a game
154 // gfSaveGame=FALSE		For loading a game
155 BOOLEAN		gfSaveGame=TRUE;
156 static INT8 gfActiveTab=0;
157 
158 static BOOLEAN gfSaveLoadScreenButtonsCreated = FALSE;
159 
160 static INT8 gbSelectedSaveLocation = -1;
161 static INT8 gbHighLightedLocation  = -1;
162 
163 static SGPVObject* guiSlgBackGroundImage;
164 static SGPVObject* guiBackGroundAddOns;
165 
166 
167 // The string that will contain the game desc text
168 static ST::string gzGameDescTextField;
169 
170 
171 static BOOLEAN gfUserInTextInputMode = FALSE;
172 static UINT8   gubSaveGameNextPass   = 0;
173 
174 static BOOLEAN gfStartedFadingOut = FALSE;
175 
176 
177 BOOLEAN		gfCameDirectlyFromGame = FALSE;
178 
179 
180 BOOLEAN		gfLoadedGame = FALSE;	//Used to know when a game has been loaded, the flag in gtacticalstatus might have been reset already
181 
182 BOOLEAN		gfLoadGameUponEntry = FALSE;
183 
184 static BOOLEAN gfHadToMakeBasementLevels = FALSE;
185 
186 
187 //
188 //Buttons
189 //
190 static BUTTON_PICS* guiSlgButtonImage;
191 
192 
193 // Cancel Button
194 static GUIButtonRef guiSlgCancelBtn;
195 
196 // Save game Button
197 static BUTTON_PICS* guiSaveLoadImage;
198 static GUIButtonRef guiSlgSaveLoadBtn;
199 
200 // buttons for Tabs
201 static BUTTON_PICS* giLoadscreenTabButtonImage[2];
202 static GUIButtonRef giLoadscreenTab[2];
203 
204 //Mouse regions for the currently selected save game
205 static MOUSE_REGION gSelectedSaveRegion[NUM_SAVE_GAMES];
206 
207 static MOUSE_REGION gSLSEntireScreenRegion;
208 
209 
210 static void EnterSaveLoadScreen();
211 static void ExitSaveLoadScreen(void);
212 static void GetSaveLoadScreenUserInput(void);
213 static void RenderSaveLoadScreen(void);
214 static void SaveLoadGameNumber();
215 static BOOLEAN IsDeadIsDeadTab(INT8 tabNo);
216 static void LoadTab(INT8 tabNo);
217 
218 
SaveLoadScreenHandle()219 ScreenID SaveLoadScreenHandle()
220 {
221 	if( gfSaveLoadScreenEntry )
222 	{
223 		EnterSaveLoadScreen();
224 		gfSaveLoadScreenEntry = FALSE;
225 		gfSaveLoadScreenExit = FALSE;
226 
227 		PauseGame();
228 
229 		//save the new rect
230 		BlitBufferToBuffer(FRAME_BUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, 439);
231 	}
232 
233 	RestoreBackgroundRects();
234 
235 	//to guarentee that we do not accept input when we are fading out
236 	if( !gfStartedFadingOut )
237 	{
238 		GetSaveLoadScreenUserInput();
239 	}
240 	else
241 		gfRedrawSaveLoadScreen = FALSE;
242 
243 	//if we have exited the save load screen, exit
244 	if( !gfSaveLoadScreenButtonsCreated )
245 		return( guiSaveLoadExitScreen );
246 
247 	RenderAllTextFields();
248 
249 	if( gfRedrawSaveLoadScreen )
250 	{
251 		RenderSaveLoadScreen();
252 		MarkButtonsDirty( );
253 		RenderButtons();
254 
255 		gfRedrawSaveLoadScreen = FALSE;
256 	}
257 
258 	if( gubSaveGameNextPass != 0 )
259 	{
260 		gubSaveGameNextPass++;
261 
262 		if( gubSaveGameNextPass == 5 )
263 		{
264 			gubSaveGameNextPass = 0;
265 			SaveLoadGameNumber();
266 		}
267 	}
268 
269 
270 	//If we are not exiting the screen, render the buttons
271 	if( !gfSaveLoadScreenExit && guiSaveLoadExitScreen == SAVE_LOAD_SCREEN )
272 	{
273 		// render buttons marked dirty
274 		RenderButtons( );
275 	}
276 
277 
278 	// ATE: Put here to save RECTS before any fast help being drawn...
279 	SaveBackgroundRects( );
280 	RenderButtonsFastHelp();
281 
282 	ExecuteBaseDirtyRectQueue( );
283 	EndFrameBufferRender( );
284 
285 	if ( HandleFadeOutCallback( ) )
286 	{
287 		return( guiSaveLoadExitScreen );
288 	}
289 
290 	if ( HandleBeginFadeOut( SAVE_LOAD_SCREEN ) )
291 	{
292 		return( SAVE_LOAD_SCREEN );
293 	}
294 
295 
296 	if( gfSaveLoadScreenExit )
297 	{
298 		ExitSaveLoadScreen();
299 	}
300 
301 	if ( HandleFadeInCallback( ) )
302 	{
303 		// Re-render the scene!
304 		RenderSaveLoadScreen();
305 	}
306 
307 	if ( HandleBeginFadeIn( SAVE_LOAD_SCREEN ) )
308 	{
309 	}
310 
311 	return( guiSaveLoadExitScreen );
312 }
313 
314 
315 static void DestroySaveLoadTextInputBoxes(void);
316 
317 
SetSaveLoadExitScreen(ScreenID const uiScreen)318 static void SetSaveLoadExitScreen(ScreenID const uiScreen)
319 {
320 	if( uiScreen == GAME_SCREEN )
321 	{
322 		EnterTacticalScreen( );
323 	}
324 
325 	gfSaveLoadScreenExit	= TRUE;
326 
327 	guiSaveLoadExitScreen = uiScreen;
328 
329 	SetPendingNewScreen( uiScreen );
330 
331 	if( gfDoingQuickLoad )
332 	{
333 		fFirstTimeInGameScreen = TRUE;
334 		SetPendingNewScreen( uiScreen );
335 	}
336 
337 	ExitSaveLoadScreen();
338 
339 	DestroySaveLoadTextInputBoxes();
340 }
341 
342 
LeaveSaveLoadScreen()343 static void LeaveSaveLoadScreen()
344 {
345 	if (gfCameDirectlyFromGame)
346 	{
347 		SetSaveLoadExitScreen(guiPreviousOptionScreen);
348 	} else {
349 		switch (guiPreviousOptionScreen)
350 		{
351 			case MAINMENU_SCREEN: SetSaveLoadExitScreen(MAINMENU_SCREEN); break;
352 			case GAME_INIT_OPTIONS_SCREEN: SetSaveLoadExitScreen(GAME_INIT_OPTIONS_SCREEN); break;
353 			case INTRO_SCREEN: SetSaveLoadExitScreen(INTRO_SCREEN); break;
354 			default: SetSaveLoadExitScreen(OPTIONS_SCREEN);
355 		}
356 	}
357 }
358 
359 
MakeButton(BUTTON_PICS * img,const ST::string & text,INT16 x,GUI_CALLBACK click)360 static GUIButtonRef MakeButton(BUTTON_PICS* img, const ST::string& text, INT16 x, GUI_CALLBACK click)
361 {
362 	return CreateIconAndTextButton(img, text, OPT_BUTTON_FONT, OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, x, SLG_BTN_POS_Y, MSYS_PRIORITY_HIGH, click);
363 }
364 
MakeTab(UINT idx,INT16 x,GUI_CALLBACK click,const ST::string & text)365 static void MakeTab(UINT idx, INT16 x, GUI_CALLBACK click, const ST::string& text)
366 {
367 	BUTTON_PICS* const img = LoadButtonImage( "sti/interface/loadscreentab.sti", idx, idx+2);
368 	giLoadscreenTabButtonImage[idx] = img;
369 	GUIButtonRef const btn = QuickCreateButtonNoMove(img, STD_SCREEN_X + x, STD_SCREEN_Y + 8, MSYS_PRIORITY_HIGHEST - 1, click);
370 	giLoadscreenTab[idx] = btn;
371 	btn->SpecifyGeneralTextAttributes(text, OPT_BUTTON_FONT, OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW);
372 }
373 
374 static void BtnSlgCancelCallback(GUI_BUTTON* btn, INT32 reason);
375 static void BtnSlgSaveLoadCallback(GUI_BUTTON* btn, INT32 reason);
376 static void BtnSlgNormalGameTabCallback(GUI_BUTTON* btn, INT32 reason);
377 static void BtnSlgDeadIsDeadTabCallback(GUI_BUTTON* btn, INT32 reason);
378 static void ClearSelectedSaveSlot(void);
379 static void InitSaveGameArray(void);
380 static BOOLEAN LoadSavedGameHeader(INT8 bEntry, SAVED_GAME_HEADER* pSaveGameHeader);
381 static void SelectedSLSEntireRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason);
382 static void SelectedSaveRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason);
383 static void SelectedSaveRegionMovementCallBack(MOUSE_REGION* pRegion, INT32 reason);
384 static void StartFadeOutForSaveLoadScreen(void);
385 
CreateLoadscreenTab()386 static void CreateLoadscreenTab()
387 {
388 	MakeTab(0,        20, BtnSlgNormalGameTabCallback, gs_dead_is_dead_mode_tab_name[0]);
389 	MakeTab(1, 90, BtnSlgDeadIsDeadTabCallback,    gs_dead_is_dead_mode_tab_name[1]);
390 	// Render the Normal Tab as selected after create
391 	giLoadscreenTab[SLS_TAB_NORMAL]->uiFlags |= BUTTON_CLICKED_ON;
392 }
393 
RemoveLoadscreenTab()394 static void RemoveLoadscreenTab()
395 {
396 	for (int i = 0; i < SLS_TAB_LENGTH; i++)
397 	{
398 		RemoveButton(giLoadscreenTab[i]);
399 		UnloadButtonImage(giLoadscreenTabButtonImage[i]);
400 	}
401 }
402 
updateTabActiveState()403 static void updateTabActiveState()
404 {
405 	for (INT8 i = 0; i < NUM_SAVE_GAMES_TABS; i++)
406 	{
407 		gfActiveTab = i;
408 		InitSaveGameArray(); // Load the savegames for the current tab
409 		// Check if the lastSavedGameSlot exists
410 
411 		bool tabHasSaves = FALSE;
412 		for (INT8 j = 0; j != NUM_SAVE_GAMES; ++j)
413 		{
414 			if (gbSaveGameArray[j])
415 			{
416 				tabHasSaves = TRUE;
417 				break;
418 			}
419 		}
420 		gbActiveSaveGameTabs[i] = tabHasSaves;
421 		if (!tabHasSaves)
422 		{
423 			DisableButton(giLoadscreenTab[i]);
424 		}
425 	}
426 }
427 // This function determines which tab to activate in the load Screen.
428 // Depending on:
429 // In which tab is the last save
430 // Are there any saves in the tab
431 // It also deactivates tabs with no saves
selectActiveTab()432 static void selectActiveTab()
433 {
434 	INT8 const lastSaveInTab = (INT8) (gGameSettings.bLastSavedGameSlot / NUM_SAVE_GAMES);
435 
436 	updateTabActiveState();
437 
438 	gfActiveTab = 0;
439 	InitSaveGameArray();
440 	// If the lastSavedGameSlot exists, switch to the appropriate tab, otherwise select the first available save
441 	if (gGameSettings.bLastSavedGameSlot != -1 && gbActiveSaveGameTabs[lastSaveInTab])
442 	{
443 		GUI_BUTTON* const b = ButtonList[giLoadscreenTab[lastSaveInTab].ID()];
444 		b->ClickCallback(b,MSYS_CALLBACK_REASON_LBUTTON_UP);
445 	}
446 	else
447 	{
448 		// This code doesn't make sense until there are more than two tabs
449 		for (int i = 1; i < NUM_SAVE_GAMES_TABS; i++)
450 		{
451 			if (gbActiveSaveGameTabs[i])
452 			{
453 				GUI_BUTTON* const b = ButtonList[giLoadscreenTab[i].ID()];
454 				b->ClickCallback(b,MSYS_CALLBACK_REASON_LBUTTON_UP);
455 				break;
456 			}
457 		}
458 	}
459 }
460 
EnterSaveLoadScreen()461 static void EnterSaveLoadScreen()
462 {
463 	gfActiveTab= 0;
464 	// Display Dead Is Dead games for saving by default if we are to choose the Dead is Dead Slot
465 	if (guiPreviousOptionScreen == GAME_INIT_OPTIONS_SCREEN)
466 	{
467 		gfActiveTab = DEAD_IS_DEAD_TAB_NO;
468 		gfSaveGame = TRUE;
469 	}
470 
471 	// This is a hack to get sector names, but if the underground sector is NOT loaded
472 	if (!gpUndergroundSectorInfoHead)
473 	{
474 		BuildUndergroundSectorInfoList();
475 		gfHadToMakeBasementLevels = TRUE;
476 	}
477 	else
478 	{
479 		gfHadToMakeBasementLevels = FALSE;
480 	}
481 
482 	guiSaveLoadExitScreen = SAVE_LOAD_SCREEN;
483 	InitSaveGameArray();
484 	EmptyBackgroundRects();
485 
486 	// If the user has asked to load the selected save
487 	if (gfLoadGameUponEntry)
488 	{
489 		// Make sure the save is valid
490 		INT8 const last_slot = gfActiveTab ? gGameSettings.bLastSavedGameSlot-NUM_SAVE_GAMES : gGameSettings.bLastSavedGameSlot;
491 		if (last_slot != -1 && gbSaveGameArray[last_slot])
492 		{
493 			gbSelectedSaveLocation = last_slot;
494 			StartFadeOutForSaveLoadScreen();
495 		}
496 		else
497 		{ // else the save is not valid, so do not load it
498 			gfLoadGameUponEntry = FALSE;
499 		}
500 	}
501 
502 	// Load main background and add ons graphic
503 	guiSlgBackGroundImage = AddVideoObjectFromFile(INTERFACEDIR "/loadscreen.sti");
504 	guiBackGroundAddOns   = AddVideoObjectFromFile(GetMLGFilename(MLG_LOADSAVEHEADER));
505 
506 	guiSlgButtonImage = LoadButtonImage(INTERFACEDIR "/loadscreenaddons.sti", 6, 9);
507 	guiSlgCancelBtn   = MakeButton(guiSlgButtonImage, zSaveLoadText[SLG_CANCEL], SLG_LOAD_CANCEL_POS_X, BtnSlgCancelCallback);
508 
509 	// Either the save or load button
510 	INT32          gfx;
511 	ST::string text;
512 	if (gfSaveGame)
513 	{
514 		gfx  = 5;
515 		text = zSaveLoadText[SLG_SAVE_GAME];
516 	}
517 	else
518 	{
519 		gfx  = 4;
520 		text = zSaveLoadText[SLG_LOAD_GAME];
521 	}
522 	guiSaveLoadImage  = UseLoadedButtonImage(guiSlgButtonImage, gfx, gfx + 3);
523 	guiSlgSaveLoadBtn = MakeButton(guiSaveLoadImage, text, SLG_SAVE_LOAD_BTN_POS_X, BtnSlgSaveLoadCallback);
524 	guiSlgSaveLoadBtn->SpecifyDisabledStyle(GUI_BUTTON::DISABLED_STYLE_HATCHED);
525 
526 	UINT16 const x = SLG_FIRST_SAVED_SPOT_X;
527 	UINT16       y = SLG_FIRST_SAVED_SPOT_Y;
528 	for (INT8 i = 0; i != NUM_SAVE_GAMES; ++i)
529 	{
530 		MOUSE_REGION& r = gSelectedSaveRegion[i];
531 		MSYS_DefineRegion(&r, x, y, x + SLG_SAVELOCATION_WIDTH, y + SLG_SAVELOCATION_HEIGHT, MSYS_PRIORITY_HIGH, CURSOR_NORMAL, SelectedSaveRegionMovementCallBack, SelectedSaveRegionCallBack);
532 		MSYS_SetRegionUserData(&r, 0, i);
533 
534 		// We cannot load a game that has not been saved
535 		if (!gfSaveGame && !gbSaveGameArray[i]) r.Disable();
536 
537 		y += SLG_GAP_BETWEEN_LOCATIONS;
538 	}
539 
540 	// Create the screen mask to enable ability to right click to cancel the save game
541 	MSYS_DefineRegion(&gSLSEntireScreenRegion, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGH - 10, CURSOR_NORMAL, MSYS_NO_CALLBACK, SelectedSLSEntireRegionCallBack);
542 
543 	// Display DiD Tab Button if We are in load game
544 	if (!gfSaveGame)
545 	{
546 		CreateLoadscreenTab();
547 		selectActiveTab();
548 	}
549 
550 	ClearSelectedSaveSlot();
551 
552 	RemoveMouseRegionForPauseOfClock();
553 
554 	gbHighLightedLocation  = -1;
555 	gzGameDescTextField = ST::null;
556 
557 	// If the last saved game slot is ok, set the selected slot to the last saved slot
558 	INT8 const last_slot = gfActiveTab ? gGameSettings.bLastSavedGameSlot-NUM_SAVE_GAMES : gGameSettings.bLastSavedGameSlot;
559 	if (last_slot != -1            &&
560 			gbSaveGameArray[last_slot] &&
561 			(!gfSaveGame || last_slot != 0)) // If it is not the quicksave slot, and we are loading
562 	{
563 		SAVED_GAME_HEADER SaveGameHeader;
564 		if (LoadSavedGameHeader(last_slot, &SaveGameHeader))
565 		{
566 			gzGameDescTextField = SaveGameHeader.sSavedGameDesc;
567 			gbSelectedSaveLocation = last_slot;
568 		}
569 		else
570 		{
571 			gGameSettings.bLastSavedGameSlot = -1;
572 		}
573 	}
574 
575 	EnableButton(guiSlgSaveLoadBtn, gbSelectedSaveLocation != -1);
576 	// Mark all buttons dirty, required for redrawing with the Tab system
577 	guiSlgCancelBtn->uiFlags |= BUTTON_DIRTY;
578 	if (!gfSaveGame)
579 	{
580 		for (INT8 i = 0; i < SLS_TAB_LENGTH; i++)
581 		{
582 			giLoadscreenTab[i]->uiFlags |= BUTTON_DIRTY;
583 		}
584 	}
585 
586 	RenderSaveLoadScreen();
587 
588 	// Save load buttons are created
589 	gfSaveLoadScreenButtonsCreated = TRUE;
590 
591 	gfDoingQuickLoad   = FALSE;
592 	gfStartedFadingOut = FALSE;
593 
594 	DisableScrollMessages();
595 
596 	gfLoadedGame = FALSE;
597 
598 	if (gfLoadGameUponEntry)
599 	{
600 		guiSlgCancelBtn->uiFlags   |= BUTTON_FORCE_UNDIRTY;
601 		guiSlgSaveLoadBtn->uiFlags |= BUTTON_FORCE_UNDIRTY;
602 		FRAME_BUFFER->Fill(0);
603 	}
604 
605 	gfGettingNameFromSaveLoadScreen = FALSE;
606 }
607 
608 
ExitSaveLoadScreen(void)609 static void ExitSaveLoadScreen(void)
610 {
611 	INT8	i;
612 
613 
614 	gfLoadGameUponEntry = FALSE;
615 
616 	if( !gfSaveLoadScreenButtonsCreated )
617 		return;
618 
619 	gfSaveLoadScreenExit = FALSE;
620 	gfSaveLoadScreenEntry = TRUE;
621 
622 	UnloadButtonImage( guiSlgButtonImage );
623 
624 	RemoveButton( guiSlgCancelBtn );
625 
626 	//Remove the save / load button
627 //	if( !gfSaveGame )
628 	{
629 		RemoveButton( guiSlgSaveLoadBtn );
630 		UnloadButtonImage( guiSaveLoadImage );
631 	}
632 	// Remove the Dead is Dead button
633 	if(!gfSaveGame)
634 	{
635 		RemoveLoadscreenTab();
636 	}
637 
638 	for(i=0; i<NUM_SAVE_GAMES; i++)
639 	{
640 		MSYS_RemoveRegion( &gSelectedSaveRegion[i]);
641 	}
642 
643 	DeleteVideoObject(guiSlgBackGroundImage);
644 	DeleteVideoObject(guiBackGroundAddOns);
645 
646 	//Destroy the text fields ( if created )
647 	DestroySaveLoadTextInputBoxes();
648 
649 	MSYS_RemoveRegion( &gSLSEntireScreenRegion );
650 
651 	gfSaveLoadScreenEntry = TRUE;
652 	gfSaveLoadScreenExit = FALSE;
653 
654 	if( !gfLoadedGame )
655 	{
656 		UnLockPauseState( );
657 		UnPauseGame();
658 	}
659 
660 	gfSaveLoadScreenButtonsCreated = FALSE;
661 
662 	gfCameDirectlyFromGame = FALSE;
663 
664 	//unload the basement sectors
665 	if( gfHadToMakeBasementLevels )
666 		TrashUndergroundSectorInfo();
667 
668 	gfGettingNameFromSaveLoadScreen = FALSE;
669 }
670 
671 
672 static void DisplaySaveGameList(void);
673 
674 
RenderSaveLoadScreen(void)675 static void RenderSaveLoadScreen(void)
676 {
677 	// If we are going to be instantly leaving the screen, don't draw the numbers
678 	if (gfLoadGameUponEntry) return;
679 
680 	BltVideoObject(FRAME_BUFFER, guiSlgBackGroundImage, 0, STD_SCREEN_X, STD_SCREEN_Y);
681 
682 	// Display the Title
683 	UINT16 const gfx = gfSaveGame ? 1 : 0;
684 	BltVideoObject(FRAME_BUFFER, guiBackGroundAddOns, gfx, SLG_TITLE_POS_X, SLG_TITLE_POS_Y);
685 
686 	DisplaySaveGameList();
687 	InvalidateScreen();
688 }
689 
690 
GetGameDescription()691 static bool GetGameDescription()
692 {
693 	INT8 const id = GetActiveFieldID();
694 	if (id == 0 || id == -1) return false;
695 
696 	gzGameDescTextField = GetStringFromField(id);
697 	return true;
698 }
699 
700 
701 static void DisplayOnScreenNumber(BOOLEAN display);
702 static BOOLEAN DisplaySaveGameEntry(INT8 bEntryID);
703 static void MoveSelectionDown();
704 static void MoveSelectionUp();
705 static void SetSelection(UINT8 ubNewSelection);
706 
707 
GetSaveLoadScreenUserInput(void)708 static void GetSaveLoadScreenUserInput(void)
709 {
710 	static BOOLEAN fWasCtrlHeldDownLastFrame = FALSE;
711 
712 	// If we are going to be instantly leaving the screen, dont draw the numbers
713 	if (gfLoadGameUponEntry) return;
714 
715 	DisplayOnScreenNumber(_KeyDown(ALT));
716 
717 	if (_KeyDown(CTRL) || fWasCtrlHeldDownLastFrame)
718 	{
719 		DisplaySaveGameEntry(gbSelectedSaveLocation);
720 	}
721 	fWasCtrlHeldDownLastFrame = _KeyDown(CTRL);
722 
723 	SGPPoint mouse_pos;
724 	GetMousePos(&mouse_pos);
725 
726 	InputAtom e;
727 	while (DequeueEvent(&e))
728 	{
729 		MouseSystemHook(e.usEvent, mouse_pos.iX, mouse_pos.iY);
730 		if (HandleTextInput(&e)) continue;
731 
732 		if (e.usEvent == KEY_DOWN)
733 		{
734 			switch (e.usParam)
735 			{
736 				case '1': SetSelection( 1); break;
737 				case '2': SetSelection( 2); break;
738 				case '3': SetSelection( 3); break;
739 				case '4': SetSelection( 4); break;
740 				case '5': SetSelection( 5); break;
741 				case '6': SetSelection( 6); break;
742 				case '7': SetSelection( 7); break;
743 				case '8': SetSelection( 8); break;
744 				case '9': SetSelection( 9); break;
745 				case '0': SetSelection(10); break;
746 			}
747 		}
748 		else if (e.usEvent == KEY_UP)
749 		{
750 			switch (e.usParam)
751 			{
752 				case 'a':
753 					if (_KeyDown(ALT) && !gfSaveGame)
754 					{
755 						INT8 const slot = GetNumberForAutoSave(TRUE);
756 						if (slot == -1) break;
757 
758 						guiLastSaveGameNum     = slot;
759 						gbSelectedSaveLocation = SAVE__END_TURN_NUM;
760 						StartFadeOutForSaveLoadScreen();
761 					}
762 					break;
763 
764 				case 'b':
765 					if (_KeyDown(ALT) && !gfSaveGame)
766 					{
767 						INT8 const slot = GetNumberForAutoSave(FALSE);
768 						if (slot == -1) break;
769 
770 						guiLastSaveGameNum     = 1 - slot;
771 						gbSelectedSaveLocation = SAVE__END_TURN_NUM;
772 						StartFadeOutForSaveLoadScreen();
773 					}
774 					break;
775 
776 				case SDLK_UP:   MoveSelectionUp();   break;
777 				case SDLK_DOWN: MoveSelectionDown(); break;
778 
779 				case SDLK_ESCAPE:
780 					if (gbSelectedSaveLocation == -1)
781 					{
782 						LeaveSaveLoadScreen();
783 					}
784 					else
785 					{ // Reset selected slot
786 						gbSelectedSaveLocation = -1;
787 						gfRedrawSaveLoadScreen = TRUE;
788 						DestroySaveLoadTextInputBoxes();
789 						DisableButton(guiSlgSaveLoadBtn);
790 					}
791 					break;
792 
793 				case SDLK_RETURN:
794 					if (!gfSaveGame)
795 					{
796 						SaveLoadGameNumber();
797 					}
798 					else if (GetGameDescription())
799 					{
800 						SetActiveField(0);
801 						DestroySaveLoadTextInputBoxes();
802 						SaveLoadGameNumber();
803 					}
804 					else if (gbSelectedSaveLocation != -1)
805 					{
806 						SaveLoadGameNumber();
807 					}
808 					else
809 					{
810 						gfRedrawSaveLoadScreen = TRUE;
811 					}
812 					break;
813 			}
814 		}
815 	}
816 }
817 
818 
819 static UINT8 CompareSaveGameVersion(INT8 bSaveGameID);
820 static void ConfirmSavedGameMessageBoxCallBack(MessageBoxReturnValue);
821 static void LoadSavedGameWarningMessageBoxCallBack(MessageBoxReturnValue);
822 static void SaveGameToSlotNum(void);
823 
824 
SaveLoadGameNumber()825 static void SaveLoadGameNumber()
826 {
827 	INT8 const save_slot_id = gbSelectedSaveLocation;
828 	if (save_slot_id < 0 || NUM_SAVE_GAMES <= save_slot_id) return;
829 
830 	if (gfSaveGame)
831 	{
832 		GetGameDescription();
833 
834 		// If there is save game in the slot, ask for confirmation before overwriting
835 		if (gbSaveGameArray[save_slot_id])
836 		{
837 			ST::string sText = st_format_printf(zSaveLoadText[SLG_CONFIRM_SAVE], save_slot_id);
838 			DoSaveLoadMessageBox(sText, SAVE_LOAD_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmSavedGameMessageBoxCallBack);
839 		}
840 		else
841 		{ // else do NOT put up a confirmation
842 			SaveGameToSlotNum();
843 		}
844 	}
845 	else
846 	{
847 		// Check to see if the save game headers are the same
848 		UINT8 const ret = CompareSaveGameVersion(save_slot_id);
849 		if (ret != SLS_HEADER_OK)
850 		{
851 			ST::string msg =
852 				ret == SLS_GAME_VERSION_OUT_OF_DATE       ? zSaveLoadText[SLG_GAME_VERSION_DIF] :
853 				ret == SLS_SAVED_GAME_VERSION_OUT_OF_DATE ? zSaveLoadText[SLG_SAVED_GAME_VERSION_DIF] :
854 				zSaveLoadText[SLG_BOTH_GAME_AND_SAVED_GAME_DIF];
855 			DoSaveLoadMessageBox(msg, SAVE_LOAD_SCREEN, MSG_BOX_FLAG_YESNO, LoadSavedGameWarningMessageBoxCallBack);
856 		}
857 		else
858 		{
859 			StartFadeOutForSaveLoadScreen();
860 		}
861 	}
862 }
IsDeadIsDeadTab(INT8 tabNo)863 BOOLEAN IsDeadIsDeadTab(INT8 tabNo)
864 {
865 	return tabNo == DEAD_IS_DEAD_TAB_NO;
866 }
867 
868 
869 // Switch between normal Load game and Dead is Dead
LoadTab(INT8 tabNo)870 void LoadTab(INT8 tabNo)
871 {
872 	if (gfActiveTab != tabNo)
873 	{
874 		gfActiveTab = tabNo;
875 
876 		// Reinit the savegame array and redraw the save load screen
877 		InitSaveGameArray();
878 		// Reinit the mouse region for selections, otherwise we can't select the save slots
879 		gbSelectedSaveLocation = -1;
880 		UINT16 const x = SLG_FIRST_SAVED_SPOT_X;
881 		UINT16       y = SLG_FIRST_SAVED_SPOT_Y;
882 		for (INT8 i = 0; i != NUM_SAVE_GAMES; ++i)
883 		{
884 			// Deinitialize first
885 			MSYS_RemoveRegion( &gSelectedSaveRegion[i]);
886 			// Reinitialize
887 			MOUSE_REGION& r = gSelectedSaveRegion[i];
888 			MSYS_DefineRegion(&r, x, y, x + SLG_SAVELOCATION_WIDTH, y + SLG_SAVELOCATION_HEIGHT, MSYS_PRIORITY_HIGH, CURSOR_NORMAL, SelectedSaveRegionMovementCallBack, SelectedSaveRegionCallBack);
889 			MSYS_SetRegionUserData(&r, 0, i);
890 
891 			// Disable unused slots and select the first used slot
892 			if (!gbSaveGameArray[i])
893 			{
894 				r.Disable();
895 			} else if(gbSelectedSaveLocation == -1)
896 			{
897 				gbSelectedSaveLocation = i;
898 			}
899 
900 			y += SLG_GAP_BETWEEN_LOCATIONS;
901 		}
902 		RenderSaveLoadScreen();
903 
904 		// Render the buttons
905 		MarkButtonsDirty( );
906 		RenderButtons();
907 	}
908 }
909 
910 
DoSaveLoadMessageBoxWithRect(const ST::string & str,ScreenID uiExitScreen,MessageBoxFlags usFlags,MSGBOX_CALLBACK ReturnCallback,SGPBox const * centering_rect)911 void DoSaveLoadMessageBoxWithRect(const ST::string& str, ScreenID uiExitScreen, MessageBoxFlags usFlags, MSGBOX_CALLBACK ReturnCallback, SGPBox const* centering_rect)
912 {
913 	// do message box and return
914 	DoMessageBox(MSG_BOX_BASIC_STYLE, str, uiExitScreen, usFlags, ReturnCallback, centering_rect);
915 }
916 
917 
DoSaveLoadMessageBox(const ST::string & str,ScreenID uiExitScreen,MessageBoxFlags usFlags,MSGBOX_CALLBACK ReturnCallback)918 void DoSaveLoadMessageBox(const ST::string& str, ScreenID uiExitScreen, MessageBoxFlags usFlags, MSGBOX_CALLBACK ReturnCallback)
919 {
920 	DoSaveLoadMessageBoxWithRect(str, uiExitScreen, usFlags, ReturnCallback, NULL);
921 }
922 
923 
InitSaveGameArray(void)924 static void InitSaveGameArray(void)
925 {
926 	for (INT8 cnt = 0; cnt < NUM_SAVE_GAMES; ++cnt)
927 	{
928 		SAVED_GAME_HEADER SaveGameHeader;
929 		gbSaveGameArray[cnt] = LoadSavedGameHeader(cnt, &SaveGameHeader);
930 	}
931 }
932 
933 
DisplaySaveGameList(void)934 static void DisplaySaveGameList(void)
935 {
936 	for (INT8 i = 0; i != NUM_SAVE_GAMES; ++i)
937 	{ // Display all the information from the header
938 		DisplaySaveGameEntry(i);
939 	}
940 }
941 
942 
DisplaySaveGameEntry(INT8 const entry_idx)943 static BOOLEAN DisplaySaveGameEntry(INT8 const entry_idx)
944 {
945 	if (entry_idx == -1) return TRUE;
946 	// If we are going to be instantly leaving the screen, dont draw the numbers
947 	if (gfLoadGameUponEntry) return TRUE;
948 	// If we are currently fading out, leave
949 	if (gfStartedFadingOut) return TRUE;
950 
951 	UINT16 const bx = SLG_FIRST_SAVED_SPOT_X;
952 	UINT16 const by = SLG_FIRST_SAVED_SPOT_Y + SLG_GAP_BETWEEN_LOCATIONS * entry_idx;
953 
954 	bool const is_selected = entry_idx == gbSelectedSaveLocation;
955 	bool const save_exists = gbSaveGameArray[entry_idx];
956 
957 	// Background
958 	UINT16 const gfx = is_selected ?
959 		SLG_SELECTED_SLOT_GRAPHICS_NUMBER : SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER;
960 	BltVideoObject(FRAME_BUFFER, guiBackGroundAddOns, gfx, bx, by);
961 
962 	SGPFont  font = SAVE_LOAD_NORMAL_FONT;
963 	UINT8 foreground;
964 	UINT8 shadow;
965 	if (entry_idx == 0 && gfSaveGame && gfActiveTab == 0)
966 	{ // The QuickSave slot
967 		FRAME_BUFFER->ShadowRect(bx, by, bx + SLG_SAVELOCATION_WIDTH, by + SLG_SAVELOCATION_HEIGHT);
968 		foreground = SAVE_LOAD_QUICKSAVE_COLOR;
969 		shadow     = SAVE_LOAD_QUICKSAVE_SHADOW_COLOR;
970 	}
971 	else if (is_selected)
972 	{ // The currently selected location
973 		foreground = SAVE_LOAD_SELECTED_COLOR;
974 		shadow     = SAVE_LOAD_SELECTED_SHADOW_COLOR;
975 	}
976 	else if (entry_idx == gbHighLightedLocation)
977 	{ // The highlighted slot
978 		foreground = SAVE_LOAD_HIGHLIGHTED_COLOR;
979 		shadow     = SAVE_LOAD_HIGHLIGHTED_SHADOW_COLOR;
980 	}
981 	else if (save_exists)
982 	{ // The file exists
983 		foreground = SAVE_LOAD_NORMAL_COLOR;
984 		shadow     = SAVE_LOAD_NORMAL_SHADOW_COLOR;
985 	}
986 	else if (gfSaveGame)
987 	{ // We are saving a game
988 		foreground = SAVE_LOAD_EMPTYSLOT_COLOR;
989 		shadow     = SAVE_LOAD_EMPTYSLOT_SHADOW_COLOR;
990 	}
991 	else
992 	{
993 		FRAME_BUFFER->ShadowRect(bx, by, bx + SLG_SAVELOCATION_WIDTH, by + SLG_SAVELOCATION_HEIGHT);
994 		foreground = SAVE_LOAD_QUICKSAVE_COLOR;
995 		shadow     = SAVE_LOAD_QUICKSAVE_SHADOW_COLOR;
996 	}
997 	SetFontShadow(shadow);
998 
999 	if (save_exists || is_selected)
1000 	{ // Setup the strings to be displayed
1001 		SAVED_GAME_HEADER header;
1002 		if (gfSaveGame && is_selected)
1003 		{ // The user has selected a spot to save.  Fill out all the required information
1004 			header.sSavedGameDesc = gzGameDescTextField;
1005 			header.uiDay                     = GetWorldDay();
1006 			header.ubHour                    = GetWorldHour();
1007 			header.ubMin                     = guiMin;
1008 			GetBestPossibleSectorXYZValues(&header.sSectorX, &header.sSectorY, &header.bSectorZ);
1009 			header.ubNumOfMercsOnPlayersTeam = NumberOfMercsOnPlayerTeam();
1010 			header.iCurrentBalance           = LaptopSaveInfo.iCurrentBalance;
1011 			header.sInitialGameOptions       = gGameOptions;
1012 		}
1013 		else if (!LoadSavedGameHeader(entry_idx, &header))
1014 		{
1015 			return FALSE;
1016 		}
1017 
1018 		UINT16 x = bx;
1019 		UINT16 y = by + SLG_DATE_OFFSET_Y;
1020 		if (is_selected)
1021 		{ // This is the currently selected location, move the text up a bit
1022 			x++;
1023 			y--;
1024 		}
1025 
1026 		if (!gfSaveGame && _KeyDown(CTRL) && is_selected)
1027 		{ // The user is LOADING and holding down the CTRL key, display the additional info
1028 			// Create a string for difficulty level
1029 			ST::string difficulty = ST::format("{} {}", gzGIOScreenText[GIO_EASY_TEXT + header.sInitialGameOptions.ubDifficultyLevel - 1], zSaveLoadText[SLG_DIFF]);
1030 
1031 			// Make a string containing the extended options
1032 			UINT8 gameModeText;
1033 			switch (header.sInitialGameOptions.ubGameSaveMode)
1034 			{
1035 				case DIF_IRON_MAN: gameModeText = GIO_IRON_MAN_TEXT; break;
1036 				case DIF_DEAD_IS_DEAD: gameModeText = GIO_DEAD_IS_DEAD_TEXT; break;
1037 				default: gameModeText = GIO_SAVE_ANYWHERE_TEXT;
1038 			}
1039 			ST::string options = ST::format("{20}     {22}     {22}     {22}",
1040 				difficulty,
1041 				/*gzGIOScreenText[GIO_TIMED_TURN_TITLE_TEXT + header.sInitialGameOptions.fTurnTimeLimit + 1],*/
1042 				gzGIOScreenText[gameModeText],
1043 				header.sInitialGameOptions.fGunNut      ? zSaveLoadText[SLG_ADDITIONAL_GUNS] : zSaveLoadText[SLG_NORMAL_GUNS],
1044 				header.sInitialGameOptions.fSciFi       ? zSaveLoadText[SLG_SCIFI]           : zSaveLoadText[SLG_REALISTIC]
1045 			);
1046 
1047 			// The date
1048 			DrawTextToScreen(options, x + SLG_DATE_OFFSET_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1049 		}
1050 		else
1051 		{ // Display the Saved game information
1052 			// The date
1053 			ST::string date = ST::format("{} {}, {02d}:{02d}", pMessageStrings[MSG_DAY], header.uiDay, header.ubHour, header.ubMin);
1054 			DrawTextToScreen(date, x + SLG_DATE_OFFSET_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1055 
1056 			// The sector
1057 			ST::string location;
1058 			if (header.sSectorX != -1 && header.sSectorY != -1 && header.bSectorZ >= 0)
1059 			{
1060 				gfGettingNameFromSaveLoadScreen = TRUE;
1061 				location = GetSectorIDString(header.sSectorX, header.sSectorY, header.bSectorZ, FALSE);
1062 				gfGettingNameFromSaveLoadScreen = FALSE;
1063 			}
1064 			else if (header.uiDay * NUM_SEC_IN_DAY + header.ubHour * NUM_SEC_IN_HOUR + header.ubMin * NUM_SEC_IN_MIN <= STARTING_TIME)
1065 			{
1066 				location = gpStrategicString[STR_PB_NOTAPPLICABLE_ABBREVIATION];
1067 			}
1068 			else
1069 			{
1070 				location = gzLateLocalizedString[STR_LATE_14];
1071 			}
1072 			location = ReduceStringLength(location, SLG_SECTOR_WIDTH, font);
1073 			DrawTextToScreen(location, x + SLG_SECTOR_OFFSET_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1074 
1075 			// Number of mercs on the team
1076 			// If only 1 merc is on the team use "merc" else "mercs"
1077 			UINT8          const n_mercs = header.ubNumOfMercsOnPlayersTeam;
1078 			ST::string merc = n_mercs == 1 ?
1079 				MercAccountText[MERC_ACCOUNT_MERC] :
1080 				pMessageStrings[MSG_MERCS];
1081 			ST::string merc_count = ST::format("{} {}", n_mercs, merc);
1082 			DrawTextToScreen(merc_count, x + SLG_NUM_MERCS_OFFSET_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1083 
1084 			// The balance
1085 			DrawTextToScreen(SPrintMoney(header.iCurrentBalance), x + SLG_BALANCE_OFFSET_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1086 
1087 			if (save_exists || (gfSaveGame && !gfUserInTextInputMode && is_selected))
1088 			{
1089 				// The saved game description
1090 				DrawTextToScreen(header.sSavedGameDesc, x + SLG_SAVE_GAME_DESC_X, y, 0, font, foreground, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1091 			}
1092 		}
1093 	}
1094 	else
1095 	{
1096 		// If this is the quick save slot
1097 		ST::string txt;
1098 		if (entry_idx == 0 && gfActiveTab == 0)
1099 		{
1100 			txt = pMessageStrings[MSG_EMPTY_QUICK_SAVE_SLOT];
1101 		} else
1102 		{
1103 			txt = pMessageStrings[MSG_EMPTYSLOT];
1104 		}
1105 		DrawTextToScreen(txt, bx, by + SLG_DATE_OFFSET_Y, 609, font, foreground, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
1106 	}
1107 
1108 	// Reset the shadow color
1109 	SetFontShadow(DEFAULT_SHADOW);
1110 
1111 	InvalidateRegion(bx, by, bx + SLG_SAVELOCATION_WIDTH, by + SLG_SAVELOCATION_HEIGHT);
1112 	return TRUE;
1113 }
1114 
1115 
LoadSavedGameHeader(const INT8 bEntry,SAVED_GAME_HEADER * const header)1116 static BOOLEAN LoadSavedGameHeader(const INT8 bEntry, SAVED_GAME_HEADER* const header)
1117 {
1118 	// make sure the entry is valid
1119 	if (0 <= bEntry && bEntry < NUM_SAVE_GAMES)
1120 	{
1121 		char zSavedGameName[512];
1122 		CreateSavedGameFileNameFromNumber(gfActiveTab ? (bEntry + NUM_SAVE_GAMES) : bEntry, zSavedGameName);
1123 
1124 		try
1125 		{
1126 			bool stracLinuxFormat;
1127 			AutoSGPFile f(GCM->openUserPrivateFileForReading(zSavedGameName));
1128 			ExtractSavedGameHeaderFromFile(f, *header, &stracLinuxFormat);
1129 			endof(header->zGameVersionNumber)[-1] =  '\0';
1130 			return TRUE;
1131 		}
1132 		catch (...) { /* Handled below */ }
1133 
1134 		gbSaveGameArray[bEntry] = FALSE;
1135 	}
1136 	*header = SAVED_GAME_HEADER{};
1137 	return FALSE;
1138 }
1139 
1140 
BtnSlgCancelCallback(GUI_BUTTON * const btn,INT32 const reason)1141 static void BtnSlgCancelCallback(GUI_BUTTON* const btn, INT32 const reason)
1142 {
1143 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1144 	{
1145 		LeaveSaveLoadScreen();
1146 	}
1147 }
1148 
1149 
BtnSlgSaveLoadCallback(GUI_BUTTON * btn,INT32 reason)1150 static void BtnSlgSaveLoadCallback(GUI_BUTTON* btn, INT32 reason)
1151 {
1152 	if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
1153 	{
1154 		SaveLoadGameNumber();
1155 	}
1156 }
1157 
BtnSlgNormalGameTabCallback(GUI_BUTTON * btn,INT32 reason)1158 static void BtnSlgNormalGameTabCallback(GUI_BUTTON* btn, INT32 reason)
1159 {
1160 	if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
1161 	{
1162 		btn->uiFlags |= BUTTON_CLICKED_ON;
1163 		giLoadscreenTab[SLS_TAB_DEAD_IS_DEAD]->uiFlags       &= ~BUTTON_CLICKED_ON;
1164 		if (IsDeadIsDeadTab(gfActiveTab))
1165 		{
1166 			LoadTab(0);
1167 		}
1168 	}
1169 }
1170 
BtnSlgDeadIsDeadTabCallback(GUI_BUTTON * btn,INT32 reason)1171 static void BtnSlgDeadIsDeadTabCallback(GUI_BUTTON* btn, INT32 reason)
1172 {
1173 	if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
1174 	{
1175 		btn->uiFlags |= BUTTON_CLICKED_ON;
1176 		giLoadscreenTab[SLS_TAB_NORMAL]->uiFlags       &= ~BUTTON_CLICKED_ON;
1177 		if (!IsDeadIsDeadTab(gfActiveTab))
1178 		{
1179 			LoadTab(1);
1180 		}
1181 	}
1182 }
1183 
1184 
1185 static void DisableSelectedSlot(void);
1186 static void InitSaveLoadScreenTextInputBoxes(void);
1187 static void RedrawSaveLoadScreenAfterMessageBox(MessageBoxReturnValue);
1188 
1189 
SelectedSaveRegionCallBack(MOUSE_REGION * pRegion,INT32 iReason)1190 static void SelectedSaveRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason)
1191 {
1192 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1193 	{
1194 		UINT8	bSelected = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
1195 		static UINT32	uiLastTime = 0;
1196 		UINT32	uiCurTime = GetJA2Clock();
1197 
1198 /*
1199 		//If we are saving and this is the quick save slot
1200 		if( gfSaveGame && bSelected == 0 )
1201 		{
1202 			//Display a pop up telling user what the quick save slot is
1203 			DoSaveLoadMessageBox(pMessageStrings[MSG_QUICK_SAVE_RESERVED_FOR_TACTICAL], SAVE_LOAD_SCREEN, MSG_BOX_FLAG_OK, RedrawSaveLoadScreenAfterMessageBox);
1204 			return;
1205 		}
1206 
1207 		SetSelection( bSelected );
1208 */
1209 
1210 		//If we are saving and this is the quick save slot
1211 		if( gfSaveGame && bSelected == 0 && gfActiveTab == 0)
1212 		{
1213 			//Display a pop up telling user what the quick save slot is
1214 			DoSaveLoadMessageBox(pMessageStrings[MSG_QUICK_SAVE_RESERVED_FOR_TACTICAL], SAVE_LOAD_SCREEN, MSG_BOX_FLAG_OK, RedrawSaveLoadScreenAfterMessageBox);
1215 			return;
1216 		}
1217 
1218 		//if the user is selecting an unselected saved game slot
1219 		if( gbSelectedSaveLocation != bSelected )
1220 		{
1221 			//Destroy the previous region
1222 			DestroySaveLoadTextInputBoxes();
1223 
1224 			gbSelectedSaveLocation = bSelected;
1225 
1226 			//Reset the global string
1227 			gzGameDescTextField = ST::null;
1228 
1229 			//Init the text field for the game desc
1230 			InitSaveLoadScreenTextInputBoxes();
1231 
1232 			//If we are Loading the game
1233 //			if( !gfSaveGame )
1234 			{
1235 				//Enable the save/load button
1236 				EnableButton( guiSlgSaveLoadBtn );
1237 			}
1238 
1239 			//If we are saving the game, disbale the button
1240 //			if( gfSaveGame )
1241 //					DisableButton( guiSlgSaveLoadBtn );
1242 //			else
1243 			{
1244 				//Set the time in which the button was first pressed
1245 				uiLastTime = GetJA2Clock();
1246 			}
1247 
1248 			gfRedrawSaveLoadScreen = TRUE;
1249 
1250 			uiLastTime = GetJA2Clock();
1251 		}
1252 
1253 		//the user is selecting the selected save game slot
1254 		else
1255 		{
1256 			//if we are saving a game
1257 			if( gfSaveGame )
1258 			{
1259 				//if the user is not currently editing the game desc
1260 				if( !gfUserInTextInputMode )
1261 				{
1262 					if( ( uiCurTime - uiLastTime ) < SLG_DOUBLE_CLICK_DELAY )
1263 					{
1264 						//Load the saved game
1265 						SaveLoadGameNumber();
1266 					}
1267 					else
1268 					{
1269 						uiLastTime = GetJA2Clock();
1270 					}
1271 
1272 					InitSaveLoadScreenTextInputBoxes();
1273 
1274 					gfRedrawSaveLoadScreen = TRUE;
1275 
1276 				}
1277 				else
1278 				{
1279 					if (GetGameDescription())
1280 					{
1281 						SetActiveField(0);
1282 
1283 						DestroySaveLoadTextInputBoxes();
1284 
1285 //						gfRedrawSaveLoadScreen = TRUE;
1286 
1287 //						EnableButton( guiSlgSaveLoadBtn );
1288 
1289 						gfRedrawSaveLoadScreen = TRUE;
1290 
1291 
1292 						if( ( uiCurTime - uiLastTime ) < SLG_DOUBLE_CLICK_DELAY )
1293 						{
1294 							gubSaveGameNextPass = 1;
1295 						}
1296 						else
1297 						{
1298 							uiLastTime = GetJA2Clock();
1299 						}
1300 					}
1301 				}
1302 			}
1303 			//else we are loading
1304 			else
1305 			{
1306 				if( ( uiCurTime - uiLastTime ) < SLG_DOUBLE_CLICK_DELAY )
1307 				{
1308 					//Load the saved game
1309 					SaveLoadGameNumber();
1310 				}
1311 				else
1312 				{
1313 					uiLastTime = GetJA2Clock();
1314 				}
1315 			}
1316 		}
1317 	}
1318 	else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
1319 	{
1320 		DisableSelectedSlot();
1321 	}
1322 }
1323 
1324 
SelectedSaveRegionMovementCallBack(MOUSE_REGION * pRegion,INT32 reason)1325 static void SelectedSaveRegionMovementCallBack(MOUSE_REGION* pRegion, INT32 reason)
1326 {
1327 	if( reason & MSYS_CALLBACK_REASON_LOST_MOUSE )
1328 	{
1329 		INT8 bTemp = gbHighLightedLocation;
1330 		gbHighLightedLocation = -1;
1331 //		DisplaySaveGameList();
1332 		DisplaySaveGameEntry( bTemp );
1333 	}
1334 	else if( reason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
1335 	{
1336 		//If we are saving and this is the quick save slot, leave
1337 		if( gfSaveGame )
1338 		{
1339 			return;
1340 		}
1341 
1342 		gbHighLightedLocation = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
1343 		DisplaySaveGameEntry( gbHighLightedLocation );//, usPosY );
1344 	}
1345 }
1346 
1347 
InitSaveLoadScreenTextInputBoxes(void)1348 static void InitSaveLoadScreenTextInputBoxes(void)
1349 {
1350 	if (gbSelectedSaveLocation == -1)              return;
1351 	if (!gfSaveGame)                               return;
1352 	// If we are exiting, don't create the fields
1353 	if (gfSaveLoadScreenExit)                      return;
1354 	if (guiSaveLoadExitScreen != SAVE_LOAD_SCREEN) return;
1355 
1356 	InitTextInputMode();
1357 	SetTextInputCursor(CUROSR_IBEAM_WHITE);
1358 	SetTextInputFont(FONT12ARIALFIXEDWIDTH);
1359 	Set16BPPTextFieldColor(Get16BPPColor(FROMRGB(0, 0, 0)));
1360 	SetBevelColors(Get16BPPColor(FROMRGB(136, 138, 135)), Get16BPPColor(FROMRGB(24, 61, 81)));
1361 	SetTextInputRegularColors(FONT_WHITE, 2);
1362 	SetTextInputHilitedColors(2, FONT_WHITE, FONT_WHITE);
1363 	SetCursorColor(Get16BPPColor(FROMRGB(255, 255, 255)));
1364 
1365 	AddUserInputField(NULL);
1366 
1367 	// If we are modifying a previously modifed string, use it
1368 	if (!gbSaveGameArray[gbSelectedSaveLocation])
1369 	{
1370 		gzGameDescTextField = ST::null;
1371 	}
1372 	else if (gzGameDescTextField.empty())
1373 	{
1374 		SAVED_GAME_HEADER SaveGameHeader;
1375 		LoadSavedGameHeader(gbSelectedSaveLocation, &SaveGameHeader);
1376 		gzGameDescTextField = SaveGameHeader.sSavedGameDesc;
1377 	}
1378 
1379 	// Game Desc Field
1380 	INT16 const x = SLG_FIRST_SAVED_SPOT_X + SLG_SAVE_GAME_DESC_X;
1381 	INT16 const y = SLG_FIRST_SAVED_SPOT_Y + SLG_SAVE_GAME_DESC_Y - 5 + SLG_GAP_BETWEEN_LOCATIONS * gbSelectedSaveLocation;
1382 	AddTextInputField(x, y, SLG_SAVELOCATION_WIDTH - SLG_SAVE_GAME_DESC_X - 7, 17, MSYS_PRIORITY_HIGH + 2, gzGameDescTextField, 46, INPUTTYPE_FULL_TEXT);
1383 	SetActiveField(1);
1384 
1385 	gfUserInTextInputMode = TRUE;
1386 }
1387 
1388 
DestroySaveLoadTextInputBoxes(void)1389 static void DestroySaveLoadTextInputBoxes(void)
1390 {
1391 	gfUserInTextInputMode = FALSE;
1392 	KillAllTextInputModes();
1393 	SetTextInputCursor( CURSOR_IBEAM );
1394 }
1395 
1396 
SetSelection(UINT8 const new_selection)1397 static void SetSelection(UINT8 const new_selection)
1398 {
1399 	// If we are loading and there is no entry, return
1400 	if (!gfSaveGame && !gbSaveGameArray[new_selection]) return;
1401 
1402 	gfRedrawSaveLoadScreen = TRUE;
1403 	DestroySaveLoadTextInputBoxes();
1404 
1405 	INT8 const old_slot = gbSelectedSaveLocation;
1406 	gbSelectedSaveLocation = new_selection;
1407 
1408 	if (gfSaveGame && old_slot != new_selection)
1409 	{
1410 		DestroySaveLoadTextInputBoxes();
1411 
1412 		// Null out the current description
1413 		gzGameDescTextField = ST::null;
1414 
1415 		//Init the text field for the game desc
1416 		InitSaveLoadScreenTextInputBoxes();
1417 	}
1418 
1419 	EnableButton(guiSlgSaveLoadBtn);
1420 }
1421 
1422 
CompareSaveGameVersion(INT8 bSaveGameID)1423 static UINT8 CompareSaveGameVersion(INT8 bSaveGameID)
1424 {
1425 	UINT8 ubRetVal=SLS_HEADER_OK;
1426 
1427 	SAVED_GAME_HEADER SaveGameHeader;
1428 
1429 	//Get the heade for the saved game
1430 	LoadSavedGameHeader( bSaveGameID, &SaveGameHeader );
1431 
1432 	// check to see if the saved game version in the header is the same as the current version
1433 	if( SaveGameHeader.uiSavedGameVersion != guiSavedGameVersion )
1434 	{
1435 		ubRetVal = SLS_SAVED_GAME_VERSION_OUT_OF_DATE;
1436 	}
1437 
1438 	if (strcmp(SaveGameHeader.zGameVersionNumber, g_version_number)!= 0)
1439 	{
1440 		if( ubRetVal == SLS_SAVED_GAME_VERSION_OUT_OF_DATE )
1441 			ubRetVal = SLS_BOTH_SAVE_GAME_AND_GAME_VERSION_OUT_OF_DATE;
1442 		else
1443 			ubRetVal = SLS_GAME_VERSION_OUT_OF_DATE;
1444 	}
1445 
1446 	return( ubRetVal );
1447 }
1448 
1449 
1450 static void LoadSavedGameDeleteAllSaveGameMessageBoxCallBack(MessageBoxReturnValue);
1451 
1452 
LoadSavedGameWarningMessageBoxCallBack(MessageBoxReturnValue const bExitValue)1453 static void LoadSavedGameWarningMessageBoxCallBack(MessageBoxReturnValue const bExitValue)
1454 {
1455 	// yes, load the game
1456 	if( bExitValue == MSG_BOX_RETURN_YES )
1457 	{
1458 		//Setup up the fade routines
1459 		StartFadeOutForSaveLoadScreen();
1460 	}
1461 
1462 	//The user does NOT want to continue..
1463 	else
1464 	{
1465 		//ask if the user wants to delete all the saved game files
1466 		DoSaveLoadMessageBox(zSaveLoadText[SLG_DELETE_ALL_SAVE_GAMES], SAVE_LOAD_SCREEN, MSG_BOX_FLAG_YESNO, LoadSavedGameDeleteAllSaveGameMessageBoxCallBack);
1467 	}
1468 }
1469 
1470 
1471 static void DeleteAllSaveGameFile(void);
1472 
1473 
LoadSavedGameDeleteAllSaveGameMessageBoxCallBack(MessageBoxReturnValue const bExitValue)1474 static void LoadSavedGameDeleteAllSaveGameMessageBoxCallBack(MessageBoxReturnValue const bExitValue)
1475 {
1476 	// yes, Delete all the save game files
1477 	if( bExitValue == MSG_BOX_RETURN_YES )
1478 	{
1479 		DeleteAllSaveGameFile( );
1480 		gfSaveLoadScreenExit = TRUE;
1481 	}
1482 
1483 	SetSaveLoadExitScreen( OPTIONS_SCREEN );
1484 
1485 	gbSelectedSaveLocation=-1;
1486 }
1487 
1488 
DeleteAllSaveGameFile(void)1489 static void DeleteAllSaveGameFile(void)
1490 {
1491 	UINT8	cnt;
1492 
1493 	for( cnt=0; cnt<NUM_SAVE_GAMES; cnt++)
1494 	{
1495 		DeleteSaveGameNumber( cnt );
1496 	}
1497 
1498 	gGameSettings.bLastSavedGameSlot = -1;
1499 
1500 	InitSaveGameArray();
1501 }
1502 
1503 
DeleteSaveGameNumber(UINT8 const save_slot_id)1504 void DeleteSaveGameNumber(UINT8 const save_slot_id)
1505 {
1506 	char filename[512];
1507 	CreateSavedGameFileNameFromNumber(save_slot_id, filename);
1508 	FileDelete(filename);
1509 }
1510 
1511 
DisplayOnScreenNumber(BOOLEAN display)1512 static void DisplayOnScreenNumber(BOOLEAN display)
1513 {
1514 	// Start at 1 - don't diplay it for the quicksave
1515 	for (INT8 bLoopNum = 1; bLoopNum < NUM_SAVE_GAMES; ++bLoopNum)
1516 	{
1517 		const UINT16 usPosX = STD_SCREEN_X + 6;
1518 		const UINT16 usPosY = SLG_FIRST_SAVED_SPOT_Y + SLG_GAP_BETWEEN_LOCATIONS * bLoopNum;
1519 
1520 		BlitBufferToBuffer(guiSAVEBUFFER, FRAME_BUFFER, usPosX, usPosY + SLG_DATE_OFFSET_Y, 10, 10);
1521 
1522 		if (display)
1523 		{
1524 			const INT8 bNum = (bLoopNum == 10 ? 0 : bLoopNum);
1525 			ST::string zTempString = ST::format("{2d}", bNum);
1526 			DrawTextToScreen(zTempString, usPosX, usPosY + SLG_DATE_OFFSET_Y, 0, SAVE_LOAD_NUMBER_FONT, SAVE_LOAD_NUMBER_COLOR, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
1527 		}
1528 
1529 		InvalidateRegion(usPosX, usPosY + SLG_DATE_OFFSET_Y, usPosX + 10, usPosY + SLG_DATE_OFFSET_Y + 10);
1530 	}
1531 }
1532 
1533 
1534 static void DoneFadeInForSaveLoadScreen(void);
1535 static void FailedLoadingGameCallBack(MessageBoxReturnValue);
1536 
1537 
DoneFadeOutForSaveLoadScreen(void)1538 static void DoneFadeOutForSaveLoadScreen(void)
1539 {
1540 	// Make sure we DON'T reset the levels if we are loading a game
1541 	gfHadToMakeBasementLevels = FALSE;
1542 
1543 	try
1544 	{
1545 		LoadSavedGame(IsDeadIsDeadTab(gfActiveTab) ? gbSelectedSaveLocation + NUM_SAVE_GAMES : gbSelectedSaveLocation);
1546 
1547 		gFadeInDoneCallback = DoneFadeInForSaveLoadScreen;
1548 
1549 		ScreenID const screen = guiScreenToGotoAfterLoadingSavedGame;
1550 		SetSaveLoadExitScreen(screen);
1551 		if (screen == MAP_SCREEN)
1552 		{ // We are to go to map screen after loading the game
1553 			FadeInNextFrame();
1554 		}
1555 		else
1556 		{ // We are to go to the Tactical screen after loading
1557 			PauseTime(FALSE);
1558 			FadeInGameScreen();
1559 		}
1560 	}
1561 	catch (std::exception const& e)
1562 	{
1563 		ST::string msg = st_format_printf(zSaveLoadText[SLG_LOAD_GAME_ERROR], e.what());
1564 		DoSaveLoadMessageBox(msg, SAVE_LOAD_SCREEN, MSG_BOX_FLAG_OK, FailedLoadingGameCallBack);
1565 		NextLoopCheckForEnoughFreeHardDriveSpace();
1566 	}
1567 	gfStartedFadingOut = FALSE;
1568 }
1569 
1570 
DoneFadeInForSaveLoadScreen(void)1571 static void DoneFadeInForSaveLoadScreen(void)
1572 {
1573 	//Leave the screen
1574 	//if we are supposed to stay in tactical, due nothing,
1575 	//if we are supposed to goto mapscreen, leave tactical and go to mapscreen
1576 
1577 	if( guiScreenToGotoAfterLoadingSavedGame == MAP_SCREEN )
1578 	{
1579 		if( !gfPauseDueToPlayerGamePause )
1580 		{
1581 			UnLockPauseState( );
1582 			UnPauseGame( );
1583 		}
1584 	}
1585 
1586 	else
1587 	{
1588 		//if the game is currently paused
1589 		if( GamePaused() )
1590 		{
1591 			//need to call it twice
1592 			HandlePlayerPauseUnPauseOfGame();
1593 			HandlePlayerPauseUnPauseOfGame();
1594 		}
1595 
1596 //		UnLockPauseState( );
1597 //		UnPauseGame( );
1598 
1599 	}
1600 }
1601 
1602 
SelectedSLSEntireRegionCallBack(MOUSE_REGION * pRegion,INT32 iReason)1603 static void SelectedSLSEntireRegionCallBack(MOUSE_REGION* pRegion, INT32 iReason)
1604 {
1605 	if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
1606 	{
1607 		DisableSelectedSlot();
1608 	}
1609 }
1610 
1611 
DisableSelectedSlot(void)1612 static void DisableSelectedSlot(void)
1613 {
1614 	//reset selected slot
1615 	gbSelectedSaveLocation = -1;
1616 	gfRedrawSaveLoadScreen = TRUE;
1617 	DestroySaveLoadTextInputBoxes();
1618 
1619 	if( !gfSaveGame )
1620 		DisableButton( guiSlgSaveLoadBtn );
1621 
1622 	//reset the selected graphic
1623 	ClearSelectedSaveSlot();
1624 }
1625 
1626 
ConfirmSavedGameMessageBoxCallBack(MessageBoxReturnValue const bExitValue)1627 static void ConfirmSavedGameMessageBoxCallBack(MessageBoxReturnValue const bExitValue)
1628 {
1629 	Assert( gbSelectedSaveLocation != -1 );
1630 
1631 	if( bExitValue == MSG_BOX_RETURN_YES )
1632 	{
1633 		SaveGameToSlotNum();
1634 	}
1635 }
1636 
1637 
FailedLoadingGameCallBack(MessageBoxReturnValue const bExitValue)1638 static void FailedLoadingGameCallBack(MessageBoxReturnValue const bExitValue)
1639 {
1640 	// yes
1641 	if( bExitValue == MSG_BOX_RETURN_OK )
1642 	{
1643 		//if the current screen is tactical
1644 		if( guiPreviousOptionScreen == MAP_SCREEN )
1645 		{
1646 			SetPendingNewScreen( MAINMENU_SCREEN );
1647 		}
1648 		else
1649 		{
1650 			LeaveTacticalScreen( MAINMENU_SCREEN );
1651 		}
1652 
1653 		SetSaveLoadExitScreen( MAINMENU_SCREEN );
1654 
1655 
1656 		//We want to reinitialize the game
1657 		ReStartingGame();
1658 	}
1659 }
1660 
1661 
DoQuickSave()1662 void DoQuickSave()
1663 {
1664 	// Use the Dead is Dead function if we are in DiD
1665 	if (gGameOptions.ubGameSaveMode == DIF_DEAD_IS_DEAD)
1666 	{
1667 		DoDeadIsDeadSave();
1668 	} else
1669 	{
1670 		if (SaveGame(0, ST::null)) return;
1671 
1672 		if (guiPreviousOptionScreen == MAP_SCREEN)
1673 		{
1674 			DoMapMessageBox(MSG_BOX_BASIC_STYLE, zSaveLoadText[SLG_SAVE_GAME_ERROR], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL);
1675 		} else
1676 		{
1677 			DoMessageBox(MSG_BOX_BASIC_STYLE, zSaveLoadText[SLG_SAVE_GAME_ERROR], GAME_SCREEN, MSG_BOX_FLAG_OK, NULL, NULL);
1678 		}
1679 	}
1680 }
1681 
1682 // Save function for Dead Is Dead
DoDeadIsDeadSave()1683 void DoDeadIsDeadSave()
1684 {
1685 	// Check if we are in a sane state! Do not save if:
1686 	// - we are in an AI Turn
1687 	// - we are in a Dialogue
1688 	// - we are in Meanwhile.....
1689 	// - we are in a locked ui
1690 	// - we are currently in a message box - The Messagebox would be gone without selection after loading
1691 	if (gTacticalStatus.ubCurrentTeam == OUR_TEAM && !gfInTalkPanel && !gfInMeanwhile && !gfPreBattleInterfaceActive && guiPreviousOptionScreen != MSG_BOX_SCREEN && gCurrentUIMode != LOCKUI_MODE)
1692 	{
1693 		// Backup old saves
1694 		BackupSavedGame(gGameSettings.bLastSavedGameSlot);
1695 		// Save the previous option screen State to reset it after saving
1696 		ScreenID tmpGuiPreviousOptionScreen = guiPreviousOptionScreen;
1697 		// We want to save the current screen we are in. Unless we are in Options, Laptop, or others
1698 		// Make sure we are always in a sane screen.
1699 		if (tmpGuiPreviousOptionScreen != MAP_SCREEN && tmpGuiPreviousOptionScreen != GAME_SCREEN) {
1700 			if (guiCurrentScreen != MAP_SCREEN && guiCurrentScreen != GAME_SCREEN) {
1701 				// If all fails, go to the map screen, this (almost) guarantees the game will start
1702 				guiPreviousOptionScreen = MAP_SCREEN;
1703 			} else {
1704 				guiPreviousOptionScreen = guiCurrentScreen;
1705 			}
1706 		}
1707 
1708 		BOOLEAN tmpSuccess = SaveGame(gGameSettings.bLastSavedGameSlot, gGameSettings.sCurrentSavedGameName);
1709 
1710 		// Reset the previous option screen
1711 		guiPreviousOptionScreen = tmpGuiPreviousOptionScreen;
1712 		if (tmpSuccess) return;
1713 
1714 		if (guiPreviousOptionScreen == MAP_SCREEN)
1715 		{
1716 			DoMapMessageBox(MSG_BOX_BASIC_STYLE, zSaveLoadText[SLG_SAVE_GAME_ERROR], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL);
1717 		} else
1718 		{
1719 			DoMessageBox(MSG_BOX_BASIC_STYLE, zSaveLoadText[SLG_SAVE_GAME_ERROR], GAME_SCREEN, MSG_BOX_FLAG_OK, NULL, NULL);
1720 		}
1721 	}
1722 }
1723 
1724 
DoQuickLoad()1725 void DoQuickLoad()
1726 {
1727 	// If there is no save in the quick save slot
1728 	InitSaveGameArray();
1729 	if (!gbSaveGameArray[0]) return;
1730 
1731 	// Set the selection to be the quick save slot
1732 	gbSelectedSaveLocation = 0;
1733 
1734 	StartFadeOutForSaveLoadScreen();
1735 	gfDoingQuickLoad = TRUE;
1736 }
1737 
1738 
AreThereAnySavedGameFiles()1739 bool AreThereAnySavedGameFiles()
1740 {
1741 	for (INT8 i = 0; i != (NUM_SAVE_GAMES_TABS * NUM_SAVE_GAMES); ++i)
1742 	{
1743 		char filename[512];
1744 		CreateSavedGameFileNameFromNumber(i, filename);
1745 		if (GCM->doesGameResExists(filename)) return true;
1746 	}
1747 	return false;
1748 }
1749 
1750 
RedrawSaveLoadScreenAfterMessageBox(MessageBoxReturnValue const bExitValue)1751 static void RedrawSaveLoadScreenAfterMessageBox(MessageBoxReturnValue const bExitValue)
1752 {
1753 	gfRedrawSaveLoadScreen = TRUE;
1754 }
1755 
1756 
MoveSelectionDown()1757 static void MoveSelectionDown()
1758 {
1759 	INT8 const slot = gbSelectedSaveLocation;
1760 	if (gfSaveGame)
1761 	{ // We are saving, any slot other then the quick save slot is valid
1762 		if (slot == -1)
1763 		{
1764 			SetSelection(1);
1765 		}
1766 		else if (slot < NUM_SAVE_GAMES - 1)
1767 		{
1768 			SetSelection(slot + 1);
1769 		}
1770 	}
1771 	else
1772 	{
1773 		for (INT32 i = slot != -1 ? slot + 1 : 0; i != NUM_SAVE_GAMES; ++i)
1774 		{
1775 			if (!gbSaveGameArray[i]) continue;
1776 			SetSelection(i);
1777 			break;
1778 		}
1779 	}
1780 }
1781 
1782 
MoveSelectionUp()1783 static void MoveSelectionUp()
1784 {
1785 	INT8 const slot = gbSelectedSaveLocation;
1786 	if (gfSaveGame)
1787 	{ // We are saving, any slot other then the quick save slot is valid
1788 		if (slot == -1)
1789 		{
1790 			SetSelection(NUM_SAVE_GAMES - 1);
1791 		}
1792 		else if (slot > 1)
1793 		{
1794 			SetSelection(slot - 1);
1795 		}
1796 	}
1797 	else
1798 	{
1799 		for (INT32 i = slot != -1 ? slot - 1 : NUM_SAVE_GAMES - 1; i >= 0; --i)
1800 		{
1801 			if (!gbSaveGameArray[i]) continue;
1802 			SetSelection(i);
1803 			break;
1804 		}
1805 	}
1806 }
1807 
1808 
ClearSelectedSaveSlot(void)1809 static void ClearSelectedSaveSlot(void)
1810 {
1811 	gbSelectedSaveLocation = -1;
1812 }
1813 
1814 
SaveGameToSlotNum(void)1815 static void SaveGameToSlotNum(void)
1816 {
1817 	//Redraw the save load screen
1818 	RenderSaveLoadScreen();
1819 
1820 	//render the buttons
1821 	MarkButtonsDirty( );
1822 	RenderButtons();
1823 
1824 	// If we are selecting the Dead is Dead Savegame slot, only remember the slot, do not save
1825 	// Also set the INTRO_SCREEN as previous options screen. This is a hack to get the game started
1826 	if (guiPreviousOptionScreen == GAME_INIT_OPTIONS_SCREEN)
1827 	{
1828 		guiPreviousOptionScreen = INTRO_SCREEN;
1829 		gGameSettings.bLastSavedGameSlot = (gbSelectedSaveLocation + NUM_SAVE_GAMES);
1830 		gGameSettings.sCurrentSavedGameName = gzGameDescTextField;
1831 	}
1832 	else if( !SaveGame(gbSelectedSaveLocation, gzGameDescTextField ) )
1833 	{
1834 		DoSaveLoadMessageBox(zSaveLoadText[SLG_SAVE_GAME_ERROR], SAVE_LOAD_SCREEN, MSG_BOX_FLAG_OK, NULL);
1835 	}
1836 
1837 	SetSaveLoadExitScreen( guiPreviousOptionScreen );
1838 }
1839 
1840 
StartFadeOutForSaveLoadScreen(void)1841 static void StartFadeOutForSaveLoadScreen(void)
1842 {
1843 	//if the game is paused, and we are in tactical, unpause
1844 	if( guiPreviousOptionScreen == GAME_SCREEN )
1845 	{
1846 		PauseTime( FALSE );
1847 	}
1848 
1849 	gFadeOutDoneCallback = DoneFadeOutForSaveLoadScreen;
1850 
1851 	FadeOutNextFrame( );
1852 	gfStartedFadingOut = TRUE;
1853 }
1854