////////////////////////////////////////////////////////////////////////////////
//
// 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
//
// GameSettings.cpp
// Project: Postal
//
// History:
//		03/31/97 JMI	Started.
//
//		03/31/97	JMI	Moved CGameSettings implementation from game.h to this 
//							file.
//
//		03/31/97	JMI	Now loads game play keys from prefs file.
//
//		04/07/97	JMI	Added m_szServerName and m_usServerPort.
//
//		04/08/97	JMI	Added m_szPlayerName and m_sPlayerColorIndex.
//
//		04/08/97	JMI	Changed defualt for m_usServerPort from 9999 to 61663.
//
//		04/11/97	JMI	No longer sets m_sClient and m_sServer in PreDemo().
//
//		04/14/97	JMI	Added TEMP flag m_bDontBlit to allow us to speed up the
//							Snap() call by not blitting.
//
//		04/21/97 MJR	Added m_pszRealm for the name of the realm prefs file.
//
//		04/22/97	JMI	Added m_sCanRecordDemos indicating something obscure.
//
//		05/15/97	JMI	Added m_sAlphaBlend and m_sXRayEffect.
//
//		05/19/97	JMI	Added m_sDisplayInfo.
//
//		05/22/97	JMI	Added m_s3dFog.
//
//		05/22/97	JMI	Added m_sParticleEffects.
//
//		06/03/97	JMI	Added m_lInitialDemoTimeOut and m_lPersistentDemoTimeOut.
//
//		06/09/97	JMI	Added m_sCanTakeSnapShots.
//
//		06/09/97	JMI	Added m_sCrossHair.
//
//		06/11/97	JMI	Added m_szDontShowTitles.
//
//		06/12/97 MJR	Renamed m_pszRealm to m_pszRealmPrefsFile.
//							Removed m_sServer and m_sClient and m_sDemo.
//							Everything now sets defaults in constructor instead of
//							some things doing it in the Load() portion.
//
//		06/13/97 MJR	Removed m_bDontBlit and cleaned up the loads and saves
//							and made sure everything defaulted properly.
//
//		06/16/97 MJR	Added m_pszDemoMovie.
//							Added m_sNetGetInputInterval
//							Added m_sNetSendInputInterval.
//							Added m_sNetMaxFrameLag.
//							Added m_sNetTimePerFrame.
//
//					MJR	Added m_lNetMaxBlockingTime.
//							Added m_sNetUsersMaxPlayers;
//
//					JMI	Added m_sTrickySystemQuit.
//
//		06/17/97 MJR	Added m_lNetForceAbortTime.
//
//					MJR	Modified to call newer version of CorrectifyBasePath().
//
//		06/19/97	JMI	Added m_sResetMPScoresEachLevel.
//
//		06/23/97	JMI	Added m_szSynchLogFile.
//
//		07/07/97	JMI	Added m_dGameFilmScale and m_dEditorFilmScale.
//
//		07/07/97	JMI	Removed m_dEditorFilmScale and added m_sEditorViewWidth
//							and m_sEditorViewHeight.
//
//		07/08/97 MJR	Added use of separate section ("MacPaths") for mac paths.
//
//		07/16/97	JMI	Changed m_lTitleLoadLoops to m_lTitleDuration.
//
//		07/17/97	JMI	Now saves and loads volume category settings.
//
//		07/20/97	JMI	Added m_sVolumeDistance and m_sGripZoneRadius.
//							Also, now saves m_sDisplayInfo.
//
//		07/23/97 BRH	Changed title durations so that each title screen
//							can have its own duration time rather than splitting
//							it up evenly across all title screens.
//
//		08/03/97 BRH	Added m_usProtocol to be loaded and saved in the ini
//							file.
//
//		08/04/97	JMI	Added m_sPlayAmbientSounds.
//
//		08/05/97	JMI	Added m_eNetConnectionType and 
//							ms_apszNetConnectionTypeNames[].
//
//		08/11/97 MJR	Added m_szHostName and modified connection types and text.
//
//		08/13/97	JMI	PreDemo() now uses difficulty level 10.
//
//		08/18/97 MJR	Lots of changes to network-related stuff.
//
//		08/20/97 BRH	Added Sound, Game and Hoods paths to give more 
//							installation options.
//
//		08/23/97	JMI	Added ms_apszPlayerColorDescriptions[] to provide color
//							descriptions and ms_sNumPlayerColorDescriptions.
//
//		08/24/97	JMI	Editor width and height now default to 640 and 480.
//
//		08/25/97	JMI	Changed some of the color descriptors.
//
//		08/25/97	JMI	Now includes the m_eCurSoundQuality enum representing the
//							game's current sound quality.
//							Also, now sets all the default volumes to one value and
//							stores all values from 0 to the UserMaxVolume instead of
//							in the 0..MaxVolume scale samplemaster uses.
//
//		09/06/97 MJR	Clamped net values to valid ranges.
//
//		09/07/97 MJR	Now defaults to 2 for network lag.
//
//////////////////////////////////////////////////////////////////////////////
//
// Implementation for CGameSettings object.  Each instance contains settings
// for Postal.
//
//////////////////////////////////////////////////////////////////////////////

