(svn r1525) -Codechange: rewrote the _order_array, now it can be made dynamic.

-Codechange: renamed all 'schedule' stuff to 'order(list)'
-Codechange: moved all order-stuff to order_cmd.c / order.h
-Codechange: vehicles that share orders are now linked to eachother
  with next_shared/prev_shared in Vehicle

  Developers: please use AssignOrder to assign data to an order. If not, 
   you _WILL_ make the save-routine to assert!
pull/155/head
truelight 20 years ago
parent 0e651d9702
commit 7cafdf3b0b

@ -3618,7 +3618,7 @@ static void AiStateRemoveStation(Player *p)
// Get a list of all stations that are in use by a vehicle
memset(in_use, 0, sizeof(in_use));
for (ord = _order_array; ord != _ptr_to_next_order; ++ord) {
FOR_ALL_ORDERS(ord) {
if (ord->type == OT_GOTO_STATION)
in_use[ord->station] = 1;
}

@ -502,14 +502,12 @@ static bool AiNew_CheckVehicleStation(Player *p, Station *st) {
// Also check if we don't have already a lot of busses to this city...
FOR_ALL_VEHICLES(v) {
if (v->owner == _current_player) {
const Order *sched = v->schedule_ptr;
if (sched != NULL) {
for (; sched->type != OT_NOTHING; ++sched) {
if (sched->type == OT_GOTO_STATION &&
GetStation(sched->station) == st) {
// This vehicle has this city in his list
count++;
}
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
if (order->type == OT_GOTO_STATION && GetStation(order->station) == st) {
// This vehicle has this city in its list
count++;
}
}
}

@ -126,7 +126,7 @@ int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
// allocate 2 or 3 vehicle structs, depending on type
if (!AllocateVehicles(vl, (avi->subtype & 1) == 0 ? 3 : 2) ||
_ptr_to_next_order >= endof(_order_array))
IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
unit_num = GetFreeUnitNumber(VEH_Aircraft);
@ -200,9 +200,6 @@ int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_new_aircraft_id = v->index;
_ptr_to_next_order->type = OT_NOTHING;
_ptr_to_next_order->flags = 0;
v->schedule_ptr = _ptr_to_next_order++;
// the AI doesn't click on a tile to build airplanes, so the below code will
// never work. Therefore just assume the AI's planes always come from Hangar0
// On hold for NewAI
@ -490,7 +487,7 @@ static void CheckIfAircraftNeedsService(Vehicle *v)
v->current_order.flags & OF_FULL_LOAD)
return;
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
st = GetStation(v->current_order.station);
@ -510,13 +507,13 @@ static void CheckIfAircraftNeedsService(Vehicle *v)
void InvalidateAircraftWindows(const Vehicle *v)
{
const Order *o;
const Order *order;
InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
for ( o = v->schedule_ptr; o->type != OT_NOTHING; o++) {
if (o->type == OT_GOTO_STATION ) {
InvalidateWindow(WC_AIRCRAFT_LIST, o->station << 16 | v->owner);
FOR_VEHICLE_ORDERS(v, order) {
if (order->type == OT_GOTO_STATION ) {
InvalidateWindow(WC_AIRCRAFT_LIST, (order->station << 16) | v->owner);
}
}
}
@ -1024,21 +1021,9 @@ static void HandleAircraftSmoke(Vehicle *v)
}
}
// returns true if the vehicle does have valid orders
// false if none are valid
static bool CheckForValidOrders(Vehicle *v)
{
int i;
for (i = 0; i < v->num_orders; i++) {
if( v->schedule_ptr[i].type != OT_DUMMY )
return true;
}
return false;
}
static void ProcessAircraftOrder(Vehicle *v)
{
Order order;
Order *order;
// OT_GOTO_DEPOT, OT_LOADING
if (v->current_order.type == OT_GOTO_DEPOT ||
@ -1057,32 +1042,32 @@ static void ProcessAircraftOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
order = v->schedule_ptr[v->cur_order_index];
order = GetVehicleOrder(v, v->cur_order_index);
if (order.type == OT_NOTHING) {
if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
return;
}
if ( order.type == OT_DUMMY && !CheckForValidOrders(v))
if (order->type == OT_DUMMY && !CheckForValidOrders(v))
CrashAirplane(v);
if (order.type == v->current_order.type &&
order.flags == v->current_order.flags &&
order.station == v->current_order.station)
if (order->type == v->current_order.type &&
order->flags == v->current_order.flags &&
order->station == v->current_order.station)
return;
v->current_order = order;
v->current_order = *order;
// orders are changed in flight, ensure going to the right station
if (order.type == OT_GOTO_STATION && v->u.air.state == FLYING) {
if (order->type == OT_GOTO_STATION && v->u.air.state == FLYING) {
AircraftNextAirportPos_and_Order(v);
v->u.air.targetairport = order.station;
v->u.air.targetairport = order->station;
}
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
InvalidateAircraftWindows(v);
}
@ -1116,7 +1101,7 @@ static void HandleAircraftLoading(Vehicle *v, int mode)
}
}
v->cur_order_index++;
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
static void CrashAirplane(Vehicle *v)

@ -920,16 +920,13 @@ void ShowAircraftDepotWindow(uint tile)
}
}
static void DrawSmallSchedule(Vehicle *v, int x, int y) {
const Order *sched;
int sel;
Order ord;
int i = 0;
static void DrawSmallOrderList(Vehicle *v, int x, int y) {
const Order *order;
int sel, i = 0;
sched = v->schedule_ptr;
sel = v->cur_order_index;
while ((ord = *sched++).type != OT_NOTHING) {
FOR_VEHICLE_ORDERS(v, order) {
if (sel == 0) {
_stringwidth_base = 0xE0;
DoDrawString( "\xAF", x-6, y, 16);
@ -937,8 +934,8 @@ static void DrawSmallSchedule(Vehicle *v, int x, int y) {
}
sel--;
if (ord.type == OT_GOTO_STATION) {
SetDParam(0, ord.station);
if (order->type == OT_GOTO_STATION) {
SetDParam(0, order->station);
DrawString(x, y, STR_A036, 0);
y += 6;
@ -1052,7 +1049,7 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
DrawString(x + 19, y, STR_01AB, 0);
}
DrawSmallSchedule(v, x + 136, y);
DrawSmallOrderList(v, x + 136, y);
y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
}

@ -150,6 +150,8 @@ void CSleep(int milliseconds)
#endif
}
void InitializeVehicles();
void InitializeOrders();
void InitializeClearLand();
void InitializeRail();
void InitializeRailGui();
@ -206,7 +208,7 @@ void InitializeGame()
}
InitializeVehicles();
_backup_orders_tile = 0;
InitializeOrders();
InitNewsItemStructs();
InitializeLandscape();

@ -752,6 +752,22 @@ static void FixDepot(Depot *n, OldDepot *o, int num)
} while (n++,o++,--num);
}
static void FixOrder(uint16 *o, int num)
{
Order *order;
int i;
for (i = 0; i < num; ++i) {
order = GetOrder(i);
AssignOrder(order, UnpackOldOrder(*o));
/* Recover the next list */
if (i > 0 && order->type != OT_NOTHING)
GetOrder(i - 1)->next = order;
o++;
}
}
static void FixVehicle(OldVehicle *o, int num)
{
Vehicle *n;
@ -767,10 +783,9 @@ static void FixVehicle(OldVehicle *o, int num)
n->subtype = o->subtype;
if (o->schedule_ptr == 0xFFFFFFFF || o->schedule_ptr == 0) {
n->schedule_ptr = NULL;
n->orders = NULL;
} else {
n->schedule_ptr = _order_array + REMAP_ORDER_IDX(o->schedule_ptr);
assert(n->schedule_ptr >= _order_array && n->schedule_ptr < _ptr_to_next_order);
n->orders = GetOrder(REMAP_ORDER_IDX(o->schedule_ptr));
}
n->current_order.type = o->next_order & 0x0f;
@ -870,6 +885,31 @@ static void FixVehicle(OldVehicle *o, int num)
break;
}
} while (i++,o++,--num);
/* Check for shared orders, and link them correctly */
{
Vehicle *v;
FOR_ALL_VEHICLES(v) {
Vehicle *u;
if (v->type == 0)
continue;
FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
if (u->type == 0)
continue;
/* If a vehicle has the same orders, add the link to eachother
in both vehicles */
if (v->orders == u->orders) {
v->next_shared = u;
u->prev_shared = v;
break;
}
}
}
}
}
static void FixSubsidy(Subsidy *n, OldSubsidy *o, int num)
@ -1447,15 +1487,12 @@ bool LoadOldSaveGame(const char *file)
}
}
for (i = 0; i < lengthof(m->order_list); ++i)
_order_array[i] = UnpackOldOrder(m->order_list[i]);
_ptr_to_next_order = _order_array + REMAP_ORDER_IDX(m->ptr_to_next_order);
FixTown(m->town_list, lengthof(m->town_list), m->town_name_type);
FixIndustry(m->industries, lengthof(m->industries));
FixStation(m->stations, lengthof(m->stations));
FixDepot(_depots, m->depots, lengthof(m->depots));
FixOrder(m->order_list, lengthof(m->order_list));
FixVehicle(m->vehicles, lengthof(m->vehicles));
FixSubsidy(_subsidies, m->subsidies, lengthof(m->subsidies));

