/* AMX Mod X 
   *   Counter-Strike Module 
   * 
   * by the AMX Mod X Development Team 
   * 
   * This file is part of AMX Mod X. 
   * 
   * 
   *  This program is free software; you can redistribute it and/or modify it 
   *  under the terms of the GNU General Public License as published by the 
   *  Free Software Foundation; either version 2 of the License, or (at 
   *  your option) any later version. 
   * 
   *  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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
   * 
   *  In addition, as a special exception, the author gives permission to 
   *  link the code of this program with the Half-Life Game Engine ("HL 
   *  Engine") and Modified Game Libraries ("MODs") developed by Valve, 
   *  L.L.C ("Valve"). You must obey the GNU General Public License in all 
   *  respects for all of the code used other than the HL Engine and MODs 
   *  from Valve. If you modify this file, you may extend this exception 
   *  to your version of the file, but you are not obligated to do so. If 
   *  you do not wish to do so, delete this exception statement from your 
   *  version. 
   */ 

// cstrike MODULE TO DO HERE: http://www.amxmodx.org/forums/viewtopic.php?t=45
// This implementation uses Vexd's way (lightly modified) of setting models on players.

#include <extdll.h>
#include <meta_api.h>
#include "amxxmodule.h"
#include "CstrikePlayer.h"

#define GETINFOKEYBUFFER				(*g_engfuncs.pfnGetInfoKeyBuffer)
#define	SETCLIENTKEYVALUE				(*g_engfuncs.pfnSetClientKeyValue)
#define GETCLIENTKEYVALUE				(*g_engfuncs.pfnInfoKeyValue)
#define CREATENAMEDENTITY				(*g_engfuncs.pfnCreateNamedEntity)

#if defined __linux__
	#define EXTRAOFFSET					5 // offsets 5 higher in Linux builds
	#define EXTRAOFFSET_WEAPONS			4 // weapon offsets are obviously only 4 steps higher on Linux!
#else
	#define EXTRAOFFSET					0 // no change in Windows builds
	#define EXTRAOFFSET_WEAPONS			0
#endif // defined __linux__
/*
	Offset history:
	041029:
	Confirmed (pretty much) ALL offsets for 32 bit Windows, 32 bit Linux and amd64 (yes that's all of them).
	Found out that weapon offsets are only +4 higher on Linux.
	Also backpack ammo offsets were all obviously 5 steps too high since unknown time...

*/

#define HAS_SHIELD      (1<<24) //16777216 

// "player" entities
#if !defined __amd64__
	// 32 bit offsets here
	#define OFFSET_ARMORTYPE			112 + EXTRAOFFSET
	#define OFFSET_TEAM					114 + EXTRAOFFSET
	#define OFFSET_CSMONEY				115 + EXTRAOFFSET
	#define OFFSET_PRIMARYWEAPON		116 + EXTRAOFFSET
	#define OFFSET_INTERNALMODEL		126 + EXTRAOFFSET
	#define OFFSET_NVGOGGLES			129 + EXTRAOFFSET
	#define OFFSET_DEFUSE_PLANT			193 + EXTRAOFFSET
	#define OFFSET_VIP					209 + EXTRAOFFSET
	#define OFFSET_TK					216 + EXTRAOFFSET // 040926
	#define OFFSET_BUYZONE				235 + EXTRAOFFSET
	#define OFFSET_ISDRIVING			350 + EXTRAOFFSET // 040926
	#define OFFSET_STATIONARY			362 + EXTRAOFFSET // 040927 (363 works also!)

	#define OFFSET_AWM_AMMO				377 + EXTRAOFFSET // 041029: All of these *_AMMO:s were changed -5
	#define OFFSET_SCOUT_AMMO			378 + EXTRAOFFSET
	#define OFFSET_PARA_AMMO			379 + EXTRAOFFSET
	#define OFFSET_FAMAS_AMMO			380 + EXTRAOFFSET
	#define OFFSET_M3_AMMO				381 + EXTRAOFFSET
	#define OFFSET_USP_AMMO				382 + EXTRAOFFSET
	#define OFFSET_FIVESEVEN_AMMO		383 + EXTRAOFFSET
	#define OFFSET_DEAGLE_AMMO			384 + EXTRAOFFSET
	#define OFFSET_P228_AMMO			385 + EXTRAOFFSET
	#define OFFSET_GLOCK_AMMO			386 + EXTRAOFFSET
	#define OFFSET_FLASH_AMMO			387 + EXTRAOFFSET
	#define OFFSET_HE_AMMO				388 + EXTRAOFFSET
	#define OFFSET_SMOKE_AMMO			389 + EXTRAOFFSET
	#define OFFSET_C4_AMMO				390	+ EXTRAOFFSET

	#define OFFSET_CSDEATHS				444 + EXTRAOFFSET // 040926
	#define OFFSET_SHIELD				510 + EXTRAOFFSET
	// "weapon_*" entities
	#define OFFSET_WEAPONTYPE			43 + EXTRAOFFSET_WEAPONS
	#define OFFSET_CLIPAMMO				51 + EXTRAOFFSET_WEAPONS
	#define OFFSET_SILENCER_FIREMODE	74 + EXTRAOFFSET_WEAPONS
	// "hostage_entity" entities
	#define OFFSET_HOSTAGEFOLLOW		86 + EXTRAOFFSET
	#define OFFSET_HOSTAGEID			487 + EXTRAOFFSET
	// "armoury_entity"
	#define OFFSET_ARMOURY_TYPE			34 + EXTRAOFFSET
