diff --git a/extension/natives/baseentity.cpp b/extension/natives/baseentity.cpp index b718e0a..c6f506e 100644 --- a/extension/natives/baseentity.cpp +++ b/extension/natives/baseentity.cpp @@ -510,6 +510,22 @@ cell_t IsCombatCharacter(IPluginContext* context, const cell_t* params) { return entity->MyCombatCharacterPointer() ? 1 : 0; } +cell_t TakeDamage(IPluginContext* context, const cell_t* params) { + auto entity = Get(context, params[1]); + if (!entity) { + return 0; + } + + CTakeDamageInfo* inputInfo = (CTakeDamageInfo*)PawnAddressToPtr(params[2]); + if (!inputInfo) { + context->ThrowNativeError("CTakeDamageInfo is a null ptr!"); + return 0; + } + + entity->TakeDamage(*inputInfo); + return 0; +} + void setup(std::vector& natives) { sp_nativeinfo_t list[] = { {"CBaseEntity.iUpdateOnRemove", iUpdateOnRemove}, @@ -554,7 +570,8 @@ void setup(std::vector& natives) { {"CBaseEntity.MyNextBotPointer", MyNextBotPointer}, {"CBaseEntity.GetBaseAnimating", GetBaseAnimating}, {"CBaseEntity.MyCombatCharacterPointer", MyCombatCharacterPointer}, - {"CBaseEntity.IsCombatCharacter", IsCombatCharacter} + {"CBaseEntity.IsCombatCharacter", IsCombatCharacter}, + {"CBaseEntity.TakeDamage", TakeDamage} }; natives.insert(natives.end(), std::begin(list), std::end(list)); } diff --git a/extension/natives/takedamageinfo.cpp b/extension/natives/takedamageinfo.cpp index 9280beb..b4615d4 100644 --- a/extension/natives/takedamageinfo.cpp +++ b/extension/natives/takedamageinfo.cpp @@ -13,10 +13,10 @@ #include extern SourceMod::IGameHelpers* gamehelpers; -CTakeDamageInfo::CTakeDamageInfo(){} - namespace natives::takedamageinfo { +CTakeDamageInfo g_GlobalDamageInfo; + inline CTakeDamageInfo* Get(IPluginContext* context, const cell_t param) { CTakeDamageInfo* info = (CTakeDamageInfo*)PawnAddressToPtr(param); if (!info) { @@ -30,6 +30,69 @@ cell_t CTakeDamageInfo_Ctor(IPluginContext* context, const cell_t* params) { return PtrToPawnAddress(PawnAddressToPtr(params[1])); } +cell_t GetGlobalDamageInfo(IPluginContext* context, const cell_t* params) { + return PtrToPawnAddress(&g_GlobalDamageInfo); +} + +cell_t Init(IPluginContext* context, const cell_t* params) { + CTakeDamageInfo* info = Get(context, params[1]); + if (!info) { + return 0; + } + + CBaseEntity* inflictor = gamehelpers->ReferenceToEntity(params[2]); + if (!inflictor && params[2] != -1) { + return context->ThrowNativeError("Invalid inflictor index!"); + } + + CBaseEntity* attacker = gamehelpers->ReferenceToEntity(params[3]); + if (!attacker && params[3] != -1) { + return context->ThrowNativeError("Invalid attacker index!"); + } + + CBaseEntity* weapon = gamehelpers->ReferenceToEntity(params[4]); + if (!attacker && params[4] != -1) { + return context->ThrowNativeError("Invalid weapon index!"); + } + + cell_t* damageForceAddr; + context->LocalToPhysAddr(params[5], &damageForceAddr); + Vector damageForce; + if (context->GetNullRef(SP_NULL_VECTOR) == damageForceAddr) { + damageForce = vec3_origin; + } + else { + PawnVectorToVector(damageForceAddr, &damageForce); + } + + cell_t* damagePositionAddr; + context->LocalToPhysAddr(params[6], &damagePositionAddr); + Vector damagePosition; + if (context->GetNullRef(SP_NULL_VECTOR) == damagePositionAddr) { + damagePosition = vec3_origin; + } + else { + PawnVectorToVector(damagePositionAddr, &damagePosition); + } + + float damage = sp_ctof(params[7]); + int bitsDamageType = params[8]; + int customDamage = params[9]; + + cell_t* reportedPositionAddr; + context->LocalToPhysAddr(params[10], &reportedPositionAddr); + Vector reportedPosition; + if (context->GetNullRef(SP_NULL_VECTOR) == reportedPositionAddr) { + reportedPosition = vec3_origin; + } + else { + PawnVectorToVector(reportedPositionAddr, &reportedPosition); + } + + info->Set(inflictor, attacker, weapon, damageForce, damagePosition, damage, bitsDamageType, customDamage, &reportedPosition); + return 0; +} + cell_t GetInflictor(IPluginContext* context, const cell_t* params) { CTakeDamageInfo* info = Get(context, params[1]); if (!info) { @@ -47,7 +110,7 @@ cell_t SetInflictor(IPluginContext* context, const cell_t* params) { CBaseEntity* inflictor = gamehelpers->ReferenceToEntity(params[2]); if (!inflictor && params[2] != -1) { - context->ThrowNativeError("Invalid inflictor index!"); + return context->ThrowNativeError("Invalid inflictor index!"); } info->m_hInflictor = inflictor; return 0; @@ -70,7 +133,7 @@ cell_t SetWeapon(IPluginContext* context, const cell_t* params) { CBaseEntity* weapon = gamehelpers->ReferenceToEntity(params[2]); if (!weapon && params[2] != -1) { - context->ThrowNativeError("Invalid weapon index!"); + return context->ThrowNativeError("Invalid weapon index!"); } info->m_hWeapon = weapon; return 0; @@ -90,7 +153,7 @@ cell_t SetAttacker(IPluginContext* context, const cell_t* params) { CBaseEntity* attacker = gamehelpers->ReferenceToEntity(params[2]); if (!attacker && params[2] != -1) { - context->ThrowNativeError("Invalid attacker index!"); + return context->ThrowNativeError("Invalid attacker index!"); } info->m_hAttacker = attacker; return 0; @@ -503,6 +566,10 @@ void setup(std::vector& natives) { sp_nativeinfo_t list[] = { {"CTakeDamageInfo.CTakeDamageInfo", CTakeDamageInfo_Ctor}, + {"GetGlobalDamageInfo", GetGlobalDamageInfo}, + + {"CTakeDamageInfo.Init", Init}, + {"CTakeDamageInfo.GetInflictor", GetInflictor}, {"CTakeDamageInfo.SetInflictor", SetInflictor}, diff --git a/extension/sourcesdk/baseentity.cpp b/extension/sourcesdk/baseentity.cpp index 13da12c..8e538af 100644 --- a/extension/sourcesdk/baseentity.cpp +++ b/extension/sourcesdk/baseentity.cpp @@ -23,6 +23,7 @@ VCall CBaseEntity::vGetBaseAnimating; VCall CBaseEntity::vMyNextBotPointer; MCall CBaseEntity::mInvalidatePhysicsRecursive; VCall CBaseEntity::vWorldSpaceCenter; +MCall CBaseEntity::mTakeDamage; VCall CBaseEntity::vOnTakeDamage; VCall CBaseEntity::vIsAlive; MCall CBaseEntity::mCalcAbsolutePosition; @@ -120,6 +121,7 @@ bool CBaseEntity::Init(SourceMod::IGameConfig* config, char* error, size_t maxle vMyNextBotPointer.Init(config, "CBaseEntity::MyNextBotPointer"); vWorldSpaceCenter.Init(config, "CBaseEntity::WorldSpaceCenter"); vEyeAngles.Init(config, "CBaseEntity::EyeAngles"); + mTakeDamage.Init(config, "CBaseEntity::TakeDamage"); vOnTakeDamage.Init(configSDKHooks, "OnTakeDamage"); vIsAlive.Init(config, "CBaseEntity::IsAlive"); @@ -303,6 +305,11 @@ const Vector& CBaseEntity::WorldSpaceCenter(void) return vWorldSpaceCenter(this); } +void CBaseEntity::TakeDamage(const CTakeDamageInfo& inputInfo) +{ + return mTakeDamage(this, inputInfo); +} + int CBaseEntity::OnTakeDamage(const CTakeDamageInfo& info) { return vOnTakeDamage(this, info); diff --git a/extension/sourcesdk/baseentity.h b/extension/sourcesdk/baseentity.h index bb338a7..96edc32 100644 --- a/extension/sourcesdk/baseentity.h +++ b/extension/sourcesdk/baseentity.h @@ -146,6 +146,9 @@ class CBaseEntity : public IServerEntity void CalcAbsolutePosition(void); void CalcAbsoluteVelocity(void); + static MCall mTakeDamage; + void TakeDamage(const CTakeDamageInfo& inputInfo); + static VCall vOnTakeDamage; int OnTakeDamage(const CTakeDamageInfo& info); diff --git a/extension/sourcesdk/takedamageinfo.cpp b/extension/sourcesdk/takedamageinfo.cpp index bfd2853..8473211 100644 --- a/extension/sourcesdk/takedamageinfo.cpp +++ b/extension/sourcesdk/takedamageinfo.cpp @@ -2,6 +2,58 @@ #include #include +CTakeDamageInfo::CTakeDamageInfo() +{ + Init( NULL, NULL, NULL, vec3_origin, vec3_origin, vec3_origin, 0, 0, 0 ); +} + +void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, const Vector &reportedPosition, float flDamage, int bitsDamageType, int iCustomDamage ) +{ + m_hInflictor = pInflictor; + if ( pAttacker ) + { + m_hAttacker = pAttacker; + } + else + { + m_hAttacker = pInflictor; + } + + m_hWeapon = pWeapon; + + m_flDamage = flDamage; + + m_flBaseDamage = BASEDAMAGE_NOT_SPECIFIED; + + m_bitsDamageType = bitsDamageType; + m_iDamageCustom = iCustomDamage; + + m_flMaxDamage = flDamage; + m_vecDamageForce = damageForce; + m_vecDamagePosition = damagePosition; + m_vecReportedPosition = reportedPosition; + m_iAmmoType = -1; + m_iDamagedOtherPlayers = 0; + m_iPlayerPenetrationCount = 0; + m_flDamageBonus = 0.f; + m_bForceFriendlyFire = false; + m_flDamageForForce = 0.f; + +#if SOURCE_ENGINE == SE_TF2 + m_eCritType = kCritType_None; +#endif +} + +void CTakeDamageInfo::Set( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pWeapon, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType, Vector *reportedPosition ) +{ + Vector vecReported = vec3_origin; + if ( reportedPosition ) + { + vecReported = *reportedPosition; + } + Init( pInflictor, pAttacker, pWeapon, damageForce, damagePosition, vecReported, flDamage, bitsDamageType, iKillType ); +} + #if SOURCE_ENGINE == SE_TF2 void CTakeDamageInfo::SetCritType( ECritType eType ) { diff --git a/gamedata/cbasenpc.txt b/gamedata/cbasenpc.txt index 55dc86c..0a48c3b 100644 --- a/gamedata/cbasenpc.txt +++ b/gamedata/cbasenpc.txt @@ -268,6 +268,13 @@ "windows" "" "linux" "@_ZN11CBaseEntity15SetGroundEntityEPS_" } + // Find string "CBaseEntity::TakeDamage: with inputInfo.GetDamageForce() == vec3_origin\n" + "CBaseEntity::TakeDamage" + { + "library" "server" + "windows" "\x55\x8B\xEC\x81\xEC\x98\x00\x00\x00\x53\x8B\xD9" + "linux" "@_ZN11CBaseEntity10TakeDamageERK15CTakeDamageInfo" + } // "g_EntityListPool" "g_EntityListPool" { diff --git a/product.version b/product.version index 62321af..1cac385 100644 --- a/product.version +++ b/product.version @@ -1 +1 @@ -1.10.3 \ No newline at end of file +1.11.0 diff --git a/scripting/include/cbasenpc/baseentity.inc b/scripting/include/cbasenpc/baseentity.inc index ce07df1..26d5f86 100644 --- a/scripting/include/cbasenpc/baseentity.inc +++ b/scripting/include/cbasenpc/baseentity.inc @@ -3,6 +3,8 @@ #endif #define _CBASENPC_BASEENTITY_INC_ +#include "takedamageinfo.inc" + methodmap CBaseEntity { public CBaseEntity(int iEnt) @@ -910,4 +912,14 @@ methodmap CBaseEntity { SetEntityMoveType(this.index, val); } + + /** + * Causes the entity to take damage with the given parameters. + * Filters are checked and damage scaling is applied before it calls the + * entity's OnTakeDamage(). + * + * @param inputInfo The damage parameters to use + * @error Invalid entity or a NULL pointer is given + */ + public native void TakeDamage(CTakeDamageInfo inputInfo); } \ No newline at end of file diff --git a/scripting/include/cbasenpc/takedamageinfo.inc b/scripting/include/cbasenpc/takedamageinfo.inc index b98be71..2e53d64 100644 --- a/scripting/include/cbasenpc/takedamageinfo.inc +++ b/scripting/include/cbasenpc/takedamageinfo.inc @@ -19,6 +19,22 @@ methodmap CTakeDamageInfo */ public native CTakeDamageInfo(Address ptr); + /** + * Initializes the CTakeDamageInfo's values. + * + * @param inflictor The inflictor entity index. + * @param attacker The attacker entity index. + * @param weapon The weapon entity index. + * @param damageForce The damage force vector. + * @param damagePosition The damage position vector. + * @param damage The amount of damage to set. + * @param bitsDamageType The damage type bitmask. + * @param customDamage The custom damage to set. + * @param reportedPosition The position to report to players on where the damage came from. + * @error Invalid takedamageinfo, or invalid inflictor, attacker, and weapon entity index. + */ + public native void Init(int inflictor = -1, int attacker = -1, int weapon = -1, const float damageForce[3] = NULL_VECTOR, const float damagePosition[3] = NULL_VECTOR, float damage = 0.0, int bitsDamageType = 0, int customDamage = 0, const float reportedPosition[3] = NULL_VECTOR); + /** * Gets the inflictor. * @@ -249,7 +265,7 @@ methodmap CTakeDamageInfo * @param bitmask The damage type bitmask. * @error Invalid takedamageinfo. */ - public native int SetDamageType(); + public native int SetDamageType(int bitmask); /** * Adds the damage bitmask to the current damage bitmask. @@ -257,7 +273,7 @@ methodmap CTakeDamageInfo * @param bitmask The damage type bitmask to add. * @error Invalid takedamageinfo. */ - public native int AddDamageType(); + public native int AddDamageType(int bitmask); /** * Gets the custom damage. @@ -370,4 +386,13 @@ methodmap CTakeDamageInfo * @error Invalid takedamageinfo. */ public native TakeDamageInfo_CritType GetCritType(); -}; \ No newline at end of file +}; + +/** + * Returns the address of a global CTakeDamageInfo object. Make sure to + * initialize the values of the object first using CTakeDamageInfo.Init() + * before modifying and using it in a function call. + * + * @return Address to the global CTakeDamageInfo object. + */ +native CTakeDamageInfo GetGlobalDamageInfo(); \ No newline at end of file