src/station_cmd.cpp
branchnoai
changeset 9629 66dde6412125
parent 9628 b5c2449616b5
child 9631 8a2d1c2ceb88
--- a/src/station_cmd.cpp	Sun Jun 17 21:31:00 2007 +0000
+++ b/src/station_cmd.cpp	Tue Jun 26 23:40:58 2007 +0000
@@ -285,11 +285,7 @@
 	}
 
 	tmp = free_names & ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 12) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30));
-	if (tmp == 0) {
-		_error_message = STR_3007_TOO_MANY_STATIONS_LOADING;
-		return false;
-	}
-	found = FindFirstBit(tmp);
+	found = (tmp == 0) ? M(STR_SV_STNAME_FALLBACK) : FindFirstBit(tmp);
 
 done:
 	st->string_id = found + STR_SV_STNAME;
@@ -355,7 +351,7 @@
 	uint mask = 0;
 
 	for (CargoID i = 0; i < NUM_CARGO; i++) {
-		if (st->goods[i].waiting_acceptance & 0x8000) mask |= 1 << i;
+		if (st->goods[i].acceptance) mask |= 1 << i;
 	}
 	return mask;
 }
@@ -536,7 +532,7 @@
 				(is_passengers && !(st->facilities & (byte)~FACIL_TRUCK_STOP)))
 			amt = 0;
 
-		SB(st->goods[i].waiting_acceptance, 12, 4, amt);
+		st->goods[i].acceptance = (amt >= 8);
 	}
 
 	// Only show a message in case the acceptance was actually changed.
@@ -612,13 +608,13 @@
 	UpdateStationSignCoord(st);
 }
 
-static int32 ClearTile_Station(TileIndex tile, byte flags);
+static CommandCost ClearTile_Station(TileIndex tile, byte flags);
 
 // Tries to clear the given area. Returns the cost in case of success.
 // Or an error code if it failed.
-int32 CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station, bool check_clear = true)
+CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station, bool check_clear = true)
 {
-	int32 cost = 0;
+	CommandCost cost;
 	int allowed_z = -1;
 
 	BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
@@ -653,7 +649,7 @@
 					(invalid_dirs & 8 && !(tileh & SLOPE_NW) && (uint)h_cur == h)) {
 				return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 			}
-			cost += _price.terraform;
+			cost.AddCost(_price.terraform);
 			flat_z += TILE_HEIGHT;
 		}
 
@@ -680,9 +676,9 @@
 				}
 			}
 		} else if (check_clear) {
-			int32 ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+			CommandCost ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 			if (CmdFailed(ret)) return ret;
-			cost += ret;
+			cost.AddCost(ret);
 		}
 	} END_TILE_LOOP(tile_cur, w, h, tile)
 
@@ -801,10 +797,10 @@
  * - p2 = (bit  8-15) - custom station class
  * - p2 = (bit 16-23) - custom station id
  */
-int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint32 p2)
 {
 	int w_org, h_org;
-	int32 ret;
+	CommandCost ret;
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
@@ -838,7 +834,7 @@
 	//  for detail info, see: https://sourceforge.net/tracker/index.php?func=detail&aid=1029064&group_id=103924&atid=636365
 	ret = CheckFlatLandBelow(tile_org, w_org, h_org, flags & ~DC_EXEC, 5 << axis, _patches.nonuniform_stations ? &est : NULL);
 	if (CmdFailed(ret)) return ret;
-	int32 cost = ret + (numtracks * _price.train_station_track + _price.train_station_length) * plat_len;
+	CommandCost cost(ret.GetCost() + (numtracks * _price.train_station_track + _price.train_station_length) * plat_len);
 
 	Station *st = NULL;
 	bool check_surrounding = true;
@@ -1054,7 +1050,7 @@
  * @param p1 start_tile
  * @param p2 unused
  */
-int32 CmdRemoveFromRailroadStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdRemoveFromRailroadStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	TileIndex start = p1 == 0 ? tile : p1;
 
@@ -1121,11 +1117,11 @@
 	/* If we've not removed any tiles, give an error */
 	if (quantity == 0) return CMD_ERROR;
 
-	return _price.remove_rail_station * quantity;
+	return CommandCost(_price.remove_rail_station * quantity);
 }
 
 
