Add "elevator mod by orwell.
|
@ -15,6 +15,7 @@ The following mods are also included:
|
|||
* chains ([homedecor_modpack][homedecor])
|
||||
* [christmas][] ([MIT](mods/buildings/christmas/LICENSE.txt))
|
||||
* computer ([homedecor_modpack][homedecor])
|
||||
* [elevator][] ([WTFPL](mods/buildings/elevator/readme.txt))
|
||||
* fake_fire ([homedecor_modpack][homedecor])
|
||||
* [fort_spikes][] ([MIT/CC0](mods/buildings/fort_spikes/LICENSE))
|
||||
* homedecor([homedecor_modpack][homedecor])
|
||||
|
@ -138,6 +139,7 @@ The following mods are also included:
|
|||
[compassgps]: https://forum.minetest.net/viewtopic.php?t=9373
|
||||
[craft_guide]: https://cornernote.github.io/minetest-craft_guide/
|
||||
[creeper]: https://forum.minetest.net/viewtopic.php?t=11891
|
||||
[elevator]: https://forum.minetest.net/viewtopic.php?t=12944
|
||||
[farming_plus]: https://forum.minetest.net/viewtopic.php?t=2787
|
||||
[fort_spikes]: https://forum.minetest.net/viewtopic.php?t=14574
|
||||
[glow]: https://forum.minetest.net/viewtopic.php?t=6300
|
||||
|
|
|
@ -0,0 +1,838 @@
|
|||
--ELEVATOR mod by orwell
|
||||
|
||||
|
||||
--table
|
||||
--[[format:
|
||||
[n]={
|
||||
motor_pos=pos
|
||||
xdir=bool
|
||||
entries={
|
||||
name=str
|
||||
deep=int
|
||||
sidecoord=1 or 2
|
||||
}
|
||||
}
|
||||
]]
|
||||
|
||||
elevators={}
|
||||
|
||||
elevator_fpath=minetest.get_worldpath().."/elevators"
|
||||
local file, err = io.open(elevator_fpath, "r")
|
||||
if not file then
|
||||
local er=err or "Unknown Error"
|
||||
print("[elevators]Failed loading file:"..er)
|
||||
else
|
||||
elevators = minetest.deserialize(file:read("*a"))
|
||||
if type(elevators) ~= "table" then
|
||||
elevators={}
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
|
||||
|
||||
elevator_save_cntdn=10
|
||||
elevator_save_stuff=function(dtime)--warning dtime can be missing (on shutdown)
|
||||
--and it will save everything
|
||||
|
||||
local datastr = minetest.serialize(elevators)
|
||||
if not datastr then
|
||||
minetest.log("error", "[elevator] Failed to serialize data!")
|
||||
return
|
||||
end
|
||||
local file, err = io.open(elevator_fpath, "w")
|
||||
if err then
|
||||
print(err)
|
||||
return
|
||||
end
|
||||
file:write(datastr)
|
||||
file:close()
|
||||
|
||||
end
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if elevator_save_cntdn<=0 then
|
||||
elevator_save_cntdn=10 --10 seconds interval!
|
||||
end
|
||||
elevator_save_cntdn=elevator_save_cntdn-dtime
|
||||
end)
|
||||
minetest.register_on_shutdown(elevator_save_stuff)
|
||||
|
||||
minetest.register_node("elevator:elev_rail", {
|
||||
drawtype="torchlike",
|
||||
tiles={"elevator_rail_bt.png", "elevator_rail_bt.png", "elevator_rail.png"},
|
||||
inventory_image = "elevator_rail.png",
|
||||
wield_image = "elevator_rail.png",
|
||||
paramtype="light",
|
||||
sunlight_propagates=true,
|
||||
paramtype2="wallmounted",
|
||||
description="Elevator Rail (place on wall!!!)",
|
||||
walkable=false,
|
||||
groups={elevator_rail=1, not_blocking_elevators=1, crumbly=1, oddly_breakable_by_hand=1, attached_node=1},
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
wall_bottom = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
wall_side = {-0.5, -0.5, -0.1, 0.1, 0.5, 0.1},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("elevator:elev_motor", {
|
||||
|
||||
drawtype = "normal",
|
||||
tiles = {"elevator_motor_top.png", "elevator_motor_bottom.png", "elevator_motor_side1.png", "elevator_motor_side3.png", "elevator_motor_side2.png", "elevator_motor_side4.png"},
|
||||
--^ Textures of node; +Y, -Y, +X, -X, +Z, -Z
|
||||
|
||||
description="Elevator Motor",
|
||||
|
||||
groups={crumbly=1, oddly_breakable_by_hand=1}, --kann man nicht abbauen
|
||||
|
||||
after_place_node=function(pos, placer, itemstack, pointed_thing)
|
||||
--can this node be placed here?
|
||||
local xdir=elevator_node_has_group(elevator_posadd(pos, {x=1, y=0, z=0}), "elevator_rail") and elevator_node_has_group(elevator_posadd(pos, {x=-1, y=0, z=0}), "elevator_rail")
|
||||
local zdir=elevator_node_has_group(elevator_posadd(pos, {x=0, y=0, z=1}), "elevator_rail") and elevator_node_has_group(elevator_posadd(pos, {x=0, y=0, z=-1}), "elevator_rail")
|
||||
if not (xdir or zdir) then
|
||||
if placer and placer:get_inventory() then
|
||||
placer:get_inventory():add_item("main", "elevator:elev_motor")
|
||||
end
|
||||
minetest.set_node(pos, {name="air"})
|
||||
end
|
||||
--create new table instance
|
||||
local ev={}
|
||||
ev.xdir=xdir
|
||||
ev.motor_pos=pos
|
||||
ev.entries={}
|
||||
table.insert(elevators, ev)
|
||||
end,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
for id,elev in pairs(elevators) do
|
||||
if elev.motor_pos.x==pos.x and elev.motor_pos.y==pos.y and elev.motor_pos.z==pos.z then
|
||||
elevator_purge(id, digger)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
function elevator_create_entity_at(id, deep)
|
||||
local ent=minetest.add_entity({x=elevators[id].motor_pos.x, y=elevators[id].motor_pos.y-deep-2, z=elevators[id].motor_pos.z}, "elevator:elevator")
|
||||
if elevators[id].xdir then
|
||||
ent:setyaw(math.pi*0.5);
|
||||
end
|
||||
ent:set_armor_groups({immortal=1})
|
||||
local luaent=ent:get_luaentity()
|
||||
luaent.currdeep=deep
|
||||
luaent.xdir=elevators[id].xdir
|
||||
luaent.tardeep=deep
|
||||
luaent.tardeep_set=true
|
||||
luaent.id=id
|
||||
luaent.nodestroy=true
|
||||
end
|
||||
|
||||
function elevator_entity_step(self, deltatime)
|
||||
|
||||
--if not self.lastchk or not self.lifetime then
|
||||
-- self.lastchk=0
|
||||
-- self.lifetime=0
|
||||
--end
|
||||
--self.lifetime=self.lifetime+deltatime
|
||||
--if self.lifetime < self.lastchk + 0.2 then--skip step
|
||||
-- return
|
||||
--end
|
||||
--self.lastchk=self.lifetime
|
||||
|
||||
--checking stuff
|
||||
|
||||
if not elevators[self.id] then self:on_punch() return end
|
||||
|
||||
--if minetest.get_node(self.motor_pos).name~="elevator:elev_motor" then
|
||||
-- print("[elevator]destroying due to missing motor block")
|
||||
-- self.object:remove()
|
||||
-- return
|
||||
--end
|
||||
|
||||
--end
|
||||
if not self.tardeep then
|
||||
self.tardeep=self.currdeep or 0
|
||||
end
|
||||
|
||||
if self.currdeep<0 then
|
||||
self.tardeep=0
|
||||
end
|
||||
|
||||
if not self.movement then
|
||||
self.movement=0
|
||||
end
|
||||
|
||||
local pos=self.object:getpos()
|
||||
--moving object before new movement is calculated
|
||||
self.object:setpos({x=math.floor(pos.x+0.5), y=pos.y, z=math.floor(pos.z+0.5)})
|
||||
|
||||
--calculating movement
|
||||
pos=self.object:getpos()
|
||||
|
||||
self.currdeep=(elevators[self.id].motor_pos.y-2)-math.floor(pos.y+0.5)
|
||||
|
||||
--check if shaft is free and equipped with rails
|
||||
local pos1, pos2
|
||||
if self.xdir then
|
||||
pos1, pos2= {x=1, y=0, z=0}, {x=-1, y=0, z=0}
|
||||
else
|
||||
pos1, pos2= {x=0, y=0, z=1}, {x=0, y=0, z=-1}
|
||||
end
|
||||
|
||||
local free=elevator_valid_room({x=math.floor(pos.x+0.5), y=math.floor(pos.y+0.5)+self.movement, z=math.floor(pos.z+0.5)}, pos1, pos2)
|
||||
if not free and self.currdeep~=self.tardeep then
|
||||
--[[if self.movement==1 then
|
||||
--minetest.chat_send_all("Elevator shaft is blocked, destroying...")
|
||||
--self.on_punch(self)
|
||||
--self.movement=-1
|
||||
self.tardeep=self.currdeep+1
|
||||
elseif self.movement==-1 then
|
||||
--minetest.chat_send_all("Elevator shaft blocked while driving down!!!")
|
||||
--self.currdeep=self.maxdeep+0
|
||||
--self.movement=1
|
||||
self.tardeep=self.currdeep-1
|
||||
elseif self.movement==0 then
|
||||
--self.maxdeep=self.currdeep-1
|
||||
self.tardeep=self.currdeep-1
|
||||
--self.currdeep=self.maxdeep-1
|
||||
|
||||
end]]
|
||||
self.tardeep=self.currdeep
|
||||
self.tardeep_set=true
|
||||
self.getoffto=nil
|
||||
end
|
||||
|
||||
--print(self.currdeep,self.tardeep,self.movement,pos.y,elevators[self.id].motor_pos.y-self.tardeep-2)
|
||||
|
||||
local roundedpos={x=math.floor(pos.x+0.5), y=math.floor(pos.y+0.5), z=math.floor(pos.z+0.5)}
|
||||
if self.currdeep==self.tardeep and ((self.movement==1 and pos.y>=elevators[self.id].motor_pos.y-self.tardeep-2) or (self.movement==-1 and pos.y<=elevators[self.id].motor_pos.y-self.tardeep-2) or self.tardeep_set) then
|
||||
--target reached
|
||||
self.movement=0
|
||||
self.object:setpos({x=elevators[self.id].motor_pos.x, y=elevators[self.id].motor_pos.y-self.tardeep-2, z=elevators[self.id].motor_pos.z})
|
||||
--some extra stuff to get the player off
|
||||
if (self.oldmovement~=0 or self.tardeep_set) then
|
||||
elevator_open_door(elevator_posadd(roundedpos, {x=pos1.z, y=pos1.y-1, z=pos1.x}))
|
||||
elevator_open_door(elevator_posadd(roundedpos, {x=pos2.z, y=pos2.y-1, z=pos2.x}))--swaps x and z since pos1 and pos2 orient to rails...
|
||||
end
|
||||
if self.getoffto and (self.oldmovement~=0 or self.tardeep_set) and self.driver then
|
||||
--print("[elevator]halt. self:"..dump(self))
|
||||
local player=self.driver
|
||||
if self.getoffto==1 then--vertausche x und z, weil diese die Schienenposotionen angeben
|
||||
local setoffpos={x=elevators[self.id].motor_pos.x+(2*pos1.z), y=((elevators[self.id].motor_pos.y-2)-self.currdeep), z=elevators[self.id].motor_pos.z+(2*pos1.x)}
|
||||
minetest.after(0.5, function()
|
||||
player:set_detach()
|
||||
--minetest.chat_send_player(player:get_player_name(), "Get off to "..minetest.pos_to_string(setoffpos))
|
||||
minetest.after(0, function()
|
||||
player:setpos(setoffpos)
|
||||
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
end)
|
||||
end)
|
||||
self.driver=nil
|
||||
elseif self.getoffto==2 then
|
||||
local setoffpos={x=elevators[self.id].motor_pos.x+(2*pos2.z), y=((elevators[self.id].motor_pos.y-2)-self.currdeep), z=elevators[self.id].motor_pos.z+(2*pos2.x)}
|
||||
minetest.after(0.5, function()
|
||||
player:set_detach()
|
||||
--minetest.chat_send_player(player:get_player_name(), "Get off to "..minetest.pos_to_string(setoffpos))
|
||||
minetest.after(0, function()
|
||||
player:setpos(setoffpos)
|
||||
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
end)
|
||||
end)
|
||||
self.driver=nil
|
||||
end
|
||||
end
|
||||
elseif self.currdeep>self.tardeep then--moving up
|
||||
self.movement=1
|
||||
if self.oldmovement==0 then
|
||||
self.movestartfactor=0
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos1.z, y=pos1.y-1, z=pos1.x}))--swaps x and z since pos1 and pos2 orient to rails...
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos2.z, y=pos2.y-1, z=pos2.x}))
|
||||
end
|
||||
elseif self.currdeep<self.tardeep then--moving down
|
||||
self.movement=-1
|
||||
if self.oldmovement==0 then
|
||||
self.movestartfactor=0
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos1.z, y=pos1.y-1, z=pos1.x}))--swaps x and z since pos1 and pos2 orient to rails...
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos2.z, y=pos2.y-1, z=pos2.x}))
|
||||
end
|
||||
end
|
||||
self.oldmovement=self.movement+0
|
||||
--setting velocity after new movement has been calculated
|
||||
--self.object:moveto({x=elevators[self.id].motor_pos.x, y=elevators[self.id].motor_pos.y-self.tardeep-2, z=elevators[self.id].motor_pos.z},2)
|
||||
local spdfactor=math.max(math.min(math.abs((elevators[self.id].motor_pos.y-self.tardeep-2) - pos.y),8),0.5)--distance to target, but maximum 8 and minimum 0.5
|
||||
if not self.movestartfactor then
|
||||
self.movestartfactor=0
|
||||
end
|
||||
if self.movestartfactor<1 then
|
||||
self.movestartfactor=self.movestartfactor+0.05
|
||||
end
|
||||
local newvelocity=self.movement*spdfactor*self.movestartfactor
|
||||
--ensure vars are not nil
|
||||
if not self.forcevelocitytimer then self.forcevelocitytimer=5 end
|
||||
if not self.oldvelocity then self.oldvelocity=0 end
|
||||
|
||||
self.forcevelocitytimer=self.forcevelocitytimer+deltatime--forces a velocity client send update every 5 secs or when velocity changes.
|
||||
if self.oldvelocity~=newvelocity or self.forcevelocitytimer>5 then
|
||||
self.object:setvelocity({x=0, y=newvelocity, z=0});
|
||||
self.forcevelocitytimer=0
|
||||
end
|
||||
self.oldvelocity=newvelocity
|
||||
self.tardeep_set=false
|
||||
end
|
||||
|
||||
function elevator_entity_rightclick(self, clicker)--now it begins to get interesting
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
if self.driver and clicker == self.driver and self.movement==0 then
|
||||
minetest.show_formspec(clicker:get_player_name(), "elevator_drive_"..self.id, elevator_get_formspec(elevators[self.id].entries, self.currdeep))
|
||||
elseif not self.driver and not self.shaft_exploration then
|
||||
self.driver = clicker
|
||||
clicker:set_attach(self.object, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
|
||||
clicker:set_eye_offset({x=0,y=-5,z=0},{x=0,y=-5,z=0})
|
||||
minetest.show_formspec(clicker:get_player_name(), "elevator_drive_"..self.id, elevator_get_formspec(elevators[self.id].entries, self.currdeep))
|
||||
end
|
||||
--print("[elevator] [dbg] [entries] "..dump(self.entries))
|
||||
end
|
||||
function elevator_get_formspec(entries, currdeep)
|
||||
--step 1: buttons for goto
|
||||
local form="size[10, 8]"
|
||||
local exit1, exit2
|
||||
for index, entry in ipairs(entries) do
|
||||
form=form.."button_exit[1,"..(index/1.5)..";5,1;goto"..entry.deep..":"..entry.sidecoord..";"..entry.name.."]"
|
||||
if entry.deep==currdeep then
|
||||
if entry.sidecoord==1 then
|
||||
exit1=entry.name
|
||||
elseif entry.sidecoord==2 then
|
||||
exit2=entry.name
|
||||
end
|
||||
end
|
||||
end
|
||||
--step 2 getoff buttons
|
||||
|
||||
if exit1 then
|
||||
form=form.."button_exit[1,7;4,1;getoff1;Get off at "..exit1.."]"
|
||||
end
|
||||
if exit2 then
|
||||
form=form.."button_exit[5,7;4,1;getoff2;Get off at "..exit2.."]"
|
||||
end
|
||||
return form
|
||||
end
|
||||
function elevator_receives_fields(self, player, fields)
|
||||
if not player or not self.driver or self.driver~=player then
|
||||
return
|
||||
end
|
||||
for key, value in pairs(fields) do
|
||||
local get, side=string.match(key, "goto([0-9%-]+):([12])")
|
||||
if get then
|
||||
self.tardeep=get+0
|
||||
self.getoffto=side+0;
|
||||
self.tardeep_set=true
|
||||
minetest.chat_send_player(player:get_player_name(), "Elevator driving to "..value)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local pos1, pos2
|
||||
if not self.xdir then
|
||||
pos1, pos2= {x=1, y=0, z=0}, {x=-1, y=0, z=0}
|
||||
else
|
||||
pos1, pos2= {x=0, y=0, z=1}, {x=0, y=0, z=-1}
|
||||
end
|
||||
|
||||
if fields.getoff1 then
|
||||
player:set_detach()
|
||||
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
local setoffpos={x=elevators[self.id].motor_pos.x+(2*pos1.x), y=((elevators[self.id].motor_pos.y-2)-self.currdeep), z=elevators[self.id].motor_pos.z+(2*pos1.z)}
|
||||
--minetest.chat_send_player(player:get_player_name(), "Get off to"..minetest.pos_to_string(setoffpos))
|
||||
minetest.after(0.2, function() player:setpos(setoffpos) end)
|
||||
self.driver=nil
|
||||
elseif fields.getoff2 then
|
||||
player:set_detach()
|
||||
player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
local setoffpos={x=elevators[self.id].motor_pos.x+(2*pos2.x), y=((elevators[self.id].motor_pos.y-2)-self.currdeep), z=elevators[self.id].motor_pos.z+(2*pos2.z)}
|
||||
--minetest.chat_send_player(player:get_player_name(), "Get off to"..minetest.pos_to_string(setoffpos))
|
||||
minetest.after(0.2, function() player:setpos(setoffpos) end)
|
||||
self.driver=nil
|
||||
end
|
||||
end
|
||||
---register
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local idstr=string.match(formname, "elevator_drive_(.+)")
|
||||
if idstr then
|
||||
print(idstr)
|
||||
local id=idstr+0
|
||||
for obj_id, ent in pairs(minetest.luaentities) do
|
||||
if ent.is_elevator and ent.id and ent.id==id then
|
||||
elevator_receives_fields(ent, player, fields)
|
||||
--minetest.chat_send_all("click elevator")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
local nposs=string.match(formname, "elevator_setname_(%(.+%))")
|
||||
if nposs then
|
||||
local nos=minetest.string_to_pos(nposs)
|
||||
if not fields.name or fields.name=="" then
|
||||
player:get_inventory():add_item("main", "elevator:elev_entry")
|
||||
minetest.set_node(nos, {name="air"})
|
||||
else
|
||||
elevator_set_name(nos, fields.name, player)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
------------------------helpers
|
||||
--[[function elevator_get_elev_data(pos)
|
||||
if minetest.get_node(pos).name~="elevator:elev_motor" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local xdir=elevator_node_has_group(elevator_posadd(pos, {x=1, y=0, z=0}), "elevator_rail") and elevator_node_has_group(elevator_posadd(pos, {x=-1, y=0, z=0}), "elevator_rail")
|
||||
local zdir=elevator_node_has_group(elevator_posadd(pos, {x=0, y=0, z=1}), "elevator_rail") and elevator_node_has_group(elevator_posadd(pos, {x=0, y=0, z=-1}), "elevator_rail")
|
||||
if xdir and not zdir then
|
||||
return elevator_get_deep(elevator_posadd(pos, {x=0, y=-2, z=0}), {x=1, y=0, z=0}, {x=-1, y=0, z=0})
|
||||
elseif zdir and not xdir then
|
||||
return elevator_get_deep(elevator_posadd(pos, {x=0, y=-2, z=0}), {x=0, y=0, z=1}, {x=0, y=0, z=-1})
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--crawls down and does the actual work
|
||||
function elevator_get_deep(pos, railp1, railp2)
|
||||
local curry=0
|
||||
local entries={}
|
||||
while elevator_valid_room(elevator_posadd(pos, {x=0, y=-curry, z=0}), railp1, railp2) do
|
||||
if elevator_node_has_group(elevator_posadd(pos, {x=railp1.z, y=-curry, z=railp1.x}), "elevator_entry") then
|
||||
local meta=minetest.get_meta(elevator_posadd(pos, {x=railp1.z, y=-curry, z=railp1.x}))
|
||||
if meta then
|
||||
local n=meta:get_string("entry_name")
|
||||
table.insert(entries, {deep=curry, name=n})
|
||||
end
|
||||
end
|
||||
if elevator_node_has_group(elevator_posadd(pos, {x=railp2.z, y=-curry, z=railp2.x}), "elevator_entry") then
|
||||
local meta=minetest.get_meta(elevator_posadd(pos, {x=railp1.z, y=-curry, z=railp1.x}))
|
||||
if meta then
|
||||
local n=meta:get_string("entry_name")
|
||||
table.insert(entries, {deep=curry, name=n})
|
||||
end
|
||||
end
|
||||
curry=curry+1
|
||||
end
|
||||
if curry<=0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return curry-1, entries
|
||||
|
||||
end]]--no longer needed
|
||||
|
||||
function elevator_valid_room(pos, railp1, railp2)
|
||||
local posis={
|
||||
{x=1, y=0, z=1},
|
||||
{x=0, y=0, z=1},
|
||||
{x=-1, y=0, z=1},
|
||||
{x=1, y=0, z=0},
|
||||
{x=0, y=0, z=0},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=1, y=0, z=-1},
|
||||
{x=0, y=0, z=-1},
|
||||
{x=-1, y=0, z=-1}
|
||||
}
|
||||
for _,posi in ipairs(posis) do
|
||||
if not elevator_node_has_group(elevator_posadd(pos, posi), "not_blocking_elevators") then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return elevator_node_has_group(elevator_posadd(pos, railp1), "elevator_rail") and elevator_node_has_group(elevator_posadd(pos, railp2), "elevator_rail")
|
||||
end
|
||||
|
||||
function elevator_node_has_group(pos, group)
|
||||
local node=minetest.get_node(pos)
|
||||
if not node then return true end
|
||||
local def=minetest.registered_nodes[node.name].groups
|
||||
if not def then return false end
|
||||
return def[group]
|
||||
end
|
||||
function elevator_posadd(pos, add)
|
||||
return {x=pos.x+add.x, y=pos.y+add.y, z=pos.z+add.z}
|
||||
end
|
||||
function elevator_purge(id, player)
|
||||
local elev=table.remove(elevators, id)
|
||||
for k,v in pairs(elev.entries) do
|
||||
minetest.remove_node(v.pos)
|
||||
if player then player:get_inventory():add_item("main", "elevator:elev_entry") end
|
||||
end
|
||||
end
|
||||
function elevator_set_name(pos, name, player)
|
||||
|
||||
--register in elevator
|
||||
--find one
|
||||
local found_id, sidecoord, nodedircrd, temp_nodedircrd
|
||||
local found_layer=31000
|
||||
for id,elev in ipairs(elevators) do
|
||||
--is it a possible elevator
|
||||
local mpos=elev.motor_pos
|
||||
local xdir=elev.xdir
|
||||
local pos1, pos2
|
||||
if not xdir then
|
||||
pos1, pos2= elevator_posadd(mpos,{x=1, y=0, z=0}), elevator_posadd(mpos,{x=-1, y=0, z=0})
|
||||
temp_nodedircrd={2, 0}
|
||||
else
|
||||
pos1, pos2= elevator_posadd(mpos,{x=0, y=0, z=1}), elevator_posadd(mpos,{x=0, y=0, z=-1})
|
||||
temp_nodedircrd={1, 3}
|
||||
end
|
||||
|
||||
--sidecoord=1
|
||||
if (pos.x==pos1.x and pos.z==pos1.z) then
|
||||
print(xdir,"SIDECOORD 1",dump(nodedircrd))
|
||||
if found_layer>mpos.y and mpos.y>pos.y then
|
||||
found_layer=mpos.y
|
||||
found_id=id
|
||||
sidecoord=1
|
||||
nodedircrd=temp_nodedircrd
|
||||
end
|
||||
end
|
||||
if (pos.x==pos2.x and pos.z==pos2.z) then
|
||||
print(xdir," SIDECOORD 2",dump(nodedircrd))
|
||||
if found_layer>mpos.y and mpos.y>pos.y then
|
||||
found_layer=mpos.y
|
||||
found_id=id
|
||||
sidecoord=2
|
||||
nodedircrd=temp_nodedircrd
|
||||
end
|
||||
end
|
||||
end
|
||||
if found_id then
|
||||
--find pos to insert
|
||||
local added=false
|
||||
for key,entry in ipairs(elevators[found_id].entries) do
|
||||
if entry.deep>(found_layer-pos.y-3) then
|
||||
table.insert(elevators[found_id].entries,key,{name=name, deep=found_layer-pos.y-3, sidecoord=sidecoord, pos=pos})
|
||||
added=true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not added then
|
||||
table.insert(elevators[found_id].entries,{name=name, deep=found_layer-pos.y-3, sidecoord=sidecoord, pos=pos})
|
||||
end
|
||||
--local num=#elevators[found_id].entries+1
|
||||
|
||||
--turn the block the right direction...
|
||||
minetest.set_node(pos, {name="elevator:elev_entry", param2=nodedircrd[sidecoord]})
|
||||
|
||||
local meta=minetest.get_meta(pos)
|
||||
if meta then
|
||||
meta:set_string("calls_id", found_id)
|
||||
meta:set_string("calls_deep", found_layer-pos.y-3)
|
||||
end
|
||||
print("added",name,"to",found_id,"deep",found_layer-pos.y-3)
|
||||
--print(dump(elevators))
|
||||
|
||||
else
|
||||
minetest.chat_send_player(player:get_player_name(),"No elevator found here!")
|
||||
minetest.remove_node(pos)
|
||||
player:get_inventory():add_item("main", "elevator:elev_entry")
|
||||
end
|
||||
end
|
||||
|
||||
--opening/closing doors (lol)
|
||||
function elevator_open_door(pos)
|
||||
local node=minetest.get_node_or_nil(pos)
|
||||
--print("opening door ",minetest.pos_to_string(pos)," node:",dump(node))
|
||||
if node and node.name=="elevator:elev_entry" then
|
||||
--print(" is right door type, will open...")
|
||||
minetest.swap_node(pos, {name="elevator:elev_entry_half", param2=node.param2})
|
||||
minetest.after(0.3,function()
|
||||
minetest.swap_node(pos, {name="elevator:elev_entry_open", param2=node.param2})
|
||||
end)
|
||||
end
|
||||
end
|
||||
function elevator_close_door(pos)
|
||||
local node=minetest.get_node_or_nil(pos)
|
||||
--print("closing door ",minetest.pos_to_string(pos)," node:",dump(node))
|
||||
if node and node.name=="elevator:elev_entry_open" then
|
||||
--print(" is right door type, will close...")
|
||||
minetest.swap_node(pos, {name="elevator:elev_entry_half", param2=node.param2})
|
||||
minetest.after(0.3,function()
|
||||
minetest.swap_node(pos, {name="elevator:elev_entry", param2=node.param2})
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local entry_nodebox_open={
|
||||
-- A fixed box (facedir param2 is used, if applicable)
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, -0.2, 0.5, 0.5},--base node
|
||||
{-0.4, 0.5, -1.0, -0.3, 2.5, -0.5},--left wing
|
||||
{-0.4, 0.5, 0.5, -0.3, 2.5, 1.0},--right wing
|
||||
|
||||
{-0.5, 0.5, -1.5, -0.4, 2.5, -0.5},--left panel
|
||||
{-0.5, 0.5, 0.5, -0.4, 2.5, 1.5},--right panel
|
||||
|
||||
}
|
||||
}
|
||||
local entry_nodebox_half={
|
||||
-- A fixed box (facedir param2 is used, if applicable)
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, -0.2, 0.5, 0.5},--base node
|
||||
{-0.4, 0.5, -0.75, -0.4, 2.5, -0.25},--left wing
|
||||
{-0.4, 0.5, 0.25, -0.3, 2.5, 0.75},--right wing
|
||||
|
||||
{-0.5, 0.5, -1.5, -0.4, 2.5, -0.5},--left panel
|
||||
{-0.5, 0.5, 0.5, -0.4, 2.5, 1.5},--right panel
|
||||
}
|
||||
}
|
||||
local entry_nodebox_closed={
|
||||
-- A fixed box (facedir param2 is used, if applicable)
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, -0.2, 0.5, 0.5},--base node
|
||||
{-0.4, 0.5, -0.5, -0.3, 2.5, 0.5},--door
|
||||
|
||||
{-0.5, 0.5, -1.5, -0.4, 2.5, -0.5},--left panel
|
||||
{-0.5, 0.5, 0.5, -0.4, 2.5, 1.5},--right panel
|
||||
}
|
||||
}
|
||||
|
||||
elevator_on_entry_rightclick=function(pos, node, clicker)
|
||||
if not clicker or not clicker:is_player() then return end
|
||||
|
||||
local meta=minetest.get_meta(pos)
|
||||
local ids=meta:get_string("calls_id")
|
||||
if not ids or ids=="" then return end--fixed fast doubleclick
|
||||
local id=ids+0
|
||||
if id and elevators[id] then
|
||||
local deep=meta:get_string("calls_deep")+0
|
||||
for obj_id, ent in pairs(minetest.luaentities) do
|
||||
if ent.is_elevator and ent.id==id then
|
||||
if not ent.driver then
|
||||
if math.abs(ent.currdeep-deep)<(math.max((minetest.setting_get("active_block_range") or 0)-1,1)*16) then
|
||||
ent.tardeep=deep
|
||||
ent.getoffto=nil
|
||||
ent.tardeep_set=true
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Called Elevator.")
|
||||
return nil
|
||||
else
|
||||
ent:on_punch()
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Another player is using this elevator! Can't call!")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
elevator_create_entity_at(id, deep)
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Spawned Elevator.")
|
||||
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Invalid Metadata")
|
||||
--print(dump(elevators))
|
||||
--print(dump(meta:to_table()))
|
||||
--print(id)
|
||||
end
|
||||
end,
|
||||
|
||||
minetest.register_node("elevator:elev_entry", {
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = entry_nodebox_closed,
|
||||
selection_box = entry_nodebox_closed,
|
||||
collision_box = entry_nodebox_closed,
|
||||
|
||||
tiles = {"elevator_entry.png"},
|
||||
|
||||
paramtype2="facedir",
|
||||
paramtype="light",
|
||||
|
||||
description="Elevator Door",
|
||||
inventory_image="elevator_entry.png",
|
||||
wield_image="elevator_entry.png",
|
||||
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
if placer and pos then
|
||||
minetest.show_formspec(placer:get_player_name(), "elevator_setname_"..minetest.pos_to_string(pos), "field[name;Name of door;]")
|
||||
end
|
||||
end,
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
print(dump(oldmetadata))
|
||||
if not oldmetadata.fields.calls_id then return end
|
||||
local id=oldmetadata.fields["calls_id"]+0
|
||||
if id and elevators[id] then
|
||||
for key,entry in pairs(elevators[id].entries) do
|
||||
if entry.pos.x==pos.x and entry.pos.y==pos.y and entry.pos.z==pos.z then
|
||||
table.remove(elevators[id].entries,key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
--on_rightclick=elevator_on_entry_rightclick,
|
||||
groups={not_blocking_elevators=1, elevator_entry=1, cracky=1, oddly_breakable_by_hand=1},
|
||||
|
||||
on_rightclick=function(pos, node, clicker)
|
||||
elevator_on_entry_rightclick(pos, node, clicker)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_node("elevator:elev_entry_open", {
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = entry_nodebox_open,
|
||||
selection_box = entry_nodebox_open,
|
||||
collision_box = entry_nodebox_open,
|
||||
|
||||
|
||||
tiles = {"elevator_entry.png"},
|
||||
|
||||
description="Elevator Door (open) (you hacker you...)",
|
||||
|
||||
paramtype2="facedir",
|
||||
paramtype="light",
|
||||
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
print(dump(oldmetadata))
|
||||
local id=(oldmetadata.fields["calls_id"] or -1)+0
|
||||
if id and elevators[id] then
|
||||
for key,entry in pairs(elevators[id].entries) do
|
||||
if entry.pos.x==pos.x and entry.pos.y==pos.y and entry.pos.z==pos.z then
|
||||
table.remove(elevators[id].entries,key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
drop = 'elevator:elev_entry',
|
||||
groups={not_blocking_elevators=1, elevator_entry=1, cracky=1, oddly_breakable_by_hand=1, not_in_creative_inventory=1},
|
||||
on_rightclick=function(pos, node, clicker)
|
||||
elevator_on_entry_rightclick(pos, node, clicker)
|
||||
end
|
||||
|
||||
})
|
||||
minetest.register_node("elevator:elev_entry_half", {
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = entry_nodebox_half,
|
||||
selection_box = entry_nodebox_half,
|
||||
collision_box = entry_nodebox_half,
|
||||
|
||||
|
||||
tiles = {"elevator_entry.png"},
|
||||
|
||||
description="Elevator Door (half-open) (you hacker you...)",
|
||||
|
||||
paramtype2="facedir",
|
||||
paramtype="light",
|
||||
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
print(dump(oldmetadata))
|
||||
local id=(oldmetadata.fields["calls_id"] or -1)+0
|
||||
if id and elevators[id] then
|
||||
for key,entry in pairs(elevators[id].entries) do
|
||||
if entry.pos.x==pos.x and entry.pos.y==pos.y and entry.pos.z==pos.z then
|
||||
table.remove(elevators[id].entries,key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
drop = 'elevator:elev_entry',
|
||||
groups={not_blocking_elevators=1, elevator_entry=1, cracky=1, oddly_breakable_by_hand=1, not_in_creative_inventory=1},
|
||||
on_rightclick=function(pos, node, clicker)
|
||||
elevator_on_entry_rightclick(pos, node, clicker)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_entity("elevator:elevator", {
|
||||
is_elevator=true,
|
||||
on_step=elevator_entity_step,
|
||||
on_activate=function(self, staticdata)
|
||||
if staticdata=="destroy" then
|
||||
self.on_punch(self)
|
||||
end
|
||||
end,
|
||||
get_staticdata=function(self)
|
||||
return "destroy"
|
||||
end,
|
||||
on_rightclick=elevator_entity_rightclick,
|
||||
on_punch=function(self, puncher)
|
||||
--if elevators[self.id] then
|
||||
-- minetest.set_node(elevators[self.id].motor_pos, {name="air"})
|
||||
--end
|
||||
--close doors here...
|
||||
if self.xdir then
|
||||
pos1, pos2= {x=1, y=0, z=0}, {x=-1, y=0, z=0}
|
||||
else
|
||||
pos1, pos2= {x=0, y=0, z=1}, {x=0, y=0, z=-1}
|
||||
end
|
||||
local pos=self.object:getpos()
|
||||
local roundedpos={x=math.floor(pos.x+0.5), y=math.floor(pos.y+0.5), z=math.floor(pos.z+0.5)}
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos1.z, y=pos1.y-1, z=pos1.x}))--swaps x and z since pos1 and pos2 orient to rails...
|
||||
elevator_close_door(elevator_posadd(roundedpos, {x=pos2.z, y=pos2.y-1, z=pos2.x}))
|
||||
|
||||
--if not puncher or not puncher:is_player() then return true end
|
||||
if self.driver then
|
||||
self.driver:set_detach()
|
||||
self.driver:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||
end
|
||||
|
||||
self.object:remove()
|
||||
|
||||
--local inv = puncher:get_inventory()
|
||||
--if minetest.setting_getbool("creative_mode") then
|
||||
-- if not inv:contains_item("main", "elevator:elev_motor") then
|
||||
-- inv:add_item("main", "elevator:elev_motor")
|
||||
-- end
|
||||
--else
|
||||
-- inv:add_item("main", "elevator:elev_motor")
|
||||
--end
|
||||
--return true
|
||||
end,
|
||||
|
||||
visual = "mesh",
|
||||
mesh = "elevator.x",
|
||||
textures = {
|
||||
"elevator_obj.png"
|
||||
},
|
||||
collide_with_objects = true
|
||||
})
|
||||
|
||||
minetest.after(0, function()
|
||||
minetest.registered_nodes.air.groups.not_blocking_elevators=1;
|
||||
minetest.registered_nodes["default:torch"].groups.not_blocking_elevators=1;
|
||||
end)
|
||||
|
||||
minetest.register_craft(
|
||||
{
|
||||
output = 'elevator:elev_rail 16',
|
||||
recipe = {
|
||||
{'', 'default:steel_ingot'},
|
||||
{'default:steel_ingot', 'default:steel_ingot'},
|
||||
{'', 'default:steel_ingot'}, -- Also groups; e.g. 'group:crumbly'
|
||||
},
|
||||
}
|
||||
)
|
||||
minetest.register_craft(
|
||||
{
|
||||
output = 'elevator:elev_motor',
|
||||
recipe = {
|
||||
{'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
|
||||
{'default:copper_ingot', 'default:gold_ingot', 'default:copper_ingot'},
|
||||
{'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'}, -- Also groups; e.g. 'group:crumbly'
|
||||
},
|
||||
}
|
||||
)
|
||||
minetest.register_craft(
|
||||
{
|
||||
output = 'elevator:elev_entry',
|
||||
recipe = {
|
||||
{'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
|
||||
{'default:steel_ingot', 'default:copper_ingot', 'default:steel_ingot'},
|
||||
{'default:steel_ingot', 'default:copper_ingot', 'default:steel_ingot'}, -- Also groups; e.g. 'group:crumbly'
|
||||
},
|
||||
}
|
||||
)
|
|
@ -0,0 +1,85 @@
|
|||
Elevator mod by orwell
|
||||
|
||||
This mod adds elevators (or lifts in american english) to minetest. Since a [lifts] mod already exists, I called the mod elevator.
|
||||
|
||||
Elevators consist of a shaft with special rails, a motor and some elevator "doors" (called entries, better suggestion for translation welcome). They can move up and down between doors, just like real elevators do, with one limitation:
|
||||
If it is obvious that the elevator has been or will become inactive during the ride to the player because it is leaving an active area (it is too far away from a player), the elevator will teleport itself to the target entry. It will never do this with a player riding it.
|
||||
|
||||
Constructing elevators:
|
||||
-----------------------
|
||||
1. dig a shaft of 3*3 nodes diameter. No nodes are allowed inside the shaft except elevator rails, entries, torches(from minetest_game) and air.
|
||||
2. place rails at the shaft walls, so that the shaft looks like:
|
||||
-----
|
||||
| |
|
||||
|- -| where - are elevator rails
|
||||
| |
|
||||
-----
|
||||
(rails behave like torches - they need a node behind them to back them up)
|
||||
3. place an elevator motor between the uppermost rail pair:
|
||||
-----
|
||||
| |
|
||||
|-M-| where - are elevator rails and M is a motor
|
||||
| |
|
||||
-----
|
||||
4. place elevator entries into the shaft in the following way:
|
||||
-----
|
||||
| |
|
||||
|- -| where - are elevator rails and E is an entry
|
||||
| E |
|
||||
-- -- <- there should be air, since this is the position the player is getting off to
|
||||
or
|
||||
-- --
|
||||
| E |
|
||||
|- -|
|
||||
| |
|
||||
-----
|
||||
(or even:
|
||||
-- --
|
||||
| E |
|
||||
|- -|
|
||||
| E |
|
||||
-- --)
|
||||
That entry has to be placed one layer below the actual entry layer, so that you can walk on it:
|
||||
| | = rails
|
||||
| ____ <-floor
|
||||
|E <-entry node
|
||||
The entries will ask for a name, this is the name of the button appearing inside the elevator.
|
||||
|
||||
The motor must be placed first. To destruct an elevator, dig the motor and the entries are digged and added to your inventory too (of course there has to be space :) ).
|
||||
|
||||
Using elevators
|
||||
---------------
|
||||
To call an elevator, right-click the elevator entry node.
|
||||
The elevator will either be called (if it is loaded and in range) or spawned (if it has been unloaded or was too far away)
|
||||
Then, right-click the elevator. You are attached to the elevator and a formspec will open. Select your target door. The elevator will drive to it and you will exit automatically.
|
||||
If the shaft is blocked in any way, the elevator will stop. Right-click it again and select an entry you can drive to, or dig the blocking node and select your initial target again.
|
||||
|
||||
Try it, it's simple and comfortable.
|
||||
There is no height limit. (you just need the rails...)
|
||||
Placing rails on the floor or the ceiling will work, but this looks ugly.
|
||||
|
||||
Differences to the old WIP version 1.0
|
||||
--------------------------------------
|
||||
- The mod does not depend on forceload-lib anymore.
|
||||
- Elevators teleport instead of forceloading the areas around them.
|
||||
- When constructing, you place the motor before placing entries!
|
||||
- Old elevators will probably not work anymore, re-construct the motor and the entries.
|
||||
- If minetest crashes when opening a world including an elevator from the old version, load the old mod, remove all elevators, all entries and all motors and then load the new mod again.
|
||||
|
||||
License:
|
||||
-------
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
-------
|
After Width: | Height: | Size: 255 B |
After Width: | Height: | Size: 505 B |
After Width: | Height: | Size: 642 B |
After Width: | Height: | Size: 402 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 479 B |
After Width: | Height: | Size: 522 B |
After Width: | Height: | Size: 379 B |
After Width: | Height: | Size: 248 B |
After Width: | Height: | Size: 463 B |