19d69394b6
This allows new calls entered while the car is moving to be serviced before the original destination, provided they are in the correct direction, will be reached before the original destination, and the car can stop soon enough.
886 lines
31 KiB
Lua
886 lines
31 KiB
Lua
celevator.drives.entity = {
|
|
name = "Drive",
|
|
description = "Normal entity-based drive",
|
|
nname = "celevator:drive",
|
|
buzzsoundhandles = {},
|
|
movementsoundhandles = {},
|
|
movementsoundstate = {},
|
|
entityinfo = {},
|
|
sheaverefs = {},
|
|
}
|
|
|
|
local function update_ui(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
local apos = tonumber(meta:get_string("apos")) or 0
|
|
local status = "Idle"
|
|
local vel = tonumber(meta:get_string("vel")) or 0
|
|
local state = meta:get_string("state")
|
|
if state == "running" and vel > 0 then
|
|
status = string.format("Running: Up, %0.02f m/s",vel)
|
|
elseif state == "running" and vel < 0 then
|
|
status = string.format("Running: Down, %0.02f m/s",math.abs(vel))
|
|
elseif state == "fakerunning" and vel > 0 then
|
|
status = string.format("Running (simulated): Up, %0.02f m/s",vel)
|
|
elseif state == "fakerunning" and vel < 0 then
|
|
status = string.format("Running (simulated): Down, %0.02f m/s",math.abs(vel))
|
|
end
|
|
meta:set_string("infotext",string.format("Drive - %s - Position: %0.02f m",status,apos))
|
|
end
|
|
|
|
local function playbuzz(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
if celevator.drives.entity.buzzsoundhandles[hash] == "cancel" then return end
|
|
celevator.drives.entity.buzzsoundhandles[hash] = minetest.sound_play("celevator_drive_run",{
|
|
pos = pos,
|
|
loop = true,
|
|
gain = 0.2,
|
|
})
|
|
end
|
|
|
|
local function startbuzz(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
if celevator.drives.entity.buzzsoundhandles[hash] == "cancel" then
|
|
celevator.drives.entity.buzzsoundhandles[hash] = nil
|
|
return
|
|
end
|
|
if celevator.drives.entity.buzzsoundhandles[hash] then return end
|
|
celevator.drives.entity.buzzsoundhandles[hash] = "pending"
|
|
minetest.after(0.5,playbuzz,pos)
|
|
end
|
|
|
|
local function stopbuzz(pos)
|
|
local hash = minetest.hash_node_position(pos)
|
|
if not celevator.drives.entity.buzzsoundhandles[hash] then return end
|
|
if celevator.drives.entity.buzzsoundhandles[hash] == "pending" then
|
|
celevator.drives.entity.buzzsoundhandles[hash] = "cancel"
|
|
end
|
|
if type(celevator.drives.entity.buzzsoundhandles[hash]) ~= "string" then
|
|
minetest.sound_stop(celevator.drives.entity.buzzsoundhandles[hash])
|
|
celevator.drives.entity.buzzsoundhandles[hash] = nil
|
|
end
|
|
end
|
|
|
|
local function motorsound(pos,newstate)
|
|
local hash = minetest.hash_node_position(pos)
|
|
local oldstate = celevator.drives.entity.movementsoundstate[hash]
|
|
oldstate = oldstate or "idle"
|
|
if oldstate == newstate then return end
|
|
local carid = minetest.get_meta(pos):get_int("carid")
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not (carinfo and carinfo.machinepos) then return end
|
|
local oldhandle = celevator.drives.entity.movementsoundhandles[hash]
|
|
if newstate == "slow" then
|
|
if oldstate == "idle" then
|
|
minetest.sound_play("celevator_brake_release",{
|
|
pos = carinfo.machinepos,
|
|
gain = 1,
|
|
},true)
|
|
celevator.drives.entity.movementsoundhandles[hash] = minetest.sound_play("celevator_motor_slow",{
|
|
pos = carinfo.machinepos,
|
|
loop = true,
|
|
gain = 1,
|
|
})
|
|
elseif oldstate == "accel" or oldstate == "fast" or oldstate == "decel" then
|
|
if oldhandle then minetest.sound_stop(oldhandle) end
|
|
celevator.drives.entity.movementsoundhandles[hash] = minetest.sound_play("celevator_motor_slow",{
|
|
pos = carinfo.machinepos,
|
|
loop = true,
|
|
gain = 1,
|
|
})
|
|
end
|
|
elseif newstate == "accel" then
|
|
if oldhandle then minetest.sound_stop(oldhandle) end
|
|
celevator.drives.entity.movementsoundhandles[hash] = minetest.sound_play("celevator_motor_accel",{
|
|
pos = carinfo.machinepos,
|
|
gain = 1,
|
|
})
|
|
elseif newstate == "fast" then
|
|
if oldhandle then minetest.sound_stop(oldhandle) end
|
|
celevator.drives.entity.movementsoundhandles[hash] = minetest.sound_play("celevator_motor_fast",{
|
|
pos = carinfo.machinepos,
|
|
loop = true,
|
|
gain = 1,
|
|
})
|
|
elseif newstate == "decel" then
|
|
if oldhandle then minetest.sound_stop(oldhandle) end
|
|
celevator.drives.entity.movementsoundhandles[hash] = minetest.sound_play("celevator_motor_decel",{
|
|
pos = carinfo.machinepos,
|
|
gain = 1,
|
|
})
|
|
elseif newstate == "idle" then
|
|
if oldhandle then minetest.sound_stop(oldhandle) end
|
|
minetest.sound_play("celevator_brake_apply",{
|
|
pos = carinfo.machinepos,
|
|
gain = 1,
|
|
},true)
|
|
end
|
|
celevator.drives.entity.movementsoundstate[hash] = newstate
|
|
end
|
|
|
|
local function compareexchangesound(pos,compare,new)
|
|
local hash = minetest.hash_node_position(pos)
|
|
local oldstate = celevator.drives.entity.movementsoundstate[hash]
|
|
if oldstate == compare then
|
|
motorsound(pos,new)
|
|
end
|
|
end
|
|
|
|
local function accelsound(pos)
|
|
motorsound(pos,"slow")
|
|
minetest.after(1,compareexchangesound,pos,"slow","accel")
|
|
minetest.after(4,compareexchangesound,pos,"accel","fast")
|
|
end
|
|
|
|
local function decelsound(pos)
|
|
motorsound(pos,"decel")
|
|
minetest.after(2,compareexchangesound,pos,"decel","slow")
|
|
end
|
|
|
|
minetest.register_node("celevator:drive",{
|
|
description = celevator.drives.entity.name,
|
|
groups = {
|
|
cracky = 1,
|
|
_celevator_drive = 1,
|
|
},
|
|
tiles = {
|
|
"celevator_cabinet_sides.png",
|
|
"celevator_cabinet_sides.png",
|
|
"celevator_cabinet_sides.png",
|
|
"celevator_cabinet_sides.png",
|
|
"celevator_cabinet_sides.png",
|
|
"celevator_drive_front.png",
|
|
},
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.4,-0.4,-0.1,0.4,0.4,0.5},
|
|
{-0.5,-0.3,0.4,-0.4,-0.22,0.32},
|
|
{-0.5,0.22,0.4,-0.4,0.3,0.32},
|
|
},
|
|
},
|
|
_celevator_drive_type = "entity",
|
|
after_place_node = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("apos","0")
|
|
meta:set_string("dpos","0")
|
|
meta:set_string("vel","0")
|
|
meta:set_string("maxvel","0.2")
|
|
meta:set_string("state","uninit")
|
|
meta:set_string("startpos","0")
|
|
meta:set_string("doorstate","closed")
|
|
update_ui(pos)
|
|
end,
|
|
on_destruct = stopbuzz,
|
|
})
|
|
|
|
minetest.register_entity("celevator:car_moving",{
|
|
initial_properties = {
|
|
visual = "wielditem",
|
|
visual_size = vector.new(0.667,0.667,0.667),
|
|
wield_item = "default:dirt",
|
|
static_save = false,
|
|
glow = minetest.LIGHT_MAX,
|
|
},
|
|
})
|
|
|
|
function celevator.drives.entity.gathercar(pos,yaw,nodes)
|
|
if not nodes then nodes = {} end
|
|
local hash = minetest.hash_node_position(pos)
|
|
if nodes[hash] then return nodes end
|
|
nodes[hash] = true
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_xp") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.rotate_around_axis(vector.new(1,0,0),vector.new(0,1,0),yaw)),yaw,nodes)
|
|
end
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_xm") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.rotate_around_axis(vector.new(-1,0,0),vector.new(0,1,0),yaw)),yaw,nodes)
|
|
end
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_yp") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.new(0,1,0)),yaw,nodes)
|
|
end
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_ym") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.new(0,-1,0)),yaw,nodes)
|
|
end
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_zp") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.rotate_around_axis(vector.new(0,0,1),vector.new(0,1,0),yaw)),yaw,nodes)
|
|
end
|
|
if minetest.get_item_group(minetest.get_node(pos).name,"_connects_zm") == 1 then
|
|
celevator.drives.entity.gathercar(vector.add(pos,vector.rotate_around_axis(vector.new(0,0,-1),vector.new(0,1,0),yaw)),yaw,nodes)
|
|
end
|
|
return nodes
|
|
end
|
|
|
|
function celevator.drives.entity.nodestoentities(nodes,ename)
|
|
local refs = {}
|
|
for _,pos in ipairs(nodes) do
|
|
local node = minetest.get_node(pos)
|
|
local attach = minetest.get_objects_inside_radius(pos,0.9)
|
|
local eref = minetest.add_entity(pos,(ename or "celevator:car_moving"))
|
|
eref:set_properties({
|
|
wield_item = node.name,
|
|
})
|
|
eref:set_yaw(minetest.dir_to_yaw(minetest.fourdir_to_dir(node.param2)))
|
|
table.insert(refs,eref)
|
|
if node.name == "celevator:car_021" then
|
|
local toppos = vector.add(pos,vector.new(0,1,0))
|
|
local topattach = minetest.get_objects_inside_radius(toppos,0.9)
|
|
for _,ref in pairs(topattach) do
|
|
table.insert(attach,ref)
|
|
end
|
|
end
|
|
if not ename then --If ename is set, something other than the car is moving
|
|
for _,attachref in ipairs(attach) do
|
|
local included = {
|
|
["celevator:incar_pi_entity"] = true,
|
|
["celevator:car_top_box"] = true,
|
|
["celevator:car_door"] = true,
|
|
}
|
|
if attachref:get_luaentity() and included[attachref:get_luaentity().name] then
|
|
table.insert(refs,attachref)
|
|
else
|
|
local attachpos = attachref:get_pos()
|
|
local basepos = eref:get_pos()
|
|
local attachoffset = vector.multiply(vector.subtract(attachpos,basepos),30)
|
|
attachoffset = vector.rotate_around_axis(attachoffset,vector.new(0,-1,0),eref:get_yaw())
|
|
attachref:set_attach(eref,"",attachoffset)
|
|
end
|
|
end
|
|
end
|
|
minetest.remove_node(pos)
|
|
end
|
|
return refs
|
|
end
|
|
|
|
function celevator.drives.entity.entitiestonodes(refs,carid)
|
|
local ok = true
|
|
for _,eref in ipairs(refs) do
|
|
local pos = eref:get_pos()
|
|
local top = false
|
|
if pos and (eref:get_luaentity().name == "celevator:car_moving" or eref:get_luaentity().name == "celevator:hwdoor_moving") then
|
|
pos = vector.round(pos)
|
|
local node = {
|
|
name = eref:get_properties().wield_item,
|
|
param2 = minetest.dir_to_fourdir(minetest.yaw_to_dir(eref:get_yaw()))
|
|
}
|
|
if minetest.get_item_group(eref:get_properties().wield_item,"_connects_yp") ~= 1 then top = true end
|
|
minetest.set_node(pos,node)
|
|
eref:remove()
|
|
if carid then minetest.get_meta(pos):set_int("carid",carid) end
|
|
elseif pos and eref:get_luaentity().name == "celevator:incar_pi_entity" then
|
|
pos = vector.new(pos.x,math.floor(pos.y+0.5),pos.z)
|
|
eref:set_pos(pos)
|
|
else
|
|
ok = false
|
|
end
|
|
for _,i in ipairs(minetest.get_objects_inside_radius(pos,1)) do
|
|
i:set_velocity(vector.new(0,0,0))
|
|
if i:is_player() then
|
|
local ppos = i:get_pos()
|
|
ppos.y=ppos.y-0.4
|
|
if top then ppos.y = ppos.y+1.1 end
|
|
i:set_pos(ppos)
|
|
minetest.after(0.5,i.set_pos,i,ppos)
|
|
elseif i:get_luaentity().name == "celevator:car_top_box" or i:get_luaentity().name == "celevator:car_door" then
|
|
local epos = i:get_pos()
|
|
epos.y = math.floor(epos.y+0.5)
|
|
if i:get_luaentity().name == "celevator:car_top_box" then
|
|
epos.y = epos.y+0.1
|
|
end
|
|
i:set_pos(epos)
|
|
end
|
|
end
|
|
end
|
|
return ok
|
|
end
|
|
|
|
function celevator.drives.entity.step(dtime)
|
|
local entitydrives_running = minetest.deserialize(celevator.storage:get_string("entitydrives_running")) or {}
|
|
local save = false
|
|
for i,hash in ipairs(entitydrives_running) do
|
|
save = true
|
|
local pos = minetest.get_position_from_hash(hash)
|
|
local node = minetest.get_node(pos)
|
|
local sound = false
|
|
if node.name == "ignore" then
|
|
minetest.forceload_block(pos,true)
|
|
elseif node.name ~= "celevator:drive" then
|
|
table.remove(entitydrives_running,i)
|
|
else
|
|
local meta = minetest.get_meta(pos)
|
|
local carid = meta:get_int("carid")
|
|
local state = meta:get_string("state")
|
|
if not (state == "running" or state == "start" or state == "fakerunning") then
|
|
table.remove(entitydrives_running,i)
|
|
else
|
|
local dpos = tonumber(meta:get_string("dpos")) or 0
|
|
local maxvel = tonumber(meta:get_string("maxvel")) or 0.2
|
|
local startpos = tonumber(meta:get_string("startpos")) or 0
|
|
local origin = minetest.string_to_pos(meta:get_string("origin"))
|
|
if not origin then
|
|
minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(pos))
|
|
meta:set_string("fault","badorigin")
|
|
table.remove(entitydrives_running,i)
|
|
return
|
|
end
|
|
if state == "start" then
|
|
if math.abs(dpos-startpos) > 0.1 then
|
|
sound = true
|
|
if maxvel > 0.2 then
|
|
accelsound(pos)
|
|
else
|
|
motorsound(pos,"slow")
|
|
end
|
|
end
|
|
local startv = vector.add(origin,vector.new(0,startpos,0))
|
|
local hashes = celevator.drives.entity.gathercar(startv,minetest.dir_to_yaw(minetest.fourdir_to_dir(minetest.get_node(startv).param2)))
|
|
local nodes = {}
|
|
for carhash in pairs(hashes) do
|
|
local carpos = minetest.get_position_from_hash(carhash)
|
|
if vector.equals(startv,carpos) then
|
|
table.insert(nodes,1,carpos) --0,0,0 node must be first in the list
|
|
else
|
|
table.insert(nodes,carpos)
|
|
end
|
|
end
|
|
local carparam2 = minetest.get_node(nodes[1]).param2
|
|
meta:set_int("carparam2",carparam2)
|
|
local handles = celevator.drives.entity.nodestoentities(nodes)
|
|
celevator.drives.entity.entityinfo[hash] = {
|
|
handles = handles,
|
|
}
|
|
meta:set_string("state","running")
|
|
celevator.drives.entity.sheavetoentity(carid)
|
|
elseif state == "running" then
|
|
if not celevator.drives.entity.entityinfo[hash] then
|
|
meta:set_string("state","fakerunning")
|
|
return
|
|
end
|
|
local handles = celevator.drives.entity.entityinfo[hash].handles
|
|
if (not handles) or (not handles[1]:get_pos()) then
|
|
meta:set_string("state","fakerunning")
|
|
return
|
|
end
|
|
local apos = handles[1]:get_pos().y - origin.y
|
|
local sheaverefs = celevator.drives.entity.sheaverefs[carid]
|
|
if sheaverefs and sheaverefs[1] then
|
|
local rotation = sheaverefs[1]:get_rotation()
|
|
if rotation then
|
|
rotation.z = math.pi*apos*-1
|
|
sheaverefs[1]:set_rotation(rotation)
|
|
end
|
|
end
|
|
local dremain = math.abs(dpos-apos)
|
|
local dmoved = math.abs(apos-startpos)
|
|
local vel
|
|
if dremain < 0.01 then
|
|
vel = 0
|
|
meta:set_string("state","stopped")
|
|
motorsound(pos,"idle")
|
|
celevator.drives.entity.sheavetonode(carid)
|
|
local ok = celevator.drives.entity.entitiestonodes(handles,carid)
|
|
if not ok then
|
|
local carparam2 = meta:get_int("carparam2")
|
|
celevator.car.spawncar(vector.round(vector.add(origin,vector.new(0,apos,0))),minetest.dir_to_yaw(minetest.fourdir_to_dir(carparam2)),carid)
|
|
end
|
|
apos = math.floor(apos+0.5)
|
|
minetest.after(0.25,celevator.drives.entity.updatecopformspec,pos)
|
|
elseif dremain < 0.2 then
|
|
vel = 0.2
|
|
elseif dremain < 2*maxvel and dremain < dmoved then
|
|
vel = math.min(dremain,maxvel)
|
|
if celevator.drives.entity.movementsoundstate[hash] == "fast" or celevator.drives.entity.movementsoundstate[hash] == "accel" then
|
|
decelsound(pos)
|
|
end
|
|
elseif dmoved+0.1 > maxvel then
|
|
vel = maxvel
|
|
else
|
|
vel = dmoved+0.1
|
|
end
|
|
if dpos < apos then vel = 0-vel end
|
|
for _,eref in ipairs(handles) do
|
|
eref:set_velocity(vector.new(0,vel,0))
|
|
end
|
|
meta:set_string("apos",tostring(apos))
|
|
sound = vel ~= 0
|
|
meta:set_string("vel",tostring(vel))
|
|
elseif state == "fakerunning" then
|
|
local apos = tonumber(meta:get_string("apos")) or 0
|
|
local sheaverefs = celevator.drives.entity.sheaverefs[carid]
|
|
if sheaverefs and sheaverefs[1] then
|
|
local rotation = sheaverefs[1]:get_rotation()
|
|
if rotation then
|
|
rotation.z = math.pi*apos*-1
|
|
sheaverefs[1]:set_rotation(rotation)
|
|
end
|
|
end
|
|
local dremain = math.abs(dpos-apos)
|
|
local dmoved = math.abs(apos-startpos)
|
|
local vel
|
|
if dremain < 0.01 then
|
|
vel = 0
|
|
meta:set_string("state","stopped")
|
|
motorsound(pos,"idle")
|
|
celevator.drives.entity.sheavetonode(carid)
|
|
local carparam2 = meta:get_int("carparam2")
|
|
celevator.car.spawncar(vector.round(vector.add(origin,vector.new(0,apos,0))),minetest.dir_to_yaw(minetest.fourdir_to_dir(carparam2)),carid)
|
|
apos = math.floor(apos+0.5)
|
|
minetest.after(0.25,celevator.drives.entity.updatecopformspec,pos)
|
|
elseif dremain < 0.2 then
|
|
vel = 0.2
|
|
elseif dremain < 2*maxvel and dremain < dmoved then
|
|
vel = math.min(dremain,maxvel)
|
|
if celevator.drives.entity.movementsoundstate[hash] == "fast" or celevator.drives.entity.movementsoundstate[hash] == "accel" then
|
|
decelsound(pos)
|
|
end
|
|
elseif dmoved+0.1 > maxvel then
|
|
vel = maxvel
|
|
else
|
|
vel = dmoved+0.1
|
|
end
|
|
if dpos < apos then vel = 0-vel end
|
|
apos = apos+(vel*dtime)
|
|
meta:set_string("apos",tostring(apos))
|
|
sound = vel ~= 0
|
|
meta:set_string("vel",tostring(vel))
|
|
end
|
|
end
|
|
end
|
|
update_ui(pos)
|
|
if sound then
|
|
startbuzz(pos)
|
|
else
|
|
stopbuzz(pos)
|
|
end
|
|
end
|
|
if save then
|
|
celevator.storage:set_string("entitydrives_running",minetest.serialize(entitydrives_running))
|
|
end
|
|
end
|
|
|
|
minetest.register_globalstep(celevator.drives.entity.step)
|
|
|
|
function celevator.drives.entity.moveto(pos,target)
|
|
local meta = minetest.get_meta(pos)
|
|
local carid = minetest.get_meta(pos):get_int("carid")
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not (carinfo and carinfo.machinepos) then return end
|
|
local origin = minetest.string_to_pos(meta:get_string("origin"))
|
|
if not origin then
|
|
minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(pos))
|
|
meta:set_string("fault","badorigin")
|
|
return
|
|
end
|
|
if target < 0 or origin.y + target > (carinfo.machinepos.y-3) then
|
|
meta:set_string("fault","outofbounds")
|
|
return
|
|
end
|
|
if meta:get_string("state") ~= "stopped" then
|
|
local apos = tonumber(meta:get_string("apos"))
|
|
local vel = tonumber(meta:get_string("vel"))
|
|
if vel > 0 then
|
|
if target < apos+(vel*2) then return end
|
|
elseif vel < 0 then
|
|
if target > apos-(vel*-2) then return end
|
|
else
|
|
return
|
|
end
|
|
end
|
|
meta:set_string("dpos",tostring(target))
|
|
if meta:get_string("state") == "stopped" then
|
|
meta:set_string("state","start")
|
|
meta:set_string("startpos",meta:get_string("apos"))
|
|
local hash = minetest.hash_node_position(pos)
|
|
local entitydrives_running = minetest.deserialize(celevator.storage:get_string("entitydrives_running")) or {}
|
|
local running = false
|
|
for _,dhash in ipairs(entitydrives_running) do
|
|
if hash == dhash then
|
|
running = true
|
|
break
|
|
end
|
|
end
|
|
if not running then
|
|
table.insert(entitydrives_running,hash)
|
|
celevator.storage:set_string("entitydrives_running",minetest.serialize(entitydrives_running))
|
|
--Controller needs to see something so it knows the drive is running
|
|
local apos = tonumber(meta:get_string("apos"))
|
|
if apos and apos > target then
|
|
meta:set_string("vel","-0.0001")
|
|
else
|
|
meta:set_string("vel","0.0001")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function celevator.drives.entity.resetpos(pos)
|
|
celevator.drives.entity.moveto(pos,0)
|
|
end
|
|
|
|
function celevator.drives.entity.estop(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
if meta:get_string("state") ~= "running" then return end
|
|
local apos = math.floor(tonumber(meta:get_string("apos"))+0.5)
|
|
meta:set_string("dpos",tostring(apos))
|
|
meta:set_string("apos",tostring(apos))
|
|
local hash = minetest.hash_node_position(pos)
|
|
local handles = celevator.drives.entity.entityinfo[hash].handles
|
|
meta:set_string("state","stopped")
|
|
meta:set_string("vel","0")
|
|
local carid = meta:get_int("carid")
|
|
celevator.drives.entity.entitiestonodes(handles,carid)
|
|
stopbuzz(pos)
|
|
motorsound(pos,"idle")
|
|
if carid ~= 0 then celevator.drives.entity.sheavetonode(carid) end
|
|
minetest.after(0.25,celevator.drives.entity.updatecopformspec,pos)
|
|
end
|
|
|
|
|
|
function celevator.drives.entity.setmaxvel(pos,maxvel)
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("maxvel",tostring(maxvel))
|
|
end
|
|
|
|
|
|
function celevator.drives.entity.rezero(pos)
|
|
celevator.drives.entity.moveto(pos,0)
|
|
end
|
|
|
|
function celevator.drives.entity.getstatus(pos,call2)
|
|
local node = minetest.get_node(pos)
|
|
if node.name == "ignore" and not call2 then
|
|
minetest.forceload_block(pos,true)
|
|
return celevator.drives.entity.get_status(pos,true)
|
|
elseif node.name ~= "celevator:drive" then
|
|
minetest.log("error","[celevator] [entity drive] Could not load drive status at "..minetest.pos_to_string(pos))
|
|
return {fault = "metaload"}
|
|
else
|
|
local meta = minetest.get_meta(pos)
|
|
local ret = {}
|
|
ret.apos = tonumber(meta:get_string("apos")) or 0
|
|
ret.dpos = tonumber(meta:get_string("dpos")) or 0
|
|
ret.vel = tonumber(meta:get_string("vel")) or 0
|
|
ret.maxvel = tonumber(meta:get_string("maxvel")) or 0.2
|
|
ret.state = meta:get_string("state")
|
|
ret.doorstate = meta:get_string("doorstate")
|
|
ret.fault = meta:get_string("fault")
|
|
ret.neareststop = ret.apos+(ret.vel*2)
|
|
if ret.fault == "" then ret.fault = nil end
|
|
return ret
|
|
end
|
|
end
|
|
|
|
function celevator.drives.entity.movedoors(drivepos,direction)
|
|
local drivehash = minetest.hash_node_position(drivepos)
|
|
local entitydrives_running = minetest.deserialize(celevator.storage:get_string("entitydrives_running")) or {}
|
|
local drivemeta = minetest.get_meta(drivepos)
|
|
for _,hash in pairs(entitydrives_running) do
|
|
if drivehash == hash then
|
|
minetest.log("error","[celevator] [entity drive] Attempted to open doors while drive at "..minetest.pos_to_string(drivepos).." was still moving")
|
|
drivemeta:set_string("fault","doorinterlock")
|
|
return
|
|
end
|
|
end
|
|
local origin = minetest.string_to_pos(drivemeta:get_string("origin"))
|
|
if not origin then
|
|
minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(drivepos))
|
|
drivemeta:set_string("fault","badorigin")
|
|
return
|
|
end
|
|
local apos = tonumber(drivemeta:get_string("apos")) or 0
|
|
local carpos = vector.add(origin,vector.new(0,apos,0))
|
|
local carnode = minetest.get_node(carpos)
|
|
local hwdoorpos = vector.add(carpos,vector.rotate_around_axis(minetest.fourdir_to_dir(carnode.param2),vector.new(0,1,0),math.pi))
|
|
if direction == "open" and (minetest.get_item_group(minetest.get_node(hwdoorpos).name,"_celevator_hwdoor_root") == 1 or drivemeta:get_string("doorstate") == "closing") then
|
|
celevator.doors.hwopen(hwdoorpos,drivepos)
|
|
drivemeta:set_string("doorstate","opening")
|
|
elseif direction == "close" and minetest.get_node(hwdoorpos).name == "celevator:hwdoor_placeholder" then
|
|
celevator.doors.hwclose(hwdoorpos,drivepos)
|
|
drivemeta:set_string("doorstate","closing")
|
|
end
|
|
end
|
|
|
|
function celevator.drives.entity.resetfault(pos)
|
|
minetest.get_meta(pos):set_string("fault","")
|
|
end
|
|
|
|
function celevator.drives.entity.pibeep(drivepos)
|
|
local drivemeta = minetest.get_meta(drivepos)
|
|
local origin = minetest.string_to_pos(drivemeta:get_string("origin"))
|
|
if not origin then
|
|
minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(drivepos))
|
|
drivemeta:set_string("fault","badorigin")
|
|
return
|
|
end
|
|
local apos = tonumber(drivemeta:get_string("apos")) or 0
|
|
local beeppos = vector.add(origin,vector.new(0,apos+2,0))
|
|
minetest.sound_play("celevator_pi_beep",{
|
|
pos = beeppos,
|
|
gain = 1,
|
|
},true)
|
|
end
|
|
|
|
local function carsearch(pos)
|
|
for i=1,500,1 do
|
|
local searchpos = vector.subtract(pos,vector.new(0,i,0))
|
|
local node = minetest.get_node(searchpos)
|
|
if minetest.get_item_group(node.name,"_celevator_car") == 1 then
|
|
local yaw = minetest.dir_to_yaw(minetest.fourdir_to_dir(node.param2))
|
|
local offsettext = minetest.registered_nodes[node.name]._position
|
|
local xoffset = tonumber(string.sub(offsettext,1,1))
|
|
local yoffset = tonumber(string.sub(offsettext,2,2))
|
|
local zoffset = tonumber(string.sub(offsettext,3,3))
|
|
local offset = vector.new(xoffset,yoffset,zoffset)
|
|
offset = vector.rotate_around_axis(offset,vector.new(0,1,0),yaw)
|
|
return vector.subtract(searchpos,offset)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function updatecarpos(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
if meta:get_int("carid") == 0 then return end
|
|
local carpos = carsearch(pos)
|
|
if carpos then
|
|
meta:set_string("origin",minetest.pos_to_string(carpos))
|
|
minetest.get_meta(carpos):set_string("machinepos",minetest.pos_to_string(pos))
|
|
meta:set_string("infotext",string.format("Using car with origin %s",minetest.pos_to_string(carpos)))
|
|
local carid = meta:get_int("carid")
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not carinfo then return end
|
|
carinfo.origin = carpos
|
|
celevator.storage:set_string(string.format("car%d",carid),minetest.serialize(carinfo))
|
|
local drivepos = celevator.controller.finddrive(carinfo.controllerpos)
|
|
if drivepos then
|
|
local drivemeta = minetest.get_meta(drivepos)
|
|
if drivemeta:get_string("state") == "uninit" then
|
|
drivemeta:set_string("origin",minetest.pos_to_string(carpos))
|
|
drivemeta:set_string("state","stopped")
|
|
drivemeta:set_int("carid",carid)
|
|
end
|
|
end
|
|
local caryaw = minetest.dir_to_yaw(minetest.fourdir_to_dir(minetest.get_node(carpos).param2))
|
|
local carnodes = celevator.drives.entity.gathercar(carpos,caryaw)
|
|
for hash in pairs(carnodes) do
|
|
local carmeta = minetest.get_meta(minetest.get_position_from_hash(hash))
|
|
carmeta:set_int("carid",carid)
|
|
end
|
|
else
|
|
meta:set_string("infotext","No car found! Punch to try again")
|
|
end
|
|
end
|
|
|
|
minetest.register_node("celevator:machine",{
|
|
description = "Hoist Machine",
|
|
groups = {
|
|
dig_immediate = 2,
|
|
_celevator_machine = 1,
|
|
},
|
|
paramtype = "light",
|
|
paramtype2 = "4dir",
|
|
tiles = {
|
|
"celevator_machine_top.png",
|
|
"celevator_machine_top.png",
|
|
"celevator_machine_sides.png",
|
|
"celevator_machine_sides.png",
|
|
"celevator_machine_front.png",
|
|
"celevator_machine_front.png",
|
|
},
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.3,-0.5,-0.2,0.3,0.4,0.2}, -- Main body
|
|
{-0.2,0.4,-0.2,0.2,0.5,0.2}, -- Top of circle
|
|
{-0.4,-0.1,-0.2,-0.3,0.3,0.2}, -- Left of circle
|
|
{0.3,-0.1,-0.2,0.4,0.3,0.2}, -- Right of circle
|
|
{-0.42,0.075,-0.22,0.42,0.125,0.22}, -- Sealing flanges
|
|
{0.3,-0.3,-0.1,0.35,-0.1,0.1}, -- Bearing cap opposite motor
|
|
{-0.35,-0.3,-0.1,-0.3,-0.1,0.1}, -- Bearing cap on motor side
|
|
{-0.1,0,-0.5,0.1,0.2,-0.2}, -- Shaft to sheave
|
|
{-0.15,-0.05,0.2,0.15,0.25,0.25}, -- Bearing cap opposite sheave
|
|
{-0.15,-0.05,-0.25,0.15,0.25,-0.2}, -- Bearing cap on sheave side
|
|
{-0.5,-0.25,-0.05,-0.35,-0.15,0.05} -- Shaft from motor
|
|
},
|
|
},
|
|
after_place_node = function(pos)
|
|
updatecarpos(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_string("formspec","formspec_version[7]size[8,5]field[0.5,0.5;7,1;carid;Car ID;]button[3,3.5;2,1;save;Save]")
|
|
end,
|
|
on_punch = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
if not minetest.string_to_pos(meta:get_string("origin")) then
|
|
updatecarpos(pos)
|
|
end
|
|
end,
|
|
on_receive_fields = function(pos,_,fields)
|
|
if tonumber(fields.carid) then
|
|
local carid = tonumber(fields.carid)
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not carinfo then return end
|
|
carinfo.machinepos = pos
|
|
celevator.storage:set_string(string.format("car%d",carid),minetest.serialize(carinfo))
|
|
local meta = minetest.get_meta(pos)
|
|
meta:set_int("carid",carid)
|
|
meta:set_string("formspec","")
|
|
end
|
|
end,
|
|
})
|
|
|
|
minetest.register_node("celevator:motor",{
|
|
description = "Hoist Motor",
|
|
groups = {
|
|
dig_immediate = 2,
|
|
},
|
|
paramtype = "light",
|
|
paramtype2 = "4dir",
|
|
tiles = {
|
|
"celevator_machine_top.png",
|
|
"celevator_machine_top.png",
|
|
"celevator_motor_sides.png",
|
|
"celevator_motor_sides.png",
|
|
"celevator_machine_top.png",
|
|
"celevator_machine_top.png",
|
|
},
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.5,-0.5,-0.3,0.1,0.1,0.3}, -- Motor body
|
|
{0.1,-0.25,-0.05,0.5,-0.15,0.05}, -- Shaft
|
|
{0.3,-0.4,-0.2,0.35,0,0.2}, -- Brake disc
|
|
{0.275,-0.3,-0.1,0.375,-0.1,0.1}, -- Brake disc clamp
|
|
{0.2,-0.5,0.15,0.45,0.1,0.3}, -- Brake housing
|
|
{-0.4,0.1,-0.2,0,0.3,0.2}, -- Junction box
|
|
},
|
|
},
|
|
})
|
|
|
|
minetest.register_node("celevator:sheave",{
|
|
description = "Sheave",
|
|
groups = {
|
|
dig_immediate = 2,
|
|
},
|
|
paramtype = "light",
|
|
paramtype2 = "4dir",
|
|
tiles = {
|
|
"celevator_sheave_sides.png^[transformR90",
|
|
"celevator_sheave_sides.png^[transformR270",
|
|
"celevator_sheave_sides.png",
|
|
"celevator_sheave_sides.png^[transformR180",
|
|
"celevator_sheave_front.png",
|
|
"celevator_sheave_front.png",
|
|
},
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.3,-0.2,0.2,0.3,0.4,0.5},
|
|
{-0.4,-0.1,0.2,-0.3,0.3,0.5},
|
|
{0.3,-0.1,0.2,0.4,0.3,0.5},
|
|
{-0.2,0.4,0.2,0.2,0.5,0.5},
|
|
{-0.2,-0.3,0.2,0.2,-0.2,0.5},
|
|
},
|
|
},
|
|
})
|
|
|
|
minetest.register_node("celevator:sheave_centered",{
|
|
description = "Centered Sheave",
|
|
groups = {
|
|
dig_immediate = 2,
|
|
},
|
|
paramtype = "light",
|
|
paramtype2 = "4dir",
|
|
tiles = {
|
|
"celevator_sheave_sides.png^[transformR90",
|
|
"celevator_sheave_sides.png^[transformR270",
|
|
"celevator_sheave_sides.png",
|
|
"celevator_sheave_sides.png^[transformR180",
|
|
"celevator_sheave_front_centered.png",
|
|
"celevator_sheave_front_centered.png",
|
|
},
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.3,-0.3,0.2,0.3,0.3,0.5},
|
|
{-0.4,-0.2,0.2,-0.3,0.2,0.5},
|
|
{0.3,-0.2,0.2,0.4,0.2,0.5},
|
|
{-0.2,0.3,0.2,0.2,0.4,0.5},
|
|
{-0.2,-0.4,0.2,0.2,-0.3,0.5},
|
|
},
|
|
},
|
|
})
|
|
|
|
minetest.register_entity("celevator:sheave_moving",{
|
|
initial_properties = {
|
|
visual = "wielditem",
|
|
visual_size = vector.new(0.667,0.667,0.667),
|
|
wield_item = "celevator:sheave_centered",
|
|
static_save = false,
|
|
},
|
|
})
|
|
|
|
function celevator.drives.entity.sheavetoentity(carid)
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not (carinfo and carinfo.machinepos) then return end
|
|
local dir = minetest.fourdir_to_dir(minetest.get_node(carinfo.machinepos).param2)
|
|
local pos = vector.add(carinfo.machinepos,vector.multiply(dir,-1))
|
|
minetest.set_node(pos,{
|
|
name = "celevator:sheave",
|
|
param2 = minetest.dir_to_fourdir(dir),
|
|
})
|
|
local sheaverefs = celevator.drives.entity.nodestoentities({pos},"celevator:sheave_moving")
|
|
celevator.drives.entity.sheaverefs[carid] = sheaverefs
|
|
sheaverefs[1]:set_properties({wield_item = "celevator:sheave_centered"})
|
|
sheaverefs[1]:set_pos(vector.add(pos,vector.new(0,0.1,0)))
|
|
end
|
|
|
|
function celevator.drives.entity.sheavetonode(carid)
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not (carinfo and carinfo.machinepos) then return end
|
|
local dir = minetest.fourdir_to_dir(minetest.get_node(carinfo.machinepos).param2)
|
|
local pos = vector.add(carinfo.machinepos,vector.multiply(dir,-1))
|
|
local erefs = celevator.drives.entity.sheaverefs[carid]
|
|
if erefs and erefs[1] then
|
|
erefs[1]:remove()
|
|
end
|
|
minetest.set_node(pos,{
|
|
name = "celevator:sheave",
|
|
param2 = minetest.dir_to_fourdir(dir),
|
|
})
|
|
end
|
|
|
|
function celevator.drives.entity.updatecopformspec(drivepos)
|
|
local entitydrives_running = minetest.deserialize(celevator.storage:get_string("entitydrives_running")) or {}
|
|
if entitydrives_running[minetest.hash_node_position(drivepos)] then return end
|
|
local drivemeta = minetest.get_meta(drivepos)
|
|
local carid = drivemeta:get_int("carid")
|
|
if carid == 0 then return end
|
|
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
|
if not carinfo then return end
|
|
local copformspec = minetest.get_meta(carinfo.controllerpos):get_string("copformspec")
|
|
local switchformspec = minetest.get_meta(carinfo.controllerpos):get_string("switchformspec")
|
|
local origin = minetest.string_to_pos(drivemeta:get_string("origin"))
|
|
if not origin then
|
|
minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(drivepos))
|
|
drivemeta:set_string("fault","badorigin")
|
|
return
|
|
end
|
|
local apos = tonumber(drivemeta:get_string("apos")) or 0
|
|
local carpos = vector.add(origin,vector.new(0,apos,0))
|
|
local carnodes = celevator.drives.entity.gathercar(carpos,minetest.dir_to_yaw(minetest.fourdir_to_dir(minetest.get_node(carpos).param2)))
|
|
for hash in pairs(carnodes) do
|
|
local piecepos = minetest.get_position_from_hash(hash)
|
|
local piece = minetest.get_node(piecepos)
|
|
if piece.name == "celevator:car_010" then
|
|
minetest.get_meta(piecepos):set_string("formspec",copformspec)
|
|
elseif piece.name == "celevator:car_000" then
|
|
minetest.get_meta(piecepos):set_string("formspec",switchformspec)
|
|
end
|
|
end
|
|
end
|