-static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
+static CommandCost RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
 {
 	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
 	if (_current_player == OWNER_WATER && _patches.nonuniform_stations)
@@ -1142,7 +1138,7 @@
 
 	assert(w != 0 && h != 0);
 
-	int32 cost = 0;
+	CommandCost cost;
 	/* clear all areas of the station */
 	do {
 		int w_bak = w;
@@ -1151,7 +1147,7 @@
 			if (st->TileBelongsToRailStation(tile)) {
 				if (!EnsureNoVehicle(tile))
 					return CMD_ERROR;
-				cost += _price.remove_rail_station;
+				cost.AddCost(_price.remove_rail_station);
 				if (flags & DC_EXEC) {
 					Track track = GetRailStationTrack(tile);
 					DoClearSquare(tile);
@@ -1191,7 +1187,7 @@
  * @return            The cost and state of the operation
  * @retval CMD_ERROR  An error occured during the operation.
  */
-int32 DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
+CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
 {
 	const Station* st = GetStationByTile(tile);
 
@@ -1211,7 +1207,7 @@
 		YapfNotifyTrackLayoutChange(tile, GetRailStationTrack(tile));
 	}
 
-	return _price.build_rail / 2;
+	return CommandCost(_price.build_rail / 2);
 }
 
 /**
@@ -1243,7 +1239,7 @@
  *           bit 2..4: the roadtypes
  *           bit 5: allow stations directly adjacent to other stations.
  */
-int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	bool type = HASBIT(p2, 0);
 	bool is_drive_through = HASBIT(p2, 1);
@@ -1267,7 +1263,7 @@
 
 	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR;
 
-	int32 cost = 0;
+	CommandCost cost;
 
 	/* Not allowed to build over this road */
 	if (build_over_road) {
@@ -1340,7 +1336,7 @@
 		st->sign.width_1 = 0;
 	}
 
-	cost += (type) ? _price.build_truck_station : _price.build_bus_station;
+	cost.AddCost((type) ? _price.build_truck_station : _price.build_bus_station);
 
 	if (flags & DC_EXEC) {
 		// Insert into linked list of RoadStops
@@ -1371,7 +1367,7 @@
 }
 
 // Remove a bus station
-static int32 RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
+static CommandCost RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
 {
 	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner)) {
 		return CMD_ERROR;
@@ -1416,7 +1412,7 @@
 		DeleteStationIfEmpty(st);
 	}
 
-	return (is_truck) ? _price.remove_truck_station : _price.remove_bus_station;
+	return CommandCost((is_truck) ? _price.remove_truck_station : _price.remove_bus_station);
 }
 
 /** Remove a bus or truck stop
@@ -1425,7 +1421,7 @@
  * @param p1 not used
  * @param p2 bit 0: 0 for Bus stops, 1 for truck stops
  */
-int32 CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	/* Make sure the specified tile is a road stop of the correct type */
 	if (!IsTileType(tile, MP_STATION) || !IsRoadStop(tile) || (uint32)GetRoadStopType(tile) != p2) return CMD_ERROR;
@@ -1438,10 +1434,10 @@
 			DiagDirToRoadBits(GetRoadStopDir(tile));
 	bool is_towns_road = is_drive_through && GetStopBuiltOnTownRoad(tile);
 
-	int32 ret = RemoveRoadStop(st, flags, tile);
+	CommandCost ret = RemoveRoadStop(st, flags, tile);
 
 	/* If the stop was a drive-through stop replace the road */
-	if ((flags & DC_EXEC) && !CmdFailed(ret) && is_drive_through) {
+	if ((flags & DC_EXEC) && CmdSucceeded(ret) && is_drive_through) {
 		/* Rebuild the drive throuhg road stop. As a road stop can only be
 		 * removed by the owner of the roadstop, _current_player is the
 		 * owner of the road stop. */
@@ -1550,7 +1546,7 @@
  * @param p1 airport type, @see airport.h
  * @param p2 (bit 0) - allow airports directly adjacent to other airports.
  */
-int32 CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	bool airport_upgrade = true;
 
@@ -1582,9 +1578,9 @@
 	int w = afc->size_x;
 	int h = afc->size_y;
 
-	int32 ret = CheckFlatLandBelow(tile, w, h, flags, 0, NULL);
+	CommandCost ret = CheckFlatLandBelow(tile, w, h, flags, 0, NULL);
 	if (CmdFailed(ret)) return ret;
-	int32 cost = ret;
+	CommandCost cost(ret.GetCost());
 
 	Station *st = NULL;
 
@@ -1638,7 +1634,7 @@
 		}
 	}
 
-	cost += _price.build_airport * w * h;
+	cost.AddCost(_price.build_airport * w * h);
 
 	if (flags & DC_EXEC) {
 		st->airport_tile = tile;
@@ -1676,7 +1672,7 @@
 	return cost;
 }
 
-static int32 RemoveAirport(Station *st, uint32 flags)
+static CommandCost RemoveAirport(Station *st, uint32 flags)
 {
 	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
 		return CMD_ERROR;
@@ -1687,7 +1683,7 @@
 	int w = afc->size_x;
 	int h = afc->size_y;
 
-	int32 cost = w * h * _price.remove_airport;
+	CommandCost cost(w * h * _price.remove_airport);
 
 	Vehicle *v;
 	FOR_ALL_VEHICLES(v) {
@@ -1730,7 +1726,7 @@
  * @param p1 unused
  * @param p2 unused
  */
-int32 CmdBuildBuoy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildBuoy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
@@ -1769,7 +1765,7 @@
 		st_auto_delete.Release();
 	}
 
-	return _price.build_dock;
+	return CommandCost(_price.build_dock);
 }
 
 /* Checks if any ship is servicing the buoy specified. Returns yes or no */
@@ -1789,7 +1785,7 @@
 	return false;
 }
 
-static int32 RemoveBuoy(Station *st, uint32 flags)
+static CommandCost RemoveBuoy(Station *st, uint32 flags)
 {
 	/* XXX: strange stuff */
 	if (!IsValidPlayer(_current_player))  return_cmd_error(INVALID_STRING_ID);
@@ -1821,7 +1817,7 @@
 		DeleteStationIfEmpty(st);
 	}
 
-	return _price.remove_truck_station;
+	return CommandCost(_price.remove_truck_station);
 }
 
 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
@@ -1839,9 +1835,9 @@
  * @param p1 (bit 0) - allow docks directly adjacent to other docks.
  * @param p2 unused
  */
-int32 CmdBuildDock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildDock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	int32 cost;
+	CommandCost cost;
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
@@ -1935,10 +1931,10 @@
 		/* success, so don't delete the new station */
 		st_auto_delete.Release();
 	}
-	return _price.build_dock;
+	return CommandCost(_price.build_dock);
 }
 
-static int32 RemoveDock(Station *st, uint32 flags)
+static CommandCost RemoveDock(Station *st, uint32 flags)
 {
 	if (!CheckOwnership(st->owner)) return CMD_ERROR;
 
@@ -1964,7 +1960,7 @@
 		DeleteStationIfEmpty(st);
 	}
 
-	return _price.remove_dock;
+	return CommandCost(_price.remove_dock);
 }
 
 #include "table/station_land.h"
@@ -2347,11 +2343,10 @@
 		/* Slowly increase the rating back to his original level in the case we
 		 *  didn't deliver cargo yet to this station. This happens when a bribe
 		 *  failed while you didn't moved that cargo yet to a station. */
-		if (ge->enroute_from == INVALID_STATION && ge->rating < INITIAL_STATION_RATING)
+		if (ge->days_since_pickup == 255 && ge->rating < INITIAL_STATION_RATING)
 			ge->rating++;
 		/* Only change the rating if we are moving this cargo */