#else
	// Amd64 offsets here
	#define OFFSET_ARMORTYPE			137 + EXTRAOFFSET
	#define OFFSET_TEAM					139 + EXTRAOFFSET // +25
	#define OFFSET_CSMONEY				140 + EXTRAOFFSET // +25
	#define OFFSET_PRIMARYWEAPON		141 + EXTRAOFFSET // +25
	#define OFFSET_INTERNALMODEL		152 + EXTRAOFFSET // +26
	#define OFFSET_NVGOGGLES			155 + EXTRAOFFSET // +26
	#define OFFSET_DEFUSE_PLANT			219 + EXTRAOFFSET // +26
	#define OFFSET_VIP					242 + EXTRAOFFSET // +27
	#define OFFSET_TK					249 + EXTRAOFFSET // +33 040927
	#define OFFSET_BUYZONE				268 + EXTRAOFFSET // +27
	#define OFFSET_ISDRIVING			386 + EXTRAOFFSET // 040927
	#define OFFSET_STATIONARY			400 + EXTRAOFFSET // 040927 (401 works also)

	#define OFFSET_AWM_AMMO				426 + EXTRAOFFSET // +44
	#define OFFSET_SCOUT_AMMO			427 + EXTRAOFFSET // +44
	#define OFFSET_PARA_AMMO			428 + EXTRAOFFSET // +44
	#define OFFSET_FAMAS_AMMO			429 + EXTRAOFFSET // +44
	#define OFFSET_M3_AMMO				430 + EXTRAOFFSET // +44
	#define OFFSET_USP_AMMO				431 + EXTRAOFFSET // +44
	#define OFFSET_FIVESEVEN_AMMO		432 + EXTRAOFFSET // +44
	#define OFFSET_DEAGLE_AMMO			433 + EXTRAOFFSET // +44
	#define OFFSET_P228_AMMO			434 + EXTRAOFFSET // +44
	#define OFFSET_GLOCK_AMMO			435 + EXTRAOFFSET // +44
	#define OFFSET_FLASH_AMMO			436 + EXTRAOFFSET // +44
	#define OFFSET_HE_AMMO				437 + EXTRAOFFSET // +44
	#define OFFSET_SMOKE_AMMO			438 + EXTRAOFFSET // +44
	#define OFFSET_C4_AMMO				439	+ EXTRAOFFSET // +44

	#define OFFSET_CSDEATHS				493 + EXTRAOFFSET // +49
	#define OFFSET_SHIELD				559 + EXTRAOFFSET
	// "weapon_*" entities
	#define OFFSET_WEAPONTYPE			57 + EXTRAOFFSET // +14
	#define OFFSET_CLIPAMMO				65 + EXTRAOFFSET // +14
	#define OFFSET_SILENCER_FIREMODE	88 + EXTRAOFFSET // +14
	// "hostage_entity" entities
	#define OFFSET_HOSTAGEFOLLOW		51 + EXTRAOFFSET // +21, long=51, int=107! (must use the long* offset because pointers on amd64 are stored the size of longs, 8 bytes, instead of the usual int 4 bytes.)
	#define OFFSET_HOSTAGEID			516 + EXTRAOFFSET // +29
#endif

// Ids of weapons in CS
#define CSW_P228						1
//#define CSW_SHIELD					2
#define CSW_SCOUT						3
#define CSW_HEGRENADE					4
#define CSW_XM1014						5
#define CSW_C4							6
#define CSW_MAC10						7
#define CSW_AUG							8
#define CSW_SMOKEGRENADE				9
#define CSW_ELITE						10
#define CSW_FIVESEVEN					11
#define CSW_UMP45						12
#define CSW_SG550						13
#define CSW_GALI						14
#define CSW_FAMAS						15
#define CSW_USP							16
#define CSW_GLOCK18						17
#define CSW_AWP							18
#define CSW_MP5NAVY						19
#define CSW_M249						20
#define CSW_M3							21
#define CSW_M4A1						22
#define CSW_TMP							23
#define CSW_G3SG1						24
#define CSW_FLASHBANG					25
#define CSW_DEAGLE						26
#define CSW_SG552						27
#define CSW_AK47						28
//#define CSW_KNIFE						29
#define CSW_P90							30
#define CSW_VEST						31 // Brand new invention!
#define CSW_VESTHELM					32 // Brand new invention!

