/**
 * vim: set ts=4 :
 * =============================================================================
 * SourceMod (C)2009-2013 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>.
 */

#if defined _sdkhooks_included
 #endinput
#endif
#define _sdkhooks_included

// this is obviously _not_ a robust check, but it will solve most conflict and is clean
#if !defined DMG_GENERIC
#define DMG_GENERIC                  0          /**< generic damage was done */
#define DMG_CRUSH                   (1 << 0)    /**< crushed by falling or moving object.
                                                     NOTE: It's assumed crush damage is occurring as a result of physics collision,
                                                     so no extra physics force is generated by crush damage.
                                                     DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics
                                                     collision. You probably want DMG_CLUB instead. */
#define DMG_BULLET                  (1 << 1)    /**< shot */
#define DMG_SLASH                   (1 << 2)    /**< cut, clawed, stabbed */
#define DMG_BURN                    (1 << 3)    /**< heat burned */
#define DMG_VEHICLE                 (1 << 4)    /**< hit by a vehicle */
#define DMG_FALL                    (1 << 5)    /**< fell too far */
#define DMG_BLAST                   (1 << 6)    /**< explosive blast damage */
#define DMG_CLUB                    (1 << 7)    /**< crowbar, punch, headbutt */
#define DMG_SHOCK                   (1 << 8)    /**< electric shock */
#define DMG_SONIC                   (1 << 9)    /**< sound pulse shockwave */
#define DMG_ENERGYBEAM              (1 << 10)   /**< laser or other high energy beam  */
#define DMG_PREVENT_PHYSICS_FORCE   (1 << 11)   /**< Prevent a physics force  */
#define DMG_NEVERGIB                (1 << 12)   /**< with this bit OR'd in, no damage type will be able to gib victims upon death */
#define DMG_ALWAYSGIB               (1 << 13)   /**< with this bit OR'd in, any damage type can be made to gib victims upon death. */
#define DMG_DROWN                   (1 << 14)   /**< Drowning */
#define DMG_PARALYZE                (1 << 15)   /**< slows affected creature down */
#define DMG_NERVEGAS                (1 << 16)   /**< nerve toxins, very bad */
#define DMG_POISON                  (1 << 17)   /**< blood poisoning - heals over time like drowning damage */
#define DMG_RADIATION               (1 << 18)   /**< radiation exposure */
#define DMG_DROWNRECOVER            (1 << 19)   /**< drowning recovery */
#define DMG_ACID                    (1 << 20)   /**< toxic chemicals or acid burns */
#define DMG_SLOWBURN                (1 << 21)   /**< in an oven */
#define DMG_REMOVENORAGDOLL         (1 << 22)   /**< with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed.
                                                     use this to kill an entity that you've already got a server-side ragdoll for */
#define DMG_PHYSGUN                 (1 << 23)   /**< Hit by manipulator. Usually doesn't do any damage. */
#define DMG_PLASMA                  (1 << 24)   /**< Shot by Cremator */
#define DMG_AIRBOAT                 (1 << 25)   /**< Hit by the airboat's gun */
#define DMG_DISSOLVE                (1 << 26)   /**< Dissolving! */
#define DMG_BLAST_SURFACE           (1 << 27)   /**< A blast on the surface of water that cannot harm things underwater */
#define DMG_DIRECT                  (1 << 28)
#define DMG_BUCKSHOT                (1 << 29)   /**< not quite a bullet. Little, rounder, different. */
#endif

#if !defined DMG_CRIT
	#define DMG_CRIT                DMG_ACID        /**< TF2 crits and minicrits */
#endif

#if !defined DMG_RADIUS_MAX
	#define DMG_RADIUS_MAX          DMG_ENERGYBEAM  /**< No damage falloff */
#endif

#if !defined DMG_NOCLOSEDISTANCEMOD
	#define DMG_NOCLOSEDISTANCEMOD  DMG_POISON      /**< Don't do damage falloff too close */
#endif

#if !defined DMG_HALF_FALLOFF
	#define DMG_HALF_FALLOFF        DMG_RADIATION   /**< 50% damage falloff */
#endif

#if !defined DMG_USEDISTANCEMOD
	#define DMG_USEDISTANCEMOD      DMG_SLOWBURN    /**< Do damage falloff */
#endif

#if !defined DMG_IGNITE
	#define DMG_IGNITE              DMG_PLASMA      /**< Ignite victim */
#endif

#if !defined DMG_USE_HITLOCATIONS
	#define DMG_USE_HITLOCATIONS    DMG_AIRBOAT     /**< Do hit location damage (Like the sniperrifle and ambassador) */
#endif

