////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 RWS Inc, All Rights Reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as published by
// the Free Software Foundation
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// game.h
// Project: Nostril (aka Postal)
//
// History:
//		12/02/96 MJR	Started.
//
//		01/31/97	JMI	Added g_resmgrGame for specific to actual game data.
//
//		01/31/97	JMI	Added m_lTitleLoadLoops to settings.
//
//		02/03/97	JMI	Added NoSakDir directory for files when there is no SAK
//							to settings.
//
//		02/04/97	JMI	Added functions to get and set the gamma level.
//
//		02/13/97	JMI	Removed game level alpha XRay stuff (now setup in CHood).
//
//		02/21/97	JMI	Now sets gamma level on Save().
//							Also, added m_sUseCurrentDeviceDimensions to settings
//							indicating, if TRUE, not to change the current display
//							device mode.
//
//		03/24/97	JMI	Added m_dDegreesPerSec and m_sUseMouse to CGameSettings.
//
//		03/31/97	JMI	Moved CGameSettings definition to GameSettings.h and the
//							implementation to GameSettings.cpp.
//
//		04/11/97	JMI	Added Game_Menu_Demo() proto.
//
//		05/21/97	JMI	Added a resource manager for resources that are not SAKed.
//
//		06/12/97 MJR	Rewored the callbacks so that the game-specific code now
//							resides in this module rather than the menu module.
//
//		06/16/97	JMI	Added g_fontSmall.
//
//		06/18/97 MJR	Added SeedRandom() and GetRandom().
//
//		06/24/97	JMI	Added SynchLog() and associated macros.
//
//		07/03/97	JMI	Added Game_ControlsMenu().
//
//		07/11/97 BRH	Finished up the expiration date checking for the 
//							Registry.  Still need to add something for the Mac
//							version.  Verified that it works with different times
//							and dates.
//
//		07/13/97	JMI	Added Game_StartChallengeGame() proto.
//
//		07/18/97 BRH	Added game load and save functions so that the player's
//							game can be saved and loaded.  Also added a global
//							stockpile object used to transfer loaded/saved info to/from
//							the CDude's stockpile.
//
//		07/26/97	JMI	Added g_fontPostal to replace g_fontSmall.  Got rid of
//							g_fontSmall.
//
//		08/05/97	JMI	Added Game_AudioOptionsChoice().
//
//		08/12/97	JMI	Added SubPathOpenBox() (see proto for details) and
//							FullPathCustom().
//
//		08/14/97	JMI	Added psDifficulty parameter to Game_Save/LoadPlayersGame()
//							so they can query/modify realm difficulty.
//
//
//		08/15/97	JRD	Added a function to control brightness/contrast in place
//							of gamme.  This was because the gamma function could not
//							recreate a "normal palette."
//
//		08/15/97 JRD	Attempted to hook both brightness and contrast changes to
//							the old gamma slider with a crude algorithm.
//
//		08/20/97	JMI	Moved Game_LoadPlayersGame() proto into game.cpp b/c it
//							now takes an ACTION* but ACTION is defined in game.cpp and
//							since no one currently calls this function externally, what
//							the hell.
//
//		08/21/97 MJR	Added Game_HostMultiGame() and Game_JoinMultiGame().
//
//		08/21/97	JMI	Added rspUpdateDisplay() macros to flag these calls (they
//							should be calls to app level version -- UpdateDisplay() ).
//
//		08/22/97	JMI	Removed rspUpdateDisplay() macro b/c we don't need it now that
//							we're lock/unlocking correctly.
//
//		08/23/97	JMI	Added Game_InitMainMenu() so game.cpp can hook init/kill of
//							main menu.
//
//		10/07/97	JMI	Now GetRandom() uses the logging call in any TRACENASSERT
//							mode (used to be just in _DEBUG mode).
//
//		10/14/97	JMI	LOG() and if() no longer automatically call GetInstanceID()
//							(too many GetRand()s are called from non-CThings).  Now
//							LOG() has an additional argument for specifying the user
//							value which, of course, could be a call to GetInstanceID().
//
//		10/14/97	JMI	Made SynchLog()'s expr parameter a double instead of an int
//							for more accuracy.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef GAME_H
#define GAME_H

