/**
 * vim: set ts=4 :
 * =============================================================================
 * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
 * =============================================================================
 *
 * This file is part of the SourceMod/SourcePawn SDK.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, version 3.0, 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, see <http://www.gnu.org/licenses/>.
 *
 * As a special exception, AlliedModders LLC gives you permission to link the
 * code of this program (as well as its derivative works) to "Half-Life 2," the
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 * by the Valve Corporation.  You must obey the GNU General Public License in
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
 * this exception to all derivative works.  AlliedModders LLC defines further
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 * or <http://www.sourcemod.net/license.php>.
 *
 * Version: $Id$
 */

#if defined _entity_prop_stocks_included
 #endinput
#endif
#define _entity_prop_stocks_included

enum MoveType
{
	MOVETYPE_NONE = 0,          /**< never moves */
	MOVETYPE_ISOMETRIC,         /**< For players */
	MOVETYPE_WALK,              /**< Player only - moving on the ground */
	MOVETYPE_STEP,              /**< gravity, special edge handling -- monsters use this */
	MOVETYPE_FLY,               /**< No gravity, but still collides with stuff */
	MOVETYPE_FLYGRAVITY,        /**< flies through the air + is affected by gravity */
	MOVETYPE_VPHYSICS,          /**< uses VPHYSICS for simulation */
	MOVETYPE_PUSH,              /**< no clip to world, push and crush */
	MOVETYPE_NOCLIP,            /**< No gravity, no collisions, still do velocity/avelocity */
	MOVETYPE_LADDER,            /**< Used by players only when going onto a ladder */
	MOVETYPE_OBSERVER,          /**< Observer movement, depends on player's observer mode */
	MOVETYPE_CUSTOM             /**< Allows the entity to describe its own physics */
};

enum RenderMode
{
	RENDER_NORMAL,              /**< src */
	RENDER_TRANSCOLOR,          /**< c*a+dest*(1-a) */
	RENDER_TRANSTEXTURE,        /**< src*a+dest*(1-a) */
	RENDER_GLOW,                /**< src*a+dest -- No Z buffer checks -- Fixed size in screen space */
	RENDER_TRANSALPHA,          /**< src*srca+dest*(1-srca) */
	RENDER_TRANSADD,            /**< src*a+dest */
	RENDER_ENVIRONMENTAL,       /**< not drawn, used for environmental effects */
	RENDER_TRANSADDFRAMEBLEND,  /**< use a fractional frame value to blend between animation frames */
	RENDER_TRANSALPHAADD,       /**< src + dest*(1-a) */
	RENDER_WORLDGLOW,           /**< Same as kRenderGlow but not fixed size in screen space */
	RENDER_NONE                 /**< Don't render. */
};

enum RenderFx
{
	RENDERFX_NONE = 0,
	RENDERFX_PULSE_SLOW,
	RENDERFX_PULSE_FAST,
	RENDERFX_PULSE_SLOW_WIDE,
	RENDERFX_PULSE_FAST_WIDE,
	RENDERFX_FADE_SLOW,
	RENDERFX_FADE_FAST,
	RENDERFX_SOLID_SLOW,
	RENDERFX_SOLID_FAST,
	RENDERFX_STROBE_SLOW,
	RENDERFX_STROBE_FAST,
	RENDERFX_STROBE_FASTER,
	RENDERFX_FLICKER_SLOW,
	RENDERFX_FLICKER_FAST,
	RENDERFX_NO_DISSIPATION,
	RENDERFX_DISTORT,           /**< Distort/scale/translate flicker */
	RENDERFX_HOLOGRAM,          /**< kRenderFxDistort + distance fade */
	RENDERFX_EXPLODE,           /**< Scale up really big! */
	RENDERFX_GLOWSHELL,         /**< Glowing Shell */
	RENDERFX_CLAMP_MIN_SCALE,   /**< Keep this sprite from getting very small (SPRITES only!) */
	RENDERFX_ENV_RAIN,          /**< for environmental rendermode, make rain */
	RENDERFX_ENV_SNOW,          /**<  "        "            "    , make snow */
	RENDERFX_SPOTLIGHT,         /**< TEST CODE for experimental spotlight */
	RENDERFX_RAGDOLL,           /**< HACKHACK: TEST CODE for signalling death of a ragdoll character */
	RENDERFX_PULSE_FAST_WIDER,
	RENDERFX_MAX
};

