Skip to content

Commit

Permalink
Fix custom weapon issue #4072 (#4076)
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX authored Mar 6, 2025
1 parent a8bf644 commit a744cd1
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 78 deletions.
57 changes: 30 additions & 27 deletions Client/game_sa/CWeaponSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

extern CGameSA* pGame;

CWeaponInfo* CWeaponSA::GetInfo(const eWeaponSkill& skill) const
CWeaponInfo* CWeaponSA::GetInfo(eWeaponSkill skill) const
{
return m_interface ? pGame->GetWeaponInfo(m_interface->m_eWeaponType, skill) : nullptr;
}
Expand Down Expand Up @@ -55,42 +55,41 @@ void CWeaponSA::Remove()
}
}

void CWeaponSA::Initialize(const eWeaponType& type, std::uint32_t ammo, CPed* ped)
void CWeaponSA::Initialize(eWeaponType type, std::uint32_t ammo, CPed* ped)
{
if (m_interface)
m_interface->Initialize(type, ammo, ped);
}

void CWeaponSA::Update(CPed* ped)
{
// Note: CWeapon::Update is called mainly to check for reload
if (m_interface)
m_interface->Update(ped);
m_interface->Initialize(type, ammo, ped ? ped->GetPedInterface() : nullptr);
}

void CWeaponSA::AddGunshell(CEntity* firingEntity, const CVector& vecOrigin, const CVector2D& vecDirection, float size) const
{
if (m_interface && firingEntity)
m_interface->AddGunshell(firingEntity, vecOrigin, vecDirection, size);
m_interface->AddGunshell(firingEntity->GetInterface(), vecOrigin, vecDirection, size);
}

void CWeaponSA::DoBulletImpact(CEntity* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget, const CColPoint& colPoint, int incrementalHit) const
void CWeaponSA::DoBulletImpact(CEntity* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget,
const CColPointSAInterface& colPoint, int incrementalHit) const
{
if (m_interface)
m_interface->DoBulletImpact(firingEntity, hitEntityInterface, vecOrigin, vecTarget, colPoint, incrementalHit);
m_interface->DoBulletImpact(firingEntity ? firingEntity->GetInterface() : nullptr, hitEntityInterface, vecOrigin, vecTarget, colPoint, incrementalHit);
}

bool CWeaponSA::Fire(CEntity* firingEntity, CVector* vecOrigin, CVector* vecEffectPos, CEntity* targetEntity, CVector* vecTarget, CVector* vecAlt)
{
if (!firingEntity)
if (!firingEntity || !m_interface)
return false;

return m_interface ? m_interface->Fire(firingEntity, vecOrigin, vecEffectPos, targetEntity, vecTarget, vecAlt) : false;
return m_interface->Fire(firingEntity->GetInterface(), vecOrigin, vecEffectPos, targetEntity ? targetEntity->GetInterface() : nullptr, vecTarget, vecAlt);
}

bool CWeaponSA::FireInstantHit(CEntity* firingEntity, const CVector* vecOrigin, const CVector* vecMuzzle, CEntity* targetEntity, const CVector* vecTarget, const CVector* vecForDriveby, bool crossHairGun, bool createGunFx)
bool CWeaponSA::FireInstantHit(CEntity* firingEntity, CVector* vecOrigin, CVector* vecMuzzle, CEntity* targetEntity, CVector* vecTarget, CVector* vecForDriveby,
bool crossHairGun, bool createGunFx)
{
return m_interface ? m_interface->FireInstantHit(firingEntity, const_cast<CVector*>(vecOrigin), const_cast<CVector*>(vecMuzzle), targetEntity, const_cast<CVector*>(vecTarget), const_cast<CVector*>(vecForDriveby), crossHairGun, createGunFx) : false;
if (!m_interface)
return false;

return m_interface->FireInstantHit(firingEntity ? firingEntity->GetInterface() : nullptr, vecOrigin, vecMuzzle,
targetEntity ? targetEntity->GetInterface() : nullptr, vecTarget, vecForDriveby, crossHairGun, createGunFx);
}

