Skip to content

Commit b653e3c

Browse files
committed
Updated unused turret VO addon to match p2ce-game
1 parent 428a4ea commit b653e3c

File tree

4 files changed

+202
-5
lines changed

4 files changed

+202
-5
lines changed

unused_turret_vo/addon.kv3

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
22
{
33
mod = "Unused Turret VO (★)"
4-
description = "Reimplements the unused Turret VO found within Portal 1/2's files.\n\nA total of 12 additional voicelines now have the ability to play.\n\nVersion 1.00."
4+
description = "Reimplements the unused Turret VO found within Portal's files.\n\nAlso adds logic to restore lines designed to play if Turrets are blocked by a Hard Light Bridge.\n\nOverall, a total of 16 additional voicelines have the ability to play.\n\nVersion 1.1.0"
55
type = ""
66
id = 0
77
thumbnail = ".assets/thumb.jpg"
@@ -14,10 +14,7 @@
1414
[
1515
"Scripts",
1616
]
17-
ignore =
18-
[
19-
"Hello",
20-
]
17+
ignore = [ ]
2118
metadata =
2219
{
2320
}

unused_turret_vo/scripts/sounds/unused_turret_vo.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,23 @@
179179
"wave" "npc/turret_floor/turret_tipped_5.wav"
180180
"wave" "npc/turret_floor/turret_tipped_6.wav"
181181
}
182+
}
183+
184+
// NEW FOR UNUSED TURRRT VO ADDON
185+
186+
"NPC_FloorTurret.TalkBlockedByBridge"
187+
{
188+
"channel" "CHAN_VOICE"
189+
"volume" "VOL_NORM"
190+
"pitch" "PITCH_NORM"
191+
192+
"soundlevel" "SNDLVL_55dB"
193+
194+
"rndwave"
195+
{
196+
"wave" "npc/turret/turretlightbridgeblock01.wav"
197+
"wave" "npc/turret/turretlightbridgeblock02.wav"
198+
"wave" "npc/turret/turretlightbridgeblock03.wav"
199+
"wave" "npc/turret/turretlightbridgeblock04.wav"
200+
}
182201
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
IncludeScript("unused_turret_vo/helper.nut")
2+
3+
// sv_init.nut runs before entities have spawned, wait until entities are ready
4+
function ScriptInit() {
5+
local canStartTimer = CreateEntityByName("logic_timer", { // check every tick if entities have actually spawned in yet
6+
targetname = "unusedturretvo_canstarttimer"
7+
RefireTime = 0.01
8+
})
9+
10+
canStartTimer.ConnectOutput("OnTimer", "ScriptInit_CheckForStart")
11+
Dev.EntFireByHandleCompressed(canStartTimer, "Enable")
12+
}
13+
function ScriptInit_CheckForStart() { // if player exists, other entities exist
14+
if(GetPlayer() != null) {
15+
EntFire("unusedturretvo_canstarttimer", "Kill")
16+
Init()
17+
}
18+
}
19+
20+
player <- null
21+
turretArr <- []
22+
23+
turretVoBlocked <- true
24+
turretVoBlockedCooldownTimer <- null
25+
26+
const TURRET_SOUNDSCRIPT_BLOCKED = "NPC_FloorTurret.TalkBlockedByBridge" // custom - added inside unused_turret_vo.txt
27+
const TURRET_SOUNDSCRIPT_COOLDOWN_MIN = 7
28+
const TURRET_SOUNDSCRIPT_COOLDOWN_MAX = 10
29+
const TURRET_SOUNDSCRIPT_PLAYCHANCE = 40 // higher number = lower chance of playing (1 in X chance)
30+
31+
const TURRET_MAX_TEST_DISTANCE = 1024
32+
const TURRET_MAX_COUNT = 32 // max number of turrets to store
33+
34+
TURRET_TRACE_BOUNDS_MIN <- Vector(-4,-4,-4)
35+
TURRET_TRACE_BOUNDS_MAX <- TURRET_TRACE_BOUNDS_MIN * -1
36+
TURRET_TRACE_MASK <- MASK_SOLID
37+
TURRET_TRACE_COLLISION_GROUP <- COLLISION_GROUP_PLAYER
38+
39+
// runs when entities are ready
40+
function Init() {
41+
// store turret handles to prevent constant searching, one slight downfall of this is if turrets are spawned after ScriptInit, but this rarely happens in maps
42+
for(local turret = null; turret = Entities.FindByClassname(turret, "npc_portal_turret_floor");) {
43+
turretArr.append(turret)
44+
if(turretArr.len() >= TURRET_MAX_COUNT) break // only store a certain number of turrets to save on performance
45+
}
46+
47+
if(turretArr.len() == 0 || Entities.FindByClassname(null, "prop_wall_projector") == null) return // if there are no turrets or bridges, do nothing
48+
49+
player = GetPlayer()
50+
51+
local loop = CreateEntityByName("logic_timer", { // loop timer for turrets checking for the player
52+
RefireTime = 0.2
53+
})
54+
55+
loop.ConnectOutput("OnTimer", "Turret_CheckForPlayerBehindBridge")
56+
Dev.EntFireByHandleCompressed(loop, "Enable")
57+
58+
turretVoBlockedCooldownTimer = CreateEntityByName("logic_timer", { // timer to allow turret VO again after a delay
59+
RefireTime = RandomInt(TURRET_SOUNDSCRIPT_COOLDOWN_MIN, TURRET_SOUNDSCRIPT_COOLDOWN_MAX)
60+
})
61+
62+
turretVoBlockedCooldownTimer.ConnectOutput("OnTimer", "Turret_AllowBlockedVoiceLines")
63+
turretVoBlockedCooldownTimer.PrecacheSoundScript(TURRET_SOUNDSCRIPT_BLOCKED) // precache needs to be ran off an entity
64+
}
65+
66+
function Turret_CheckForPlayerBehindBridge() {
67+
if(!turretVoBlocked) return // if delay is in progress
68+
69+
local playerPos = player.GetCenter()
70+
local turretMaxTestDistanceSqr = TURRET_MAX_TEST_DISTANCE * TURRET_MAX_TEST_DISTANCE
71+
72+
foreach(turret in turretArr) {
73+
// make sure script doesnt complain
74+
if(!turret.IsValid()) {
75+
Dev.arrayRemoveValue(turretArr, turret)
76+
continue
77+
}
78+
79+
// remove dead turrets from list
80+
local turretActivity = turret.GetSequenceActivityName(turret.GetSequence())
81+
if(turretActivity == "ACT_FLOOR_TURRET_DIE_IDLE" || turretActivity == "ACT_FLOOR_TURRET_DIE") {
82+
Dev.arrayRemoveValue(turretArr, turret)
83+
continue
84+
} else if(turretActivity != "ACT_FLOOR_TURRET_CLOSED_IDLE") continue // don't check turrets that are not closed
85+
86+
local turretPos = turret.EyePosition()
87+
88+
if(Dev.distanceSqr(playerPos, turretPos) <= turretMaxTestDistanceSqr) { // if turret is within range
89+
// check if turret is looking through a bridge
90+
local traceBridge = TraceHull(
91+
turretPos,
92+
turretPos + (turret.GetForwardVector() * TURRET_MAX_TEST_DISTANCE),
93+
TURRET_TRACE_BOUNDS_MIN,
94+
TURRET_TRACE_BOUNDS_MAX,
95+
TURRET_TRACE_MASK,
96+
turret,
97+
TURRET_TRACE_COLLISION_GROUP
98+
)
99+
100+
if(traceBridge.DidHitNonWorldEntity()) {
101+
if(traceBridge.GetEntity().GetClassname() == "projected_wall_entity") {
102+
// check if there is LOS between turret's center and player center (ignoring bridge)
103+
local traceForPlayer = TraceHull(
104+
turretPos,
105+
playerPos,
106+
TURRET_TRACE_BOUNDS_MIN,
107+
TURRET_TRACE_BOUNDS_MAX,
108+
TURRET_TRACE_MASK,
109+
traceBridge.GetEntity(),
110+
TURRET_TRACE_COLLISION_GROUP
111+
)
112+
113+
if(traceForPlayer.DidHitNonWorldEntity()) {
114+
if(traceForPlayer.GetEntity() == player) { // can play blocked voice lines
115+
// check if player is behind bridge from turret's POV
116+
local traceForPlayerBridge = TraceHull(
117+
turretPos,
118+
playerPos,
119+
TURRET_TRACE_BOUNDS_MIN,
120+
TURRET_TRACE_BOUNDS_MAX,
121+
TURRET_TRACE_MASK,
122+
turret,
123+
TURRET_TRACE_COLLISION_GROUP
124+
)
125+
126+
if(traceForPlayerBridge.DidHitNonWorldEntity()) {
127+
if(traceForPlayerBridge.GetEntity().GetClassname() == "projected_wall_entity" && RandomInt(1,TURRET_SOUNDSCRIPT_PLAYCHANCE) == 1) { // 1 in TURRET_SOUNDSCRIPT_PLAYCHANCE chance of playing (when permitted)
128+
turret.EmitSound(TURRET_SOUNDSCRIPT_BLOCKED)
129+
130+
turretVoBlocked = false
131+
132+
turretVoBlockedCooldownTimer.__KeyValueFromInt("RefireTime", RandomInt(TURRET_SOUNDSCRIPT_COOLDOWN_MIN, TURRET_SOUNDSCRIPT_COOLDOWN_MAX))
133+
Dev.EntFireByHandleCompressed(turretVoBlockedCooldownTimer, "Enable") // enable delay
134+
}
135+
}
136+
}
137+
}
138+
}
139+
}
140+
}
141+
}
142+
}
143+
144+
// re-enable ability to play voice lines once delay is up
145+
function Turret_AllowBlockedVoiceLines() {
146+
turretVoBlocked = true
147+
Dev.EntFireByHandleCompressed(turretVoBlockedCooldownTimer, "Disable")
148+
}
149+
150+
// run the script
151+
ScriptInit()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// table containing useful dev functions
2+
if(!("Dev" in getroottable())) {
3+
::Dev <- {
4+
function msg(msg) {
5+
printl("[UNUSED TURRET VO] " + msg)
6+
}
7+
8+
function msgDeveloper(msg) {
9+
if(GetDeveloperLevel() > 0) printl("[UNUSED TURRET VO - DEV] " + msg)
10+
}
11+
12+
function EntFireByHandleCompressed(ent, input, param = "", delay = 0.0, activator = null, caller = null) {
13+
if(ent != null) EntFireByHandle(ent, input, param, delay, activator, caller)
14+
else Dev.msgDeveloper("Tried to fire null entity!")
15+
}
16+
17+
function distanceSqr(vec1, vec2) {
18+
return (vec1 - vec2).LengthSqr()
19+
}
20+
21+
function arrayRemoveValue(arr, valToRemove) {
22+
foreach(idx, val in arr) {
23+
if(val == valToRemove) {
24+
arr.remove(idx)
25+
return
26+
}
27+
}
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)