// These defines are for client button presses.
#define IN_ATTACK                (1 << 0)
#define IN_JUMP                  (1 << 1)
#define IN_DUCK                  (1 << 2)
#define IN_FORWARD               (1 << 3)
#define IN_BACK                  (1 << 4)
#define IN_USE                   (1 << 5)
#define IN_CANCEL                (1 << 6)
#define IN_LEFT                  (1 << 7)
#define IN_RIGHT                 (1 << 8)
#define IN_MOVELEFT              (1 << 9)
#define IN_MOVERIGHT             (1 << 10)
#define IN_ATTACK2               (1 << 11)
#define IN_RUN                   (1 << 12)
#define IN_RELOAD                (1 << 13)
#define IN_ALT1                  (1 << 14)
#define IN_ALT2                  (1 << 15)
#define IN_SCORE                 (1 << 16)   /**< Used by client.dll for when scoreboard is held down */
#define IN_SPEED                 (1 << 17)   /**< Player is holding the speed key */
#define IN_WALK                  (1 << 18)   /**< Player holding walk key */
#define IN_ZOOM                  (1 << 19)   /**< Zoom key for HUD zoom */
#define IN_WEAPON1               (1 << 20)   /**< weapon defines these bits */
#define IN_WEAPON2               (1 << 21)   /**< weapon defines these bits */
#define IN_BULLRUSH              (1 << 22)
#define IN_GRENADE1              (1 << 23)   /**< grenade 1 */
#define IN_GRENADE2              (1 << 24)   /**< grenade 2 */
#define IN_ATTACK3               (1 << 25)

// Note: these are only for use with GetEntityFlags and SetEntityFlags
//       and may not match the game's actual, internal m_fFlags values.
// PLAYER SPECIFIC FLAGS FIRST BECAUSE WE USE ONLY A FEW BITS OF NETWORK PRECISION
#define FL_ONGROUND              (1 << 0)   /**< At rest / on the ground */
#define FL_DUCKING               (1 << 1)   /**< Player flag -- Player is fully crouched */
#define FL_WATERJUMP             (1 << 2)   /**< player jumping out of water */
#define FL_ONTRAIN               (1 << 3)   /**< Player is _controlling_ a train, so movement commands should be ignored on client during prediction. */
#define FL_INRAIN                (1 << 4)   /**< Indicates the entity is standing in rain */
#define FL_FROZEN                (1 << 5)   /**< Player is frozen for 3rd person camera */
#define FL_ATCONTROLS            (1 << 6)   /**< Player can't move, but keeps key inputs for controlling another entity */
#define FL_CLIENT                (1 << 7)   /**< Is a player */
#define FL_FAKECLIENT            (1 << 8)   /**< Fake client, simulated server side; don't send network messages to them */
// NOTE if you move things up, make sure to change this value
#define PLAYER_FLAG_BITS          9
// NON-PLAYER SPECIFIC (i.e., not used by GameMovement or the client .dll ) -- Can still be applied to players, though
#define FL_INWATER               (1 << 9)   /**< In water */
#define FL_FLY                   (1 << 10)  /**< Changes the SV_Movestep() behavior to not need to be on ground */
#define FL_SWIM                  (1 << 11)  /**< Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) */
#define FL_CONVEYOR              (1 << 12)
#define FL_NPC                   (1 << 13)
#define FL_GODMODE               (1 << 14)
#define FL_NOTARGET              (1 << 15)
#define FL_AIMTARGET             (1 << 16)  /**< set if the crosshair needs to aim onto the entity */
#define FL_PARTIALGROUND         (1 << 17)  /**< not all corners are valid */
#define FL_STATICPROP            (1 << 18)  /**< Eetsa static prop!  */
#define FL_GRAPHED               (1 << 19)  /**< worldgraph has this ent listed as something that blocks a connection */
#define FL_GRENADE               (1 << 20)
#define FL_STEPMOVEMENT          (1 << 21)  /**< Changes the SV_Movestep() behavior to not do any processing */
#define FL_DONTTOUCH             (1 << 22)  /**< Doesn't generate touch functions, generates Untouch() for anything it was touching when this flag was set */
#define FL_BASEVELOCITY          (1 << 23)  /**< Base velocity has been applied this frame (used to convert base velocity into momentum) */
#define FL_WORLDBRUSH            (1 << 24)  /**< Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) */
#define FL_OBJECT                (1 << 25)  /**< Terrible name. This is an object that NPCs should see. Missiles, for example. */
#define FL_KILLME                (1 << 26)  /**< This entity is marked for death -- will be freed by game DLL */
#define FL_ONFIRE                (1 << 27)  /**< You know... */
#define FL_DISSOLVING            (1 << 28)  /**< We're dissolving! */
#define FL_TRANSRAGDOLL          (1 << 29)  /**< In the process of turning into a client side ragdoll. */
#define FL_UNBLOCKABLE_BY_PLAYER (1 << 30)  /**< pusher that can't be blocked by the player */
#define FL_FREEZING              (1 << 31)  /**< We're becoming frozen! */
#define FL_EP2V_UNKNOWN1         (1 << 31)  /**< Unknown */
// END entity flag #defines

