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