summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbjarni <bjarni@openttd.org>2005-11-07 23:20:47 +0000
committerbjarni <bjarni@openttd.org>2005-11-07 23:20:47 +0000
commitdf6c48fdba7933e30a16c82e69d8d57ab9515e6d (patch)
tree419d4e9a7f19cca429bc209799068506c9d20f9d
parent1258ca0bf0beeb045a6f039c900f31658b8c331b (diff)
downloadopenttd-df6c48fdba7933e30a16c82e69d8d57ab9515e6d.tar.xz
(svn r3155) -Feature: [autoreplace] autoreplace can now remove cars from too long trains
-Trains will now remember the length of stations it visits and sell cars when being autoreplaced if they became too long -If it needs to remove cars, then it starts from the front and sells all it can find until the train is short enough -This only works for trains, that knows the station length of the route so a full uninterrupted run is needed -a train needs 1-2 runs to detect if the shortest station is expanded -This feature can be turned on and off in the train replace window and each company can have it's own setting -NOTE: minor savegame version bump
-rw-r--r--lang/english.txt3
-rw-r--r--openttd.c17
-rw-r--r--order_cmd.c4
-rw-r--r--player.h1
-rw-r--r--players.c23
-rw-r--r--saveload.c2
-rw-r--r--station.h5
-rw-r--r--station_cmd.c5
-rw-r--r--train_cmd.c24
-rw-r--r--vehicle.c35
-rw-r--r--vehicle.h11
-rw-r--r--vehicle_gui.c13
12 files changed, 129 insertions, 14 deletions
diff --git a/lang/english.txt b/lang/english.txt
index fc542bb06..e078a9cb0 100644
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -943,6 +943,7 @@ STR_TRAIN_AUTORENEW_FAILED :{WHITE}Autorene
STR_ROADVEHICLE_AUTORENEW_FAILED :{WHITE}Autorenew failed on road vehicle {COMMA} (money limit)
STR_SHIP_AUTORENEW_FAILED :{WHITE}Autorenew failed on ship {COMMA} (money limit)
STR_AIRCRAFT_AUTORENEW_FAILED :{WHITE}Autorenew failed on aircraft {COMMA} (money limit)
+STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}Train {COMMA} is too long after replacement
STR_CONFIG_PATCHES :{BLACK}Configure Patches
STR_CONFIG_PATCHES_TIP :{BLACK}Configure the patches
@@ -2752,6 +2753,8 @@ STR_REPLACE_HELP_START_BUTTON :{BLACK}Press to
STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the railtype you want to replace engines for
STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any
STR_REPLACE_HELP :{BLACK}This allows you to replace one engine type with another type, when trains of the original type enter a depot
+STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{SKIP}{STRING}
+STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Setting this to "On" will make autoreplace remove wagons from trains to make them keep their length if they exceed length of the shortest station in their orders.{}It will remove as many wagons as needed starting from the front
STR_SHORT_DATE :{WHITE}{DATE_TINY}
STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s}
diff --git a/openttd.c b/openttd.c
index f6f3a61f6..1229b24f9 100644
--- a/openttd.c
+++ b/openttd.c
@@ -1300,6 +1300,23 @@ bool AfterLoadGame(uint version)
}
}
+ /* In version 16.1 of the savegame, trains became aware of station lengths
+ need to initialized to the invalid state
+ players needs to set renew_keep_length too */
+ if (version < 0x1001) {
+ Vehicle *v;
+ FOR_ALL_PLAYERS(p) {
+ p->renew_keep_length = false;
+ }
+
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Train) {
+ v->u.rail.shortest_platform[0] = 255;
+ v->u.rail.shortest_platform[1] = 0;
+ }
+ }
+ }
+
FOR_ALL_PLAYERS(p) {
p->avail_railtypes = GetPlayerRailtypes(p->index);
}
diff --git a/order_cmd.c b/order_cmd.c
index 227152cde..fda452ba8 100644
--- a/order_cmd.c
+++ b/order_cmd.c
@@ -388,6 +388,7 @@ int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
}
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u);
+ if (u->type == VEH_Train) u->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
u = u->next_shared;
}
@@ -520,6 +521,7 @@ int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
v->current_order.flags = 0;
+ if (v->type == VEH_Train) v->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
InvalidateVehicleOrder(v);
}
@@ -663,6 +665,7 @@ int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
InvalidateVehicleOrder(src);
RebuildVehicleLists();
+ if (dst->type == VEH_Train) dst->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
}
} break;
@@ -722,6 +725,7 @@ int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
InvalidateVehicleOrder(dst);
RebuildVehicleLists();
+ if (dst->type == VEH_Train) dst->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
}
} break;
diff --git a/player.h b/player.h
index b00a0f9e3..1bfaa0f04 100644
--- a/player.h
+++ b/player.h
@@ -190,6 +190,7 @@ typedef struct Player {
PlayerEconomyEntry old_economy[24];
EngineID engine_replacement[TOTAL_NUM_ENGINES];
bool engine_renew;
+ bool renew_keep_length;
int16 engine_renew_months;
uint32 engine_renew_money;
} Player;
diff --git a/players.c b/players.c
index 59ad5bf36..a9629a716 100644
--- a/players.c
+++ b/players.c
@@ -497,6 +497,7 @@ Player *DoStartupNewPlayer(bool is_ai)
for (i = 0; i < TOTAL_NUM_ENGINES; i++)
p->engine_replacement[i] = INVALID_ENGINE;
+ p->renew_keep_length = false;
p->engine_renew = false;
p->engine_renew_months = -6;
p->engine_renew_money = 100000;
@@ -654,6 +655,7 @@ static void DeletePlayerStuff(PlayerID pi)
* - p1 = 2 - change auto renew money
* - p1 = 3 - change auto renew array
* - p1 = 4 - change bool, months & money all together
+ * - p1 = 5 - change renew_keep_length
* @param p2 value to set
* if p1 = 0, then:
* - p2 = enable engine renewal
@@ -668,6 +670,8 @@ static void DeletePlayerStuff(PlayerID pi)
* - p1 bit 15 = enable engine renewal
* - p1 bits 16-31 = months left before engine expires to replace it
* - p2 bits 0-31 = minimum amount of money available
+ * if p1 = 5, then
+ * - p2 = enable renew_keep_length
*/
int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
@@ -754,8 +758,19 @@ int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
}
}
break;
- }
+ case 5:
+ if (p->renew_keep_length == (bool)GB(p2, 0, 1))
+ return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ p->renew_keep_length = (bool)GB(p2, 0, 1);
+ if (IsLocalPlayer()) {
+ InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
+ }
+ }
+ break;
+ }
return 0;
}
@@ -1131,9 +1146,11 @@ static const SaveLoad _player_desc[] = {
SLE_CONDVAR(Player,engine_renew, SLE_UINT8, 16, 255),
SLE_CONDVAR(Player,engine_renew_months, SLE_INT16, 16, 255),
SLE_CONDVAR(Player,engine_renew_money, SLE_UINT32, 16, 255),
+ SLE_CONDVAR(Player,renew_keep_length, SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2
- // reserve extra space in savegame here. (currently 64 bytes)
- SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 8, 2, 255),
+ // reserve extra space in savegame here. (currently 63 bytes)
+ SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 7, 2, 255),
+ SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 7, 2, 255),
SLE_END()
};
diff --git a/saveload.c b/saveload.c
index 499bd3006..05bfb4475 100644
--- a/saveload.c
+++ b/saveload.c
@@ -30,7 +30,7 @@
enum {
SAVEGAME_MAJOR_VERSION = 16,
- SAVEGAME_MINOR_VERSION = 0,
+ SAVEGAME_MINOR_VERSION = 1,
SAVEGAME_LOADABLE_VERSION = (SAVEGAME_MAJOR_VERSION << 8) + SAVEGAME_MINOR_VERSION
};
diff --git a/station.h b/station.h
index 7b72ab29d..45f88fa9c 100644
--- a/station.h
+++ b/station.h
@@ -320,6 +320,11 @@ static inline bool IsBuoyTile(TileIndex tile)
return IsTileType(tile, MP_STATION) && _m[tile].m5 == 0x52;
}
+static inline bool TileBelongsToRailStation(const Station *st, TileIndex tile)
+{
+ return IsTileType(tile, MP_STATION) && _m[tile].m2 == st->index && _m[tile].m5 < 8;
+}
+
/* Get's the direction the station exit points towards. Ie, returns 0 for a
* station with the exit NE. */
static inline byte GetRoadStationDir(TileIndex tile)
diff --git a/station_cmd.c b/station_cmd.c
index 1a5e81bda..ec643fcf7 100644
--- a/station_cmd.c
+++ b/station_cmd.c
@@ -1083,11 +1083,6 @@ int32 CmdBuildRailroadStation(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return cost;
}
-static bool TileBelongsToRailStation(const Station *st, TileIndex tile)
-{
- return IsTileType(tile, MP_STATION) && _m[tile].m2 == st->index && _m[tile].m5 < 8;
-}
-
static void MakeRailwayStationAreaSmaller(Station *st)
{
uint w = st->trainst_w;
diff --git a/train_cmd.c b/train_cmd.c
index 0e79e76a0..e5daaf014 100644
--- a/train_cmd.c
+++ b/train_cmd.c
@@ -752,6 +752,9 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->type = VEH_Train;
v->cur_image = 0xAC2;
+ v->u.rail.shortest_platform[0] = 255;
+ v->u.rail.shortest_platform[1] = 0;
+
VehiclePositionChanged(v);
if (rvi->flags & RVI_MULTIHEAD && !HASBIT(p2, 0)) {
@@ -2349,6 +2352,27 @@ static bool ProcessTrainOrder(Vehicle *v)
v->dest_tile = 0;
+ // store the station length if no shorter station was visited this order round
+ if (v->cur_order_index == 0) {
+ if (v->u.rail.shortest_platform[1] != 0 && v->u.rail.shortest_platform[1] != 255) {
+ // we went though a whole round of orders without interruptions, so we store the length of the shortest station
+ v->u.rail.shortest_platform[0] = v->u.rail.shortest_platform[1];
+ }
+ // all platforms are shorter than 255, so now we can find the shortest in the next order round. They might have changed size
+ v->u.rail.shortest_platform[1] = 255;
+ }
+
+ if (v->last_station_visited != INVALID_STATION) {
+ Station *st = GetStation(v->last_station_visited);
+ if (TileBelongsToRailStation(st, v->tile)) {
+ byte length = GetStationPlatforms(st, v->tile);
+
+ if (length < v->u.rail.shortest_platform[1]) {
+ v->u.rail.shortest_platform[1] = length;
+ }
+ }
+ }
+
result = false;
switch (order->type) {
case OT_GOTO_STATION:
diff --git a/vehicle.c b/vehicle.c
index ff327d25c..ece0547b4 100644
--- a/vehicle.c
+++ b/vehicle.c
@@ -1693,6 +1693,8 @@ static int32 ReplaceVehicle(Vehicle **w, byte flags)
if (old_v->type == VEH_Train){
// move the entire train to the new engine, including the old engine. It will be sold in a moment anyway
DoCommand(0, 0, (new_v->index << 16) | old_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
+ new_v->u.rail.shortest_platform[0] = old_v->u.rail.shortest_platform[0];
+ new_v->u.rail.shortest_platform[1] = old_v->u.rail.shortest_platform[1];
}
}
}
@@ -1720,6 +1722,7 @@ static void MaybeReplaceVehicle(Vehicle *v)
byte flags = 0;
int32 cost, temp_cost = 0;
bool stopped = false;
+ bool train_fits_in_station = false;
_current_player = v->owner;
@@ -1733,6 +1736,11 @@ static void MaybeReplaceVehicle(Vehicle *v)
stopped = true;
}
+ if (v->type == VEH_Train && v->u.rail.shortest_platform[0]*16 <= v->u.rail.cached_total_length && GetPlayer(v->owner)->renew_keep_length) {
+ // the train is not too long for the stations it visits. We should try to keep it that way if we change anything
+ train_fits_in_station = true;
+ }
+
while (true) {
cost = 0;
w = v;
@@ -1794,6 +1802,27 @@ static void MaybeReplaceVehicle(Vehicle *v)
flags |= DC_EXEC;
}
+ if (train_fits_in_station) {
+ // the train fitted in the stations it got in it's orders, so we should make sure that it still do
+ Vehicle *temp;
+ w = v;
+ while (v->u.rail.shortest_platform[0]*16 < v->u.rail.cached_total_length) {
+ // the train is too long. We will remove cars one by one from the start of the train until it's short enough
+ while (w != NULL && !(RailVehInfo(w->engine_type)->flags&RVI_WAGON) ) {
+ w = GetNextVehicle(w);
+ }
+ if (w == NULL) {
+ // we failed to make the train short enough
+ SetDParam(0, v->unitnumber);
+ AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+ break;
+ }
+ temp = w;
+ w = GetNextVehicle(w);
+ cost += DoCommand(0, 0, temp->index, 0, flags, CMD_SELL_VEH(temp->type));
+ }
+ }
+
if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
if (stopped)
@@ -2085,8 +2114,10 @@ static const SaveLoad _train_desc[] = {
SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_status), SLE_UINT8, 2, 255),
SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_tile), SLE_UINT32, 2, 255),
SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_trackdir), SLE_UINT8, 2, 255),
- // reserve extra space in savegame here. (currently 7 bytes)
- SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 7, 2, 255),
+ SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[0]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2
+ SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[1]), SLE_UINT8, 2, 255), // added with 16.1, but was blank since 2
+ // reserve extra space in savegame here. (currently 5 bytes)
+ SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 5, 2, 255),
SLE_END()
};
diff --git a/vehicle.h b/vehicle.h
index 91921d4ba..f5eb66db6 100644
--- a/vehicle.h
+++ b/vehicle.h
@@ -85,6 +85,14 @@ typedef struct VehicleRail {
byte pbs_status;
TileIndex pbs_end_tile;
Trackdir pbs_end_trackdir;
+
+ /**
+ * stuff to figure out how long a train should be. Used by autoreplace
+ * first byte holds the length of the shortest station. Updated each time order 0 is reached
+ * last byte is the shortest station reached this round though the orders. It can be invalidated by
+ * skip station and alike by setting it to 0. That way we will ensure that a complete loop is used to find the shortest station
+ */
+ byte shortest_platform[2];
} VehicleRail;
enum {
@@ -177,7 +185,6 @@ struct Vehicle {
int32 x_pos; // coordinates
int32 y_pos;
- bool leave_depot_instantly; // NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
byte z_pos;
byte direction; // facing
@@ -248,6 +255,8 @@ struct Vehicle {
byte breakdown_chance;
byte build_year;
+ bool leave_depot_instantly; // NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
+
uint16 load_unload_time_rem;
int32 profit_this_year;
diff --git a/vehicle_gui.c b/vehicle_gui.c
index 9edb40caa..ebe2afebc 100644
--- a/vehicle_gui.c
+++ b/vehicle_gui.c
@@ -748,10 +748,10 @@ static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int
static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
{
static const StringID _vehicle_type_names[4] = {STR_019F_TRAIN, STR_019C_ROAD_VEHICLE, STR_019E_SHIP,STR_019D_AIRCRAFT};
+ const Player *p = GetPlayer(_local_player);
switch (e->event) {
case WE_PAINT: {
- const Player *p = GetPlayer(_local_player);
int pos = w->vscroll.pos;
int selected_id[2] = {-1,-1};
int x = 1;
@@ -839,6 +839,12 @@ static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
// now the actual drawing of the window itself takes place
SetDParam(0, _vehicle_type_names[WP(w, replaceveh_d).vehicletype - VEH_Train]);
+
+ if (WP(w, replaceveh_d).vehicletype == VEH_Train) {
+ // set on/off for renew_keep_length
+ SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+ }
+
DrawWindowWidgets(w);
// sets up the string for the vehicle that is being replaced to
@@ -925,6 +931,9 @@ static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
ShowDropDownMenu(w, _rail_types_list, _railtype_selected_in_replace_gui, 15, 0, ~GetPlayer(_local_player)->avail_railtypes);
break;
}
+ case 17: { /* toggle renew_keep_length */
+ DoCommandP(0, 5, p->renew_keep_length ? 0 : 1, NULL, CMD_REPLACE_VEHICLE);
+ } break;
case 4: { /* Start replacing */
EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
EngineID veh_to = WP(w, replaceveh_d).sel_engine[1];
@@ -991,7 +1000,7 @@ static const Widget _replace_rail_vehicle_widgets[] = {
{ WWT_PANEL, RESIZE_TB, 14, 154, 277, 210, 221, STR_NULL, STR_REPLACE_HELP_RAILTYPE},
{ WWT_CLOSEBOX, RESIZE_TB, 14, 278, 289, 210, 221, STR_0225, STR_REPLACE_HELP_RAILTYPE},
{ WWT_PANEL, RESIZE_TB, 14, 290, 305, 210, 221, STR_NULL, STR_NULL},
-{ WWT_PANEL, RESIZE_TB, 14, 317, 455, 198, 209, STR_NULL, STR_NULL},
+{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 317, 455, 198, 209, STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP},
// end of train specific stuff
{ WWT_RESIZEBOX, RESIZE_TB, 14, 444, 455, 210, 221, STR_NULL, STR_RESIZE_BUTTON},
{ WIDGETS_END},