summaryrefslogtreecommitdiff
path: root/order_cmd.c
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2007-01-02 19:19:48 +0000
committerrubidium <rubidium@openttd.org>2007-01-02 19:19:48 +0000
commit66bbf336c6af7353ef0aeed58002c46543b30635 (patch)
treead4a63860df2626b22f77e7dac712e958bea54cb /order_cmd.c
parentccc0a3f4dbf58c005b22341ac8874252924690cd (diff)
downloadopenttd-66bbf336c6af7353ef0aeed58002c46543b30635.tar.xz
(svn r7759) -Merge: makefile rewrite. This merge features:
- A proper ./configure, so everything needs to be configured only once, not for every make. - Usage of makedepend when available. This greatly reduces the time needed for generating the dependencies. - A generator for all project files. There is a single file with sources, which is used to generate Makefiles and the project files for MSVC. - Proper support for OSX universal binaries. - Object files for non-MSVC compiles are also placed in separate directories, making is faster to switch between debug and release compiles and it does not touch the directory with the source files. - Functionality to make a bundle of all needed files for for example a nightly or distribution of a binary with all needed GRFs and language files. Note: as this merge moves almost all files, it is recommended to make a backup of your working copy before updating your working copy.
Diffstat (limited to 'order_cmd.c')
-rw-r--r--order_cmd.c1278
1 files changed, 0 insertions, 1278 deletions
diff --git a/order_cmd.c b/order_cmd.c
deleted file mode 100644
index b510e84ea..000000000
--- a/order_cmd.c
+++ /dev/null
@@ -1,1278 +0,0 @@
-/* $Id$ */
-
-#include "stdafx.h"
-#include "openttd.h"
-#include "order.h"
-#include "airport.h"
-#include "depot.h"
-#include "functions.h"
-#include "table/strings.h"
-#include "vehicle.h"
-#include "waypoint.h"
-#include "command.h"
-#include "station.h"
-#include "player.h"
-#include "news.h"
-#include "saveload.h"
-#include "vehicle_gui.h"
-
-/**
- * Called if a new block is added to the order-pool
- */
-static void OrderPoolNewBlock(uint start_item)
-{
- Order *order;
-
- /* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
- * TODO - This is just a temporary stage, this will be removed. */
- for (order = GetOrder(start_item); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) order->index = start_item++;
-}
-
-DEFINE_OLD_POOL(Order, Order, OrderPoolNewBlock, NULL)
-
-/**
- *
- * Unpacks a order from savegames made with TTD(Patch)
- *
- */
-Order UnpackOldOrder(uint16 packed)
-{
- Order order;
- order.type = GB(packed, 0, 4);
- order.flags = GB(packed, 4, 4);
- order.dest = GB(packed, 8, 8);
- order.next = NULL;
-
- order.refit_cargo = CT_NO_REFIT;
- order.refit_subtype = 0;
- order.index = 0; // avoid compiler warning
-
- // Sanity check
- // TTD stores invalid orders as OT_NOTHING with non-zero flags/station
- if (order.type == OT_NOTHING && (order.flags != 0 || order.dest != 0)) {
- order.type = OT_DUMMY;
- order.flags = 0;
- }
-
- return order;
-}
-
-/**
- *
- * Unpacks a order from savegames with version 4 and lower
- *
- */
-static Order UnpackVersion4Order(uint16 packed)
-{
- Order order;
- order.type = GB(packed, 0, 4);
- order.flags = GB(packed, 4, 4);
- order.dest = GB(packed, 8, 8);
- order.next = NULL;
- order.index = 0; // avoid compiler warning
- order.refit_cargo = CT_NO_REFIT;
- order.refit_subtype = 0;
- return order;
-}
-
-/**
- *
- * Updates the widgets of a vehicle which contains the order-data
- *
- */
-void InvalidateVehicleOrder(const Vehicle *v)
-{
- InvalidateWindow(WC_VEHICLE_VIEW, v->index);
- InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
-}
-
-/**
- *
- * Swap two orders
- *
- */
-static void SwapOrders(Order *order1, Order *order2)
-{
- Order temp_order;
-
- temp_order = *order1;
- AssignOrder(order1, *order2);
- order1->next = order2->next;
- AssignOrder(order2, temp_order);
- order2->next = temp_order.next;
-}
-
-/**
- *
- * Allocate a new order
- *
- * @return Order* if a free space is found, else NULL.
- *
- */
-static Order *AllocateOrder(void)
-{
- Order *order;
-
- /* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
- * TODO - This is just a temporary stage, this will be removed. */
- for (order = GetOrder(0); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) {
- if (!IsValidOrder(order)) {
- OrderID index = order->index;
-
- memset(order, 0, sizeof(*order));
- order->index = index;
- order->next = NULL;
- order->refit_cargo = CT_NO_REFIT;
- order->refit_subtype = 0;
-
- return order;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_Order_pool)) return AllocateOrder();
-
- return NULL;
-}
-
-/**
- *
- * Assign data to an order (from an other order)
- * This function makes sure that the index is maintained correctly
- *
- */
-void AssignOrder(Order *order, Order data)
-{
- order->type = data.type;
- order->flags = data.flags;
- order->dest = data.dest;
-
- order->refit_cargo = data.refit_cargo;
- order->refit_subtype = data.refit_subtype;
-}
-
-
-/**
- * Delete all news items regarding defective orders about a vehicle
- * This could kill still valid warnings (for example about void order when just
- * another order gets added), but assume the player will notice the problems,
- * when (s)he's changing the orders.
- */
-static void DeleteOrderWarnings(const Vehicle* v)
-{
- DeleteVehicleNews(v->index, STR_TRAIN_HAS_TOO_FEW_ORDERS + (v->type - VEH_Train) * 4);
- DeleteVehicleNews(v->index, STR_TRAIN_HAS_VOID_ORDER + (v->type - VEH_Train) * 4);
- DeleteVehicleNews(v->index, STR_TRAIN_HAS_DUPLICATE_ENTRY + (v->type - VEH_Train) * 4);
- DeleteVehicleNews(v->index, STR_TRAIN_HAS_INVALID_ENTRY + (v->type - VEH_Train) * 4);
-}
-
-
-/** Add an order to the orderlist of a vehicle.
- * @param tile unused
- * @param p1 various bitstuffed elements
- * - p1 = (bit 0 - 15) - ID of the vehicle
- * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
- * the order will be inserted before that one
- * only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 packed order to insert
- */
-int32 CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *v;
- VehicleID veh = GB(p1, 0, 16);
- VehicleOrderID sel_ord = GB(p1, 16, 16);
- Order new_order = UnpackOrder(p2);
-
- if (!IsValidVehicleID(veh)) return CMD_ERROR;
-
- v = GetVehicle(veh);
-
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
- /* Check if the inserted order is to the correct destination (owner, type),
- * and has the correct flags if any */
- switch (new_order.type) {
- case OT_GOTO_STATION: {
- const Station *st;
-
- if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
- st = GetStation(new_order.dest);
-
- if (st->airport_type != AT_OILRIG && !IsBuoy(st) && !CheckOwnership(st->owner)) {
- return CMD_ERROR;
- }
-
- switch (v->type) {
- case VEH_Train:
- if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
- break;
-
- case VEH_Road:
- if (v->cargo_type == CT_PASSENGERS) {
- if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
- } else {
- if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
- }
- break;
-
- case VEH_Ship:
- if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
- break;
-
- case VEH_Aircraft:
- if (!(st->facilities & FACIL_AIRPORT)) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
-
- /* Order flags can be any of the following for stations:
- * [full-load | unload] [+ transfer] [+ non-stop]
- * non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case 0:
- case OF_FULL_LOAD:
- case OF_FULL_LOAD | OF_TRANSFER:
- case OF_UNLOAD:
- case OF_UNLOAD | OF_TRANSFER:
- case OF_TRANSFER:
- break;
-
- case OF_NON_STOP:
- case OF_NON_STOP | OF_FULL_LOAD:
- case OF_NON_STOP | OF_FULL_LOAD | OF_TRANSFER:
- case OF_NON_STOP | OF_UNLOAD:
- case OF_NON_STOP | OF_UNLOAD | OF_TRANSFER:
- case OF_NON_STOP | OF_TRANSFER:
- if (v->type != VEH_Train) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
- break;
- }
-
- case OT_GOTO_DEPOT: {
- if (v->type == VEH_Aircraft) {
- const Station* st;
-
- if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
- st = GetStation(new_order.dest);
-
- if ((st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
- !(st->facilities & FACIL_AIRPORT) ||
- GetAirport(st->airport_type)->nof_depots == 0) {
- return CMD_ERROR;
- }
- } else {
- const Depot* dp;
-
- if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
- dp = GetDepot(new_order.dest);
-
- if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
-
- switch (v->type) {
- case VEH_Train:
- if (!IsTileDepotType(dp->xy, TRANSPORT_RAIL)) return CMD_ERROR;
- break;
-
- case VEH_Road:
- if (!IsTileDepotType(dp->xy, TRANSPORT_ROAD)) return CMD_ERROR;
- break;
-
- case VEH_Ship:
- if (!IsTileDepotType(dp->xy, TRANSPORT_WATER)) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
- }
-
- /* Order flags can be any of the following for depots:
- * order [+ halt] [+ non-stop]
- * non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case OF_PART_OF_ORDERS:
- case OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
- break;
-
- case OF_NON_STOP | OF_PART_OF_ORDERS:
- case OF_NON_STOP | OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
- if (v->type != VEH_Train) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
- break;
- }
-
- case OT_GOTO_WAYPOINT: {
- const Waypoint* wp;
-
- if (v->type != VEH_Train) return CMD_ERROR;
-
- if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
- wp = GetWaypoint(new_order.dest);
-
- if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
-
- /* Order flags can be any of the following for waypoints:
- * [non-stop]
- * non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case 0: break;
-
- case OF_NON_STOP:
- if (v->type != VEH_Train) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
- break;
- }
-
- default: return CMD_ERROR;
- }
-
- if (sel_ord > v->num_orders) return CMD_ERROR;
-
- if (IsOrderPoolFull()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
-
- /* XXX - This limit is only here because the backuppedorders can't
- * handle any more then this.. */
- if (v->num_orders >= MAX_BACKUP_ORDER_COUNT) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
-
- /* For ships, make sure that the station is not too far away from the
- * previous destination, for human players with new pathfinding disabled */
- if (v->type == VEH_Ship && IsHumanPlayer(v->owner) &&
- sel_ord != 0 && GetVehicleOrder(v, sel_ord - 1)->type == OT_GOTO_STATION
- && !_patches.new_pathfinding_all) {
-
- int dist = DistanceManhattan(
- GetStation(GetVehicleOrder(v, sel_ord - 1)->dest)->xy,
- GetStation(new_order.dest)->xy // XXX type != OT_GOTO_STATION?
- );
- if (dist >= 130)
- return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
- }
-
- if (flags & DC_EXEC) {
- Vehicle *u;
- Order *new = AllocateOrder();
- AssignOrder(new, new_order);
-
- /* Create new order and link in list */
- if (v->orders == NULL) {
- v->orders = new;
- } else {
- /* Try to get the previous item (we are inserting above the
- selected) */
- Order *order = GetVehicleOrder(v, sel_ord - 1);
-
- if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) {
- /* There is no previous item, so we are altering v->orders itself
- But because the orders can be shared, we copy the info over
- the v->orders, so we don't have to change the pointers of
- all vehicles */
- SwapOrders(v->orders, new);
- /* Now update the next pointers */
- v->orders->next = new;
- } else if (order == NULL) {
- /* 'sel' is a non-existing order, add him to the end */
- order = GetLastVehicleOrder(v);
- order->next = new;
- } else {
- /* Put the new order in between */
- new->next = order->next;
- order->next = new;
- }
- }
-
- u = GetFirstVehicleFromSharedList(v);
- DeleteOrderWarnings(u);
- for (; u != NULL; u = u->next_shared) {
- /* Increase amount of orders */
- u->num_orders++;
-
- /* If the orderlist was empty, assign it */
- if (u->orders == NULL) u->orders = v->orders;
-
- assert(v->orders == u->orders);
-
- /* If there is added an order before the current one, we need
- to update the selected order */
- if (sel_ord <= u->cur_order_index) {
- uint cur = u->cur_order_index + 1;
- /* Check if we don't go out of bound */
- if (cur < u->num_orders)
- u->cur_order_index = cur;
- }
- /* Update any possible open window of the vehicle */
- InvalidateVehicleOrder(u);
- }
-
- /* Make sure to rebuild the whole list */
- RebuildVehicleLists();
- }
-
- return 0;
-}
-
-/** Declone an order-list
- * @param *dst delete the orders of this vehicle
- * @param flags execution flags
- */
-static int32 DecloneOrder(Vehicle *dst, uint32 flags)
-{
- if (flags & DC_EXEC) {
- DeleteVehicleOrders(dst);
- InvalidateVehicleOrder(dst);
- RebuildVehicleLists();
- }
- return 0;
-}
-
-/** Delete an order from the orderlist of a vehicle.
- * @param tile unused
- * @param p1 the ID of the vehicle
- * @param p2 the order to delete (max 255)
- */
-int32 CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *v, *u;
- VehicleID veh_id = p1;
- VehicleOrderID sel_ord = p2;
- Order *order;
-
- if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
-
- v = GetVehicle(veh_id);
-
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
- /* If we did not select an order, we maybe want to de-clone the orders */
- if (sel_ord >= v->num_orders)
- return DecloneOrder(v, flags);
-
- order = GetVehicleOrder(v, sel_ord);
- if (order == NULL) return CMD_ERROR;
-
- if (flags & DC_EXEC) {
- if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
- if (GetVehicleOrder(v, sel_ord + 1) != NULL) {
- /* First item, but not the last, so we need to alter v->orders
- Because we can have shared order, we copy the data
- from the next item over the deleted */
- order = GetVehicleOrder(v, sel_ord + 1);
- SwapOrders(v->orders, order);
- } else {
- /* Last item, so clean the list */
- v->orders = NULL;
- }
- } else {
- GetVehicleOrder(v, sel_ord - 1)->next = order->next;
- }
-
- /* Give the item free */
- order->type = OT_NOTHING;
- order->next = NULL;
-
- u = GetFirstVehicleFromSharedList(v);
- DeleteOrderWarnings(u);
- for (; u != NULL; u = u->next_shared) {
- u->num_orders--;
-
- if (sel_ord < u->cur_order_index)
- u->cur_order_index--;
-
- /* If we removed the last order, make sure the shared vehicles
- * also set their orders to NULL */
- if (v->orders == NULL) u->orders = NULL;
-
- assert(v->orders == u->orders);
-
- /* NON-stop flag is misused to see if a train is in a station that is
- * on his order list or not */
- if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
- HASBIT(u->current_order.flags, OFB_NON_STOP)) {
- u->current_order.flags = 0;
- }
-
- /* Update any possible open window of the vehicle */
- InvalidateVehicleOrder(u);
- }
-
- RebuildVehicleLists();
- }
-
- return 0;
-}
-
-/** Goto next order of order-list.
- * @param tile unused
- * @param p1 The ID of the vehicle which order is skipped
- * @param p2 unused
- */
-int32 CmdSkipOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *v;
- VehicleID veh_id = p1;
-
- if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
-
- v = GetVehicle(veh_id);
-
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
- if (flags & DC_EXEC) {
- /* Goto next order */
- VehicleOrderID b = v->cur_order_index + 1;
- if (b >= v->num_orders) b = 0;
-
- v->cur_order_index = b;
-
- if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
-
- if (v->type == VEH_Road) ClearSlot(v);
-
- /* NON-stop flag is misused to see if a train is in a station that is
- * on his order list or not */
- if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
- v->current_order.flags = 0;
-
- InvalidateVehicleOrder(v);
- }
-
- /* We have an aircraft/ship, they have a mini-schedule, so update them all */
- if (v->type == VEH_Aircraft) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
- if (v->type == VEH_Ship) InvalidateWindowClasses(WC_SHIPS_LIST);
-
- return 0;
-}
-
-
-/** Modify an order in the orderlist of a vehicle.
- * @param tile unused
- * @param p1 various bitstuffed elements
- * - p1 = (bit 0 - 15) - ID of the vehicle
- * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
- * the order will be inserted before that one
- * only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 mode to change the order to (always set)
- */
-int32 CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *v;
- Order *order;
- VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
- VehicleID veh = GB(p1, 0, 16);
-
- if (!IsValidVehicleID(veh)) return CMD_ERROR;
- if (p2 != OFB_FULL_LOAD && p2 != OFB_UNLOAD && p2 != OFB_NON_STOP && p2 != OFB_TRANSFER) return CMD_ERROR;
-
- v = GetVehicle(veh);
-
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
- /* Is it a valid order? */
- if (sel_ord >= v->num_orders) return CMD_ERROR;
-
- order = GetVehicleOrder(v, sel_ord);
- if (order->type != OT_GOTO_STATION &&
- (order->type != OT_GOTO_DEPOT || p2 == OFB_UNLOAD) &&
- (order->type != OT_GOTO_WAYPOINT || p2 != OFB_NON_STOP)) {
- return CMD_ERROR;
- }
-
- if (flags & DC_EXEC) {
- switch (p2) {
- case OFB_FULL_LOAD:
- TOGGLEBIT(order->flags, OFB_FULL_LOAD);
- if (order->type != OT_GOTO_DEPOT) CLRBIT(order->flags, OFB_UNLOAD);
- break;
- case OFB_UNLOAD:
- TOGGLEBIT(order->flags, OFB_UNLOAD);
- CLRBIT(order->flags, OFB_FULL_LOAD);
- break;
- case OFB_NON_STOP:
- TOGGLEBIT(order->flags, OFB_NON_STOP);
- break;
- case OFB_TRANSFER:
- TOGGLEBIT(order->flags, OFB_TRANSFER);
- break;
- default: NOT_REACHED();
- }
-
- /* Update the windows and full load flags, also for vehicles that share the same order list */
- {
- Vehicle* u;
-
- u = GetFirstVehicleFromSharedList(v);
- DeleteOrderWarnings(u);
- for (; u != NULL; u = u->next_shared) {
- /* Toggle u->current_order "Full load" flag if it changed.
- * However, as the same flag is used for depot orders, check
- * whether we are not going to a depot as there are three
- * cases where the full load flag can be active and only
- * one case where the flag is used for depot orders. In the
- * other cases for the OrderType the flags are not used,
- * so do not care and those orders should not be active
- * when this function is called.
- */
- if (sel_ord == u->cur_order_index &&
- u->current_order.type != OT_GOTO_DEPOT &&
- HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) {
- TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD);
- }
- InvalidateVehicleOrder(u);
- }
- }
- }
-
- return 0;
-}
-
-/** Clone/share/copy an order-list of an other vehicle.
- * @param p1 various bitstuffed elements
- * - p1 = (bit 0-15) - destination vehicle to clone orders to (p1 & 0xFFFF)
- * - p1 = (bit 16-31) - source vehicle to clone orders from, if any (none for CO_UNSHARE)
- * @param p2 mode of cloning: CO_SHARE, CO_COPY, or CO_UNSHARE
- */
-int32 CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *dst;
- VehicleID veh_src = GB(p1, 16, 16);
- VehicleID veh_dst = GB(p1, 0, 16);
-
- if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
-
- dst = GetVehicle(veh_dst);
-
- if (!CheckOwnership(dst->owner)) return CMD_ERROR;
-
- switch (p2) {
- case CO_SHARE: {
- Vehicle *src;
-
- if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
-
- src = GetVehicle(veh_src);
-
- /* Sanity checks */
- if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
- return CMD_ERROR;
-
- /* Trucks can't share orders with busses (and visa versa) */
- if (src->type == VEH_Road) {
- if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
- return CMD_ERROR;
- }
-
- /* Is the vehicle already in the shared list? */
- {
- const Vehicle* u;
-
- for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
- if (u == dst) return CMD_ERROR;
- }
- }
-
- if (flags & DC_EXEC) {
- /* If the destination vehicle had a OrderList, destroy it */
- DeleteVehicleOrders(dst);
-
- dst->orders = src->orders;
- dst->num_orders = src->num_orders;
-
- /* Link this vehicle in the shared-list */
- dst->next_shared = src->next_shared;
- dst->prev_shared = src;
- if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
- src->next_shared = dst;
-
- InvalidateVehicleOrder(dst);
- InvalidateVehicleOrder(src);
-
- RebuildVehicleLists();
- }
- } break;
-
- case CO_COPY: {
- Vehicle *src;
- int delta;
-
- if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
-
- src = GetVehicle(veh_src);
-
- /* Sanity checks */
- if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
- return CMD_ERROR;
-
- /* Trucks can't copy all the orders from busses (and visa versa) */
- if (src->type == VEH_Road) {
- const Order *order;
- TileIndex required_dst = INVALID_TILE;
-
- FOR_VEHICLE_ORDERS(src, order) {
- if (order->type == OT_GOTO_STATION) {
- const Station *st = GetStation(order->dest);
- if (dst->cargo_type == CT_PASSENGERS) {
- if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
- } else {
- if (st->truck_stops != NULL) required_dst = st->truck_stops->xy;
- }
- /* This station has not the correct road-bay, so we can't copy! */
- if (required_dst == INVALID_TILE)
- return CMD_ERROR;
- }
- }
- }
-
- /* make sure there are orders available */
- delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
- if (!HasOrderPoolFree(delta))
- return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
-
- if (flags & DC_EXEC) {
- const Order *order;
- Order **order_dst;
-
- /* If the destination vehicle had a OrderList, destroy it */
- DeleteVehicleOrders(dst);
-
- order_dst = &dst->orders;
- FOR_VEHICLE_ORDERS(src, order) {
- *order_dst = AllocateOrder();
- AssignOrder(*order_dst, *order);
- order_dst = &(*order_dst)->next;
- }
-
- dst->num_orders = src->num_orders;
-
- InvalidateVehicleOrder(dst);
-
- RebuildVehicleLists();
- }
- } break;
-
- case CO_UNSHARE: return DecloneOrder(dst, flags);
- default: return CMD_ERROR;
- }
-
- return 0;
-}
-
-/** Add/remove refit orders from an order
- * @param tile Not used
- * @param p1 VehicleIndex of the vehicle having the order
- * @param p2 bitmask
- * - bit 0-7 CargoID
- * - bit 8-15 Cargo subtype
- * - bit 16-23 number of order to modify
- */
-int32 CmdOrderRefit(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- const Vehicle *v;
- Order *order;
- VehicleID veh = GB(p1, 0, 16);
- VehicleOrderID order_number = GB(p2, 16, 8);
- CargoID cargo = GB(p2, 0, 8);
- byte subtype = GB(p2, 8, 8);
-
- if (!IsValidVehicleID(veh)) return CMD_ERROR;
-
- v = GetVehicle(veh);
-
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
-
- order = GetVehicleOrder(v, order_number);
- if (order == NULL) return CMD_ERROR;
-
- if (flags & DC_EXEC) {
- Vehicle *u;
-
- order->refit_cargo = cargo;
- order->refit_subtype = subtype;
-
- u = GetFirstVehicleFromSharedList(v);
- for (; u != NULL; u = u->next_shared) {
- /* Update any possible open window of the vehicle */
- InvalidateVehicleOrder(u);
-
- /* If the vehicle already got the current depot set as current order, then update current order as well */
- if (u->cur_order_index == order_number && HASBIT(u->current_order.flags, OFB_PART_OF_ORDERS)) {
- u->current_order.refit_cargo = cargo;
- u->current_order.refit_subtype = subtype;
- }
- }
- }
-
- return 0;
-}
-
-/**
- *
- * Backup a vehicle order-list, so you can replace a vehicle
- * without loosing the order-list
- *
- */
-void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
-{
- /* Save general info */
- bak->orderindex = v->cur_order_index;
- bak->service_interval = v->service_interval;
-
- /* Safe custom string, if any */
- if (!IsCustomName(v->string_id)) {
- bak->name[0] = '\0';
- } else {
- GetName(bak->name, v->string_id & 0x7FF, lastof(bak->name));
- }
-
- /* If we have shared orders, store it on a special way */
- if (IsOrderListShared(v)) {
- const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
-
- bak->clone = u->index;
- } else {
- /* Else copy the orders */
- Order *order, *dest;
-
- dest = bak->order;
-
- /* We do not have shared orders */
- bak->clone = INVALID_VEHICLE;
-
- /* Copy the orders */
- FOR_VEHICLE_ORDERS(v, order) {
- *dest = *order;
- dest++;
- }
- /* End the list with an OT_NOTHING */
- dest->type = OT_NOTHING;
- dest->next = NULL;
- }
-}
-
-/**
- *
- * Restore vehicle orders that are backupped via BackupVehicleOrders
- *
- */
-void RestoreVehicleOrders(const Vehicle* v, const BackuppedOrders* bak)
-{
- uint i;
-
- /* If we have a custom name, process that */
- if (bak->name[0] != 0) {
- _cmd_text = bak->name;
- DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
- }
-
- /* If we had shared orders, recover that */
- if (bak->clone != INVALID_VEHICLE) {
- DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
- return;
- }
-
- /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
- * order number is one more than the current amount of orders, and because
- * in network the commands are queued before send, the second insert always
- * fails in test mode. By bypassing the test-mode, that no longer is a problem. */
- for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
- if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
- break;
- }
-
- /* Restore vehicle order-index and service interval */
- DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
-}
-
-/** Restore the current order-index of a vehicle and sets service-interval.
- * @param tile unused
- * @param p1 the ID of the vehicle
- * @param p2 various bistuffed elements
- * - p2 = (bit 0-15) - current order-index (p2 & 0xFFFF)
- * - p2 = (bit 16-31) - service interval (p2 >> 16)
- * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle
- * as far as I can see. We can store it in BackuppedOrders, and restore it, but
- * but we have no way of seeing it has been tampered with or not, as we have no
- * legit way of knowing what that ID was.@n
- * If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and
- * restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;"
- */
-int32 CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *v;
- VehicleOrderID cur_ord = GB(p2, 0, 16);
- uint16 serv_int = GB(p2, 16, 16);
-
- if (!IsValidVehicleID(p1)) return CMD_ERROR;
-
- v = GetVehicle(p1);
-
- /* Check the vehicle type and ownership, and if the service interval and order are in range */
- if (!CheckOwnership(v->owner)) return CMD_ERROR;
- if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
-
- if (flags & DC_EXEC) {
- v->cur_order_index = cur_ord;
- v->service_interval = serv_int;
- }
-
- return 0;
-}
-
-
-static TileIndex GetStationTileForVehicle(const Vehicle* v, const Station* st)
-{
- switch (v->type) {
- default: NOT_REACHED();
- case VEH_Train: return st->train_tile;
- case VEH_Aircraft: return st->airport_tile;
- case VEH_Ship: return st->dock_tile;
- case VEH_Road:
- if (v->cargo_type == CT_PASSENGERS) {
- return (st->bus_stops != NULL) ? st->bus_stops->xy : 0;
- } else {
- return (st->truck_stops != NULL) ? st->truck_stops->xy : 0;
- }
- }
-}
-
-
-/**
- *
- * Check the orders of a vehicle, to see if there are invalid orders and stuff
- *
- */
-void CheckOrders(const Vehicle* v)
-{
- /* Does the user wants us to check things? */
- if (_patches.order_review_system == 0) return;
-
- /* Do nothing for crashed vehicles */
- if (v->vehstatus & VS_CRASHED) return;
-
- /* Do nothing for stopped vehicles if setting is '1' */
- if (_patches.order_review_system == 1 && v->vehstatus & VS_STOPPED)
- return;
-
- /* do nothing we we're not the first vehicle in a share-chain */
- if (v->next_shared != NULL) return;
-
- /* Only check every 20 days, so that we don't flood the message log */
- if (v->owner == _local_player && v->day_counter % 20 == 0) {
- int n_st, problem_type = -1;
- const Order *order;
- int message = 0;
-
- /* Check the order list */
- n_st = 0;
-
- FOR_VEHICLE_ORDERS(v, order) {
- /* Dummy order? */
- if (order->type == OT_DUMMY) {
- problem_type = 1;
- break;
- }
- /* Does station have a load-bay for this vehicle? */
- if (order->type == OT_GOTO_STATION) {
- const Station* st = GetStation(order->dest);
- TileIndex required_tile = GetStationTileForVehicle(v, st);
-
- n_st++;
- if (required_tile == 0) problem_type = 3;
- }
- }
-
- /* Check if the last and the first order are the same */
- if (v->num_orders > 1) {
- const Order* last = GetLastVehicleOrder(v);
-
- if (v->orders->type == last->type &&
- v->orders->flags == last->flags &&
- v->orders->dest == last->dest) {
- problem_type = 2;
- }
- }
-
- /* Do we only have 1 station in our order list? */
- if (n_st < 2 && problem_type == -1) problem_type = 0;
-
- /* We don't have a problem */
- if (problem_type < 0) return;
-
- message = STR_TRAIN_HAS_TOO_FEW_ORDERS + ((v->type - VEH_Train) << 2) + problem_type;
- //DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
-
- SetDParam(0, v->unitnumber);
- AddNewsItem(
- message,
- NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
- v->index,
- 0
- );
- }
-}
-
-/**
- * Removes an order from all vehicles. Triggers when, say, a station is removed.
- * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
- * @param destination The destination. Can be a StationID, DepotID or WaypointID.
- */
-void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
-{
- Vehicle *v;
-
- /* Aircraft have StationIDs for depot orders and never use DepotIDs
- * This fact is handled specially below
- */
-
- /* Go through all vehicles */
- FOR_ALL_VEHICLES(v) {
- Order *order;
- bool invalidate;
-
- /* Forget about this station if this station is removed */
- if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
- v->last_station_visited = INVALID_STATION;
- }
-
- order = &v->current_order;
- if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
- v->current_order.dest == destination) {
- order->type = OT_DUMMY;
- order->flags = 0;
- InvalidateWindow(WC_VEHICLE_VIEW, v->index);
- }
-
- /* Clear the order from the order-list */
- invalidate = false;
- FOR_VEHICLE_ORDERS(v, order) {
- if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
- order->dest == destination) {
- order->type = OT_DUMMY;
- order->flags = 0;
- invalidate = true;
- }
- }
-
- /* Only invalidate once, and if needed */
- if (invalidate) InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
- }
-}
-
-/**
- *
- * Checks if a vehicle has a GOTO_DEPOT in his order list
- *
- * @return True if this is true (lol ;))
- *
- */
-bool VehicleHasDepotOrders(const Vehicle *v)
-{
- const Order *order;
-
- FOR_VEHICLE_ORDERS(v, order) {
- if (order->type == OT_GOTO_DEPOT)
- return true;
- }
-
- return false;
-}
-
-/**
- *
- * Delete all orders from a vehicle
- *
- */
-void DeleteVehicleOrders(Vehicle *v)
-{
- Order *cur, *next;
-
- DeleteOrderWarnings(v);
-
- /* If we have a shared order-list, don't delete the list, but just
- remove our pointer */
- if (IsOrderListShared(v)) {
- const Vehicle *u = v;
-
- v->orders = NULL;
- v->num_orders = 0;
-
- /* Unlink ourself */
- if (v->prev_shared != NULL) {
- v->prev_shared->next_shared = v->next_shared;
- u = v->prev_shared;
- }
- if (v->next_shared != NULL) {
- v->next_shared->prev_shared = v->prev_shared;
- u = v->next_shared;
- }
- v->prev_shared = NULL;
- v->next_shared = NULL;
-
- /* We only need to update this-one, because if there is a third
- * vehicle which shares the same order-list, nothing will change. If
- * this is the last vehicle, the last line of the order-window
- * will change from Shared order list, to Order list, so it needs
- * an update */
- InvalidateVehicleOrder(u);
- return;
- }
-
- /* Remove the orders */
- cur = v->orders;
- v->orders = NULL;
- v->num_orders = 0;
-
- if (cur != NULL) {
- /* Delete the vehicle list of shared orders, if any */
- int window_type = 0;
-
- switch (v->type) {
- case VEH_Train: window_type = WC_TRAINS_LIST; break;
- case VEH_Road: window_type = WC_ROADVEH_LIST; break;
- case VEH_Ship: window_type = WC_SHIPS_LIST; break;
- case VEH_Aircraft: window_type = WC_AIRCRAFT_LIST; break;
- default: NOT_REACHED();
- }
- DeleteWindowById(window_type, (cur->index << 16) | (v->type << 11) | VLW_SHARED_ORDERS | v->owner);
- }
-
- while (cur != NULL) {
- next = cur->next;
- DeleteOrder(cur);
- cur = next;
- }
-}
-
-/**
- *
- * Check if we share our orders with an other vehicle
- *
- * @return Returns the vehicle who has the same order
- *
- */
-bool IsOrderListShared(const Vehicle *v)
-{
- return v->next_shared != NULL || v->prev_shared != NULL;
-}
-
-/**
- *
- * Check if a vehicle has any valid orders
- *
- * @return false if there are no valid orders
- *
- */
-bool CheckForValidOrders(const Vehicle* v)
-{
- const Order *order;
-
- FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
-
- return false;
-}
-
-void InitializeOrders(void)
-{
- CleanPool(&_Order_pool);
- AddBlockToPool(&_Order_pool);
-
- _backup_orders_tile = 0;
-}
-
-static const SaveLoad _order_desc[] = {
- SLE_VAR(Order, type, SLE_UINT8),
- SLE_VAR(Order, flags, SLE_UINT8),
- SLE_VAR(Order, dest, SLE_UINT16),
- SLE_REF(Order, next, REF_ORDER),
- SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION),
- SLE_CONDVAR(Order, refit_subtype, SLE_UINT8, 36, SL_MAX_VERSION),
-
- /* Leftover from the minor savegame version stuff
- * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
- SLE_CONDNULL(10, 5, 35),
- SLE_END()
-};
-
-static void Save_ORDR(void)
-{
- Order *order;
-
- FOR_ALL_ORDERS(order) {
- SlSetArrayIndex(order->index);
- SlObject(order, _order_desc);
- }
-}
-
-static void Load_ORDR(void)
-{
- if (CheckSavegameVersionOldStyle(5, 2)) {
- /* Version older than 5.2 did not have a ->next pointer. Convert them
- (in the old days, the orderlist was 5000 items big) */
- uint len = SlGetFieldLength();
- uint i;
-
- if (CheckSavegameVersion(5)) {
- /* Pre-version 5 had an other layout for orders
- (uint16 instead of uint32) */
- uint16 orders[5000];
-
- len /= sizeof(uint16);
- assert (len <= lengthof(orders));
-
- SlArray(orders, len, SLE_UINT16);
-
- for (i = 0; i < len; ++i) {
- if (!AddBlockIfNeeded(&_Order_pool, i))
- error("Orders: failed loading savegame: too many orders");
-
- AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
- }
- } else if (CheckSavegameVersionOldStyle(5, 2)) {
- uint32 orders[5000];
-
- len /= sizeof(uint32);
- assert (len <= lengthof(orders));
-
- SlArray(orders, len, SLE_UINT32);
-
- for (i = 0; i < len; ++i) {
- if (!AddBlockIfNeeded(&_Order_pool, i))
- error("Orders: failed loading savegame: too many orders");
-
- AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
- }
- }
-
- /* Update all the next pointer */
- for (i = 1; i < len; ++i) {
- /* The orders were built like this:
- * Vehicle one had order[0], and as long as order++.type was not
- * OT_NOTHING, it was part of the order-list of that vehicle */
- if (GetOrder(i)->type != OT_NOTHING)
- GetOrder(i - 1)->next = GetOrder(i);
- }
- } else {
- int index;
-
- while ((index = SlIterateArray()) != -1) {
- Order *order;
-
- if (!AddBlockIfNeeded(&_Order_pool, index))
- error("Orders: failed loading savegame: too many orders");
-
- order = GetOrder(index);
- SlObject(order, _order_desc);
- }
- }
-}
-
-const ChunkHandler _order_chunk_handlers[] = {
- { 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
-};