#include "RSPiX.h"

#ifdef PATHS_IN_INCLUDES
	#include "WishPiX/ResourceManager/resmgr.h"
#else
	#include "resmgr.h"
#endif

#include "settings.h"
#include "localize.h"
#include "GameSettings.h"
#include "StockPile.h"

#define ENGLISH_AUDIO	0
#define JAPANESE_AUDIO	1

#define NUM_AUDIO_LANGUAGES 2

////////////////////////////////////////////////////////////////////////////////
// Macros.
////////////////////////////////////////////////////////////////////////////////

// Global game settings
extern CGameSettings g_GameSettings;

// todo: magic numbers
// High scores
extern int32_t g_HighScores[23][8];

// Check for cookie flag
extern int32_t g_lCookieMonster;

// Global big font
extern RFont g_fontBig;

// Global Postal font.
extern RFont g_fontPostal;

// Global flag for end of level 
extern bool g_bLastLevelDemo;

// Resource manager for game resources.  These are resources used by the actual
// game, like things that a CThing loads that is not level specific.  For example,
// CBall loads, of course, foot.bmp, which would be loaded through this ResMgr.
// Note:  This resmgr should not be used for things like info on ordering, menu
// resources, g_fontBig, or anything not specific to the real game.
// Note:  Realm specifc data, such as alpha effects, etc., should be loaded
// through prealm->m_resmgr.
extern RResMgr	g_resmgrGame;

// Resource manager for shell resources.  Do not use this to load things like
// the main dudes' sprites.
extern RResMgr	g_resmgrShell;

// Resource manager for non-SAK resources.
extern RResMgr	g_resmgrRes;

// Time codes for registry values and expiration date
extern int32_t g_lRegTime;
extern int32_t g_lRegValue;
extern int32_t g_lExpTime;
extern int32_t g_lExpValue;
extern int32_t g_lReleaseTime;

// Loaded and saved games use this stockpile to transfer to/from the
// dude's stockpile
extern CStockPile	g_stockpile[4];
extern bool       g_bTransferStockpile;
extern int16_t	   g_sRealmNumToSave;

// todo:

typedef struct
{	
	// Game
	int8_t 	cHudMode;
	int8_t	cRumbleStrength;
	int8_t 	sActiveCoopPlayers;
	int8_t 	sPlayerColorIndex;
	int8_t 	sDifficulty[2];
	int16_t sAction[2];
	int16_t sRealmNum[2];	
	uint32_t ulUnlockedLevels;	
	// Stockpile
	int16_t	sStockPileHitPoints[5];
	int16_t	sStockPileNumGrenades[5];
	int16_t	sStockPileNumFireBombs[5];
	int16_t	sStockPileNumMissiles[5];
	int16_t	sStockPileNumNapalms[5];
	int16_t	sStockPileNumBullets[5];
	int16_t	sStockPileNumShells[5];	
	int16_t	sStockPileNumFuel[5];
	int16_t	sStockPileNumMines[5];
	int16_t	sStockPileNumHeatseekers[5];
	int16_t	sStockPileMachineGun[5];
	int16_t	sStockPileMissileLauncher[5];
	int16_t	sStockPileShotGun[5];
	int16_t	sStockPileSprayCannon[5];
	int16_t	sStockPileFlameThrower[5];
	int16_t	sStockPileNapalmLauncher[5];
	int16_t	sStockPileDeathWadLauncher[5];
	int16_t	sStockPileDoubleBarrel[5];
	int16_t	sStockPileKevlarLayers[5];
	int16_t	sStockPileBackpack[5];
	// Audio
	int8_t sAudioLanguage;
	int8_t sPainFrequency;
	int16_t sCategoryVolume[10];
	// Controlsets
	int8_t sControllerSet[4];
	// High scores
	int32_t lHighScores[23][8];
} GameSave;

