/***
*
*	Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*	
*	This product contains software technology licensed from Id 
*	Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*	All Rights Reserved.
*
*   Use, distribution, and modification of this source code and/or resulting
*   object code is restricted to non-commercial enhancements to products from
*   Valve LLC.  All other use, distribution, or modification is prohibited
*   without written permission from Valve LLC.
*
****/
//=========================================================
// GameRules.cpp
//=========================================================

#include	"extdll.h"
#include	"util.h"
#include	"cbase.h"
//added by harSens
#include	"effects.h"
#include	"aura.h"
#include	"classes.h"
#include	"magicattack.h"
#include	"explodingattack.h"

#include	"player.h"
#include	"weapons.h"
#include	"gamerules.h"
#include	"teamplay_gamerules.h"
/* disabled by harSens
#include	"skill.h"
*/
#include	"game.h"
//added by harSens
#include	"dragonball.h"
#include	"shenlong.h"
#include	"capturethedragonballs_gamerules.h"
#include "string.h"

// Added by Rick
#include "../bot/bot_util.h"
#include "../bot/bot.h"
// End add by Rick
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );

DLL_GLOBAL CGameRules*	g_pGameRules = NULL;
extern DLL_GLOBAL BOOL	g_fGameOver;
extern int gmsgDeathMsg;	// client dll messages
extern int gmsgMOTD;

int g_teamplay = 0;

//=========================================================
//=========================================================
BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry )
{	/*disabled by harSens
	int iAmmoIndex;

	if ( pszAmmoName )
	{
		iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName );

		if ( iAmmoIndex > -1 )
		{
			if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry )
			{
				// player has room for more of this type of ammo
				return TRUE;
			}
		}
	}*/

	return FALSE;
}

// Added by Rick
edict_t *CGameRules :: GetSinglePlayerSpawnSpot(CBasePlayer *pPlayer)
{
	TMultiChoice<CBaseEntity *> SpawnPointChoices;
	CBaseEntity *pSpot = NULL;
	CBasePlayer *pPlay;
	bool bPlayerNearSpot;

	while((pSpot = UTIL_FindEntityByClassname(pSpot, "info_player_sp")) != NULL)
	{
		// Is there a player near this spawnpoint?
		bPlayerNearSpot = false;
		for(byte b=1;b<gpGlobals->maxClients;b++)
		{
			pPlay = (CBasePlayer *)UTIL_PlayerByIndex(b);

			if (pPlay == pPlayer)
				continue;

			if (!UTIL_IsValidPlayer(pPlay, false, false))
				continue;

			if (UTIL_Distance(pPlay->pev->origin, pSpot->pev->origin) < 128.0f)
			{
				bPlayerNearSpot = true;
				break;
			}
		}

		// Lower chance for this spot if there is a near player
		if (bPlayerNearSpot)
			SpawnPointChoices.Insert(pSpot, 2);
		else
			SpawnPointChoices.Insert(pSpot, 50);
	}

	if (SpawnPointChoices.GetSelection(pSpot))
	{
		// Is there a near player?
		for(byte b=1;b<gpGlobals->maxClients;b++)
		{
			pPlay = (CBasePlayer *)UTIL_PlayerByIndex(b);

			if (pPlay == pPlayer)
				continue;

			if (!UTIL_IsValidPlayer(pPlay, false, false))
				continue;

			if (UTIL_Distance(pPlay->pev->origin, pPlayer->pev->origin) < 128.0f)
			{
				// Kill it
				pPlay->TakeDamage(VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC);
			}
		}

		return pSpot->edict();
	}
	
	return NULL;
}

