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 };

Generated on Mon Sep 22 20:34:15 2008 for openttd by  doxygen 1.5.6