@ -0,0 +1,124 @@
#ifndef ORDER_H
#define ORDER_H
/* Order types */
enum {
OT_NOTHING = 0,
OT_GOTO_STATION = 1,
OT_GOTO_DEPOT = 2,
OT_LOADING = 3,
OT_LEAVESTATION = 4,
OT_DUMMY = 5,
OT_GOTO_WAYPOINT = 6
};
/* Order flags -- please use OFB instead OF and use HASBIT/SETBIT/CLEARBIT */
enum {
OF_UNLOAD = 0x2,
OF_FULL_LOAD = 0x4, // Also used when to force an aircraft into a depot
OF_NON_STOP = 0x8
};
/* Order flags bits */
enum {
OFB_UNLOAD = 1,
OFB_FULL_LOAD = 2,
OFB_NON_STOP = 3
};
/* Possible clone options */
enum {
CO_SHARE = 0,
CO_COPY = 1,
CO_UNSHARE = 2
};
/* If you change this, keep in mind that it is saved on 3 places:
- Load_ORDR, all the global orders
- Vehicle -> current_order
- REF_SHEDULE (all REFs are currently limited to 16 bits!!) */
typedef struct Order {
uint8 type;
uint8 flags;
uint16 station;
struct Order *next; //! Pointer to next order. If NULL, end of list
uint16 index; //! Index of the order, is not saved or anything, just for reference
} Order;
typedef struct {
VehicleID clone;
byte orderindex;
Order order[41];
uint16 service_interval;
char name[32];
} BackuppedOrders;
VARDEF TileIndex _backup_orders_tile;
VARDEF BackuppedOrders _backup_orders_data[1];
VARDEF Order _orders[5000];
VARDEF uint32 _orders_size;
static inline Order *GetOrder(uint index)
{
assert(index < _orders_size);
return &_orders[index];
}
#define FOR_ALL_ORDERS_FROM(o, from) for(o = GetOrder(from); o != &_orders[_orders_size]; o++)
#define FOR_ALL_ORDERS(o) FOR_ALL_ORDERS_FROM(o, 0)
#define FOR_VEHICLE_ORDERS(v, order) for (order = v->orders; order != NULL; order = order->next)
static inline bool HasOrderPoolFree(uint amount)
{
Order *order;
FOR_ALL_ORDERS(order)
if (order->type == OT_NOTHING)
if (--amount == 0)
return true;
return false;
}
static inline bool IsOrderPoolFull()
{
return !HasOrderPoolFree(1);
}
/* Pack and unpack routines */
static inline uint32 PackOrder(const Order *order)
{
return order->station << 16 | order->flags << 8 | order->type;
}
static inline Order UnpackOrder(uint32 packed)
{
Order order;
order.type = (packed & 0x000000FF);
order.flags = (packed & 0x0000FF00) >> 8;
order.station = (packed & 0xFFFF0000) >> 16;
order.next = NULL;
return order;
}
/* Functions */
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *order);
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order);
void DeleteDestinationFromVehicleOrder(Order dest);
void InvalidateVehicleOrder(const Vehicle *v);
bool VehicleHasDepotOrders(const Vehicle *v);
bool CheckOrders(const Vehicle *v);
void DeleteVehicleOrders(Vehicle *v);
bool IsOrderListShared(const Vehicle *v);
void AssignOrder(Order *order, Order data);
bool CheckForValidOrders(Vehicle *v);
Order UnpackVersion4Order(uint16 packed);
Order UnpackOldOrder(uint16 packed);
#endif /* ORDER_H */

File diff suppressed because it is too large Load Diff

