diff --git a/env/include/sdkhooks-2.2.inc b/env/include/sdkhooks-2.2.inc new file mode 100644 index 0000000..d09c17f --- /dev/null +++ b/env/include/sdkhooks-2.2.inc @@ -0,0 +1,345 @@ +#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 + // TF2 crits and minicrits + #define DMG_CRIT DMG_ACID +#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 +}; + +/* + Alphabetized for easy readability + + SDKHook_EndTouch, + SDKHook_EndTouchPost, + + SDKHook_FireBulletsPost, + + SDKHook_GroundEntChangedPost, + + SDKHook_OnTakeDamage, + SDKHook_OnTakeDamagePost, + + SDKHook_PreThink, + SDKHook_PreThinkPost, + + SDKHook_PostThink, + SDKHook_PostThinkPost, + + 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 +}; + +funcenum SDKHookCB +{ + // PreThink/Post + // PostThink/Post + public(client), + + // GroundEntChanged + // Spawn/Post + // Think/Post + // VPhysicsUpdate/Post + public(entity), + + // EndTouch + // StartTouch + // Touch + Action:public(entity, other), + + // EndTouchPost + // StartTouchPost + // TouchPost + public(entity, other), + + // SetTransmit + Action:public(entity, client), + + // WeaponCanSwitchTo + // WeaponCanUse + // WeaponDrop + // WeaponEquip + // WeaponSwitch + Action:public(client, weapon), + + // WeaponCanSwitchToPost + // WeaponCanUsePost + // WeaponDropPost + // WeaponEquipPost + // WeaponSwitchPost + public(client, weapon), + + // OnTakeDamage + // Note: Force application is dependent on game and damage type(s) + Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype), + Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]), + + // OnTakeDamagePost + public(victim, attacker, inflictor, Float:damage, damagetype), + public(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3]), + + // FireBulletsPost + public(client, shots, const String:weaponname[]), + + // TraceAttack + Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup), + + // TraceAttackPost + public(victim, attacker, inflictor, Float:damage, damagetype, ammotype, hitbox, hitgroup), + + // ShouldCollide + bool:public(entity, collisiongroup, contentsmask, bool:originalResult), + + // Use + Action:public(entity, activator, caller, UseType:type, Float:value), + + // UsePost + public(entity, activator, caller, UseType:type, Float:value) +}; + + +/** + * @brief When an entity is created + * + * @param entity Entity index + * @param classname Class name + * @noreturn + */ +forward OnEntityCreated(entity, const String:classname[]); + +/** + * @brief When an entity is destroyed + * + * @param entity Entity index + * @noreturn + */ +forward OnEntityDestroyed(entity); + +/** + * @brief When the game description is retrieved + * + * @param gameDesc Game description + * @noreturn + */ +forward Action:OnGetGameDescription(String:gameDesc[64]); + +/** + * @brief When the level is initialized + * + * @param mapName Name of the map + * @param mapEntities Entities of the map + * @noreturn + */ +forward Action:OnLevelInit(const String:mapName[], String:mapEntities[2097152]); + +/** + * @brief Hooks an entity + * + * @param entity Entity index + * @param type Type of function to hook + * @param callback Function to call when hook is called + * @noreturn + */ +native SDKHook(entity, SDKHookType:type, SDKHookCB:callback); + +/** + * @brief Hooks an entity + * + * @param entity Entity index + * @param type Type of function to hook + * @param callback Function to call when hook is called + * @return bool Hook Successful + */ +native bool:SDKHookEx(entity, SDKHookType:type, SDKHookCB:callback); + +/** + * @brief Unhooks an entity + * + * @param entity Entity index + * @param type Type of function to unhook + * @param callback Callback function to unhook + * @noreturn + */ +native SDKUnhook(entity, SDKHookType:type, SDKHookCB:callback); + +/** + * @brief 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 + * @noreturn + */ +native SDKHooks_TakeDamage(entity, inflictor, attacker, Float:damage, damageType=DMG_GENERIC, weapon=-1, const Float:damageForce[3]=NULL_VECTOR, const Float:damagePosition[3]=NULL_VECTOR); + +/** + * @brief 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. + * @noreturn + * @error Invalid client or weapon entity, weapon not owned by client. + */ +native SDKHooks_DropWeapon(client, 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 +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_sdkhooks_SetNTVOptional() +{ + MarkNativeAsOptional("SDKHook"); + MarkNativeAsOptional("SDKHookEx"); + MarkNativeAsOptional("SDKUnhook"); + MarkNativeAsOptional("SDKHooks_TakeDamage"); + MarkNativeAsOptional("SDKHooks_DropWeapon"); +} +#endif diff --git a/src/testsuite/zr/damageinfo.sp b/src/testsuite/zr/damageinfo.sp new file mode 100644 index 0000000..0f8ea63 --- /dev/null +++ b/src/testsuite/zr/damageinfo.sp @@ -0,0 +1,164 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: damageinfo.sp + * Type: Test plugin + * Description: Dumps damage information. + * + * Copyright (C) 2009-2012 Greyscale, Richard Helgeby + * + * 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 3 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, see . + * + * ============================================================================ + */ + +#pragma semicolon 1 +#include +#include + +public Plugin:myinfo = +{ + name = "Damage information", + author = "Greyscale | Richard Helgeby", + description = "Dumps damage information.", + version = "1.0.0", + url = "http://code.google.com/p/zombiereloaded/" +}; + +new Handle:hBlockOnTakeDamage; +new Handle:hBlockTraceAttack; + +public OnPluginStart() +{ + hBlockOnTakeDamage = CreateConVar("zrtest_blockontakedamage", "0", "Block OnTakeDamage."); + hBlockTraceAttack = CreateConVar("zrtest_blocktraceattack", "0", "Block TraceAttack."); + + if (!HookEventEx("player_hurt", Event_PlayerHurt)) + { + LogError("Failed to hook event player_hurt."); + } +} + +public OnClientPutInServer(client) +{ + SDKHook(client, SDKHook_TraceAttack, TraceAttack); + SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); +} + +public OnClientDisconnect(client) +{ + SDKUnhook(client, SDKHook_TraceAttack, TraceAttack); + SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage); +} + +public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) +{ + new victim = GetClientOfUserId(GetEventInt(event, "userid")); + new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + new hitgroup = GetEventInt(event, "hitgroup"); + new damage = GetEventInt(event, "dmg_health"); + new damageArmor = GetEventInt(event, "dmg_armor"); + decl String:weapon[64]; + weapon[0] = 0; + GetEventString(event, "weapon", weapon, sizeof(weapon)); + + decl String:msg[128]; + msg[0] = 0; + + Format(msg, sizeof(msg), "victim:%d | attacker:%d | hitgroup:%d | dmg:%d | dmg armor:%d | weapon:%s", victim, attacker, hitgroup, damage, damageArmor, weapon); + + PrintToChat(victim, "Receive hurt event -- %s", msg); + PrintToConsole(victim, "Receive hurt event -- %s", msg); + + if (attacker > 0 && attacker < MaxClients) + { + PrintToChat(attacker, "Send hurt event -- %s", msg); + PrintToConsole(attacker, "Send hurt event -- %s", msg); + } +} + +public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]) +{ + /* + Here we can control whether bullets or other damage that hits the + victim's body should be allowed. + + If TraceAttack is blocked, bullets will go through the body and the + attacker can't deal any damage to the victim. + + By blocking OnTakeDamage we can use this to allow players to actually + hit a player without giving damage to him. This can be used as a simple + trace, for example healing the victim instead of damaging him. + */ + + decl String:msg[128]; + msg[0] = 0; + + Format(msg, sizeof(msg), "victim:%d | attacker:%d | inflictor:%d | dmg:%0.2f | dmg type:%d | weapon ent:%d | force:%0.2f | dmg pos:%0.2f", victim, attacker, inflictor, damage, damagetype, weapon, damageForce, damagePosition); + + PrintToChat(victim, "Damage taken -- %s", msg); + PrintToConsole(victim, "Damage taken -- %s", msg); + + if (attacker > 0 && attacker < MaxClients) + { + PrintToChat(attacker, "Damage given -- %s", msg); + PrintToConsole(attacker, "Damage given -- %s", msg); + } + + if (GetConVarBool(hBlockOnTakeDamage)) + { + return Plugin_Handled; + } + else + { + return Plugin_Continue; + } +} + +public Action:TraceAttack(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup) +{ + /* + Here we can control whether bullets or other damage is allowed to hit + the player's body. + + If blocked, bullets will go through the body. + + OnTakeDamage decides whether damage is actually allowed. + */ + + decl String:msg[128]; + msg[0] = 0; + + Format(msg, sizeof(msg), "victim:%d | attacker:%d | inflictor:%d | dmg:%0.2f | dmg type:%d | ammo type:%d | hitbox:%d | hitgroup: %d", victim, attacker, inflictor, damage, damagetype, ammotype, hitbox, hitgroup); + + PrintToChat(victim, "Receive attack -- %s", msg); + PrintToConsole(victim, "Receive attack -- %s", msg); + + if (attacker > 0 && attacker < MaxClients) + { + PrintToChat(attacker, "Attacking -- %s", msg); + PrintToConsole(attacker, "Attacking -- %s", msg); + } + + if (GetConVarBool(hBlockTraceAttack)) + { + return Plugin_Handled; + } + else + { + return Plugin_Continue; + } +}