// These are used with armoury_entity:s.
#define CSA_MP5NAVY						0
#define CSA_TMP							1
#define CSA_P90							2
#define CSA_MAC10						3
#define CSA_AK47						4
#define CSA_SG552						5
#define CSA_M4A1						6
#define CSA_AUG							7
#define CSA_SCOUT						8
#define CSA_G3SG1						9
#define CSA_AWP							10
#define CSA_M3							11
#define CSA_XM1014						12
#define CSA_M249						13
#define CSA_FLASHBANG					14
#define CSA_HEGRENADE					15
#define CSA_VEST						16
#define CSA_VESTHELM					17
#define CSA_SMOKEGRENADE				18

#define M4A1_SILENCED					(1<<2)
#define M4A1_ATTACHSILENCEANIM			6
#define M4A1_DETACHSILENCEANIM			13
#define USP_SILENCED					(1<<0)
#define USP_ATTACHSILENCEANIM			7
#define USP_DETACHSILENCEANIM			15

#define GLOCK_SEMIAUTOMATIC				0
#define GLOCK_BURSTMODE					2
#define FAMAS_AUTOMATIC					0
#define FAMAS_BURSTMODE					16

#define PLAYER_IS_VIP					(1<<8)

#define TEAM_UNASSIGNED					0
#define TEAM_T							1
#define TEAM_CT							2
#define TEAM_SPECTATOR					3

#define CAN_PLANT_BOMB					(1<<8) // 256
#define HAS_DEFUSE_KIT					(1<<16) // 65536

#define DEFUSER_COLOUR_R				0
#define DEFUSER_COLOUR_G				160
#define DEFUSER_COLOUR_B				0

#define HAS_NVGOGGLES					(1<<0)

#define SCOREATTRIB_NOTHING				0
#define SCOREATTRIB_DEAD				1
#define SCOREATTRIB_BOMB				2 // t only
#define SCOREATTRIB_VIP					4 // ct only

#define AMD64_STATIONARY_NO				2
#define AMD64_STATIONARY_YES			3

#define CS_ARMOR_NONE					0
#define CS_ARMOR_KEVLAR					1
#define CS_ARMOR_ASSAULTSUIT			2

enum CS_Internal_Models {
	CS_DONTCHANGE = 0,
	CS_CT_URBAN = 1,
	CS_T_TERROR = 2,
	CS_T_LEET = 3,
	CS_T_ARCTIC = 4,
	CS_CT_GSG9 = 5,
	CS_CT_GIGN = 6,
	CS_CT_SAS = 7,
	CS_T_GUERILLA = 8,
	CS_CT_VIP = 9
};
// cstrike-specific defines above

CCstrikePlayer g_players[33];
bool g_precachedknife = false;
bool g_noknives = false;
// Globals above

#define CHECK_ENTITY(x) \
	if (x < 0 || x > gpGlobals->maxEntities) { \
		MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \
		return 0; \
	} else { \
		if (x <= gpGlobals->maxClients) { \
			if (!MF_IsPlayerIngame(x)) { \
				MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d (not in-game)", x); \
				return 0; \
			} \
		} else { \
			if (x != 0 && FNullEnt(INDEXENT(x))) { \
				MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \
				return 0; \
			} \
		} \
	}

#define CHECK_PLAYER(x) \
	if (x < 1 || x > gpGlobals->maxClients) { \
		MF_LogError(amx, AMX_ERR_NATIVE, "Player out of range (%d)", x); \
		return 0; \
	} else { \
		if (!MF_IsPlayerIngame(x) || FNullEnt(MF_GetPlayerEdict(x))) { \
			MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", x); \
			return 0; \
		} \
	}

#define CHECK_NONPLAYER(x) \
	if (x < 1 || x <= gpGlobals->maxClients || x > gpGlobals->maxEntities) { \
		MF_LogError(amx, AMX_ERR_NATIVE, "Non-player entity %d out of range", x); \
		return 0; \
	} else { \
		if (FNullEnt(INDEXENT(x))) { \
			MF_LogError(amx, AMX_ERR_NATIVE, "Invalid non-player entity %d", x); \
			return 0; \
		} \
	}

#define GETEDICT(n) \
	((n >= 1 && n <= gpGlobals->maxClients) ? MF_GetPlayerEdict(n) : INDEXENT(n))