781 lines
20 KiB
Lua
781 lines
20 KiB
Lua
local defaultCodes = require(script.DefaultCodes)
|
|
|
|
local dataStore = nil
|
|
local DataStoreService = game:GetService("DataStoreService")
|
|
dataStoreKey = script.Parent.dataStoreKey.Value
|
|
if dataStoreKey ~= "" then
|
|
dataStore = DataStoreService:GetDataStore('securityCodes-' .. script.Parent.dataStoreKey.Value or "XP-99")
|
|
else
|
|
-- Make virtual datastore for offline use
|
|
dataStore = {
|
|
_data = {},
|
|
GetAsync = function(self, key)
|
|
return self._data[key]
|
|
end,
|
|
SetAsync = function(self, key, value)
|
|
self._data[key] = value
|
|
end
|
|
}
|
|
end
|
|
|
|
function setup(parentScript)
|
|
-- dont touch
|
|
local version = "v1.2.4"
|
|
|
|
-- codes object, will be swapped for data store later
|
|
codes = dataStore:GetAsync("codes")
|
|
if not codes then
|
|
codes = defaultCodes
|
|
dataStore:SetAsync("codes", codes)
|
|
end
|
|
|
|
-- Make a settings object mapped to the values in parentScript.Parent.Settings
|
|
settings = {}
|
|
for i, e in pairs(parentScript.Parent.Settings:GetChildren()) do
|
|
settings[e.Name] = e.Value
|
|
end
|
|
|
|
power = false
|
|
chime = true
|
|
armState = 0
|
|
delay = 0
|
|
instant = false
|
|
faults = {}
|
|
fault = false
|
|
alarms = {}
|
|
fires = {}
|
|
zones = {}
|
|
keypads = {}
|
|
countdown = nil
|
|
|
|
--[[
|
|
armState
|
|
0 is disarmed
|
|
1 is armed stay
|
|
2 is armed away
|
|
3 is alarm
|
|
4 is fire alarm
|
|
5 is armed instant (stay no entry delay)
|
|
6 is armed maximum (away no entry delay)
|
|
|
|
delay
|
|
0 is inactive
|
|
1 is exit delay
|
|
When active, use slow beep, show ARMED ***AWAY***\nYou may exit now or ARMED ***STAY***\nYou may exit now depending on state. During last 10 seconds of delay, switch to fast beep, at each second check if the system has been armed, if it has drop out of the loop
|
|
2 is entry delay. When active, use slow beep, show "DISARM SYSTEM\nOr alarm will occur", during last 10 seconds of delay, switch to fast beep. At each second check if the system has been disarmed, if it has drop out of the loop
|
|
]]
|
|
ux = require(parentScript.Parent.ScriptModules:WaitForChild("UX"))
|
|
|
|
-- Get keypads
|
|
for i, e in pairs(parentScript.Parent.Keypads:GetChildren()) do
|
|
if e:IsA("Model") then table.insert(keypads, e) end
|
|
end
|
|
|
|
-- Get zone
|
|
for i, e in ipairs(parentScript.Parent.Zones:GetChildren()) do
|
|
-- add a task that constantly checks e.tripped.Value, and set zones[i] to the value of e.tripped.Value
|
|
zones[e.Name] = e
|
|
end
|
|
|
|
-- Funcs
|
|
function rightAlignString(str)
|
|
local strLen = string.len(str)
|
|
local padding = 16 - strLen
|
|
local paddingStr = ""
|
|
for i = 1, padding do paddingStr = paddingStr .. " " end
|
|
return paddingStr .. str
|
|
end
|
|
|
|
function playAud(sound) if not sound.Playing then sound:Play() end end
|
|
|
|
function stopAud(sound) if sound.Playing then sound:Stop() end end
|
|
local curTone = 0
|
|
local lastTone = 0 -- only really used to go back from button pulse to previous tone
|
|
local beeping = false
|
|
|
|
function changeTone(tone) curTone = tone end
|
|
|
|
function beep(keypad)
|
|
|
|
if not power then return end
|
|
if not beeping then
|
|
task.spawn(function()
|
|
beeping = true
|
|
lastTone = curTone
|
|
playAud(keypad.Display.hi)
|
|
wait(0.08)
|
|
stopAud(keypad.Display.hi)
|
|
wait(0.08)
|
|
beeping = false
|
|
end)
|
|
end
|
|
end
|
|
|
|
function ding(count)
|
|
-- Play a ding sound count times, each lasting .3 seconds with a .1 second pause between each
|
|
task.spawn(function()
|
|
for i = 1, count do
|
|
if not power then return end
|
|
for i, keypad in ipairs(keypads) do
|
|
playAud(keypad.Display.ding)
|
|
end
|
|
wait(0.2)
|
|
-- if its not the last ding, stop the sound
|
|
if i ~= count then
|
|
for i, keypad in ipairs(keypads) do
|
|
stopAud(keypad.Display.ding)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
--[[
|
|
0 no tone
|
|
1 constant
|
|
2 pulse (for number input)
|
|
3 slow pulse (entry/exit delay main)
|
|
4 fast pulse (end of exit/entry delay and trouble)
|
|
]]
|
|
function switchKeypadAudio(enabled)
|
|
for i,e in ipairs(script.KeypadAudio:GetChildren()) do
|
|
if e.Name ~= enabled then
|
|
e.Disabled = true
|
|
else
|
|
e.Enabled = true
|
|
end
|
|
end
|
|
end
|
|
function audioLoop()
|
|
while true do
|
|
wait()
|
|
if not power then curTone = 0 end
|
|
if curTone == 0 then -- Stop tone
|
|
switchKeypadAudio("off")
|
|
elseif curTone == 1 then -- Constant tone
|
|
switchKeypadAudio("constant")
|
|
elseif curTone == 2 then -- Slow pulse tone
|
|
switchKeypadAudio("slowpulse")
|
|
elseif curTone == 3 then -- Fast pulse tone
|
|
switchKeypadAudio("fastpulse")
|
|
elseif curTone == 4 then -- HiLo tone alarm
|
|
switchKeypadAudio("hilo")
|
|
elseif curTone == 5 then -- Fire alarm tone
|
|
switchKeypadAudio("fire")
|
|
end
|
|
end
|
|
end
|
|
|
|
function alignText(leftText, rightText, totalWidth)
|
|
local leftLength = #leftText
|
|
local rightLength = #rightText
|
|
local spaceBetween = totalWidth - (leftLength + rightLength)
|
|
|
|
-- If the total length of both texts exceeds the totalWidth, return concatenated textif spaceBetween < 0thenreturn leftText .. rightText
|
|
return leftText .. string.rep(" ", spaceBetween) .. rightText
|
|
end
|
|
|
|
function displayLoop()
|
|
while true do
|
|
wait()
|
|
if not power then
|
|
for i, keypad in ipairs(keypads) do
|
|
ux.setDisplays(keypads, "", "")
|
|
end
|
|
else
|
|
if armState == 0 then -- We are disarmed, check if there are any faults
|
|
if #faults > 0 then
|
|
-- for however many faults there are, display them one at a time based on faultPage (gets updated every 2 seconds, or when * is pressed)
|
|
--ux.setDisplays(keypads, "FAULT " .. table.concat(faults, ", ", faultPage, faultPage + 1))
|
|
ux.setLEDs(keypads, "ready", false)
|
|
fault = true
|
|
ux.setDisplays(keypads, "FAULT " .. faults[1])
|
|
else
|
|
ux.setLEDs(keypads, "ready", true)
|
|
ux.setLEDs(keypads, "armed", false)
|
|
if not chime then
|
|
ux.setDisplays(keypads, "****DISARMED****", " READY TO ARM ")
|
|
else
|
|
ux.setDisplays(keypads, " DISARMED CHIME ", " READY TO ARM ")
|
|
end
|
|
end
|
|
elseif armState == 1 then -- We are armed stay
|
|
ux.setLEDs(keypads, "armed", true)
|
|
ux.setLEDs(keypads, "ready", false)
|
|
if delay == 1 then
|
|
ux.setDisplays(keypads, "ARMED ***STAY***", "You may exit now")
|
|
elseif delay == 2 then
|
|
ux.setDisplays(keypads, "DISARM SYSTEM", "Or alarm occurs.")
|
|
else
|
|
ux.setDisplays(keypads, "ARMED ***STAY***")
|
|
end
|
|
elseif armState == 2 then -- We are armed away
|
|
ux.setLEDs(keypads, "armed", true)
|
|
ux.setLEDs(keypads, "ready", false)
|
|
if delay == 1 then
|
|
if settings.showCountdown then
|
|
ln2 = alignText("May Exit Now", tostring(settings.exitDelay - countdown), 16)
|
|
else
|
|
ln2 = "You may exit now"
|
|
end
|
|
ux.setDisplays(keypads, "ARMED ***AWAY***", ln2)
|
|
elseif delay == 2 then
|
|
ux.setDisplays(keypads, "DISARM SYSTEM", "Or alarm occurs.")
|
|
else
|
|
ux.setDisplays(keypads, "ARMED ***AWAY***", "***ALL SECURE***")
|
|
end
|
|
elseif armState == 3 then -- We are in alarm
|
|
ux.setLEDs(keypads, "ready", false)
|
|
if curTone ~= 4 then changeTone(4) end
|
|
-- show the zone number of the alarmed zone
|
|
ux.setDisplays(keypads, "ALARM " .. tostring(alarms[1] or ""))
|
|
elseif armState == 4 then -- We are in fire alarm
|
|
ux.setLEDs(keypads, "ready", false)
|
|
-- show the zone number of the alarmed zone
|
|
ux.setDisplays(keypads, "FIRE " .. tostring(fires[1] or ""))
|
|
elseif armState == 5 then -- Armed instant
|
|
ux.setLEDs(keypads, "armed", true)
|
|
ux.setLEDs(keypads, "ready", false)
|
|
if delay == 1 then
|
|
ux.setDisplays(keypads, "ARMED *INSTANT*", "You may exit now")
|
|
else
|
|
ux.setDisplays(keypads, "ARMED *INSTANT*")
|
|
end
|
|
elseif armState == 6 then -- Armed max
|
|
ux.setLEDs(keypads, "armed", true)
|
|
ux.setLEDs(keypads, "ready", false)
|
|
if delay == 1 then
|
|
if settings.showCountdown then
|
|
ln2 = alignText("May Exit Now", tostring(settings.exitDelay - countdown), 16)
|
|
else
|
|
ln2 = "You may exit now"
|
|
end
|
|
ux.setDisplays(keypads, "ARMED *MAXIMUM*", ln2)
|
|
else
|
|
ux.setDisplays(keypads, "ARMED *MAXIMUM*", "***ALL SECURE***")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
local input = {}
|
|
local keyClear = nil
|
|
local authenticated = false
|
|
local inputCount = 0
|
|
local inputMode = 0
|
|
local authedUser = nil
|
|
|
|
lockout = false
|
|
authAttempts = 0
|
|
function handleInput(key)
|
|
if not power then return end
|
|
if lockout then
|
|
task.spawn(function()
|
|
curTone = 1
|
|
wait(2)
|
|
curTone = 0
|
|
end)
|
|
return
|
|
end -- eventually do long beep 2 seconds here
|
|
if key == "*" then
|
|
deauth()
|
|
return
|
|
end
|
|
keyClear = math.random(1, 10000)
|
|
task.spawn(function() inputTimeout(keyClear) end)
|
|
if not authenticated then
|
|
-- Should work like a honeywell vista, for every number entered 4 or more in buffer, check if the last 4 numbers are a valid code. For every 4 numbers entered, if its not a valid code add one to the attempts
|
|
table.insert(input, key)
|
|
if #input >= 4 then
|
|
local code = table.concat(input, "", #input - 3, #input)
|
|
if table.find(codes, code) then
|
|
authenticated = true
|
|
inputMode = 1
|
|
authAttempts = 0
|
|
keyClear = nil
|
|
input = {}
|
|
authedUser = code
|
|
else
|
|
authAttempts = authAttempts + 1
|
|
if authAttempts >= 3 then
|
|
task.spawn(lockoutFunc)
|
|
end
|
|
keyClear = nil
|
|
input = {}
|
|
end
|
|
end
|
|
elseif authenticated and inputMode == 1 then
|
|
wait(math.random(.5, 1.5))
|
|
if key == "1" then
|
|
disarm()
|
|
deauth()
|
|
elseif key == "2" then
|
|
if armState ~= 0 then return end
|
|
armAway()
|
|
deauth()
|
|
elseif key == "3" then
|
|
if armState ~= 0 then return end
|
|
armStay()
|
|
deauth()
|
|
elseif key == "4" then -- Arm Max
|
|
if armState ~= 0 then return end
|
|
armMax()
|
|
deauth()
|
|
elseif key == "5" then -- Test (TODO)
|
|
|
|
elseif key == "6" then -- Bypass (TODO)
|
|
|
|
elseif key == "7" then -- Instant
|
|
if armState ~= 0 then return end
|
|
armInstant()
|
|
deauth()
|
|
elseif key == "8" then
|
|
-- If the code used was code 1, and the system is disarmed, Set inputMode to 2 (code change)
|
|
-- See what index the code is at, if its index 1, its the right code, set mode to 2. do NOT hardcode the code here
|
|
print(codes[1] .. " : " .. authedUser)
|
|
if codes[1] == authedUser then
|
|
inputMode = 2
|
|
else
|
|
ding(1)
|
|
deauth()
|
|
end
|
|
elseif key == "9" then
|
|
toggleChime()
|
|
deauth()
|
|
end
|
|
elseif authenticated and inputMode == 2 then
|
|
-- Keep adding inputs together until we have 2+4+4 in the buffer, if both codes match, and arent being used, set the new code to the code at index of the first 2 digits
|
|
-- input data is: 2 digits: user id/index, 4 digits: new code, 4 digits: new code verify
|
|
table.insert(input, key)
|
|
-- check if digit 3 is a hash and 4 a 0, if so delete the user
|
|
if #input >= 4 and input[3] == "#" and input[4] == "0" then
|
|
local uid = table.concat(input, "", 1, 2)
|
|
if tonumber(uid) == 1 then
|
|
ding(4)
|
|
return
|
|
else
|
|
codes[tonumber(uid)] = nil
|
|
dataStore:SetAsync("codes", codes)
|
|
ding(1)
|
|
end
|
|
deauth()
|
|
else
|
|
if #input >= 10 then
|
|
local uid = table.concat(input, "", 1, 2)
|
|
local newCode = table.concat(input, "", 3, 6)
|
|
local newCodeVerify = table.concat(input, "", 7, 10)
|
|
if newCode == newCodeVerify then
|
|
if not table.find(codes, newCode) then
|
|
codes[tonumber(uid)] = newCode
|
|
dataStore:SetAsync("codes", codes)
|
|
ding(1)
|
|
else
|
|
ding(4)
|
|
end
|
|
else
|
|
ding(4)
|
|
end
|
|
deauth()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function deauth()
|
|
keyClear = nil
|
|
authenticated = false
|
|
input = {}
|
|
inputMode = 0
|
|
end
|
|
|
|
function toggleChime()
|
|
if chime then
|
|
ding(2)
|
|
else
|
|
ding(1)
|
|
end
|
|
chime = not chime
|
|
deauth()
|
|
end
|
|
|
|
function disarm()
|
|
deauth()
|
|
task.spawn(function()
|
|
-- Reset any smoke zones
|
|
for i,e in pairs(zones) do
|
|
if e:FindFirstChild("Reset") then
|
|
e.Reset.Value = true
|
|
wait(5)
|
|
e.Reset.Value = false
|
|
end
|
|
end
|
|
end)
|
|
wait(.1)
|
|
armState = 0
|
|
changeTone(0)
|
|
alarms = {}
|
|
fires = {}
|
|
faults = {}
|
|
ding(1)
|
|
end
|
|
|
|
function armStay()
|
|
if #faults > 0 then
|
|
ding(1)
|
|
return
|
|
end
|
|
armState = 1
|
|
delay = 1
|
|
task.spawn(function()
|
|
ding(3)
|
|
for i = 1, settings.exitDelay do
|
|
if armState ~= 1 then
|
|
delay = 0
|
|
countdown = 0
|
|
return
|
|
end
|
|
countdown = i
|
|
wait(1)
|
|
if i >= settings.exitDelay then delay = 0 countdown = 0 end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function armAway()
|
|
if #faults > 0 then
|
|
ding(1)
|
|
return
|
|
end
|
|
armState = 2
|
|
delay = 1
|
|
task.spawn(function()
|
|
changeTone(2)
|
|
for i = 1, settings.exitDelay do
|
|
if armState ~= 2 then
|
|
changeTone(0)
|
|
delay = 0
|
|
countdown = 0
|
|
return
|
|
end
|
|
countdown = i
|
|
wait(1)
|
|
if i >= settings.exitDelay - 10 then changeTone(3) end
|
|
if i >= settings.exitDelay then
|
|
changeTone(0)
|
|
delay = 0
|
|
countdown = 0
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function armMax()
|
|
if #faults > 0 then
|
|
ding(1)
|
|
return
|
|
end
|
|
armState = 6
|
|
delay = 1
|
|
task.spawn(function()
|
|
changeTone(2)
|
|
for i = 1, settings.exitDelay do
|
|
if armState ~= 6 then
|
|
changeTone(0)
|
|
delay = 0
|
|
countdown = 0
|
|
return
|
|
end
|
|
countdown = i
|
|
wait(1)
|
|
if i >= settings.exitDelay - 10 then changeTone(3) end
|
|
if i >= settings.exitDelay then
|
|
changeTone(0)
|
|
delay = 0
|
|
countdown = 0
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function armInstant()
|
|
if #faults > 0 then
|
|
ding(1)
|
|
return
|
|
end
|
|
armState = 5
|
|
delay = 1
|
|
task.spawn(function()
|
|
ding(3)
|
|
for i = 1, settings.exitDelay do
|
|
if armState ~= 5 then
|
|
delay = 0
|
|
countdown = 0
|
|
return
|
|
end
|
|
countdown = i
|
|
wait(1)
|
|
if i >= settings.exitDelay then delay = 0 countdown = 0 end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function inputTimeout(myNum)
|
|
wait(10)
|
|
if keyClear ~= myNum then return end
|
|
authenticated = false
|
|
input = {}
|
|
end
|
|
|
|
function lockoutFunc()
|
|
lockout = true
|
|
changeTone(1)
|
|
wait(2)
|
|
changeTone(0)
|
|
wait(60)
|
|
lockout = false
|
|
end
|
|
-- Button Click Handler (each keypad has Buttons folder with parts that have a clickdetector nested within, add an event handler for each that adds the button to the input buffer)
|
|
function buttonClickHandler(button)
|
|
button.MouseClick:Connect(function()
|
|
if not power then return end
|
|
task.spawn(function() beep(button.Parent.Parent.Parent) end)
|
|
wait(0.05)
|
|
handleInput(button.Parent.Name)
|
|
end)
|
|
end
|
|
|
|
for i, keypad in ipairs(keypads) do
|
|
for j, button in ipairs(keypad.Buttons:GetChildren()) do
|
|
buttonClickHandler(button.ClickDetector)
|
|
end
|
|
end
|
|
|
|
-- Arming Functions
|
|
|
|
function boot()
|
|
task.spawn(audioLoop)
|
|
power = true
|
|
wait()
|
|
ux.displayPower(keypads, true)
|
|
ux.setLEDs(keypads, "*", true)
|
|
ux.setDisplays(keypads, "################", "################")
|
|
changeTone(1)
|
|
wait(1)
|
|
changeTone(0)
|
|
ux.setLEDs(keypads, "*", false)
|
|
ux.setLEDs(keypads, "power", true)
|
|
ux.setDisplays(keypads, "Busy - Standby", rightAlignString(version))
|
|
wait(5)
|
|
task.spawn(displayLoop)
|
|
task.spawn(handleZones)
|
|
task.spawn(sirenLoop)
|
|
task.spawn(stateLoop)
|
|
|
|
end
|
|
|
|
function stateLoop()
|
|
while true do
|
|
if #alarms > 0 then
|
|
script.Parent.Reporting.alarmZone.Value = alarms[1]
|
|
else
|
|
script.Parent.Reporting.alarmZone.Value = -1
|
|
end
|
|
if #fires > 0 then
|
|
script.Parent.Reporting.fireZone.Value = fires[1]
|
|
else
|
|
script.Parent.Reporting.fireZone.Value = -1
|
|
end
|
|
script.Parent.Reporting.armState.Value = armState
|
|
script.Parent.Reporting.delay.Value = delay
|
|
script.Parent.Reporting.curTone.Value = curTone
|
|
wait(0)
|
|
end
|
|
end
|
|
|
|
function handleZones()
|
|
while true do
|
|
wait()
|
|
-- Always: If a zone is tripped, add it to the faults table if its not already there
|
|
-- If the zone is not tripped remove it from the faults table if its there
|
|
-- If the zone is tripped and the system is armed, check if its an instant zone, if it is, set the alarm state to 3, otherwise trigger entry delay
|
|
-- If the system is in alarm, check if the zone is tripped, if it is, add it to the alarms table if its not already there
|
|
for i, zone in pairs(zones) do
|
|
-- if the zone is tripped add it to the faults table if its not already there
|
|
if zone.tripped.Value then
|
|
-- if the zone is already in faults, continue
|
|
if not table.find(faults, zone.Name) then
|
|
if not table.find(faults, zone.Name) then
|
|
table.insert(faults, zone.Name)
|
|
end
|
|
if zone.isFire.Value then
|
|
armState = 4
|
|
changeTone(5)
|
|
table.insert(fires, zone.Name)
|
|
end
|
|
|
|
if zone.alwaysOn.Value then -- This zone is a 24/7 audible zone, go straight to alarm
|
|
armState = 3
|
|
changeTone(4)
|
|
table.insert(alarms, zone.Name)
|
|
end
|
|
|
|
if armState == 0 then
|
|
if zone:FindFirstChild("chime") then
|
|
if chime and zone.chime.Value then
|
|
ding(3)
|
|
end
|
|
end
|
|
elseif armState == 1 and delay == 0 then
|
|
-- if the zone is interior, ignore
|
|
if zone.interior.Value then
|
|
-- ignore
|
|
else
|
|
-- Check if the zone is instant or not
|
|
-- If it is, set the alarm state to 3
|
|
-- If it is not, trigger entry delay
|
|
if zone.instant.Value then
|
|
-- Add to alarms
|
|
table.insert(alarms, zone.Name)
|
|
armState = 3
|
|
changeTone(4)
|
|
else
|
|
delay = 2
|
|
task.spawn(function()
|
|
table.insert(alarms, zone.Name)
|
|
changeTone(2)
|
|
for i = 1, settings.entryDelay do
|
|
if armState ~= 1 then
|
|
changeTone(0)
|
|
delay = 0
|
|
return
|
|
end
|
|
wait(1)
|
|
if i >= settings.entryDelay - 10 then
|
|
changeTone(3)
|
|
end
|
|
if i >= settings.entryDelay then
|
|
-- at this point the system has not been disarmed, go to alarm
|
|
changeTone(4)
|
|
delay = 0
|
|
armState = 3
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
elseif armState == 2 and delay == 0 then
|
|
-- Check if the zone is instant or not
|
|
-- If it is, set the alarm state to 3
|
|
-- If it is not, trigger entry delay
|
|
if zone.instant.Value then
|
|
-- Add to alarms
|
|
table.insert(alarms, zone.Name)
|
|
armState = 3
|
|
changeTone(4)
|
|
else
|
|
table.insert(alarms, zone.Name)
|
|
delay = 2
|
|
task.spawn(function()
|
|
changeTone(2)
|
|
for i = 1, settings.entryDelay do
|
|
if armState ~= 2 then
|
|
changeTone(0)
|
|
delay = 0
|
|
return
|
|
end
|
|
wait(1)
|
|
if i >= settings.entryDelay - 10 then
|
|
changeTone(3)
|
|
end
|
|
if i >= settings.entryDelay then
|
|
-- at this point the system has not been disarmed, go to alarm
|
|
|
|
changeTone(4)
|
|
delay = 0
|
|
armState = 3
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
elseif armState == 3 then
|
|
-- if the zone is already in alarms, continue
|
|
if not table.find(alarms, zone.Name) then
|
|
table.insert(alarms, zone.Name)
|
|
changeTone(4)
|
|
end
|
|
elseif armState == 5 and delay == 0 then -- Armed instant,
|
|
if not zone.interior.Value then
|
|
table.insert(alarms, zone.Name)
|
|
armState = 3
|
|
changeTone(4)
|
|
end
|
|
elseif armState == 6 and delay == 0 then
|
|
table.insert(alarms, zone.Name)
|
|
armState = 3
|
|
changeTone(4)
|
|
end
|
|
end
|
|
else
|
|
if table.find(faults, zone.Name) then
|
|
table.remove(faults, table.find(faults, zone.Name))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function sirenLoop() -- For external sirens
|
|
while true do
|
|
wait()
|
|
if armState == 3 then
|
|
-- Turn on siren
|
|
for i,e in ipairs(parentScript.Parent.Sirens:GetChildren()) do
|
|
if not e.Speaker.siren.playing then
|
|
e.Speaker.siren:Play()
|
|
end
|
|
end
|
|
elseif armState == 4 then -- Fire alarm
|
|
-- Handle dedicated fire sirens
|
|
for i,e in ipairs(parentScript.Parent.FireSirens:GetChildren()) do
|
|
if not e.Speaker.siren.playing then
|
|
e.Speaker.siren:Play()
|
|
end
|
|
end
|
|
-- Make this do temporal 3
|
|
for i = 1, 3 do
|
|
for i,e in ipairs(parentScript.Parent.Sirens:GetChildren()) do
|
|
if not e.Speaker.siren.playing then
|
|
e.Speaker.siren:Play()
|
|
end
|
|
end
|
|
wait(.5)
|
|
for i,e in ipairs(parentScript.Parent.Sirens:GetChildren()) do
|
|
if e.Speaker.siren.playing then
|
|
e.Speaker.siren:Stop()
|
|
end
|
|
end
|
|
wait(.5)
|
|
end
|
|
wait(1)
|
|
else
|
|
-- Turn off siren
|
|
for i,e in ipairs(parentScript.Parent.Sirens:GetChildren()) do
|
|
if e.Speaker.siren.playing then
|
|
e.Speaker.siren:Stop()
|
|
end
|
|
end
|
|
for i,e in ipairs(parentScript.Parent.FireSirens:GetChildren()) do
|
|
if e.Speaker.siren.playing then
|
|
e.Speaker.siren:Stop()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
boot()
|
|
end
|
|
|
|
setup(script) |