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:
orwell96 2017-02-09 00:11:28 +01:00
parent 4abb967f92
commit 3f382974b8
8 changed files with 139 additions and 84 deletions

Binary file not shown.

View File

@ -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.

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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, {})

View File

@ -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},

View File

@ -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},