Added real timetable support
All checks were successful
Continuous Integration / lint-and-security (pull_request) Successful in 33s
Continuous Integration / tests-and-coverage (pull_request) Successful in 26s

This commit is contained in:
2026-07-23 20:59:28 +02:00
parent 954663e80c
commit 3b54a722d6
10 changed files with 561 additions and 21 deletions

View File

@@ -0,0 +1,257 @@
From 73f6770eb3e0ec5be8da9e74fa0874fb6ba2d36d Mon Sep 17 00:00:00 2001
From: kovagoadi <kovagoadi@gmail.com>
Date: Sun, 19 Jul 2026 00:33:23 +0200
Subject: [PATCH] Add GameScript API timetable getters to ScriptOrder
Expose read-only timetable data to AI/GS scripts: per-order wait/travel
times, timetabled/fixed flags, leave type and max speed, plus per-vehicle
lateness, timetable start tick, current order time and total duration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
src/script/api/script_order.cpp | 104 ++++++++++++++++++++++++++++
src/script/api/script_order.hpp | 116 ++++++++++++++++++++++++++++++++
2 files changed, 220 insertions(+)
diff --git a/src/script/api/script_order.cpp b/src/script/api/script_order.cpp
index 865df623f9..ee18f7d588 100644
--- a/src/script/api/script_order.cpp
+++ b/src/script/api/script_order.cpp
@@ -718,3 +718,107 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance &instance)
return ScriptMap::DistanceManhattan(origin_tile, dest_tile);
}
}
+
+/* static */ SQInteger ScriptOrder::GetTimetableWaitTime(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return -1;
+ return order->GetWaitTime();
+}
+
+/* static */ SQInteger ScriptOrder::GetTimetableTravelTime(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return -1;
+ return order->GetTravelTime();
+}
+
+/* static */ bool ScriptOrder::IsWaitTimetabled(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return false;
+ return order->IsWaitTimetabled();
+}
+
+/* static */ bool ScriptOrder::IsTravelTimetabled(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return false;
+ return order->IsTravelTimetabled();
+}
+
+/* static */ bool ScriptOrder::IsWaitFixed(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return false;
+ return order->IsWaitFixed();
+}
+
+/* static */ bool ScriptOrder::IsTravelFixed(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return false;
+ return order->IsTravelFixed();
+}
+
+/* static */ SQInteger ScriptOrder::GetLeaveType(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return -1;
+ return order->GetLeaveType();
+}
+
+/* static */ SQInteger ScriptOrder::GetTimetableMaxSpeed(VehicleID vehicle_id, OrderPosition order_position)
+{
+ if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
+
+ const Order *order = ::ResolveOrder(vehicle_id, order_position);
+ if (order == nullptr) return -1;
+ return order->GetMaxSpeed();
+}
+
+/* static */ SQInteger ScriptOrder::GetTimetableLateness(VehicleID vehicle_id)
+{
+ if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return 0;
+
+ return ::Vehicle::Get(vehicle_id)->lateness_counter;
+}
+
+/* static */ SQInteger ScriptOrder::GetTimetableStartTick(VehicleID vehicle_id)
+{
+ if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return -1;
+
+ return ::Vehicle::Get(vehicle_id)->timetable_start.base();
+}
+
+/* static */ SQInteger ScriptOrder::GetCurrentOrderTime(VehicleID vehicle_id)
+{
+ if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return -1;
+
+ return ::Vehicle::Get(vehicle_id)->current_order_time;
+}
+
+/* static */ SQInteger ScriptOrder::GetTimetableTotalDuration(VehicleID vehicle_id)
+{
+ if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return -1;
+
+ const Vehicle *v = ::Vehicle::Get(vehicle_id);
+ if (v->orders == nullptr) return -1;
+ Ticks duration = v->orders->GetTimetableTotalDuration();
+ if (duration == INVALID_TICKS) return -1;
+ return duration;
+}
diff --git a/src/script/api/script_order.hpp b/src/script/api/script_order.hpp
index 81dc06cd7d..6c96b91b3a 100644
--- a/src/script/api/script_order.hpp
+++ b/src/script/api/script_order.hpp
@@ -604,6 +604,122 @@ public:
* @see ScriptEngine::GetMaximumOrderDistance and ScriptVehicle::GetMaximumOrderDistance
*/
static SQInteger GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile);
+
+ /**
+ * Gets the timetabled wait time of the given order for the given vehicle.
+ * @param vehicle_id The vehicle to get the timetable wait time for.
+ * @param order_position The order to get the timetable wait time for.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return The wait time of the order in ticks, or -1 when the order is invalid.
+ * @note The raw stored wait time is returned even if the wait time is not
+ * timetabled; use IsWaitTimetabled to check whether it is explicitly set.
+ */
+ static SQInteger GetTimetableWaitTime(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Gets the timetabled travel time of the given order for the given vehicle.
+ * @param vehicle_id The vehicle to get the timetable travel time for.
+ * @param order_position The order to get the timetable travel time for.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return The travel time of the order in ticks, or -1 when the order is invalid.
+ * @note The raw stored travel time is returned even if the travel time is not
+ * timetabled; use IsTravelTimetabled to check whether it is explicitly set.
+ */
+ static SQInteger GetTimetableTravelTime(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Checks whether the wait time of the given order is timetabled (explicitly set).
+ * @param vehicle_id The vehicle to check the order for.
+ * @param order_position The order to check.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return True if and only if the wait time is timetabled.
+ */
+ static bool IsWaitTimetabled(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Checks whether the travel time of the given order is timetabled (explicitly set).
+ * @param vehicle_id The vehicle to check the order for.
+ * @param order_position The order to check.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return True if and only if the travel time is timetabled.
+ */
+ static bool IsTravelTimetabled(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Checks whether the wait time of the given order is fixed (locked against autofill).
+ * @param vehicle_id The vehicle to check the order for.
+ * @param order_position The order to check.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return True if and only if the wait time is fixed.
+ */
+ static bool IsWaitFixed(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Checks whether the travel time of the given order is fixed (locked against autofill).
+ * @param vehicle_id The vehicle to check the order for.
+ * @param order_position The order to check.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return True if and only if the travel time is fixed.
+ */
+ static bool IsTravelFixed(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Gets the leave type of the given order for the given vehicle.
+ * @param vehicle_id The vehicle to get the leave type for.
+ * @param order_position The order to get the leave type for.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return The leave type of the order (0 = leave when timetabled, 1 = leave as
+ * soon as possible, 2 = leave early if any cargo fully loaded, 3 = leave early
+ * if all cargo fully loaded), or -1 when the order is invalid.
+ */
+ static SQInteger GetLeaveType(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Gets the timetabled maximum speed of the given order for the given vehicle.
+ * @param vehicle_id The vehicle to get the timetable max speed for.
+ * @param order_position The order to get the timetable max speed for.
+ * @pre IsValidVehicleOrder(vehicle_id, order_position).
+ * @return The maximum speed of the order (65535 when no speed cap is set),
+ * or -1 when the order is invalid.
+ */
+ static SQInteger GetTimetableMaxSpeed(VehicleID vehicle_id, OrderPosition order_position);
+
+ /**
+ * Gets the timetable lateness of the given vehicle.
+ * @param vehicle_id The vehicle to get the lateness for.
+ * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
+ * @return How many ticks the vehicle is late; negative values mean the vehicle
+ * is running early. Returns 0 when the vehicle is invalid, which is
+ * indistinguishable from an on-time vehicle; check the vehicle validity first.
+ */
+ static SQInteger GetTimetableLateness(VehicleID vehicle_id);
+
+ /**
+ * Gets the state tick at which the timetable of the given vehicle starts.
+ * @param vehicle_id The vehicle to get the timetable start tick for.
+ * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
+ * @return The absolute state tick the timetable starts at (0 when the
+ * timetable has not been started), or -1 when the vehicle is invalid.
+ */
+ static SQInteger GetTimetableStartTick(VehicleID vehicle_id);
+
+ /**
+ * Gets the number of ticks the given vehicle has spent on its current order.
+ * @param vehicle_id The vehicle to get the current order time for.
+ * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
+ * @return The number of ticks spent on the current order, or -1 when the
+ * vehicle is invalid.
+ */
+ static SQInteger GetCurrentOrderTime(VehicleID vehicle_id);
+
+ /**
+ * Gets the total duration of the timetable of the given vehicle.
+ * @param vehicle_id The vehicle to get the timetable duration for.
+ * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
+ * @return The total timetable duration in ticks, or -1 when the vehicle is
+ * invalid, has no orders, or the timetable is not complete.
+ */
+ static SQInteger GetTimetableTotalDuration(VehicleID vehicle_id);
};
DECLARE_ENUM_AS_BIT_SET(ScriptOrder::ScriptOrderFlags)
--
2.54.0