Skip to content

Instantly share code, notes, and snippets.

@cheapie
Created April 2, 2023 02:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cheapie/30ac989d0b6dcef0f76f4bb06fa223e2 to your computer and use it in GitHub Desktop.
Save cheapie/30ac989d0b6dcef0f76f4bb06fa223e2 to your computer and use it in GitHub Desktop.
--Movestone Elevator 2 - Controller
--A product of Greapie Elevator Co., a Cheapie Systems company
--This is free and unencumbered software released into the public domain.
--See http://unlicense.org/ for more information
local debugmode = false
local cars = 3
local landings = 9
local mainlanding = 7
local landingnames = {
[0] = "P7",
[1] = "P6",
[2] = "P5",
[3] = "P4",
[4] = "P3",
[5] = "P2",
[6] = "P1",
[7] = "L",
[8] = "UL",
}
local distanceabove = {
[0] = 7,
[1] = 7,
[2] = 7,
[3] = 7,
[4] = 7,
[5] = 7,
[6] = 7,
[7] = 7,
}
local keyholders = {
singleplayer = true,
}
local doorholdtime = 5
local passchimesfx = {sound="b2",volume=0.7,pitch=1.5}
local upchimesfx = {sound="elevatorparts_chime2-up",volume=1,pitch=1}
local downchime1sfx = {sound="elevatorparts_chime2-up",volume=1,pitch=1}
local downchime2sfx = {sound="elevatorparts_chime2-up",volume=1,pitch=1}
local motorstartsfx = {sound="elevatorparts_motor_start2",volume=1,pitch=1}
local motorstopsfx = {sound="elevatorparts_motor_stop2",volume=1,pitch=1}
local chimedelay = 0.75
if debugmode then
print("------------------------------------")
print("Elevator DEBUG: Event")
print(event)
local olddlsend = digiline_send
function digiline_send(channel,msg)
print("Elevator DEBUG: Digiline Send, Channel: "..channel)
olddlsend(channel,msg)
end
end
local tslib = {
getColorEscapeSequence = function(color)
return(string.char(0x1b).."(c@"..color..")")
end,
colorize = function(color,message)
return(string.char(0x1b).."(c@"..color..")"..message..string.char(0x1b).."(c@#FFFFFF)")
end,
_mt = {
setChannel = function(self,channel)
self._channel = channel
end,
getChannel = function(self)
return(self._channel)
end,
draw = function(self)
digiline_send(self._channel,self._commands)
end,
clear = function(self)
self._commands = {{command="clear"}}
end,
setLock = function(self,lock)
if lock then
table.insert(self._commands,{command="lock"})
else
table.insert(self._commands,{command="unlock"})
end
end,
addLabel = function(self,x,y,label,vertical)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
if type(label) ~= "string" then
label = tostring(label)
end
local cmd = {
command = "addlabel",
X = x,
Y = y,
label = label,
}
if vertical then cmd.command = "addvertlabel" end
table.insert(self._commands,cmd)
end,
addImage = function(self,x,y,w,h,tex)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if type(tex) ~= "string" then
tex = tostring(tex)
end
local cmd = {
command = "addimage",
X = x,
Y = y,
W = w,
H = h,
texture_name = tex,
}
table.insert(self._commands,cmd)
end,
addButton = function(self,x,y,w,h,name,label,exit)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if type(name) ~= "string" then
name = tostring(name)
end
if type(label) ~= "string" then
label = tostring(label)
end
local cmd = {
command = "addbutton",
X = x,
Y = y,
W = w,
H = h,
name = name,
label = label,
}
if exit then cmd.command = "addbutton_exit" end
table.insert(self._commands,cmd)
end,
addImageButton = function(self,x,y,w,h,name,label,tex,exit)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if type(name) ~= "string" then
name = tostring(name)
end
if type(label) ~= "string" then
label = tostring(label)
end
if type(tex) ~= "string" then
tex = tostring(tex)
end
local cmd = {
command = "addimage_button",
X = x,
Y = y,
W = w,
H = h,
name = name,
label = label,
image = tex,
}
if exit then cmd.command = "addimage_button_exit" end
table.insert(self._commands,cmd)
end,
addField = function(self,x,y,w,h,name,label,default,password)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if type(name) ~= "string" then
name = tostring(name)
end
if type(label) ~= "string" then
label = tostring(label)
end
if type(default) ~= "string" then
default = tostring(default)
end
local cmd = {
command = "addfield",
X = x,
Y = y,
W = w,
H = h,
name = name,
label = label,
default = default,
}
if password then cmd.command = "addpwdfield" end
table.insert(self._commands,cmd)
end,
addTextArea = function(self,x,y,w,h,name,label,default)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if type(name) ~= "string" then
name = tostring(name)
end
if type(label) ~= "string" then
label = tostring(label)
end
if type(default) ~= "string" then
default = tostring(default)
end
local cmd = {
command = "addtextarea",
X = x,
Y = y,
W = w,
H = h,
name = name,
label = label,
default = default,
}
table.insert(self._commands,cmd)
end,
addDropdown = function(self,x,y,w,h,name,choices,selected)
assert((type(x))=="number","Invalid X position")
assert((type(y))=="number","Invalid Y position")
assert((type(w))=="number","Invalid width")
assert((type(h))=="number","Invalid height")
if not selected then selected = 1 end
assert((type(selected))=="number","Invalid selection index")
if type(name) ~= "string" then
name = tostring(name)
end
assert((type(choices) == "table" and #choices >= 1),"Invalid choices list")
local cmd = {
command = "adddropdown",
X = x,
Y = y,
W = w,
H = h,
name = name,
choices = choices,
selected_id = selected,
}
table.insert(self._commands,cmd)
end,
},
new = function(self,channel)
local ret = {}
for k,v in pairs(self._mt) do
ret[k] = v
end
ret._channel = channel
ret._commands = {{command="clear"}}
return ret
end,
}
local function getnextcallabove(car,dir)
if not car then return end
if mem.pos[car] + 1 == landings then return end
local nextcall = -1
for landing=landings-1,mem.pos[car],-1 do
if mem["carcalls"..car][landing] or (mem["upcalls"..car][landing] and dir ~= "down") or (mem["dncalls"..car][landing] and dir ~= "up") then
nextcall = landing
end
end
if nextcall > -1 then return nextcall end
end
local function getnextcallbelow(car,dir)
if not car then return end
if mem.pos[car] == 0 then return end
local nextcall = 99
for landing=0,mem.pos[car],1 do
if mem["carcalls"..car][landing] or (mem["upcalls"..car][landing] and dir ~= "down") or (mem["dncalls"..car][landing] and dir ~= "up") then
nextcall = landing
end
end
if nextcall < 99 then return nextcall end
end
local function getlowestupcall(car)
for landing=0,landings-1,1 do
if mem["carcalls"..car][landing] or mem["upcalls"..car][landing] then return landing,mem["upcalls"..car][landing] end
end
end
local function gethighestdncall(car)
for landing=landings-1,0,-1 do
if mem["carcalls"..car][landing] or mem["dncalls"..car][landing] then return landing,mem["dncalls"..car][landing] end
end
end
local function pi(car,landing,attribute,value)
if mem.pistate[car][landing][attribute] == value then return end
local channel = string.format("pi%d%d",car,landing)
mem.pistate[car][landing][attribute] = value
if attribute == "pos" then
digiline_send(channel,value)
else
digiline_send(channel,attribute.."_"..value)
end
end
local function callack(landing,attribute,value)
if mem.callackstate[landing][attribute] == value then return end
local channel = string.format("call%d",landing)
mem.callackstate[landing][attribute] = value
digiline_send(channel,attribute.."_"..value)
end
local newupcalls = {}
local newdncalls = {}
local oldpos = {}
local oldtgtpos = {}
local olddopen = {}
local olddir = {}
local olddrive = {}
local olddrivestart = {}
local dispupdate = {}
local fs1update = false
for car=0,cars-1,1 do
if mem.pos then oldpos[car] = mem.pos[car] end
if mem.tgtpos then oldtgtpos[car] = mem.tgtpos[car] end
if mem.dopen then olddopen[car] = mem.dopen[car] end
if mem.dir then olddir[car] = mem.dir[car] end
if mem.drive then olddrive[car] = mem.drive[car] end
if mem.drivestart then olddrivestart[car] = mem.drivestart[car] end
end
if event.type == "program" then
mem.upcalls = {}
mem.dncalls = {}
mem.unassignedupcalls = {}
mem.unassigneddncalls = {}
mem.pos = {}
mem.tgtpos = {}
mem.dopen = {}
mem.dir = {}
mem.drive = {}
mem.mode = {}
mem.drivestart = {}
mem.copdisplay = {}
mem.stopswitch = {}
mem.indswitch = {}
mem.insswitch = {}
mem.insenable = {}
mem.fs1switch = "off"
mem.fs2switch = {}
mem.lightswitch = {}
mem.fanswitch = {}
mem.fs1active = false
fs1update = true
mem.pistate = {}
mem.callackstate = {}
for landing=0,landings-1,1 do
mem.callackstate[landing] = {}
end
for car=0,cars-1,1 do
mem.fs2switch[car] = "off"
mem.lightswitch[car] = true
mem.fanswitch[car] = true
mem.copdisplay[car] = "buttons"
mem["carcalls"..car] = {}
mem["upcalls"..car] = {}
mem["dncalls"..car] = {}
mem["pistate"..car] = {}
mem["oldpistate"..car] = {}
mem.pistate[car] = {}
for landing=0,landings-1,1 do
mem.pistate[car][landing] = {}
end
mem.pos[car] = landings-1
mem.tgtpos[car] = 0
mem.mode[car] = "bfdemand"
dispupdate[car] = true
end
elseif event.channel and string.sub(event.channel,1,4) == "call" then
local landing = tonumber(string.sub(event.channel,5,5))
local dir = (event.msg == "up_press" and "up") or (event.msg == "down_press" and "down")
if not (dir and landing) then return end
local caravailable = false
for car=0,cars-1,1 do
caravailable = caravailable or mem.mode[car] == "normal"
end
if dir == "up" and caravailable then
local alreadyserved = false
for car=0,cars-1,1 do
if mem.pos[car] == landing and mem.dopen[car] and mem.mode[car] == "normal" and mem.dir[car] == "up" then
alreadyserved = true
end
end
if not alreadyserved then
if not mem.upcalls[landing] then newupcalls[landing] = true end
mem.upcalls[landing] = true
end
elseif dir == "down" and caravailable then
local alreadyserved = false
for car=0,cars-1,1 do
if mem.pos[car] == landing and mem.dopen[car] and mem.mode[car] == "normal" and mem.dir[car] == "down" then
alreadyserved = true
end
end
if not alreadyserved then
if not mem.dncalls[landing] then newdncalls[landing] = true end
mem.dncalls[landing] = true
end
end
elseif event.iid and string.sub(event.iid,1,6) == "incpos" then
local car = tonumber(string.sub(event.iid,7,7))
if not car or mem.drive[car] ~= "up" then return end
dispupdate[car] = true
if not (mem.mode[car] == "inspection" or mem.mode[car] == "stop") then
mem.pos[car] = mem.pos[car]+1
if mem.pos[car] < mem.tgtpos[car] then
interrupt(distanceabove[mem.pos[car]]/3,string.format("incpos%d",car))
else
interrupt(3,string.format("level%d",car))
digiline_send(string.format("sfx%d%d",car,landings-1),motorstopsfx)
end
if mem.mode[car] == "normal" then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),passchimesfx)
end
end
elseif event.iid and string.sub(event.iid,1,6) == "decpos" then
local car = tonumber(string.sub(event.iid,7,7))
if not car or mem.drive[car] ~= "down" then return end
dispupdate[car] = true
if not (mem.mode[car] == "inspection" or mem.mode[car] == "stop") then
mem.pos[car] = mem.pos[car]-1
if mem.pos[car] > mem.tgtpos[car] then
interrupt(distanceabove[mem.pos[car]-1]/3,string.format("decpos%d",car))
else
interrupt(3,string.format("level%d",car))
digiline_send(string.format("sfx%d%d",car,landings-1),motorstopsfx)
end
if mem.mode[car] == "normal" then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),passchimesfx)
end
end
elseif event.iid and string.sub(event.iid,1,5) == "level" then
local car = tonumber(string.sub(event.iid,6,6))
if not car then return end
dispupdate[car] = true
mem.drivestart[car] = nil
if mem.dir[car] == "up" and not getnextcallabove(car) and getnextcallbelow(car) then mem.dir[car] = "down"
elseif mem.dir[car] == "down" and not getnextcallbelow(car) and getnextcallabove(car) then mem.dir[car] = "up" end
if mem.pos[car] == 0 then
mem.dir[car] = "up"
elseif mem.pos[car] == landings-1 then
mem.dir[car] = "down"
end
if mem.upcalls[mem.pos[car]] and mem.dir[car] == "up" then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),upchimesfx)
elseif mem.dncalls[mem.pos[car]] and mem.dir[car] == "down" then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),downchime1sfx)
interrupt(chimedelay,string.format("chime%d%d",car,mem.pos[car]))
end
mem["carcalls"..car][mem.pos[car]] = nil
if mem.dir[car] == "up" then
mem["upcalls"..car][mem.pos[car]] = nil
mem.unassignedupcalls[mem.pos[car]] = nil
mem.upcalls[mem.pos[car]] = nil
elseif mem.dir[car] == "down" then
mem["dncalls"..car][mem.pos[car]] = nil
mem.unassigneddncalls[mem.pos[car]] = nil
mem.dncalls[mem.pos[car]] = nil
end
mem.drive[car] = nil
if mem.mode[car] == "bfdemand" then mem.mode[car] = "normal" end
if mem.mode[car] == "normal" or mem.mode[car] == "independent" or mem.mode[car] == "fire1" then mem.dopen[car] = true end
if mem.mode[car] == "normal" then interrupt(doorholdtime,string.format("close%d",car)) end
elseif event.iid and string.sub(event.iid,1,5) == "close" then
local car = tonumber(string.sub(event.iid,6,6))
if not car then return end
dispupdate[car] = true
if not getnextcallabove(car) and not getnextcallbelow(car) then mem.dir[car] = nil end
mem.dopen[car] = false
elseif event.iid and string.sub(event.iid,1,7) == "insstop" then
local car = tonumber(string.sub(event.iid,8,8))
if not car then return end
if mem.mode[car] == "inspection" then
mem.drive[car] = false
mem.drivestart[car] = false
end
elseif event.iid and string.sub(event.iid,1,5) == "chime" then
digiline_send(string.format("sfx%s",string.sub(event.iid,6,7)),downchime2sfx)
elseif event.iid and string.sub(event.iid,1,10) == "drivestart" then
local car = tonumber(string.sub(event.iid,11,11))
if not car then return end
dispupdate[car] = true
if not (mem.mode[car] == "inspection" or mem.mode[car] == "stop") then
for landing=0,landings-1,1 do
if mem.tgtpos[car] == landing then
digiline_send(string.format("sel%d%d",car,landing),"retract_sticky")
else
digiline_send(string.format("sel%d%d",car,landing),"extend")
end
end
if mem.drive[car] == "up" then
mem.drivestart[car] = true
interrupt(distanceabove[mem.pos[car]]/3,string.format("incpos%d",car))
elseif mem.drive[car] == "down" then
mem.drivestart[car] = true
interrupt(distanceabove[mem.pos[car]-1]/3,string.format("decpos%d",car))
end
end
elseif event.channel and string.sub(event.channel,1,3) == "cop" then
local car = tonumber(string.sub(event.channel,4,4))
if not car then return end
dispupdate[car] = true
if mem.copdisplay[car] == "buttons" then
for landing=0,landings-1,1 do
if event.msg["carcall"..landing] and (not (mem.pos[car] == landing and mem.dopen[car])) and (mem.mode[car] == "normal" or mem.mode[car] == "fire2" or mem.mode[car] == "independent") then
mem["carcalls"..car][landing] = true
end
end
if event.msg.open and not mem.drive[car] and (mem.mode[car] == "normal" or mem.mode[car] == "fire2" or mem.mode[car] == "independent") then
mem.dopen[car] = true
if mem.mode[car] == "normal" then interrupt(doorholdtime,string.format("close%d",car)) end
elseif event.msg.close and (mem.mode[car] == "normal" or mem.mode[car] == "fire2" or mem.mode[car] == "independent") then
interrupt(0,string.format("close%d",car))
elseif event.msg.alarm then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),"bobblocks_health")
elseif event.msg.phone then
digiline_send(string.format("sfx%d%d",car,mem.pos[car]),"infrastructure_emergency_phone")
elseif event.msg.openpanel then
if keyholders[event.msg.clicker] then
mem.copdisplay[car] = "switchpanel"
else
mem.copdisplay[car] = "switchpanellocked"
end
elseif event.msg.callcancel and (mem.mode[car] == "independent" or mem.mode[car] == "fire2") then
mem["carcalls"..car] = {}
end
elseif mem.copdisplay[car] == "switchpanellocked" then
if event.msg.back or event.msg.quit then
mem.copdisplay[car] = "buttons"
end
elseif mem.copdisplay[car] == "switchpanel" then
if event.msg.back then
mem.copdisplay[car] = "buttons"
elseif event.msg.lighton then
mem.lightswitch[car] = true
digiline_send("light"..car,14)
elseif event.msg.lightoff then
mem.lightswitch[car] = false
digiline_send("light"..car,0)
elseif event.msg.fanon then
mem.fanswitch[car] = true
elseif event.msg.fanoff then
mem.fanswitch[car] = false
elseif event.msg.indon then
mem.indswitch[car] = true
elseif event.msg.indoff then
mem.indswitch[car] = false
elseif event.msg.inson then
mem.insswitch[car] = true
elseif event.msg.insoff then
mem.insswitch[car] = false
mem.insenable[car] = false
elseif event.msg.insenable and mem.mode[car] == "inspection" then
mem.insenable[car] = not mem.insenable[car]
if not mem.insenable[car] then
mem.drive[car] = nil
mem.drivestart[car] = false
end
elseif event.msg.fson then
mem.fs2switch[car] = "on"
elseif event.msg.fshold then
mem.fs2switch[car] = "hold"
elseif event.msg.fsoff then
mem.fs2switch[car] = "off"
elseif event.msg.stop then
mem.stopswitch[car] = true
elseif event.msg.run then
mem.stopswitch[car] = false
elseif event.msg.insup and mem.mode[car] == "inspection" and mem.insenable[car] then
mem.drive[car] = "up"
mem.drivestart[car] = true
interrupt(0.15,string.format("insstop%d",car))
elseif event.msg.insdown and mem.mode[car] == "inspection" and mem.insenable[car] then
mem.drive[car] = "down"
mem.drivestart[car] = true
interrupt(0.15,string.format("insstop%d",car))
end
end
elseif event.channel == "groupdisplay" then
for landing=0,landings-1,1 do
if event.msg["upcall"..landing] then
local alreadyserved = false
for car=0,cars-1,1 do
if mem.pos[car] == landing and mem.dopen[car] and mem.mode[car] == "normal" and mem.dir[car] == "up" then
alreadyserved = true
end
end
if not alreadyserved then
if not mem.upcalls[landing] then newupcalls[landing] = true end
mem.upcalls[landing] = true
end
end
if event.msg["dncall"..landing] then
local alreadyserved = false
for car=0,cars-1,1 do
if mem.pos[car] == landing and mem.dopen[car] and mem.mode[car] == "normal" and mem.dir[car] == "down" then
alreadyserved = true
end
end
if not alreadyserved then
if not mem.dncalls[landing] then newdncalls[landing] = true end
mem.dncalls[landing] = true
end
end
for car=0,cars-1,1 do
if event.msg["carcall"..car..landing] and not (mem.dopen[car] and mem.pos[car] == landing) then
mem["carcalls"..car][landing] = true
end
end
end
elseif event.channel == "firesvcswitch" then
fs1update = true
if event.msg.on then mem.fs1switch = "on"
elseif event.msg.off then mem.fs1switch = "off"
elseif event.msg.reset then mem.fs1switch = "reset" end
end
if mem.fs1switch == "on" or pin.a or pin.b or pin.c or pin.d then
if not mem.fs1active then
fs1update = true
for car=0,cars-1,1 do
mem.drive[car] = nil
end
end
mem.fs1active = true
elseif mem.fs1switch == "reset" then
mem.fs1active = false
end
if mem.fs1active then
newupcalls = {}
newdncalls = {}
mem.unassignedupcalls = {}
mem.unassigneddncalls = {}
for car=0,cars-1,1 do
mem["upcalls"..car] = {}
mem["dncalls"..car] = {}
mem.dir[car] = nil
dispupdate[car] = true
end
end
for car=0,cars-1,1 do
local oldmode = mem.mode[car]
if mem.stopswitch[car] then
mem.mode[car] = "stop"
mem.drive[car] = nil
mem.tgtpos[car] = mem.pos[car]
mem["carcalls"..car] = {}
elseif mem.insswitch[car] then
if mem.mode[car] ~= "inspection" then
mem.drive[car] = nil
mem.drivestart[car] = false
for landing=0,landings-1,1 do
digiline_send(string.format("sel%d%d",car,landing),"extend")
end
end
mem.mode[car] = "inspection"
mem.dopen[car] = false
mem["carcalls"..car] = {}
elseif mem.fs1active and mem.mode[car] ~= "bfdemand" then
if mem.fs2switch[car] == "on" then
mem.mode[car] = "fire2"
elseif mem.fs2switch[car] == "hold" then
mem.mode[car] = "fire2hold"
else
mem.dopen[car] = false
mem["carcalls"..car] = {}
mem.mode[car] = "fire1"
if mem.pos[car] == mainlanding and not mem.drive[car] then mem.dopen[car] = true end
mem.tgtpos[car] = mainlanding
end
elseif mem.indswitch[car] and mem.mode[car] ~= "bfdemand" then
if mem.mode[car] ~= "independent" then mem.dopen[car] = true end
mem.mode[car] = "independent"
elseif mem.mode[car] == "inspection" or mem.mode[car] == "stop" then
mem.mode[car] = "bfdemand"
mem.pos[car] = landings-1
mem.tgtpos[car] = 0
mem.dopen[car] = false
elseif mem.mode[car] ~= "bfdemand" then
if mem.mode[car] == "fire1" then
mem.dopen[car] = false
end
if mem.mode[car] == "independent" then interrupt(doorholdtime,string.format("close%d",car)) end
mem.mode[car] = "normal"
end
if mem.mode[car] ~= oldmode then dispupdate[car] = true end
end
for landing=0,landings-1,1 do
for car=0,cars-1,1 do
if mem.mode[car] ~= "normal" then
if mem["upcalls"..car][landing] then
mem.unassignedupcalls[landing] = true
mem["upcalls"..car][landing] = false
end
if mem["dncalls"..car][landing] then
mem.unassigneddncalls[landing] = true
mem["dncalls"..car][landing] = false
end
end
end
local upcall = mem.unassignedupcalls[landing] or newupcalls[landing]
local dncall = mem.unassigneddncalls[landing] or newdncalls[landing]
if upcall then
local assigned = false
local nearestcar
local nearestdistance
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and mem.dir[car] == "up" and mem.dopen[car] and mem.pos[car] == landing then
assigned = true
end
end
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and not mem.dir[car] and not mem.dopen[car] and not assigned then
local distance = math.abs(mem.pos[car]-landing)
if not nearestcar or distance < nearestdistance then
nearestcar = car
nearestdistance = distance
end
end
end
if nearestcar then
mem["upcalls"..nearestcar][landing] = true
assigned = true
mem.unassignedupcalls[landing] = false
end
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and mem.dir[car] == "up" and mem.pos[car] < landing and mem.dopen[car] and not assigned then
local distance = math.abs(mem.pos[car]-landing)
if not nearestcar or distance < nearestdistance then
nearestcar = car
nearestdistance = distance
end
end
end
if nearestcar then
mem["upcalls"..nearestcar][landing] = true
assigned = true
mem.unassignedupcalls[landing] = false
end
if not assigned then mem.unassignedupcalls[landing] = true end
end
if dncall then
local assigned = false
local nearestcar
local nearestdistance
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and mem.dir[car] == "down" and mem.dopen[car] and mem.pos[car] == landing then
assigned = true
end
end
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and not mem.dir[car] and not mem.dopen[car] and not assigned then
local distance = math.abs(mem.pos[car]-landing)
if not nearestcar or distance < nearestdistance then
nearestcar = car
nearestdistance = distance
end
end
end
if nearestcar then
mem["dncalls"..nearestcar][landing] = true
assigned = true
mem.unassigneddncalls[landing] = false
end
for car=0,cars-1,1 do
if mem.mode[car] == "normal" and mem.dir[car] == "down" and mem.pos[car] > landing and mem.dopen[car] and not assigned then
local distance = math.abs(mem.pos[car]-landing)
if not nearestcar or distance < nearestdistance then
nearestcar = car
nearestdistance = distance
end
end
end
if nearestcar and not mem["upcalls"..nearestcar][landing] then
mem["dncalls"..nearestcar][landing] = true
assigned = true
mem.unassigneddncalls[landing] = false
end
if not assigned then mem.unassigneddncalls[landing] = true end
end
callack(landing,"up_light",mem.upcalls[landing] and "on" or "off")
callack(landing,"down_light",mem.dncalls[landing] and "on" or "off")
for car=0,cars-1,1 do
if mem.dopen[car] ~= olddopen[car] then
if mem.pos[car] == landing and mem.dopen[car] then
digiline_send(string.format("door%d%d",car,landing),"retract_sticky")
else
digiline_send(string.format("door%d%d",car,landing),"extend")
end
end
if dispupdate[car] then
if mem.pos[car] == landing then
if mem.dopen[car] and mem.mode[car] == "normal" then
if mem.dir[car] == "up" then
pi(car,landing,"up_light","on")
pi(car,landing,"down_light","off")
elseif mem.dir[car] == "down" then
pi(car,landing,"up_light","off")
pi(car,landing,"down_light","on")
end
else
pi(car,landing,"up_light","off")
pi(car,landing,"down_light","off")
end
else
pi(car,landing,"up_light","off")
pi(car,landing,"down_light","off")
end
if mem.mode[car] == "stop" or mem.mode[car] == "inspection" or mem.mode[car] == "bfdemand" then
pi(car,landing,"pos","---")
else
pi(car,landing,"pos",landingnames[mem.pos[car]])
end
if mem.drive[car] == "up" then
pi(car,landing,"arrow","up")
elseif mem.drive[car] == "down" then
pi(car,landing,"arrow","down")
else
pi(car,landing,"arrow","off")
end
if mem.fs1active then
pi(car,landing,"flash","fs")
elseif mem.mode[car] == "independent" then
pi(car,landing,"flash","is")
else
pi(car,landing,"flash","off")
end
end
end
end
for car=0,cars-1,1 do
if not mem.dopen[car] and not mem.drive[car] and mem.pos[car] == mem.tgtpos[car] then
local lowestup,upishall = getlowestupcall(car)
local highestdn,dnishall = gethighestdncall(car)
if lowestup then
mem.tgtpos[car] = lowestup
if upishall then
mem.dir[car] = "up"
else
mem.dir[car] = lowestup > mem.pos[car] and "up" or "down"
end
elseif highestdn then
mem.tgtpos[car] = highestdn
if dnishall then
mem.dir[car] = "up"
else
mem.dir[car] = highestdn > mem.pos[car] and "up" or "down"
end
end
elseif mem.dopen[car] then
if debugmode then print("Elevator DEBUG: Checking for calls on car "..car) end
local nextup = getnextcallabove(car,"up")
local nextdn = getnextcallbelow(car,"down")
if debugmode then
print("Elevator DEBUG: Next up "..(nextup or "none")..", down "..(nextdn or "none"))
end
if mem.dir[car] == "up" then
if nextup then
mem.tgtpos[car] = nextup
elseif nextdn then
mem.dir[car] = "down"
mem.tgtpos[car] = nextdn
pi(car,mem.pos[car],"up_light","off")
pi(car,mem.pos[car],"down_light","on")
end
elseif mem.dir[car] == "down" then
if nextdn then
mem.tgtpos[car] = nextdn
elseif nextup then
mem.dir[car] = "up"
mem.tgtpos[car] = nextup
pi(car,mem.pos[car],"up_light","on")
pi(car,mem.pos[car],"down_light","off")
end
end
if debugmode then print("Elevator DEBUG: New target pos "..(mem.tgtpos[car] or "none")) end
end
if mem.tgtpos[car] ~= mem.pos[car] and not mem.drive[car] and not mem.dopen[car] then
if mem.tgtpos[car] > mem.pos[car] then
mem.drive[car] = "up"
dispupdate[car] = true
interrupt(1,string.format("drivestart%d",car))
elseif mem.tgtpos[car] < mem.pos[car] then
mem.drive[car] = "down"
dispupdate[car] = true
interrupt(1,string.format("drivestart%d",car))
end
elseif mem.tgtpos[car] == mem.pos[car] and (mem["carcalls"..car][mem.pos[car]] or mem["upcalls"..car][mem.pos[car]] or mem["dncalls"..car][mem.pos[car]]) and not mem.drive[car] then
interrupt(0,string.format("level%d",car))
end
if mem.drive[car] ~= olddrive[car] or mem.drivestart[car] ~= olddrivestart[car] then
digiline_send(string.format("up%d",car),(mem.drive[car] == "up" and mem.drivestart[car]) and "extend" or "retract_sticky")
digiline_send(string.format("down%d",car),(mem.drive[car] == "down" and mem.drivestart[car]) and "extend" or "retract_sticky")
if (mem.drive[car] and mem.drivestart[car]) ~= (olddrive[car] and olddrivestart[car]) then
if mem.drive[car] and mem.drivestart[car] then
digiline_send(string.format("sfx%d%d",car,landings-1),motorstartsfx)
end
end
end
if dispupdate[car] then
local cop = tslib:new(string.format("cop%d",car))
if mem.copdisplay[car] == "buttons" then
cop:addLabel(1,0,"GREAPIE ELEVATOR CO.")
cop:addLabel(1.1,0.33,"2000 LBS CAPACITY")
for landing=landings-1,0,-1 do
local dy = 5/landings
local y = 1.5 + ((landings-landing-1)*dy)
if mem["carcalls"..car][landing] then
cop:addImageButton(1.4,y,0.6,0.6,string.format("carcall%d",landing),(landing == mainlanding and "*" or "")..landingnames[landing],"digistuff_junctionbox.png^[colorize:#FFFF55",false)
else
cop:addImageButton(1.4,y,0.6,0.6,string.format("carcall%d",landing),(landing == mainlanding and "*" or "")..landingnames[landing],"digistuff_junctionbox.png^[colorize:#444444",false)
end
end
cop:addImageButton(1,6.5,0.6,0.6,"open","<|>","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addImageButton(1.8,6.5,0.6,0.6,"close",">|<","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addImageButton(1,7.25,0.6,0.6,"alarm","Alarm","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addImageButton(1.8,7.25,0.6,0.6,"phone","Phone","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addImageButton(2.6,7.25,0.6,0.6,"callcancel","Call\nCancel","digistuff_junctionbox.png^[colorize:#444444",false)
local arrow = " "
if mem.drive[car] == "up" then arrow = "^ "
elseif mem.drive[car] == "down" then arrow = "v " end
cop:addImageButton(1.35,0.75,0.75,0.6,"pi",arrow..landingnames[mem.pos[car]],"digistuff_junctionbox.png^[colorize:#000000",false)
cop:addButton(8,7.25,2,1,"openpanel","Open Switch Panel")
elseif mem.copdisplay[car] == "switchpanel" then
local stoptex = mem.stopswitch[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local runtex = (not mem.stopswitch[car]) and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local indontex = mem.indswitch[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local indofftex = (not mem.indswitch[car]) and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local insontex = mem.insswitch[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local insofftex = (not mem.insswitch[car]) and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local insenabletex = mem.insenable[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local fsofftex = (mem.fs2switch[car] == "off") and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local fsholdtex = (mem.fs2switch[car] == "hold") and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local fsontex = (mem.fs2switch[car] == "on") and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local fanontex = mem.fanswitch[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local fanofftex = (not mem.fanswitch[car]) and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local lightontex = mem.lightswitch[car] and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local lightofftex = (not mem.lightswitch[car]) and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
cop:addImageButton(0,1,1,0.6,"stop","STOP",stoptex,false)
cop:addImageButton(0,2.2,1,0.6,"run","RUN",runtex,false)
cop:addLabel(0,2.6,"EMERG STOP")
cop:addImageButton(2,1,1,0.6,"indon","ON",indontex,false)
cop:addImageButton(2,2.2,1,0.6,"indoff","OFF",indofftex,false)
cop:addLabel(2,2.6,"IND SVC")
cop:addImageButton(4,1,1,0.6,"fson","ON",fsontex,false)
cop:addImageButton(4,1.6,1,0.6,"fshold","HOLD",fsholdtex,false)
cop:addImageButton(4,2.2,1,0.6,"fsoff","OFF",fsofftex,false)
cop:addLabel(4,2.6,"FIRE SVC")
cop:addImageButton(6,1,1,0.6,"fanon","ON",fanontex,false)
cop:addImageButton(6,2.2,1,0.6,"fanoff","OFF",fanofftex,false)
cop:addLabel(6,2.6,"CAR FAN")
cop:addImageButton(8,1,1,0.6,"lighton","ON",lightontex,false)
cop:addImageButton(8,2.2,1,0.6,"lightoff","OFF",lightofftex,false)
cop:addLabel(8,2.6,"CAR LIGHT")
cop:addImageButton(0,4,1,0.6,"inson","INSPECT",insontex,false)
cop:addImageButton(0,5.2,1,0.6,"insoff","NORMAL",insofftex,false)
cop:addImageButton(1,4,1,0.6,"insup","UP","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addImageButton(1,4.6,1,0.6,"insenable","ENABLE",insenabletex,false)
cop:addImageButton(1,5.2,1,0.6,"insdown","DOWN","digistuff_junctionbox.png^[colorize:#444444",false)
cop:addLabel(0.5,5.6,"INSPECTION")
cop:addButton(8,7.25,2,1,"back","Close Panel")
elseif mem.copdisplay[car] == "switchpanellocked" then
cop:addLabel(3.75,3,"You don't have the key to")
cop:addLabel(3.85,3.25,"open this panel!")
cop:addButton(3.5,3.5,2,1,"back","Back")
end
cop:draw()
end
end
local modestrings = {
normal = "AUT",
stop = "OTS",
bfdemand = "BFD",
independent = "IND",
inspection = "INS",
fire1 = "FS1",
fire2 = "FS2",
fire2hold = "FS2",
}
local gd = tslib:new("groupdisplay")
gd:addLabel(4,0,"GROUP DISPLAY")
gd:addImage(1,1,0.1,7,"digistuff_junctionbox.png^[colorize:#AAAAAA")
gd:addImage(8.75,1,0.1,7,"digistuff_junctionbox.png^[colorize:#AAAAAA")
gd:addLabel(0.15,7,"UP CALLS")
gd:addLabel(9,7,"DN CALLS")
gd:addLabel(0.15,0.6,"UP CALLS")
gd:addLabel(9,0.6,"DN CALLS")
for car=0,cars-1,1 do
gd:addLabel(1.2+(car/1.3),0.6,"CAR "..(car+1))
gd:addLabel(1.2+(car/1.3),7,"CAR "..(car+1))
gd:addLabel(1.27+(car/1.3),0.8,tslib.colorize("#FF5555",modestrings[mem.mode[car]]))
gd:addLabel(1.27+(car/1.3),6.8,tslib.colorize("#FF5555",modestrings[mem.mode[car]]))
end
for landing=0,landings-1,1 do
gd:addLabel(0.8,6.3-(landing/1.7),landingnames[landing])
gd:addLabel(8.95,6.3-(landing/1.7),landingnames[landing])
for car=0,cars-1,1 do
local buttontext = ""
if mem["carcalls"..car][landing] then buttontext = "*" end
if mem.pos[car] == landing then
buttontext = mem.dopen[car] and "<>" or "||"
if mem.dir[car] == "up" then
buttontext = tslib.colorize("#55FF00",buttontext)
elseif mem.dir[car] == "down" then
buttontext = tslib.colorize("#FF5555",buttontext)
end
end
if mem["upcalls"..car][landing] then
buttontext = tslib.colorize("#55FF00","^")..buttontext
end
if mem["dncalls"..car][landing] then
buttontext = buttontext..tslib.colorize("#FF5555","v")
end
gd:addImageButton(1.2+(car/1.3),6.3-(landing/1.7),0.6,0.6,string.format("carcall%d%d",car,landing),buttontext,"digistuff_ts_bg.png")
end
end
for landing=0,landings-2,1 do
gd:addImageButton(0.25,6.3-(landing/1.7),0.6,0.6,string.format("upcall%d",landing),mem.upcalls[landing] and tslib.colorize("#55FF55","^") or "","digistuff_ts_bg.png")
end
for landing=1,landings-1,1 do
gd:addImageButton(9.2,6.3-(landing/1.7),0.6,0.6,string.format("dncall%d",landing),mem.dncalls[landing] and tslib.colorize("#FF5555","v") or "","digistuff_ts_bg.png")
end
gd:draw()
if fs1update then
local fsswitch = tslib:new("firesvcswitch")
fsswitch:setLock(true)
local ontex = mem.fs1switch == "on" and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local offtex = mem.fs1switch == "off" and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local resettex = mem.fs1switch == "reset" and "digistuff_junctionbox.png^[colorize:#AAAAAA" or "digistuff_junctionbox.png^[colorize:#444444"
local ledtex = mem.fs1active and "digistuff_junctionbox.png^[colorize:#FF5555" or "digistuff_junctionbox.png^[colorize:#000000"
fsswitch:addImage(5,3,0.6,0.6,ledtex)
fsswitch:addImageButton(4,3,1,0.6,"on","ON",ontex,false)
fsswitch:addImageButton(4,3.6,1,0.6,"off","OFF",offtex,false)
fsswitch:addImageButton(4,4.2,1,0.6,"reset","RESET",resettex,false)
fsswitch:addLabel(4,4.6,"FIRE SVC")
fsswitch:draw()
end
local needforceload = false
for i=0,cars-1,1 do
needforceload = needforceload or mem.drive[i]
end
if needforceload ~= mem.oldforceload or event.type == "program" then digiline_send("forceload",needforceload and "extend" or "retract_sticky") end
mem.oldforceload = needforceload
if debugmode then print("------------------------------------") end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment