aboutsummaryrefslogtreecommitdiff
path: root/advtrains
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains')
-rw-r--r--advtrains/helpers.lua15
-rw-r--r--advtrains/init.lua33
-rw-r--r--advtrains/trainhud.lua74
-rw-r--r--advtrains/trainlogic.lua200
-rw-r--r--advtrains/wagons.lua51
5 files changed, 238 insertions, 135 deletions
diff --git a/advtrains/helpers.lua b/advtrains/helpers.lua
index 3864d81..5f5521f 100644
--- a/advtrains/helpers.lua
+++ b/advtrains/helpers.lua
@@ -150,6 +150,13 @@ function advtrains.merge_tables(a, ...)
end
return new
end
+function advtrains.save_keys(tbl, keys)
+ local new={}
+ for _,key in ipairs(keys) do
+ new[key] = tbl[key]
+ end
+ return new
+end
function advtrains.yaw_from_3_positions(prev, curr, next)
local pts=minetest.pos_to_string
--atprint("p3 "..pts(prev)..pts(curr)..pts(next))
@@ -315,3 +322,11 @@ function advtrains.get_matching_conn(conn, nconns)
return connlku[nconns][conn]
end
+function advtrains.random_id()
+ local idst=""
+ for i=0,5 do
+ idst=idst..(math.random(0,9))
+ end
+ return idst
+end
+
diff --git a/advtrains/init.lua b/advtrains/init.lua
index e3a19e4..4834a45 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -184,6 +184,17 @@ function advtrains.avt_load()
advtrains.player_to_train_mapping = tbl.ptmap or {}
advtrains.ndb.load_data(tbl.ndb)
advtrains.atc.load_data(tbl.atc)
+ --remove wagon_save entries that are not part of a train
+ local todel=advtrains.merge_tables(advtrains.wagon_save)
+ for tid, train in pairs(advtrains.trains) do
+ for _, wid in ipairs(train.trainparts) do
+ todel[wid]=nil
+ end
+ end
+ for wid, _ in pairs(todel) do
+ atwarn("Removing unused wagon", wid, "from wagon_save table.")
+ advtrains.wagon_save[wid]=nil
+ end
else
--oh no, its the old one...
advtrains.trains=tbl
@@ -257,23 +268,15 @@ advtrains.avt_save = function(remove_players_from_wagons)
local tmp_trains={}
for id, train in pairs(advtrains.trains) do
--first, deep_copy the train
- local v=advtrains.merge_tables(train)
+ local v=advtrains.save_keys(train, {
+ "last_pos", "last_pos_prev", "movedir", "velocity", "tarvelocity",
+ "trainparts", "savedpos_off_track_index_offset", "recently_collided_with_env",
+ "atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open"
+ })
--then invalidate
- if v.index then
- v.restore_add_index=v.index-math.floor(v.index+1)
+ if train.index then
+ v.restore_add_index=train.index-math.floor(train.index+1)
end
- v.path=nil
- v.path_dist=nil
- v.index=nil
- v.end_index=nil
- v.min_index_on_track=nil
- v.max_index_on_track=nil
- v.path_extent_min=nil
- v.path_extent_max=nil
-
- v.detector_old_index=nil
- v.detector_old_end_index=nil
-
--then save it
tmp_trains[id]=v
end
diff --git a/advtrains/trainhud.lua b/advtrains/trainhud.lua
index 78c7624..9b7b9e8 100644
--- a/advtrains/trainhud.lua
+++ b/advtrains/trainhud.lua
@@ -1,9 +1,11 @@
--trainhud.lua: holds all the code for train controlling
advtrains.hud = {}
+advtrains.hhud = {}
minetest.register_on_leaveplayer(function(player)
advtrains.hud[player:get_player_name()] = nil
+advtrains.hhud[player:get_player_name()] = nil
end)
local mletter={[1]="F", [-1]="R", [0]="N"}
@@ -40,12 +42,23 @@ function advtrains.on_control_change(pc, train, flip)
end
--shift+use:see wagons.lua
else
+ local act=false
if pc.up then
- train.tarvelocity = math.min(train.tarvelocity + 1, maxspeed)
+ train.lever=4
+ act=true
+ end
+ if pc.jump then
+ train.lever = 1
+ act=true
end
if pc.down then
if train.velocity>0 then
- train.tarvelocity = math.max(train.tarvelocity - 1, 0)
+ if pc.jump then
+ train.lever = 0
+ else
+ train.lever = 2
+ end
+ act=true
else
train.movedir = -train.movedir
end
@@ -64,12 +77,7 @@ function advtrains.on_control_change(pc, train, flip)
train.door_open = train.movedir
end
end
- if train.brake_hold_state~=2 then
- train.brake = false
- end
- if pc.jump then
- train.brake = true
- end
+ train.active_control = act
if pc.aux1 then
--horn
end
@@ -109,6 +117,44 @@ function advtrains.set_trainhud(name, text)
hud.oldText=text
end
end
+function advtrains.set_help_hud(name, text)
+ local hud = advtrains.hhud[name]
+ local player=minetest.get_player_by_name(name)
+ if not player then
+ return
+ end
+ if not hud then
+ hud = {}
+ advtrains.hhud[name] = hud
+ hud.id = player:hud_add({
+ hud_elem_type = "text",
+ name = "ADVTRAINS_HELP",
+ number = 0xFFFFFF,
+ position = {x=1, y=0.3},
+ offset = {x=0, y=0},
+ text = text,
+ scale = {x=200, y=60},
+ alignment = {x=1, y=0},
+ })
+ hud.oldText=text
+ return
+ elseif hud.oldText ~= text then
+ player:hud_change(hud.id, "text", text)
+ hud.oldText=text
+ end
+end
+
+--train.lever:
+--Speed control lever in train, for new train control system.
+--[[
+Value Disp Control Meaning
+0 BB S+Space Emergency Brake
+1 B Space Normal Brake
+2 - S Roll
+3 o <none> Stay at speed
+4 + W Accelerate
+]]
+
function advtrains.hud_train_format(train, flip)
local fct=flip and -1 or 1
if not train then return "" end
@@ -118,9 +164,19 @@ function advtrains.hud_train_format(train, flip)
local tvel=advtrains.abs_ceil(train.tarvelocity)
local vel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.velocity))
local tvel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.tarvelocity))
+
+ local levers = "B - o +"
+ local tlev=train.lever
+ if train.velocity==0 and not train.active_control then tlev=1 end
+ if tlev == 0 then levers = ">BB< - o +" end
+ if tlev == 1 then levers = ">B< - o +" end
+ if tlev == 2 then levers = "B >-< o +" end
+ if tlev == 3 then levers = "B - >o< +" end
+ if tlev == 4 then levers = "B - o >+<" end
+
local topLine, firstLine, secondLine
- topLine=" ["..mletter[fct*train.movedir].."] "..doorstr[(train.door_open or 0) * train.movedir].." "..(train.brake and "="..( train.brake_hold_state==2 and "^" or "" ).."B=" or "")
+ topLine=" ["..mletter[fct*train.movedir].."] {"..levers.."} "..doorstr[(train.door_open or 0) * train.movedir]
firstLine=attrans("Speed:").." |"..string.rep("+", vel)..string.rep("_", max-vel).."> "..vel_kmh.." km/h"
secondLine=attrans("Target:").." |"..string.rep("+", tvel)..string.rep("_", max-tvel).."> "..tvel_kmh.." km/h"
diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua
index a72d246..5681817 100644
--- a/advtrains/trainlogic.lua
+++ b/advtrains/trainlogic.lua
@@ -31,11 +31,20 @@ function endstep()
end
end
-advtrains.train_accel_force=2--per second and divided by number of wagons
-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)
-
+--acceleration for lever modes (trainhud.lua), per wagon
+local t_accel_all={
+ [0] = -10,
+ [1] = -3,
+ [2] = -0.5,
+ [4] = 0,
+}
+--acceleration per engine
+local t_accel_eng={
+ [0] = 0,
+ [1] = 0,
+ [2] = 0,
+ [4] = 2,
+}
advtrains.mainloop_trainlogic=function(dtime)
--build a table of all players indexed by pts. used by damage and door system.
@@ -139,7 +148,7 @@ function advtrains.train_step_a(id, train, dtime)
if train.min_index_on_track then
assert(math.floor(train.min_index_on_track)==train.min_index_on_track)
end
- --- 1. LEGACY STUFF ---
+ --- 1. not exactly legacy. required now because of saving ---
if not train.drives_on or not train.max_speed then
advtrains.update_trainpart_properties(id)
end
@@ -226,15 +235,16 @@ function advtrains.train_step_a(id, train, dtime)
--- 3. handle velocity influences ---
local train_moves=(train.velocity~=0)
+ local tarvel_cap
if train.recently_collided_with_env then
- train.tarvelocity=0
+ tarvel_cap=0
if not train_moves then
- train.recently_collided_with_env=false--reset status when stopped
+ train.recently_collided_with_env=nil--reset status when stopped
end
end
if train.locomotives_in_train==0 then
- train.tarvelocity=0
+ tarvel_cap=0
end
--- 3a. this can be useful for debugs/warnings and is used for check_trainpartload ---
@@ -250,86 +260,95 @@ function advtrains.train_step_a(id, train, dtime)
local pprint
if front_off_track and back_off_track then--allow movement in both directions
- if train.tarvelocity>1 then
- train.tarvelocity=1
- atprint("Train",t_info,"is off track at both ends. Clipping velocity to 1")
- pprint=true
- end
+ tarvel_cap=1
elseif front_off_track then--allow movement only backward
- if train.movedir==1 and train.tarvelocity>0 then
- train.tarvelocity=0
- atprint("Train",t_info,"is off track. Trying to drive further out. Velocity clipped to 0")
- pprint=true
+ if train.movedir==1 then
+ tarvel_cap=0
end
- if train.movedir==-1 and train.tarvelocity>1 then
- train.tarvelocity=1
- atprint("Train",t_info,"is off track. Velocity clipped to 1")
- pprint=true
+ if train.movedir==-1 then
+ tarvel_cap=1
end
elseif back_off_track then--allow movement only forward
- if train.movedir==-1 and train.tarvelocity>0 then
- train.tarvelocity=0
- atprint("Train",t_info,"is off track. Trying to drive further out. Velocity clipped to 0")
- pprint=true
+ if train.movedir==1 then
+ tarvel_cap=1
end
- if train.movedir==1 and train.tarvelocity>1 then
- train.tarvelocity=1
- atprint("Train",t_info,"is off track. Velocity clipped to 1")
- pprint=true
+ if train.movedir==-1 then
+ tarvel_cap=0
end
end
- if pprint then
- atprint("max_iot", train.max_index_on_track, "min_iot", train.min_index_on_track, "<> index", train.index, "end_index", train.end_index)
- end
- --interpret ATC command
- if train.atc_brake_target and train.atc_brake_target>=train.velocity then
- train.atc_brake_target=nil
- end
- if train.atc_wait_finish then
- if not train.atc_brake_target and train.velocity==train.tarvelocity then
- train.atc_wait_finish=nil
+ --interpret ATC command and apply auto-lever control when not actively controlled
+ local trainvelocity = train.velocity
+ if not train.lever then train.lever=3 end
+ if train.active_control then
+ advtrains.atc.train_reset_command(id)
+ else
+ if train.atc_brake_target and train.atc_brake_target>=trainvelocity then
+ train.atc_brake_target=nil
end
- end
- if train.atc_command then
- if train.atc_delay<=0 and not train.atc_wait_finish then
- advtrains.atc.execute_atc_command(id, train)
- else
- train.atc_delay=train.atc_delay-dtime
+ if train.atc_wait_finish then
+ if not train.atc_brake_target and train.velocity==train.tarvelocity then
+ train.atc_wait_finish=nil
+ end
+ end
+ if train.atc_command then
+ if train.atc_delay<=0 and not train.atc_wait_finish then
+ advtrains.atc.execute_atc_command(id, train)
+ else
+ train.atc_delay=train.atc_delay-dtime
+ end
+ end
+
+ train.lever = 3
+ if train.tarvelocity>trainvelocity then train.lever=4 end
+ if train.tarvelocity<trainvelocity then
+ if (train.atc_brake_target and train.atc_brake_target<trainvelocity) then
+ train.lever=1
+ else
+ train.lever=2
+ end
end
end
- --make brake adjust the tarvelocity if necessary
- if train.brake and (math.ceil(train.velocity)-1)<train.tarvelocity then
- train.tarvelocity=math.max((math.ceil(train.velocity)-1), 0)
+ if tarvel_cap and tarvel_cap<train.tarvelocity then
+ train.tarvelocity=tarvel_cap
+ end
+ local tmp_lever = train.lever
+ if tarvel_cap and trainvelocity>tarvel_cap then
+ tmp_lever = 0
end
--- 3a. actually calculate new velocity ---
- if train.velocity~=train.tarvelocity then
- local applydiff=0
- local mass=#train.trainparts
- local diff=train.tarvelocity-train.velocity
- if diff>0 then--accelerating, force will be brought on only by locomotives.
- --atprint("accelerating with default force")
- applydiff=(math.min((advtrains.train_accel_force*train.locomotives_in_train*dtime)/mass, math.abs(diff)))
- else--decelerating
- if front_off_track or back_off_track or train.recently_collided_with_env then --every wagon has a brake, so not divided by mass.
- --atprint("braking with emergency force")
- applydiff= -(math.min((advtrains.train_emerg_force*dtime), math.abs(diff)))
- elseif train.brake or (train.atc_brake_target and train.atc_brake_target<train.velocity) then
- --atprint("braking with default force")
- --no math.min, because it can grow beyond tarvelocity, see up there
- --dont worry, it will never fall below zero.
- applydiff= -((advtrains.train_brake_force*dtime))
- else
- --atprint("roll")
- applydiff= -(math.min((advtrains.train_roll_force*dtime), math.abs(diff)))
+ if tmp_lever~=3 then
+ local acc_all = t_accel_all[tmp_lever]
+ local acc_eng = t_accel_eng[tmp_lever]
+ local nwagons = #train.trainparts
+ local accel = acc_all + (acc_eng*train.locomotives_in_train)/nwagons
+ local vdiff = accel*dtime
+ if not train.active_control then
+ local tvdiff = train.tarvelocity - trainvelocity
+ if math.abs(vdiff) > math.abs(tvdiff) then
+ --applying this change would cross tarvelocity
+ vdiff=tvdiff
end
end
- train.last_accel=(applydiff*train.movedir)
- train.velocity=math.min(math.max( train.velocity+applydiff , 0), train.max_speed or 10)
+ if tarvel_cap and trainvelocity<=tarvel_cap and trainvelocity+vdiff>tarvel_cap then
+ vdiff = tarvel_cap - train.velocity
+ end
+ if trainvelocity+vdiff < 0 then
+ vdiff = - trainvelocity
+ end
+ local mspeed = (train.max_speed or 10)
+ if trainvelocity+vdiff > mspeed then
+ vdiff = mspeed - trainvelocity
+ end
+ train.last_accel=(vdiff*train.movedir)
+ train.velocity=train.velocity+vdiff
+ if train.active_control then
+ train.tarvelocity = train.velocity
+ end
else
- train.last_accel=0
+ train.last_accel = 0
end
--- 4. move train ---
@@ -558,8 +577,8 @@ end
--returns new id
function advtrains.create_new_train_at(pos, pos_prev)
- local newtrain_id=os.time()..os.clock()
- while advtrains.trains[newtrain_id] do newtrain_id=os.time()..os.clock() end--ensure uniqueness(will be unneccessary)
+ local newtrain_id=advtrains.random_id()
+ while advtrains.trains[newtrain_id] do newtrain_id=advtrains.random_id() end--ensure uniqueness
advtrains.trains[newtrain_id]={}
advtrains.trains[newtrain_id].last_pos=pos
@@ -903,24 +922,29 @@ function advtrains.invalidate_all_paths(pos)
end
end
if exec then
- --TODO duplicate code in init.lua avt_save()!
- if v.index then
- v.restore_add_index=v.index-math.floor(v.index+1)
- end
- v.path=nil
- v.path_dist=nil
- v.index=nil
- v.end_index=nil
- v.min_index_on_track=nil
- v.max_index_on_track=nil
- v.path_extent_min=nil
- v.path_extent_max=nil
-
- v.detector_old_index=nil
- v.detector_old_end_index=nil
+ advtrains.invalidate_path(k)
end
end
end
+function advtrains.invalidate_path(id)
+ local v=advtrains.trains[id]
+ if not v then return end
+ --TODO duplicate code in init.lua avt_save()!
+ if v.index then
+ v.restore_add_index=v.index-math.floor(v.index+1)
+ end
+ v.path=nil
+ v.path_dist=nil
+ v.index=nil
+ v.end_index=nil
+ v.min_index_on_track=nil
+ v.max_index_on_track=nil
+ v.path_extent_min=nil
+ v.path_extent_max=nil
+
+ v.detector_old_index=nil
+ v.detector_old_end_index=nil
+end
--not blocking trains group
function advtrains.train_collides(node)
diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua
index b75ca50..0616f9f 100644
--- a/advtrains/wagons.lua
+++ b/advtrains/wagons.lua
@@ -59,16 +59,18 @@ function wagon:get_staticdata()
self.ser_inv=advtrains.serialize_inventory(inv)
end
--save to table before being unloaded
- advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self)
+ advtrains.wagon_save[self.unique_id]=advtrains.save_keys(self, {
+ "seatp", "owner", "ser_inv", "wagon_flipped", "train_id"
+ })
advtrains.wagon_save[self.unique_id].entity_name=self.name
- advtrains.wagon_save[self.unique_id].name=nil
- advtrains.wagon_save[self.unique_id].object=nil
return self.unique_id
end)
end
--returns: uid of wagon
function wagon:init_new_instance(train_id, properties)
- self.unique_id=os.time()..os.clock()
+ local new_id=advtrains.random_id()
+ while advtrains.wagon_save[new_id] do new_id=advtrains.random_id() end--ensure uniqueness
+ self.unique_id=new_id
self.train_id=train_id
for k,v in pairs(properties) do
if k~="name" and k~="object" then
@@ -361,7 +363,7 @@ function wagon:on_step(dtime)
--DisCouple
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
- if gp.velocity==0 and not self.lock_couples then
+ if gp.velocity==0 then
if not self.discouple or not self.discouple.object:getyaw() then
local object=minetest.add_entity(pos, "advtrains:discouple")
if object then
@@ -501,24 +503,27 @@ function wagon:on_step(dtime)
self.object:setacceleration(accelerationvec)
if #self.seats > 0 and self.old_yaw ~= yaw then
- if not self.player_yaw then
- self.player_yaw = {}
- end
- for _,name in pairs(self.seatp) do
- local p = minetest.get_player_by_name(name)
- if p then
- if not self.turning then
- -- save player looking direction offset
- self.player_yaw[name] = p:get_look_horizontal()-self.old_yaw
- end
- -- set player looking direction using calculated offset
- p:set_look_horizontal(self.player_yaw[name]+yaw)
- end
- end
- self.turning = true
+ if not self.player_yaw then
+ self.player_yaw = {}
+ end
+ if not self.old_yaw then
+ self.old_yaw=yaw
+ end
+ for _,name in pairs(self.seatp) do
+ local p = minetest.get_player_by_name(name)
+ if p then
+ if not self.turning then
+ -- save player looking direction offset
+ self.player_yaw[name] = p:get_look_horizontal()-self.old_yaw
+ end
+ -- set player looking direction using calculated offset
+ p:set_look_horizontal(self.player_yaw[name]+yaw)
+ end
+ end
+ self.turning = true
elseif self.old_yaw == yaw then
- -- train is no longer turning
- self.turning = false
+ -- train is no longer turning
+ self.turning = false
end
self.object:setyaw(yaw)
@@ -527,7 +532,7 @@ function wagon:on_step(dtime)
self:update_animation(gp.velocity, self.old_velocity)
end
if self.custom_on_velocity_change then
- self:custom_on_velocity_change(gp.velocity, self.old_velocity or 0)
+ self:custom_on_velocity_change(gp.velocity, self.old_velocity or 0, dtime)
end
end