// Added by Rick
edict_t *CGameRules :: GetSPBotSpawnSpot(CBasePlayer *pPlayer)
{
	CSPBot *pBot = (CSPBot *)UTIL_GetBotPointer(pPlayer);
	return pBot->m_pSpawnPoint->edict();
}
//=========================================================
//=========================================================
edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer )
{
	// Added/modified by Rick: check for coop/hazardcourse
	edict_t *pentSpawnSpot = NULL;

	// Player is a bot?
	if (UTIL_IsBot(pPlayer))
	{
		// Is this bot created by an info_bot entity?
		if (UTIL_GetBotPointer(pPlayer)->IsSPBot())
		{
			pentSpawnSpot = GetSPBotSpawnSpot(pPlayer);
			pPlayer->m_pSPSpawnPoint = NULL;
		}
		else
		{
			pentSpawnSpot = GetSinglePlayerSpawnSpot(pPlayer);
			if (pentSpawnSpot)
				pPlayer->m_pSPSpawnPoint = CBaseEntity::Instance(VARS(pentSpawnSpot));
		}
	}
	else
	{
		pentSpawnSpot = GetSinglePlayerSpawnSpot(pPlayer);
		if (pentSpawnSpot)
			pPlayer->m_pSPSpawnPoint = CBaseEntity::Instance(VARS(pentSpawnSpot));
	}

	if (!pentSpawnSpot)
	{
		pentSpawnSpot = EntSelectSpawnPoint( pPlayer );
		pPlayer->m_pSPSpawnPoint = NULL;
	}

	pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1);
	pPlayer->pev->v_angle  = g_vecZero;
	pPlayer->pev->velocity = g_vecZero;
	pPlayer->pev->angles = VARS(pentSpawnSpot)->angles;
	pPlayer->pev->punchangle = g_vecZero;
	pPlayer->pev->fixangle = TRUE;
	
	return pentSpawnSpot;
}

//=========================================================
//=========================================================
BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon )
{
	// only living players can have items
	if ( pPlayer->pev->deadflag != DEAD_NO )
		return FALSE;

	if ( pWeapon->pszAmmo1() )
	{
		if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) )
		{
			// we can't carry anymore ammo for this gun. We can only 
			// have the gun if we aren't already carrying one of this type
			if ( pPlayer->HasPlayerItem( pWeapon ) )
			{
				return FALSE;
			}
		}
	}
	else
	{
		// weapon doesn't use ammo, don't take another if you already have it.
		if ( pPlayer->HasPlayerItem( pWeapon ) )
		{
			return FALSE;
		}
	}

	// note: will fall through to here if GetItemInfo doesn't fill the struct!
	return TRUE;
}

/*
Added by harSens
*/
void CGameRules::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer )
{	// prevent skin/color/model changes
	char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" );

	// Pcjoe: Set model clientside
	if( stricmp(pPlayer->m_szCurrentModel, g_engfuncs.pfnInfoKeyValue(infobuffer, "model")) )
	{	// Long and cumbersome, but game crashes if we use a non precached model
		// Note - This removes custom model support, no more ssj scripts
		bool blCanChange = false;
		for(int i = 0; i < NUM_PLR_MODELS; i++)
		{	if(!stricmp(g_szModelList[i],""))
			{	break;
			}
			if(!stricmp(g_szModelList[i],mdls))
			{	blCanChange = true;
			}
		}
		if(blCanChange)
		{	UTIL_SetPlayerModel(pPlayer, g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ));
		}
	}
	//for stoopid fools wanting to use ssj-scripts
	if (CVAR_GET_FLOAT( "mp_lockmodels")==0)
	{	return;
	}
	
	// skip base class
	int class_nr = pPlayer->m_pClass->Classify();
	if (class_nr < 0)
		return;

	char class_model[255];
	strcpy(class_model,pPlayer->m_pClass->GetModelName());	
	
	// wrong model for current player?
	if ( stricmp(mdls,class_model )) 
	{	//restore class_model
		g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", class_model ); 
		// Pcjoe: Set model clientside
		UTIL_SetPlayerModel(pPlayer, class_model);
	}	

}

