Proper implementation for getting on by walking into train, rework damage and player controls in train, fix death and join bugs, do not spawn bones on death
This commit is contained in:
parent
4abb967f92
commit
3f382974b8
BIN
advtrains.zip
BIN
advtrains.zip
Binary file not shown.
|
@ -60,6 +60,10 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
|
|||
[1]={frames={x=60, y=80}, time=1} -- close right doors
|
||||
}
|
||||
},
|
||||
door_entry={ 1.5, -1.5 }
|
||||
^- optional. If defined, defines the locations of the doors on the model as distance from the object center on the path.
|
||||
^- Getting on by walking in then takes effect.
|
||||
^- Positive values mean front, negative ones back. Resulting position is automatically shifted to the right side.
|
||||
|
||||
wagon_span=2,
|
||||
^- How far this wagon extends from its base position. Is the half of the wagon length.
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
--damage.lua
|
||||
--a globalstep that damages players overrolled by trains.
|
||||
|
||||
advtrains.player_to_train_mapping={}
|
||||
|
||||
local tmr=0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
tmr=tmr-dtime
|
||||
if tmr<=0 then
|
||||
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local pos=player:getpos()
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
local le=object:get_luaentity()
|
||||
if le and le.is_wagon and le.initialized and le:train() then
|
||||
if (not advtrains.player_to_train_mapping[player:get_player_name()] or le.train_id~=advtrains.player_to_train_mapping[player:get_player_name()]) and math.abs(le:train().velocity)>2 then
|
||||
--player:punch(object, 1000, {damage={fleshy=3*math.abs(le:train().velocity)}})
|
||||
player:set_hp(player:get_hp()-math.abs(le:train().velocity)-3)
|
||||
elseif (not advtrains.player_to_train_mapping[player:get_player_name()] or le.train_id~=advtrains.player_to_train_mapping[player:get_player_name()]) and le:train().door_open~=0 then
|
||||
le:on_rightclick(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tmr=0.5
|
||||
end
|
||||
end)
|
|
@ -7,7 +7,7 @@ end
|
|||
|
||||
--advtrains
|
||||
|
||||
advtrains = {trains={}, wagon_save={}}
|
||||
advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}}
|
||||
|
||||
advtrains.modpath = minetest.get_modpath("advtrains")
|
||||
|
||||
|
@ -84,7 +84,6 @@ dofile(advtrains.modpath.."/wagons.lua")
|
|||
dofile(advtrains.modpath.."/trackdb_legacy.lua")
|
||||
dofile(advtrains.modpath.."/nodedb.lua")
|
||||
dofile(advtrains.modpath.."/couple.lua")
|
||||
dofile(advtrains.modpath.."/damage.lua")
|
||||
|
||||
dofile(advtrains.modpath.."/signals.lua")
|
||||
dofile(advtrains.modpath.."/misc_nodes.lua")
|
||||
|
@ -105,6 +104,7 @@ else
|
|||
--congrats, we have the new save format.
|
||||
advtrains.trains = tbl.trains
|
||||
advtrains.wagon_save = tbl.wagon_save
|
||||
advtrains.player_to_train_mapping = tbl.ptmap or {}
|
||||
advtrains.ndb.load_data(tbl.ndb)
|
||||
advtrains.atc.load_data(tbl.atc)
|
||||
else
|
||||
|
@ -174,6 +174,7 @@ advtrains.save = function()
|
|||
local save_tbl={
|
||||
trains = advtrains.trains,
|
||||
wagon_save = advtrains.wagon_save,
|
||||
ptmap = advtrains.player_to_train_mapping,
|
||||
atc = advtrains.atc.save_data(),
|
||||
ndb = advtrains.ndb.save_data(),
|
||||
version = 1,
|
||||
|
|
|
@ -36,10 +36,9 @@ advtrains.train_brake_force=3--per second, not divided by number of wagons
|
|||
advtrains.train_roll_force=0.5--per second, not divided by number of wagons, acceleration when rolling without brake
|
||||
advtrains.train_emerg_force=10--for emergency brakes(when going off track)
|
||||
|
||||
advtrains.audit_interval=10
|
||||
advtrains.save_interval=10
|
||||
advtrains.save_timer=advtrains.save_interval
|
||||
|
||||
|
||||
advtrains.save_and_audit_timer=advtrains.audit_interval
|
||||
minetest.register_globalstep(function(dtime_mt)
|
||||
--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains
|
||||
local dtime=dtime_mt
|
||||
|
@ -48,14 +47,23 @@ minetest.register_globalstep(function(dtime_mt)
|
|||
dtime=0.2
|
||||
end
|
||||
|
||||
advtrains.save_and_audit_timer=advtrains.save_and_audit_timer-dtime
|
||||
if advtrains.save_and_audit_timer<=0 then
|
||||
advtrains.save_timer=advtrains.save_timer-dtime
|
||||
if advtrains.save_timer<=0 then
|
||||
local t=os.clock()
|
||||
--save
|
||||
advtrains.save()
|
||||
advtrains.save_and_audit_timer=advtrains.audit_interval
|
||||
advtrains.save_timer=advtrains.save_interval
|
||||
atprintbm("saving", t)
|
||||
end
|
||||
--build a table of all players indexed by pts. used by damage and door system.
|
||||
advtrains.playersbypts={}
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
if not advtrains.player_to_train_mapping[player:get_player_name()] then
|
||||
--players in train are not subject to damage
|
||||
local ptspos=minetest.pos_to_string(vector.round(player:getpos()))
|
||||
advtrains.playersbypts[ptspos]=player
|
||||
end
|
||||
end
|
||||
--regular train step
|
||||
-- do in two steps:
|
||||
-- a: predict path and add all nodes to the advtrains.detector.on_node table
|
||||
|
@ -67,13 +75,48 @@ minetest.register_globalstep(function(dtime_mt)
|
|||
advtrains.train_step_a(k, v, dtime)
|
||||
end
|
||||
for k,v in pairs(advtrains.trains) do
|
||||
advtrains.train_step_b(k, v, dtime)
|
||||
advtrains.train_step_b(k, v, dtime, playersbypts)
|
||||
end
|
||||
|
||||
atprintbm("trainsteps", t)
|
||||
endstep()
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
--set the player to the train position.
|
||||
--minetest will emerge the area and load the objects, which then will call reattach_all().
|
||||
--because player is in mapping, it will not be subject to dying.
|
||||
player:setpos(train.last_pos_prev)
|
||||
--independent of this, cause all wagons of the train which are loaded to reattach their players
|
||||
--needed because already loaded wagons won't call reattach_all()
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
wagon:reattach_all()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
--when player dies, detach him from the train
|
||||
--call get_off_plr on every wagon since we don't know which one he's on.
|
||||
wagon:get_off_plr(pname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
--[[
|
||||
train step structure:
|
||||
|
||||
|
@ -440,14 +483,11 @@ end
|
|||
|
||||
function advtrains.train_step_b(id, train, dtime)
|
||||
|
||||
--- 8. check for collisions with other trains ---
|
||||
--- 8. check for collisions with other trains and damage players ---
|
||||
|
||||
local train_moves=(train.velocity~=0)
|
||||
|
||||
if train_moves then
|
||||
|
||||
--heh, new collision again.
|
||||
--this time, based on NODES and the advtrains.detector.on_node table.
|
||||
local collpos
|
||||
local coll_grace=1
|
||||
if train.movedir==1 then
|
||||
|
@ -460,6 +500,7 @@ function advtrains.train_step_b(id, train, dtime)
|
|||
for x=-1,1 do
|
||||
for z=-1,1 do
|
||||
local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
|
||||
--- 8a Check collision ---
|
||||
local testpts=minetest.pos_to_string(testpos)
|
||||
if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then
|
||||
--collides
|
||||
|
@ -470,11 +511,27 @@ function advtrains.train_step_b(id, train, dtime)
|
|||
train.movedir=train.movedir*-1
|
||||
train.tarvelocity=0
|
||||
end
|
||||
--- 8b damage players ---
|
||||
local player=advtrains.playersbypts[testpts]
|
||||
if player and train.velocity>3 then
|
||||
--instantly kill player
|
||||
--drop inventory contents first, to not to spawn bones
|
||||
local player_inv=player:get_inventory()
|
||||
for i=1,player_inv:get_size("main") do
|
||||
minetest.add_item(testpos, player_inv:get_stack("main", i))
|
||||
end
|
||||
for i=1,player_inv:get_size("craft") do
|
||||
minetest.add_item(testpos, player_inv:get_stack("craft", i))
|
||||
end
|
||||
-- empty lists main and craft
|
||||
player_inv:set_list("main", {})
|
||||
player_inv:set_list("craft", {})
|
||||
player:set_hp(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -223,12 +223,13 @@ function wagon:on_step(dtime)
|
|||
atprint("[wagon "..self.unique_id.."] missing train_id, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
elseif not self.initialized then
|
||||
self.initialized=true
|
||||
end
|
||||
if not self.seatp then
|
||||
self.seatp={}
|
||||
end
|
||||
|
||||
--Legacy: remove infotext since it does not work this way anyways
|
||||
self.infotext=nil
|
||||
|
||||
--custom on_step function
|
||||
if self.custom_on_step then
|
||||
|
@ -237,43 +238,38 @@ function wagon:on_step(dtime)
|
|||
|
||||
--driver control
|
||||
for seatno, seat in ipairs(self.seats) do
|
||||
if seat.driving_ctrl_access then
|
||||
local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
local get_off_pressed=false
|
||||
if driver and driver:get_player_control_bits()~=self.old_player_control_bits then
|
||||
local pc=driver:get_player_control()
|
||||
|
||||
local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
if seat.driving_ctrl_access and driver then
|
||||
advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
|
||||
end
|
||||
if driver and driver:get_player_control_bits()~=self.seatpc[seatno] then
|
||||
local pc=driver:get_player_control()
|
||||
self.seatpc[seatno]=driver:get_player_control_bits()
|
||||
|
||||
if seat.driving_ctrl_access then
|
||||
--regular driver stand controls
|
||||
advtrains.on_control_change(pc, self:train(), self.wagon_flipped)
|
||||
if pc.aux1 and pc.sneak then
|
||||
get_off_pressed=true
|
||||
end
|
||||
|
||||
self.old_player_control_bits=driver:get_player_control_bits()
|
||||
else
|
||||
-- If on a passenger seat and doors are open, get off when W or D pressed.
|
||||
local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
if pass and self:train().door_open~=0 then
|
||||
local pc=pass:get_player_control()
|
||||
if pc.up or pc.down then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
end
|
||||
end
|
||||
if driver then
|
||||
if get_off_pressed then
|
||||
self:get_off(seatno)
|
||||
else
|
||||
advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
|
||||
end
|
||||
if pc.aux1 and pc.sneak then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
else
|
||||
local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
if pass and self:train().door_open~=0 then
|
||||
local pc=pass:get_player_control()
|
||||
if pc.up or pc.down then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local gp=self:train()
|
||||
|
||||
local fct=self.wagon_flipped and -1 or 1
|
||||
--door animation
|
||||
if self.doors then
|
||||
if (self.door_anim_timer or 0)<=0 then
|
||||
local fct=self.wagon_flipped and -1 or 1
|
||||
local dstate = (gp.door_open or 0) * fct
|
||||
if dstate ~= self.door_state then
|
||||
local at
|
||||
|
@ -299,6 +295,7 @@ function wagon:on_step(dtime)
|
|||
self.door_anim_timer = (self.door_anim_timer or 0) - dtime
|
||||
end
|
||||
end
|
||||
|
||||
--DisCouple
|
||||
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
|
||||
if gp.velocity==0 and not self.lock_couples then
|
||||
|
@ -334,6 +331,31 @@ function wagon:on_step(dtime)
|
|||
local index=advtrains.get_real_path_index(self:train(), self.pos_in_train)
|
||||
--atprint("trainindex "..gp.index.." wagonindex "..index)
|
||||
|
||||
--automatic get_on
|
||||
--needs to know index and path
|
||||
if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==0 then
|
||||
--using the mapping created by the trainlogic globalstep
|
||||
for i, ino in ipairs(self.door_entry) do
|
||||
--fct is the flipstate flag from door animation above
|
||||
local aci = index + ino*fct
|
||||
local ix1=gp.path[math.floor(aci)]
|
||||
local ix2=gp.path[math.floor(aci+1)]
|
||||
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
||||
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
||||
local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
|
||||
local pts1=minetest.pos_to_string(vector.round(vector.add(ix1, add)))
|
||||
local pts2=minetest.pos_to_string(vector.round(vector.add(ix2, add)))
|
||||
|
||||
if advtrains.playersbypts[pts1] then
|
||||
self:on_rightclick(advtrains.playersbypts[pts1])
|
||||
end
|
||||
if advtrains.playersbypts[pts2] then
|
||||
self:on_rightclick(advtrains.playersbypts[pts2])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--position recalculation
|
||||
local first_pos=gp.path[math.floor(index)]
|
||||
local second_pos=gp.path[math.floor(index)+1]
|
||||
|
@ -490,6 +512,8 @@ function wagon:on_rightclick(clicker)
|
|||
self:get_off(no)
|
||||
end
|
||||
else
|
||||
--do not attach if already on a train
|
||||
if advtrains.player_to_train_mapping[pname] then return end
|
||||
if self.seat_groups then
|
||||
if #self.seats==0 then
|
||||
if self.has_inventory and self.get_inventory_formspec then
|
||||
|
@ -518,9 +542,9 @@ function wagon:on_rightclick(clicker)
|
|||
end
|
||||
|
||||
function wagon:get_on(clicker, seatno)
|
||||
if not self.seatp then
|
||||
self.seatp={}
|
||||
end
|
||||
if not self.seatp then self.seatp={}end
|
||||
if not self.seatpc then self.seatpc={}end--player controls in driver stands
|
||||
|
||||
if not self.seats[seatno] then return end
|
||||
local oldno=self:get_seatno(clicker:get_player_name())
|
||||
if oldno then
|
||||
|
@ -535,6 +559,7 @@ function wagon:get_on(clicker, seatno)
|
|||
end
|
||||
atprint("get_on: attaching",clicker:get_player_name())
|
||||
self.seatp[seatno] = clicker:get_player_name()
|
||||
self.seatpc[seatno] = clicker:get_player_control_bits()
|
||||
advtrains.player_to_train_mapping[clicker:get_player_name()]=self.train_id
|
||||
clicker:set_attach(self.object, "", self.seats[seatno].attach_offset, {x=0,y=0,z=0})
|
||||
clicker:set_eye_offset(self.seats[seatno].view_offset, self.seats[seatno].view_offset)
|
||||
|
@ -569,12 +594,14 @@ function wagon:get_off(seatno)
|
|||
--abuse helper function
|
||||
for _,r in ipairs({-1, 1}) do
|
||||
local p=vector.add({x=isx and r or 0, y=0, z=not isx and r or 0}, objpos)
|
||||
local offp=vector.add({x=isx and r*2 or 0, y=1, z=not isx and r*2 or 0}, objpos)
|
||||
if minetest.get_item_group(minetest.get_node(p).name, "platform")>0 then
|
||||
minetest.after(0.2, function() clicker:setpos({x=p.x, y=p.y+1, z=p.z}) end)
|
||||
minetest.after(0.2, function() clicker:setpos(offp) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.seatp[seatno]=nil
|
||||
self.seatpc[seatno]=nil
|
||||
end
|
||||
function wagon:show_get_on_form(pname)
|
||||
if not self.initialized then return end
|
||||
|
@ -660,7 +687,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
end
|
||||
uid=string.match(formname, "^advtrains_prop_(.+)$")
|
||||
if uid then
|
||||
atprint(fields)
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
|
||||
local pname=player:get_player_name()
|
||||
|
@ -731,13 +757,6 @@ function wagon:reattach_all()
|
|||
end
|
||||
end
|
||||
end
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized then
|
||||
wagon:reattach_all()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function advtrains.register_wagon(sysname, prototype, desc, inv_img)
|
||||
setmetatable(prototype, {__index=wagon})
|
||||
|
@ -772,7 +791,6 @@ function advtrains.register_wagon(sysname, prototype, desc, inv_img)
|
|||
local le=ob:get_luaentity()
|
||||
|
||||
le.owner=placer:get_player_name()
|
||||
le.infotext=desc..", owned by "..placer:get_player_name()
|
||||
|
||||
local wagon_uid=le:init_new_instance(id, {})
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ advtrains.register_wagon("engine_japan", {
|
|||
[1]={frames={x=60, y=80}, time=1}
|
||||
}
|
||||
},
|
||||
door_entry={-1},
|
||||
visual_size = {x=1, y=1},
|
||||
wagon_span=2.5,
|
||||
is_locomotive=true,
|
||||
|
@ -134,6 +135,7 @@ advtrains.register_wagon("wagon_japan", {
|
|||
[1]={frames={x=60, y=80}, time=1}
|
||||
}
|
||||
},
|
||||
door_entry={-1, 1},
|
||||
visual_size = {x=1, y=1},
|
||||
wagon_span=2.3,
|
||||
collisionbox = {-1.0,-0.5,-1.0, 1.0,2.5,1.0},
|
||||
|
|
|
@ -66,6 +66,7 @@ advtrains.register_wagon("subway_wagon", {
|
|||
[1]={frames={x=60, y=80}, time=1}
|
||||
}
|
||||
},
|
||||
door_entry={-1, 1},
|
||||
visual_size = {x=1, y=1},
|
||||
wagon_span=2,
|
||||
--collisionbox = {-1.0,-0.5,-1.8, 1.0,2.5,1.8},
|
||||
|
|
Loading…
Reference in New Issue