-		if (ge->enroute_from != INVALID_STATION) {
-			byte_inc_sat(&ge->enroute_time);
+		if (ge->last_speed != 0) {
 			byte_inc_sat(&ge->days_since_pickup);
 
 			int rating = 0;
@@ -2383,7 +2378,7 @@
 				(rating += 35, true);
 			}
 
-			int waiting = GB(ge->waiting_acceptance, 0, 12);
+			uint waiting = ge->cargo.Count();
 			(rating -= 90, waiting > 1500) ||
 			(rating += 55, waiting > 1000) ||
 			(rating += 35, waiting > 600) ||
@@ -2409,12 +2404,13 @@
 				if (rating <= 127 && waiting != 0) {
 					uint32 r = Random();
 					if (rating <= (int)GB(r, 0, 7)) {
-						waiting = max(waiting - (int)GB(r, 8, 2) - 1, 0);
+						/* Need to have int, otherwise it will just overflow etc. */
+						waiting = max((int)waiting - (int)GB(r, 8, 2) - 1, 0);
 						waiting_changed = true;
 					}
 				}
 
-				if (waiting_changed) SB(ge->waiting_acceptance, 0, 12, waiting);
+				if (waiting_changed) ge->cargo.Truncate(waiting);
 			}
 		}
 	} while (++ge != endof(st->goods));
@@ -2467,7 +2463,7 @@
 			for (CargoID i = 0; i < NUM_CARGO; i++) {
 				GoodsEntry* ge = &st->goods[i];
 
-				if (ge->enroute_from != INVALID_STATION) {
+				if (ge->days_since_pickup != 255) {
 					ge->rating = clamp(ge->rating + amount, 0, 255);
 				}
 			}
@@ -2477,13 +2473,8 @@
 
 static void UpdateStationWaiting(Station *st, CargoID type, uint amount)
 {
-	SB(st->goods[type].waiting_acceptance, 0, 12,
-		min(0xFFF, GB(st->goods[type].waiting_acceptance, 0, 12) + amount)
-	);
-
-	st->goods[type].enroute_time = 0;
-	st->goods[type].enroute_from = st->index;
-	st->goods[type].enroute_from_xy = st->xy;
+	st->goods[type].cargo.Append(new CargoPacket(st->index, amount));
+
 	InvalidateWindow(WC_STATION_VIEW, st->index);
 	st->MarkTilesDirty(true);
 }
@@ -2494,7 +2485,7 @@
  * @param p1 station ID that is to be renamed
  * @param p2 unused
  */
-int32 CmdRenameStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdRenameStation(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	if (!IsValidStationID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
 	Station *st = GetStation(p1);
@@ -2516,7 +2507,7 @@
 		DeleteName(str);
 	}
 
-	return 0;
+	return CommandCost();
 }
 
 
@@ -2553,7 +2544,7 @@
 			if (around[i] == NULL) {
 				if (!st->IsBuoy() &&
 						(st->town->exclusive_counter == 0 || st->town->exclusivity == st->owner) && // check exclusive transport rights
-						st->goods[type].rating != 0 &&
+						st->goods[type].rating != 0 && st->goods[type].last_speed != 0 && // we actually service the station
 						(!_patches.selectgoods || st->goods[type].last_speed > 0) && // if last_speed is 0, no vehicle has been there.
 						((st->facilities & ~FACIL_BUS_STOP)   != 0 || IsCargoInClass(type, CC_PASSENGERS)) && // if we have other fac. than a bus stop, or the cargo is passengers
 						((st->facilities & ~FACIL_TRUCK_STOP) != 0 || !IsCargoInClass(type, CC_PASSENGERS))) { // if we have other fac. than a cargo bay or the cargo is not passengers
@@ -2683,10 +2674,8 @@
 	st->build_date = _date;
 
 	for (CargoID j = 0; j < NUM_CARGO; j++) {
-		st->goods[j].waiting_acceptance = 0;
-		st->goods[j].days_since_pickup = 0;
-		st->goods[j].enroute_from = INVALID_STATION;
-		st->goods[j].enroute_from_xy = INVALID_TILE;
+		st->goods[j].acceptance = false;
+		st->goods[j].days_since_pickup = 255;
 		st->goods[j].rating = INITIAL_STATION_RATING;
 		st->goods[j].last_speed = 0;
 		st->goods[j].last_age = 255;
@@ -2748,7 +2737,7 @@
 				CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_TRAM), OWNER_TOWN, &edge_road, ROADTYPE_TRAM);
 }
 
-static int32 ClearTile_Station(TileIndex tile, byte flags)
+static CommandCost ClearTile_Station(TileIndex tile, byte flags)
 {
 	if (flags & DC_AUTO) {
 		switch (GetStationType(tile)) {
@@ -2810,6 +2799,8 @@
 
 			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
 		}
+
+		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
 	}
 }
 
@@ -2906,18 +2897,27 @@
 	SLE_END()
 };
 