/*
* Pcjoe: Set Melee Settings
*/
void CGameRules::SetMeleeSettings( void )
{	// - Slow
	m_MeleeSettings[0].flMinRange = 0.4;
	m_MeleeSettings[0].flWeakRange = 0.7;
	m_MeleeSettings[0].flMediumRange = 1.1;
	m_MeleeSettings[0].flStrongRange = 1.5;
	m_MeleeSettings[0].flStunPerPunch = 0.85;
	// - Medium
	m_MeleeSettings[1].flMinRange = 0.3;
	m_MeleeSettings[1].flWeakRange = 0.5;
	m_MeleeSettings[1].flMediumRange = 0.9;
	m_MeleeSettings[1].flStrongRange = 1.35;
	m_MeleeSettings[1].flStunPerPunch = 0.75;
	// - Fast
	m_MeleeSettings[2].flMinRange = 0.2;
	m_MeleeSettings[2].flWeakRange = 0.4;
	m_MeleeSettings[2].flMediumRange = 0.7;
	m_MeleeSettings[2].flStrongRange = 1.0;
	m_MeleeSettings[2].flStunPerPunch = 0.5;
}

/*
* Get Melee Skill Varibles
*/
melee_settings_s *CGameRules::GetMeleeSkillValues( void )
{	int iValue = (int)melee_skill.value;
	if(iValue < 0)
		iValue = 0;
	else if(iValue > MELEE_SKILL_SETTINGS-1)
		iValue = MELEE_SKILL_SETTINGS-1;

	return (&m_MeleeSettings[iValue]);
}