#define SAVE_FILE_NAME 				"POSTAL"
#define SAVE_FILE_BLOCKS			3
#define FLAG_SAVE_ALL 				(1<<0)
#define FLAG_SAVE_UNLOCKED_LEVELS	(1<<1)
#define FLAG_SAVE_HIGHSCORES		(1<<2)
#define FLAG_SAVE_PREFS				(1<<3)
#define PLAYER_1 (1<<0)
#define PLAYER_2 (1<<1)
#define PLAYER_3 (1<<2)
#define PLAYER_4 (1<<3)
#define MAX_DUDES 4

extern volatile GameSave g_SaveGameState[5];
extern volatile int8_t g_sSaveGameSlot;
extern volatile int8_t g_cPlayerCount;
extern volatile int8_t g_sActiveMenuController;
extern volatile int8_t g_cCoopPlayerColours[4];
extern volatile int8_t g_cLastPlayerToDie;
extern volatile int8_t g_sActivePlayers;
extern volatile int8_t g_sPlayerFlags[4];
extern volatile int8_t g_sPlayerScorePos;
extern volatile bool g_bAllCoopPlayersDead;
extern volatile bool g_bLimitMenuInput;
extern volatile bool g_bResetCamera;
extern volatile bool g_bHighScoreUpdated;
extern volatile bool g_bSaveHighScore;

extern volatile const uint8_t g_pVmuImgData[192];
extern volatile const uint16_t g_pSaveIconPalData[16];
extern volatile const uint8_t g_pSaveIconImgData[512];

////////////////////////////////////////////////////////////////////////////////
//
// Do the high-level startup stuff, run the game, and then cleanup afterwards.
//
// It is assumed that the system/RSPiX environment are setup properly before
// this function is called.
//
////////////////////////////////////////////////////////////////////////////////
extern void TheGame(void);


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Start Single Player Game" menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_StartSinglePlayerGame(
	int16_t sMenuItem);


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Start MultiPlayer Game" menu
//
////////////////////////////////////////////////////////////////////////////////
extern bool Game_StartMultiPlayerGame(
	int16_t sMenuItem);


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Join MultiPlayer Game" menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_JoinMultiPlayerGame(
	int16_t sMenuItem);


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Host MultiPlayer Game" menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_HostMultiPlayerGame(
	int16_t sMenuItem);

////////////////////////////////////////////////////////////////////////////////
//
// Callback for the Main Menu init/kill.
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_InitMainMenu(	// Returns nothing.
	int16_t sInit);						// In:  TRUE, if initializing; FALSE, if killing.


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Start Demo Game" menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_StartDemoGame(
	int16_t sMenuItem);


////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Editor" option on the Main Menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_StartEditor(void);

////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Buy" option on the Main Menu
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_Buy(void);

////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Controls" menu.
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_ControlsMenu(	// Returns nothing.
	int16_t sMenuItem);					// In:  Chosen menu item.

////////////////////////////////////////////////////////////////////////////////
//
// Callback for the "Start Challenge" menu.
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_StartChallengeGame(	// Returns nothing.
	int16_t sChallengeNum);				// In: Path to Challenge realm

////////////////////////////////////////////////////////////////////////////////
//
// Callback for "Audio Options" menu.
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_AudioOptionsChoice(	// Returns nothing.
	int16_t sMenuItem);							// In:  Chosen item.


////////////////////////////////////////////////////////////////////////////////
//
// Save game settings of the current level so that play can continue on this
//	level.
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t Game_SavePlayersGame(
				MAPLE::cMapleVmu* pMemoryCard,	// Returns SUCCESS if all goes well
				int8_t cSlotNumber,	// In: The save file slot number
				char* pszSaveName,		// In:  Name of the save file
				int8_t sDifficulty,
				int16_t sSaveFlags = FLAG_SAVE_ALL);		// In:  Current realm difficulty.

extern int16_t Game_SavePlayersPrefs(
				MAPLE::cMapleVmu* pMemoryCard,	// Returns SUCCESS if all goes well
				int8_t cSlotNumber,	// In: The save file slot number
				char* pszSaveName		// In:  Name of the save file				
				);		// In:  Current realm difficulty.

extern int16_t Game_SavePlayerHighScores(
				MAPLE::cMapleVmu* pMemoryCard,	// Returns SUCCESS if all goes well
				int8_t cSlotNumber,	// In: The save file slot number
				char* pszSaveName	// In:  Name of the save file				
				);		// In:  Current realm difficulty.

