Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix custom weapon issue #4072 #4076

Merged
merged 7 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading