Created
April 2, 2023 02:51
-
-
Save cheapie/30ac989d0b6dcef0f76f4bb06fa223e2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--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