aboutsummaryrefslogtreecommitdiff
path: root/advtrains/wagons.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/wagons.lua')
-rw-r--r--advtrains/wagons.lua176
1 files changed, 140 insertions, 36 deletions
diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua
index 4093f06..62e65af 100644
--- a/advtrains/wagons.lua
+++ b/advtrains/wagons.lua
@@ -364,6 +364,15 @@ function wagon:on_step(dtime)
outside = outside .."\n!!! Train off track !!!"
end
+ -- liquid container: display liquid contents in infotext
+ if self.techage_liquid_capacity then
+ if data.techage_liquid and data.techage_liquid.name then
+ outside = outside .."\nLiquid: "..data.techage_liquid.name..", "..data.techage_liquid.amount.." units"
+ else
+ outside = outside .."\nLiquid: empty"
+ end
+ end
+
if self.infotext_cache~=outside then
self.object:set_properties({infotext=outside})
self.infotext_cache=outside
@@ -413,13 +422,38 @@ function wagon:on_step(dtime)
end
-- Calculate new position, yaw and direction vector
+ -- note: "index" is needed to be the center index, required by door code
local index = advtrains.path_get_index_by_offset(train, train.index, -data.pos_in_train)
- local pos, yaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
- local vdir = vector.normalize(vector.subtract(npos2, npos))
+ local pos, yaw, npos, npos2, vdir
+
+ -- use new position logic?
+ if self.wheel_positions then
+ -- request two positions, calculate difference and yaw from this
+ -- depending on flipstate, need to invert wheel pos indices -> wheelpos * fct
+ local index1 = advtrains.path_get_index_by_offset(train, index, self.wheel_positions[1] * fct)
+ local index2 = advtrains.path_get_index_by_offset(train, index, self.wheel_positions[2] * fct)
+ local pos1 = advtrains.path_get_interpolated(train, index1)
+ local pos2 = advtrains.path_get_interpolated(train, index2)
+ npos = advtrains.path_get(train, atfloor(index)) -- need npos just for node loaded check
+ -- calculate center of 2 positions and vdir vector
+ -- if wheel positions are asymmetric, needs to weight by the difference!
+ local fact = self.wheel_positions[1] / (self.wheel_positions[1]-self.wheel_positions[2])
+ pos = {x=pos1.x-(pos1.x-pos2.x)*fact, y=pos1.y-(pos1.y-pos2.y)*fact, z=pos1.z-(pos1.z-pos2.z)*fact}
+ if data.wagon_flipped then
+ vdir = vector.normalize(vector.subtract(pos2, pos1))
+ else
+ vdir = vector.normalize(vector.subtract(pos1, pos2))
+ end
+ yaw = math.atan2(-vdir.x, vdir.z)
+ else
+ --old position logic (for small wagons): use center index and just get position
+ pos, yaw, npos, npos2 = advtrains.path_get_interpolated(train, index)
+ vdir = vector.normalize(vector.subtract(npos2, npos))
+ end
--automatic get_on
--needs to know index and path
- if self.door_entry and train.door_open and train.door_open~=0 and train.velocity==0 then
+ if train.velocity==0 and self.door_entry and train.door_open and train.door_open~=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
@@ -470,28 +504,32 @@ function wagon:on_step(dtime)
end
end
- --DisCouple
+ -- Spawn discouple object when train stands, in all other cases remove it.
-- FIX: Need to do this after the yaw calculation
- if is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then
- if train.velocity==0 then
- if not self.discouple or not self.discouple.object:get_yaw() then
- atprint(self.id,"trying to spawn discouple")
- local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span, z=math.cos(yaw)*self.wagon_span})
- local object=minetest.add_entity(dcpl_pos, "advtrains:discouple")
- if object then
- local le=object:get_luaentity()
- le.wagon=self
- --box is hidden when attached, so unuseful.
- --object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
- self.discouple=le
- end
- end
- else
- if self.discouple and self.discouple.object:get_yaw() then
- self.discouple.object:remove()
- atprint(self.id," removing discouple")
+ if train.velocity==0 and is_in_loaded_area and data.pos_in_trainparts and data.pos_in_trainparts>1 then
+ if not self.discouple or not self.discouple.object:get_yaw() then
+ atprint(self.id,"trying to spawn discouple")
+ local dcpl_pos = vector.add(pos, {y=0, x=-math.sin(yaw)*self.wagon_span, z=math.cos(yaw)*self.wagon_span})
+ local object=minetest.add_entity(dcpl_pos, "advtrains:discouple")
+ if object then
+ local le=object:get_luaentity()
+ le.wagon=self
+ --box is hidden when attached, so unuseful.
+ --object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
+ self.discouple=le
end
end
+ else
+ if self.discouple and self.discouple.object:get_yaw() then
+ self.discouple.object:remove()
+ atprint(self.id," removing discouple")
+ end
+ end
+
+ -- object yaw (corrected by flipstate)
+ local oyaw = yaw
+ if data.wagon_flipped then
+ oyaw = yaw + math.pi
end
--FIX: use index of the wagon, not of the train.
@@ -500,10 +538,6 @@ function wagon:on_step(dtime)
local velocityvec = vector.multiply(vdir, velocity)
local accelerationvec = vector.multiply(vdir, acceleration)
- if data.wagon_flipped then
- yaw=yaw+math.pi
- end
-
-- this timer runs off every 2 seconds.
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
local updatepct_timer_elapsed = self.updatepct_timer<=0
@@ -540,19 +574,19 @@ function wagon:on_step(dtime)
or not vector.equals(velocityvec, self.old_velocity_vector)
or not self.old_acceleration_vector
or not vector.equals(accelerationvec, self.old_acceleration_vector)
- or self.old_yaw~=yaw
+ or self.old_yaw~=oyaw
or updatepct_timer_elapsed then--only send update packet if something changed
self.object:set_pos(pos)
self.object:set_velocity(velocityvec)
self.object:set_acceleration(accelerationvec)
- if #self.seats > 0 and self.old_yaw ~= yaw then
+ if #self.seats > 0 and self.old_yaw ~= oyaw then
if not self.player_yaw then
self.player_yaw = {}
end
if not self.old_yaw then
- self.old_yaw=yaw
+ self.old_yaw=oyaw
end
for _,name in pairs(data.seatp) do
local p = minetest.get_player_by_name(name)
@@ -562,11 +596,11 @@ function wagon:on_step(dtime)
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] or 0)+yaw)
+ p:set_look_horizontal((self.player_yaw[name] or 0)+oyaw)
end
end
self.turning = true
- elseif self.old_yaw == yaw then
+ elseif self.old_yaw == oyaw then
-- train is no longer turning
self.turning = false
end
@@ -576,9 +610,9 @@ function wagon:on_step(dtime)
if data.wagon_flipped then
pitch = -pitch
end
- self.object:set_rotation({x=pitch, y=yaw, z=0})
+ self.object:set_rotation({x=pitch, y=oyaw, z=0})
else
- self.object:set_yaw(yaw)
+ self.object:set_yaw(oyaw)
end
if self.update_animation then
@@ -597,7 +631,7 @@ function wagon:on_step(dtime)
self.old_velocity_vector=velocityvec
self.old_velocity = train.velocity
self.old_acceleration_vector=accelerationvec
- self.old_yaw=yaw
+ self.old_yaw=oyaw
atprintbm("wagon step", t)
end
@@ -1316,14 +1350,23 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
minetest.register_entity(":"..sysname,prototype)
advtrains.wagon_prototypes[sysname] = prototype
+ --group classification to make recipe searching easier
+ local wagon_groups = { not_in_creative_inventory = nincreative and 1 or 0}
+ if prototype.is_locomotive then wagon_groups['at_loco'] = 1 end
+ if prototype.seat_groups then
+ if prototype.seat_groups.dstand then wagon_groups['at_control'] = 1 end
+ if prototype.seat_groups.pass then wagon_groups['at_pax'] = 1 end
+ end
+ if prototype.has_inventory then wagon_groups['at_freight'] = 1 end
+
minetest.register_craftitem(":"..sysname, {
description = desc,
inventory_image = inv_img,
wield_image = inv_img,
stack_max = 1,
- groups = { not_in_creative_inventory = nincreative and 1 or 0},
-
+ groups = wagon_groups,
+
on_place = function(itemstack, placer, pointed_thing)
if not pointed_thing.type == "node" then
return
@@ -1384,3 +1427,64 @@ advtrains.register_wagon("advtrains:wagon_placeholder", {
drops={},
}, "Wagon placeholder", "advtrains_wagon_placeholder.png", true)
+
+
+-- Helper function to retrieve the wagon at a certain position in a train, given its train ID and the desired index within that train's path
+--
+-- Returns: wagon_num, wagon_id, wagon_data, offset_from_center
+-- wagon_num: The n'th wagon in the train (index into "trainparts" table)
+-- wagon_id: The wagon ID. Obtain wagon data from advtrains.wagons[wagon_id], and subsequently the wagon prototype via advtrains.get_wagon_prototype(data)
+-- offset_from_center: The offset (an absolute distance value) from the center point of the wagon. Positive is towards the end of the train, negative towards the start. (note that this is inverse to the counting direction of the index!)
+--
+--[[ To get the wagon standing at a certain world position, you first need to retrieve the index via the occupation table, as follows:
+ local trains = advtrains.occ.get_trains_at(pos)
+ for train_id, index in pairs(trains) do
+ local wagon_num, wagon_id, wagon_data, offset_from_center = advtrains.get_wagon_at_index(train_id, index)
+ if wagon_num then
+ ...
+ end
+ end
+]]--
+function advtrains.get_wagon_at_index(train_id, w_index)
+ local train = advtrains.trains[train_id]
+ if not train then error("Passed train id "..train_id.." doesnt exist") end
+ -- ensure init - always required
+ advtrains.train_ensure_init(train_id, train)
+ -- Use path dist to determine the offset from the start of the train
+ local dstart = advtrains.path_get_path_dist_fractional(train, train.index)
+ local dtarget = advtrains.path_get_path_dist_fractional(train, w_index)
+ local dist_from_start = dstart - dtarget -- NOTE: dist_from_start is supposed to be positive, but dtarget will be smaller than dstart
+ -- if dist_from_start is <0, we are outside of train
+ if dist_from_start < 0 then
+ return nil
+ end
+ -- scan over wagons to see if dist_from_start falls into its window
+ local start_pos = 0
+ local center_pos
+ local end_pos
+ local i = 1
+ while train.trainparts[i] do
+ local w_id = train.trainparts[i]
+ -- get wagon prototype to retrieve wagon span
+ local wdata = advtrains.wagons[w_id]
+ if wdata then
+ local wtype, wproto = advtrains.get_wagon_prototype(wdata)
+ local wagon_span = wproto.wagon_span
+ -- determine center and end pos
+ center_pos = start_pos + wagon_span
+ end_pos = center_pos + wagon_span
+ if start_pos <= dist_from_start and dist_from_start < end_pos then
+ -- Found the correct wagon in the train!
+ local offset_from_center = dist_from_start - center_pos
+ return i, w_id, wdata, offset_from_center
+ end
+ -- go on
+ start_pos = end_pos
+ else
+ error("Wagon "..w_id.." from train "..train_id.." doesnt exist!")
+ end
+ i = i + 1
+ end
+ -- nothing found, dist must be further back
+ return nil
+end \ No newline at end of file