# economy.cpp

Go to the documentation of this file.

    00001 /* $Id: economy.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "currency.h"
    00008 #include "landscape.h"
    00009 #include "news.h"
    00010 #include "player_base.h"
    00011 #include "player_func.h"
    00012 #include "station.h"
    00013 #include "command_func.h"
    00014 #include "saveload.h"
    00015 #include "industry.h"
    00016 #include "town.h"
    00017 #include "network/network.h"
    00018 #include "engine.h"
    00019 #include "network/network_data.h"
    00020 #include "variables.h"
    00021 #include "vehicle_gui.h"
    00022 #include "ai/ai.h"
    00023 #include "train.h"
    00024 #include "roadveh.h"
    00025 #include "aircraft.h"
    00026 #include "newgrf_engine.h"
    00027 #include "newgrf_sound.h"
    00028 #include "newgrf_callbacks.h"
    00029 #include "newgrf_industries.h"
    00030 #include "newgrf_industrytiles.h"
    00031 #include "unmovable.h"
    00032 #include "cargotype.h"
    00033 #include "player_face.h"
    00034 #include "group.h"
    00035 #include "strings_func.h"
    00036 #include "tile_cmd.h"
    00037 #include "functions.h"
    00038 #include "window_func.h"
    00039 #include "date_func.h"
    00040 #include "vehicle_func.h"
    00041 #include "sound_func.h"
    00042 #include "track_type.h"
    00043 #include "track_func.h"
    00044 #include "road_func.h"
    00045 #include "rail_map.h"
    00046 #include "signal_func.h"
    00047 #include "gfx_func.h"
    00048 #include "autoreplace_func.h"
    00049 #include "signs.h"
    00050
    00051 #include "table/strings.h"
    00052 #include "table/sprites.h"
    00053
    00065 static inline int32 BigMulS(const int32 a, const int32 b, const uint8 shift)
    00066 {
    00067   return (int32)((int64)a * (int64)b >> shift);
    00068 }
    00069
    00081 static inline uint32 BigMulSU(const uint32 a, const uint32 b, const uint8 shift)
    00082 {
    00083   return (uint32)((uint64)a * (uint64)b >> shift);
    00084 }
    00085
    00086 /* Score info */
    00087 const ScoreInfo _score_info[] = {
    00088   { SCORE_VEHICLES,        120, 100 },
    00089   { SCORE_STATIONS,         80, 100 },
    00090   { SCORE_MIN_PROFIT,    10000, 100 },
    00091   { SCORE_MIN_INCOME,    50000,  50 },
    00092   { SCORE_MAX_INCOME,   100000, 100 },
    00093   { SCORE_DELIVERED,     40000, 400 },
    00094   { SCORE_CARGO,             8,  50 },
    00095   { SCORE_MONEY,      10000000,  50 },
    00096   { SCORE_LOAN,         250000,  50 },
    00097   { SCORE_TOTAL,             0,   0 }
    00098 };
    00099
    00100 int _score_part[MAX_PLAYERS][SCORE_END];
    00101 Economy _economy;
    00102 Subsidy _subsidies[MAX_PLAYERS];
    00103 Prices _price;
    00104 uint16 _price_frac[NUM_PRICES];
    00105 Money  _cargo_payment_rates[NUM_CARGO];
    00106 uint16 _cargo_payment_rates_frac[NUM_CARGO];
    00107 Money _additional_cash_required;
    00108
    00109 Money CalculateCompanyValue(const Player* p)
    00110 {
    00111   PlayerID owner = p->index;
    00112   Money value = 0;
    00113
    00114   Station *st;
    00115   uint num = 0;
    00116
    00117   FOR_ALL_STATIONS(st) {
    00118     if (st->owner == owner) num += CountBits(st->facilities);
    00119   }
    00120
    00121   value += num * _price.station_value * 25;
    00122
    00123   Vehicle *v;
    00124   FOR_ALL_VEHICLES(v) {
    00125     if (v->owner != owner) continue;
    00126
    00127     if (v->type == VEH_TRAIN ||
    00128         v->type == VEH_ROAD ||
    00129         (v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) ||
    00130         v->type == VEH_SHIP) {
    00131       value += v->value * 3 >> 1;
    00132     }
    00133   }
    00134
    00135   /* Add real money value */
    00136   value -= p->current_loan;
    00137   value += p->player_money;
    00138
    00139   return max(value, (Money)1);
    00140 }
    00141
    00148 int UpdateCompanyRatingAndValue(Player *p, bool update)
    00149 {
    00150   byte owner = p->index;
    00151   int score = 0;
    00152
    00153   memset(_score_part[owner], 0, sizeof(_score_part[owner]));
    00154
    00155 /* Count vehicles */
    00156   {
    00157     Vehicle *v;
    00158     Money min_profit = 0;
    00159     bool min_profit_first = true;
    00160     uint num = 0;
    00161
    00162     FOR_ALL_VEHICLES(v) {
    00163       if (v->owner != owner) continue;
    00164       if (IsPlayerBuildableVehicleType(v->type) && v->IsPrimaryVehicle()) {
    00165         num++;
    00166         if (v->age > 730) {
    00167           /* Find the vehicle with the lowest amount of profit */
    00168           if (min_profit_first || min_profit > v->profit_last_year) {
    00169             min_profit = v->profit_last_year;
    00170             min_profit_first = false;
    00171           }
    00172         }
    00173       }
    00174     }
    00175
    00176     min_profit >>= 8; // remove the fract part
    00177
    00178     _score_part[owner][SCORE_VEHICLES] = num;
    00179     /* Don't allow negative min_profit to show */
    00180     if (min_profit > 0)
    00181       _score_part[owner][SCORE_MIN_PROFIT] = ClampToI32(min_profit);
    00182   }
    00183
    00184 /* Count stations */
    00185   {
    00186     uint num = 0;
    00187     const Station* st;
    00188
    00189     FOR_ALL_STATIONS(st) {
    00190       if (st->owner == owner) num += CountBits(st->facilities);
    00191     }
    00192     _score_part[owner][SCORE_STATIONS] = num;
    00193   }
    00194
    00195 /* Generate statistics depending on recent income statistics */
    00196   {
    00197     int numec = min(p->num_valid_stat_ent, 12);
    00198     if (numec != 0) {
    00199       const PlayerEconomyEntry *pee = p->old_economy;
    00200       Money min_income = pee->income + pee->expenses;
    00201       Money max_income = pee->income + pee->expenses;
    00202
    00203       do {
    00204         min_income = min(min_income, pee->income + pee->expenses);
    00205         max_income = max(max_income, pee->income + pee->expenses);
    00206       } while (++pee,--numec);
    00207
    00208       if (min_income > 0)
    00209         _score_part[owner][SCORE_MIN_INCOME] = ClampToI32(min_income);
    00210
    00211       _score_part[owner][SCORE_MAX_INCOME] = ClampToI32(max_income);
    00212     }
    00213   }
    00214
    00215 /* Generate score depending on amount of transported cargo */
    00216   {
    00217     const PlayerEconomyEntry* pee;
    00218     int numec;
    00219     uint32 total_delivered;
    00220
    00221     numec = min(p->num_valid_stat_ent, 4);
    00222     if (numec != 0) {
    00223       pee = p->old_economy;
    00224       total_delivered = 0;
    00225       do {
    00226         total_delivered += pee->delivered_cargo;
    00227       } while (++pee,--numec);
    00228
    00229       _score_part[owner][SCORE_DELIVERED] = total_delivered;
    00230     }
    00231   }
    00232
    00233 /* Generate score for variety of cargo */
    00234   {
    00235     uint num = CountBits(p->cargo_types);
    00236     _score_part[owner][SCORE_CARGO] = num;
    00237     if (update) p->cargo_types = 0;
    00238   }
    00239
    00240 /* Generate score for player money */
    00241   {
    00242     if (p->player_money > 0) {
    00243       _score_part[owner][SCORE_MONEY] = ClampToI32(p->player_money);
    00244     }
    00245   }
    00246
    00247 /* Generate score for loan */
    00248   {
    00249     _score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - p->current_loan);
    00250   }
    00251
    00252   /* Now we calculate the score for each item.. */
    00253   {
    00254     int total_score = 0;
    00255     int s;
    00256     score = 0;
    00257     for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
    00258       /* Skip the total */
    00259       if (i == SCORE_TOTAL) continue;
    00260       /*  Check the score */
    00261       s = Clamp(_score_part[owner][i], 0, _score_info[i].needed) * _score_info[i].score / _score_info[i].needed;
    00262       score += s;
    00263       total_score += _score_info[i].score;
    00264     }
    00265
    00266     _score_part[owner][SCORE_TOTAL] = score;
    00267
    00268     /*  We always want the score scaled to SCORE_MAX (1000) */
    00269     if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score;
    00270   }
    00271
    00272   if (update) {
    00273     p->old_economy[0].performance_history = score;
    00274     UpdateCompanyHQ(p, score);
    00275     p->old_economy[0].company_value = CalculateCompanyValue(p);
    00276   }
    00277
    00278   InvalidateWindow(WC_PERFORMANCE_DETAIL, 0);
    00279   return score;
    00280 }
    00281
    00282 /*  use PLAYER_SPECTATOR as new_player to delete the player. */
    00283 void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
    00284 {
    00285   Town *t;
    00286   PlayerID old = _current_player;
    00287
    00288   assert(old_player != new_player);
    00289
    00290   {
    00291     Player *p;
    00292     uint i;
    00293
    00294     /* See if the old_player had shares in other companies */
    00295     _current_player = old_player;
    00296     FOR_ALL_PLAYERS(p) {
    00297       if (!p->is_active) continue;
    00298       for (i = 0; i < 4; i++) {
    00299         if (p->share_owners[i] == old_player) {
    00300           /* Sell his shares */
    00301           CommandCost res = DoCommand(0, p->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
    00302           /* Because we are in a DoCommand, we can't just execute an other one and
    00303            *  expect the money to be removed. We need to do it ourself! */
    00304           SubtractMoneyFromPlayer(res);
    00305         }
    00306       }
    00307     }
    00308
    00309     /* Sell all the shares that people have on this company */
    00310     p = GetPlayer(old_player);
    00311     for (i = 0; i < 4; i++) {
    00312       _current_player = p->share_owners[i];
    00313       if (_current_player != PLAYER_SPECTATOR) {
    00314         /* Sell the shares */
    00315         CommandCost res = DoCommand(0, old_player, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
    00316         /* Because we are in a DoCommand, we can't just execute an other one and
    00317          *  expect the money to be removed. We need to do it ourself! */
    00318         SubtractMoneyFromPlayer(res);
    00319       }
    00320     }
    00321   }
    00322
    00323   _current_player = old_player;
    00324
    00325   /* Temporarily increase the player's money, to be sure that
    00326    * removing his/her property doesn't fail because of lack of money.
    00327    * Not too drastically though, because it could overflow */
    00328   if (new_player == PLAYER_SPECTATOR) {
    00329     GetPlayer(old_player)->player_money = MAX_UVALUE(uint64) >> 2; // jackpot ;p
    00330   }
    00331
    00332   if (new_player == PLAYER_SPECTATOR) {
    00333     Subsidy *s;
    00334
    00335     for (s = _subsidies; s != endof(_subsidies); s++) {
    00336       if (s->cargo_type != CT_INVALID && s->age >= 12) {
    00337         if (GetStation(s->to)->owner == old_player) s->cargo_type = CT_INVALID;
    00338       }
    00339     }
    00340   }
    00341
    00342   /* Take care of rating in towns */
    00343   FOR_ALL_TOWNS(t) {
    00344     /* If a player takes over, give the ratings to that player. */
    00345     if (new_player != PLAYER_SPECTATOR) {
    00346       if (HasBit(t->have_ratings, old_player)) {
    00347         if (HasBit(t->have_ratings, new_player)) {
    00348           // use max of the two ratings.
    00349           t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
    00350         } else {
    00351           SetBit(t->have_ratings, new_player);
    00352           t->ratings[new_player] = t->ratings[old_player];
    00353         }
    00354       }
    00355     }
    00356
    00357     /* Reset the ratings for the old player */
    00358     t->ratings[old_player] = 500;
    00359     ClrBit(t->have_ratings, old_player);
    00360   }
    00361
    00362   {
    00363     int num_train = 0;
    00364     int num_road = 0;
    00365     int num_ship = 0;
    00366     int num_aircraft = 0;
    00367     Vehicle *v;
    00368
    00369     /*  Determine Ids for the new vehicles */
    00370     FOR_ALL_VEHICLES(v) {
    00371       if (v->owner == new_player) {
    00372         switch (v->type) {
    00373           case VEH_TRAIN:    if (IsFrontEngine(v)) num_train++; break;
    00374           case VEH_ROAD:     if (IsRoadVehFront(v)) num_road++; break;
    00375           case VEH_SHIP:     num_ship++; break;
    00376           case VEH_AIRCRAFT: if (IsNormalAircraft(v)) num_aircraft++; break;
    00377           default: break;
    00378         }
    00379       }
    00380     }
    00381
    00382     FOR_ALL_VEHICLES(v) {
    00383       if (v->owner == old_player && IsInsideMM(v->type, VEH_TRAIN, VEH_AIRCRAFT + 1)) {
    00384         if (new_player == PLAYER_SPECTATOR) {
    00385           DeleteWindowById(WC_VEHICLE_VIEW, v->index);
    00386           DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
    00387           DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
    00388
    00389           if (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && IsFreeWagon(v))) {
    00390             switch (v->type) {
    00391               default: NOT_REACHED();
    00392
    00393               case VEH_TRAIN: {
    00394                 Vehicle *u = v;
    00395                 do {
    00396                   Vehicle *next = GetNextVehicle(u);
    00397                   delete u;
    00398                   u = next;
    00399                 } while (u != NULL);
    00400               } break;
    00401
    00402               case VEH_ROAD:
    00403               case VEH_SHIP:
    00404                 delete v;
    00405                 break;
    00406
    00407               case VEH_AIRCRAFT:
    00408                 DeleteVehicleChain(v);
    00409                 break;
    00410             }
    00411           }
    00412         } else {
    00413           v->owner = new_player;
    00414           v->colormap = PAL_NONE;
    00415           v->group_id = DEFAULT_GROUP;
    00416           if (IsEngineCountable(v)) GetPlayer(new_player)->num_engines[v->engine_type]++;
    00417           switch (v->type) {
    00418             case VEH_TRAIN:    if (IsFrontEngine(v)) v->unitnumber = ++num_train; break;
    00419             case VEH_ROAD:     if (IsRoadVehFront(v)) v->unitnumber = ++num_road; break;
    00420             case VEH_SHIP:     v->unitnumber = ++num_ship; break;
    00421             case VEH_AIRCRAFT: if (IsNormalAircraft(v)) v->unitnumber = ++num_aircraft; break;
    00422             default: NOT_REACHED();
    00423           }
    00424         }
    00425       }
    00426     }
    00427   }
    00428
    00429   /*  Change ownership of tiles */
    00430   {
    00431     TileIndex tile = 0;
    00432     do {
    00433       ChangeTileOwner(tile, old_player, new_player);
    00434     } while (++tile != MapSize());
    00435
    00436     if (new_player != PLAYER_SPECTATOR) {
    00437       /* Update all signals because there can be new segment that was owned by two players
    00438        * and signals were not propagated
    00439        * Similiar with crossings - it is needed to bar crossings that weren't before
    00440        * because of different owner of crossing and approaching train */
    00441       tile = 0;
    00442
    00443       do {
    00444         if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, new_player) && HasSignals(tile)) {
    00445           TrackBits tracks = GetTrackBits(tile);
    00446           do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT
    00447             Track track = RemoveFirstTrack(&tracks);
    00448             if (HasSignalOnTrack(tile, track)) AddTrackToSignalBuffer(tile, track, new_player);
    00449           } while (tracks != TRACK_BIT_NONE);
    00450         } else if (IsLevelCrossingTile(tile) && IsTileOwner(tile, new_player)) {
    00451           UpdateLevelCrossing(tile);
    00452         }
    00453       } while (++tile != MapSize());
    00454     }
    00455
    00456     /* update signals in buffer */
    00457     UpdateSignalsInBuffer();
    00458   }
    00459
    00460   /* In all cases clear replace engine rules.
    00461    * Even if it was copied, it could interfere with new owner's rules */
    00462   RemoveAllEngineReplacementForPlayer(GetPlayer(old_player));
    00463
    00464   if (new_player == PLAYER_SPECTATOR) {
    00465     RemoveAllGroupsForPlayer(old_player);
    00466   } else {
    00467     Group *g;
    00468     FOR_ALL_GROUPS(g) {
    00469       if (g->owner == old_player) g->owner = new_player;
    00470     }
    00471   }
    00472
    00473   Sign *si;
    00474   FOR_ALL_SIGNS(si) {
    00475     if (si->owner == old_player) si->owner = new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player;
    00476   }
    00477
    00478   /* Change color of existing windows */
    00479   if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);
    00480
    00481   _current_player = old;
    00482
    00483   MarkWholeScreenDirty();
    00484 }
    00485
    00486 static void ChangeNetworkOwner(PlayerID current_player, PlayerID new_player)
    00487 {
    00488 #ifdef ENABLE_NETWORK
    00489   if (!_networking) return;
    00490
    00491   if (current_player == _local_player) {
    00492     _network_playas = new_player;
    00493     SetLocalPlayer(new_player);
    00494   }
    00495
    00496   if (!_network_server) return;
    00497
    00498   /* The server has to handle all administrative issues, for example
    00499   * updating and notifying all clients of what has happened */
    00500   NetworkTCPSocketHandler *cs;
    00501   NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
    00502
    00503   /* The server has just changed from player */
    00504   if (current_player == ci->client_playas) {
    00505     ci->client_playas = new_player;
    00506     NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
    00507   }
    00508
    00509   /* Find all clients that were in control of this company, and mark them as new_player */
    00510   FOR_ALL_CLIENTS(cs) {
    00511     ci = DEREF_CLIENT_INFO(cs);
    00512     if (current_player == ci->client_playas) {
    00513       ci->client_playas = new_player;
    00514       NetworkUpdateClientInfo(ci->client_index);
    00515     }
    00516   }
    00517 #endif /* ENABLE_NETWORK */
    00518 }
    00519
    00520 static void PlayersCheckBankrupt(Player *p)
    00521 {
    00522   PlayerID owner;
    00523
    00524   /*  If the player has money again, it does not go bankrupt */
    00525   if (p->player_money >= 0) {
    00526     p->quarters_of_bankrupcy = 0;
    00527     return;
    00528   }
    00529
    00530   p->quarters_of_bankrupcy++;
    00531
    00532   owner = p->index;
    00533
    00534   switch (p->quarters_of_bankrupcy) {
    00535     case 2:
    00536       AddNewsItem( (StringID)(owner | NB_BTROUBLE),
    00537         NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
    00538       break;
    00539     case 3: {
    00540       /* XXX - In multiplayer, should we ask other players if it wants to take
    00541               over when it is a human company? -- TrueLight */
    00542       if (IsHumanPlayer(owner)) {
    00543         AddNewsItem( (StringID)(owner | NB_BTROUBLE),
    00544           NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
    00545         break;
    00546       }
    00547
    00548       /* Check if the company has any value.. if not, declare it bankrupt
    00549        *  right now */
    00550       Money val = CalculateCompanyValue(p);
    00551       if (val > 0) {
    00552         p->bankrupt_value = val;
    00553         p->bankrupt_asked = 1 << owner; // Don't ask the owner
    00554         p->bankrupt_timeout = 0;
    00555         break;
    00556       }
    00557       /* Else, falltrue to case 4... */
    00558     }
    00559     case 4: {
    00560       /* Close everything the owner has open */
    00561       DeletePlayerWindows(owner);
    00562
    00563       /* Show bankrupt news */
    00564       SetDParam(0, p->index);
    00565       AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
    00566
    00567       if (IsHumanPlayer(owner)) {
    00568         /* XXX - If we are in offline mode, leave the player playing. Eg. there
    00569          * is no THE-END, otherwise mark the player as spectator to make sure
    00570          * he/she is no long in control of this company */
    00571         if (!_networking) {
    00572           p->bankrupt_asked = 0xFF;
    00573           p->bankrupt_timeout = 0x456;
    00574           break;
    00575         }
    00576
    00577         ChangeNetworkOwner(owner, PLAYER_SPECTATOR);
    00578       }
    00579
    00580       /* Remove the player */
    00581       ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
    00582       /* Register the player as not-active */
    00583       p->is_active = false;
    00584
    00585       if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
    00586         AI_PlayerDied(owner);
    00587     }
    00588   }
    00589 }
    00590
    00591 void DrawNewsBankrupcy(Window *w)
    00592 {
    00593   DrawNewsBorder(w);
    00594
    00595   const NewsItem *ni = WP(w, news_d).ni;
    00596   Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
    00597   DrawPlayerFace(p->face, p->player_color, 2, 23);
    00598   GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
    00599
    00600   SetDParam(0, p->index);
    00601
    00602   DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
    00603
    00604   switch (ni->string_id & 0xF0) {
    00605   case NB_BTROUBLE:
    00606     DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
    00607
    00608     SetDParam(0, p->index);
    00609
    00610     DrawStringMultiCenter(
    00611       ((w->width - 101) >> 1) + 98,
    00612       90,
    00613       STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
    00614       w->width - 101);
    00615     break;
    00616
    00617   case NB_BMERGER:
    00618     DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
    00619     SetDParam(0, ni->params[0]);
    00620     SetDParam(1, p->index);
    00621     SetDParam(2, ni->params[1]);
    00622     DrawStringMultiCenter(
    00623       ((w->width - 101) >> 1) + 98,
    00624       90,
    00625       ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
    00626       w->width - 101);
    00627     break;
    00628
    00629   case NB_BBANKRUPT:
    00630     DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
    00631     SetDParam(0, ni->params[0]);
    00632     DrawStringMultiCenter(
    00633       ((w->width - 101) >> 1) + 98,
    00634       90,
    00635       STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
    00636       w->width - 101);
    00637     break;
    00638
    00639   case NB_BNEWCOMPANY:
    00640     DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
    00641     SetDParam(0, p->index);
    00642     SetDParam(1, ni->params[0]);
    00643     DrawStringMultiCenter(
    00644       ((w->width - 101) >> 1) + 98,
    00645       90,
    00646       STR_705F_STARTS_CONSTRUCTION_NEAR,
    00647       w->width - 101);
    00648     break;
    00649
    00650   default:
    00651     NOT_REACHED();
    00652   }
    00653 }
    00654
    00655 StringID GetNewsStringBankrupcy(const NewsItem *ni)
    00656 {
    00657   const Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
    00658
    00659   switch (ni->string_id & 0xF0) {
    00660   case NB_BTROUBLE:
    00661     SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
    00662     SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
    00663     SetDParam(2, p->index);
    00664     return STR_02B6;
    00665   case NB_BMERGER:
    00666     SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
    00667     SetDParam(1, ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
    00668     SetDParam(2, ni->params[0]);
    00669     SetDParam(3, p->index);
    00670     SetDParam(4, ni->params[1]);
    00671     return STR_02B6;
    00672   case NB_BBANKRUPT:
    00673     SetDParam(0, STR_705C_BANKRUPT);
    00674     SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
    00675     SetDParam(2, ni->params[0]);
    00676     return STR_02B6;
    00677   case NB_BNEWCOMPANY:
    00678     SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
    00679     SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
    00680     SetDParam(2, p->index);
    00681     SetDParam(3, ni->params[0]);
    00682     return STR_02B6;
    00683   default:
    00684     NOT_REACHED();
    00685   }
    00686 }
    00687
    00688 static void PlayersGenStatistics()
    00689 {
    00690   Station *st;
    00691   Player *p;
    00692
    00693   FOR_ALL_STATIONS(st) {
    00694     _current_player = st->owner;
    00695     CommandCost cost(EXPENSES_PROPERTY, _price.station_value >> 1);
    00696     SubtractMoneyFromPlayer(cost);
    00697   }
    00698
    00699   if (!HasBit(1<<0|1<<3|1<<6|1<<9, _cur_month))
    00700     return;
    00701
    00702   FOR_ALL_PLAYERS(p) {
    00703     if (p->is_active) {
    00704       memmove(&p->old_economy[1], &p->old_economy[0], sizeof(p->old_economy) - sizeof(p->old_economy[0]));
    00705       p->old_economy[0] = p->cur_economy;
    00706       memset(&p->cur_economy, 0, sizeof(p->cur_economy));
    00707
    00708       if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++;
    00709
    00710       UpdateCompanyRatingAndValue(p, true);
    00711       PlayersCheckBankrupt(p);
    00712
    00713       if (p->block_preview != 0) p->block_preview--;
    00714     }
    00715   }
    00716
    00717   InvalidateWindow(WC_INCOME_GRAPH, 0);
    00718   InvalidateWindow(WC_OPERATING_PROFIT, 0);
    00719   InvalidateWindow(WC_DELIVERED_CARGO, 0);
    00720   InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
    00721   InvalidateWindow(WC_COMPANY_VALUE, 0);
    00722   InvalidateWindow(WC_COMPANY_LEAGUE, 0);
    00723 }
    00724
    00725 static void AddSingleInflation(Money *value, uint16 *frac, int32 amt)
    00726 {
    00727   /* Is it safe to add inflation ? */
    00728   if ((INT64_MAX / amt) < (*value + 1)) {
    00729     *value = INT64_MAX / amt;
    00730     *frac = 0;
    00731   } else {
    00732     int64 tmp = (int64)*value * amt + *frac;
    00733     *frac   = GB(tmp, 0, 16);
    00734     *value += tmp >> 16;
    00735   }
    00736 }
    00737
    00738 static void AddInflation()
    00739 {
    00740   /* The cargo payment inflation differs from the normal inflation, so the
    00741    * relative amount of money you make with a transport decreases slowly over
    00742    * the 170 years. After a few hundred years we reach a level in which the
    00743    * games will become unplayable as the maximum income will be less than
    00744    * the minimum running cost.
    00745    *
    00746    * Furthermore there are a lot of inflation related overflows all over the
    00747    * place. Solving them is hardly possible because inflation will always
    00748    * reach the overflow threshold some day. So we'll just perform the
    00749    * inflation mechanism during the first 170 years (the amount of years that
    00750    * one had in the original TTD) and stop doing the inflation after that
    00751    * because it only causes problems that can't be solved nicely and the
    00752    * inflation doesn't add anything after that either; it even makes playing
    00753    * it impossible due to the diverging cost and income rates.
    00754    */
    00755   if ((_cur_year - _patches.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return;
    00756
    00757   /* Approximation for (100 + infl_amount)% ** (1 / 12) - 100%
    00758    * scaled by 65536
    00759    * 12 -> months per year
    00760    * This is only a good approxiamtion for small values
    00761    */
    00762   Money inf = _economy.infl_amount * 54;
    00763
    00764   for (uint i = 0; i != NUM_PRICES; i++) {
    00765     AddSingleInflation((Money*)&_price + i, _price_frac + i, inf);
    00766   }
    00767
    00768   AddSingleInflation(&_economy.max_loan_unround, &_economy.max_loan_unround_fract, inf);
    00769
    00770   if (_economy.max_loan + 50000 <= _economy.max_loan_unround) _economy.max_loan += 50000;
    00771
    00772   inf = _economy.infl_amount_pr * 54;
    00773   for (CargoID i = 0; i < NUM_CARGO; i++) {
    00774     AddSingleInflation(
    00775       (Money*)_cargo_payment_rates + i,
    00776       _cargo_payment_rates_frac + i,
    00777       inf
    00778     );
    00779   }
    00780
    00781   InvalidateWindowClasses(WC_BUILD_VEHICLE);
    00782   InvalidateWindowClasses(WC_REPLACE_VEHICLE);
    00783   InvalidateWindowClasses(WC_VEHICLE_DETAILS);
    00784   InvalidateWindow(WC_PAYMENT_RATES, 0);
    00785 }
    00786
    00787 static void PlayersPayInterest()
    00788 {
    00789   const Player* p;
    00790   int interest = _economy.interest_rate * 54;
    00791
    00792   FOR_ALL_PLAYERS(p) {
    00793     if (!p->is_active) continue;
    00794
    00795     _current_player = p->index;
    00796
    00797     SubtractMoneyFromPlayer(CommandCost(EXPENSES_LOAN_INT, (Money)BigMulSU(p->current_loan, interest, 16)));
    00798
    00799     SubtractMoneyFromPlayer(CommandCost(EXPENSES_OTHER, _price.station_value >> 2));
    00800   }
    00801 }
    00802
    00803 static void HandleEconomyFluctuations()
    00804 {
    00805   if (_opt.diff.economy == 0) return;
    00806
    00807   if (--_economy.fluct == 0) {
    00808     _economy.fluct = -(int)GB(Random(), 0, 2);
    00809     AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
    00810   } else if (_economy.fluct == -12) {
    00811     _economy.fluct = GB(Random(), 0, 8) + 312;
    00812     AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
    00813   }
    00814 }
    00815
    00816 static byte _price_category[NUM_PRICES] = {
    00817   0, 2, 2, 2, 2, 2, 2, 2,
    00818   2, 2, 2, 2, 2, 2, 2, 2,
    00819   2, 2, 2, 2, 2, 2, 2, 2,
    00820   2, 2, 2, 2, 2, 2, 2, 2,
    00821   2, 2, 2, 2, 2, 2, 2, 2,
    00822   2, 2, 1, 1, 1, 1, 1, 1,
    00823   2,
    00824 };
    00825
    00826 static const Money _price_base[NUM_PRICES] = {
    00827       100,
    00828       100,
    00829        95,
    00830        65,
    00831       275,
    00832       600,
    00833       500,
    00834       700,
    00835       450,
    00836       200,
    00837       180,
    00838       600,
    00839       200,
    00840       200,
    00841       350,
    00842    400000,
    00843      2000,
    00844    700000,
    00845     14000,
    00846     65000,
    00847        20,
    00848       250,
    00849        20,
    00850        40,
    00851       200,
    00852       500,
    00853        20,
    00854       -70,
    00855        10,
    00856        50,
    00857        80,
    00858        80,
    00859        90,
    00860        30,
    00861     10000,
    00862        50,
    00863        30,
    00864        50,
    00865        50,
    00866        55,
    00867      1600,
    00868        40,
    00869      5600,
    00870      5200,
    00871      4800,
    00872      9600,
    00873      1600,
    00874      5600,
    00875   1000000,
    00876 };
    00877
    00878 static byte price_base_multiplier[NUM_PRICES];
    00879
    00883 void ResetPriceBaseMultipliers()
    00884 {
    00885   uint i;
    00886
    00887   /* 8 means no multiplier. */
    00888   for (i = 0; i < NUM_PRICES; i++)
    00889     price_base_multiplier[i] = 8;
    00890 }
    00891
    00899 void SetPriceBaseMultiplier(uint price, byte factor)
    00900 {
    00901   assert(price < NUM_PRICES);
    00902   price_base_multiplier[price] = factor;
    00903 }
    00904
    00905 void StartupEconomy()
    00906 {
    00907   int i;
    00908
    00909   assert(sizeof(_price) == NUM_PRICES * sizeof(Money));
    00910
    00911   for (i = 0; i != NUM_PRICES; i++) {
    00912     Money price = _price_base[i];
    00913     if (_price_category[i] != 0) {
    00914       uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
    00915       if (mod < 1) {
    00916         price = price * 3 >> 2;
    00917       } else if (mod > 1) {
    00918         price = price * 9 >> 3;
    00919       }
    00920     }
    00921     if (price_base_multiplier[i] > 8) {
    00922       price <<= price_base_multiplier[i] - 8;
    00923     } else {
    00924       price >>= 8 - price_base_multiplier[i];
    00925     }
    00926     ((Money*)&_price)[i] = price;
    00927     _price_frac[i] = 0;
    00928   }
    00929
    00930   _economy.interest_rate = _opt.diff.initial_interest;
    00931   _economy.infl_amount = _opt.diff.initial_interest;
    00932   _economy.infl_amount_pr = max(0, _opt.diff.initial_interest - 1);
    00933   _economy.max_loan_unround = _economy.max_loan = _opt.diff.max_loan * 1000;
    00934   _economy.fluct = GB(Random(), 0, 8) + 168;
    00935 }
    00936
    00937
    00938 Money GetPriceByIndex(uint8 index)
    00939 {
    00940   if (index > NUM_PRICES) return 0;
    00941
    00942   return ((Money*)&_price)[index];
    00943 }
    00944
    00945
    00946 Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode)
    00947 {
    00948   TileIndex tile;
    00949   TileIndex tile2;
    00950   Pair tp;
    00951
    00952   /* if mode is false, use the singular form */
    00953   const CargoSpec *cs = GetCargo(s->cargo_type);
    00954   SetDParam(0, mode ? cs->name : cs->name_single);
    00955
    00956   if (s->age < 12) {
    00957     if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
    00958       SetDParam(1, STR_INDUSTRY);
    00959       SetDParam(2, s->from);
    00960       tile = GetIndustry(s->from)->xy;
    00961
    00962       if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
    00963         SetDParam(4, STR_INDUSTRY);
    00964         SetDParam(5, s->to);
    00965         tile2 = GetIndustry(s->to)->xy;
    00966       } else {
    00967         SetDParam(4, STR_TOWN);
    00968         SetDParam(5, s->to);
    00969         tile2 = GetTown(s->to)->xy;
    00970       }
    00971     } else {
    00972       SetDParam(1, STR_TOWN);
    00973       SetDParam(2, s->from);
    00974       tile = GetTown(s->from)->xy;
    00975
    00976       SetDParam(4, STR_TOWN);
    00977       SetDParam(5, s->to);
    00978       tile2 = GetTown(s->to)->xy;
    00979     }
    00980   } else {
    00981     SetDParam(1, s->from);
    00982     tile = GetStation(s->from)->xy;
    00983
    00984     SetDParam(2, s->to);
    00985     tile2 = GetStation(s->to)->xy;
    00986   }
    00987
    00988   tp.a = tile;
    00989   tp.b = tile2;
    00990
    00991   return tp;
    00992 }
    00993
    00994 void DeleteSubsidyWithTown(TownID index)
    00995 {
    00996   Subsidy *s;
    00997
    00998   for (s = _subsidies; s != endof(_subsidies); s++) {
    00999     if (s->cargo_type != CT_INVALID && s->age < 12) {
    01000       const CargoSpec *cs = GetCargo(s->cargo_type);
    01001       if (((cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) && (index == s->from || index == s->to)) ||
    01002         ((cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) && index == s->to)) {
    01003         s->cargo_type = CT_INVALID;
    01004       }
    01005     }
    01006   }
    01007 }
    01008
    01009 void DeleteSubsidyWithIndustry(IndustryID index)
    01010 {
    01011   Subsidy *s;
    01012
    01013   for (s = _subsidies; s != endof(_subsidies); s++) {
    01014     if (s->cargo_type != CT_INVALID && s->age < 12) {
    01015       const CargoSpec *cs = GetCargo(s->cargo_type);
    01016       if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL &&
    01017         (index == s->from || (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD && index == s->to))) {
    01018         s->cargo_type = CT_INVALID;
    01019       }
    01020     }
    01021   }
    01022 }
    01023
    01024 void DeleteSubsidyWithStation(StationID index)
    01025 {
    01026   Subsidy *s;
    01027   bool dirty = false;
    01028
    01029   for (s = _subsidies; s != endof(_subsidies); s++) {
    01030     if (s->cargo_type != CT_INVALID && s->age >= 12 &&
    01031         (s->from == index || s->to == index)) {
    01032       s->cargo_type = CT_INVALID;
    01033       dirty = true;
    01034     }
    01035   }
    01036
    01037   if (dirty)
    01038     InvalidateWindow(WC_SUBSIDIES_LIST, 0);
    01039 }
    01040
    01041 struct FoundRoute {
    01042   uint distance;
    01043   CargoID cargo;
    01044   void *from;
    01045   void *to;
    01046 };
    01047
    01048 static void FindSubsidyPassengerRoute(FoundRoute *fr)
    01049 {
    01050   Town *from,*to;
    01051
    01052   fr->distance = (uint)-1;
    01053
    01054   fr->from = from = GetRandomTown();
    01055   if (from == NULL || from->population < 400) return;
    01056
    01057   fr->to = to = GetRandomTown();
    01058   if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
    01059     return;
    01060
    01061   fr->distance = DistanceManhattan(from->xy, to->xy);
    01062 }
    01063
    01064 static void FindSubsidyCargoRoute(FoundRoute *fr)
    01065 {
    01066   Industry *i;
    01067   int trans, total;
    01068   CargoID cargo;
    01069
    01070   fr->distance = (uint)-1;
    01071
    01072   fr->from = i = GetRandomIndustry();
    01073   if (i == NULL) return;
    01074
    01075   /* Randomize cargo type */
    01076   if (HasBit(Random(), 0) && i->produced_cargo[1] != CT_INVALID) {
    01077     cargo = i->produced_cargo[1];
    01078     trans = i->last_month_pct_transported[1];
    01079     total = i->last_month_production[1];
    01080   } else {
    01081     cargo = i->produced_cargo[0];
    01082     trans = i->last_month_pct_transported[0];
    01083     total = i->last_month_production[0];
    01084   }
    01085
    01086   /* Quit if no production in this industry
    01087    * or if the cargo type is passengers
    01088    * or if the pct transported is already large enough */
    01089   if (total == 0 || trans > 42 || cargo == CT_INVALID) return;
    01090
    01091   const CargoSpec *cs = GetCargo(cargo);
    01092   if (cs->town_effect == TE_PASSENGERS) return;
    01093
    01094   fr->cargo = cargo;
    01095
    01096   if (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) {
    01097     /*  The destination is a town */
    01098     Town *t = GetRandomTown();
    01099
    01100     /* Only want big towns */
    01101     if (t == NULL || t->population < 900) return;
    01102
    01103     fr->distance = DistanceManhattan(i->xy, t->xy);
    01104     fr->to = t;
    01105   } else {
    01106     /* The destination is an industry */
    01107     Industry *i2 = GetRandomIndustry();
    01108
    01109     /* The industry must accept the cargo */
    01110     if (i2 == NULL || i == i2 ||
    01111         (cargo != i2->accepts_cargo[0] &&
    01112         cargo != i2->accepts_cargo[1] &&
    01113         cargo != i2->accepts_cargo[2])) {
    01114       return;
    01115     }
    01116     fr->distance = DistanceManhattan(i->xy, i2->xy);
    01117     fr->to = i2;
    01118   }
    01119 }
    01120
    01121 static bool CheckSubsidyDuplicate(Subsidy *s)
    01122 {
    01123   const Subsidy* ss;
    01124
    01125   for (ss = _subsidies; ss != endof(_subsidies); ss++) {
    01126     if (s != ss &&
    01127         ss->from == s->from &&
    01128         ss->to == s->to &&
    01129         ss->cargo_type == s->cargo_type) {
    01130       s->cargo_type = CT_INVALID;
    01131       return true;
    01132     }
    01133   }
    01134   return false;
    01135 }
    01136
    01137
    01138 static void SubsidyMonthlyHandler()
    01139 {
    01140   Subsidy *s;
    01141   Pair pair;
    01142   Station *st;
    01143   uint n;
    01144   FoundRoute fr;
    01145   bool modified = false;
    01146
    01147   for (s = _subsidies; s != endof(_subsidies); s++) {
    01148     if (s->cargo_type == CT_INVALID) continue;
    01149
    01150     if (s->age == 12-1) {
    01151       pair = SetupSubsidyDecodeParam(s, 1);
    01152       AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
    01153       s->cargo_type = CT_INVALID;
    01154       modified = true;
    01155     } else if (s->age == 2*12-1) {
    01156       st = GetStation(s->to);
    01157       if (st->owner == _local_player) {
    01158         pair = SetupSubsidyDecodeParam(s, 1);
    01159         AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
    01160       }
    01161       s->cargo_type = CT_INVALID;
    01162       modified = true;
    01163     } else {
    01164       s->age++;
    01165     }
    01166   }
    01167
    01168   /* 25% chance to go on */
    01169   if (Chance16(1,4)) {
    01170     /*  Find a free slot*/
    01171     s = _subsidies;
    01172     while (s->cargo_type != CT_INVALID) {
    01173       if (++s == endof(_subsidies))
    01174         goto no_add;
    01175     }
    01176
    01177     n = 1000;
    01178     do {
    01179       FindSubsidyPassengerRoute(&fr);
    01180       if (fr.distance <= 70) {
    01181         s->cargo_type = CT_PASSENGERS;
    01182         s->from = ((Town*)fr.from)->index;
    01183         s->to = ((Town*)fr.to)->index;
    01184         goto add_subsidy;
    01185       }
    01186       FindSubsidyCargoRoute(&fr);
    01187       if (fr.distance <= 70) {
    01188         s->cargo_type = fr.cargo;
    01189         s->from = ((Industry*)fr.from)->index;
    01190         {
    01191           const CargoSpec *cs = GetCargo(fr.cargo);
    01192           s->to = (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
    01193         }
    01194   add_subsidy:
    01195         if (!CheckSubsidyDuplicate(s)) {
    01196           s->age = 0;
    01197           pair = SetupSubsidyDecodeParam(s, 0);
    01198           AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
    01199           modified = true;
    01200           break;
    01201         }
    01202       }
    01203     } while (n--);
    01204   }
    01205 no_add:;
    01206   if (modified)
    01207     InvalidateWindow(WC_SUBSIDIES_LIST, 0);
    01208 }
    01209
    01210 static const SaveLoad _subsidies_desc[] = {
    01211       SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
    01212       SLE_VAR(Subsidy, age,        SLE_UINT8),
    01213   SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
    01214   SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
    01215   SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
    01216   SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
    01217   SLE_END()
    01218 };
    01219
    01220 static void Save_SUBS()
    01221 {
    01222   int i;
    01223   Subsidy *s;
    01224
    01225   for (i = 0; i != lengthof(_subsidies); i++) {
    01226     s = &_subsidies[i];
    01227     if (s->cargo_type != CT_INVALID) {
    01228       SlSetArrayIndex(i);
    01229       SlObject(s, _subsidies_desc);
    01230     }
    01231   }
    01232 }
    01233
    01234 static void Load_SUBS()
    01235 {
    01236   int index;
    01237   while ((index = SlIterateArray()) != -1)
    01238     SlObject(&_subsidies[index], _subsidies_desc);
    01239 }
    01240
    01241 Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
    01242 {
    01243   const CargoSpec *cs = GetCargo(cargo_type);
    01244
    01245   /* Use callback to calculate cargo profit, if available */
    01246   if (HasBit(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) {
    01247     uint32 var18 = min(dist, 0xFFFF) | (min(num_pieces, 0xFF) << 16) | (transit_days << 24);
    01248     uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs);
    01249     if (callback != CALLBACK_FAILED) {
    01250       int result = GB(callback, 0, 14);
    01251
    01252       /* Simulate a 15 bit signed value */
    01253       if (HasBit(callback, 14)) result = 0x4000 - result;
    01254
    01255       /* "The result should be a signed multiplier that gets multiplied
    01256        * by the amount of cargo moved and the price factor, then gets
    01257        * divided by 8192." */
    01258       return result * num_pieces * _cargo_payment_rates[cargo_type] / 8192;
    01259     }
    01260   }
    01261
    01262   /* zero the distance (thus income) if it's the bank and very short transport. */
    01263   if (_opt.landscape == LT_TEMPERATE && cs->label == 'VALU' && dist < 10) return 0;
    01264
    01265
    01266   static const int MIN_TIME_FACTOR = 31;
    01267   static const int MAX_TIME_FACTOR = 255;
    01268
    01269   const int days1 = cs->transit_days[0];
    01270   const int days2 = cs->transit_days[1];
    01271   const int days_over_days1 = transit_days - days1;
    01272
    01273   /*
    01274    * The time factor is calculated based on the time it took
    01275    * (transit_days) compared two cargo-depending values. The
    01276    * range is divided into three parts:
    01277    *
    01278    *  - constant for fast transits
    01279    *  - linear decreasing with time with a slope of -1 for medium transports
    01280    *  - linear decreasing with time with a slope of -2 for slow transports
    01281    *
    01282    */
    01283   int time_factor;
    01284   if (days_over_days1 <= 0) {
    01285     time_factor = MAX_TIME_FACTOR;
    01286   } else if (days_over_days1 <= days2) {
    01287     time_factor = MAX_TIME_FACTOR - days_over_days1;
    01288   } else {
    01289     time_factor = MAX_TIME_FACTOR - 2 * days_over_days1 + days2;
    01290   }
    01291
    01292   if (time_factor < MIN_TIME_FACTOR) time_factor = MIN_TIME_FACTOR;
    01293
    01294   return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
    01295 }
    01296
    01297 static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
    01298 {
    01299   Industry *best = NULL;
    01300   Industry *ind;
    01301   const IndustrySpec *indspec;
    01302   uint best_dist;
    01303   uint accepted_cargo_index = 0;
    01304
    01305   /* Check if there's an industry close to the station that accepts the cargo
    01306    * XXX - Think of something better to
    01307    *       1) Only deliver to industries which are withing the catchment radius
    01308    *       2) Distribute between industries if more then one is present */
    01309   best_dist = (_patches.station_spread + 8) * 2;
    01310   FOR_ALL_INDUSTRIES(ind) {
    01311     indspec = GetIndustrySpec(ind->type);
    01312     uint i;
    01313
    01314     for (i = 0; i < lengthof(ind->accepts_cargo); i++) {
    01315       if (cargo_type == ind->accepts_cargo[i]) break;
    01316     }
    01317
    01318     /* Check if matching cargo has been found */
    01319     if (i == lengthof(ind->accepts_cargo)) continue;
    01320
    01321     if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
    01322       uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
    01323       if (res == 0) continue;
    01324     }
    01325
    01326     uint dist = DistanceManhattan(ind->xy, xy);
    01327
    01328     if (dist < best_dist) {
    01329       best = ind;
    01330       best_dist = dist;
    01331       accepted_cargo_index = i;
    01332     }
    01333   }
    01334
    01335   /* Found one? */
    01336   if (best != NULL) {
    01337     indspec = GetIndustrySpec(best->type);
    01338     uint16 callback = indspec->callback_flags;
    01339
    01340     best->was_cargo_delivered = true;
    01341     best->last_cargo_accepted_at = _date;
    01342
    01343     if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
    01344       best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
    01345       if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
    01346         IndustryProductionCallback(best, 0);
    01347       } else {
    01348         InvalidateWindow(WC_INDUSTRY_VIEW, best->index);
    01349       }
    01350     } else {
    01351       best->produced_cargo_waiting[0] = min(best->produced_cargo_waiting[0] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][0] / 256), 0xFFFF);
    01352       best->produced_cargo_waiting[1] = min(best->produced_cargo_waiting[1] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][1] / 256), 0xFFFF);
    01353     }
    01354
    01355     TriggerIndustry(best, INDUSTRY_TRIGGER_RECEIVED_CARGO);
    01356     StartStopIndustryTileAnimation(best, IAT_INDUSTRY_RECEIVED_CARGO);
    01357   }
    01358 }
    01359
    01360 static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
    01361 {
    01362   Subsidy *s;
    01363   TileIndex xy;
    01364   Pair pair;
    01365
    01366   /* check if there is an already existing subsidy that applies to us */
    01367   for (s = _subsidies; s != endof(_subsidies); s++) {
    01368     if (s->cargo_type == cargo_type &&
    01369         s->age >= 12 &&
    01370         s->from == from->index &&
    01371         s->to == to->index) {
    01372       return true;
    01373     }
    01374   }
    01375
    01376   /* check if there's a new subsidy that applies.. */
    01377   for (s = _subsidies; s != endof(_subsidies); s++) {
    01378     if (s->cargo_type == cargo_type && s->age < 12) {
    01379       /* Check distance from source */
    01380       const CargoSpec *cs = GetCargo(cargo_type);
    01381       if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
    01382         xy = GetTown(s->from)->xy;
    01383       } else {
    01384         xy = (GetIndustry(s->from))->xy;
    01385       }
    01386       if (DistanceMax(xy, from->xy) > 9) continue;
    01387
    01388       /* Check distance from dest */
    01389       switch (cs->town_effect) {
    01390         case TE_PASSENGERS:
    01391         case TE_MAIL:
    01392         case TE_GOODS:
    01393         case TE_FOOD:
    01394           xy = GetTown(s->to)->xy;
    01395           break;
    01396
    01397         default:
    01398           xy = GetIndustry(s->to)->xy;
    01399           break;
    01400       }
    01401       if (DistanceMax(xy, to->xy) > 9) continue;
    01402
    01403       /* Found a subsidy, change the values to indicate that it's in use */
    01404       s->age = 12;
    01405       s->from = from->index;
    01406       s->to = to->index;
    01407
    01408       /* Add a news item */
    01409       pair = SetupSubsidyDecodeParam(s, 0);
    01410       InjectDParam(1);
    01411
    01412       SetDParam(0, _current_player);
    01413       AddNewsItem(
    01414         STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
    01415         NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
    01416         pair.a, pair.b
    01417       );
    01418
    01419       InvalidateWindow(WC_SUBSIDIES_LIST, 0);
    01420       return true;
    01421     }
    01422   }
    01423   return false;
    01424 }
    01425
    01426 static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit)
    01427 {
    01428   bool subsidised;
    01429   Station *s_from, *s_to;
    01430   Money profit;
    01431
    01432   assert(num_pieces > 0);
    01433
    01434   /* Update player statistics */
    01435   {
    01436     Player *p = GetPlayer(_current_player);
    01437     p->cur_economy.delivered_cargo += num_pieces;
    01438     SetBit(p->cargo_types, cargo_type);
    01439   }
    01440
    01441   /* Get station pointers. */
    01442   s_from = GetStation(source);
    01443   s_to = GetStation(dest);
    01444
    01445   /* Check if a subsidy applies. */
    01446   subsidised = CheckSubsidised(s_from, s_to, cargo_type);
    01447
    01448   /* Increase town's counter for some special goods types */
    01449   const CargoSpec *cs = GetCargo(cargo_type);
    01450   if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
    01451   if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
    01452
    01453   /* Give the goods to the industry. */
    01454   DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
    01455
    01456   /* Determine profit */
    01457   profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
    01458
    01459   /* Modify profit if a subsidy is in effect */
    01460   if (subsidised) {
    01461     switch (_opt.diff.subsidy_multiplier) {
    01462       case 0:  profit += profit >> 1; break;
    01463       case 1:  profit *= 2; break;
    01464       case 2:  profit *= 3; break;
    01465       default: profit *= 4; break;
    01466     }
    01467   }
    01468
    01469   return profit;
    01470 }
    01471
    01476 void VehiclePayment(Vehicle *front_v)
    01477 {
    01478   int result = 0;
    01479
    01480   Money vehicle_profit = 0; // Money paid to the train
    01481   Money route_profit   = 0; // The grand total amount for the route. A-D of transfer chain A-B-C-D
    01482   Money virtual_profit = 0; // The virtual profit for entire vehicle chain
    01483
    01484   StationID last_visited = front_v->last_station_visited;
    01485   Station *st = GetStation(last_visited);
    01486
    01487   /* The owner of the train wants to be paid */
    01488   PlayerID old_player = _current_player;
    01489   _current_player = front_v->owner;
    01490
    01491   /* At this moment loading cannot be finished */
    01492   ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED);
    01493
    01494   /* Start unloading in at the first possible moment */
    01495   front_v->load_unload_time_rem = 1;
    01496
    01497   for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
    01498     /* No cargo to unload */
    01499     if (v->cargo_cap == 0 || v->cargo.Empty()) continue;
    01500
    01501     /* All cargo has already been paid for, no need to pay again */
    01502     if (!v->cargo.UnpaidCargo()) {
    01503       SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
    01504       continue;
    01505     }
    01506
    01507     GoodsEntry *ge = &st->goods[v->cargo_type];
    01508     const CargoList::List *cargos = v->cargo.Packets();
    01509
    01510     for (CargoList::List::const_iterator it = cargos->begin(); it != cargos->end(); it++) {
    01511       CargoPacket *cp = *it;
    01512       if (!cp->paid_for &&
    01513           cp->source != last_visited &&
    01514           HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) &&
    01515           (front_v->current_order.flags & OFB_TRANSFER) == 0) {
    01516         /* Deliver goods to the station */
    01517         st->time_since_unload = 0;
    01518
    01519         /* handle end of route payment */
    01520         Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit);
    01521         cp->paid_for = true;
    01522         route_profit   += profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
    01523         vehicle_profit += profit - cp->feeder_share;                    // whole vehicle is not payed for transfers picked up earlier
    01524
    01525         result |= 1;
    01526
    01527         SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
    01528       } else if (front_v->current_order.flags & (OFB_UNLOAD | OFB_TRANSFER)) {
    01529         if (!cp->paid_for && (front_v->current_order.flags & OFB_TRANSFER) != 0) {
    01530           Money profit = GetTransportedGoodsIncome(
    01531             cp->count,
    01532             /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
    01533             DistanceManhattan(cp->loaded_at_xy, GetStation(last_visited)->xy),
    01534             cp->days_in_transit,
    01535             v->cargo_type);
    01536
    01537           front_v->profit_this_year += profit << 8;
    01538           virtual_profit   += profit; // accumulate transfer profits for whole vehicle
    01539           cp->feeder_share += profit; // account for the (virtual) profit already made for the cargo packet
    01540           cp->paid_for      = true;   // record that the cargo has been paid for to eliminate double counting
    01541         }
    01542         result |= 2;
    01543
    01544         SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
    01545       }
    01546     }
    01547     v->cargo.InvalidateCache();
    01548   }
    01549
    01550   if (virtual_profit > 0) {
    01551     ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
    01552   }
    01553
    01554   if (route_profit != 0) {
    01555     front_v->profit_this_year += vehicle_profit << 8;
    01556     SubtractMoneyFromPlayer(CommandCost(front_v->GetExpenseType(true), -route_profit));
    01557
    01558     if (IsLocalPlayer() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
    01559       SndPlayVehicleFx(SND_14_CASHTILL, front_v);
    01560     }
    01561
    01562     ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -vehicle_profit);
    01563   }
    01564
    01565   _current_player = old_player;
    01566 }
    01567
    01576 static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
    01577 {
    01578   assert(v->current_order.type == OT_LOADING);
    01579
    01580   /* We have not waited enough time till the next round of loading/unloading */
    01581   if (--v->load_unload_time_rem != 0) {
    01582     if (_patches.improved_load && HasBit(v->current_order.flags, OF_FULL_LOAD)) {
    01583       /* 'Reserve' this cargo for this vehicle, because we were first. */
    01584       for (; v != NULL; v = v->Next()) {
    01585         if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
    01586       }
    01587     }
    01588     return;
    01589   }
    01590
    01591   StationID last_visited = v->last_station_visited;
    01592   Station *st = GetStation(last_visited);
    01593
    01594   if (v->type == VEH_TRAIN && (!IsTileType(v->tile, MP_STATION) || GetStationIndex(v->tile) != st->index)) {
    01595     /* The train reversed in the station. Take the "easy" way
    01596      * out and let the train just leave as it always did. */
    01597     SetBit(v->vehicle_flags, VF_LOADING_FINISHED);
    01598     return;
    01599   }
    01600
    01601   int unloading_time = 0;
    01602   Vehicle *u = v;
    01603   int result = 0;
    01604   uint cap;
    01605
    01606   bool completely_emptied = true;
    01607   bool anything_unloaded = false;
    01608   bool anything_loaded   = false;
    01609   uint32 cargo_not_full  = 0;
    01610   uint32 cargo_full      = 0;
    01611
    01612   v->cur_speed = 0;
    01613
    01614   for (; v != NULL; v = v->Next()) {
    01615     if (v->cargo_cap == 0) continue;
    01616
    01617     byte load_amount = EngInfo(v->engine_type)->load_amount;
    01618     if (_patches.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) {
    01619       uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
    01620       if (cb_load_amount != CALLBACK_FAILED && GB(cb_load_amount, 0, 8) != 0) load_amount = GB(cb_load_amount, 0, 8);
    01621     }
    01622
    01623     GoodsEntry *ge = &st->goods[v->cargo_type];
    01624
    01625     if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING)) {
    01626       uint cargo_count = v->cargo.Count();
    01627       uint amount_unloaded = _patches.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
    01628       bool remaining; // Are there cargo entities in this vehicle that can still be unloaded here?
    01629
    01630       if (HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) && !(u->current_order.flags & OFB_TRANSFER)) {
    01631         /* The cargo has reached it's final destination, the packets may now be destroyed */
    01632         remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, last_visited);
    01633
    01634         result |= 1;
    01635       } else if (u->current_order.flags & (OFB_UNLOAD | OFB_TRANSFER)) {
    01636         remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
    01637         SetBit(ge->acceptance_pickup, GoodsEntry::PICKUP);
    01638
    01639         result |= 2;
    01640       } else {
    01641         /* The order changed while unloading (unset unload/transfer) or the
    01642          * station does not accept goods anymore. */
    01643         ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
    01644         continue;
    01645       }
    01646
    01647       /* Deliver goods to the station */
    01648       st->time_since_unload = 0;
    01649
    01650       unloading_time += amount_unloaded;
    01651
    01652       anything_unloaded = true;
    01653       if (_patches.gradual_loading && remaining) {
    01654         completely_emptied = false;
    01655       } else {
    01656         /* We have finished unloading (cargo count == 0) */
    01657         ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
    01658       }
    01659
    01660       continue;
    01661     }
    01662
    01663     /* Do not pick up goods that we unloaded */
    01664     if (u->current_order.flags & OFB_UNLOAD) continue;
    01665
    01666     /* update stats */
    01667     int t;
    01668     switch (u->type) {
    01669       case VEH_TRAIN: t = u->u.rail.cached_max_speed; break;
    01670       case VEH_ROAD:  t = u->max_speed / 2;           break;
    01671       default:        t = u->max_speed;               break;
    01672     }
    01673
    01674     /* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
    01675     ge->last_speed = min(t, 255);
    01676     ge->last_age = _cur_year - u->build_year;
    01677     ge->days_since_pickup = 0;
    01678
    01679     /* If there's goods waiting at the station, and the vehicle
    01680      * has capacity for it, load it on the vehicle. */
    01681     if (!ge->cargo.Empty() &&
    01682         (cap = v->cargo_cap - v->cargo.Count()) != 0) {
    01683       uint count = ge->cargo.Count();
    01684
    01685       /* Skip loading this vehicle if another train/vehicle is already handling
    01686        * the same cargo type at this station */
    01687       if (_patches.improved_load && cargo_left[v->cargo_type] <= 0) {
    01688         SetBit(cargo_not_full, v->cargo_type);
    01689         continue;
    01690       }
    01691
    01692       if (cap > count) cap = count;
    01693       if (_patches.gradual_loading) cap = min(cap, load_amount);
    01694       if (_patches.improved_load) {
    01695         /* Don't load stuff that is already 'reserved' for other vehicles */
    01696         cap = min((uint)cargo_left[v->cargo_type], cap);
    01697         cargo_left[v->cargo_type] -= cap;
    01698       }
    01699
    01700       if (v->cargo.Empty()) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
    01701
    01702       /* TODO: Regarding this, when we do gradual loading, we
    01703        * should first unload all vehicles and then start
    01704        * loading them. Since this will cause
    01705        * VEHICLE_TRIGGER_EMPTY to be called at the time when
    01706        * the whole vehicle chain is really totally empty, the
    01707        * completely_emptied assignment can then be safely
    01708        * removed; that's how TTDPatch behaves too. --pasky */
    01709       completely_emptied = false;
    01710       anything_loaded = true;
    01711
    01712       ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
    01713
    01714       st->time_since_load = 0;
    01715       st->last_vehicle_type = v->type;
    01716
    01717       unloading_time += cap;
    01718
    01719       result |= 2;
    01720     }
    01721
    01722     if (v->cargo.Count() == v->cargo_cap) {
    01723       SetBit(cargo_full, v->cargo_type);
    01724     } else {
    01725       SetBit(cargo_not_full, v->cargo_type);
    01726     }
    01727   }
    01728
    01729   /* Only set completly_emptied, if we just unloaded all remaining cargo */
    01730   completely_emptied &= anything_unloaded;
    01731
    01732   /* We update these variables here, so gradual loading still fills
    01733    * all wagons at the same time instead of using the same 'improved'
    01734    * loading algorithm for the wagons (only fill wagon when there is
    01735    * enough to fill the previous wagons) */
    01736   if (_patches.improved_load && HasBit(u->current_order.flags, OF_FULL_LOAD)) {
    01737     /* Update left cargo */
    01738     for (v = u; v != NULL; v = v->Next()) {
    01739       if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
    01740     }
    01741   }
    01742
    01743   v = u;
    01744
    01745   if (anything_loaded || anything_unloaded) {
    01746     if (_patches.gradual_loading) {
    01747       /* The time it takes to load one 'slice' of cargo or passengers depends
    01748       * on the vehicle type - the values here are those found in TTDPatch */
    01749       const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
    01750
    01751       unloading_time = gradual_loading_wait_time[v->type];
    01752     }
    01753   } else {
    01754     bool finished_loading = true;
    01755     if (HasBit(v->current_order.flags, OF_FULL_LOAD)) {
    01756       if (_patches.full_load_any) {
    01757         /* if the aircraft carries passengers and is NOT full, then
    01758          * continue loading, no matter how much mail is in */
    01759         if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo.Count()) ||
    01760             (cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
    01761           finished_loading = false;
    01762         }
    01763       } else if (cargo_not_full != 0) {
    01764         finished_loading = false;
    01765       }
    01766     }
    01767     unloading_time = 20;
    01768
    01769     SB(v->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
    01770   }
    01771
    01772   if (v->type == VEH_TRAIN) {
    01773     /* Each platform tile is worth 2 rail vehicles. */
    01774     int overhang = v->u.rail.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
    01775     if (overhang > 0) {
    01776       unloading_time <<= 1;
    01777       unloading_time += (overhang * unloading_time) / 8;
    01778     }
    01779   }
    01780
    01781   /* Calculate the loading indicator fill percent and display
    01782    * In the Game Menu do not display indicators
    01783    * If _patches.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 )
    01784    * if _patches.loading_indicators == 1, _local_player must be the owner or must be a spectator to show ind., so 1 > 0
    01785    * if _patches.loading_indicators == 0, do not display indicators ... 0 is never greater than anything
    01786    */
    01787   if (_game_mode != GM_MENU && (_patches.loading_indicators > (uint)(v->owner != _local_player && _local_player != PLAYER_SPECTATOR))) {
    01788     StringID percent_up_down = STR_NULL;
    01789     int percent = CalcPercentVehicleFilled(v, &percent_up_down);
    01790     if (v->fill_percent_te_id == INVALID_TE_ID) {
    01791       v->fill_percent_te_id = ShowFillingPercent(v->x_pos, v->y_pos, v->z_pos + 20, percent, percent_up_down);
    01792     } else {
    01793       UpdateFillingPercent(v->fill_percent_te_id, percent, percent_up_down);
    01794     }
    01795   }
    01796
    01797   v->load_unload_time_rem = unloading_time;
    01798
    01799   if (completely_emptied) {
    01800     TriggerVehicle(v, VEHICLE_TRIGGER_EMPTY);
    01801   }
    01802
    01803   if (result != 0) {
    01804     InvalidateWindow(v->GetVehicleListWindowClass(), v->owner);
    01805     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01806
    01807     st->MarkTilesDirty(true);
    01808     v->MarkDirty();
    01809
    01810     if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited);
    01811   }
    01812 }
    01813
    01819 void LoadUnloadStation(Station *st)
    01820 {
    01821   int cargo_left[NUM_CARGO];
    01822
    01823   for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = st->goods[i].cargo.Count();
    01824
    01825   std::list<Vehicle *>::iterator iter;
    01826   for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
    01827     Vehicle *v = *iter;
    01828     if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) LoadUnloadVehicle(v, cargo_left);
    01829   }
    01830 }
    01831
    01832 void PlayersMonthlyLoop()
    01833 {
    01834   PlayersGenStatistics();
    01835   if (_patches.inflation && _cur_year < MAX_YEAR)
    01836     AddInflation();
    01837   PlayersPayInterest();
    01838   /* Reset the _current_player flag */
    01839   _current_player = OWNER_NONE;
    01840   HandleEconomyFluctuations();
    01841   SubsidyMonthlyHandler();
    01842 }
    01843
    01844 static void DoAcquireCompany(Player *p)
    01845 {
    01846   Player *owner;
    01847   int i;
    01848   Money value;
    01849
    01850   SetDParam(0, p->index);
    01851   SetDParam(1, p->bankrupt_value);
    01852   AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
    01853
    01854   /* original code does this a little bit differently */
    01855   PlayerID pi = p->index;
    01856   ChangeNetworkOwner(pi, _current_player);
    01857   ChangeOwnershipOfPlayerItems(pi, _current_player);
    01858
    01859   if (p->bankrupt_value == 0) {
    01860     owner = GetPlayer(_current_player);
    01861     owner->current_loan += p->current_loan;
    01862   }
    01863
    01864   value = CalculateCompanyValue(p) >> 2;
    01865   PlayerID old_player = _current_player;
    01866   for (i = 0; i != 4; i++) {
    01867     if (p->share_owners[i] != PLAYER_SPECTATOR) {
    01868       _current_player = p->share_owners[i];
    01869       SubtractMoneyFromPlayer(CommandCost(EXPENSES_OTHER, -value));
    01870     }
    01871   }
    01872   _current_player = old_player;
    01873
    01874   p->is_active = false;
    01875
    01876   DeletePlayerWindows(pi);
    01877   RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
    01878 }
    01879
    01880 extern int GetAmountOwnedBy(const Player *p, PlayerID owner);
    01881
    01888 CommandCost CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01889 {
    01890   Player *p;
    01891   CommandCost cost(EXPENSES_OTHER);
    01892
    01893   /* Check if buying shares is allowed (protection against modified clients) */
    01894   /* Cannot buy own shares */
    01895   if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR;
    01896
    01897   p = GetPlayer((PlayerID)p1);
    01898
    01899   /* Cannot buy shares of non-existent nor bankrupted company */
    01900   if (!p->is_active) return CMD_ERROR;
    01901
    01902   /* Protect new companies from hostile takeovers */
    01903   if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_PROTECTED);
    01904
    01905   /* Those lines are here for network-protection (clients can be slow) */
    01906   if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return cost;
    01907
    01908   /* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
    01909   if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return cost;
    01910
    01911   cost.AddCost(CalculateCompanyValue(p) >> 2);
    01912   if (flags & DC_EXEC) {
    01913     PlayerByte* b = p->share_owners;
    01914     int i;
    01915
    01916     while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
    01917     *b = _current_player;
    01918
    01919     for (i = 0; p->share_owners[i] == _current_player;) {
    01920       if (++i == 4) {
    01921         p->bankrupt_value = 0;
    01922         DoAcquireCompany(p);
    01923         break;
    01924       }
    01925     }
    01926     InvalidateWindow(WC_COMPANY, p1);
    01927   }
    01928   return cost;
    01929 }
    01930
    01937 CommandCost CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01938 {
    01939   Player *p;
    01940   Money cost;
    01941
    01942   /* Check if selling shares is allowed (protection against modified clients) */
    01943   /* Cannot sell own shares */
    01944   if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR;
    01945
    01946   p = GetPlayer((PlayerID)p1);
    01947
    01948   /* Cannot sell shares of non-existent nor bankrupted company */
    01949   if (!p->is_active) return CMD_ERROR;
    01950
    01951   /* Those lines are here for network-protection (clients can be slow) */
    01952   if (GetAmountOwnedBy(p, _current_player) == 0) return CommandCost();
    01953
    01954   /* adjust it a little to make it less profitable to sell and buy */
    01955   cost = CalculateCompanyValue(p) >> 2;
    01956   cost = -(cost - (cost >> 7));
    01957
    01958   if (flags & DC_EXEC) {
    01959     PlayerByte* b = p->share_owners;
    01960     while (*b != _current_player) b++; // share owners is guaranteed to contain player
    01961     *b = PLAYER_SPECTATOR;
    01962     InvalidateWindow(WC_COMPANY, p1);
    01963   }
    01964   return CommandCost(EXPENSES_OTHER, cost);
    01965 }
    01966
    01976 CommandCost CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01977 {
    01978   Player *p;
    01979   PlayerID pid = (PlayerID)p1;
    01980
    01981   /* Disable takeovers in multiplayer games */
    01982   if (!IsValidPlayer(pid) || _networking) return CMD_ERROR;
    01983
    01984   /* Do not allow players to take over themselves */
    01985   if (pid == _current_player) return CMD_ERROR;
    01986
    01987   p = GetPlayer(pid);
    01988
    01989   if (!p->is_ai) return CMD_ERROR;
    01990
    01991   if (flags & DC_EXEC) {
    01992     DoAcquireCompany(p);
    01993   }
    01994   return CommandCost(EXPENSES_OTHER, p->bankrupt_value);
    01995 }
    01996
    01998 static void SaveLoad_PRIC()
    01999 {
    02000   int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
    02001   SlArray(&_price,      NUM_PRICES, vt);
    02002   SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
    02003 }
    02004
    02006 static void SaveLoad_CAPR()
    02007 {
    02008   uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
    02009   int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
    02010   SlArray(&_cargo_payment_rates,      num_cargo, vt);
    02011   SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
    02012 }
    02013
    02014 static const SaveLoad _economy_desc[] = {
    02015   SLE_CONDVAR(Economy, max_loan,         SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
    02016   SLE_CONDVAR(Economy, max_loan,         SLE_INT64,                  65, SL_MAX_VERSION),
    02017   SLE_CONDVAR(Economy, max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
    02018   SLE_CONDVAR(Economy, max_loan_unround, SLE_INT64,                  65, SL_MAX_VERSION),
    02019   SLE_CONDVAR(Economy, max_loan_unround_fract, SLE_UINT16,           70, SL_MAX_VERSION),
    02020       SLE_VAR(Economy, fluct,            SLE_INT16),
    02021       SLE_VAR(Economy, interest_rate,    SLE_UINT8),
    02022       SLE_VAR(Economy, infl_amount,      SLE_UINT8),
    02023       SLE_VAR(Economy, infl_amount_pr,   SLE_UINT8),
    02024       SLE_END()
    02025 };
    02026
    02028 static void SaveLoad_ECMY()
    02029 {
    02030   SlObject(&_economy, _economy_desc);
    02031 }
    02032
    02033 extern const ChunkHandler _economy_chunk_handlers[] = {
    02034   { 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
    02035   { 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
    02036   { 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
    02037   { 'ECMY', SaveLoad_ECMY, SaveLoad_ECMY, CH_RIFF | CH_LAST},
    02038 };