#include "RSPiX.h"
#include "GameSettings.h"
#include "game.h"
#include "SampleMaster.h"
#include "localize.h"
#include "dude.h"	// For MaxTextures.

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

// Determines the number of elements in the passed array at compile time.
#define NUM_ELEMENTS(a)					(sizeof(a) / sizeof(a[0]) )

// Clamp the specified value so it's between min and max, inclusive
template <class T>
inline T CLAMP(T val, T min,T max)
	{
	if (val < min)
		val = min;
	if (val > max)
		val = max;
	return val;
	}


//////////////////////////////////////////////////////////////////////////////
// Instantiate static members.
//////////////////////////////////////////////////////////////////////////////

// Player color descriptions.
char*	CGameSettings::ms_apszPlayerColorDescriptions[CDude::MaxTextures + 1][6] =
	{

	{"Black", "Schwarz", "Noir", "Negro", "Zwart", "Nero"},
	{"Green", "Grun", "Vert", "Verde", "Groene", "Verde"},
	{"Blue", "Blau", "Bleu", "Azul", "Blauw", "Blu"},
	{"Gray", "Grau", "Gris", "Gris", "Grijs", "Grigio"},
	{"Brown", "Braun", "Brun", "Marron", "Bruin", "Marrone"}, // todo: Accent marrón
	{"Red", "Rot", "Rouge", "Rojo", "Rood", "Rosso"},
	{"Tan", "Beige", "Beige", "Beige", "Beige", "Beige"},
	{"Purple", "Lila", "Violet", "Morado", "Purper", "Viola"},
	// Add new colors above this line.
	{"Error", "Error", "Error"}	// Try to catch errors.
	};

// Number of color descriptions.
const	int16_t CGameSettings::ms_sNumPlayerColorDescriptions	= NUM_ELEMENTS(ms_apszPlayerColorDescriptions) - 1;


char*	CGameSettings::ms_apszAudioLanguageDescriptions[3][6]	=
{	
	{
		g_pszAudioMenu_English[0],
		g_pszAudioMenu_English[1],
		g_pszAudioMenu_English[2],		
		g_pszAudioMenu_English[3],
		g_pszAudioMenu_English[4],
		g_pszAudioMenu_English[5],
	},
	{
		g_pszAudioMenu_Japanese[0],
		g_pszAudioMenu_Japanese[1],
		g_pszAudioMenu_Japanese[2],
		g_pszAudioMenu_Japanese[3],
		g_pszAudioMenu_Japanese[4],
		g_pszAudioMenu_Japanese[5],
	},
	{		
		"Error",	// Try to catch errors.
		"Error",	// Try to catch errors.
		"Error",	// Try to catch errors.
		"Error",	// Try to catch errors.
		"Error",	// Try to catch errors.
		"Error"		// Try to catch errors.
	},	
};