bool CWeaponSA::FireBullet(CEntity* firingEntity, const CVector& vecOrigin, const CVector& vecTarget)
Expand Down Expand Up @@ -130,7 +129,7 @@ bool CWeaponSA::FireBullet(CEntity* firingEntity, const CVector& vecOrigin, cons
firingPlayerPed->GetTransformedBonePosition(BONE_RIGHTWRIST, &vecGunMuzzle);

// Bullet trace
FireInstantHit(firingEntity, &vecOrigin, &vecGunMuzzle, nullptr, &vecTarget, nullptr, false, true);
FireInstantHit(firingEntity, const_cast<CVector*>(&vecOrigin), &vecGunMuzzle, nullptr, const_cast<CVector*>(&vecTarget), nullptr, false, true);

// Fire sound
if (firingPlayerPed)
Expand All @@ -156,23 +155,26 @@ bool CWeaponSA::GenerateDamageEvent(CPed* ped, CEntity* responsible, eWeaponType
if (!ped || !m_interface)
return false;

return m_interface->GenerateDamageEvent(ped, responsible, weaponType, damagePerHit, hitZone, dir);
return m_interface->GenerateDamageEvent(ped ? ped->GetPedInterface() : nullptr, responsible ? responsible->GetInterface() : nullptr, weaponType,
damagePerHit, hitZone, dir);
}

bool CWeaponSA::ProcessLineOfSight(const CVector* vecStart, const CVector* vecEnd, CColPoint** colCollision, CEntity** collisionEntity, const SLineOfSightFlags& flags, SLineOfSightBuildingResult* buildingResult, const eWeaponType& weaponType, CEntitySAInterface** entity)
bool CWeaponSA::ProcessLineOfSight(const CVector& vecStart, const CVector& vecEnd, CColPoint** colCollision, CEntity*& collisionEntity,
const SLineOfSightFlags& flags, SLineOfSightBuildingResult* buildingResult, eWeaponType weaponType,
CEntitySAInterface** entity)
{
// Call CBirds::HandleGunShot
((void(__cdecl*)(CVector*, CVector*))FUNC_CBirds_CheckForHit)(const_cast<CVector*>(vecStart), const_cast<CVector*>(vecEnd));
((void(__cdecl*)(const CVector*, const CVector*))FUNC_CBirds_CheckForHit)(&vecStart, &vecEnd);

// Call CShadows::GunShotSetsOilOnFire
((void(__cdecl*)(CVector*, CVector*))FUNC_CShadows_CheckForHit)(const_cast<CVector*>(vecStart), const_cast<CVector*>(vecEnd));
((void(__cdecl*)(const CVector&, const CVector&))FUNC_CShadows_CheckForHit)(vecStart, vecEnd);

bool hit = pGame->GetWorld()->ProcessLineOfSight(vecStart, vecEnd, colCollision, collisionEntity, flags, buildingResult);
bool hit = pGame->GetWorld()->ProcessLineOfSight(&vecStart, &vecEnd, colCollision, &collisionEntity, flags, buildingResult);

if (hit)
{
if (*collisionEntity)
*entity = (*collisionEntity)->GetInterface();
if (collisionEntity)
*entity = collisionEntity->GetInterface();
else
{
if (buildingResult->bValid)
Expand All @@ -182,7 +184,8 @@ bool CWeaponSA::ProcessLineOfSight(const CVector* vecStart, const CVector* vecEn

// Call CWeapon::CheckForShootingVehicleOccupant
if (*entity && (*entity)->nType == ENTITY_TYPE_VEHICLE)
((void(__cdecl*)(CEntitySAInterface*, CColPointSAInterface*, eWeaponType, CVector*, CVector*))FUNC_CWeapon_CheckForShootingVehicleOccupant)(*entity, (*colCollision)->GetInterface(), weaponType, const_cast<CVector*>(vecStart), const_cast<CVector*>(vecEnd));
((bool(__cdecl*)(CEntitySAInterface**, CColPointSAInterface*, eWeaponType, const CVector&,
const CVector&))FUNC_CWeapon_CheckForShootingVehicleOccupant)(entity, (*colCollision)->GetInterface(), weaponType, vecStart, vecEnd);

return hit;
}
Expand All @@ -199,6 +202,6 @@ int CWeaponSA::GetWeaponReloadTime(CWeaponStat* weaponStat) const
int CWeaponSA::GetWeaponFireTime(CWeaponStat* weaponStat)
{
std::uint32_t timer = pGame->GetSystemTime();
float weaponFireTime = (weaponStat->GetWeaponAnimLoopStop() - weaponStat->GetWeaponAnimLoopStart()) * 1000.0f;
float weaponFireTime = (weaponStat->GetWeaponAnimLoopStop() - weaponStat->GetWeaponAnimLoopStart()) * 1000.0f;
return static_cast<int>(weaponFireTime);
}
117 changes: 78 additions & 39 deletions Client/game_sa/CWeaponSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,9 @@

#pragma once

#define FUNC_CWeapon_Shutdown 0x73A380
#define FUNC_CWeapon_CheckForShootingVehicleOccupant 0x73f480
#define FUNC_CWeapon_Initialize 0x73b4a0
#define FUNC_CWeapon_Update 0x73db40
#define FUNC_CWeapon_Fire 0x742300
#define FUNC_CWeapon_AddGunshell 0x73a3e0
#define FUNC_CWeapon_DoBulletImpact 0x73b550
#define FUNC_CWeapon_GenerateDamageEvent 0x73a530
#define FUNC_CWeapon_FireInstantHit 0x73FB10
#define FUNC_CBirds_CheckForHit 0x712E40
#define FUNC_CShadows_CheckForHit 0x707550
#define FUNC_CWeapon_CheckForShootingVehicleOccupant 0x73f480
#define FUNC_CBirds_CheckForHit 0x712E40
#define FUNC_CShadows_CheckForHit 0x707550

class CWeaponSAInterface
{
Expand All @@ -31,64 +23,111 @@ class CWeaponSAInterface
std::uint32_t m_ammoInClip{0};
std::uint32_t m_ammoTotal{0};
std::uint32_t m_timeToNextShootInMS{0};
bool m_firstPersonEnabled{false}; // Unused
bool m_dontPlaceInHand{false}; // Used in case of goggles
FxSystem_c* m_fxSystem{nullptr}; // Fx system (flamethrower, spraycan, extinguisher)

void Shutdown() { ((void(__thiscall*)(CWeaponSAInterface*))FUNC_CWeapon_Shutdown)(this); }
void Initialize(const eWeaponType& weaponType, std::uint32_t ammo, CPed* ped) { ((void(__thiscall*)(CWeaponSAInterface*, eWeaponType, std::uint32_t, CPedSAInterface*))FUNC_CWeapon_Initialize)(this, weaponType, ammo, ped ? ped->GetPedInterface() : nullptr); }
void Update(CPed* ped) { ((void(__thiscall*)(CWeaponSAInterface*, CPedSAInterface*))FUNC_CWeapon_Update)(this, ped ? ped->GetPedInterface() : nullptr); }
void AddGunshell(CEntity* firingEntity, const CVector& vecOrigin, const CVector2D& vecDirection, float size) { ((void(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, const CVector&, const CVector2D&, float))FUNC_CWeapon_AddGunshell)(this, firingEntity ? firingEntity->GetInterface() : nullptr, vecOrigin, vecDirection, size); }
void DoBulletImpact(CEntity* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget, const CColPoint& colPoint, int incrementalHit) { ((void(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CEntitySAInterface*, const CVector&, const CVector&, const CColPoint&, int))FUNC_CWeapon_DoBulletImpact)(this, firingEntity ? firingEntity->GetInterface() : nullptr, hitEntityInterface, vecOrigin, vecTarget, colPoint, incrementalHit); }
bool Fire(CEntity* firingEntity, CVector* vecOrigin, CVector* vecEffectPos, CEntity* targetEntity, CVector* vecTarget, CVector* vecAlt) { return ((bool(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CVector*, CVector*, CEntitySAInterface*, CVector*, CVector*))FUNC_CWeapon_Fire)(this, firingEntity ? firingEntity->GetInterface() : nullptr, vecOrigin, vecEffectPos, targetEntity ? targetEntity->GetInterface() : nullptr, vecTarget, vecAlt); }
bool FireInstantHit(CEntity* firingEntity, CVector* vecOrigin, CVector* vecMuzzle, CEntity* targetEntity, CVector* vecTarget, CVector* vecForDriveby, bool crossHairGun, bool createGunFx) { return ((bool(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CVector*, CVector*, CEntitySAInterface*, CVector*, CVector*, bool, bool))FUNC_CWeapon_FireInstantHit)(this, firingEntity ? firingEntity->GetInterface() : nullptr, vecOrigin, vecMuzzle, targetEntity ? targetEntity->GetInterface() : nullptr, vecTarget, vecForDriveby, crossHairGun, createGunFx); }
bool GenerateDamageEvent(CPed* ped, CEntity* responsible, eWeaponType weaponType, int damagePerHit, ePedPieceTypes hitZone, std::uint8_t dir) { return ((bool(__thiscall*)(CWeaponSAInterface*, CPedSAInterface*, CEntitySAInterface*, eWeaponType, int, ePedPieceTypes, std::uint8_t))FUNC_CWeapon_GenerateDamageEvent)(this, ped ? ped->GetPedInterface() : nullptr, responsible ? responsible->GetInterface() : nullptr, weaponType, damagePerHit, hitZone, dir); }
bool m_firstPersonEnabled{false}; // Unused
bool m_dontPlaceInHand{false}; // Used in case of goggles
FxSystem_c* m_fxSystem{nullptr}; // Fx system (flamethrower, spraycan, extinguisher)

void Shutdown() { ((void(__thiscall*)(CWeaponSAInterface*))0x73A380)(this); }
void Initialize(eWeaponType weaponType, std::uint32_t ammo, CPedSAInterface* ped)
{
((void(__thiscall*)(CWeaponSAInterface*, eWeaponType, std::uint32_t, CPedSAInterface*))0x73B4A0)(this, weaponType, ammo, ped);
}
void AddGunshell(CEntitySAInterface* firingEntity, const CVector& vecOrigin, const CVector2D& vecDirection, float size)
{
((void(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, const CVector&, const CVector2D&, float))0x73A3E0)(this, firingEntity, vecOrigin,
vecDirection, size);
}
void DoBulletImpact(CEntitySAInterface* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget,
const CColPointSAInterface& colPoint, int incrementalHit)
{
((void(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CEntitySAInterface*, const CVector&, const CVector&, const CColPointSAInterface&,
int))0x73B550)(this, firingEntity, hitEntityInterface, vecOrigin, vecTarget, colPoint, incrementalHit);
}
bool Fire(CEntitySAInterface* firingEntity, CVector* vecOrigin, CVector* vecEffectPos, CEntitySAInterface* targetEntity, CVector* vecTarget,
CVector* vecAlt)
{
return ((bool(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CVector*, CVector*, CEntitySAInterface*, CVector*, CVector*))0x742300)(
this, firingEntity, vecOrigin, vecEffectPos, targetEntity, vecTarget, vecAlt);
}
bool FireInstantHit(CEntitySAInterface* firingEntity, CVector* vecOrigin, CVector* vecMuzzle, CEntitySAInterface* targetEntity, CVector* vecTarget,
CVector* vecForDriveby, bool crossHairGun, bool createGunFx)
{
return ((bool(__thiscall*)(CWeaponSAInterface*, CEntitySAInterface*, CVector*, CVector*, CEntitySAInterface*, CVector*, CVector*, bool, bool))0x73FB10)(
this, firingEntity, vecOrigin, vecMuzzle, targetEntity, vecTarget, vecForDriveby, crossHairGun, createGunFx);
}
bool GenerateDamageEvent(CPedSAInterface* ped, CEntitySAInterface* responsible, eWeaponType weaponType, int damagePerHit, ePedPieceTypes hitZone,
std::uint8_t dir)
{
return ((bool(__thiscall*)(CWeaponSAInterface*, CPedSAInterface*, CEntitySAInterface*, eWeaponType, int, ePedPieceTypes, std::uint8_t))0x73A530)(
this, ped, responsible, weaponType, damagePerHit, hitZone, dir);
}
};
static_assert(sizeof(CWeaponSAInterface) == 0x1C, "Invalid size for CWeaponSAInterface");

class CWeaponSA : public CWeapon
{
public:
CWeaponSA(CWeaponSAInterface* weaponInterface, CPed* owner, eWeaponSlot weaponSlot) : m_interface(weaponInterface), m_owner(owner), m_weaponSlot(weaponSlot) {}
CWeaponSA(CWeaponSAInterface* weaponInterface, CPed* owner, eWeaponSlot weaponSlot) : m_interface(weaponInterface), m_owner(owner), m_weaponSlot(weaponSlot)
{
}
CWeaponSAInterface* GetInterface() { return m_interface; }
CWeaponSAInterface* GetInterface() const { return m_interface; }

eWeaponType GetType() const override { return m_interface ? m_interface->m_eWeaponType : eWeaponType::WEAPONTYPE_UNIDENTIFIED; }
void SetType(const eWeaponType& type) override { if (m_interface) m_interface->m_eWeaponType = type; }
void SetType(eWeaponType type) override
{
if (m_interface)
m_interface->m_eWeaponType = type;
}

eWeaponState GetState() const override { return m_interface ? m_interface->m_eState : eWeaponState::WEAPONSTATE_READY; }
void SetState(const eWeaponState& state) override { if (m_interface) m_interface->m_eState = state; }
void SetState(eWeaponState state) override
{
if (m_interface)
m_interface->m_eState = state;
}

std::uint32_t GetAmmoInClip() const override { return m_interface ? m_interface->m_ammoInClip : 0; }
void SetAmmoInClip(std::uint32_t ammoInClip) override { if (m_interface) m_interface->m_ammoInClip = ammoInClip; }
void SetAmmoInClip(std::uint32_t ammoInClip) override
{
if (m_interface)
m_interface->m_ammoInClip = ammoInClip;
}

std::uint32_t GetAmmoTotal() const override { return m_interface ? m_interface->m_ammoTotal : 0; }
void SetAmmoTotal(std::uint32_t ammoTotal) override { if (m_interface) m_interface->m_ammoTotal = ammoTotal; }
void SetAmmoTotal(std::uint32_t ammoTotal) override
{
if (m_interface)
m_interface->m_ammoTotal = ammoTotal;
}

CPed* GetPed() const noexcept override { return m_owner; }
eWeaponSlot GetSlot() const noexcept override { return m_weaponSlot; }
CWeaponInfo* GetInfo(const eWeaponSkill& skill) const override;
CPed* GetPed() const noexcept override { return m_owner; }
eWeaponSlot GetSlot() const noexcept override { return m_weaponSlot; }
CWeaponInfo* GetInfo(eWeaponSkill skill) const override;

void SetAsCurrentWeapon() override;

void Destroy() override;
void Remove() override;
void Initialize(const eWeaponType& type, std::uint32_t ammo, CPed* ped) override;
void Update(CPed* ped) override;
void Initialize(eWeaponType type, std::uint32_t ammo, CPed* ped) override;

void AddGunshell(CEntity* firingEntity, const CVector& vecOrigin, const CVector2D& vecDirection, float size) const override;
void DoBulletImpact(CEntity* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget, const CColPoint& colPoint, int incrementalHit) const override;
void DoBulletImpact(CEntity* firingEntity, CEntitySAInterface* hitEntityInterface, const CVector& vecOrigin, const CVector& vecTarget,
const CColPointSAInterface& colPoint, int incrementalHit) const override;
bool Fire(CEntity* firingEntity, CVector* vecOrigin, CVector* vecEffectPos, CEntity* targetEntity, CVector* vecTarget, CVector* vecAlt) override;
bool FireInstantHit(CEntity* firingEntity, const CVector* vecOrigin, const CVector* vecMuzzle, CEntity* targetEntity, const CVector* vecTarget, const CVector* vecForDriveby, bool crossHairGun, bool createGunFx) override;
bool FireInstantHit(CEntity* firingEntity, CVector* vecOrigin, CVector* vecMuzzle, CEntity* targetEntity, CVector* vecTarget, CVector* vecForDriveby,
bool crossHairGun, bool createGunFx) override;
bool FireBullet(CEntity* firingEntity, const CVector& vecOrigin, const CVector& vecTarget) override;

bool GenerateDamageEvent(CPed* ped, CEntity* responsible, eWeaponType weaponType, int damagePerHit, ePedPieceTypes hitZone, std::uint8_t dir) const override;
bool GenerateDamageEvent(CPed* ped, CEntity* responsible, eWeaponType weaponType, int damagePerHit, ePedPieceTypes hitZone,
std::uint8_t dir) const override;

bool ProcessLineOfSight(const CVector* vecStart, const CVector* vecEnd, CColPoint** colCollision, CEntity** collisionEntity, const SLineOfSightFlags& flags, SLineOfSightBuildingResult* buildingResult, const eWeaponType& weaponType, CEntitySAInterface** entity) override;
bool ProcessLineOfSight(const CVector& vecStart, const CVector& vecEnd, CColPoint** colCollision, CEntity*& collisionEntity, const SLineOfSightFlags& flags,
SLineOfSightBuildingResult* buildingResult, eWeaponType weaponType, CEntitySAInterface** entity) override;

int GetWeaponReloadTime(CWeaponStat* weaponStat) const override;
int GetWeaponReloadTime(CWeaponStat* weaponStat) const override;
static int GetWeaponFireTime(CWeaponStat* weaponStat);

private:
CWeaponSAInterface* m_interface{nullptr};
CPed* m_owner{nullptr};
Expand Down
Loading

0 comments on commit a744cd1

Please sign in to comment.