diff options
Diffstat (limited to 'advtrains/wagons.lua')
-rw-r--r-- | advtrains/wagons.lua | 254 |
1 files changed, 147 insertions, 107 deletions
diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua index e9b6d7a..f9b29bb 100644 --- a/advtrains/wagons.lua +++ b/advtrains/wagons.lua @@ -200,7 +200,7 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct end for listname, _ in pairs(inv:get_lists()) do if not inv:is_empty(listname) then - minetest.chat_send_player(puncher:get_player_name(), attrans("The wagon's inventory is not empty!")); + minetest.chat_send_player(puncher:get_player_name(), attrans("The wagon's inventory is not empty.")); return end end @@ -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 @@ -664,7 +698,7 @@ function wagon:on_rightclick(clicker) end local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak - local allow, rsn=false, "Wagon has no seats!" + local allow, rsn=false, attrans("This wagon has no seats.") for _,sgr in ipairs(self.assign_to_seat_group) do allow, rsn = self:check_seat_group_access(pname, sgr) if allow then @@ -675,16 +709,16 @@ function wagon:on_rightclick(clicker) self:get_on(clicker, seatid) return else - rsn="Wagon is full." + rsn=attrans("This wagon is full.") end else - rsn="Doors are closed! (try holding sneak key!)" + rsn=attrans("Doors are closed! (Try holding sneak key!)") end end end end end - minetest.chat_send_player(pname, attrans("Can't get on: "..rsn)) + minetest.chat_send_player(pname, rsn or attrans("You can't get on this wagon.")) else self:show_get_on_form(pname) end @@ -1213,7 +1247,7 @@ function wagon:seating_from_key_helper(pname, fields, no) self:show_bordcom(pname) end if fields.dcwarn then - minetest.chat_send_player(pname, attrans("Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!")) + minetest.chat_send_player(pname, attrans("Doors are closed. Use Sneak+rightclick to ignore the closed doors and get off.")) end if fields.off then self:get_off(no) @@ -1222,7 +1256,7 @@ end function wagon:check_seat_group_access(pname, sgr) local data = advtrains.wagons[self.id] if self.seat_groups[sgr].driving_ctrl_access and not (advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist)) then - return false, "Not allowed to access a driver stand!" + return false, attrans("You are not allowed to access the driver stand.") end if self.seat_groups[sgr].driving_ctrl_access then advtrains.log("Drive", pname, self.object:getpos(), self:train().text_outside) @@ -1240,70 +1274,6 @@ function wagon:reattach_all() end end -local function check_twagon_owner(train, b_first, pname) - local wtp = b_first and 1 or #train.trainparts - local wid = train.trainparts[wtp] - local wdata = advtrains.wagons[wid] - if wdata then - return advtrains.check_driving_couple_protection(pname, wdata.owner, wdata.whitelist) - end - return false -end - -function advtrains.safe_couple_trains(id1, id2, t1f, t2f, pname, try_run,v1,v2) - - if pname and not minetest.check_player_privs(pname, "train_operator") then - minetest.chat_send_player(pname, "Missing train_operator privilege") - return false - end - - local train1=advtrains.trains[id1] - local train2=advtrains.trains[id2] - - if not advtrains.train_ensure_init(id1, train1) - or not advtrains.train_ensure_init(id2, train2) then - return false - end - local wck_t1, wck_t2 - if pname then - wck_t1 = check_twagon_owner(train1, t1f, pname) - wck_t2 = check_twagon_owner(train2, t2f, pname) - end - if (wck_t1 or wck_t2) or not pname then - if not v1 then - v1 = 0 - end - if not v2 then - v2 = 0 - end - if try_run then - return true - end - if t1f then - if t2f then - v1 = -v1 - advtrains.invert_train(id1) - advtrains.do_connect_trains(id1, id2, v1+v2) - else - advtrains.do_connect_trains(id2, id1, v1+v2) - end - else - if t2f then - advtrains.do_connect_trains(id1, id2, v1+v2) - else - v2 = -v2 - advtrains.invert_train(id2) - advtrains.do_connect_trains(id1, id2, v1+v2) - end - end - return true - else - minetest.chat_send_player(pname, "You must be authorized for at least one wagon.") - return false - end -end - - function advtrains.safe_decouple_wagon(w_id, pname, try_run) if not minetest.check_player_privs(pname, "train_operator") then minetest.chat_send_player(pname, "Missing train_operator privilege") @@ -1380,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 @@ -1448,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 |