From 73f6770eb3e0ec5be8da9e74fa0874fb6ba2d36d Mon Sep 17 00:00:00 2001 From: kovagoadi 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 --- 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