//=========================================================
// load the SkillData struct with the proper values based on the skill level.
//=========================================================
/*
void CGameRules::RefreshSkillData ( void )
{
	int	iSkill;

	iSkill = (int)CVAR_GET_FLOAT("skill");
	g_iSkillLevel = iSkill;

	if ( iSkill < 1 )
	{
		iSkill = 1;
	}
	else if ( iSkill > 3 )
	{
		iSkill = 3; 
	}

	gSkillData.iSkillLevel = iSkill;

	ALERT ( at_console, "\nGAME SKILL LEVEL:%d\n",iSkill );

	//Agrunt		
	gSkillData.agruntHealth = GetSkillCvar( "sk_agrunt_health" );
	gSkillData.agruntDmgPunch = GetSkillCvar( "sk_agrunt_dmg_punch");

	// Apache 
	gSkillData.apacheHealth = GetSkillCvar( "sk_apache_health");

	// Barney
	gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health");

	// Big Momma
	gSkillData.bigmommaHealthFactor = GetSkillCvar( "sk_bigmomma_health_factor" );
	gSkillData.bigmommaDmgSlash = GetSkillCvar( "sk_bigmomma_dmg_slash" );
	gSkillData.bigmommaDmgBlast = GetSkillCvar( "sk_bigmomma_dmg_blast" );
	gSkillData.bigmommaRadiusBlast = GetSkillCvar( "sk_bigmomma_radius_blast" );

	// Bullsquid
	gSkillData.bullsquidHealth = GetSkillCvar( "sk_bullsquid_health");
	gSkillData.bullsquidDmgBite = GetSkillCvar( "sk_bullsquid_dmg_bite");
	gSkillData.bullsquidDmgWhip = GetSkillCvar( "sk_bullsquid_dmg_whip");
	gSkillData.bullsquidDmgSpit = GetSkillCvar( "sk_bullsquid_dmg_spit");

	// Gargantua
	gSkillData.gargantuaHealth = GetSkillCvar( "sk_gargantua_health");
	gSkillData.gargantuaDmgSlash = GetSkillCvar( "sk_gargantua_dmg_slash");
	gSkillData.gargantuaDmgFire = GetSkillCvar( "sk_gargantua_dmg_fire");
	gSkillData.gargantuaDmgStomp = GetSkillCvar( "sk_gargantua_dmg_stomp");

	// Hassassin
	gSkillData.hassassinHealth = GetSkillCvar( "sk_hassassin_health");

	// Headcrab
	gSkillData.headcrabHealth = GetSkillCvar( "sk_headcrab_health");
	gSkillData.headcrabDmgBite = GetSkillCvar( "sk_headcrab_dmg_bite");

	// Hgrunt 
	gSkillData.hgruntHealth = GetSkillCvar( "sk_hgrunt_health");
	gSkillData.hgruntDmgKick = GetSkillCvar( "sk_hgrunt_kick");
	gSkillData.hgruntShotgunPellets = GetSkillCvar( "sk_hgrunt_pellets");
	gSkillData.hgruntGrenadeSpeed = GetSkillCvar( "sk_hgrunt_gspeed");

	// Houndeye
	gSkillData.houndeyeHealth = GetSkillCvar( "sk_houndeye_health");
	gSkillData.houndeyeDmgBlast = GetSkillCvar( "sk_houndeye_dmg_blast");

	// ISlave
	gSkillData.slaveHealth = GetSkillCvar( "sk_islave_health");
	gSkillData.slaveDmgClaw = GetSkillCvar( "sk_islave_dmg_claw");
	gSkillData.slaveDmgClawrake = GetSkillCvar( "sk_islave_dmg_clawrake");
	gSkillData.slaveDmgZap = GetSkillCvar( "sk_islave_dmg_zap");

	// Icthyosaur
	gSkillData.ichthyosaurHealth = GetSkillCvar( "sk_ichthyosaur_health");
	gSkillData.ichthyosaurDmgShake = GetSkillCvar( "sk_ichthyosaur_shake");

	// Leech
	gSkillData.leechHealth = GetSkillCvar( "sk_leech_health");

	gSkillData.leechDmgBite = GetSkillCvar( "sk_leech_dmg_bite");

	// Controller
	gSkillData.controllerHealth = GetSkillCvar( "sk_controller_health");
	gSkillData.controllerDmgZap = GetSkillCvar( "sk_controller_dmgzap");
	gSkillData.controllerSpeedBall = GetSkillCvar( "sk_controller_speedball");
	gSkillData.controllerDmgBall = GetSkillCvar( "sk_controller_dmgball");

	// Nihilanth
	gSkillData.nihilanthHealth = GetSkillCvar( "sk_nihilanth_health");
	gSkillData.nihilanthZap = GetSkillCvar( "sk_nihilanth_zap");

	// Scientist
	gSkillData.scientistHealth = GetSkillCvar( "sk_scientist_health");

	// Snark
	gSkillData.snarkHealth = GetSkillCvar( "sk_snark_health");
	gSkillData.snarkDmgBite = GetSkillCvar( "sk_snark_dmg_bite");
	gSkillData.snarkDmgPop = GetSkillCvar( "sk_snark_dmg_pop");

	// Zombie
	gSkillData.zombieHealth = GetSkillCvar( "sk_zombie_health");
	gSkillData.zombieDmgOneSlash = GetSkillCvar( "sk_zombie_dmg_one_slash");
	gSkillData.zombieDmgBothSlash = GetSkillCvar( "sk_zombie_dmg_both_slash");

	//Turret
	gSkillData.turretHealth = GetSkillCvar( "sk_turret_health");

	// MiniTurret
	gSkillData.miniturretHealth = GetSkillCvar( "sk_miniturret_health");
	
	// Sentry Turret
	gSkillData.sentryHealth = GetSkillCvar( "sk_sentry_health");

// PLAYER WEAPONS

	// Crowbar whack
	gSkillData.plrDmgCrowbar = GetSkillCvar( "sk_plr_crowbar");

	// Glock Round
	gSkillData.plrDmg9MM = GetSkillCvar( "sk_plr_9mm_bullet");

	// 357 Round
	gSkillData.plrDmg357 = GetSkillCvar( "sk_plr_357_bullet");

	// MP5 Round
	gSkillData.plrDmgMP5 = GetSkillCvar( "sk_plr_9mmAR_bullet");

	// M203 grenade
	gSkillData.plrDmgM203Grenade = GetSkillCvar( "sk_plr_9mmAR_grenade");

	// Shotgun buckshot
	gSkillData.plrDmgBuckshot = GetSkillCvar( "sk_plr_buckshot");

	// Crossbow
	gSkillData.plrDmgCrossbowClient = GetSkillCvar( "sk_plr_xbow_bolt_client");
	gSkillData.plrDmgCrossbowMonster = GetSkillCvar( "sk_plr_xbow_bolt_monster");

	// RPG
	gSkillData.plrDmgRPG = GetSkillCvar( "sk_plr_rpg");

	// Gauss gun
	gSkillData.plrDmgGauss = GetSkillCvar( "sk_plr_gauss");

	// Egon Gun
	gSkillData.plrDmgEgonNarrow = GetSkillCvar( "sk_plr_egon_narrow");
	gSkillData.plrDmgEgonWide = GetSkillCvar( "sk_plr_egon_wide");

	// Hand Grendade
	gSkillData.plrDmgHandGrenade = GetSkillCvar( "sk_plr_hand_grenade");

	// Satchel Charge
	gSkillData.plrDmgSatchel = GetSkillCvar( "sk_plr_satchel");

	// Tripmine
	gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine");

	// MONSTER WEAPONS
	gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet");
	gSkillData.monDmgMP5 = GetSkillCvar ("sk_9mmAR_bullet" );
	gSkillData.monDmg9MM = GetSkillCvar( "sk_9mm_bullet");

	// MONSTER HORNET
	gSkillData.monDmgHornet = GetSkillCvar( "sk_hornet_dmg");

	// PLAYER HORNET
// Up to this point, player hornet damage and monster hornet damage were both using
// monDmgHornet to determine how much damage to do. In tuning the hivehand, we now need
// to separate player damage and monster hivehand damage. Since it's so late in the project, we've
// added plrDmgHornet to the SKILLDATA struct, but not to the engine CVar list, so it's inaccesible
// via SKILLS.CFG. Any player hivehand tuning must take place in the code. (sjb)
	gSkillData.plrDmgHornet = 7;


	// HEALTH/CHARGE
	gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" );
	gSkillData.batteryCapacity = GetSkillCvar( "sk_battery" );
	gSkillData.healthchargerCapacity = GetSkillCvar ( "sk_healthcharger" );
	gSkillData.healthkitCapacity = GetSkillCvar ( "sk_healthkit" );
	gSkillData.scientistHeal = GetSkillCvar ( "sk_scientist_heal" );

	// monster damage adj
	gSkillData.monHead = GetSkillCvar( "sk_monster_head" );
	gSkillData.monChest = GetSkillCvar( "sk_monster_chest" );
	gSkillData.monStomach = GetSkillCvar( "sk_monster_stomach" );
	gSkillData.monLeg = GetSkillCvar( "sk_monster_leg" );
	gSkillData.monArm = GetSkillCvar( "sk_monster_arm" );

	// player damage adj
	gSkillData.plrHead = GetSkillCvar( "sk_player_head" );
	gSkillData.plrChest = GetSkillCvar( "sk_player_chest" );
	gSkillData.plrStomach = GetSkillCvar( "sk_player_stomach" );
	gSkillData.plrLeg = GetSkillCvar( "sk_player_leg" );
	gSkillData.plrArm = GetSkillCvar( "sk_player_arm" );
}
*/
//=========================================================
// instantiate the proper game rules object
//=========================================================

CGameRules *InstallGameRules( void )
{
	SERVER_COMMAND( "exec game.cfg\n" );
	SERVER_EXECUTE( );

	/* Modified by harSens
	if ( !gpGlobals->deathmatch )
	{
		// generic half-life
		g_teamplay = 0;
		return new CHalfLifeRules;
	}
	else
	{
		if ( teamplay.value > 0 )
		{
			// teamplay

			g_teamplay = 1;
			return new CHalfLifeTeamplay;
		}
		if ((int)gpGlobals->deathmatch == 1)
		{
			// vanilla deathmatch
			g_teamplay = 0;
			return new CHalfLifeMultiplay;
		}
		else
		{
			// vanilla deathmatch??
			g_teamplay = 0;
			return new CHalfLifeMultiplay;
		}
	}*/
	switch ((int)CVAR_GET_FLOAT( "mp_gamemode" ))
	{	case 1: g_teamplay = 1; return new CHalfLifeTeamplay;
		case 2: g_teamplay = 1; return new CHalfLifeCaptureTheDragonBalls;
		default:g_teamplay = 0; return new CHalfLifeMultiplay;
	};	
}



