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

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