summaryrefslogtreecommitdiff
path: root/drive_entity.lua
diff options
context:
space:
mode:
Diffstat (limited to 'drive_entity.lua')
-rw-r--r--drive_entity.lua176
1 files changed, 159 insertions, 17 deletions
diff --git a/drive_entity.lua b/drive_entity.lua
index ae72bca..0ddd4c4 100644
--- a/drive_entity.lua
+++ b/drive_entity.lua
@@ -11,6 +11,8 @@ celevator.drives.entity = {
sheaverefs = {},
}
+local playerposlimits = {}
+
local function update_ui(pos)
local meta = minetest.get_meta(pos)
local apos = tonumber(meta:get_string("apos")) or 0
@@ -231,6 +233,80 @@ minetest.register_entity("celevator:car_moving",{
},
})
+minetest.register_entity("celevator:player_holder",{
+ initial_properties = {
+ visual = "cube",
+ textures = {
+ "blank.png",
+ "blank.png",
+ "blank.png",
+ "blank.png",
+ "blank.png",
+ "blank.png",
+ },
+ --I have no idea where this magic number comes from, but it seems about right and that's good enough
+ visual_size = vector.new(3,3,3),
+ static_save = false,
+ pointable = false,
+ },
+ on_step = function(self,dtime)
+ local obj = self.object
+ local car,_,attachoffset = obj:get_attach()
+ if not car then
+ obj:remove()
+ return
+ end
+ local children = obj:get_children()
+ local player
+ for _,i in pairs(children) do
+ if i:is_player() then
+ player = i
+ end
+ end
+ if not player then return end
+ local caryaw = car:get_yaw()
+ local playeryaw = player:get_look_horizontal()
+ local attachrot = vector.new(0,(caryaw-playeryaw)*57.296,0)
+ local control = player:get_player_control()
+ if (control.up or control.down or control.left or control.right) then
+ local walkspeed = 120
+ local walkamount = walkspeed*dtime
+ local displacement = vector.new(0,0,0)
+ if control.up then
+ displacement = vector.add(displacement,vector.new(0,0,walkamount))
+ end
+ if control.down then
+ displacement = vector.add(displacement,vector.new(0,0,0-walkamount))
+ end
+ if control.left then
+ displacement = vector.add(displacement,vector.new(0-walkamount,0,0))
+ end
+ if control.right then
+ displacement = vector.add(displacement,vector.new(walkamount,0,0))
+ end
+ displacement = vector.rotate_around_axis(displacement,vector.new(0,1,0),playeryaw)
+ displacement = vector.rotate_around_axis(displacement,vector.new(0,-1,0),caryaw)
+ local oldattachoffset = vector.copy(attachoffset)
+ attachoffset = vector.add(attachoffset,displacement)
+ local realattachoffset = vector.rotate_around_axis(vector.multiply(attachoffset,1/30),vector.new(0,1,0),caryaw)
+ local newpos = vector.add(car:get_pos(),realattachoffset)
+ local limits = playerposlimits[player:get_player_name()] or {}
+ if limits.xmin and limits.xmax and limits.xmin < limits.xmax then
+ if newpos.x > limits.xmax or newpos.x < limits.xmin then
+ attachoffset = oldattachoffset
+ end
+ end
+ if limits.zmin and limits.zmax and limits.zmin < limits.zmax then
+ if newpos.z > limits.zmax or newpos.z < limits.zmin then
+ attachoffset = oldattachoffset
+ end
+ end
+ end
+ obj:set_attach(car,"",attachoffset,vector.new(0,0,0))
+ player:set_attach(obj,"",vector.new(0,0,0),attachrot)
+ end,
+})
+
function celevator.drives.entity.gathercar(pos,yaw,nodes)
if not nodes then nodes = {} end
local hash = minetest.hash_node_position(pos)
@@ -259,6 +335,16 @@ end
function celevator.drives.entity.nodestoentities(nodes,ename)
local refs = {}
+ local xmin = 32000
+ local xmax = -32000
+ local zmin = 32000
+ local zmax = -32000
+ for _,pos in ipairs(nodes) do
+ if pos.x < xmin then xmin = pos.x end
+ if pos.x > xmax then xmax = pos.x end
+ if pos.z < zmin then zmin = pos.z end
+ if pos.z > zmax then zmax = pos.z end
+ end
for _,pos in ipairs(nodes) do
local node = celevator.get_node(pos)
local attach = minetest.get_objects_inside_radius(pos,0.9)
@@ -268,7 +354,8 @@ function celevator.drives.entity.nodestoentities(nodes,ename)
})
eref:set_yaw(minetest.dir_to_yaw(minetest.fourdir_to_dir(node.param2)))
table.insert(refs,eref)
- if node.name == "celevator:car_021" or node.name == "celevator:car_122" then
+ local ndef = minetest.registered_nodes[node.name] or {}
+ if ndef._cartopbox or ndef._tapehead then
local toppos = vector.add(pos,vector.new(0,1,0))
local topattach = minetest.get_objects_inside_radius(toppos,0.75)
for _,ref in pairs(topattach) do
@@ -285,12 +372,27 @@ function celevator.drives.entity.nodestoentities(nodes,ename)
}
if attachref:get_luaentity() and included[attachref:get_luaentity().name] then
table.insert(refs,attachref)
+ elseif attachref:is_player() then
+ local attachpos = attachref:get_pos()
+ local basepos = eref:get_pos()
+ local attachoffset = vector.subtract(attachpos,basepos)
+ attachoffset = vector.rotate_around_axis(attachoffset,vector.new(0,-1,0),eref:get_yaw())
+ local holder = minetest.add_entity(attachpos,"celevator:player_holder")
+ holder:set_attach(eref,"",vector.multiply(attachoffset,30),vector.new(0,0,0))
+ attachref:set_attach(holder,"")
+ local extra = 0.25 --To allow getting closer to walls
+ playerposlimits[attachref:get_player_name()] = {
+ xmin = xmin-extra,
+ xmax = xmax+extra,
+ zmin = zmin-extra,
+ zmax = zmax+extra,
+ }
else
local attachpos = attachref:get_pos()
local basepos = eref:get_pos()
- local attachoffset = vector.multiply(vector.subtract(attachpos,basepos),30)
+ local attachoffset = vector.subtract(attachpos,basepos)
attachoffset = vector.rotate_around_axis(attachoffset,vector.new(0,-1,0),eref:get_yaw())
- attachref:set_attach(eref,"",attachoffset)
+ attachref:set_attach(eref,"",vector.multiply(attachoffset,30),vector.new(0,0,0))
end
end
end
@@ -333,10 +435,15 @@ function celevator.drives.entity.entitiestonodes(refs,carid)
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
+ ppos.y=ppos.y-0.48
+ if top then ppos.y = ppos.y+1.02 end
i:set_pos(ppos)
- minetest.after(0.5,i.set_pos,i,ppos)
+ minetest.after(0.5,function()
+ if not i:is_player() then return end
+ local newpos = i:get_pos()
+ newpos.y = math.max(newpos.y,ppos.y)
+ i:set_pos(newpos)
+ end)
elseif i:get_luaentity() and rounded[i:get_luaentity().name] then
local epos = i:get_pos()
epos.y = math.floor(epos.y+0.5)
@@ -373,6 +480,7 @@ function celevator.drives.entity.step(dtime)
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 oldvel = tonumber(meta:get_string("vel")) or 0
local inspection = meta:get_int("inspection") == 1
local origin = minetest.string_to_pos(meta:get_string("origin"))
if not origin then
@@ -402,7 +510,12 @@ function celevator.drives.entity.step(dtime)
end
end
local carparam2 = celevator.get_node(nodes[1]).param2
+ local cardef = minetest.registered_nodes[celevator.get_node(nodes[1]).name] or {}
+ local cartype = cardef._celevator_car_type or "standard"
+ local carmeta = celevator.get_meta(startv)
meta:set_int("carparam2",carparam2)
+ meta:set_string("cartype",cartype)
+ meta:set_string("doortype",carmeta:get_string("doortype"))
local handles = celevator.drives.entity.nodestoentities(nodes)
celevator.drives.entity.entityinfo[hash] = {
handles = handles,
@@ -432,20 +545,28 @@ function celevator.drives.entity.step(dtime)
local dremain = math.abs(dpos-apos)
local dmoved = math.abs(apos-startpos)
local vel
- if dremain < 0.01 then
+ local relevel = (dpos < apos and oldvel > 0) or (dpos > apos and oldvel < 0)
+ if dremain < 0.01 or (inspection and relevel) then
vel = 0
meta:set_string("state","stopped")
motorsound(pos,"idle")
celevator.drives.entity.sheavetonode(carid)
local ok = celevator.drives.entity.entitiestonodes(handles,carid)
+ local doortype = meta:get_string("doortype")
+ if (not doortype) or doortype == "" then doortype = "glass" end
+ local spawnpos = vector.round(vector.add(origin,vector.new(0,apos,0)))
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)
+ local cartype = meta:get_string("cartype")
+ celevator.car.spawncar(spawnpos,minetest.dir_to_yaw(minetest.fourdir_to_dir(carparam2)),carid,cartype,doortype)
+ else
+ celevator.get_meta(spawnpos):set_string("doortype",doortype)
end
apos = math.floor(apos+0.5)
minetest.after(0.25,celevator.drives.entity.updatecopformspec,pos)
- elseif dremain < 0.2 and not inspection then
- vel = 0.2
+ table.remove(entitydrives_running,i)
+ elseif dremain < 0.1 and not inspection then
+ vel = 0.1
elseif dremain < 2*maxvel and dremain < dmoved and not inspection then
vel = math.min(dremain,maxvel)
if celevator.drives.entity.movementsoundstate[hash] == "fast" or celevator.drives.entity.movementsoundstate[hash] == "accel" then
@@ -478,17 +599,23 @@ function celevator.drives.entity.step(dtime)
local dremain = math.abs(dpos-apos)
local dmoved = math.abs(apos-startpos)
local vel
- if dremain < 0.01 then
+ local relevel = (dpos < apos and oldvel > 0) or (dpos > apos and oldvel < 0)
+ if dremain < 0.01 or (relevel and inspection) 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)
+ local cartype = meta:get_string("cartype")
+ local doortype = meta:get_string("doortype")
+ if (not doortype) or doortype == "" then doortype = "glass" end
+ local spawnpos = vector.round(vector.add(origin,vector.new(0,apos,0)))
+ celevator.car.spawncar(spawnpos,minetest.dir_to_yaw(minetest.fourdir_to_dir(carparam2)),carid,cartype,doortype)
apos = math.floor(apos+0.5)
minetest.after(0.25,celevator.drives.entity.updatecopformspec,pos)
- elseif dremain < 0.2 and not inspection then
- vel = 0.2
+ table.remove(entitydrives_running,i)
+ elseif dremain < 0.1 and not inspection then
+ vel = 0.1
elseif dremain < 2*maxvel and dremain < dmoved and not inspection then
vel = math.min(dremain,maxvel)
if celevator.drives.entity.movementsoundstate[hash] == "fast" or celevator.drives.entity.movementsoundstate[hash] == "accel" then
@@ -526,7 +653,21 @@ function celevator.drives.entity.moveto(pos,target,inspection)
meta:mark_as_private({"apos","dpos","vel","maxvel","state","startpos","doorstate"})
local carid = celevator.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
+ if not (carinfo and carinfo.machinepos and celevator.get_node(carinfo.machinepos).name == "celevator:machine") then
+ meta:set_string("fault","nomachine")
+ return
+ end
+ if not carinfo.controllerpos then return end
+ local controllermeta = celevator.get_meta(carinfo.controllerpos)
+ if controllermeta:get_int("carid") ~= carid then
+ meta:set_string("fault","controllermismatch")
+ return
+ end
+ local machinemeta = celevator.get_meta(carinfo.machinepos)
+ if machinemeta:get_int("carid") ~= carid then
+ meta:set_string("fault","machinemismatch")
+ 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))
@@ -1025,9 +1166,10 @@ function celevator.drives.entity.updatecopformspec(drivepos)
for hash in pairs(carnodes) do
local piecepos = minetest.get_position_from_hash(hash)
local piece = celevator.get_node(piecepos)
- if piece.name == "celevator:car_010" then
+ local ndef = minetest.registered_nodes[piece.name] or {}
+ if ndef._cop then
celevator.get_meta(piecepos):set_string("formspec",copformspec)
- elseif piece.name == "celevator:car_000" then
+ elseif ndef._keyswitches then
celevator.get_meta(piecepos):set_string("formspec",switchformspec)
end
end