+static uint16 _waiting_acceptance;
+static uint16 _cargo_source;
+static uint32 _cargo_source_xy;
+static uint16 _cargo_days;
+static Money  _cargo_feeder_share;
+
 static const SaveLoad _goods_desc[] = {
-	    SLE_VAR(GoodsEntry, waiting_acceptance, SLE_UINT16),
-	SLE_CONDVAR(GoodsEntry, unload_pending,     SLE_UINT16,                51, SL_MAX_VERSION),
-	    SLE_VAR(GoodsEntry, days_since_pickup,  SLE_UINT8),
-	    SLE_VAR(GoodsEntry, rating,             SLE_UINT8),
-	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_FILE_U8 | SLE_VAR_U16,  0, 6),
-	SLE_CONDVAR(GoodsEntry, enroute_from,       SLE_UINT16,                 7, SL_MAX_VERSION),
-	SLE_CONDVAR(GoodsEntry, enroute_from_xy,    SLE_UINT32,                44, SL_MAX_VERSION),
-	    SLE_VAR(GoodsEntry, enroute_time,       SLE_UINT8),
-	    SLE_VAR(GoodsEntry, last_speed,         SLE_UINT8),
-	    SLE_VAR(GoodsEntry, last_age,           SLE_UINT8),
-	SLE_CONDVAR(GoodsEntry, feeder_profit,      SLE_INT32,                 14, SL_MAX_VERSION),
+	SLEG_CONDVAR(            _waiting_acceptance, SLE_UINT16,                  0, 67),
+	 SLE_CONDVAR(GoodsEntry, acceptance,          SLE_BOOL,                   68, SL_MAX_VERSION),
+	SLE_CONDNULL(2,                                                           51, 67),
+	     SLE_VAR(GoodsEntry, days_since_pickup,   SLE_UINT8),
+	     SLE_VAR(GoodsEntry, rating,              SLE_UINT8),
+	SLEG_CONDVAR(            _cargo_source,       SLE_FILE_U8 | SLE_VAR_U16,   0, 6),
+	SLEG_CONDVAR(            _cargo_source,       SLE_UINT16,                  7, 67),
+	SLEG_CONDVAR(            _cargo_source_xy,    SLE_UINT32,                 44, 67),
+	SLEG_CONDVAR(            _cargo_days,         SLE_UINT8,                   0, 67),
+	     SLE_VAR(GoodsEntry, last_speed,          SLE_UINT8),
+	     SLE_VAR(GoodsEntry, last_age,            SLE_UINT8),
+	SLEG_CONDVAR(            _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64),
+	SLEG_CONDVAR(            _cargo_feeder_share, SLE_INT64,                  65, 67),
+	 SLE_CONDLST(GoodsEntry, cargo,               REF_CARGO_PACKET,           68, SL_MAX_VERSION),
 
 	SLE_END()
 };
@@ -2934,9 +2934,30 @@
 {
 	SlObject(st, _station_desc);
 
+	_waiting_acceptance = 0;
+
 	uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
 	for (CargoID i = 0; i < num_cargo; i++) {
-		SlObject(&st->goods[i], _goods_desc);
+		GoodsEntry *ge = &st->goods[i];
+		SlObject(ge, _goods_desc);
+		if (CheckSavegameVersion(68)) {
+			ge->acceptance = HASBIT(_waiting_acceptance, 15);
+			if (GB(_waiting_acceptance, 0, 12) != 0) {
+				/* Don't construct the packet with station here, because that'll fail with old savegames */
+				CargoPacket *cp = new CargoPacket();
+				/* In old versions, enroute_from used 0xFF as INVALID_STATION */
+				cp->source          = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
+				cp->count           = GB(_waiting_acceptance, 0, 12);
+				cp->days_in_transit = _cargo_days;
+				cp->feeder_share    = _cargo_feeder_share;
+				cp->source_xy       = _cargo_source_xy;
+				cp->days_in_transit = _cargo_days;
+				cp->feeder_share    = _cargo_feeder_share;
+				ge->cargo.Append(cp);
+			} else {
+				ge->days_since_pickup = 255;
+			}
+		}
 	}
 
 	if (st->num_specs != 0) {