/**
 * Get an entity's flags.
 *
 * @note The game's actual flags are internally translated by SM
 *       to match the entity flags defined above as the actual values
 *       can differ per engine.
 *
 * @param entity        Entity index.
 * @return              Entity's flags, see entity flag defines above.
 * @error               Invalid entity index, or lack of mod compliance.
 */
native int GetEntityFlags(int entity);

/**
 * Sets an entity's flags.
 *
 * @note The entity flags as defined above are internally translated by SM
 *       to match the current game's expected value for the flags as
 *       the actual values can differ per engine.
 *
 * @param entity        Entity index.
 * @param flags         Entity flags, see entity flag defines above.
 * @error               Invalid entity index, or lack of mod compliance.
 */
native void SetEntityFlags(int entity, int flags);


/**
 * Gets an entity's movetype.
 *
 * @param entity        Entity index.
 * @return              Movetype, see enum above.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock MoveType GetEntityMoveType(int entity)
{
	static bool gotconfig = false;
	static char datamap[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_MoveType", datamap, sizeof(datamap));
		delete gc;

		if (!exists)
		{
			strcopy(datamap, sizeof(datamap), "m_MoveType");
		}

		gotconfig = true;
	}

	return view_as<MoveType>(GetEntProp(entity, Prop_Data, datamap));
}

/**
 * Sets an entity's movetype.
 *
 * @param entity        Entity index.
 * @param mt            Movetype, see enum above.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityMoveType(int entity, MoveType mt)
{
	static bool gotconfig = false;
	static char datamap[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_MoveType", datamap, sizeof(datamap));
		delete gc;

		if (!exists)
		{
			strcopy(datamap, sizeof(datamap), "m_MoveType");
		}

		gotconfig = true;
	}

	SetEntProp(entity, Prop_Data, datamap, mt);
}

/**
 * Gets an entity's render mode.
 *
 * @param entity        Entity index.
 * @return              RenderMode value.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock RenderMode GetEntityRenderMode(int entity)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_nRenderMode", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_nRenderMode");
		}

		gotconfig = true;
	}

	return view_as<RenderMode>(GetEntProp(entity, Prop_Send, prop, 1));
}

/**
 * Sets an entity's render mode.
 *
 * @param entity        Entity index.
 * @param mode          RenderMode value.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityRenderMode(int entity, RenderMode mode)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_nRenderMode", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_nRenderMode");
		}

		gotconfig = true;
	}

	SetEntProp(entity, Prop_Send, prop, mode, 1);
}

/**
 * Gets an entity's render Fx.
 *
 * @param entity        Entity index.
 * @return              RenderFx value.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock RenderFx GetEntityRenderFx(int entity)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_nRenderFX", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_nRenderFX");
		}

		gotconfig = true;
	}

	return view_as<RenderFx>(GetEntProp(entity, Prop_Send, prop, 1));
}

/**
 * Sets an entity's render Fx.
 *
 * @param entity        Entity index.
 * @param fx            RenderFx value.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityRenderFx(int entity, RenderFx fx)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_nRenderFX", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_nRenderFX");
		}

		gotconfig = true;
	}

	SetEntProp(entity, Prop_Send, prop, fx, 1);
}

/**
 * Gets an entity's color.
 *
 * @param entity        Entity index.
 * @param r             Amount of red (0-255)
 * @param g             Amount of green (0-255)
 * @param b             Amount of blue (0-255)
 * @param a             Amount of alpha (0-255)
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void GetEntityRenderColor(int entity, int &r, int &g, int &b, int &a)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_clrRender", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_clrRender");
		}

		gotconfig = true;
	}

	int offset = GetEntSendPropOffs(entity, prop);

	if (offset <= 0)
	{
		ThrowError("GetEntityRenderColor not supported by this mod");
	}

	r = GetEntData(entity, offset, 1);
	g = GetEntData(entity, offset + 1, 1);
	b = GetEntData(entity, offset + 2, 1);
	a = GetEntData(entity, offset + 3, 1);
}

/**
 * Sets an entity's color.
 *
 * @param entity        Entity index
 * @param r             Amount of red (0-255)
 * @param g             Amount of green (0-255)
 * @param b             Amount of blue (0-255)
 * @param a             Amount of alpha (0-255)
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityRenderColor(int entity, int r=255, int g=255, int b=255, int a=255)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_clrRender", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_clrRender");
		}

		gotconfig = true;
	}

	int offset = GetEntSendPropOffs(entity, prop);

	if (offset <= 0)
	{
		ThrowError("SetEntityRenderColor not supported by this mod");
	}

	SetEntData(entity, offset, r, 1, true);
	SetEntData(entity, offset + 1, g, 1, true);
	SetEntData(entity, offset + 2, b, 1, true);
	SetEntData(entity, offset + 3, a, 1, true);
}

/**
 * Gets an entity's gravity.
 *
 * @param entity 	Entity index.
 * @return              Entity's m_flGravity value.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock float GetEntityGravity(int entity)
{
	static bool gotconfig = false;
	static char datamap[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_flGravity", datamap, sizeof(datamap));
		delete gc;

		if (!exists)
		{
			strcopy(datamap, sizeof(datamap), "m_flGravity");
		}

		gotconfig = true;
	}

	return GetEntPropFloat(entity, Prop_Data, datamap);
}

/**
 * Sets an entity's gravity.
 *
 * @param entity        Entity index.
 * @param amount        Gravity to set (default = 1.0, half = 0.5, double = 2.0).
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityGravity(int entity, float amount)
{
	static bool gotconfig = false;
	static char datamap[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_flGravity", datamap, sizeof(datamap));
		delete gc;

		if (!exists)
		{
			strcopy(datamap, sizeof(datamap), "m_flGravity");
		}

		gotconfig = true;
	}

	SetEntPropFloat(entity, Prop_Data, datamap, amount);
}

/**
 * Sets an entity's health
 *
 * @param entity        Entity index.
 * @param amount        Health amount.
 * @error               Invalid entity index, or lack of mod compliance.
 */