//////////////////////////////////////////////////////////////////////////////
// Set settings to default values
//////////////////////////////////////////////////////////////////////////////
CGameSettings::CGameSettings(void)
	{
	m_pszCDPath[0]					= 0;
	m_pszHDPath[0]					= 0;
	m_pszVDPath[0]					= 0;
	m_pszSoundPath[0]				= 0;
	m_pszGamePath[0]				= 0;
	m_pszHoodsPath[0]				= 0;
	m_szNoSakDir[0]				= 0;
	m_pszRealmPrefsFile[0]		= 0;
										
	m_sDifficulty					= 5;
	m_sViolence						= 11;
	m_sCrossHair					= TRUE;
	
	m_cHudMode = rspIsVGA() ? 0 : 1;
	m_cCutSceneUnderscan = false;
	m_cRumbleStrength = 1;

	m_sViewX = 0;
	m_sViewY = 0;
	m_sViewW = 640;	
	m_sFilmX = 0;	

	// todo:
	switch (m_cHudMode)
	{
		case 0:						
			m_sViewH = 400;
			m_sFilmY = 40;
			break;
		case 1:
			m_sViewH = 440;			
			m_sFilmY = 40;
			break;
	}
	
	m_cActiveLanguage = 0;
	m_bLimitedSampleTesters = false;

#if LOCALE == JAPAN
	m_sAudioLanguage = JAPANESE_AUDIO;
#else
	m_sAudioLanguage = ENGLISH_AUDIO;
#endif

	m_sPainFrequency = 8;
	m_ulUnlockedLevels = 1114113; // first levels of original, SD and Plus

/*** 01/14/98 SPA ***/
// todo: most of these aren't used - hard code the rest?
	m_lInitialDemoTimeOut		= 10000;
	m_lPersistentDemoTimeOut	= 60000;
	m_sCanRecordDemos				= FALSE;
	m_szDemoDebugMovie[0]		= 0;
	m_sNumAvailableDemos			= 0;

	m_sGammaVal						= 128;
	m_sUseCurrentDeviceDimensions = 0;

	m_sAlphaBlend					= TRUE;
	m_sXRayEffect					= TRUE;					
	m_s3dFog							= TRUE;
	m_sParticleEffects			= TRUE;
	m_sVolumeDistance				= TRUE;
	m_sPlayAmbientSounds			= TRUE;
										
	m_sDisplayInfo					= FALSE;
										
	m_sCanTakeSnapShots			= FALSE;
										
	m_szDontShowTitles[0]		= 0;

	m_sTrickySystemQuit			= FALSE;

	m_szSynchLogFile[0]			= '\0';

	m_dGameFilmScale				= 1.0;	// 100%
	
	m_sEditorViewWidth			= 640;
	m_sEditorViewHeight			= 480;

	m_sGripZoneRadius				= 75;

	m_eCurSoundQuality			= SampleMaster::SQ_22050_8;

	// Initialize all category volumes.
	int16_t i;
	for (i = 0; i < SampleMaster::MAX_NUM_SOUND_CATEGORIES; i++)
		{
		m_asCategoryVolumes[i] = SampleMaster::UserDefaultVolume;
		}
	}


//////////////////////////////////////////////////////////////////////////////
// Destructor
//////////////////////////////////////////////////////////////////////////////
CGameSettings::~CGameSettings()
	{
	}


