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