enum SDKHookType
{
	SDKHook_EndTouch,
	SDKHook_FireBulletsPost,
	SDKHook_OnTakeDamage,
	SDKHook_OnTakeDamagePost,
	SDKHook_PreThink,
	SDKHook_PostThink,
	SDKHook_SetTransmit,
	SDKHook_Spawn,
	SDKHook_StartTouch,
	SDKHook_Think,
	SDKHook_Touch,
	SDKHook_TraceAttack,
	SDKHook_TraceAttackPost,
	SDKHook_WeaponCanSwitchTo,
	SDKHook_WeaponCanUse,
	SDKHook_WeaponDrop,
	SDKHook_WeaponEquip,
	SDKHook_WeaponSwitch,
	SDKHook_ShouldCollide,
	SDKHook_PreThinkPost,
	SDKHook_PostThinkPost,
	SDKHook_ThinkPost,
	SDKHook_EndTouchPost,
	SDKHook_GroundEntChangedPost,
	SDKHook_SpawnPost,
	SDKHook_StartTouchPost,
	SDKHook_TouchPost,
	SDKHook_VPhysicsUpdate,
	SDKHook_VPhysicsUpdatePost,
	SDKHook_WeaponCanSwitchToPost,
	SDKHook_WeaponCanUsePost,
	SDKHook_WeaponDropPost,
	SDKHook_WeaponEquipPost,
	SDKHook_WeaponSwitchPost,
	SDKHook_Use,
	SDKHook_UsePost,
	SDKHook_Reload,
	SDKHook_ReloadPost,
	SDKHook_GetMaxHealth,  /**< ep2v and later */
	SDKHook_Blocked,
	SDKHook_BlockedPost,
	SDKHook_OnTakeDamageAlive,
	SDKHook_OnTakeDamageAlivePost,
	SDKHook_CanBeAutobalanced
};

/*
	Alphabetized for easy readability

	SDKHook_Blocked,
	SDKHook_BlockedPost,

	SDKHook_CanBeAutobalanced,

	SDKHook_EndTouch,
	SDKHook_EndTouchPost,

	SDKHook_FireBulletsPost,

	SDKHook_GetMaxHealth,  (ep2v and later)

	SDKHook_GroundEntChangedPost,

	SDKHook_OnTakeDamage,
	SDKHook_OnTakeDamagePost,

	SDKHook_OnTakeDamageAlive,
	SDKHook_OnTakeDamageAlivePost,

	SDKHook_PreThink,
	SDKHook_PreThinkPost,

	SDKHook_PostThink,
	SDKHook_PostThinkPost,

	SDKHook_Reload,
	SDKHook_ReloadPost,

	SDKHook_SetTransmit,

	SDKHook_ShouldCollide,

	SDKHook_Spawn,
	SDKHook_SpawnPost,

	SDKHook_StartTouch,
	SDKHook_StartTouchPost,

	SDKHook_Think,
	SDKHook_ThinkPost,

	SDKHook_Touch,
	SDKHook_TouchPost,

	SDKHook_TraceAttack,
	SDKHook_TraceAttackPost,

	SDKHook_Use,
	SDKHook_UsePost,

	SDKHook_VPhysicsUpdate,
	SDKHook_VPhysicsUpdatePost,

	SDKHook_WeaponCanSwitchTo,
	SDKHook_WeaponCanSwitchToPost,

	SDKHook_WeaponCanUse,
	SDKHook_WeaponCanUsePost,

	SDKHook_WeaponDrop,
	SDKHook_WeaponDropPost,

	SDKHook_WeaponEquip,
	SDKHook_WeaponEquipPost,

	SDKHook_WeaponSwitch,
	SDKHook_WeaponSwitchPost
*/

enum UseType
{
	Use_Off,
	Use_On,
	Use_Set,
	Use_Toggle
};