////////////////////////////////////////////////////////////////////////////////
//
// Seed the random number generator
//
////////////////////////////////////////////////////////////////////////////////
#define SeedRand SeedRandom
extern void SeedRandom(
	int32_t lSeed);


////////////////////////////////////////////////////////////////////////////////
//
// Get a random number
//
////////////////////////////////////////////////////////////////////////////////
#define GetRand GetRandom

#if defined(_DEBUG) || defined(TRACENASSERT)

	#define GetRandom()	GetRandomDebug(__FILE__, __LINE__)
	extern int32_t GetRandomDebug(char* FILE_MACRO, int32_t LINE_MACRO);

#else

	extern int32_t GetRandom(void);

#endif	// defined(_DEBUG) || defined(TRACENASSERT)

////////////////////////////////////////////////////////////////////////////////
// Synchronization logger -- Call this function to log an expression and a user
// value in the synch log.  When active (if g_GameSettings.m_szSynchLog is
// a valid path and filename), if recording a demo, these calls are logged to
// a file including the calling file and line number.  When active, if playing
// back a demo, these calls are compared to those stored in the log and, if
// a discrepancy occurs, a modal dialog box will pop up with the pertinent info
// followed by an ASSERT(0) for easy debugging.
////////////////////////////////////////////////////////////////////////////////
extern int SynchLog(		// Result of expr.
	double	expr,			// In:  Expression to evaluate.
	char*		pszFile,		// In:  Calling file.
	int32_t		lLine,		// In:  Calling line.
	char*		pszExpr,		// In:  Original C++ source expression.
	U32		u32User);	// In:  A user value that is intended to be consistent.

////////////////////////////////////////////////////////////////////////////////
// If 'LOG_IFS' macro is defined, this will redefine 'if' such that it will 
// still perform its comparison but will also SynchLog() the expression.
////////////////////////////////////////////////////////////////////////////////
#if defined(LOG_IFS)
	#define if(expr)		if (SynchLog(double(expr != 0), __FILE__, __LINE__, #expr, 0 ) )
#endif

////////////////////////////////////////////////////////////////////////////////
// If 'LOG_LOGS' macro is defined, this will define 'LOG' such that it will 
// SynchLog() the expression.
// If the macro is not defined, this macro expands into absolutely nothing using
// no CPU time or memory.  Note that the expression will __NOT__ be evaluated
// at all.
////////////////////////////////////////////////////////////////////////////////
#if defined(LOG_LOGS)
	#define LOG(expr, user_val)		SynchLog(expr, __FILE__, __LINE__, #expr, user_val)
#else
	#define LOG(expr, user_val)
#endif

////////////////////////////////////////////////////////////////////////////////
//
// Do palette transition so menu can be displayed on top of existing background.
// NOTE: There must be a matching PalTranOff() for each PalTranOn()!!!
//
////////////////////////////////////////////////////////////////////////////////
extern void PalTranOn(
	int32_t lTime = -1);											// In:  How long transition should take (or -1 for default)


////////////////////////////////////////////////////////////////////////////////
//
// Undo the palette transition to restore the original background colors.
//
////////////////////////////////////////////////////////////////////////////////
extern void PalTranOff(void);


////////////////////////////////////////////////////////////////////////////////
//
// Create a full path out of a partial path.
//
// The partial path must be in "RSPiX neutral" format, which is pretty much
// like a partial Windows path, except with slashes instead of backslashes.
//
// BEWARE: The return value is a pointer to a static string, which means its
// contents are changed every time this function is called!  If you're just
// going to use the string and then be done with it, this should work fine, but
// if you need the string to stick around a while, you should probably do a
// strcpy() into your own string buffer.
//
// There are several variations - pick the one you like best.
//
////////////////////////////////////////////////////////////////////////////////

#define GAME_PATH_CD			0
#define GAME_PATH_HD			1
#define GAME_PATH_VD			2
#define GAME_PATH_SOUND		3
#define GAME_PATH_GAME		4
#define GAME_PATH_HOODS		5

