From 1e4bdcca84e956ece32d2d77dc8001bfd1d8e2f8 Mon Sep 17 00:00:00 2001 From: kovagoadi Date: Fri, 24 Jul 2026 22:32:29 +0200 Subject: [PATCH] Add GameScript API scheduled dispatch getters to ScriptOrder Expose read-only scheduled dispatch data to AI/GS scripts: per-vehicle schedule count and enabled flag, per-schedule duration, start tick, max delay and slot re-use, and per-slot offset and flags. Enables the AdminBridge GameScript's get_dispatch command and the Python client's OpenTTDAdminClient.get_dispatch(). Co-Authored-By: Claude Opus 4.8 --- src/script/api/script_order.cpp | 81 +++++++++++++++++++++++++++++++++ src/script/api/script_order.hpp | 75 ++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/src/script/api/script_order.cpp b/src/script/api/script_order.cpp index ee18f7d588..3db4639f14 100644 --- a/src/script/api/script_order.cpp +++ b/src/script/api/script_order.cpp @@ -822,3 +822,84 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance &instance) if (duration == INVALID_TICKS) return -1; return duration; } + +/** + * Resolve a scheduled dispatch schedule for a vehicle, or nullptr if the vehicle/schedule is invalid. + */ +static const DispatchSchedule *ResolveDispatchSchedule(VehicleID vehicle_id, SQInteger schedule_index) +{ + if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return nullptr; + const Vehicle *v = ::Vehicle::Get(vehicle_id); + if (v->orders == nullptr) return nullptr; + if (schedule_index < 0 || static_cast(schedule_index) >= v->orders->GetScheduledDispatchScheduleCount()) return nullptr; + return &v->orders->GetDispatchScheduleByIndex(static_cast(schedule_index)); +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchScheduleCount(VehicleID vehicle_id) +{ + if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return -1; + + const Vehicle *v = ::Vehicle::Get(vehicle_id); + if (v->orders == nullptr) return 0; + return v->orders->GetScheduledDispatchScheduleCount(); +} + +/* static */ SQInteger ScriptOrder::IsScheduledDispatchEnabled(VehicleID vehicle_id) +{ + if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return -1; + + return ::Vehicle::Get(vehicle_id)->vehicle_flags.Test(VehicleFlag::ScheduledDispatch) ? 1 : 0; +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchDuration(VehicleID vehicle_id, SQInteger schedule_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + return ds->GetScheduledDispatchDuration(); +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchStartTick(VehicleID vehicle_id, SQInteger schedule_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + return ds->GetScheduledDispatchStartTick().base(); +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchDelay(VehicleID vehicle_id, SQInteger schedule_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + return ds->GetScheduledDispatchDelay(); +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchReuseSlots(VehicleID vehicle_id, SQInteger schedule_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + return ds->GetScheduledDispatchReuseSlots() ? 1 : 0; +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchSlotCount(VehicleID vehicle_id, SQInteger schedule_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + return (SQInteger)ds->GetScheduledDispatch().size(); +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchSlotOffset(VehicleID vehicle_id, SQInteger schedule_index, SQInteger slot_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + const std::vector &slots = ds->GetScheduledDispatch(); + if (slot_index < 0 || static_cast(slot_index) >= slots.size()) return -1; + return slots[static_cast(slot_index)].offset; +} + +/* static */ SQInteger ScriptOrder::GetScheduledDispatchSlotFlags(VehicleID vehicle_id, SQInteger schedule_index, SQInteger slot_index) +{ + const DispatchSchedule *ds = ::ResolveDispatchSchedule(vehicle_id, schedule_index); + if (ds == nullptr) return -1; + const std::vector &slots = ds->GetScheduledDispatch(); + if (slot_index < 0 || static_cast(slot_index) >= slots.size()) return -1; + return slots[static_cast(slot_index)].flags; +} diff --git a/src/script/api/script_order.hpp b/src/script/api/script_order.hpp index 6c96b91b3a..d0a7e41fa7 100644 --- a/src/script/api/script_order.hpp +++ b/src/script/api/script_order.hpp @@ -720,6 +720,81 @@ public: * invalid, has no orders, or the timetable is not complete. */ static SQInteger GetTimetableTotalDuration(VehicleID vehicle_id); + + /** + * Gets the number of scheduled dispatch schedules of the given vehicle. + * @param vehicle_id The vehicle to query. + * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id). + * @return The number of dispatch schedules (0 when the vehicle has no order list), + * or -1 when the vehicle is invalid. + */ + static SQInteger GetScheduledDispatchScheduleCount(VehicleID vehicle_id); + + /** + * Gets whether scheduled dispatch is enabled for the given vehicle. + * @param vehicle_id The vehicle to query. + * @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id). + * @return 1 if enabled, 0 if disabled, or -1 when the vehicle is invalid. + */ + static SQInteger IsScheduledDispatchEnabled(VehicleID vehicle_id); + + /** + * Gets the duration in ticks of a dispatch schedule. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @return The schedule duration in ticks, or -1 when the vehicle or schedule is invalid. + */ + static SQInteger GetScheduledDispatchDuration(VehicleID vehicle_id, SQInteger schedule_index); + + /** + * Gets the start tick of a dispatch schedule. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @return The absolute start state tick, or -1 when the vehicle or schedule is invalid. + */ + static SQInteger GetScheduledDispatchStartTick(VehicleID vehicle_id, SQInteger schedule_index); + + /** + * Gets the maximum allowed delay of a dispatch schedule. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @return The maximum delay in ticks, or -1 when the vehicle or schedule is invalid. + */ + static SQInteger GetScheduledDispatchDelay(VehicleID vehicle_id, SQInteger schedule_index); + + /** + * Gets whether a dispatch schedule re-uses its dispatch slots. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @return 1 if slots are re-used, 0 if not, or -1 when the vehicle or schedule is invalid. + */ + static SQInteger GetScheduledDispatchReuseSlots(VehicleID vehicle_id, SQInteger schedule_index); + + /** + * Gets the number of departure slots in a dispatch schedule. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @return The number of slots, or -1 when the vehicle or schedule is invalid. + */ + static SQInteger GetScheduledDispatchSlotCount(VehicleID vehicle_id, SQInteger schedule_index); + + /** + * Gets the departure offset (in ticks, within the schedule duration) of a dispatch slot. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @param slot_index The slot index within the schedule. + * @return The slot offset, or -1 when the vehicle, schedule or slot is invalid. + */ + static SQInteger GetScheduledDispatchSlotOffset(VehicleID vehicle_id, SQInteger schedule_index, SQInteger slot_index); + + /** + * Gets the flag word of a dispatch slot. + * @param vehicle_id The vehicle to query. + * @param schedule_index The dispatch schedule index. + * @param slot_index The slot index within the schedule. + * @return The slot flags, or -1 when the vehicle, schedule or slot is invalid. + */ + static SQInteger GetScheduledDispatchSlotFlags(VehicleID vehicle_id, SQInteger schedule_index, SQInteger slot_index); }; DECLARE_ENUM_AS_BIT_SET(ScriptOrder::ScriptOrderFlags) -- 2.54.0