From 3f382974b85c99fdd9b985cba20b19dded42dd6b Mon Sep 17 00:00:00 2001 From: orwell96 Date: Thu, 9 Feb 2017 00:11:28 +0100 Subject: 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 --- advtrains.zip | Bin 5122262 -> 5122882 bytes advtrains/advtrains/api_doc.txt | 4 ++ advtrains/advtrains/damage.lua | 28 -------- advtrains/advtrains/init.lua | 5 +- advtrains/advtrains/trainlogic.lua | 81 ++++++++++++++++++++---- advtrains/advtrains/wagons.lua | 102 ++++++++++++++++++------------ advtrains/advtrains_train_japan/init.lua | 2 + advtrains/advtrains_train_subway/init.lua | 1 + 8 files changed, 139 insertions(+), 84 deletions(-) delete mode 100644 advtrains/advtrains/damage.lua diff --git a/advtrains.zip b/advtrains.zip index b668390..6652233 100644 Binary files a/advtrains.zip and b/advtrains.zip differ diff --git a/advtrains/advtrains/api_doc.txt b/advtrains/advtrains/api_doc.txt index 09b3cc1..db72dda 100644 --- a/advtrains/advtrains/api_doc.txt +++ b/advtrains/advtrains/api_doc.txt @@ -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. diff --git a/advtrains/advtrains/damage.lua b/advtrains/advtrains/damage.lua deleted file mode 100644 index e05d00d..0000000 --- a/advtrains/advtrains/damage.lua +++ /dev/null @@ -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) diff --git a/advtrains/advtrains/init.lua b/advtrains/advtrains/init.lua index c60b2f1..970bbb6 100644 --- a/advtrains/advtrains/init.lua +++ b/advtrains/advtrains/init.lua @@ -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, diff --git a/advtrains/advtrains/trainlogic.lua b/advtrains/advtrains/trainlogic.lua index 5fafb89..0b28129 100644 --- a/advtrains/advtrains/trainlogic.lua +++ b/advtrains/advtrains/trainlogic.lua @@ -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 diff --git a/advtrains/advtrains/wagons.lua b/advtrains/advtrains/wagons.lua index 3efa6b8..461dfb5 100644 --- a/advtrains/advtrains/wagons.lua +++ b/advtrains/advtrains/wagons.lua @@ -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, {}) diff --git a/advtrains/advtrains_train_japan/init.lua b/advtrains/advtrains_train_japan/init.lua index ffe169f..8816db3 100644 --- a/advtrains/advtrains_train_japan/init.lua +++ b/advtrains/advtrains_train_japan/init.lua @@ -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}, diff --git a/advtrains/advtrains_train_subway/init.lua b/advtrains/advtrains_train_subway/init.lua index faf8ceb..8864e92 100644 --- a/advtrains/advtrains_train_subway/init.lua +++ b/advtrains/advtrains_train_subway/init.lua @@ -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}, -- cgit v1.2.3