economy.cpp

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

Generated on Sun Mar 15 22:49:46 2009 for openttd by  doxygen 1.5.6