gameloop.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #ifdef PRECOMPILEDHEADERS
  2. #include "JA2 All.h"
  3. #include "HelpScreen.h"
  4. #include "Prebattle Interface.h"
  5. #else
  6. #include <stdio.h>
  7. #include "sgp.h"
  8. #include "Gameloop.h"
  9. #include "Screens.h"
  10. #include "Wcheck.h"
  11. #include "cursors.h"
  12. #include "init.h"
  13. #include "music control.h"
  14. #include "sys globals.h"
  15. #include "laptop.h"
  16. #include "mapscreen.h"
  17. #include "Game Clock.h"
  18. #include "Timer Control.h"
  19. #include "overhead.h"
  20. #include "LibraryDataBase.h"
  21. #include "Map Screen Interface.h"
  22. #include "Tactical Save.h"
  23. #include "Interface.h"
  24. #include "GameSettings.h"
  25. #include "mapscreen.h"
  26. #include "Interface Control.h"
  27. #include "fade screen.h"
  28. #include "JA2 Demo Ads.h"
  29. #include "text.h"
  30. #include "HelpScreen.h"
  31. #endif
  32. UINT32 guiCurrentScreen;
  33. UINT32 guiPendingScreen = NO_PENDING_SCREEN;
  34. UINT32 guiPreviousScreen = NO_PENDING_SCREEN;
  35. INT32 giStartingMemValue = 0;
  36. #define DONT_CHECK_FOR_FREE_SPACE 255
  37. UINT8 gubCheckForFreeSpaceOnHardDriveCount=DONT_CHECK_FOR_FREE_SPACE;
  38. extern BOOLEAN DoSkiMessageBox( UINT8 ubStyle, INT16 *zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback );
  39. extern void NotEnoughHardDriveSpaceForQuickSaveMessageBoxCallBack( UINT8 bExitValue );
  40. extern BOOLEAN gfTacticalPlacementGUIActive;
  41. extern BOOLEAN gfTacticalPlacementGUIDirty;
  42. extern BOOLEAN gfValidLocationsChanged;
  43. extern BOOLEAN gfInMsgBox;
  44. // callback to confirm game is over
  45. void EndGameMessageBoxCallBack( UINT8 bExitValue );
  46. void HandleNewScreenChange( UINT32 uiNewScreen, UINT32 uiOldScreen );
  47. // The InitializeGame function is responsible for setting up all data and Gaming Engine
  48. // tasks which will run the game
  49. #ifdef JA2BETAVERSION
  50. BOOLEAN gubReportMapscreenLock = 0;
  51. void ReportMapscreenErrorLock()
  52. {
  53. switch( gubReportMapscreenLock )
  54. {
  55. case 1:
  56. DoScreenIndependantMessageBox( L"You have just loaded the game which is in a state that you shouldn't be able to. You can still play, but there should be a sector with enemies co-existing with mercs. Please don't report that.", MSG_BOX_FLAG_OK, NULL );
  57. fDisableDueToBattleRoster = FALSE;
  58. fDisableMapInterfaceDueToBattle = FALSE;
  59. gubReportMapscreenLock = 0;
  60. break;
  61. case 2:
  62. DoScreenIndependantMessageBox( L"You have just saved the game which is in a state that you shouldn't be able to. Please report circumstances (ex: merc in other sector pipes up about enemies), etc. Autocorrected, but if you reload the save, don't report the error appearing in load.", MSG_BOX_FLAG_OK, NULL );
  63. fDisableDueToBattleRoster = FALSE;
  64. fDisableMapInterfaceDueToBattle = FALSE;
  65. gubReportMapscreenLock = 0;
  66. break;
  67. }
  68. }
  69. #endif
  70. BOOLEAN InitializeGame(void)
  71. {
  72. UINT32 uiIndex;
  73. giStartingMemValue = MemGetFree( );
  74. ClearAllDebugTopics();
  75. RegisterJA2DebugTopic( TOPIC_JA2OPPLIST, "Reg" );
  76. //RegisterJA2DebugTopic( TOPIC_MEMORY_MANAGER, "Reg" );
  77. // Initlaize mouse subsystems
  78. MSYS_Init( );
  79. InitButtonSystem();
  80. InitCursors( );
  81. // Init Fonts
  82. if ( !InitializeFonts( ) )
  83. {
  84. // Send debug message and quit
  85. DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "COULD NOT INUT FONT SYSTEM...");
  86. return( ERROR_SCREEN );
  87. }
  88. //Deletes all the Temp files in the Maps\Temp directory
  89. InitTacticalSave( TRUE );
  90. // Initialize Game Screens.
  91. for (uiIndex = 0; uiIndex < MAX_SCREENS; uiIndex++)
  92. {
  93. if ((*(GameScreens[uiIndex].InitializeScreen))() == FALSE)
  94. { // Failed to initialize one of the screens.
  95. return FALSE;
  96. }
  97. }
  98. //Init the help screen system
  99. InitHelpScreenSystem();
  100. //Loads the saved (if any) general JA2 game settings
  101. LoadGameSettings();
  102. //Initialize the Game options ( Gun nut, scifi and dif. levels
  103. InitGameOptions();
  104. // preload mapscreen graphics
  105. HandlePreloadOfMapGraphics( );
  106. guiCurrentScreen = INIT_SCREEN;
  107. return TRUE;
  108. }
  109. // The ShutdownGame function will free up/undo all things that were started in InitializeGame()
  110. // It will also be responsible to making sure that all Gaming Engine tasks exit properly
  111. void ShutdownGame(void)
  112. {
  113. // handle shutdown of game with respect to preloaded mapscreen graphics
  114. HandleRemovalOfPreLoadedMapGraphics( );
  115. ShutdownJA2( );
  116. //Save the general save game settings to disk
  117. SaveGameSettings();
  118. //shutdown the file database manager
  119. ShutDownFileDatabase( );
  120. //Deletes all the Temp files in the Maps\Temp directory
  121. InitTacticalSave( FALSE );
  122. }
  123. // This is the main Gameloop. This should eventually by one big switch statement which represents
  124. // the state of the game (i.e. Main Menu, PC Generation, Combat loop, etc....)
  125. // This function exits constantly and reenters constantly
  126. void GameLoop(void)
  127. {
  128. InputAtom InputEvent;
  129. POINT MousePos;
  130. UINT32 uiOldScreen=guiCurrentScreen;
  131. GetCursorPos(&MousePos);
  132. // Hook into mouse stuff for MOVEMENT MESSAGES
  133. MouseSystemHook(MOUSE_POS, (UINT16)MousePos.x ,(UINT16)MousePos.y ,_LeftButtonDown, _RightButtonDown);
  134. MusicPoll( FALSE );
  135. while (DequeueSpecificEvent(&InputEvent, LEFT_BUTTON_REPEAT|RIGHT_BUTTON_REPEAT|LEFT_BUTTON_DOWN|LEFT_BUTTON_UP|RIGHT_BUTTON_DOWN|RIGHT_BUTTON_UP ) == TRUE )
  136. {
  137. // HOOK INTO MOUSE HOOKS
  138. switch(InputEvent.usEvent)
  139. {
  140. case LEFT_BUTTON_DOWN:
  141. MouseSystemHook(LEFT_BUTTON_DOWN, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown);
  142. break;
  143. case LEFT_BUTTON_UP:
  144. MouseSystemHook(LEFT_BUTTON_UP, (INT16)MousePos.x, (INT16)MousePos.y ,_LeftButtonDown, _RightButtonDown);
  145. break;
  146. case RIGHT_BUTTON_DOWN:
  147. MouseSystemHook(RIGHT_BUTTON_DOWN, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown);
  148. break;
  149. case RIGHT_BUTTON_UP:
  150. MouseSystemHook(RIGHT_BUTTON_UP, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown);
  151. break;
  152. case LEFT_BUTTON_REPEAT:
  153. MouseSystemHook(LEFT_BUTTON_REPEAT, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown);
  154. break;
  155. case RIGHT_BUTTON_REPEAT:
  156. MouseSystemHook(RIGHT_BUTTON_REPEAT, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown);
  157. break;
  158. }
  159. }
  160. if ( gfGlobalError )
  161. {
  162. guiCurrentScreen = ERROR_SCREEN;
  163. }
  164. //if we are to check for free space on the hard drive
  165. if( gubCheckForFreeSpaceOnHardDriveCount < DONT_CHECK_FOR_FREE_SPACE )
  166. {
  167. //only if we are in a screen that can get this check
  168. if( guiCurrentScreen == MAP_SCREEN || guiCurrentScreen == GAME_SCREEN || guiCurrentScreen == SAVE_LOAD_SCREEN )
  169. {
  170. if( gubCheckForFreeSpaceOnHardDriveCount < 1 )
  171. {
  172. gubCheckForFreeSpaceOnHardDriveCount++;
  173. }
  174. else
  175. {
  176. // Make sure the user has enough hard drive space
  177. if( !DoesUserHaveEnoughHardDriveSpace() )
  178. {
  179. CHAR16 zText[512];
  180. CHAR16 zSpaceOnDrive[512];
  181. UINT32 uiSpaceOnDrive;
  182. CHAR16 zSizeNeeded[512];
  183. swprintf( zSizeNeeded, L"%d", REQUIRED_FREE_SPACE / BYTESINMEGABYTE );
  184. InsertCommasForDollarFigure( zSizeNeeded );
  185. uiSpaceOnDrive = GetFreeSpaceOnHardDriveWhereGameIsRunningFrom( );
  186. swprintf( zSpaceOnDrive, L"%.2f", uiSpaceOnDrive / (FLOAT)BYTESINMEGABYTE );
  187. swprintf( zText, pMessageStrings[ MSG_LOWDISKSPACE_WARNING ], zSpaceOnDrive, zSizeNeeded );
  188. if( guiPreviousOptionScreen == MAP_SCREEN )
  189. DoMapMessageBox( MSG_BOX_BASIC_STYLE, zText, MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
  190. else
  191. DoMessageBox( MSG_BOX_BASIC_STYLE, zText, GAME_SCREEN, MSG_BOX_FLAG_OK, NULL, NULL );
  192. }
  193. gubCheckForFreeSpaceOnHardDriveCount = DONT_CHECK_FOR_FREE_SPACE;
  194. }
  195. }
  196. }
  197. // ATE: Force to be in message box screen!
  198. if ( gfInMsgBox )
  199. {
  200. guiPendingScreen = MSG_BOX_SCREEN;
  201. }
  202. if ( guiPendingScreen != NO_PENDING_SCREEN )
  203. {
  204. // Based on active screen, deinit!
  205. if( guiPendingScreen != guiCurrentScreen )
  206. {
  207. switch( guiCurrentScreen )
  208. {
  209. case MAP_SCREEN:
  210. if( guiPendingScreen != MSG_BOX_SCREEN )
  211. {
  212. EndMapScreen( FALSE );
  213. }
  214. break;
  215. case LAPTOP_SCREEN:
  216. ExitLaptop();
  217. break;
  218. }
  219. }
  220. // if the screen has chnaged
  221. if( uiOldScreen != guiPendingScreen )
  222. {
  223. // Set the fact that the screen has changed
  224. uiOldScreen = guiPendingScreen;
  225. HandleNewScreenChange( guiPendingScreen, guiCurrentScreen );
  226. }
  227. guiCurrentScreen = guiPendingScreen;
  228. guiPendingScreen = NO_PENDING_SCREEN;
  229. }
  230. uiOldScreen = (*(GameScreens[guiCurrentScreen].HandleScreen))();
  231. // if the screen has chnaged
  232. if( uiOldScreen != guiCurrentScreen )
  233. {
  234. HandleNewScreenChange( uiOldScreen, guiCurrentScreen );
  235. guiCurrentScreen = uiOldScreen;
  236. }
  237. RefreshScreen( NULL );
  238. guiGameCycleCounter++;
  239. UpdateClock();
  240. #ifdef JA2BETAVERSION
  241. if( gubReportMapscreenLock )
  242. {
  243. ReportMapscreenErrorLock();
  244. }
  245. #endif
  246. }
  247. void SetCurrentScreen( UINT32 uiNewScreen )
  248. {
  249. guiCurrentScreen = uiNewScreen;
  250. (*(GameScreens[guiCurrentScreen].HandleScreen))();
  251. }
  252. void SetPendingNewScreen( UINT32 uiNewScreen )
  253. {
  254. guiPendingScreen = uiNewScreen;
  255. }
  256. // Gets called when the screen changes, place any needed in code in here
  257. void HandleNewScreenChange( UINT32 uiNewScreen, UINT32 uiOldScreen )
  258. {
  259. //if we are not going into the message box screen, and we didnt just come from it
  260. if( ( uiNewScreen != MSG_BOX_SCREEN && uiOldScreen != MSG_BOX_SCREEN ) )
  261. {
  262. //reset the help screen
  263. NewScreenSoResetHelpScreen( );
  264. }
  265. }
  266. void HandleShortCutExitState( void )
  267. {
  268. // look at the state of fGameIsRunning, if set false, then prompt user for confirmation
  269. // use YES/NO Pop up box, settup for particular screen
  270. SGPRect pCenteringRect= {0, 0, 640, INV_INTERFACE_START_Y };
  271. if( guiCurrentScreen == ERROR_SCREEN )
  272. { //an assert failure, don't bring up the box!
  273. gfProgramIsRunning = FALSE;
  274. return;
  275. }
  276. if( guiCurrentScreen == AUTORESOLVE_SCREEN )
  277. {
  278. DoMessageBox( MSG_BOX_BASIC_STYLE, pMessageStrings[ MSG_EXITGAME ], guiCurrentScreen, ( UINT8 ) ( MSG_BOX_FLAG_YESNO | MSG_BOX_FLAG_USE_CENTERING_RECT ), EndGameMessageBoxCallBack, &pCenteringRect );
  279. return;
  280. }
  281. /// which screen are we in?
  282. if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
  283. {
  284. // set up for mapscreen
  285. DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMessageStrings[ MSG_EXITGAME ], MAP_SCREEN, MSG_BOX_FLAG_YESNO, EndGameMessageBoxCallBack );
  286. }
  287. else if( guiCurrentScreen == LAPTOP_SCREEN )
  288. {
  289. // set up for laptop
  290. DoLapTopSystemMessageBox( MSG_BOX_LAPTOP_DEFAULT, pMessageStrings[ MSG_EXITGAME ], LAPTOP_SCREEN, MSG_BOX_FLAG_YESNO, EndGameMessageBoxCallBack );
  291. }
  292. else if( guiCurrentScreen == SHOPKEEPER_SCREEN )
  293. {
  294. DoSkiMessageBox( MSG_BOX_BASIC_STYLE, pMessageStrings[ MSG_EXITGAME ], SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, EndGameMessageBoxCallBack );
  295. }
  296. else
  297. {
  298. // check if error or editor
  299. #ifdef JA2BETAVERSION
  300. if ( guiCurrentScreen == AIVIEWER_SCREEN || guiCurrentScreen == QUEST_DEBUG_SCREEN )
  301. {
  302. // then don't prompt
  303. gfProgramIsRunning = FALSE;
  304. return;
  305. }
  306. #endif
  307. if( ( guiCurrentScreen == ERROR_SCREEN ) || ( guiCurrentScreen == EDIT_SCREEN ) || ( guiCurrentScreen == DEBUG_SCREEN ) )
  308. {
  309. // then don't prompt
  310. gfProgramIsRunning = FALSE;
  311. return;
  312. }
  313. // set up for all otherscreens
  314. DoMessageBox( MSG_BOX_BASIC_STYLE, pMessageStrings[ MSG_EXITGAME ], guiCurrentScreen, ( UINT8 ) ( MSG_BOX_FLAG_YESNO | MSG_BOX_FLAG_USE_CENTERING_RECT ), EndGameMessageBoxCallBack, &pCenteringRect );
  315. }
  316. }
  317. void EndGameMessageBoxCallBack( UINT8 bExitValue )
  318. {
  319. // yes, so start over, else stay here and do nothing for now
  320. if( bExitValue == MSG_BOX_RETURN_YES )
  321. {
  322. #ifdef JA2DEMOADS
  323. guiPendingScreen = DEMO_EXIT_SCREEN;
  324. SetMusicMode( MUSIC_MAIN_MENU );
  325. FadeOutNextFrame( );
  326. #else
  327. gfProgramIsRunning = FALSE;
  328. #endif
  329. }
  330. //If we are in the tactical placement gui, we need this flag set so the interface is updated.
  331. if( gfTacticalPlacementGUIActive )
  332. {
  333. gfTacticalPlacementGUIDirty = TRUE;
  334. gfValidLocationsChanged = TRUE;
  335. }
  336. return;
  337. }
  338. void NextLoopCheckForEnoughFreeHardDriveSpace()
  339. {
  340. gubCheckForFreeSpaceOnHardDriveCount = 0;
  341. }