Skip to content

Commit dc85e9a

Browse files
committed
New effect: Water Cannon
1 parent 418e2c6 commit dc85e9a

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include "util/EffectBase.h"
2+
#include "util/GenericUtil.h"
3+
#include "util/hooks/HookMacros.h"
4+
5+
#include <set>
6+
7+
#include <CCamera.h>
8+
#include <CStreaming.h>
9+
#include <CWeaponInfo.h>
10+
11+
namespace
12+
{
13+
typedef void (*CWaterCannons_UpdateOne_f) (uint32_t vehicle, CVector *start,
14+
CVector *end);
15+
} // namespace
16+
17+
class WaterCannonEffect : public EffectBase
18+
{
19+
private:
20+
const int PED_DAMAGE_TIME = 750;
21+
static inline std::set<CPed *> pedsSet{};
22+
static inline int timer = 0;
23+
static inline CWaterCannons_UpdateOne_f WaterCannonsUpdateOne = nullptr;
24+
25+
public:
26+
void
27+
OnStart (EffectInstance *inst) override
28+
{
29+
if (!WaterCannonsUpdateOne)
30+
{
31+
WaterCannonsUpdateOne
32+
= reinterpret_cast<CWaterCannons_UpdateOne_f> (0x728CB0);
33+
}
34+
HOOK_METHOD_ARGS (inst, Hooked_CWeapon_Fire,
35+
char (CWeapon *, CPed *, CVector *, CVector *,
36+
CEntity *, CVector *, CVector *),
37+
0x742300);
38+
39+
HOOK_ARGS (inst, Hook_RwIm3DTransform,
40+
void *(RwIm3DVertex *, RwUInt32, RwMatrix *, RwUInt32),
41+
0x729551);
42+
43+
HOOK_METHOD_ARGS (inst, Hooked_CPhysical_ApplyMoveForce,
44+
void (CPhysical *, CVector), 0x729906);
45+
46+
auto *player = FindPlayerPed ();
47+
if (!player) return;
48+
49+
CStreaming::RequestModel (MODEL_FIRE_EX, 2);
50+
CStreaming::LoadAllRequestedModels (false);
51+
52+
player->GiveWeapon (WEAPON_EXTINGUISHER, 500, 1);
53+
const auto *info = CWeaponInfo::GetWeaponInfo (WEAPON_EXTINGUISHER, 1);
54+
player->SetCurrentWeapon (info->m_nSlot);
55+
56+
CStreaming::SetModelIsDeletable (MODEL_FIRE_EX);
57+
58+
timer = 0;
59+
}
60+
61+
void
62+
OnTick (EffectInstance *inst) override
63+
{
64+
timer += int (GenericUtil::CalculateTick ());
65+
66+
if (timer >= PED_DAMAGE_TIME)
67+
{
68+
bool pedDamaged = false;
69+
for (auto *ped : pedsSet)
70+
{
71+
if (!ped) continue;
72+
ped->m_fHealth -= inst->Random (7.0f, 11.0f);
73+
ped->m_fHealth = std::max (0.0f, ped->m_fHealth);
74+
pedDamaged = true;
75+
}
76+
77+
auto *player = FindPlayerPed ();
78+
if (pedDamaged && player && inst->Random (0, 1))
79+
{
80+
plugin::Call<0x532010, eCrimeType, CEntity *, CPed *> (
81+
CRIME_FIRE_WEAPON_HIT_PED, player, player);
82+
}
83+
84+
pedsSet.clear ();
85+
86+
timer -= PED_DAMAGE_TIME;
87+
}
88+
}
89+
90+
static void
91+
Hooked_CPhysical_ApplyMoveForce (auto &&cb, CPhysical *self, CVector force)
92+
{
93+
cb ();
94+
95+
auto *player = FindPlayerPed ();
96+
for (CPed *ped : CPools::ms_pPedPool)
97+
{
98+
if (ped->m_nPhysicalFlags.bInfiniteMass
99+
&& ped->m_nPhysicalFlags.bDisableMoveForce)
100+
{
101+
continue;
102+
}
103+
if (ped == self && ped != player && ped->m_fHealth > 0.0f)
104+
{
105+
pedsSet.emplace (ped);
106+
break;
107+
}
108+
}
109+
}
110+
111+
static void *
112+
Hook_RwIm3DTransform (auto &&cb, RwIm3DVertex *pVerts, RwUInt32 numVerts,
113+
RwMatrix *ltm, RwUInt32 flags)
114+
{
115+
if (pVerts)
116+
{
117+
RwRGBA waterColor{240, 240, 100, 0};
118+
for (int i = 0; i < numVerts; i++)
119+
{
120+
RwUInt8 alpha = (pVerts[i].color >> 24) & 0xFF;
121+
122+
pVerts[i].color = RwUInt32 (alpha << 24)
123+
| RwUInt32 (waterColor.red << 16)
124+
| RwUInt32 (waterColor.green << 8)
125+
| RwUInt32 (waterColor.blue);
126+
}
127+
}
128+
return cb ();
129+
}
130+
131+
static char
132+
Hooked_CWeapon_Fire (auto &&cb, CWeapon *thisWeapon, CPed *owner,
133+
CVector *vecOrigin, CVector *_vecEffectPosn,
134+
CEntity *targetEntity, CVector *vecTarget,
135+
CVector *arg_14)
136+
{
137+
auto *player = FindPlayerPed ();
138+
if (player && owner == player && WaterCannonsUpdateOne && thisWeapon
139+
&& thisWeapon->m_eWeaponType == WEAPON_EXTINGUISHER)
140+
{
141+
auto beginPoint
142+
= player->TransformFromObjectSpace ({0.0f, 0.0f, -0.085f});
143+
float dirX = 0.75f * -std::sin (player->GetHeading ());
144+
float dirY = 0.75f * std::cos (player->GetHeading ());
145+
beginPoint.x += dirX;
146+
beginPoint.y += dirY;
147+
CVector endPoint = TheCamera.m_matrix->up;
148+
endPoint /= 1.5f;
149+
WaterCannonsUpdateOne ((uint32_t) player, &beginPoint, &endPoint);
150+
151+
return 1;
152+
}
153+
154+
return cb ();
155+
}
156+
};
157+
158+
DEFINE_EFFECT (WaterCannonEffect, "effect_water_cannon", GROUP_WEAPONS);

0 commit comments

Comments
 (0)