diff options
Diffstat (limited to 'drive_entity.lua')
-rw-r--r-- | drive_entity.lua | 176 |
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 |