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
|
untyped //TODO: get rid of player.s.cloakedShotsAllowed. (Referenced in base_gametype_sp, so remove for R5)
global function PlayerCloak_Init
global const CLOAK_FADE_IN = 1.0
global const CLOAK_FADE_OUT = 1.0
global function EnableCloak
global function DisableCloak
global function EnableCloakForever
global function DisableCloakForever
//=========================================================
// player_cloak
//
//=========================================================
void function PlayerCloak_Init()
{
RegisterSignal( "OnStartCloak" )
RegisterSignal( "KillHandleCloakEnd" ) //Somewhat awkward, mainly to smooth out weird interactions with cloak ability and cloak execution
AddCallback_OnPlayerKilled( AbilityCloak_OnDeath )
AddSpawnCallback( "npc_titan", SetCannotCloak )
}
void function SetCannotCloak( entity ent )
{
ent.SetCanCloak( false )
}
void function PlayCloakSounds( entity player )
{
EmitSoundOnEntityOnlyToPlayer( player, player, "cloak_on_1P" )
EmitSoundOnEntityExceptToPlayer( player, player, "cloak_on_3P" )
EmitSoundOnEntityOnlyToPlayer( player, player, "cloak_sustain_loop_1P" )
EmitSoundOnEntityExceptToPlayer( player, player, "cloak_sustain_loop_3P" )
}
void function EnableCloak( entity player, float duration, float fadeIn = CLOAK_FADE_IN )
{
if ( player.cloakedForever )
return
thread AICalloutCloak( player )
PlayCloakSounds( player )
float cloakDuration = duration - fadeIn
Assert( cloakDuration > 0.0, "Not valid cloak duration. Check that duration is larger than the fadeinTime. When this is not true it will cause the player to be cloaked forever. If you want to do that use EnableCloakForever instead" )
player.SetCloakDuration( fadeIn, cloakDuration, CLOAK_FADE_OUT )
player.s.cloakedShotsAllowed = 0
Battery_StopFXAndHideIconForPlayer( player )
thread HandleCloakEnd( player )
}
void function AICalloutCloak( entity player )
{
player.EndSignal( "OnDeath" )
wait CLOAK_FADE_IN //Give it a beat after cloak has finishing cloaking in
array<entity> nearbySoldiers = GetNPCArrayEx( "npc_soldier", TEAM_ANY, player.GetTeam(), player.GetOrigin(), 1000 ) //-1 for distance parameter means all spectres in map
foreach ( entity grunt in nearbySoldiers )
{
if ( !IsAlive( grunt ) )
continue
if ( grunt.GetEnemy() == player )
{
ScriptDialog_PilotCloaked( grunt, player )
return //Only need one guy to say this instead of multiple guys
}
}
}
void function EnableCloakForever( entity player )
{
player.SetCloakDuration( CLOAK_FADE_IN, -1, CLOAK_FADE_OUT )
player.cloakedForever = true
thread HandleCloakEnd( player )
PlayCloakSounds( player )
}
void function DisableCloak( entity player, float fadeOut = CLOAK_FADE_OUT )
{
StopSoundOnEntity( player, "cloak_sustain_loop_1P" )
StopSoundOnEntity( player, "cloak_sustain_loop_3P" )
bool wasCloaked = player.IsCloaked( CLOAK_INCLUDE_FADE_IN_TIME )
if ( fadeOut < CLOAK_FADE_OUT && wasCloaked )
{
EmitSoundOnEntityOnlyToPlayer( player, player, "cloak_interruptend_1P" )
EmitSoundOnEntityExceptToPlayer( player, player, "cloak_interruptend_3P" )
StopSoundOnEntity( player, "cloak_warningtoend_1P" )
StopSoundOnEntity( player, "cloak_warningtoend_3P" )
}
player.SetCloakDuration( 0, 0, fadeOut )
}
void function DisableCloakForever( entity player, float fadeOut = CLOAK_FADE_OUT )
{
DisableCloak( player, fadeOut )
player.cloakedForever = false
}
void function HandleCloakEnd( entity player )
{
player.EndSignal( "OnDeath" )
player.EndSignal( "OnEMPPilotHit" )
player.EndSignal( "OnChangedPlayerClass" )
player.Signal( "OnStartCloak" )
player.EndSignal( "OnStartCloak" )
player.EndSignal( "KillHandleCloakEnd" ) //Calling DisableCloak() after EnableCloak() doesn't kill this thread by design (to allow attacking through cloak etc), so this signal is for when you want to kill this thread
float duration = player.GetCloakEndTime() - Time()
OnThreadEnd(
function() : ( player )
{
if ( !IsValid( player ) )
return
if ( PlayerHasBattery( player ) )
Battery_StartFX( GetBatteryOnBack( player ) )
StopSoundOnEntity( player, "cloak_sustain_loop_1P" )
StopSoundOnEntity( player, "cloak_sustain_loop_3P" )
if ( !IsCloaked( player ) )
return
if ( !IsAlive( player ) || !player.IsHuman() )
{
DisableCloak( player )
return
}
float duration = player.GetCloakEndTime() - Time()
if ( duration <= 0 )
{
DisableCloak( player )
}
}
)
float soundBufferTime = 3.45
if ( duration > soundBufferTime )
{
wait ( duration - soundBufferTime )
if ( !IsCloaked( player ) )
return
EmitSoundOnEntityOnlyToPlayer( player, player, "cloak_warningtoend_1P" )
EmitSoundOnEntityExceptToPlayer( player, player, "cloak_warningtoend_3P" )
wait soundBufferTime
}
else
{
wait duration
}
}
void function AbilityCloak_OnDeath( entity player, entity attacker, var damageInfo )
{
if ( !IsCloaked( player ) )
return
DisableCloak( player, 0 )
}
|