stock void SetEntityHealth(int entity, int amount)
{
	static bool gotconfig = false;
	static char prop[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_iHealth", prop, sizeof(prop));
		delete gc;

		if (!exists)
		{
			strcopy(prop, sizeof(prop), "m_iHealth");
		}

		gotconfig = true;
	}

	char cls[64];
	PropFieldType type;
	int offset;

	if (!GetEntityNetClass(entity, cls, sizeof(cls)))
	{
		ThrowError("SetEntityHealth not supported by this mod: Could not get serverclass name");
		return;
	}

	offset = FindSendPropInfo(cls, prop, type);

	if (offset <= 0)
	{
		ThrowError("SetEntityHealth not supported by this mod");
		return;
	}

	/* Dark Messiah uses a float for the health instead an integer */
	if (type == PropField_Float)
	{
		SetEntDataFloat(entity, offset, float(amount));
	}
	else
	{
		SetEntProp(entity, Prop_Send, prop, amount);
	}
}

/**
 * Get's a users current pressed buttons
 *
 * @param client        Client index
 * @return              Bitsum of buttons
 * @error               Invalid client index, client not in game,
 *                      or lack of mod compliance.
 */
stock int GetClientButtons(int client)
{
	static bool gotconfig = false;
	static char datamap[32];

	if (!gotconfig)
	{
		GameData gc = new GameData("core.games");
		bool exists = gc.GetKeyValue("m_nButtons", datamap, sizeof(datamap));
		delete gc;

		if (!exists)
		{
			strcopy(datamap, sizeof(datamap), "m_nButtons");
		}

		gotconfig = true;
	}

	return GetEntProp(client, Prop_Data, datamap);
}