//////////////////////////////////////////////////////////////////////////////
// Read settings that are stored in preference file
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::LoadPrefs(
	RPrefs* pPrefs)
	{
	int16_t sResult = 0;

	pPrefs->GetVal("Paths", "CD", "", m_pszCDPath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszCDPath, ".");
#endif
		
	sResult = (strlen(m_pszCDPath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszCDPath, sizeof(m_pszCDPath));	
	
	pPrefs->GetVal("Paths", "HD", "", m_pszHDPath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszHDPath, ".");
#endif

	//TODO?
	strcpy(m_pszHDPath, "/cd");


	sResult = (strlen(m_pszHDPath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszHDPath, sizeof(m_pszHDPath));	

	pPrefs->GetVal("Paths", "VD", "", m_pszVDPath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszVDPath, ".");
#endif
	sResult = (strlen(m_pszVDPath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszVDPath, sizeof(m_pszVDPath));

	pPrefs->GetVal("Paths", "Sound", "", m_pszSoundPath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszSoundPath, ".");
#endif
	sResult = (strlen(m_pszSoundPath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszSoundPath, sizeof(m_pszSoundPath));	

	pPrefs->GetVal("Paths", "Game", "", m_pszGamePath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszGamePath, ".");
#endif
	sResult = (strlen(m_pszGamePath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszGamePath, sizeof(m_pszGamePath));
	
	pPrefs->GetVal("Paths", "Hoods", "", m_pszHoodsPath);
#if defined(PANDORA) || defined(ODROID)
	strcpy(m_pszHoodsPath, ".");
#endif
	sResult = (strlen(m_pszHoodsPath) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_pszHoodsPath, sizeof(m_pszHoodsPath));	

	pPrefs->GetVal("Paths", "NoSakDir", "", m_szNoSakDir);
	sResult = (strlen(m_szNoSakDir) + 1) <= RSP_MAX_PATH ? 0 : -1;
	if (sResult == 0)
		sResult = CorrectifyBasePath(m_szNoSakDir, sizeof(m_szNoSakDir));	

	pPrefs->GetVal("Realms", "File", "", m_pszRealmPrefsFile);
	if (strlen(m_pszRealmPrefsFile) == 0)
		{
		sResult = -1;		
		}
	else if ((strlen(m_pszRealmPrefsFile) + 1) >= RSP_MAX_PATH)
		{
		sResult = -1;		
		}

	pPrefs->GetVal("Game", "RecentDifficulty", m_sDifficulty, &m_sDifficulty);
	if (m_sDifficulty < 0)
		m_sDifficulty = 0;
	if (m_sDifficulty > 11)
		m_sDifficulty = 11;
	pPrefs->GetVal("Game", "RecentViolence", m_sViolence, &m_sViolence);
	if (m_sViolence < 0)
		m_sViolence = 0;
	if (m_sViolence > 11)
		m_sViolence = 11;
	pPrefs->GetVal("Game", "UseCrossHair", m_sCrossHair, &m_sCrossHair);
	
	pPrefs->GetVal("Audio", "AudioLanguage", m_sAudioLanguage, &m_sAudioLanguage);
	if (m_sAudioLanguage < 0 || m_sAudioLanguage >= NUM_AUDIO_LANGUAGES)
	{
		#if LOCALE == JAPAN
			m_sAudioLanguage = JAPANESE_AUDIO;
		#else
			m_sAudioLanguage = ENGLISH_AUDIO;
		#endif
	}

	pPrefs->GetVal("Audio", "PainFrequency", m_sPainFrequency, &m_sPainFrequency);
	// clamp pain frequency value to allowed range
	if (m_sPainFrequency < 1)
		{
		m_sPainFrequency = 1;
		}
	else if (m_sPainFrequency > 16)
		{
		m_sPainFrequency = 16;
		}
	#ifdef KID_FRIENDLY_OPTION
	if (m_sAprilFools == TRUE)
	{
		// As per Rich's request, the Kid Mode option is available to
		// everyone on April Fool's Day, and on every other day, only to
		// those who have completed the full campaign ("ALL LEVELS").
		// It defaults to on on April Fool's, and off when it is
		// unlocked via beating the campaign. Since we always want it to
		// be automatically enabled on April Fool's, but we don't want
		// this to interfere with the user's choice on other days, AND
		// we don't want the option to be automatically re-enabled if
		// they disable it and then restart the game on April Fool's,
		// the best way I can think of to handle these situations is to
		// keep track of the setting in a separate variable on April
		// Fool's Day. I guess the other possibility is to force it to
		// be enabled on April Fool's...
		pPrefs->GetVal("Game", "KidModeAprilFools", m_sKidMode, &m_sKidMode);
	} else {
		pPrefs->GetVal("Game", "KidMode", m_sKidMode, &m_sKidMode);
	}
	pPrefs->GetVal("Game", "CompletedAllLevelsMode", m_sCompletedAllLevelsMode, &m_sCompletedAllLevelsMode);
	#endif

	pPrefs->GetVal("Game", "UnlockedLevels", m_ulUnlockedLevels, &m_ulUnlockedLevels);
	
	// todo:
	pPrefs->GetVal("Multiplayer", "Color", m_sPlayerColorIndex, &m_sPlayerColorIndex);
		
	pPrefs->GetVal("Demo", "InitialTimeOut", m_lInitialDemoTimeOut, &m_lInitialDemoTimeOut);
	pPrefs->GetVal("Demo", "PersistentTimeOut", m_lPersistentDemoTimeOut, &m_lPersistentDemoTimeOut);
	pPrefs->GetVal("Demo", "CanRecordDemos", m_sCanRecordDemos, &m_sCanRecordDemos);
	pPrefs->GetVal("Demo", "DemoDebugMovie", m_szDemoDebugMovie, m_szDemoDebugMovie);
	pPrefs->GetVal("Demo", "NumAvailable", m_sNumAvailableDemos, &m_sNumAvailableDemos);

	int16_t i;
	char szDurationName[100];
	for (i = 0; i < MAX_TITLE_SCREENS; i++)
	{
		sprintf(szDurationName, "Duration%d", i+1);
		pPrefs->GetVal("Title", szDurationName, 3000, &(m_alTitleDurations[i]));
	}

	pPrefs->GetVal("Video", "GammaVal", m_sGammaVal, &m_sGammaVal);
	pPrefs->GetVal("Video", "UseCurrentDeviceDimensions", m_sUseCurrentDeviceDimensions, &m_sUseCurrentDeviceDimensions);
	pPrefs->GetVal("Video", "GameFilmScale", m_dGameFilmScale, &m_dGameFilmScale);
	pPrefs->GetVal("Video", "EditorViewWidth", m_sEditorViewWidth, &m_sEditorViewWidth);
	pPrefs->GetVal("Video", "EditorViewHeight", m_sEditorViewHeight, &m_sEditorViewHeight);

	pPrefs->GetVal("Features", "AlphaBlend", m_sAlphaBlend, &m_sAlphaBlend);
	pPrefs->GetVal("Features", "XRayEffect", m_sXRayEffect, &m_sXRayEffect);
	pPrefs->GetVal("Features", "3DLighting", m_s3dFog, &m_s3dFog);
	pPrefs->GetVal("Features", "ParticleEffects", m_sParticleEffects, &m_sParticleEffects);
	pPrefs->GetVal("Features", "VolumeDistance", m_sVolumeDistance, &m_sVolumeDistance);
	pPrefs->GetVal("Features", "PlayAmbientSounds", m_sPlayAmbientSounds, &m_sPlayAmbientSounds);

	pPrefs->GetVal("Debug", "DisplayInfo", m_sDisplayInfo, &m_sDisplayInfo);
	pPrefs->GetVal("Debug", "IfLog", m_szSynchLogFile, m_szSynchLogFile);

	pPrefs->GetVal("Can", "TakeSnapShots", m_sCanTakeSnapShots, &m_sCanTakeSnapShots);

	pPrefs->GetVal("Title", "DontShow", m_szDontShowTitles, m_szDontShowTitles);

	pPrefs->GetVal("Shell", "TrickySystemQuit", m_sTrickySystemQuit, &m_sTrickySystemQuit);

	/*for (i = 0; i < SampleMaster::MAX_NUM_SOUND_CATEGORIES; i++)
		{
		pPrefs->GetVal("Volumes", SampleMaster::ms_apszSoundCategories[i], SampleMaster::UserDefaultVolume, &m_asCategoryVolumes[i]);
		}*/

	// Verify we're in bounds.
	if (m_sPlayerColorIndex >= CDude::MaxTextures || m_sPlayerColorIndex < 0)
		{
		m_sPlayerColorIndex	= 0;
		}

	if (!sResult)
		{
		if (pPrefs->IsError())
			sResult = -1;
		}

	return sResult;
	}


//////////////////////////////////////////////////////////////////////////////
// Write settings that are stored in preference file
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::SavePrefs(
	RPrefs* pPrefs)
	{
	return 0;
	}


//////////////////////////////////////////////////////////////////////////////
// Load settings that are stored in game file
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::LoadGame(
	RFile* pFile)
	{
	pFile->Read(&m_sDifficulty);
	pFile->Read(&m_sViolence);
	return 0;
	}


//////////////////////////////////////////////////////////////////////////////
// Save settings that are stored in game file
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::SaveGame(
	RFile* pFile)
	{
	pFile->Write(&m_sDifficulty);
	pFile->Write(&m_sViolence);
	return 0;
	}


//////////////////////////////////////////////////////////////////////////////
// Temporarily set settings for demo mode (file is for saving current settings)
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::PreDemo(
	RFile* pFile)
	{
	pFile->Write(&m_sDifficulty);
	pFile->Write(&m_sViolence);
	m_sDifficulty = 10;
	m_sViolence = 11;
	return 0;
	}


//////////////////////////////////////////////////////////////////////////////
// Restore settings to what they were prior to demo mode
//////////////////////////////////////////////////////////////////////////////
int16_t CGameSettings::PostDemo(
	RFile* pFile)
	{
	pFile->Read(&m_sDifficulty);
	pFile->Read(&m_sViolence);
	return 0;
	}


///////////////////////////////////////////////////////////////////////////////
// EOF
///////////////////////////////////////////////////////////////////////////////
