Script - Bitching Betty
This script is intended to emulate the "bitching Betty" mechanisms found on modern jet fighters and airliners. These are designed to play audio warnings whenever something requiring pilot attention comes up. This script was originally written for Blue Planet: War In Heaven.
How it works
Once gameplay starts, the script does its initialization. It scans the player ship for commonly used subsystem names, and starts to monitor ship status. As soon as one of the predefined triggers is hit, a message will be added to a message queue, which will then be processed with a definable gap between each message. This script relies on voice-acted audio cues that are defined in the mods' sounds.tbl, like so:
; Bitching Betty $Name: 500 bettycomms.ogg, 0, 1.0, 0 $Name: 501 bettyengine.ogg, 0, 1.0, 0 $Name: 502 bettynav.ogg, 0, 1.0, 0 $Name: 503 bettysensors.ogg, 0, 1.0, 0 $Name: 504 bettyweapons.ogg, 0, 1.0, 0 $Name: 505 bettyhull.ogg, 0, 1.0, 0 $Name: 506 bettyeject.ogg, 0, 1.0, 0 $Name: 507 bettyprimaryammo1.ogg, 0, 1.0, 0 $Name: 508 bettyprimaryammo2.ogg, 0, 1.0, 0 $Name: 509 bettyprimaryammo3.ogg, 0, 1.0, 0 $Name: 510 bettysecondaryammo1.ogg, 0, 1.0, 0 $Name: 511 bettysecondaryammo2.ogg, 0, 0.50, 0 $Name: 512 bettysecondaryammo3.ogg, 0, 0.50, 0 $Name: 513 bettysecondaryammo4.ogg, 0, 0.50, 0 $Name: 514 bettysecondaryempty1.ogg, 0, 1.0, 0 $Name: 515 bettysecondaryempty2.ogg, 0, 0.50, 0 $Name: 516 bettysecondaryempty3.ogg, 0, 0.50, 0 $Name: 517 bettysecondaryempty4.ogg, 0, 1.0, 0 $Name: 518 bettyprimaryempty1.ogg, 0, 0.50, 0 $Name: 519 bettyprimaryempty2.ogg, 0, 0.50, 0 $Name: 520 bettyprimaryempty3.ogg, 0, 0.50, 0
The sound indices are hardcoded in the script, and need to match up with the sounds.tbl indices.
Things you should be aware of
- This script can be disabled at runtime by setting the lua variable "BettyOverride" to true. This can be done via the script-eval sexp, or from within another script.
- In BP:WiH, this script is only enabled for UEF fighters. The relevant checks have been commented out here; look at the part of the script running in the $On Frame: hook for details.
Table entry
;The bitching betty script. Monitors subsystem health status, and queues up audio warnings from sounds.tbl to blast at the player.
#Conditional Hooks
$Application: FS2_Open
$State: GS_STATE_GAME_PLAY
$On State Start:
[
function initbetty()
if not bettyinited then
betty = {}
if not betty.plr then
betty.plr = hv.Player
if betty.plr:isValid() then
betty.plrship = mn.getObjectFromSignature(betty.plr:getSignature())
end
end
if betty.plrship:isValid() then
betty.subsystems = {}
betty.subsystems.comms = false
betty.subsystems.engine = false
betty.subsystems.engine01 = false
betty.subsystems.engine02 = false
betty.subsystems.engine03 = false
betty.subsystems.engine04 = false
betty.subsystems.nav = false
betty.subsystems.sensors = false
betty.subsystems.weapons = false
betty.status = {}
betty.status.secondarywarned = {false, false, false, false}
betty.status.secondaryemptywarned = {false, false, false, false}
betty.status.primarywarned = {}
betty.status.primarywarned = {false, false, false}
betty.status.primaryemptywarned = {}
betty.status.primaryemptywarned = {false, false, false}
betty.queue = {}
betty.queueprocessdelay = 2 --Minimum delay for queue processing
betty.comms = 500 --see sounds.tbl
betty.engine = 501
betty.nav = 502
betty.sensors = 503
betty.weapons = 504
betty.hull = 505
betty.eject = 506
betty.primary = {}
betty.primary[1] = 507
betty.primary[2] = 508
betty.primary[3] = 509
betty.secondary = {}
betty.secondary[1] = 510
betty.secondary[2] = 511
betty.secondary[3] = 512
betty.secondary[4] = 513
betty.secondaryempty = {}
betty.secondaryempty[1] = 514
betty.secondaryempty[2] = 515
betty.secondaryempty[3] = 516
betty.secondaryempty[4] = 517
betty.primaryempty = {}
betty.primaryempty[1] = 518
betty.primaryempty[2] = 519
betty.primaryempty[3] = 520
betty.subspace = 521
if not betty.subsystems.comms then
if betty.plrship["communications"]:isValid() then
betty.subsystems.comms = betty.plrship["communications"]
end
end
if not betty.subsystems.engine then
if betty.plrship["engine"]:isValid() then
betty.subsystems.engine = betty.plrship["engine"]
betty.enginenum = 0
end
if betty.plrship["engines"]:isValid() then
betty.subsystems.engine = betty.plrship["engines"]
betty.enginenum = 0
end
end
if not betty.subsystems.engine01 then
if betty.plrship["engine01"]:isValid() then
betty.subsystems.engine01 = betty.plrship["engine01"]
betty.enginenum = 1
end
end
if not betty.subsystems.engine02 then
if betty.plrship["engine02"]:isValid() then
betty.subsystems.engine02 = betty.plrship["engine02"]
betty.enginenum = 2
end
end
if not betty.subsystems.engine03 then
if betty.plrship["engine03"]:isValid() then
betty.subsystems.engine03 = betty.plrship["engine03"]
betty.enginenum = 3
end
end
if not betty.subsystems.engine04 then
if betty.plrship["engine04"]:isValid() then
betty.subsystems.engine04 = betty.plrship["engine04"]
betty.enginenum = 4
end
end
if not betty.subsystems.engine01 then
if betty.plrship["engine01a"]:isValid() then
betty.subsystems.engine01 = betty.plrship["engine01a"]
betty.enginenum = 1
end
end
if not betty.subsystems.engine02 then
if betty.plrship["engine02a"]:isValid() then
betty.subsystems.engine02 = betty.plrship["engine02a"]
betty.enginenum = 2
end
end
if not betty.subsystems.engine03 then
if betty.plrship["engine03a"]:isValid() then
betty.subsystems.engine03 = betty.plrship["engine03a"]
betty.enginenum = 3
end
end
if not betty.subsystems.engine04 then
if betty.plrship["engine04a"]:isValid() then
betty.subsystems.engine04 = betty.plrship["engine04a"]
betty.enginenum = 4
end
end
if not betty.subsystems.nav then
if betty.plrship["navigation"]:isValid() then
betty.subsystems.nav = betty.plrship["navigation"]
end
end
if not betty.subsystems.sensors then
if betty.plrship["sensors"]:isValid() then
betty.subsystems.sensors = betty.plrship["sensors"]
end
end
if not betty.subsystems.weapons then
if betty.plrship["weapons"]:isValid() then
betty.subsystems.weapons = betty.plrship["weapons"]
end
end
betty.queue.timestamp = 0
bettyinited = true
getenginemaxhealth()
else
bettyinited = false
BettyOverride = true
end
end
end
function getenginemaxhealth()
if betty.enginenum == 0 then
betty.enginemaxhealth = betty.subsystems.engine.HitpointsMax
elseif betty.enginenum == 1 then
betty.enginemaxhealth = betty.subsystems.engine01.HitpointsMax
elseif betty.enginenum == 2 then
betty.enginemaxhealth = betty.subsystems.engine01.HitpointsMax + betty.subsystems.engine02.HitpointsMax
elseif betty.enginenum == 3 then
betty.enginemaxhealth = betty.subsystems.engine01.HitpointsMax + betty.subsystems.engine02.HitpointsMax + betty.subsystems.engine03.HitpointsMax
elseif betty.enginenum == 4 then
betty.enginemaxhealth = betty.subsystems.engine01.HitpointsMax + betty.subsystems.engine02.HitpointsMax + betty.subsystems.engine03.HitpointsMax + betty.subsystems.engine04.HitpointsMax
end
end
function getenginehealth()
if betty.enginenum == 0 then
betty.enginehealth = (betty.subsystems.engine.HitpointsLeft) / betty.enginemaxhealth
elseif betty.enginenum == 1 then
betty.enginehealth = (betty.subsystems.engine01.HitpointsLeft) / betty.enginemaxhealth
elseif betty.enginenum == 2 then
betty.enginehealth = (betty.subsystems.engine01.HitpointsLeft + betty.subsystems.engine02.HitpointsLeft) / betty.enginemaxhealth
elseif betty.enginenum == 3 then
betty.enginehealth = (betty.subsystems.engine01.HitpointsLeft + betty.subsystems.engine02.HitpointsLeft + betty.subsystems.engine03.HitpointsLeft) / betty.enginemaxhealth
elseif betty.enginenum == 4 then
betty.enginehealth = (betty.subsystems.engine01.HitpointsLeft + betty.subsystems.engine02.HitpointsLeft + betty.subsystems.engine03.HitpointsLeft + betty.subsystems.engine04.HitpointsLeft) / betty.enginemaxhealth
end
end
function queueWarning(warning)
local i = 1
queued = false
while not queued do
if betty.queue[i] == nil then
betty.queue[i] = warning
queued = true
else
i = i + 1
end
end
end
function processQueue()
local mtime = mn.getMissionTime()
if mtime ~= 0 then
if (mtime - betty.queue.timestamp) > betty.queueprocessdelay then
if betty.queue[1] ~= nil then
ad.playGameSound(betty.queue[1], 0, 100, 0)
local i = 1
local processed = false
while not processed do
if betty.queue[i + 1] ~= nil then
betty.queue[i] = betty.queue[i + 1]
i = i + 1
else
betty.queue[i] = nil
processed = true
end
end
betty.queue.timestamp = mtime
end
end
end
end
function printQueue()
local i = 1
if betty.queue[1] ~= nil then
while betty.queue[i] ~= nil do
ba.print("BETTY DEBUG Item: " .. i .. ": " .. betty.queue[i] .. "\n")
i = i + 1
end
end
end
function processTriggers()
if betty.subsystems.comms then
if betty.subsystems.comms.HitpointsLeft/betty.subsystems.comms.HitpointsMax < 0.01 and not betty.status.commwarned then
queueWarning(betty.comms)
betty.status.commwarned = true
elseif betty.subsystems.comms.HitpointsLeft/betty.subsystems.comms.HitpointsMax > 0.1 then
betty.status.commwarned = false
end
end
getenginehealth()
if betty.enginehealth < 0.01 and not betty.status.enginewarned then
queueWarning(betty.engine)
betty.status.enginewarned = true
elseif betty.enginehealth > 0.1 then
betty.status.enginewarned = false
end
if betty.subsystems.nav then
if betty.subsystems.nav.HitpointsLeft/betty.subsystems.nav.HitpointsMax < 0.01 and not betty.status.navwarned then
queueWarning(betty.nav)
betty.status.navwarned = true
elseif betty.subsystems.nav.HitpointsLeft/betty.subsystems.nav.HitpointsMax > 0.1 then
betty.status.navwarned = false
end
end
if betty.subsystems.sensors then
if betty.subsystems.sensors.HitpointsLeft/betty.subsystems.sensors.HitpointsMax < 0.01 and not betty.status.sensorswarned then
queueWarning(betty.sensors)
betty.status.sensorswarned = true
elseif betty.subsystems.sensors.HitpointsLeft/betty.subsystems.sensors.HitpointsMax > 0.1 then
betty.status.sensorswarned = false
end
end
if betty.subsystems.weapons then
if betty.subsystems.weapons.HitpointsLeft/betty.subsystems.weapons.HitpointsMax < 0.01 and not betty.status.weaponswarned then
queueWarning(betty.weapons)
betty.status.weaponswarned = true
elseif betty.subsystems.weapons.HitpointsLeft/betty.subsystems.weapons.HitpointsMax > 0.1 then
betty.status.weaponswarned = false
end
end
if betty.plrship.HitpointsLeft/betty.plrship.HitpointsMax < 0.41 and not betty.status.hullwarned then
queueWarning(betty.hull)
betty.status.hullwarned = true
elseif betty.plrship.HitpointsLeft/betty.plrship.HitpointsMax > 0.41 then
betty.status.hullwarned = false
end
if betty.plrship.HitpointsLeft/betty.plrship.HitpointsMax < 0.1 and not betty.status.ejectwarned then
queueWarning(betty.eject)
betty.status.ejectwarned = true
elseif betty.plrship.HitpointsLeft/betty.plrship.HitpointsMax > 0.1 then
betty.status.ejectwarned = false
end
for i = 1, 3, 1 do
if betty.plrship.PrimaryBanks[i]:isValid() then
if betty.plrship.PrimaryBanks[i].WeaponClass.Name == "Gattler" or betty.plrship.PrimaryBanks[i].WeaponClass.Name == "Archer" or betty.plrship.PrimaryBanks[i].WeaponClass.Name == "UX Accelerator" or betty.plrship.PrimaryBanks[i].WeaponClass.Name == "Redeemer" or betty.plrship.PrimaryBanks[i].WeaponClass.Name == "Vajra" then
if betty.plrship.PrimaryBanks[i].AmmoLeft/betty.plrship.PrimaryBanks[i].AmmoMax < 0.26 and not betty.status.primarywarned[i] then
queueWarning(betty.primary[i])
betty.status.primarywarned[i] = true
elseif betty.plrship.PrimaryBanks[i].AmmoLeft/betty.plrship.PrimaryBanks[i].AmmoMax > 0.27 then
betty.status.primarywarned[i] = false
end
if betty.plrship.PrimaryBanks[i].AmmoLeft == 0 and not betty.status.primaryemptywarned[i] then
queueWarning(betty.primaryempty[i])
betty.status.primaryemptywarned[i] = true
elseif betty.plrship.PrimaryBanks[i].AmmoLeft > 0 then
betty.status.primaryemptywarned[i] = false
end
end
end
end
for i = 1, 4, 1 do
if betty.plrship.SecondaryBanks[i]:isValid() then
if betty.plrship.SecondaryBanks[i].AmmoLeft/betty.plrship.SecondaryBanks[i].AmmoMax < 0.26 and not betty.status.secondarywarned[i] then
queueWarning(betty.secondary[i])
betty.status.secondarywarned[i] = true
elseif betty.plrship.SecondaryBanks[i].AmmoLeft/betty.plrship.SecondaryBanks[i].AmmoMax > 0.27 then
betty.status.secondarywarned[i] = false
end
if betty.plrship.SecondaryBanks[i].AmmoLeft == 0 and not betty.status.secondaryemptywarned[i] then
queueWarning(betty.secondaryempty[i])
betty.status.secondaryemptywarned[i] = true
elseif betty.plrship.SecondaryBanks[i].AmmoLeft > 0 then
betty.status.secondaryemptywarned[i] = false
end
end
end
end
]
$On Frame:
[
if not BettyOverride then
ttime = mn.getMissionTime()
if ttime ~= 0 then
if not bettyinited then
initbetty()
else
--if betty.plrship.Class.Species.Name == "UEF" then
processTriggers()
printQueue()
processQueue()
--else
-- betty = nil
-- bettyinited = false
-- BettyOverride = true
--end
end
end
end
]
$On State End:
[
if bettyinited then
i = 1
while betty.queue[i] ~= nil do
betty.queue[i] = nil
ba.print("BETTY DEBUG: Clearing queue item " .. i .. "\n")
i = i + 1
end
betty = nil
bettyinited = false
end
]
#End