-
Notifications
You must be signed in to change notification settings - Fork 1
/
doom_fall.as
196 lines (158 loc) · 7.24 KB
/
doom_fall.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* doom_fall by Outerbeast
trigger_script that creates a zone at which a player falling at a certain velocity will be sure to take mortal fall damage.
They will go SPLAT.
Template entity:-
"classname" "trigger_script"
"m_iszScriptFile" "doom_fall"
"m_iszScriptFunctionName" "DOOMFALL::FallZone"
"m_iMode" "2"
// Don't change any of the above
"$s_brush" "*m" - Brush model to provide bounds
"$v_mins" "x1 y1 z1" - absmin bound coord for zone
"$v_maxs" "x2 y2 z2" - absmax bound coord for zone
"speed" "s" - fall velocity threshold at which point a player will take mortal fall damage when they land at this speed. Default is 700.
"gravity" "g" - gravity modifier for player falling. Applied when the player's fall velocity reaches "speed".
"message" "target_entity" - entity to trigger when a falling player's fall velocity exceeds "speed". Activator is the player falling.
"netname" "target_entity" - entity to trigger after a player lands on the ground. Activator is the player who fell.
If no or invalid min/max bounds for the death zone are set, the entire level is used
*/
namespace DOOMFALL
{
array<Vector> VEC_PLAYER_FALL_DATA( g_Engine.maxClients + 1 );
const bool
blPlayerSpawn = g_Hooks.RegisterHook( Hooks::Player::PlayerSpawn, OnGround ),
blPlayerPreThink = g_Hooks.RegisterHook( Hooks::Player::PlayerPreThink, Fall ),
blPlayerPostThink = g_Hooks.RegisterHook( Hooks::Player::PlayerPostThink, Splat );
EHandle Enable(float flMortalVelocity, float flGravityModifier)
{
dictionary dictDoomfall =
{
{ "m_iszScriptFile", "doom_fall" },
{ "m_iszScriptFunctionName", "DOOMFALL::FallZone" },
{ "m_iMode", "2" },
{ "speed", "" + flMortalVelocity },
{ "gravity", "" + flGravityModifier }
};
return g_EntityFuncs.CreateEntity( "trigger_script", dictDoomfall );
}
void FallZone(CBaseEntity@ pTriggerScript)
{
Vector vecAbsMin = Vector( -WORLD_BOUNDARY, -WORLD_BOUNDARY, -WORLD_BOUNDARY ), vecAbsMax = Vector( WORLD_BOUNDARY, WORLD_BOUNDARY, WORLD_BOUNDARY );
bool blBoundsSet = SetBounds( EHandle( pTriggerScript ), vecAbsMin, vecAbsMax );
EHandle hBrushModel;
if( !SetBrushModel( pTriggerScript, hBrushModel ) )
{
pTriggerScript.pev.mins = vecAbsMin - pTriggerScript.pev.origin;
pTriggerScript.pev.maxs = vecAbsMax - pTriggerScript.pev.origin;
g_EntityFuncs.SetSize( pTriggerScript.pev, pTriggerScript.pev.mins, pTriggerScript.pev.maxs );
}
for( int iPlayer = 1; iPlayer <= g_Engine.maxClients; iPlayer++ )
{
CBasePlayer@ pPlayer = g_PlayerFuncs.FindPlayerByIndex( iPlayer );
if( pPlayer is null || !pPlayer.IsConnected() || !pPlayer.IsAlive() )
{
VEC_PLAYER_FALL_DATA[iPlayer] = g_vecZero;
continue;
}
const bool blInZone = hBrushModel ? g_Utility.IsPlayerInVolume( pPlayer, hBrushModel.GetEntity() ) : pPlayer.Intersects( pTriggerScript );
VEC_PLAYER_FALL_DATA[iPlayer].z = blInZone ? pTriggerScript.entindex() : 0;
}
}
HookReturnCode OnGround(CBasePlayer@ pPlayer)
{
if( pPlayer is null )
return HOOK_CONTINUE;
VEC_PLAYER_FALL_DATA[pPlayer.entindex()] = g_vecZero;
return HOOK_CONTINUE;
}
HookReturnCode Fall(CBasePlayer@ pPlayer, uint& out uiFlags)
{
if( pPlayer is null || !pPlayer.IsConnected() || !pPlayer.IsAlive() || VEC_PLAYER_FALL_DATA[pPlayer.entindex()].z < 1 )
return HOOK_CONTINUE;
CBaseEntity@ pFallZone = g_EntityFuncs.Instance( int( VEC_PLAYER_FALL_DATA[pPlayer.entindex()].z ) );
if( pFallZone.pev.speed <= 0.0f )
pFallZone.pev.speed = 700.0f;
if( !pPlayer.pev.FlagBitSet( FL_ONGROUND ) && !pPlayer.pev.FlagBitSet( FL_INWATER ) && !pPlayer.IsOnLadder() )
{
VEC_PLAYER_FALL_DATA[pPlayer.entindex()].x = pPlayer.m_flFallVelocity;
if( VEC_PLAYER_FALL_DATA[pPlayer.entindex()].x >= pFallZone.pev.speed && VEC_PLAYER_FALL_DATA[pPlayer.entindex()].y < 1 )
{
VEC_PLAYER_FALL_DATA[pPlayer.entindex()].y = 1;
g_EntityFuncs.FireTargets( pFallZone.pev.message, pPlayer, pFallZone, USE_ON, 0.0f, 0.0f );
if( pFallZone.pev.gravity > 1 )
pPlayer.pev.gravity = pFallZone.pev.gravity;
}
}
else
VEC_PLAYER_FALL_DATA[pPlayer.entindex()] = g_vecZero;
return HOOK_CONTINUE;
}
HookReturnCode Splat(CBasePlayer@ pPlayer)
{
if( pPlayer is null || !pPlayer.IsConnected() || VEC_PLAYER_FALL_DATA[pPlayer.entindex()].z < 1 )
return HOOK_CONTINUE;
if( pPlayer.pev.FlagBitSet( FL_ONGROUND ) && VEC_PLAYER_FALL_DATA[pPlayer.entindex()].y > 0 )
{
CBaseEntity@ pFallZone = g_EntityFuncs.Instance( int( VEC_PLAYER_FALL_DATA[pPlayer.entindex()].z ) );
if( pPlayer.pev.FlagBitSet( FL_GODMODE ) )
pPlayer.pev.flags &= ~FL_GODMODE;
g_EntityFuncs.Remove( pPlayer );
if( !pPlayer.IsAlive() )
{
VEC_PLAYER_FALL_DATA[pPlayer.entindex()].y = 0;
g_EntityFuncs.FireTargets( pFallZone.pev.netname, pPlayer, pFallZone, USE_ON, 0.0f, 0.0f );
if( pPlayer.pev.gravity == pFallZone.pev.gravity )
pPlayer.pev.gravity = 1;
}
}
return HOOK_CONTINUE;
}
bool SetBounds(EHandle hTriggerScript, Vector& out vecMin, Vector& out vecMax)
{
if( !hTriggerScript )
return false;
CustomKeyvalues@ kvTriggerScript = hTriggerScript.GetEntity().GetCustomKeyvalues();
if( kvTriggerScript.HasKeyvalue( "$v_mins" ) && kvTriggerScript.HasKeyvalue( "$v_maxs" ) )
{
if( kvTriggerScript.GetKeyvalue( "$v_mins" ).GetVector() != kvTriggerScript.GetKeyvalue( "$v_maxs" ).GetVector() )
{
vecMin = kvTriggerScript.GetKeyvalue( "$v_mins" ).GetVector();
vecMax = kvTriggerScript.GetKeyvalue( "$v_maxs" ).GetVector();
return vecMin != vecMax;
}
else
return false;
}
else
return false;
}
bool SetBrushModel(EHandle hTriggerScript, EHandle& out hBrushModel)
{
if( !hTriggerScript )
return false;
CustomKeyvalues@ kvTriggerScript = hTriggerScript.GetEntity().GetCustomKeyvalues();
if( kvTriggerScript.HasKeyvalue( "$s_brush" ) )
{
if( kvTriggerScript.GetKeyvalue( "$s_brush" ).GetString() == "" )
return false;
CBaseEntity@ pBBox =
kvTriggerScript.GetKeyvalue( "$s_brush" ).GetString()[0] == "*" ?
g_EntityFuncs.FindEntityByString( pBBox, "model", kvTriggerScript.GetKeyvalue( "$s_brush" ).GetString() ) :
g_EntityFuncs.FindEntityByTargetname( pBBox, kvTriggerScript.GetKeyvalue( "$s_brush" ).GetString() );
if( pBBox !is null && pBBox.IsBSPModel() )
{
hBrushModel = pBBox;
return hBrushModel.IsValid();
}
else
return false;
}
else
return false;
}
}
/* Special thanks to:-
-Zode for extensive support, testing and proofreading
and others I've asked help from for minor things:
-KernCore
-H2 */