--- a/src/economy.cpp Sun Jun 17 21:31:00 2007 +0000
+++ b/src/economy.cpp Tue Jun 26 23:40:58 2007 +0000
@@ -57,10 +57,11 @@
int _score_part[MAX_PLAYERS][SCORE_END];
-int64 CalculateCompanyValue(const Player* p)
+Money CalculateCompanyValue(const Player* p)
{
PlayerID owner = p->index;
- int64 value;
+ /* Do a little nasty by using CommandCost, so we can use the "overflow" protection of CommandCost */
+ CommandCost value;
{
Station *st;
@@ -70,7 +71,7 @@
if (st->owner == owner) num += CountBitsSet(st->facilities);
}
- value = num * _price.station_value * 25;
+ value.AddCost(num * _price.station_value * 25);
}
{
@@ -83,14 +84,16 @@
v->type == VEH_ROAD ||
(v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) ||
v->type == VEH_SHIP) {
- value += v->value * 3 >> 1;
+ value.AddCost(v->value * 3 >> 1);
}
}
}
- value += p->money64 - p->current_loan; // add real money value
+ /* Add real money value */
+ value.AddCost(-p->current_loan);
+ value.AddCost(p->player_money);
- return max(value, 1LL);
+ return max(value.GetCost(), 1LL);
}
/** if update is set to true, the economy is updated with this score
@@ -109,7 +112,7 @@
/* Count vehicles */
{
Vehicle *v;
- int32 min_profit = 0;
+ Money min_profit = 0;
bool min_profit_first = true;
uint num = 0;
@@ -132,7 +135,7 @@
_score_part[owner][SCORE_VEHICLES] = num;
/* Don't allow negative min_profit to show */
if (min_profit > 0)
- _score_part[owner][SCORE_MIN_PROFIT] = min_profit;
+ _score_part[owner][SCORE_MIN_PROFIT] = ClampToI32(min_profit);
}
/* Count stations */
@@ -148,25 +151,21 @@
/* Generate statistics depending on recent income statistics */
{
- const PlayerEconomyEntry* pee;
- int numec;
- int32 min_income;
- int32 max_income;
+ int numec = min(p->num_valid_stat_ent, 12);
+ if (numec != 0) {
+ const PlayerEconomyEntry *pee = p->old_economy;
+ Money min_income = pee->income + pee->expenses;
+ Money max_income = pee->income + pee->expenses;
- numec = min(p->num_valid_stat_ent, 12);
- if (numec != 0) {
- min_income = 0x7FFFFFFF;
- max_income = 0;
- pee = p->old_economy;
do {
min_income = min(min_income, pee->income + pee->expenses);
max_income = max(max_income, pee->income + pee->expenses);
} while (++pee,--numec);
if (min_income > 0)
- _score_part[owner][SCORE_MIN_INCOME] = min_income;
+ _score_part[owner][SCORE_MIN_INCOME] = ClampToI32(min_income);
- _score_part[owner][SCORE_MAX_INCOME] = max_income;
+ _score_part[owner][SCORE_MAX_INCOME] = ClampToI32(max_income);
}
}
@@ -197,15 +196,14 @@
/* Generate score for player money */
{
- int32 money = p->player_money;
- if (money > 0) {
- _score_part[owner][SCORE_MONEY] = money;
+ if (p->player_money > 0) {
+ _score_part[owner][SCORE_MONEY] = ClampToI32(p->player_money);
}
}
/* Generate score for loan */
{
- _score_part[owner][SCORE_LOAN] = _score_info[SCORE_LOAN].needed - p->current_loan;
+ _score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - p->current_loan);
}
/* Now we calculate the score for each item.. */
@@ -259,7 +257,7 @@
for (i = 0; i < 4; i++) {
if (p->share_owners[i] == old_player) {
/* Sell his shares */
- int32 res = DoCommand(0, p->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
+ CommandCost res = DoCommand(0, p->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
/* Because we are in a DoCommand, we can't just execute an other one and
* expect the money to be removed. We need to do it ourself! */
SubtractMoneyFromPlayer(res);
@@ -273,7 +271,7 @@
_current_player = p->share_owners[i];
if (_current_player != PLAYER_SPECTATOR) {
/* Sell the shares */
- int32 res = DoCommand(0, old_player, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
+ CommandCost res = DoCommand(0, old_player, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
/* Because we are in a DoCommand, we can't just execute an other one and
* expect the money to be removed. We need to do it ourself! */
SubtractMoneyFromPlayer(res);
@@ -287,8 +285,7 @@
* removing his/her property doesn't fail because of lack of money.
* Not too drastically though, because it could overflow */
if (new_player == PLAYER_SPECTATOR) {
- GetPlayer(old_player)->money64 = MAX_UVALUE(uint64) >>2; // jackpot ;p
- UpdatePlayerMoney32(GetPlayer(old_player));
+ GetPlayer(old_player)->player_money = MAX_UVALUE(uint64) >> 2; // jackpot ;p
}
if (new_player == PLAYER_SPECTATOR) {
@@ -440,7 +437,6 @@
static void PlayersCheckBankrupt(Player *p)
{
PlayerID owner;
- int64 val;
/* If the player has money again, it does not go bankrupt */
if (p->player_money >= 0) {
@@ -468,7 +464,7 @@
/* Check if the company has any value.. if not, declare it bankrupt
* right now */
- val = CalculateCompanyValue(p);
+ Money val = CalculateCompanyValue(p);
if (val > 0) {
p->bankrupt_value = val;
p->bankrupt_asked = 1 << owner; // Don't ask the owner
@@ -482,8 +478,7 @@
DeletePlayerWindows(owner);
/* Show bankrupt news */
- SetDParam(0, p->name_1);
- SetDParam(1, p->name_2);
+ SetDParam(0, p->index);
AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
if (IsHumanPlayer(owner)) {
@@ -519,8 +514,7 @@
DrawPlayerFace(p->face, p->player_color, 2, 23);
GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
- SetDParam(0, p->president_name_1);
- SetDParam(1, p->president_name_2);
+ SetDParam(0, p->index);
DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
@@ -528,8 +522,7 @@
case NB_BTROUBLE:
DrawStringCentered(w->width>>1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, 0);
- SetDParam(0, p->name_1);
- SetDParam(1, p->name_2);
+ SetDParam(0, p->index);
DrawStringMultiCenter(
((w->width - 101) >> 1) + 98,
@@ -543,10 +536,9 @@
DrawStringCentered(w->width>>1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, 0);
COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
- SetDParam(2, p->name_1);
- SetDParam(3, p->name_2);
+ SetDParam(2, p->index);
price = WP(w,news_d).ni->params[2];
- SetDParam(4, price);
+ SetDParam(3, price);
DrawStringMultiCenter(
((w->width - 101) >> 1) + 98,
90,
@@ -567,9 +559,8 @@
case NB_BNEWCOMPANY:
DrawStringCentered(w->width>>1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, 0);
- SetDParam(0, p->name_1);
- SetDParam(1, p->name_2);
- COPY_IN_DPARAM(2,WP(w,news_d).ni->params, 2);
+ SetDParam(0, p->index);
+ COPY_IN_DPARAM(1,WP(w,news_d).ni->params, 2);
DrawStringMultiCenter(
((w->width - 101) >> 1) + 98,
90,
@@ -590,16 +581,14 @@
case NB_BTROUBLE:
SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
- SetDParam(2, p->name_1);
- SetDParam(3, p->name_2);
+ SetDParam(2, p->index);
return STR_02B6;
case NB_BMERGER:
SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
SetDParam(1, STR_705A_HAS_BEEN_SOLD_TO_FOR);
COPY_IN_DPARAM(2,ni->params, 2);
- SetDParam(4, p->name_1);
- SetDParam(5, p->name_2);
- COPY_IN_DPARAM(6,ni->params + 2, 1);
+ SetDParam(4, p->index);
+ COPY_IN_DPARAM(5,ni->params + 2, 1);
return STR_02B6;
case NB_BBANKRUPT:
SetDParam(0, STR_705C_BANKRUPT);
@@ -609,9 +598,8 @@
case NB_BNEWCOMPANY:
SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
- SetDParam(2, p->name_1);
- SetDParam(3, p->name_2);
- COPY_IN_DPARAM(4,ni->params, 2);
+ SetDParam(2, p->index);
+ COPY_IN_DPARAM(3,ni->params, 2);
return STR_02B6;
default:
NOT_REACHED();
@@ -658,11 +646,17 @@
InvalidateWindow(WC_COMPANY_LEAGUE, 0);
}
-static void AddSingleInflation(int32 *value, uint16 *frac, int32 amt)
+static void AddSingleInflation(Money *value, uint16 *frac, int32 amt)
{
- int64 tmp = (int64)*value * amt + *frac;
- *frac = GB(tmp, 0, 16);
- *value += tmp >> 16;
+ /* Is it safe to add inflation ? */
+ if ((INT64_MAX / amt) < (*value + 1)) {
+ *value = INT64_MAX / amt;
+ *frac = 0;
+ } else {
+ int64 tmp = (int64)*value * amt + *frac;
+ *frac = GB(tmp, 0, 16);
+ *value += tmp >> 16;
+ }
}
static void AddInflation()
@@ -672,10 +666,10 @@
* 12 -> months per year
* This is only a good approxiamtion for small values
*/
- int32 inf = _economy.infl_amount * 54;
+ Money inf = _economy.infl_amount * 54;
for (uint i = 0; i != NUM_PRICES; i++) {
- AddSingleInflation((int32*)&_price + i, _price_frac + i, inf);
+ AddSingleInflation((Money*)&_price + i, _price_frac + i, inf);
}
_economy.max_loan_unround += BIGMULUS(_economy.max_loan_unround, inf, 16);
@@ -686,7 +680,7 @@
inf = _economy.infl_amount_pr * 54;
for (CargoID i = 0; i < NUM_CARGO; i++) {
AddSingleInflation(
- (int32*)_cargo_payment_rates + i,
+ (Money*)_cargo_payment_rates + i,
_cargo_payment_rates_frac + i,
inf
);
@@ -709,7 +703,7 @@
_current_player = p->index;
SET_EXPENSES_TYPE(EXPENSES_LOAN_INT);
- SubtractMoneyFromPlayer(BIGMULUS(p->current_loan, interest, 16));
+ SubtractMoneyFromPlayer(CommandCost((Money)BIGMULUS(p->current_loan, interest, 16)));
SET_EXPENSES_TYPE(EXPENSES_OTHER);
SubtractMoneyFromPlayer(_price.station_value >> 2);
@@ -739,7 +733,7 @@
2,
};
-static const int32 _price_base[NUM_PRICES] = {
+static const Money _price_base[NUM_PRICES] = {
100, ///< station_value
100, ///< build_rail
95, ///< build_road
@@ -822,10 +816,10 @@
{
int i;
- assert(sizeof(_price) == NUM_PRICES * sizeof(int32));
+ assert(sizeof(_price) == NUM_PRICES * sizeof(Money));
for (i = 0; i != NUM_PRICES; i++) {
- int32 price = _price_base[i];
+ Money price = _price_base[i];
if (_price_category[i] != 0) {
uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
if (mod < 1) {
@@ -839,7 +833,7 @@
} else {
price >>= 8 - price_base_multiplier[i];
}
- ((int32*)&_price)[i] = price;
+ ((Money*)&_price)[i] = price;
_price_frac[i] = 0;
}
@@ -1152,7 +1146,7 @@
SlObject(&_subsidies[index], _subsidies_desc);
}
-int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
+Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
{
const CargoSpec *cs = GetCargo(cargo_type);
byte f;
@@ -1299,8 +1293,7 @@
InjectDParam(2);
p = GetPlayer(_current_player);
- SetDParam(0, p->name_1);
- SetDParam(1, p->name_2);
+ SetDParam(0, p->index);
AddNewsItem(
STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
@@ -1314,11 +1307,11 @@
return false;
}
-static int32 DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit)
+static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit)
{
bool subsidised;
Station *s_from, *s_to;
- int32 profit;
+ Money profit;
assert(num_pieces > 0);
@@ -1368,14 +1361,9 @@
{
int result = 0;
- int profit = 0;
- int total_veh_profit = 0; // accumulates the profit across the vehicle chain (used by trains)
- int32 route_profit = 0; // the grand total amount for the route. A-D of transfer chain A-B-C-D
- int virtual_profit = 0; // virtual profit of one vehicle element for feeder systems
- int virtual_profit_total = 0; // virtual profit for entire vehicle chain
- int total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
-
- int all_vehicles_cargo_feeder_share = front_v->cargo_feeder_share; // used to hold transfer value of complete vehicle chain - used by trains
+ Money vehicle_profit = 0; // Money paid to the train
+ Money route_profit = 0; // The grand total amount for the route. A-D of transfer chain A-B-C-D
+ Money virtual_profit = 0; // The virtual profit for entire vehicle chain
StationID last_visited = front_v->last_station_visited;
Station *st = GetStation(last_visited);
@@ -1392,75 +1380,70 @@
for (Vehicle *v = front_v; v != NULL; v = v->next) {
/* No cargo to unload */
- if (v->cargo_cap == 0 || v->cargo_count == 0) continue;
+ if (v->cargo_cap == 0 || v->cargo.Empty()) continue;
/* All cargo has already been paid for, no need to pay again */
- if (v->cargo_count == v->cargo_paid_for) {
+ if (!v->cargo.UnpaidCargo()) {
SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
continue;
}
GoodsEntry *ge = &st->goods[v->cargo_type];
-
- if (v->cargo_source != last_visited &&
- HASBIT(ge->waiting_acceptance, 15) &&
- (front_v->current_order.flags & OF_TRANSFER) == 0) {
- /* Deliver goods to the station */
- st->time_since_unload = 0;
-
- /* handle end of route payment */
- profit += DeliverGoods(v->cargo_count - v->cargo_paid_for, v->cargo_type, v->cargo_source, last_visited, v->cargo_source_xy, v->cargo_days);
- v->cargo_paid_for = v->cargo_count;
- route_profit = profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
- total_veh_profit = profit - all_vehicles_cargo_feeder_share; // whole vehicle is not payed for transfers picked up earlier
- total_cargo_feeder_share = -all_vehicles_cargo_feeder_share; // total of transfer fees in vehicle chain needs to be zero at end of unload
-
- v->cargo_feeder_share = 0; // clear transfer cost per vehicle
- result |= 1;
+ const CargoList::List *cargos = v->cargo.Packets();
- SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
- } else if (front_v->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
- if ((front_v->current_order.flags & OF_TRANSFER) != 0) {
- virtual_profit = GetTransportedGoodsIncome(
- v->cargo_count - v->cargo_paid_for,
- /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
- DistanceManhattan(v->cargo_loaded_at_xy, GetStation(last_visited)->xy),
- v->cargo_days,
- v->cargo_type);
+ for (CargoList::List::const_iterator it = cargos->begin(); it != cargos->end(); it++) {
+ CargoPacket *cp = *it;
+ if (!cp->paid_for &&
+ cp->source != last_visited &&
+ ge->acceptance &&
+ (front_v->current_order.flags & OF_TRANSFER) == 0) {
+ /* Deliver goods to the station */
+ st->time_since_unload = 0;
- front_v->profit_this_year += virtual_profit;
- ge->feeder_profit += v->cargo_feeder_share + virtual_profit; // transfer cargo transfer fees to station
- total_cargo_feeder_share -= v->cargo_feeder_share; // accumulate deduction of feeder shares
- v->cargo_feeder_share = 0; // clear transfer cost
+ /* handle end of route payment */
+ Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit);
+ cp->paid_for = true;
+ route_profit += profit - cp->feeder_share; // display amount paid for final route delivery, A-D of a chain A-B-C-D
+ vehicle_profit += profit; // whole vehicle is not payed for transfers picked up earlier
- /* keep total of cargo unloaded (pending) for accurate cargoshare calculation on load */
- SB(ge->unload_pending, 0, 12, GB(ge->unload_pending, 0, 12) + v->cargo_count);
+ result |= 1;
- virtual_profit_total += virtual_profit; // accumulate transfer profits for whole vehicle
- v->cargo_paid_for = v->cargo_count; // record how much of the cargo has been paid for to eliminate double counting
+ SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
+ } else if (front_v->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
+ if (!cp->paid_for && (front_v->current_order.flags & OF_TRANSFER) != 0) {
+ Money profit = GetTransportedGoodsIncome(
+ cp->count,
+ /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
+ DistanceManhattan(cp->loaded_at_xy, GetStation(last_visited)->xy),
+ cp->days_in_transit,
+ v->cargo_type);
+
+ front_v->profit_this_year += profit;
+ virtual_profit += profit; // accumulate transfer profits for whole vehicle
+ cp->feeder_share += profit; // account for the (virtual) profit already made for the cargo packet
+ cp->paid_for = true; // record that the cargo has been paid for to eliminate double counting
+ }
+ result |= 2;
+
+ SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
}
- result |= 2;
-
- SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
}
+ v->cargo.InvalidateCache();
}
- /* Ensure a negative total is only applied to the vehicle if there is value to reduce. */
- front_v->cargo_feeder_share = max(front_v->cargo_feeder_share + total_cargo_feeder_share, 0);
-
- if (virtual_profit_total > 0) {
- ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit_total);
+ if (virtual_profit > 0) {
+ ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
}
if (route_profit != 0) {
- front_v->profit_this_year += total_veh_profit;
+ front_v->profit_this_year += vehicle_profit;
SubtractMoneyFromPlayer(-route_profit);
if (IsLocalPlayer() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
SndPlayVehicleFx(SND_14_CASHTILL, front_v);
}
- ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -total_veh_profit);
+ ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -vehicle_profit);
}
_current_player = old_player;
@@ -1483,7 +1466,7 @@
if (_patches.improved_load && HASBIT(v->current_order.flags, OFB_FULL_LOAD)) {
/* 'Reserve' this cargo for this vehicle, because we were first. */
for (; v != NULL; v = v->next) {
- if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
+ if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
}
}
return;
@@ -1499,14 +1482,13 @@
int unloading_time = 0;
Vehicle *u = v;
int result = 0;
- int cap;
+ uint cap;
bool completely_empty = true;
bool anything_unloaded = false;
bool anything_loaded = false;
uint32 cargo_not_full = 0;
uint32 cargo_full = 0;
- int total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
v->cur_speed = 0;
@@ -1523,36 +1505,19 @@
}
GoodsEntry *ge = &st->goods[v->cargo_type];
- int count = GB(ge->waiting_acceptance, 0, 12);
if (HASBIT(v->vehicle_flags, VF_CARGO_UNLOADING)) {
- uint16 amount_unloaded = _patches.gradual_loading ? min(v->cargo_count, load_amount) : v->cargo_count;
+ uint cargo_count = v->cargo.Count();
+ uint amount_unloaded = _patches.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
+ bool remaining; // Are there cargo entities in this vehicle that can still be unloaded here?
- if (v->cargo_source != last_visited && ge->waiting_acceptance & 0x8000 && !(u->current_order.flags & OF_TRANSFER)) {
+ if (ge->acceptance && !(u->current_order.flags & OF_TRANSFER)) {
+ /* The cargo has reached it's final destination, the packets may now be destroyed */
+ remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, last_visited);
+
result |= 1;
} else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
- if (count == 0) {
- /* No goods waiting at station */
- ge->enroute_time = v->cargo_days;
- ge->enroute_from = v->cargo_source;
- ge->enroute_from_xy = v->cargo_source_xy;
- } else {
- /* Goods already waiting at station. Set counters to the worst value. */
- if (v->cargo_days >= ge->enroute_time) ge->enroute_time = v->cargo_days;
-
- if (last_visited != ge->enroute_from) {
- ge->enroute_from = v->cargo_source;
- ge->enroute_from_xy = v->cargo_source_xy;
- }
- }
- /* Update amount of waiting cargo. There is, however, no sense in
- * updating the count variable because this vehicle will not be
- * able to take the cargo. */
- SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + count, 0xFFF));
-
- /* if there is not enough to unload from pending, ensure it does not go -ve
- * else deduct amount actually unloaded from unload_pending */
- SB(ge->unload_pending, 0, 12, max(GB(ge->unload_pending, 0, 12) - amount_unloaded, 0U));
+ remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
result |= 2;
} else {
@@ -1567,11 +1532,8 @@
unloading_time += amount_unloaded;
- v->cargo_count -= amount_unloaded;
- v->cargo_paid_for -= min(amount_unloaded, v->cargo_paid_for);
-
anything_unloaded = true;
- if (_patches.gradual_loading && v->cargo_count != 0) {
+ if (_patches.gradual_loading && remaining) {
completely_empty = false;
} else {
/* We have finished unloading (cargo count == 0) */
@@ -1581,9 +1543,6 @@
continue;
}
- /* We cannot have paid for more cargo than there is on board. */
- assert(v->cargo_paid_for <= v->cargo_count);
-
/* Do not pick up goods that we unloaded */
if (u->current_order.flags & OF_UNLOAD) continue;
@@ -1596,14 +1555,14 @@
}
/* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
- ge->days_since_pickup = 0;
ge->last_speed = min(t, 255);
- ge->last_age = _cur_year - v->build_year;
+ ge->last_age = _cur_year - u->build_year;
/* If there's goods waiting at the station, and the vehicle
* has capacity for it, load it on the vehicle. */
- if (count != 0 &&
- (cap = v->cargo_cap - v->cargo_count) != 0) {
+ if (!ge->cargo.Empty() &&
+ (cap = v->cargo_cap - v->cargo.Count()) != 0) {
+ uint count = ge->cargo.Count();
/* Skip loading this vehicle if another train/vehicle is already handling
* the same cargo type at this station */
@@ -1616,11 +1575,11 @@
if (_patches.gradual_loading) cap = min(cap, load_amount);
if (_patches.improved_load) {
/* Don't load stuff that is already 'reserved' for other vehicles */
- cap = min(cargo_left[v->cargo_type], cap);
+ cap = min((uint)cargo_left[v->cargo_type], cap);
cargo_left[v->cargo_type] -= cap;
}
- if (v->cargo_count == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
+ if (v->cargo.Empty()) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
/* TODO: Regarding this, when we do gradual loading, we
* should first unload all vehicles and then start
@@ -1632,32 +1591,17 @@
completely_empty = false;
anything_loaded = true;
- /* cargoshare is proportioned by the amount due to unload
- * Otherwise, with gradual loading, 100% of credits would be taken immediately,
- * even if the cargo volume represents a tiny percent of the whole.
- * ge->unload_pending holds the amount that has been credited, but has not yet been unloaded.
- */
- int cargoshare = cap * 10000 / (ge->waiting_acceptance + ge->unload_pending);
- int feeder_profit_share = ge->feeder_profit * cargoshare / 10000;
- v->cargo_count += cap;
- ge->waiting_acceptance -= cap;
+ ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
+ ge->days_since_pickup = 0;
- total_cargo_feeder_share += feeder_profit_share; // store cost for later payment when cargo unloaded
- v->cargo_loaded_at_xy = st->xy; // retains location of where the cargo was picked up for intermediate payments
-
- ge->feeder_profit -= feeder_profit_share;
unloading_time += cap;
st->time_since_load = 0;
+ st->last_vehicle_type = v->type;
- /* And record the source of the cargo, and the days in travel. */
- v->cargo_source = ge->enroute_from;
- v->cargo_source_xy = ge->enroute_from_xy;
- v->cargo_days = ge->enroute_time;
result |= 2;
- st->last_vehicle_type = v->type;
}
- if (v->cargo_count == v->cargo_cap) {
+ if (v->cargo.Count() == v->cargo_cap) {
SETBIT(cargo_full, v->cargo_type);
} else {
SETBIT(cargo_not_full, v->cargo_type);
@@ -1671,14 +1615,12 @@
if (_patches.improved_load && HASBIT(u->current_order.flags, OFB_FULL_LOAD)) {
/* Update left cargo */
for (v = u; v != NULL; v = v->next) {
- if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
+ if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
}
}
v = u;
- v->cargo_feeder_share += total_cargo_feeder_share;
-
if (anything_loaded || anything_unloaded) {
if (_patches.gradual_loading) {
/* The time it takes to load one 'slice' of cargo or passengers depends
@@ -1693,7 +1635,7 @@
if (_patches.full_load_any) {
/* if the aircraft carries passengers and is NOT full, then
* continue loading, no matter how much mail is in */
- if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo_count) ||
+ if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo.Count()) ||
(cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
finished_loading = false;
}
@@ -1715,6 +1657,17 @@
}
}
+ /* Calculate the loading indicator fill percent and display */
+ if (_patches.loading_indicators && _game_mode != GM_MENU && v->owner == _local_player) {
+ StringID percent_up_down = STR_NULL;
+ int percent = CalcPercentVehicleFilled(v, &percent_up_down);
+ if (v->fill_percent_te_id == INVALID_TE_ID) {
+ v->fill_percent_te_id = ShowFillingPercent(v->x_pos, v->y_pos, v->z_pos + 20, percent, percent_up_down);
+ } else {
+ UpdateFillingPercent(v->fill_percent_te_id, percent, percent_up_down);
+ }
+ }
+
v->load_unload_time_rem = unloading_time;
if (completely_empty) {
@@ -1741,7 +1694,7 @@
{
int cargo_left[NUM_CARGO];
- for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = GB(st->goods[i].waiting_acceptance, 0, 12);
+ for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = st->goods[i].cargo.Count();
std::list<Vehicle *>::iterator iter;
for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
@@ -1766,11 +1719,10 @@
{
Player *owner;
int i;
- int64 value;
+ Money value;
- SetDParam(0, p->name_1);
- SetDParam(1, p->name_2);
- SetDParam(2, p->bankrupt_value);
+ SetDParam(0, p->index);
+ SetDParam(1, p->bankrupt_value);
AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
/* original code does this a little bit differently */
@@ -1784,14 +1736,15 @@
}
value = CalculateCompanyValue(p) >> 2;
+ PlayerID old_player = _current_player;
for (i = 0; i != 4; i++) {
if (p->share_owners[i] != PLAYER_SPECTATOR) {
- owner = GetPlayer(p->share_owners[i]);
- owner->money64 += value;
- owner->yearly_expenses[0][EXPENSES_OTHER] += value;
- UpdatePlayerMoney32(owner);
+ SET_EXPENSES_TYPE(EXPENSES_OTHER);
+ _current_player = p->share_owners[i];
+ SubtractMoneyFromPlayer(CommandCost(-value));
}
}
+ _current_player = old_player;
p->is_active = false;
@@ -1807,10 +1760,10 @@
* @param p1 player to buy the shares from
* @param p2 unused
*/
-int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Player *p;
- int64 cost;
+ CommandCost cost;
/* Check if buying shares is allowed (protection against modified clients */
if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
@@ -1822,12 +1775,12 @@
if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED);
/* Those lines are here for network-protection (clients can be slow) */
- if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return 0;
+ if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return cost;
/* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
- if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return 0;
+ if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return cost;
- cost = CalculateCompanyValue(p) >> 2;
+ cost.AddCost(CalculateCompanyValue(p) >> 2);
if (flags & DC_EXEC) {
PlayerByte* b = p->share_owners;
int i;
@@ -1853,10 +1806,10 @@
* @param p1 player to sell the shares from
* @param p2 unused
*/
-int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Player *p;
- int64 cost;
+ Money cost;
/* Check if buying shares is allowed (protection against modified clients */
if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
@@ -1865,7 +1818,7 @@
p = GetPlayer((PlayerID)p1);
/* Those lines are here for network-protection (clients can be slow) */
- if (GetAmountOwnedBy(p, _current_player) == 0) return 0;
+ if (GetAmountOwnedBy(p, _current_player) == 0) return CommandCost();
/* adjust it a little to make it less profitable to sell and buy */
cost = CalculateCompanyValue(p) >> 2;
@@ -1877,7 +1830,7 @@
*b = PLAYER_SPECTATOR;
InvalidateWindow(WC_COMPANY, p1);
}
- return cost;
+ return CommandCost(cost);
}
/** Buy up another company.
@@ -1889,7 +1842,7 @@
* @param p1 player/company to buy up
* @param p2 unused
*/
-int32 CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Player *p;
PlayerID pid = (PlayerID)p1;
@@ -1908,13 +1861,14 @@
if (flags & DC_EXEC) {
DoAcquireCompany(p);
}
- return p->bankrupt_value;
+ return CommandCost(p->bankrupt_value);
}
/** Prices */
static void SaveLoad_PRIC()
{
- SlArray(&_price, NUM_PRICES, SLE_INT32);
+ int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
+ SlArray(&_price, NUM_PRICES, vt);
SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
}
@@ -1922,18 +1876,21 @@
static void SaveLoad_CAPR()
{
uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
- SlArray(&_cargo_payment_rates, num_cargo, SLE_INT32);
+ int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
+ SlArray(&_cargo_payment_rates, num_cargo, vt);
SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
}
static const SaveLoad _economy_desc[] = {
- SLE_VAR(Economy, max_loan, SLE_INT32),
- SLE_VAR(Economy, max_loan_unround, SLE_INT32),
- SLE_VAR(Economy, fluct, SLE_FILE_I16 | SLE_VAR_I32),
- SLE_VAR(Economy, interest_rate, SLE_UINT8),
- SLE_VAR(Economy, infl_amount, SLE_UINT8),
- SLE_VAR(Economy, infl_amount_pr, SLE_UINT8),
- SLE_END()
+ SLE_CONDVAR(Economy, max_loan, SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
+ SLE_CONDVAR(Economy, max_loan, SLE_INT64, 65, SL_MAX_VERSION),
+ SLE_CONDVAR(Economy, max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
+ SLE_CONDVAR(Economy, max_loan_unround, SLE_INT64, 65, SL_MAX_VERSION),
+ SLE_VAR(Economy, fluct, SLE_FILE_I16 | SLE_VAR_I32),
+ SLE_VAR(Economy, interest_rate, SLE_UINT8),
+ SLE_VAR(Economy, infl_amount, SLE_UINT8),
+ SLE_VAR(Economy, infl_amount_pr, SLE_UINT8),
+ SLE_END()
};
/** Economy variables */