extern char* FullPath(									// Returns full path in system format
	int16_t sPathType,										// In:  PATH_CD, PATH_HD, or PATH_VD
	char* pszPartialPath);								// In:  Partial path in RSPiX format

extern char* FullPathCD(								// Returns full path in system format
	char* pszPartialPath);								// In:  Partial path in RSPiX format

//extern char* FullPathHD(								// Returns full path in system format
	//const char* pszPartialPath);						// In:  Partial path in RSPiX format

extern char* FullPathVD(								// Returns full path in system format
	char* pszPartialPath);								// In:  Partial path in RSPiX format

extern char* FullPathSound(							// Returns full path in system format
	char* pszPartialPath);								// In:  Partial path in RSPiX format

extern char* FullPathGame(								// Returns full path in system format
	char* pszPartialPath);								// In:  Partial path in RSPiX format

extern char* FullPathHoods(							// Returns full path in system format
	char* pszPartialPath);								// In:  Partial path in RSPiX format

extern char* FullPathCustom(							// Returns full path in system format
	char*	pszFullPath,									// In:  Full path in in RSPiX format.
	char* pszPartialPath);								// In:  Partial path in RSPiX format.

////////////////////////////////////////////////////////////////////////////////
//
// Correctify the specified base path.
//
// First, it ensures that the path is absolute (not relative).  Then, it ensures
// the path ends properly, either with or without the system-specific separator
// character, depending on which system we're running on.
//
////////////////////////////////////////////////////////////////////////////////
int16_t CorrectifyBasePath(								// Returns 0 if successfull, non-zero otherwise
	char* pszBasePath,									// I/O: Base path to be corrected
	int16_t sMaxPathLen);									// In:  Maximum length of base path

////////////////////////////////////////////////////////////////////////////////
//
// Get a subpath relative to the specified game path.
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t SubPathOpenBox(		// Returns 0 on success, negative on error, 1 if 
											// not subpathable (i.e., returned path is full path).
	char*	pszFullPath,				// In:  Full path to be relative to.
	char* pszBoxTitle,				// In:  Title of box.
	char*	pszDefFileName,			// In:  Default filename.
	char* pszChosenFileName,		// Out: User's choice.
	int16_t sStrSize,					// In:  Amount of memory pointed to by pszChosenFileName.
	char*	pszFilter = NULL);		// In:  If not NULL, '.' delimited extension based filename
											//	filter specification.  Ex: ".cpp.h.exe.lib" or "cpp.h.exe.lib"
											// Note: Cannot use '.' in filter.  Preceding '.' ignored.

////////////////////////////////////////////////////////////////////////////////
//
// Set gamma/brighten-effect value.
//
////////////////////////////////////////////////////////////////////////////////
extern void SetGammaLevel(
	int16_t sBase);											// In:  New brighten value

////////////////////////////////////////////////////////////////////////////////
//
//	Set Brightness and Contrast.  Zero (neutral) values yield and identity
// curve.  Valid input is from -1 to 1.
//
////////////////////////////////////////////////////////////////////////////////
extern	void	SetBrightnessContrast(
						double dBrightness,	// -1.0 = dim, 0.0 = normal, 1.0 = bright
						double dContrast		// -1.0 = low contrast, 0.0 = normal, 1.0 = high
						);

////////////////////////////////////////////////////////////////////////////////
//
// Get gamma/brighten-effect value from palette map (not from settings).
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t GetGammaLevel(void);					// Returns current brighten value


// todo
extern void SetPal60(bool bMode = false);
extern void SetLanguage(int8_t cLanguage);

////////////////////////////////////////////////////////////////////////////////
//
// Callback for the Level Select
//
////////////////////////////////////////////////////////////////////////////////
extern void Game_StartLevelOnce(
	int16_t sMenuItem);

////////////////////////////////////////////////////////////////////////////////
// Returns Title of a given Challenge-ID
////////////////////////////////////////////////////////////////////////////////
extern char* GetChallengeTitle(
	int16_t challengeID);


// todo:
extern void Game_InitSaveFile();
extern bool Game_ReadGlobalSaveStates();

extern int32_t playthroughMS;

#endif // GAME_H
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
