economy.cpp

Go to the documentation of this file.
00001 /* $Id: economy.cpp 15434 2009-02-09 21:20:05Z rubidium $ */
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   /* In all cases clear replace engine rules.
00402    * Even if it was copied, it could interfere with new owner's rules */
00403   RemoveAllEngineReplacementForCompany(GetCompany(old_owner));
00404 
00405   if (new_owner == INVALID_OWNER) {
00406     RemoveAllGroupsForCompany(old_owner);
00407   } else {
00408     Group *g;
00409     FOR_ALL_GROUPS(g) {
00410       if (g->owner == old_owner) g->owner = new_owner;
00411     }
00412   }
00413 
00414   Sign *si;
00415   FOR_ALL_SIGNS(si) {
00416     if (si->owner == old_owner) si->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner;
00417   }
00418 
00419   /* Change colour of existing windows */
00420   if (new_owner != INVALID_OWNER) ChangeWindowOwner(old_owner, new_owner);
00421 
00422   _current_company = old;
00423 
00424   MarkWholeScreenDirty();
00425 }
00426 
00427 static void ChangeNetworkOwner(Owner current_owner, Owner new_owner)
00428 {
00429 #ifdef ENABLE_NETWORK
00430   if (!_networking) return;
00431 
00432   if (current_owner == _local_company) {
00433     _network_playas = new_owner;
00434     SetLocalCompany(new_owner);
00435   }
00436 
00437   if (!_network_server) return;
00438 
00439   NetworkServerChangeOwner(current_owner, new_owner);
00440 #endif /* ENABLE_NETWORK */
00441 }
00442 
00443 static void CompanyCheckBankrupt(Company *c)
00444 {
00445   /*  If the company has money again, it does not go bankrupt */
00446   if (c->money >= 0) {
00447     c->quarters_of_bankrupcy = 0;
00448     return;
00449   }
00450 
00451   c->quarters_of_bankrupcy++;
00452 
00453   CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
00454   cni->FillData(c);
00455 
00456   switch (c->quarters_of_bankrupcy) {
00457     case 0:
00458     case 1:
00459       free(cni);
00460       break;
00461 
00462     case 2:
00463       SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
00464       SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
00465       SetDParamStr(2, cni->company_name);
00466       AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, 0, cni);
00467       AI::BroadcastNewEvent(new AIEventCompanyInTrouble(c->index));
00468       break;
00469     case 3: {
00470       /* XXX - In multiplayer, should we ask other companies if it wants to take
00471               over when it is a human company? -- TrueLight */
00472       if (IsHumanCompany(c->index)) {
00473         SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
00474         SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
00475         SetDParamStr(2, cni->company_name);
00476         AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, 0, cni);
00477         break;
00478       }
00479 
00480       /* Check if the company has any value.. if not, declare it bankrupt
00481        *  right now */
00482       Money val = CalculateCompanyValue(c);
00483       if (val > 0) {
00484         c->bankrupt_value = val;
00485         c->bankrupt_asked = 1 << c->index; // Don't ask the owner
00486         c->bankrupt_timeout = 0;
00487         free(cni);
00488         break;
00489       }
00490       /* Else, falltrue to case 4... */
00491     }
00492     default:
00493     case 4:
00494       if (!_networking && _local_company == c->index) {
00495         /* If we are in offline mode, leave the company playing. Eg. there
00496          * is no THE-END, otherwise mark the client as spectator to make sure
00497          * he/she is no long in control of this company. However... when you
00498          * join another company (cheat) the "unowned" company can bankrupt. */
00499         c->bankrupt_asked = MAX_UVALUE(CompanyMask);
00500         c->bankrupt_timeout = 0x456;
00501         break;
00502       }
00503 
00504       /* Close everything the owner has open */
00505       DeleteCompanyWindows(c->index);
00506 
00507       /* Show bankrupt news */
00508       SetDParam(0, STR_705C_BANKRUPT);
00509       SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
00510       SetDParamStr(2, cni->company_name);
00511       AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, 0, cni);
00512 
00513       /* Remove the company */
00514       ChangeNetworkOwner(c->index, COMPANY_SPECTATOR);
00515       ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
00516 
00517       if (!IsHumanCompany(c->index)) AI::Stop(c->index);
00518 
00519       CompanyID c_index = c->index;
00520       delete c;
00521       AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index));
00522   }
00523 }
00524 
00525 static void CompaniesGenStatistics()
00526 {
00527   Station *st;
00528   Company *c;
00529 
00530   FOR_ALL_STATIONS(st) {
00531     _current_company = st->owner;
00532     CommandCost cost(EXPENSES_PROPERTY, _price.station_value >> 1);
00533     SubtractMoneyFromCompany(cost);
00534   }
00535 
00536   if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month))
00537     return;
00538 
00539   FOR_ALL_COMPANIES(c) {
00540     memmove(&c->old_economy[1], &c->old_economy[0], sizeof(c->old_economy) - sizeof(c->old_economy[0]));
00541     c->old_economy[0] = c->cur_economy;
00542     memset(&c->cur_economy, 0, sizeof(c->cur_economy));
00543 
00544     if (c->num_valid_stat_ent != 24) c->num_valid_stat_ent++;
00545 
00546     UpdateCompanyRatingAndValue(c, true);
00547     CompanyCheckBankrupt(c);
00548 
00549     if (c->block_preview != 0) c->block_preview--;
00550   }
00551 
00552   InvalidateWindow(WC_INCOME_GRAPH, 0);
00553   InvalidateWindow(WC_OPERATING_PROFIT, 0);
00554   InvalidateWindow(WC_DELIVERED_CARGO, 0);
00555   InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
00556   InvalidateWindow(WC_COMPANY_VALUE, 0);
00557   InvalidateWindow(WC_COMPANY_LEAGUE, 0);
00558 }
00559 
00560 static void AddSingleInflation(Money *value, uint16 *frac, int32 amt)
00561 {
00562   /* Is it safe to add inflation ? */
00563   if ((INT64_MAX / amt) < (*value + 1)) {
00564     *value = INT64_MAX / amt;
00565     *frac = 0;
00566   } else {
00567     int64 tmp = (int64)*value * amt + *frac;
00568     *frac   = GB(tmp, 0, 16);
00569     *value += tmp >> 16;
00570   }
00571 }
00572 
00573 static void AddInflation(bool check_year = true)
00574 {
00575   /* The cargo payment inflation differs from the normal inflation, so the
00576    * relative amount of money you make with a transport decreases slowly over
00577    * the 170 years. After a few hundred years we reach a level in which the
00578    * games will become unplayable as the maximum income will be less than
00579    * the minimum running cost.
00580    *
00581    * Furthermore there are a lot of inflation related overflows all over the
00582    * place. Solving them is hardly possible because inflation will always
00583    * reach the overflow threshold some day. So we'll just perform the
00584    * inflation mechanism during the first 170 years (the amount of years that
00585    * one had in the original TTD) and stop doing the inflation after that
00586    * because it only causes problems that can't be solved nicely and the
00587    * inflation doesn't add anything after that either; it even makes playing
00588    * it impossible due to the diverging cost and income rates.
00589    */
00590   if (check_year && (_cur_year - _settings_game.game_creation.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return;
00591 
00592   /* Approximation for (100 + infl_amount)% ** (1 / 12) - 100%
00593    * scaled by 65536
00594    * 12 -> months per year
00595    * This is only a good approxiamtion for small values
00596    */
00597   int32 inf = _economy.infl_amount * 54;
00598 
00599   for (uint i = 0; i != NUM_PRICES; i++) {
00600     AddSingleInflation((Money*)&_price + i, _price_frac + i, inf);
00601   }
00602 
00603   AddSingleInflation(&_economy.max_loan_unround, &_economy.max_loan_unround_fract, inf);
00604 
00605   if (_economy.max_loan + 50000 <= _economy.max_loan_unround) _economy.max_loan += 50000;
00606 
00607   inf = _economy.infl_amount_pr * 54;
00608   for (CargoID i = 0; i < NUM_CARGO; i++) {
00609     AddSingleInflation(
00610       (Money*)_cargo_payment_rates + i,
00611       _cargo_payment_rates_frac + i,
00612       inf
00613     );
00614   }
00615 
00616   InvalidateWindowClasses(WC_BUILD_VEHICLE);
00617   InvalidateWindowClasses(WC_REPLACE_VEHICLE);
00618   InvalidateWindowClasses(WC_VEHICLE_DETAILS);
00619   InvalidateWindow(WC_PAYMENT_RATES, 0);
00620 }
00621 
00622 static void CompaniesPayInterest()
00623 {
00624   const Company *c;
00625 
00626   FOR_ALL_COMPANIES(c) {
00627     _current_company = c->index;
00628 
00629     /* Over a year the paid interest should be "loan * interest percentage",
00630      * but... as that number is likely not dividable by 12 (pay each month),
00631      * one needs to account for that in the monthly fee calculations.
00632      * To easily calculate what one should pay "this" month, you calculate
00633      * what (total) should have been paid up to this month and you substract
00634      * whatever has been paid in the previous months. This will mean one month
00635      * it'll be a bit more and the other it'll be a bit less than the average
00636      * monthly fee, but on average it will be exact. */
00637     Money yearly_fee = c->current_loan * _economy.interest_rate / 100;
00638     Money up_to_previous_month = yearly_fee * _cur_month / 12;
00639     Money up_to_this_month = yearly_fee * (_cur_month + 1) / 12;
00640 
00641     SubtractMoneyFromCompany(CommandCost(EXPENSES_LOAN_INT, up_to_this_month - up_to_previous_month));
00642 
00643     SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, _price.station_value >> 2));
00644   }
00645 }
00646 
00647 static void HandleEconomyFluctuations()
00648 {
00649   if (_settings_game.difficulty.economy == 0) return;
00650 
00651   if (--_economy.fluct == 0) {
00652     _economy.fluct = -(int)GB(Random(), 0, 2);
00653     AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NS_ECONOMY, 0, 0);
00654   } else if (_economy.fluct == -12) {
00655     _economy.fluct = GB(Random(), 0, 8) + 312;
00656     AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NS_ECONOMY, 0, 0);
00657   }
00658 }
00659 
00660 static byte _price_category[NUM_PRICES] = {
00661   0, 2, 2, 2, 2, 2, 2, 2,
00662   2, 2, 2, 2, 2, 2, 2, 2,
00663   2, 2, 2, 2, 2, 2, 2, 2,
00664   2, 2, 2, 2, 2, 2, 2, 2,
00665   2, 2, 2, 2, 2, 2, 2, 2,
00666   2, 2, 1, 1, 1, 1, 1, 1,
00667   2,
00668 };
00669 
00670 static const Money _price_base[NUM_PRICES] = {
00671       100, 
00672       100, 
00673        95, 
00674        65, 
00675       275, 
00676       600, 
00677       500, 
00678       700, 
00679       450, 
00680       200, 
00681       180, 
00682       600, 
00683       200, 
00684       200, 
00685       350, 
00686    400000, 
00687      2000, 
00688    700000, 
00689     14000, 
00690     65000, 
00691        20, 
00692       250, 
00693        20, 
00694        40, 
00695       200, 
00696       500, 
00697        20, 
00698       -70, 
00699        10, 
00700        50, 
00701        80, 
00702        80, 
00703        90, 
00704        30, 
00705     10000, 
00706        50, 
00707        30, 
00708        50, 
00709        50, 
00710        55, 
00711      1600, 
00712        40, 
00713      5600, 
00714      5200, 
00715      4800, 
00716      9600, 
00717      1600, 
00718      5600, 
00719   1000000, 
00720 };
00721 
00722 static byte price_base_multiplier[NUM_PRICES];
00723 
00727 void ResetPriceBaseMultipliers()
00728 {
00729   uint i;
00730 
00731   /* 8 means no multiplier. */
00732   for (i = 0; i < NUM_PRICES; i++)
00733     price_base_multiplier[i] = 8;
00734 }
00735 
00743 void SetPriceBaseMultiplier(uint price, byte factor)
00744 {
00745   assert(price < NUM_PRICES);
00746   price_base_multiplier[price] = factor;
00747 }
00748 
00753 void StartupIndustryDailyChanges(bool init_counter)
00754 {
00755   uint map_size = MapLogX() + MapLogY();
00756   /* After getting map size, it needs to be scaled appropriately and divided by 31,
00757    * which stands for the days in a month.
00758    * Using just 31 will make it so that a monthly reset (based on the real number of days of that month)
00759    * would not be needed.
00760    * Since it is based on "fractionnal parts", the leftover days will not make much of a difference
00761    * on the overall total number of changes performed */
00762   _economy.industry_daily_increment = (1 << map_size) / 31;
00763 
00764   if (init_counter) {
00765     /* A new game or a savegame from an older version will require the counter to be initialized */
00766     _economy.industry_daily_change_counter = 0;
00767   }
00768 }
00769 
00770 void StartupEconomy()
00771 {
00772   int i;
00773 
00774   assert(sizeof(_price) == NUM_PRICES * sizeof(Money));
00775 
00776   for (i = 0; i != NUM_PRICES; i++) {
00777     Money price = _price_base[i];
00778     if (_price_category[i] != 0) {
00779       uint mod = _price_category[i] == 1 ? _settings_game.difficulty.vehicle_costs : _settings_game.difficulty.construction_cost;
00780       if (mod < 1) {
00781         price = price * 3 >> 2;
00782       } else if (mod > 1) {
00783         price = price * 9 >> 3;
00784       }
00785     }
00786     if (price_base_multiplier[i] > 8) {
00787       price <<= price_base_multiplier[i] - 8;
00788     } else {
00789       price >>= 8 - price_base_multiplier[i];
00790     }
00791     ((Money*)&_price)[i] = price;
00792     _price_frac[i] = 0;
00793   }
00794 
00795   _economy.interest_rate = _settings_game.difficulty.initial_interest;
00796   _economy.infl_amount = _settings_game.difficulty.initial_interest;
00797   _economy.infl_amount_pr = max(0, _settings_game.difficulty.initial_interest - 1);
00798   _economy.max_loan_unround = _economy.max_loan = _settings_game.difficulty.max_loan;
00799   _economy.fluct = GB(Random(), 0, 8) + 168;
00800 
00801   StartupIndustryDailyChanges(true); // As we are starting a new game, initialize the counter too
00802 
00803 }
00804 
00805 void ResetEconomy()
00806 {
00807   /* Test if resetting the economy is needed. */
00808   bool needed = false;
00809 
00810   for (CargoID c = 0; c < NUM_CARGO; c++) {
00811     const CargoSpec *cs = GetCargo(c);
00812     if (!cs->IsValid()) continue;
00813     if (_cargo_payment_rates[c] == 0) {
00814       needed = true;
00815       break;
00816     }
00817   }
00818 
00819   if (!needed) return;
00820 
00821   /* Remember old unrounded maximum loan value. NewGRF has the ability
00822    * to change all the other inflation affected base costs. */
00823   Money old_value = _economy.max_loan_unround;
00824 
00825   /* Reset the economy */
00826   StartupEconomy();
00827   InitializeLandscapeVariables(false);
00828 
00829   /* Reapply inflation, ignoring the year */
00830   while (old_value > _economy.max_loan_unround) {
00831     AddInflation(false);
00832   }
00833 }
00834 
00835 Money GetPriceByIndex(uint8 index)
00836 {
00837   if (index > NUM_PRICES) return 0;
00838 
00839   return ((Money*)&_price)[index];
00840 }
00841 
00842 
00843 Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
00844 {
00845   TileIndex tile;
00846   TileIndex tile2;
00847   Pair tp;
00848 
00849   /* if mode is false, use the singular form */
00850   const CargoSpec *cs = GetCargo(s->cargo_type);
00851   SetDParam(0, mode ? cs->name : cs->name_single);
00852 
00853   if (s->age < 12) {
00854     if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
00855       SetDParam(1, STR_INDUSTRY);
00856       SetDParam(2, s->from);
00857       tile = GetIndustry(s->from)->xy;
00858 
00859       if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
00860         SetDParam(4, STR_INDUSTRY);
00861         SetDParam(5, s->to);
00862         tile2 = GetIndustry(s->to)->xy;
00863       } else {
00864         SetDParam(4, STR_TOWN);
00865         SetDParam(5, s->to);
00866         tile2 = GetTown(s->to)->xy;
00867       }
00868     } else {
00869       SetDParam(1, STR_TOWN);
00870       SetDParam(2, s->from);
00871       tile = GetTown(s->from)->xy;
00872 
00873       SetDParam(4, STR_TOWN);
00874       SetDParam(5, s->to);
00875       tile2 = GetTown(s->to)->xy;
00876     }
00877   } else {
00878     SetDParam(1, s->from);
00879     tile = GetStation(s->from)->xy;
00880 
00881     SetDParam(2, s->to);
00882     tile2 = GetStation(s->to)->xy;
00883   }
00884 
00885   tp.a = tile;
00886   tp.b = tile2;
00887 
00888   return tp;
00889 }
00890 
00891 void DeleteSubsidyWithTown(TownID index)
00892 {
00893   Subsidy *s;
00894 
00895   for (s = _subsidies; s != endof(_subsidies); s++) {
00896     if (s->cargo_type != CT_INVALID && s->age < 12) {
00897       const CargoSpec *cs = GetCargo(s->cargo_type);
00898       if (((cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) && (index == s->from || index == s->to)) ||
00899         ((cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) && index == s->to)) {
00900         s->cargo_type = CT_INVALID;
00901       }
00902     }
00903   }
00904 }
00905 
00906 void DeleteSubsidyWithIndustry(IndustryID index)
00907 {
00908   Subsidy *s;
00909 
00910   for (s = _subsidies; s != endof(_subsidies); s++) {
00911     if (s->cargo_type != CT_INVALID && s->age < 12) {
00912       const CargoSpec *cs = GetCargo(s->cargo_type);
00913       if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL &&
00914         (index == s->from || (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD && index == s->to))) {
00915         s->cargo_type = CT_INVALID;
00916       }
00917     }
00918   }
00919 }
00920 
00921 void DeleteSubsidyWithStation(StationID index)
00922 {
00923   Subsidy *s;
00924   bool dirty = false;
00925 
00926   for (s = _subsidies; s != endof(_subsidies); s++) {
00927     if (s->cargo_type != CT_INVALID && s->age >= 12 &&
00928         (s->from == index || s->to == index)) {
00929       s->cargo_type = CT_INVALID;
00930       dirty = true;
00931     }
00932   }
00933 
00934   if (dirty)
00935     InvalidateWindow(WC_SUBSIDIES_LIST, 0);
00936 }
00937 
00938 struct FoundRoute {
00939   uint distance;
00940   CargoID cargo;
00941   void *from;
00942   void *to;
00943 };
00944 
00945 static void FindSubsidyPassengerRoute(FoundRoute *fr)
00946 {
00947   Town *from,*to;
00948 
00949   fr->distance = UINT_MAX;
00950 
00951   fr->from = from = GetRandomTown();
00952   if (from == NULL || from->population < 400) return;
00953 
00954   fr->to = to = GetRandomTown();
00955   if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
00956     return;
00957 
00958   fr->distance = DistanceManhattan(from->xy, to->xy);
00959 }
00960 
00961 static void FindSubsidyCargoRoute(FoundRoute *fr)
00962 {
00963   Industry *i;
00964   int trans, total;
00965   CargoID cargo;
00966 
00967   fr->distance = UINT_MAX;
00968 
00969   fr->from = i = GetRandomIndustry();
00970   if (i == NULL) return;
00971 
00972   /* Randomize cargo type */
00973   if (HasBit(Random(), 0) && i->produced_cargo[1] != CT_INVALID) {
00974     cargo = i->produced_cargo[1];
00975     trans = i->last_month_pct_transported[1];
00976     total = i->last_month_production[1];
00977   } else {
00978     cargo = i->produced_cargo[0];
00979     trans = i->last_month_pct_transported[0];
00980     total = i->last_month_production[0];
00981   }
00982 
00983   /* Quit if no production in this industry
00984    * or if the cargo type is passengers
00985    * or if the pct transported is already large enough */
00986   if (total == 0 || trans > 42 || cargo == CT_INVALID) return;
00987 
00988   const CargoSpec *cs = GetCargo(cargo);
00989   if (cs->town_effect == TE_PASSENGERS) return;
00990 
00991   fr->cargo = cargo;
00992 
00993   if (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) {
00994     /*  The destination is a town */
00995     Town *t = GetRandomTown();
00996 
00997     /* Only want big towns */
00998     if (t == NULL || t->population < 900) return;
00999 
01000     fr->distance = DistanceManhattan(i->xy, t->xy);
01001     fr->to = t;
01002   } else {
01003     /* The destination is an industry */
01004     Industry *i2 = GetRandomIndustry();
01005 
01006     /* The industry must accept the cargo */
01007     if (i2 == NULL || i == i2 ||
01008         (cargo != i2->accepts_cargo[0] &&
01009         cargo != i2->accepts_cargo[1] &&
01010         cargo != i2->accepts_cargo[2])) {
01011       return;
01012     }
01013     fr->distance = DistanceManhattan(i->xy, i2->xy);
01014     fr->to = i2;
01015   }
01016 }
01017 
01018 static bool CheckSubsidyDuplicate(Subsidy *s)
01019 {
01020   const Subsidy *ss;
01021 
01022   for (ss = _subsidies; ss != endof(_subsidies); ss++) {
01023     if (s != ss &&
01024         ss->from == s->from &&
01025         ss->to == s->to &&
01026         ss->cargo_type == s->cargo_type) {
01027       s->cargo_type = CT_INVALID;
01028       return true;
01029     }
01030   }
01031   return false;
01032 }
01033 
01034 
01035 static void SubsidyMonthlyHandler()
01036 {
01037   Subsidy *s;
01038   Pair pair;
01039   Station *st;
01040   uint n;
01041   FoundRoute fr;
01042   bool modified = false;
01043 
01044   for (s = _subsidies; s != endof(_subsidies); s++) {
01045     if (s->cargo_type == CT_INVALID) continue;
01046 
01047     if (s->age == 12-1) {
01048       pair = SetupSubsidyDecodeParam(s, 1);
01049       AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
01050       s->cargo_type = CT_INVALID;
01051       modified = true;
01052       AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s - _subsidies));
01053     } else if (s->age == 2*12-1) {
01054       st = GetStation(s->to);
01055       if (st->owner == _local_company) {
01056         pair = SetupSubsidyDecodeParam(s, 1);
01057         AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
01058       }
01059       s->cargo_type = CT_INVALID;
01060       modified = true;
01061       AI::BroadcastNewEvent(new AIEventSubsidyExpired(s - _subsidies));
01062     } else {
01063       s->age++;
01064     }
01065   }
01066 
01067   /* 25% chance to go on */
01068   if (Chance16(1,4)) {
01069     /*  Find a free slot*/
01070     s = _subsidies;
01071     while (s->cargo_type != CT_INVALID) {
01072       if (++s == endof(_subsidies))
01073         goto no_add;
01074     }
01075 
01076     n = 1000;
01077     do {
01078       FindSubsidyPassengerRoute(&fr);
01079       if (fr.distance <= 70) {
01080         s->cargo_type = CT_PASSENGERS;
01081         s->from = ((Town*)fr.from)->index;
01082         s->to = ((Town*)fr.to)->index;
01083         goto add_subsidy;
01084       }
01085       FindSubsidyCargoRoute(&fr);
01086       if (fr.distance <= 70) {
01087         s->cargo_type = fr.cargo;
01088         s->from = ((Industry*)fr.from)->index;
01089         {
01090           const CargoSpec *cs = GetCargo(fr.cargo);
01091           s->to = (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
01092         }
01093   add_subsidy:
01094         if (!CheckSubsidyDuplicate(s)) {
01095           s->age = 0;
01096           pair = SetupSubsidyDecodeParam(s, 0);
01097           AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
01098           AI::BroadcastNewEvent(new AIEventSubsidyOffer(s - _subsidies));
01099           modified = true;
01100           break;
01101         }
01102       }
01103     } while (n--);
01104   }
01105 no_add:;
01106   if (modified)
01107     InvalidateWindow(WC_SUBSIDIES_LIST, 0);
01108 }
01109 
01110 Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
01111 {
01112   const CargoSpec *cs = GetCargo(cargo_type);
01113 
01114   /* Use callback to calculate cargo profit, if available */
01115   if (HasBit(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) {
01116     uint32 var18 = min(dist, 0xFFFF) | (min(num_pieces, 0xFF) << 16) | (transit_days << 24);
01117     uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs);
01118     if (callback != CALLBACK_FAILED) {
01119       int result = GB(callback, 0, 14);
01120 
01121       /* Simulate a 15 bit signed value */
01122       if (HasBit(callback, 14)) result = 0x4000 - result;
01123 
01124       /* "The result should be a signed multiplier that gets multiplied
01125        * by the amount of cargo moved and the price factor, then gets
01126        * divided by 8192." */
01127       return result * num_pieces * _cargo_payment_rates[cargo_type] / 8192;
01128     }
01129   }
01130 
01131   /* zero the distance (thus income) if it's the bank and very short transport. */
01132   if (_settings_game.game_creation.landscape == LT_TEMPERATE && cs->label == 'VALU' && dist < 10) return 0;
01133 
01134 
01135   static const int MIN_TIME_FACTOR = 31;
01136   static const int MAX_TIME_FACTOR = 255;
01137 
01138   const int days1 = cs->transit_days[0];
01139   const int days2 = cs->transit_days[1];
01140   const int days_over_days1 = max(   transit_days - days1, 0);
01141   const int days_over_days2 = max(days_over_days1 - days2, 0);
01142 
01143   /*
01144    * The time factor is calculated based on the time it took
01145    * (transit_days) compared two cargo-depending values. The
01146    * range is divided into three parts:
01147    *
01148    *  - constant for fast transits
01149    *  - linear decreasing with time with a slope of -1 for medium transports
01150    *  - linear decreasing with time with a slope of -2 for slow transports
01151    *
01152    */
01153   const int time_factor = max(MAX_TIME_FACTOR - days_over_days1 - days_over_days2, MIN_TIME_FACTOR);
01154 
01155   return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
01156 }
01157 
01158 
01159 struct FindIndustryToDeliverData {
01160   const Rect *rect;            
01161   CargoID cargo_type;          
01162 
01163   Industry *ind;               
01164   const IndustrySpec *indspec; 
01165   uint cargo_index;            
01166 };
01167 
01168 static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
01169 {
01170   FindIndustryToDeliverData *callback_data = (FindIndustryToDeliverData *)user_data;
01171   const Rect *rect = callback_data->rect;
01172   CargoID cargo_type = callback_data->cargo_type;
01173 
01174   /* Only process industry tiles */
01175   if (!IsTileType(ind_tile, MP_INDUSTRY)) return false;
01176 
01177   /* Only process tiles in the station acceptance rectangle */
01178   int x = TileX(ind_tile);
01179   int y = TileY(ind_tile);
01180   if (x < rect->left || x > rect->right || y < rect->top || y > rect->bottom) return false;
01181 
01182   Industry *ind = GetIndustryByTile(ind_tile);
01183   const IndustrySpec *indspec = GetIndustrySpec(ind->type);
01184 
01185   uint cargo_index;
01186   for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
01187     if (cargo_type == ind->accepts_cargo[cargo_index]) break;
01188   }
01189   /* Check if matching cargo has been found */
01190   if (cargo_index >= lengthof(ind->accepts_cargo)) return false;
01191 
01192   /* Check if industry temporarly refuses acceptance */
01193   if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
01194     uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
01195     if (res == 0) return false;
01196   }
01197 
01198   /* Found industry accepting the cargo */
01199   callback_data->ind = ind;
01200   callback_data->indspec = indspec;
01201   callback_data->cargo_index = cargo_index;
01202   return true;
01203 }
01204 
01213 static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int num_pieces, SmallIndustryList *industry_set)
01214 {
01215   if (st->rect.IsEmpty()) return;
01216 
01217   /* Compute acceptance rectangle */
01218   int catchment_radius = st->GetCatchmentRadius();
01219   Rect rect = {
01220     max<int>(st->rect.left   - catchment_radius, 0),
01221     max<int>(st->rect.top    - catchment_radius, 0),
01222     min<int>(st->rect.right  + catchment_radius, MapMaxX()),
01223     min<int>(st->rect.bottom + catchment_radius, MapMaxY())
01224   };
01225 
01226   /* Compute maximum extent of acceptance rectangle wrt. station sign */
01227   TileIndex start_tile = st->xy;
01228   uint max_radius = max(
01229     max(DistanceManhattan(start_tile, TileXY(rect.left , rect.top)), DistanceManhattan(start_tile, TileXY(rect.left , rect.bottom))),
01230     max(DistanceManhattan(start_tile, TileXY(rect.right, rect.top)), DistanceManhattan(start_tile, TileXY(rect.right, rect.bottom)))
01231   );
01232 
01233   FindIndustryToDeliverData callback_data;
01234   callback_data.rect = &rect;
01235   callback_data.cargo_type = cargo_type;
01236   callback_data.ind = NULL;
01237   callback_data.indspec = NULL;
01238   callback_data.cargo_index = 0;
01239 
01240   /* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo.
01241    * This fails in three cases:
01242    *  1) The station accepts the cargo because there are enough houses around it accepting the cargo.
01243    *  2) The industries in the catchment area temporarily reject the cargo, and the daily station loop has not yet updated station acceptance.
01244    *  3) The results of callbacks CBID_INDUSTRY_REFUSE_CARGO and CBID_INDTILE_CARGO_ACCEPTANCE are inconsistent. (documented behaviour)
01245    */
01246   if (CircularTileSearch(&start_tile, 2 * max_radius + 1, FindIndustryToDeliver, &callback_data)) {
01247     Industry *best = callback_data.ind;
01248     uint accepted_cargo_index = callback_data.cargo_index;
01249     assert(best != NULL);
01250 
01251     /* Insert the industry into industry_set, if not yet contained */
01252     if (industry_set != NULL) industry_set->Include(best);
01253 
01254     best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
01255   }
01256 }
01257 
01258 static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
01259 {
01260   Subsidy *s;
01261   TileIndex xy;
01262   Pair pair;
01263 
01264   /* check if there is an already existing subsidy that applies to us */
01265   for (s = _subsidies; s != endof(_subsidies); s++) {
01266     if (s->cargo_type == cargo_type &&
01267         s->age >= 12 &&
01268         s->from == from->index &&
01269         s->to == to->index) {
01270       return true;
01271     }
01272   }
01273 
01274   /* check if there's a new subsidy that applies.. */
01275   for (s = _subsidies; s != endof(_subsidies); s++) {
01276     if (s->cargo_type == cargo_type && s->age < 12) {
01277       /* Check distance from source */
01278       const CargoSpec *cs = GetCargo(cargo_type);
01279       if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
01280         xy = GetTown(s->from)->xy;
01281       } else {
01282         xy = GetIndustry(s->from)->xy;
01283       }
01284       if (DistanceMax(xy, from->xy) > 9) continue;
01285 
01286       /* Check distance from dest */
01287       switch (cs->town_effect) {
01288         case TE_PASSENGERS:
01289         case TE_MAIL:
01290         case TE_GOODS:
01291         case TE_FOOD:
01292           xy = GetTown(s->to)->xy;
01293           break;
01294 
01295         default:
01296           xy = GetIndustry(s->to)->xy;
01297           break;
01298       }
01299       if (DistanceMax(xy, to->xy) > 9) continue;
01300 
01301       /* Found a subsidy, change the values to indicate that it's in use */
01302       s->age = 12;
01303       s->from = from->index;
01304       s->to = to->index;
01305 
01306       /* Add a news item */
01307       pair = SetupSubsidyDecodeParam(s, 0);
01308       InjectDParam(1);
01309 
01310       SetDParam(0, _current_company);
01311       AddNewsItem(
01312         STR_2031_SERVICE_SUBSIDY_AWARDED + _settings_game.difficulty.subsidy_multiplier,
01313         NS_SUBSIDIES,
01314         pair.a, pair.b
01315       );
01316       AI::BroadcastNewEvent(new AIEventSubsidyAwarded(s - _subsidies));
01317 
01318       InvalidateWindow(WC_SUBSIDIES_LIST, 0);
01319       return true;
01320     }
01321   }
01322   return false;
01323 }
01324 
01335 static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit, SmallIndustryList *industry_set)
01336 {
01337   bool subsidised;
01338   Station *s_from, *s_to;
01339   Money profit;
01340 
01341   assert(num_pieces > 0);
01342 
01343   /* Update company statistics */
01344   {
01345     Company *c = GetCompany(_current_company);
01346     c->cur_economy.delivered_cargo += num_pieces;
01347     SetBit(c->cargo_types, cargo_type);
01348   }
01349 
01350   /* Get station pointers. */
01351   s_from = GetStation(source);
01352   s_to = GetStation(dest);
01353 
01354   /* Check if a subsidy applies. */
01355   subsidised = CheckSubsidised(s_from, s_to, cargo_type);
01356 
01357   /* Increase town's counter for some special goods types */
01358   const CargoSpec *cs = GetCargo(cargo_type);
01359   if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
01360   if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
01361 
01362   /* Give the goods to the industry. */
01363   DeliverGoodsToIndustry(s_to, cargo_type, num_pieces, industry_set);
01364 
01365   /* Determine profit */
01366   profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
01367 
01368   /* Modify profit if a subsidy is in effect */
01369   if (subsidised) {
01370     switch (_settings_game.difficulty.subsidy_multiplier) {
01371       case 0:  profit += profit >> 1; break;
01372       case 1:  profit *= 2; break;
01373       case 2:  profit *= 3; break;
01374       default: profit *= 4; break;
01375     }
01376   }
01377 
01378   return profit;
01379 }
01380 
01386 static void TriggerIndustryProduction(Industry *i)
01387 {
01388   const IndustrySpec *indspec = GetIndustrySpec(i->type);
01389   uint16 callback = indspec->callback_flags;
01390 
01391   i->was_cargo_delivered = true;
01392   i->last_cargo_accepted_at = _date;
01393 
01394   if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
01395     if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
01396       IndustryProductionCallback(i, 0);
01397     } else {
01398       InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
01399     }
01400   } else {
01401     for (uint cargo_index = 0; cargo_index < lengthof(i->incoming_cargo_waiting); cargo_index++) {
01402       uint cargo_waiting = i->incoming_cargo_waiting[cargo_index];
01403       if (cargo_waiting == 0) continue;
01404 
01405       i->produced_cargo_waiting[0] = min(i->produced_cargo_waiting[0] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][0] / 256), 0xFFFF);
01406       i->produced_cargo_waiting[1] = min(i->produced_cargo_waiting[1] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][1] / 256), 0xFFFF);
01407 
01408       i->incoming_cargo_waiting[cargo_index] = 0;
01409     }
01410   }
01411 
01412   TriggerIndustry(i, INDUSTRY_TRIGGER_RECEIVED_CARGO);
01413   StartStopIndustryTileAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO);
01414 }
01415 
01420 void VehiclePayment(Vehicle *front_v)
01421 {
01422   int result = 0;
01423 
01424   Money vehicle_profit = 0; // Money paid to the train
01425   Money route_profit   = 0; // The grand total amount for the route. A-D of transfer chain A-B-C-D
01426   Money virtual_profit = 0; // The virtual profit for entire vehicle chain
01427 
01428   StationID last_visited = front_v->last_station_visited;
01429   Station *st = GetStation(last_visited);
01430 
01431   /* The owner of the train wants to be paid */
01432   CompanyID old_company = _current_company;
01433   _current_company = front_v->owner;
01434 
01435   /* At this moment loading cannot be finished */
01436   ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED);
01437 
01438   /* Start unloading in at the first possible moment */
01439   front_v->load_unload_time_rem = 1;
01440 
01441   /* Collect delivered industries */
01442   static SmallIndustryList industry_set;
01443   industry_set.Clear();
01444 
01445   for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
01446     /* No cargo to unload */
01447     if (v->cargo_cap == 0 || v->cargo.Empty() || front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) continue;
01448 
01449     /* All cargo has already been paid for, no need to pay again */
01450     if (!v->cargo.UnpaidCargo()) {
01451       SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
01452       continue;
01453     }
01454 
01455     GoodsEntry *ge = &st->goods[v->cargo_type];
01456     const CargoList::List *cargos = v->cargo.Packets();
01457 
01458     for (CargoList::List::const_iterator it = cargos->begin(); it != cargos->end(); it++) {
01459       CargoPacket *cp = *it;
01460       if (!cp->paid_for &&
01461           cp->source != last_visited &&
01462           HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) &&
01463           (front_v->current_order.GetUnloadType() & OUFB_TRANSFER) == 0) {
01464         /* Deliver goods to the station */
01465         st->time_since_unload = 0;
01466 
01467         /* handle end of route payment */
01468         Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit, &industry_set);
01469         cp->paid_for = true;
01470         route_profit   += profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
01471         vehicle_profit += profit - cp->feeder_share;                    // whole vehicle is not payed for transfers picked up earlier
01472 
01473         result |= 1;
01474 
01475         SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
01476       } else if (front_v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) {
01477         if (!cp->paid_for && (front_v->current_order.GetUnloadType() & OUFB_TRANSFER) != 0) {
01478           Money profit = GetTransportedGoodsIncome(
01479             cp->count,
01480             /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
01481             DistanceManhattan(cp->loaded_at_xy, GetStation(last_visited)->xy),
01482             cp->days_in_transit,
01483             v->cargo_type);
01484 
01485           front_v->profit_this_year += profit << 8;
01486           virtual_profit   += profit; // accumulate transfer profits for whole vehicle
01487           cp->feeder_share += profit; // account for the (virtual) profit already made for the cargo packet
01488           cp->paid_for      = true;   // record that the cargo has been paid for to eliminate double counting
01489         }
01490         result |= 2;
01491 
01492         SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
01493       }
01494     }
01495     v->cargo.InvalidateCache();
01496   }
01497 
01498   /* Call the production machinery of industries only once for every vehicle chain */
01499   const Industry *const *isend = industry_set.End();
01500   for (Industry **iid = industry_set.Begin(); iid != isend; iid++) {
01501     TriggerIndustryProduction(*iid);
01502   }
01503 
01504   if (virtual_profit > 0) {
01505     ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
01506   }
01507 
01508   if (route_profit != 0) {
01509     front_v->profit_this_year += vehicle_profit << 8;
01510     SubtractMoneyFromCompany(CommandCost(front_v->GetExpenseType(true), -route_profit));
01511 
01512     if (IsLocalCompany() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
01513       SndPlayVehicleFx(SND_14_CASHTILL, front_v);
01514     }
01515 
01516     ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -vehicle_profit);
01517   }
01518 
01519   _current_company = old_company;
01520 }
01521 
01530 static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
01531 {
01532   assert(v->current_order.IsType(OT_LOADING));
01533 
01534   /* We have not waited enough time till the next round of loading/unloading */
01535   if (--v->load_unload_time_rem != 0) {
01536     if (_settings_game.order.improved_load && (v->current_order.GetLoadType() & OLFB_FULL_LOAD)) {
01537       /* 'Reserve' this cargo for this vehicle, because we were first. */
01538       for (; v != NULL; v = v->Next()) {
01539         if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
01540       }
01541     }
01542     return;
01543   }
01544 
01545   StationID last_visited = v->last_station_visited;
01546   Station *st = GetStation(last_visited);
01547 
01548   if (v->type == VEH_TRAIN && (!IsTileType(v->tile, MP_STATION) || GetStationIndex(v->tile) != st->index)) {
01549     /* The train reversed in the station. Take the "easy" way
01550      * out and let the train just leave as it always did. */
01551     SetBit(v->vehicle_flags, VF_LOADING_FINISHED);
01552     return;
01553   }
01554 
01555   int unloading_time = 0;
01556   Vehicle *u = v;
01557   int result = 0;
01558   uint cap;
01559 
01560   bool completely_emptied = true;
01561   bool anything_unloaded = false;
01562   bool anything_loaded   = false;
01563   uint32 cargo_not_full  = 0;
01564   uint32 cargo_full      = 0;
01565 
01566   v->cur_speed = 0;
01567 
01568   for (; v != NULL; v = v->Next()) {
01569     if (v->cargo_cap == 0) continue;
01570 
01571     byte load_amount = EngInfo(v->engine_type)->load_amount;
01572 
01573     /* The default loadamount for mail is 1/4 of the load amount for passengers */
01574     if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) load_amount = (load_amount + 3) / 4;
01575 
01576     if (_settings_game.order.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) {
01577       uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
01578       if (cb_load_amount != CALLBACK_FAILED && GB(cb_load_amount, 0, 8) != 0) load_amount = GB(cb_load_amount, 0, 8);
01579     }
01580 
01581     GoodsEntry *ge = &st->goods[v->cargo_type];
01582 
01583     if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) && (u->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
01584       uint cargo_count = v->cargo.Count();
01585       uint amount_unloaded = _settings_game.order.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
01586       bool remaining; // Are there cargo entities in this vehicle that can still be unloaded here?
01587 
01588       if (HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) && !(u->current_order.GetUnloadType() & OUFB_TRANSFER)) {
01589         /* The cargo has reached it's final destination, the packets may now be destroyed */
01590         remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, last_visited);
01591 
01592         result |= 1;
01593       } else if (u->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) {
01594         remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
01595         SetBit(ge->acceptance_pickup, GoodsEntry::PICKUP);
01596 
01597         result |= 2;
01598       } else {
01599         /* The order changed while unloading (unset unload/transfer) or the
01600          * station does not accept goods anymore. */
01601         ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
01602         continue;
01603       }
01604 
01605       /* Deliver goods to the station */
01606       st->time_since_unload = 0;
01607 
01608       unloading_time += amount_unloaded;
01609 
01610       anything_unloaded = true;
01611       if (_settings_game.order.gradual_loading && remaining) {
01612         completely_emptied = false;
01613       } else {
01614         /* We have finished unloading (cargo count == 0) */
01615         ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
01616       }
01617 
01618       continue;
01619     }
01620 
01621     /* Do not pick up goods when we have no-load set. */
01622     if (u->current_order.GetLoadType() & OLFB_NO_LOAD) continue;
01623 
01624     /* update stats */
01625     int t;
01626     switch (u->type) {
01627       case VEH_TRAIN: t = u->u.rail.cached_max_speed; break;
01628       case VEH_ROAD:  t = u->max_speed / 2;           break;
01629       default:        t = u->max_speed;               break;
01630     }
01631 
01632     /* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
01633     ge->last_speed = min(t, 255);
01634     ge->last_age = _cur_year - u->build_year;
01635     ge->days_since_pickup = 0;
01636 
01637     /* If there's goods waiting at the station, and the vehicle
01638      * has capacity for it, load it on the vehicle. */
01639     if (!ge->cargo.Empty() &&
01640         (cap = v->cargo_cap - v->cargo.Count()) != 0) {
01641       uint count = ge->cargo.Count();
01642 
01643       /* Skip loading this vehicle if another train/vehicle is already handling
01644        * the same cargo type at this station */
01645       if (_settings_game.order.improved_load && cargo_left[v->cargo_type] <= 0) {
01646         SetBit(cargo_not_full, v->cargo_type);
01647         continue;
01648       }
01649 
01650       if (cap > count) cap = count;
01651       if (_settings_game.order.gradual_loading) cap = min(cap, load_amount);
01652       if (_settings_game.order.improved_load) {
01653         /* Don't load stuff that is already 'reserved' for other vehicles */
01654         cap = min((uint)cargo_left[v->cargo_type], cap);
01655         cargo_left[v->cargo_type] -= cap;
01656       }
01657 
01658       if (v->cargo.Empty()) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
01659 
01660       /* TODO: Regarding this, when we do gradual loading, we
01661        * should first unload all vehicles and then start
01662        * loading them. Since this will cause
01663        * VEHICLE_TRIGGER_EMPTY to be called at the time when
01664        * the whole vehicle chain is really totally empty, the
01665        * completely_emptied assignment can then be safely
01666        * removed; that's how TTDPatch behaves too. --pasky */
01667       completely_emptied = false;
01668       anything_loaded = true;
01669 
01670       ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
01671 
01672       st->time_since_load = 0;
01673       st->last_vehicle_type = v->type;
01674 
01675       StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type);
01676 
01677       unloading_time += cap;
01678 
01679       result |= 2;
01680     }
01681 
01682     if (v->cargo.Count() == v->cargo_cap) {
01683       SetBit(cargo_full, v->cargo_type);
01684     } else {
01685       SetBit(cargo_not_full, v->cargo_type);
01686     }
01687   }
01688 
01689   /* Only set completly_emptied, if we just unloaded all remaining cargo */
01690   completely_emptied &= anything_unloaded;
01691 
01692   /* We update these variables here, so gradual loading still fills
01693    * all wagons at the same time instead of using the same 'improved'
01694    * loading algorithm for the wagons (only fill wagon when there is
01695    * enough to fill the previous wagons) */
01696   if (_settings_game.order.improved_load && (u->current_order.GetLoadType() & OLFB_FULL_LOAD)) {
01697     /* Update left cargo */
01698     for (v = u; v != NULL; v = v->Next()) {
01699       if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
01700     }
01701   }
01702 
01703   v = u;
01704 
01705   if (anything_loaded || anything_unloaded) {
01706     if (_settings_game.order.gradual_loading) {
01707       /* The time it takes to load one 'slice' of cargo or passengers depends
01708       * on the vehicle type - the values here are those found in TTDPatch */
01709       const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
01710 
01711       unloading_time = gradual_loading_wait_time[v->type];
01712     }
01713   } else {
01714     bool finished_loading = true;
01715     if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) {
01716       if (v->current_order.GetLoadType() == OLF_FULL_LOAD_ANY) {
01717         /* if the aircraft carries passengers and is NOT full, then
01718          * continue loading, no matter how much mail is in */
01719         if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo.Count()) ||
01720             (cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
01721           finished_loading = false;
01722         }
01723       } else if (cargo_not_full != 0) {
01724         finished_loading = false;
01725       }
01726     }
01727     unloading_time = 20;
01728 
01729     SB(v->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
01730   }
01731 
01732   if (v->type == VEH_TRAIN) {
01733     /* Each platform tile is worth 2 rail vehicles. */
01734     int overhang = v->u.rail.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
01735     if (overhang > 0) {
01736       unloading_time <<= 1;
01737       unloading_time += (overhang * unloading_time) / 8;
01738     }
01739   }
01740 
01741   /* Calculate the loading indicator fill percent and display
01742    * In the Game Menu do not display indicators
01743    * If _settings_client.gui.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 )
01744    * if _settings_client.gui.loading_indicators == 1, _local_company must be the owner or must be a spectator to show ind., so 1 > 0
01745    * if _settings_client.gui.loading_indicators == 0, do not display indicators ... 0 is never greater than anything
01746    */
01747   if (_game_mode != GM_MENU && (_settings_client.gui.loading_indicators > (uint)(v->owner != _local_company && _local_company != COMPANY_SPECTATOR))) {
01748     StringID percent_up_down = STR_NULL;
01749     int percent = CalcPercentVehicleFilled(v, &percent_up_down);
01750     if (v->fill_percent_te_id == INVALID_TE_ID) {
01751       v->fill_percent_te_id = ShowFillingPercent(v->x_pos, v->y_pos, v->z_pos + 20, percent, percent_up_down);
01752     } else {
01753       UpdateFillingPercent(v->fill_percent_te_id, percent, percent_up_down);
01754     }
01755   }
01756 
01757   v->load_unload_time_rem = unloading_time;
01758 
01759   if (completely_emptied) {
01760     TriggerVehicle(v, VEHICLE_TRIGGER_EMPTY);
01761   }
01762 
01763   if (result != 0) {
01764     InvalidateWindow(GetWindowClassForVehicleType(v->type), v->owner);
01765     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
01766 
01767     st->MarkTilesDirty(true);
01768     v->MarkDirty();
01769 
01770     if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited);
01771   }
01772 }
01773 
01779 void LoadUnloadStation(Station *st)
01780 {
01781   int cargo_left[NUM_CARGO];
01782 
01783   for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = st->goods[i].cargo.Count();
01784 
01785   std::list<Vehicle *>::iterator iter;
01786   for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
01787     Vehicle *v = *iter;
01788     if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) LoadUnloadVehicle(v, cargo_left);
01789   }
01790 }
01791 
01792 void CompaniesMonthlyLoop()
01793 {
01794   CompaniesGenStatistics();
01795   if (_settings_game.economy.inflation) AddInflation();
01796   CompaniesPayInterest();
01797   /* Reset the _current_company flag */
01798   _current_company = OWNER_NONE;
01799   HandleEconomyFluctuations();
01800   SubsidyMonthlyHandler();
01801 }
01802 
01803 static void DoAcquireCompany(Company *c)
01804 {
01805   Company *owner;
01806   int i;
01807   Money value;
01808   CompanyID ci = c->index;
01809 
01810   CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
01811   cni->FillData(c, GetCompany(_current_company));
01812 
01813   SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
01814   SetDParam(1, c->bankrupt_value == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
01815   SetDParamStr(2, cni->company_name);
01816   SetDParamStr(3, cni->other_company_name);
01817   SetDParam(4, c->bankrupt_value);
01818   AddNewsItem(STR_02B6, NS_COMPANY_MERGER, 0, 0, cni);
01819   AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
01820 
01821   /* original code does this a little bit differently */
01822   ChangeNetworkOwner(ci, _current_company);
01823   ChangeOwnershipOfCompanyItems(ci, _current_company);
01824 
01825   if (c->bankrupt_value == 0) {
01826     owner = GetCompany(_current_company);
01827     owner->current_loan += c->current_loan;
01828   }
01829 
01830   value = CalculateCompanyValue(c) >> 2;
01831   CompanyID old_company = _current_company;
01832   for (i = 0; i != 4; i++) {
01833     if (c->share_owners[i] != COMPANY_SPECTATOR) {
01834       _current_company = c->share_owners[i];
01835       SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -value));
01836     }
01837   }
01838   _current_company = old_company;
01839 
01840   if (!IsHumanCompany(c->index)) AI::Stop(c->index);
01841 
01842   DeleteCompanyWindows(ci);
01843   InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
01844   InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
01845   InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
01846   InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
01847 
01848   delete c;
01849 }
01850 
01851 extern int GetAmountOwnedBy(const Company *c, Owner owner);
01852 
01859 CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01860 {
01861   CommandCost cost(EXPENSES_OTHER);
01862 
01863   /* Check if buying shares is allowed (protection against modified clients) */
01864   /* Cannot buy own shares */
01865   if (!IsValidCompanyID((CompanyID)p1) || !_settings_game.economy.allow_shares || _current_company == (CompanyID)p1) return CMD_ERROR;
01866 
01867   Company *c = GetCompany((CompanyID)p1);
01868 
01869   /* Protect new companies from hostile takeovers */
01870   if (_cur_year - c->inaugurated_year < 6) return_cmd_error(STR_PROTECTED);
01871 
01872   /* Those lines are here for network-protection (clients can be slow) */
01873   if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 0) return cost;
01874 
01875   /* We can not buy out a real company (temporarily). TODO: well, enable it obviously */
01876   if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 1 && !c->is_ai) return cost;
01877 
01878   cost.AddCost(CalculateCompanyValue(c) >> 2);
01879   if (flags & DC_EXEC) {
01880     OwnerByte *b = c->share_owners;
01881     int i;
01882 
01883     while (*b != COMPANY_SPECTATOR) b++; /* share owners is guaranteed to contain at least one COMPANY_SPECTATOR */
01884     *b = _current_company;
01885 
01886     for (i = 0; c->share_owners[i] == _current_company;) {
01887       if (++i == 4) {
01888         c->bankrupt_value = 0;
01889         DoAcquireCompany(c);
01890         break;
01891       }
01892     }
01893     InvalidateWindow(WC_COMPANY, p1);
01894   }
01895   return cost;
01896 }
01897 
01904 CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01905 {
01906   /* Check if selling shares is allowed (protection against modified clients) */
01907   /* Cannot sell own shares */
01908   if (!IsValidCompanyID((CompanyID)p1) || !_settings_game.economy.allow_shares || _current_company == (CompanyID)p1) return CMD_ERROR;
01909 
01910   Company *c = GetCompany((CompanyID)p1);
01911 
01912   /* Those lines are here for network-protection (clients can be slow) */
01913   if (GetAmountOwnedBy(c, _current_company) == 0) return CommandCost();
01914 
01915   /* adjust it a little to make it less profitable to sell and buy */
01916   Money cost = CalculateCompanyValue(c) >> 2;
01917   cost = -(cost - (cost >> 7));
01918 
01919   if (flags & DC_EXEC) {
01920     OwnerByte *b = c->share_owners;
01921     while (*b != _current_company) b++; // share owners is guaranteed to contain company
01922     *b = COMPANY_SPECTATOR;
01923     InvalidateWindow(WC_COMPANY, p1);
01924   }
01925   return CommandCost(EXPENSES_OTHER, cost);
01926 }
01927 
01937 CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01938 {
01939   CompanyID cid = (CompanyID)p1;
01940 
01941   /* Disable takeovers in multiplayer games */
01942   if (!IsValidCompanyID(cid) || _networking) return CMD_ERROR;
01943 
01944   /* Do not allow companies to take over themselves */
01945   if (cid == _current_company) return CMD_ERROR;
01946 
01947   Company *c = GetCompany(cid);
01948 
01949   if (!c->is_ai) return CMD_ERROR;
01950 
01951   if (flags & DC_EXEC) {
01952     DoAcquireCompany(c);
01953   }
01954   return CommandCost(EXPENSES_OTHER, c->bankrupt_value);
01955 }

Generated on Mon Feb 16 23:12:06 2009 for openttd by  doxygen 1.5.6