@ -14,32 +14,23 @@
static int OrderGetSel(Window *w)
{
Vehicle *v = GetVehicle(w->window_number);
const Order *sched = v->schedule_ptr;
int num = WP(w,order_d).sel;
int count = 0;
if (num == 0)
return 0;
if (num < 0 || num > v->num_orders)
return v->num_orders;
while (sched->type != OT_NOTHING) {
sched++;
count++;
if (--num == 0)
break;
}
return count;
return num;
}
static void DrawOrdersWindow(Window *w)
{
Vehicle *v;
int num, sel;
const Order *sched;
Order ord;
int y, i;
const Vehicle *v;
const Order *order;
StringID str;
bool shared_schedule;
int sel;
int y, i;
bool shared_orders;
byte color;
v = GetVehicle(w->window_number);
@ -57,40 +48,41 @@ static void DrawOrdersWindow(Window *w)
w->disabled_state |= 1 << 6;
}
shared_schedule = IsScheduleShared(v) != NULL;
shared_orders = IsOrderListShared(v);
sched = v->schedule_ptr;
num=0;
while (sched->type != OT_NOTHING) {
sched++;
num++;
}
if ((uint)num + shared_schedule <= (uint)WP(w,order_d).sel)
if ((uint)v->num_orders + shared_orders <= (uint)WP(w,order_d).sel)
SETBIT(w->disabled_state, 5); /* delete */
if (num == 0)
if (v->num_orders == 0)
SETBIT(w->disabled_state, 4); /* skip */
SetVScrollCount(w, num+1);
SetVScrollCount(w, v->num_orders + 1);
sel = OrderGetSel(w);
SetDParam(2, STR_8827_FULL_LOAD);
SetDParam(2,STR_8827_FULL_LOAD);
switch (v->schedule_ptr[sel].type) {
case OT_GOTO_STATION:
break;
case OT_GOTO_DEPOT:
SETBIT(w->disabled_state, 9); /* unload */
SetDParam(2,STR_SERVICE);
break;
order = GetVehicleOrder(v, sel);
case OT_GOTO_WAYPOINT:
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
break;
if (order != NULL) {
switch (order->type) {
case OT_GOTO_STATION:
break;
case OT_GOTO_DEPOT:
SETBIT(w->disabled_state, 9); /* unload */
SetDParam(2,STR_SERVICE);
break;
case OT_GOTO_WAYPOINT:
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
break;
default:
default:
SETBIT(w->disabled_state, 6); /* nonstop */
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
}
} else {
SETBIT(w->disabled_state, 6); /* nonstop */
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
@ -102,61 +94,62 @@ static void DrawOrdersWindow(Window *w)
y = 15;
i = 0;
for(;;) {
str = ((byte)v->cur_order_index == i) ? STR_8805 : STR_8804;
i = w->vscroll.pos;
order = GetVehicleOrder(v, i);
while (order != NULL) {
str = (v->cur_order_index == i) ? STR_8805 : STR_8804;
if (i - w->vscroll.pos < 6) {
SetDParam(1, 6);
if (order->type == OT_GOTO_STATION) {
SetDParam(1, STR_8806_GO_TO + (order->flags >> 1));
SetDParam(2, order->station);
} else if (order->type == OT_GOTO_DEPOT) {
StringID s = STR_NULL;
if (v->type == VEH_Aircraft) {
s = STR_GO_TO_AIRPORT_HANGAR;
SetDParam(2, order->station);
} else {
SetDParam(2, _depots[order->station].town_index);
switch (v->type) {
case VEH_Train: s = STR_880E_GO_TO_TRAIN_DEPOT; break;
case VEH_Road: s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
case VEH_Ship: s = STR_GO_TO_SHIP_DEPOT; break;
}
}
if (v->type == VEH_Train && order->flags & OF_NON_STOP)
s += 2;
ord = v->schedule_ptr[i];
if (order->flags & OF_FULL_LOAD)
s++; /* XXX service */
if ( (uint)(i - w->vscroll.pos) < 6) {
SetDParam(1, s);
} else if (order->type == OT_GOTO_WAYPOINT) {
SetDParam(1, (order->flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
SetDParam(2, order->station);
}
if (ord.type == OT_NOTHING) {
str = shared_schedule ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
SetDParam(0, i + 1);
if (order->type != OT_DUMMY) {
DrawString(2, y, str, color);
} else {
SetDParam(1, 6);
if (ord.type == OT_GOTO_STATION) {
SetDParam(1, STR_8806_GO_TO + (ord.flags >> 1));
SetDParam(2, ord.station);
} else if (ord.type == OT_GOTO_DEPOT) {
StringID s = STR_NULL;
if (v->type == VEH_Aircraft) {
s = STR_GO_TO_AIRPORT_HANGAR;
SetDParam(2, ord.station);
} else {
SetDParam(2, _depots[ord.station].town_index);
switch (v->type) {
case VEH_Train: s = STR_880E_GO_TO_TRAIN_DEPOT; break;
case VEH_Road: s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
case VEH_Ship: s = STR_GO_TO_SHIP_DEPOT; break;
}
}
if (v->type == VEH_Train && ord.flags & OF_NON_STOP) s += 2;
if (ord.flags & OF_FULL_LOAD) ++s; /* XXX service */
SetDParam(1, s);
} else if (ord.type == OT_GOTO_WAYPOINT) {
SetDParam(2, ord.station);
SetDParam(1, (ord.flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
}
}
{
byte color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
SetDParam(0, i+1);
if (ord.type != OT_DUMMY) {
DrawString(2, y, str, color);
} else {
SetDParam(1, STR_INVALID_ORDER);
SetDParam(2, ord.station);
DrawString(2, y, str, color);
}
SetDParam(1, STR_INVALID_ORDER);
SetDParam(2, order->station);
DrawString(2, y, str, color);
}
y += 10;
}
i++;
order = order->next;
}
if (ord.type == OT_NOTHING)
break;
if (i - w->vscroll.pos < 6) {
str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
DrawString(2, y, str, color);
}
}
@ -317,12 +310,6 @@ static void OrdersPlaceObj(Vehicle *v, uint tile, Window *w)
}
}
enum OrderFlags {
FULL_LOAD = 0,
UNLOAD = 1,
NON_STOP = 2
};
static void OrderClick_Goto(Window *w, Vehicle *v)
{
InvalidateWidget(w, 7);
@ -337,27 +324,27 @@ static void OrderClick_Goto(Window *w, Vehicle *v)
static void OrderClick_FullLoad(Window *w, Vehicle *v)
{
DoCommandP(v->tile, v->index, OrderGetSel(w) | (FULL_LOAD << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_FULL_LOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
static void OrderClick_Unload(Window *w, Vehicle *v)
{
DoCommandP(v->tile, v->index, OrderGetSel(w) | (UNLOAD << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_UNLOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
static void OrderClick_Skip(Window *w, Vehicle *v)
static void OrderClick_Nonstop(Window *w, Vehicle *v)
{
DoCommandP(v->tile,v->index, 0, NULL, CMD_SKIP_ORDER);
DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_NON_STOP, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
static void OrderClick_Delete(Window *w, Vehicle *v)
static void OrderClick_Skip(Window *w, Vehicle *v)
{
DoCommandP(v->tile,v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
DoCommandP(v->tile, v->index, 0, NULL, CMD_SKIP_ORDER);
}
static void OrderClick_Nonstop(Window *w, Vehicle *v)
static void OrderClick_Delete(Window *w, Vehicle *v)
{
DoCommandP(v->tile, v->index, OrderGetSel(w) | (NON_STOP << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
}
typedef void OnButtonClick(Window *w, Vehicle *v);
@ -399,18 +386,18 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
sel += w->vscroll.pos;
if (_ctrl_pressed && sel < v->num_orders) { // watch out for schedule_ptr overflow
Order ord = v->schedule_ptr[sel];
if (_ctrl_pressed && sel < v->num_orders) {
Order *ord = GetVehicleOrder(v, sel);
int xy = 0;
switch (ord.type) {
switch (ord->type) {
case OT_GOTO_STATION: /* station order */
xy = GetStation(ord.station)->xy ;
xy = GetStation(ord->station)->xy ;
break;
case OT_GOTO_DEPOT: /* goto depot order */
xy = _depots[ord.station].xy;
xy = _depots[ord->station].xy;
break;
case OT_GOTO_WAYPOINT: /* goto waypoint order */
xy = _waypoints[ord.station].xy;
xy = _waypoints[ord->station].xy;
}
if (xy)
@ -447,7 +434,6 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
case 9: /* unload button */
OrderClick_Unload(w, v);
break;
}
} break;
@ -473,7 +459,7 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
case WE_RCLICK: {
Vehicle *v = GetVehicle(w->window_number);
if (e->click.widget != 8) break;
if (v->schedule_ptr[OrderGetSel(w)].type == OT_GOTO_DEPOT)
if (GetVehicleOrder(v, OrderGetSel(w))->type == OT_GOTO_DEPOT)
GuiShowTooltips(STR_SERVICE_HINT);
else
GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);

@ -768,10 +768,11 @@ static void DoDeleteWaypoint(Waypoint *cp)
{
Order order;
cp->xy = 0;
order.type = OT_GOTO_WAYPOINT;
order.flags = 0;
order.station = cp - _waypoints;
DeleteCommandFromVehicleSchedule(order);
DeleteDestinationFromVehicleOrder(order);
if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string);
RedrawWaypointSign(cp);
}

@ -122,7 +122,7 @@ int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return cost;
v = AllocateVehicle();
if (v == NULL || _ptr_to_next_order >= endof(_order_array))
if (v == NULL || IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
/* find the first free roadveh id */
@ -172,9 +172,6 @@ int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_new_roadveh_id = v->index;
v->string_id = STR_SV_ROADVEH_NAME;
_ptr_to_next_order->type = OT_NOTHING;
_ptr_to_next_order->flags = 0;
v->schedule_ptr = _ptr_to_next_order++;
v->service_interval = _patches.servint_roadveh;
@ -554,11 +551,11 @@ static void HandleBrokenRoadVeh(Vehicle *v)
static void ProcessRoadVehOrder(Vehicle *v)
{
Order order;
Station *st;
const Order *order;
const Station *st;
if (v->current_order.type >= OT_GOTO_DEPOT && v->current_order.type <= OT_LEAVESTATION) {
// Let a depot order in the schedule interrupt.
// Let a depot order in the orderlist interrupt.
if (v->current_order.type != OT_GOTO_DEPOT ||
!(v->current_order.flags & OF_UNLOAD))
return;
@ -573,34 +570,35 @@ static void ProcessRoadVehOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
order = v->schedule_ptr[v->cur_order_index];
order = GetVehicleOrder(v, v->cur_order_index);
if (order.type == OT_NOTHING) {
if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
return;
}
if (order.type == v->current_order.type &&
order.flags == v->current_order.flags &&
order.station == v->current_order.station)
if (order->type == v->current_order.type &&
order->flags == v->current_order.flags &&
order->station == v->current_order.station)
return;
v->current_order = order;
v->current_order = *order;
v->dest_tile = 0;
if (order.type == OT_GOTO_STATION) {
if (order.station == v->last_station_visited)
if (order->type == OT_GOTO_STATION) {
if (order->station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
st = GetStation(order.station);
v->dest_tile = v->cargo_type==CT_PASSENGERS ? st->bus_tile : st->lorry_tile;
} else if (order.type == OT_GOTO_DEPOT) {
v->dest_tile = _depots[order.station].xy;
st = GetStation(order->station);
v->dest_tile = v->cargo_type == CT_PASSENGERS ? st->bus_tile : st->lorry_tile;
} else if (order->type == OT_GOTO_DEPOT) {
v->dest_tile = _depots[order->station].xy;
}
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
static void HandleRoadVehLoading(Vehicle *v)
@ -634,7 +632,7 @@ static void HandleRoadVehLoading(Vehicle *v)
}
v->cur_order_index++;
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
static void StartRoadVehSound(Vehicle *v)
@ -1390,7 +1388,7 @@ void RoadVehEnterDepot(Vehicle *v)
v->current_order.type = OT_DUMMY;
v->current_order.flags = 0;
// Part of the schedule?
// Part of the orderlist?
if (t.flags & OF_UNLOAD) {
v->cur_order_index++;
} else if (t.flags & OF_FULL_LOAD) {
@ -1436,7 +1434,7 @@ static void CheckIfRoadVehNeedsService(Vehicle *v)
if (v->vehstatus & VS_STOPPED)
return;
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
// Don't interfere with a depot visit scheduled by the user, or a

@ -8,7 +8,7 @@
enum {
SAVEGAME_MAJOR_VERSION = 5,
SAVEGAME_MINOR_VERSION = 1,
SAVEGAME_MINOR_VERSION = 2,
SAVEGAME_LOADABLE_VERSION = (SAVEGAME_MAJOR_VERSION << 8) + SAVEGAME_MINOR_VERSION
};
@ -869,6 +869,7 @@ static void UninitWriteZlib()
extern const ChunkHandler _misc_chunk_handlers[];
extern const ChunkHandler _player_chunk_handlers[];
extern const ChunkHandler _veh_chunk_handlers[];
extern const ChunkHandler _order_chunk_handlers[];
extern const ChunkHandler _town_chunk_handlers[];
extern const ChunkHandler _sign_chunk_handlers[];
extern const ChunkHandler _station_chunk_handlers[];
@ -880,6 +881,7 @@ extern const ChunkHandler _animated_tile_chunk_handlers[];
static const ChunkHandler * const _chunk_handlers[] = {
_misc_chunk_handlers,
_veh_chunk_handlers,
_order_chunk_handlers,
_industry_chunk_handlers,
_economy_chunk_handlers,
_engine_chunk_handlers,
@ -912,9 +914,7 @@ static uint ReferenceToInt(void *v, uint t)
case REF_VEHICLE: return ((Vehicle *)v)->index + 1;
case REF_STATION: return ((Station *)v)->index + 1;
case REF_TOWN: return ((Town *)v)->index + 1;
case REF_SCHEDULE:
return ((byte*)v - (byte*)_order_array) / sizeof(_order_array[0]) + 1;
case REF_ORDER: return ((Order *)v)->index + 1;
default:
NOT_REACHED();
@ -935,13 +935,11 @@ void *IntToReference(uint r, uint t)
return NULL;
switch (t) {
case REF_ORDER: return GetOrder(r - 1);
case REF_VEHICLE: return GetVehicle(r - 1);
case REF_STATION: return GetStation(r - 1);
case REF_TOWN: return GetTown(r - 1);
case REF_SCHEDULE:
return (byte*)_order_array + (r - 1) * sizeof(_order_array[0]);
case REF_VEHICLE_OLD: {
/* Old vehicles were saved differently: invalid vehicle was 0xFFFF,
and the index was not - 1.. correct for this */

@ -70,11 +70,11 @@ typedef struct {
extern SaverLoader _sl;
enum {
REF_SCHEDULE = 0,
REF_VEHICLE = 1,
REF_STATION = 2,
REF_TOWN = 3,
REF_VEHICLE_OLD = 4,
REF_ORDER = 0,
REF_VEHICLE = 1,
REF_STATION = 2,
REF_TOWN = 3,
REF_VEHICLE_OLD = 4
};

@ -23,13 +23,13 @@ static byte GetTileShipTrackStatus(uint tile) {
void InvalidateShipWindows(const Vehicle *v)
{
const Order *o;
const Order *order;
InvalidateWindow(WC_SHIPS_LIST, v->owner);
for ( o = v->schedule_ptr; o->type != OT_NOTHING; o++) {
if (o->type == OT_GOTO_STATION ) {
InvalidateWindow(WC_SHIPS_LIST, o->station << 16 | v->owner);
FOR_VEHICLE_ORDERS(v, order) {
if (order->type == OT_GOTO_STATION ) {
InvalidateWindow(WC_SHIPS_LIST, (order->station << 16) | v->owner);
}
}
}
@ -113,7 +113,7 @@ static void CheckIfShipNeedsService(Vehicle *v)
v->current_order.flags & OF_FULL_LOAD)
return;
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
i = FindClosestShipDepot(v);
@ -215,8 +215,7 @@ static const TileIndexDiffC _dock_offs[] = {
static void ProcessShipOrder(Vehicle *v)
{
Order order;
Station *st;
const Order *order;
if (v->current_order.type >= OT_GOTO_DEPOT &&
v->current_order.type <= OT_LEAVESTATION) {
@ -235,36 +234,39 @@ static void ProcessShipOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
order = v->schedule_ptr[v->cur_order_index];
order = GetVehicleOrder(v, v->cur_order_index);
if (order.type == OT_NOTHING) {
v->current_order.type = OT_NOTHING;
if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
return;
}
if (order.type == v->current_order.type &&
order.flags == v->current_order.flags &&
order.station == v->current_order.station)
if (order->type == v->current_order.type &&
order->flags == v->current_order.flags &&
order->station == v->current_order.station)
return;
v->current_order = order;
v->current_order = *order;
if (order.type == OT_GOTO_STATION) {
if (order.station == v->last_station_visited)
if (order->type == OT_GOTO_STATION) {
const Station *st;
if (order->station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
st = GetStation(order.station);
st = GetStation(order->station);
if (st->dock_tile != 0) {
v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(_dock_offs[_map5[st->dock_tile]-0x4B]));
}
} else if (order.type == OT_GOTO_DEPOT) {
v->dest_tile = _depots[order.station].xy;
} else if (order->type == OT_GOTO_DEPOT) {
v->dest_tile = _depots[order->station].xy;
} else {
v->dest_tile = 0;
}
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
InvalidateShipWindows(v);
}
@ -301,7 +303,7 @@ static void HandleShipLoading(Vehicle *v)
}
v->cur_order_index++;
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
static void UpdateShipDeltaXY(Vehicle *v, int dir)
@ -692,7 +694,7 @@ static void ShipController(Vehicle *v)
v->last_station_visited = v->current_order.station;
/* Process station in the schedule. Don't do that for buoys (HVOT_BUOY) */
/* Process station in the orderlist. Don't do that for buoys (HVOT_BUOY) */
st = GetStation(v->current_order.station);
if (!(st->had_vehicle_of_type & HVOT_BUOY)
&& (st->facilities & FACIL_DOCK)) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
@ -711,7 +713,7 @@ static void ShipController(Vehicle *v)
v->current_order.type = OT_LEAVESTATION;
v->current_order.flags = 0;
v->cur_order_index++;
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
goto else_end;
}
@ -830,7 +832,7 @@ int32 CmdBuildShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return value;
v = AllocateVehicle();
if (v == NULL || _ptr_to_next_order >= endof(_order_array) ||
if (v == NULL || IsOrderPoolFull() ||
(unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships)
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
@ -871,9 +873,6 @@ int32 CmdBuildShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->string_id = STR_SV_SHIP_NAME;
v->u.ship.state = 0x80;
_ptr_to_next_order->type = OT_NOTHING;
_ptr_to_next_order->flags = 0;
v->schedule_ptr = _ptr_to_next_order++;
v->service_interval = _patches.servint_ships;
v->date_of_last_service = _date;

@ -863,15 +863,14 @@ void ShowShipDepotWindow(uint tile)
}
static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
Order *sched;
int sel;
Station *st;
int i = 0;
static void DrawSmallOrderList(Vehicle *v, int x, int y) {
const Order *order;
int sel, i = 0;
sel = v->cur_order_index;
order = v->orders;
for (sched = v->schedule_ptr; sched->type != OT_NOTHING; ++sched) {
while (order != NULL) {
if (sel == 0) {
_stringwidth_base = 0xE0;
DoDrawString( "\xAF", x-6, y, 16);
@ -879,11 +878,9 @@ static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
}
sel--;
if (sched->type == OT_GOTO_STATION) {
st = GetStation(sched->station);
if (!(st->had_vehicle_of_type & HVOT_BUOY)) {
SetDParam(0, sched->station);
if (order->type == OT_GOTO_STATION) {
if (!(GetStation(order->station)->had_vehicle_of_type & HVOT_BUOY)) {
SetDParam(0, order->station);
DrawString(x, y, STR_A036, 0);
y += 6;
@ -891,6 +888,8 @@ static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
break;
}
}
order = order->next;
}
}
@ -998,7 +997,7 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e)
DrawString(x + 12, y, STR_01AB, 0);
}
DrawSmallShipSchedule(v, x + 138, y);
DrawSmallOrderList(v, x + 138, y);
y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
}

@ -88,7 +88,7 @@ enum {
void ModifyStationRatingAround(TileIndex tile, byte owner, int amount, uint radius);
TileIndex GetStationTileForVehicle(Vehicle *v, Station *st);
TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st);
void ShowStationViewWindow(int station);
void UpdateAllStationVirtCoord();

@ -94,7 +94,7 @@ static Station *GetStationAround(uint tile, int w, int h, int closest_station)
return (closest_station == -1) ? NULL : GetStation(closest_station);
}
TileIndex GetStationTileForVehicle(Vehicle *v, Station *st)
TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
{
switch (v->type) {
case VEH_Train: return st->train_tile;
@ -2257,10 +2257,11 @@ static void DeleteStation(Station *st)
index = st->index;
DeleteWindowById(WC_STATION_VIEW, index);
order.type = OT_GOTO_STATION;
order.flags = 0;
order.station = index;
DeleteCommandFromVehicleSchedule(order);
DeleteDestinationFromVehicleOrder(order);
DeleteSubsidyWithStation(index);
}

@ -395,7 +395,7 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
if (!(flags & DC_QUERY_COST)) {
v = AllocateVehicle();
if (v == NULL || _ptr_to_next_order >= endof(_order_array))
if (v == NULL || IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
unit_num = GetFreeUnitNumber(VEH_Train);
@ -417,24 +417,13 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->u.rail.track = 0x80;
v->u.rail.first_engine = 0xffff;
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
// v->subtype = 0;
v->spritenum = rvi->image_index;
v->cargo_type = rvi->cargo_type;
v->cargo_cap = rvi->capacity;
v->max_speed = rvi->max_speed;
// v->cargo_count = 0;
v->value = value;
// v->day_counter = 0;
// v->current_order = 0;
// v->next_station = 0;
// v->load_unload_time_rem = 0;
// v->progress = 0;
// v->targetairport = 0;
// v->crash_anim_pos = 0;
v->last_station_visited = 0xFFFF;
v->dest_tile = 0;
// v->profit_last_year = 0;
// v->profit_this_year = 0;
v->engine_type = (byte)p1;
e = &_engines[p1];
@ -444,23 +433,10 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->max_age = e->lifelength * 366;
v->string_id = STR_SV_TRAIN_NAME;
// v->cur_speed = 0;
// v->subspeed = 0;
v->u.rail.railtype = e->railtype;
_new_train_id = v->index;
// v->cur_order_index = 0;
// v->num_orders = 0;
_ptr_to_next_order->type = OT_NOTHING;
_ptr_to_next_order->flags = 0;
v->schedule_ptr = _ptr_to_next_order++;
// v->next_in_chain = 0xffff;
// v->next = NULL;
v->service_interval = _patches.servint_trains;
// v->breakdown_ctr = 0;
// v->breakdowns_since_last_service = 0;
// v->unk4D = 0;
v->date_of_last_service = _date;
v->build_year = _cur_year;
v->type = VEH_Train;
@ -680,12 +656,9 @@ int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
// move the train to an empty line. for locomotives, we set the type to 0. for wagons, 4.
if (is_loco) {
if (src->subtype != 0) {
// setting the type to 0 also involves setting up the schedule_ptr field.
// setting the type to 0 also involves setting up the orders field.
src->subtype = 0;
assert(src->schedule_ptr == NULL);
_ptr_to_next_order->type = OT_NOTHING;
_ptr_to_next_order->flags = 0;
src->schedule_ptr = _ptr_to_next_order++;
assert(src->orders == NULL);
src->num_orders = 0;
}
dst_head = src;
@ -695,9 +668,9 @@ int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
src->u.rail.first_engine = 0xffff;
} else {
if (src->subtype == 0) {
// the vehicle was previously a loco. need to free the schedule list and delete vehicle windows etc.
// the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
DeleteWindowById(WC_VEHICLE_VIEW, src->index);
DeleteVehicleSchedule(src);
DeleteVehicleOrders(src);
}
src->subtype = 2;
@ -1644,13 +1617,13 @@ bad:;
static bool ProcessTrainOrder(Vehicle *v)
{
Order order;
const Order *order;
bool result;
// These are un-interruptible
if (v->current_order.type >= OT_GOTO_DEPOT &&
v->current_order.type <= OT_LEAVESTATION) {
// Let a depot order in the schedule interrupt.
// Let a depot order in the orderlist interrupt.
if (v->current_order.type != OT_GOTO_DEPOT ||
!(v->current_order.flags & OF_UNLOAD))
return false;
@ -1676,10 +1649,11 @@ static bool ProcessTrainOrder(Vehicle *v)
// Get the current order
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
order = v->schedule_ptr[v->cur_order_index];
order = GetVehicleOrder(v, v->cur_order_index);
// If no order, do nothing.
if (order.type == OT_NOTHING) {
if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
@ -1687,31 +1661,37 @@ static bool ProcessTrainOrder(Vehicle *v)
}
// If it is unchanged, keep it.
if (order.type == v->current_order.type &&
order.flags == v->current_order.flags &&
order.station == v->current_order.station)
if (order->type == v->current_order.type &&
order->flags == v->current_order.flags &&
order->station == v->current_order.station)
return false;
// Otherwise set it, and determine the destination tile.
v->current_order = order;
v->current_order = *order;
v->dest_tile = 0;
result = false;
if (order.type == OT_GOTO_STATION) {
if (order.station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
v->dest_tile = GetStation(order.station)->xy;
result = CheckReverseTrain(v);
} else if (order.type == OT_GOTO_DEPOT) {
v->dest_tile = _depots[order.station].xy;
result = CheckReverseTrain(v);
} else if (order.type == OT_GOTO_WAYPOINT) {
v->dest_tile = _waypoints[order.station].xy;
result = CheckReverseTrain(v);
switch (order->type) {
case OT_GOTO_STATION:
if (order->station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
v->dest_tile = GetStation(order->station)->xy;
result = CheckReverseTrain(v);
break;
case OT_GOTO_DEPOT:
v->dest_tile = _depots[order->station].xy;
result = CheckReverseTrain(v);
break;
case OT_GOTO_WAYPOINT:
v->dest_tile = _waypoints[order->station].xy;
result = CheckReverseTrain(v);
break;
}
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
return result;
}
@ -1771,7 +1751,7 @@ static void HandleTrainLoading(Vehicle *v, bool mode)
v->u.rail.days_since_order_progr = 0;
v->cur_order_index++;
InvalidateVehicleOrderWidget(v);
InvalidateVehicleOrder(v);
}
static int UpdateTrainSpeed(Vehicle *v)
@ -2669,7 +2649,7 @@ void TrainEnterDepot(Vehicle *v, uint tile)
v->current_order.type = OT_DUMMY;
v->current_order.flags = 0;
if (t.flags & OF_UNLOAD) { // Part of the schedule?
if (t.flags & OF_UNLOAD) { // Part of the orderlist?
v->u.rail.days_since_order_progr = 0;
v->cur_order_index++;
} else if (t.flags & OF_FULL_LOAD) { // User initiated?
@ -2701,7 +2681,7 @@ static void CheckIfTrainNeedsService(Vehicle *v)
if (v->vehstatus & VS_STOPPED)
return;
if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
// Don't interfere with a depot visit scheduled by the user, or a
@ -2834,11 +2814,3 @@ void InitializeTrains()
{
_age_cargo_skip_counter = 1;
}
int ScheduleHasDepotOrders(const Order *schedule)
{
for (; schedule->type != OT_NOTHING; schedule++)
if (schedule->type == OT_GOTO_DEPOT)
return true;
return false;
}

@ -496,6 +496,7 @@ static void InitializeDynamicVariables(void)
_industry_sort = NULL;
_sign_size = lengthof(_sign_list);
_orders_size = lengthof(_orders);
}
static void UnInitializeDynamicVariables(void)

@ -33,24 +33,6 @@ bool VehicleNeedsService(const Vehicle *v)
(v->date_of_last_service + v->service_interval < _date);
}
Order UnpackOldOrder(uint16 packed)
{
Order order;
order.type = (packed & 0x000f);
order.flags = (packed & 0x00f0) >> 4;
order.station = (packed & 0xff00) >> 8;
// Sanity check
// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
if (order.type == OT_NOTHING && (order.flags != 0 || order.station != 0)) {
order.type = OT_DUMMY;
order.flags = 0;
}
return order;
}
void VehicleInTheWayErrMsg(Vehicle *v)
{
StringID id;
@ -177,11 +159,6 @@ void AfterLoadVehicles()
if (v->subtype == 0)
UpdateTrainAcceleration(v);
}
#if defined(_DEBUG)
if (!(v->schedule_ptr == NULL || (v->schedule_ptr >= _order_array && v->schedule_ptr < _ptr_to_next_order)))
v->schedule_ptr = NULL;
#endif
}
}
@ -196,7 +173,7 @@ static Vehicle *InitializeVehicle(Vehicle *v)
memset(v, 0, sizeof(Vehicle));
v->index = index;
assert(v->schedule_ptr == NULL);
assert(v->orders == NULL);
v->left_coord = INVALID_COORD;
v->next = NULL;
@ -353,8 +330,6 @@ void InitializeVehicles()
v->index = i++;
memset(_vehicle_position_hash, -1, sizeof(_vehicle_position_hash));
_ptr_to_next_order = _order_array;
}
Vehicle *GetLastVehicleInChain(Vehicle *v)
@ -439,91 +414,6 @@ uint GetWaypointByTile(uint tile)
return i;
}
Vehicle *IsScheduleShared(Vehicle *u)
{
const Order *sched = u->schedule_ptr;
Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->schedule_ptr == sched && u != v && v->type != 0)
return v;
}
return NULL;
}
void DeleteVehicleSchedule(Vehicle *v)
{
Order *sched;
Order *cur;
int num;
Vehicle *u;
// if the schedule is shared, don't delete it.
if ((u = IsScheduleShared(v)) != NULL) {
v->schedule_ptr = NULL;
InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
return;
}
sched = v->schedule_ptr;
v->schedule_ptr = NULL;
num = v->num_orders + 1;
_ptr_to_next_order -= num;
cur = sched;
while (cur != _ptr_to_next_order) {
assert(cur < _ptr_to_next_order);
cur[0] = cur[num];
cur++;
}
FOR_ALL_VEHICLES(v) {
if (v->schedule_ptr != NULL && sched < v->schedule_ptr) {
v->schedule_ptr -= num;
}
}
}
void DeleteCommandFromVehicleSchedule(Order cmd)
{
Vehicle *v;
bool need_invalidate;
FOR_ALL_VEHICLES(v) {
if (v->type != 0 && v->schedule_ptr != NULL) {
Order *sched;
// clear last station visited
if (v->last_station_visited == cmd.station && cmd.type == OT_GOTO_STATION)
v->last_station_visited = 0xFFFF;
// check the next order
if (v->current_order.type == cmd.type &&
v->current_order.station == cmd.station) {
v->current_order.type = OT_DUMMY;
v->current_order.flags = 0;
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
}
// clear the order list
need_invalidate = false;
for (sched = v->schedule_ptr; sched->type != OT_NOTHING; ++sched) {
if (sched->type == cmd.type && sched->station == cmd.station) {
sched->type = OT_DUMMY;
sched->flags = 0;
need_invalidate = true;
}
}
if (need_invalidate)
InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
}
}
}
void DoDeleteDepot(uint tile)
{
Order order;
@ -538,9 +428,8 @@ void DoDeleteDepot(uint tile)
d->xy = 0;
order.type = OT_GOTO_DEPOT;
order.flags = 0;
order.station = dep_index;
DeleteCommandFromVehicleSchedule(order);
DeleteDestinationFromVehicleOrder(order);
// Delete the depot
DeleteWindowById(WC_VEHICLE_DEPOT, tile);
@ -553,8 +442,8 @@ void DeleteVehicle(Vehicle *v)
UpdateVehiclePosHash(v, INVALID_COORD, 0);
v->next_hash = 0xffff;
if (v->schedule_ptr != NULL)
DeleteVehicleSchedule(v);
if (v->orders != NULL)
DeleteVehicleOrders(v);
}
void DeleteVehicleChain(Vehicle *v)
@ -1699,12 +1588,6 @@ void EndVehicleMove(Vehicle *v)
);
}
void InvalidateVehicleOrderWidget(Vehicle *v)
{
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
InvalidateWindowWidget(WC_VEHICLE_ORDERS, v->index, 2);
}
/* returns true if staying in the same tile */
bool GetNewVehiclePos(Vehicle *v, GetNewVehiclePosResult *gp)
{
@ -1846,7 +1729,7 @@ const byte _common_veh_desc[] = {
SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, flags), SLE_UINT8, 5, 255),
SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, station), SLE_UINT16, 5, 255),
SLE_REF(Vehicle,schedule_ptr, REF_SCHEDULE),
SLE_REF(Vehicle,orders, REF_ORDER),
SLE_VAR(Vehicle,age, SLE_UINT16),
SLE_VAR(Vehicle,max_age, SLE_UINT16),
@ -1869,9 +1752,11 @@ const byte _common_veh_desc[] = {
SLE_VAR(Vehicle,random_bits, SLE_UINT8),
SLE_VAR(Vehicle,waiting_triggers, SLE_UINT8),
// reserve extra space in savegame here. (currently 14 bytes)
SLE_REF(Vehicle,next_shared, REF_VEHICLE),
SLE_REF(Vehicle,prev_shared, REF_VEHICLE),
// reserve extra space in savegame here. (currently 10 bytes)
SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 2, 2, 255), /* 2 */
SLE_CONDARR(NullStruct,null,SLE_FILE_U16 | SLE_VAR_NULL, 2, 2, 255), /* 4 */
SLE_CONDARR(NullStruct,null,SLE_FILE_U32 | SLE_VAR_NULL, 2, 2, 255), /* 8 */
SLE_END()
@ -2068,6 +1953,29 @@ static void Load_VEHS()
w->u.rail.first_engine = v->engine_type;
}
/* Check for shared order-lists (we now use pointers for that) */
if (_sl.full_version < 0x502) {
FOR_ALL_VEHICLES(v) {
Vehicle *u;
if (v->type == 0)
continue;
FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
if (u->type == 0)
continue;
/* If a vehicle has the same orders, add the link to eachother
in both vehicles */
if (v->orders == u->orders) {
v->next_shared = u;
u->prev_shared = v;
break;
}
}
}
}
/* This is to ensure all pointers are within the limits of
_vehicles_size */
if (_vehicle_id_ctr_day >= _vehicles_size)
@ -2131,55 +2039,8 @@ static void Load_CHKP()
}
}
static void Save_ORDR()
{
uint32 orders[lengthof(_order_array)];
uint len = _ptr_to_next_order - _order_array;
uint i;
assert (len <= lengthof(orders));
for (i = 0; i < len; ++i)
orders[i] = PackOrder(&_order_array[i]);
SlArray(orders, len, SLE_UINT32);
}
static void Load_ORDR()
{
uint len = SlGetFieldLength();
uint i;
if (_sl.version < 5) {
/* Older version had an other layout for orders.. convert them correctly */
uint16 orders[lengthof(_order_array)];
len /= sizeof(uint16);
assert (len <= lengthof(orders));
SlArray(orders, len, SLE_UINT16);
for (i = 0; i < len; ++i)
_order_array[i] = UnpackVersion4Order(orders[i]);
} else {
uint32 orders[lengthof(_order_array)];
len /= sizeof(uint32);
assert (len <= lengthof(orders));
SlArray(orders, len, SLE_UINT32);
for (i = 0; i < len; ++i)
_order_array[i] = UnpackOrder(orders[i]);
}
_ptr_to_next_order = _order_array + len;
}
const ChunkHandler _veh_chunk_handlers[] = {
{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY},
{ 'ORDR', Save_ORDR, Load_ORDR, CH_RIFF},
{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY},
{ 'CHKP', Save_CHKP, Load_CHKP, CH_ARRAY | CH_LAST},
};

@ -2,42 +2,7 @@
#define VEHICLE_H
#include "vehicle_gui.h"
/* If you change this, keep in mind that it is saved on 3 places:
- Load_ORDR, all the global orders
- Vehicle -> current_order
- REF_SHEDULE (all REFs are currently limited to 16 bits!!) */
typedef struct Order {
uint8 type;
uint8 flags;
uint16 station;
} Order;
static inline uint32 PackOrder(const Order *order)
{
return order->station << 16 | order->flags << 8 | order->type;
}
static inline Order UnpackOrder(uint32 packed)
{
Order order;
order.type = (packed & 0x000000FF);
order.flags = (packed & 0x0000FF00) >> 8;
order.station = (packed & 0xFFFF0000) >> 16;
return order;
}
static inline Order UnpackVersion4Order(uint16 packed)
{
Order order;
order.type = (packed & 0x000F);
order.flags = (packed & 0x00F0) >> 4;
order.station = (packed & 0xFF00) >> 8;
return order;
}
Order UnpackOldOrder(uint16 packed);
#include "order.h"
typedef struct VehicleRail {
uint16 last_speed; // NOSAVE: only used in UI
@ -177,11 +142,16 @@ struct Vehicle {
byte day_counter; // increased by one for each day
byte tick_counter;// increased by one for each tick
// related to the current order
byte cur_order_index;
byte num_orders;
Order current_order;
Order *schedule_ptr;
/* Begin Order-stuff */
Order current_order; //! The current order (+ status, like: loading)
byte cur_order_index; //! The index to the current order
Order *orders; //! Pointer to the first order for this vehicle
byte num_orders; //! How many orders there are in the list
Vehicle *next_shared; //! If not NULL, this points to the next vehicle that shared the order
Vehicle *prev_shared; //! If not NULL, this points to the prev vehicle that shared the order
/* End Order-stuff */
// Boundaries for the current position in the world and a next hash link.
// NOSAVE: All of those can be updated with VehiclePositionChanged()
@ -248,25 +218,6 @@ enum {
VEH_Disaster = 0x15,
};
/* Order types */
enum {
OT_NOTHING = 0,
OT_GOTO_STATION = 1,
OT_GOTO_DEPOT = 2,
OT_LOADING = 3,
OT_LEAVESTATION = 4,
OT_DUMMY = 5,
OT_GOTO_WAYPOINT = 6,
};
/* Order flags */
enum {
OF_UNLOAD = 0x2,
OF_FULL_LOAD = 0x4, // Also used when to force an aircraft into a depot
OF_NON_STOP = 0x8
};
enum VehStatus {
VS_HIDDEN = 1,
VS_STOPPED = 2,
@ -302,22 +253,11 @@ enum {
typedef void VehicleTickProc(Vehicle *v);
typedef void *VehicleFromPosProc(Vehicle *v, void *data);
typedef struct {
VehicleID clone;
byte orderindex;
Order order[41];
uint16 service_interval;
char name[32];
} BackuppedOrders;
void VehicleServiceInDepot(Vehicle *v);
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *order);
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order);
Vehicle *AllocateVehicle();
Vehicle *ForceAllocateVehicle();
Vehicle *ForceAllocateSpecialVehicle();
void UpdateVehiclePosHash(Vehicle *v, int x, int y);
void InitializeVehicles();
void VehiclePositionChanged(Vehicle *v);
void AfterLoadVehicles();
Vehicle *GetLastVehicleInChain(Vehicle *v);
@ -328,8 +268,6 @@ void DeleteVehicle(Vehicle *v);
void DeleteVehicleChain(Vehicle *v);
void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks();
void DeleteVehicleSchedule(Vehicle *v);
Vehicle *IsScheduleShared(Vehicle *v);
Depot *AllocateDepot();
Waypoint *AllocateWaypoint();
@ -373,16 +311,12 @@ void CheckVehicleBreakdown(Vehicle *v);
void AgeVehicle(Vehicle *v);
void MaybeReplaceVehicle(Vehicle *v);
void DeleteCommandFromVehicleSchedule(Order cmd);
void BeginVehicleMove(Vehicle *v);
void EndVehicleMove(Vehicle *v);
bool IsAircraftHangarTile(TileIndex tile);
void ShowAircraftViewWindow(Vehicle *v);
void InvalidateVehicleOrderWidget(Vehicle *v);
bool IsShipDepotTile(TileIndex tile);
uint GetFreeUnitNumber(byte type);
@ -397,9 +331,6 @@ int32 GetTrainRunningCost(Vehicle *v);
int CheckStoppedInDepot(Vehicle *v);
int ScheduleHasDepotOrders(const Order *schedule);
int CheckOrders(Vehicle *v);
bool VehicleNeedsService(const Vehicle *v);
void InvalidateAircraftWindows(const Vehicle *v);
@ -439,8 +370,43 @@ static inline Vehicle *GetVehicle(uint index)
#define FOR_ALL_VEHICLES(v) for(v = _vehicles; v != &_vehicles[_vehicles_size]; v++)
#define FOR_ALL_VEHICLES_FROM(v, from) for(v = GetVehicle(from); v != &_vehicles[_vehicles_size]; v++)
VARDEF Order _order_array[5000];
VARDEF Order *_ptr_to_next_order;
/* Returns order 'index' of a vehicle or NULL when it doesn't exists */
static inline Order *GetVehicleOrder(const Vehicle *v, int index)
{
Order *order = v->orders;
if (index < 0)
return NULL;
while (order != NULL && index-- > 0)
order = order->next;
return order;
}
/* Returns the last order of a vehicle, or NULL if it doesn't exists */
static inline Order *GetLastVehicleOrder(const Vehicle *v)
{
Order *order = v->orders;
if (order == NULL)
return NULL;
while (order->next != NULL)
order = order->next;
return order;
}
/* Get the first vehicle of a shared-list, so we only have to walk forwards */
static inline Vehicle *GetFirstVehicleFromSharedList(Vehicle *v)
{
Vehicle *u = v;
while (u->prev_shared != NULL)
u = u->prev_shared;
return u;
}
VARDEF Depot _depots[255];
@ -465,8 +431,6 @@ VARDEF TileIndex _last_built_train_depot_tile;
VARDEF TileIndex _last_built_road_depot_tile;
VARDEF TileIndex _last_built_aircraft_depot_tile;
VARDEF TileIndex _last_built_ship_depot_tile;
VARDEF TileIndex _backup_orders_tile;
VARDEF BackuppedOrders _backup_orders_data[1];
// for each player, for each vehicle type, keep a list of the vehicles.
//VARDEF Vehicle *_vehicle_arr[8][4];

@ -90,14 +90,16 @@ void BuildVehicleList(vehiclelist_d *vl, int type, int owner, int station)
const Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->subtype <= subtype) {
const Order *ord;
for (ord = v->schedule_ptr; ord->type != OT_NOTHING; ++ord)
if (ord->type == OT_GOTO_STATION && ord->station == station) {
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
if (order->type == OT_GOTO_STATION && order->station == station) {
_vehicle_sort[n].index = v->index;
_vehicle_sort[n].owner = v->owner;
++n;
break;
}
}
}
}
} else {

Loading…
Cancel
Save