typeset SDKHookCB
{
	// PreThink/Post
	// PostThink/Post
	function void (int client);

	// Spawn
	function Action (int entity);

	// GroundEntChanged
	// SpawnPost
	// Think/Post
	// VPhysicsUpdate/Post
	function void (int entity);

	// EndTouch
	// StartTouch
	// Touch
	// Blocked
	function Action (int entity, int other);

	// EndTouchPost
	// StartTouchPost
	// TouchPost
	function void (int entity, int other);

	// SetTransmit
	function Action (int entity, int client);

	// WeaponCanSwitchTo
	// WeaponCanUse
	// WeaponDrop
	// WeaponEquip
	// WeaponSwitch
	function Action (int client, int weapon);

	// WeaponCanSwitchToPost
	// WeaponCanUsePost
	// WeaponDropPost
	// WeaponEquipPost
	// WeaponSwitchPost
	function void (int client, int weapon);

	// GetMaxHealth (ep2v and later)
	function Action (int entity, int &maxhealth);

	// OnTakeDamage
	// OnTakeDamageAlive
	// SDKHooks 1.0+
	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype);

	// OnTakeDamage
	// OnTakeDamageAlive
	// Note: The weapon parameter is not used by all games and damage sources.
	// Note: Force application is dependent on game and damage type(s)
	// SDKHooks 2.0+
	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3]);

	// OnTakeDamage
	// OnTakeDamageAlive
	// Note: The weapon parameter is not used by all games and damage sources.
	// Note: Force application is dependent on game and damage type(s)
	// SDKHooks 2.1+  (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability.
	// DON'T attempt to access 'damagecustom' var if feature status != available
	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon,
		float damageForce[3], float damagePosition[3], int damagecustom);

	// OnTakeDamagePost
	// OnTakeDamageAlivePost
	function void (int victim, int attacker, int inflictor, float damage, int damagetype);

	// OnTakeDamagePost
	// OnTakeDamageAlivePost
	function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, const float damageForce[3], const float damagePosition[3]);

	// OnTakeDamagePost
	// OnTakeDamageAlivePost
	function void (int victim, int attacker, int inflictor, float damage, int damagetype, int weapon,
		const float damageForce[3], const float damagePosition[3], int damagecustom);

	// FireBulletsPost
	function void (int client, int shots, const char[] weaponname);

	// TraceAttack
	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup);

	// TraceAttackPost
	function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup);

	// ShouldCollide
	function bool (int entity, int collisiongroup, int contentsmask, bool originalResult);

	// Use
	function Action (int entity, int activator, int caller, UseType type, float value);

	// UsePost
	function void (int entity, int activator, int caller, UseType type, float value);

	// Reload
	function Action (int weapon);

	// Reload post
	function void (int weapon, bool bSuccessful);

	// CanBeAutobalanced
	function bool (int client, bool origRet);
};


/**
 * When an entity is created
 *
 * @param entity        Entity index
 * @param classname     Class name
 */
forward void OnEntityCreated(int entity, const char[] classname);

/**
 * When an entity is destroyed
 *
 * @param entity        Entity index
 */
forward void OnEntityDestroyed(int entity);

/**
 * When the game description is retrieved
 *
 * @note Not supported on ep2v.
 *
 * @param gameDesc      Game description
 * @return              Plugin_Changed if gameDesc has been edited, else no change.
 */
forward Action OnGetGameDescription(char gameDesc[64]);

/**
 * When the level is initialized
 *
 * @param mapName       Name of the map
 * @param mapEntities   Entities of the map
 * @return              Plugin_Changed if mapEntities has been edited, else no change.
 */
forward Action OnLevelInit(const char[] mapName, char mapEntities[2097152]);

/**
 * Hooks an entity
 *
 * @param entity        Entity index
 * @param type          Type of function to hook
 * @param callback      Function to call when hook is called
 */
native void SDKHook(int entity, SDKHookType type, SDKHookCB callback);

/**
 * Hooks an entity
 *
 * @param entity        Entity index
 * @param type          Type of function to hook
 * @param callback      Function to call when hook is called
 * @return              Hook Successful
 */
native bool SDKHookEx(int entity, SDKHookType type, SDKHookCB callback);

/**
 * Unhooks an entity
 *
 * @param entity   Entity index
 * @param type     Type of function to unhook
 * @param callback Callback function to unhook
 */
native void SDKUnhook(int entity, SDKHookType type, SDKHookCB callback);

/**
 * Applies damage to an entity
 *
 * @note Force application is dependent on game and damage type(s)
 *
 * @param entity         Entity index taking damage
 * @param inflictor      Inflictor entity index
 * @param attacker       Attacker entity index
 * @param damage         Amount of damage
 * @param damageType     Bitfield of damage types
 * @param weapon         Weapon index (orangebox and later) or -1 for unspecified
 * @param damageForce    Velocity of damage force
 * @param damagePosition Origin of damage
 */
native void SDKHooks_TakeDamage(int entity, int inflictor, int attacker,
		float damage, int damageType=DMG_GENERIC, int weapon=-1,
		const float damageForce[3]=NULL_VECTOR, const float damagePosition[3]=NULL_VECTOR);

/**
 * Forces a client to drop the specified weapon
 *
 * @param client        Client index.
 * @param weapon        Weapon entity index.
 * @param vecTarget     Location to toss weapon to, or NULL_VECTOR for default.
 * @param vecVelocity   Velocity at which to toss weapon, or NULL_VECTOR for default.
 * @error               Invalid client or weapon entity, weapon not owned by client.
 */
native void SDKHooks_DropWeapon(int client, int weapon, const float vecTarget[3]=NULL_VECTOR,
		const float vecVelocity[3]=NULL_VECTOR);

/**
 * Do not edit below this line!
 */
public Extension __ext_sdkhooks =
{
	name = "SDKHooks",
	file = "sdkhooks.ext",
#if defined AUTOLOAD_EXTENSIONS
	autoload = 1,
#else
	autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
	required = 1,
#else
	required = 0,
#endif
};
