~ubuntu-branches/debian/squeeze/openttd/squeeze

« back to all changes in this revision

Viewing changes to src/economy.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jordi Mallach, Matthijs Kooijman, Jordi Mallach
  • Date: 2009-04-15 18:22:10 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090415182210-22ktb8kdbp2tf3bm
[ Matthijs Kooijman ]
* New upstream release.
* Remove Debian specific desktop file, upstream provides one now. 
* Add debian/watch file.

[ Jordi Mallach ]
* Bump Standards-Version to 3.8.1, with no changes required.
* Move to debhelper compat 7. Bump Build-Depends accordingly.
* Use dh_prep.
* Add "set -e" to config script.
* Remove a few extra doc files that get installed by upstream Makefile.
* Add more complete copyright information.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: economy.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
 
1
/* $Id: economy.cpp 15726 2009-03-15 16:04:39Z smatz $ */
2
2
 
3
 
/** @file economy.cpp */
 
3
/** @file economy.cpp Handling of the economy. */
4
4
 
5
5
#include "stdafx.h"
6
6
#include "openttd.h"
7
 
#include "currency.h"
8
 
#include "landscape.h"
9
 
#include "news.h"
10
 
#include "player_base.h"
11
 
#include "player_func.h"
12
 
#include "station.h"
 
7
#include "tile_cmd.h"
 
8
#include "company_func.h"
13
9
#include "command_func.h"
14
 
#include "saveload.h"
15
 
#include "industry.h"
 
10
#include "industry_map.h"
16
11
#include "town.h"
 
12
#include "news_func.h"
17
13
#include "network/network.h"
18
 
#include "engine.h"
19
 
#include "network/network_data.h"
20
 
#include "variables.h"
 
14
#include "network/network_func.h"
21
15
#include "vehicle_gui.h"
22
 
#include "ai/ai.h"
23
 
#include "train.h"
24
 
#include "roadveh.h"
 
16
#include "ai/ai.hpp"
25
17
#include "aircraft.h"
26
18
#include "newgrf_engine.h"
27
19
#include "newgrf_sound.h"
28
 
#include "newgrf_callbacks.h"
29
20
#include "newgrf_industries.h"
30
21
#include "newgrf_industrytiles.h"
 
22
#include "newgrf_station.h"
31
23
#include "unmovable.h"
32
 
#include "cargotype.h"
33
 
#include "player_face.h"
34
24
#include "group.h"
35
25
#include "strings_func.h"
36
 
#include "tile_cmd.h"
37
26
#include "functions.h"
38
27
#include "window_func.h"
39
28
#include "date_func.h"
40
29
#include "vehicle_func.h"
41
30
#include "sound_func.h"
42
 
#include "track_type.h"
43
 
#include "track_func.h"
44
 
#include "road_func.h"
45
 
#include "rail_map.h"
46
 
#include "signal_func.h"
47
31
#include "gfx_func.h"
48
32
#include "autoreplace_func.h"
49
 
#include "signs.h"
 
33
#include "company_gui.h"
 
34
#include "signs_base.h"
50
35
 
51
36
#include "table/strings.h"
52
37
#include "table/sprites.h"
83
68
        return (uint32)((uint64)a * (uint64)b >> shift);
84
69
}
85
70
 
 
71
typedef SmallVector<Industry *, 16> SmallIndustryList;
 
72
 
86
73
/* Score info */
87
74
const ScoreInfo _score_info[] = {
88
75
        { SCORE_VEHICLES,        120, 100 },
97
84
        { SCORE_TOTAL,             0,   0 }
98
85
};
99
86
 
100
 
int _score_part[MAX_PLAYERS][SCORE_END];
 
87
int _score_part[MAX_COMPANIES][SCORE_END];
101
88
Economy _economy;
102
 
Subsidy _subsidies[MAX_PLAYERS];
 
89
Subsidy _subsidies[MAX_COMPANIES];
103
90
Prices _price;
104
91
uint16 _price_frac[NUM_PRICES];
105
92
Money  _cargo_payment_rates[NUM_CARGO];
106
93
uint16 _cargo_payment_rates_frac[NUM_CARGO];
107
94
Money _additional_cash_required;
108
95
 
109
 
Money CalculateCompanyValue(const Player* p)
 
96
Money CalculateCompanyValue(const Company *c)
110
97
{
111
 
        PlayerID owner = p->index;
 
98
        Owner owner = c->index;
112
99
        Money value = 0;
113
100
 
114
101
        Station *st;
133
120
        }
134
121
 
135
122
        /* Add real money value */
136
 
        value -= p->current_loan;
137
 
        value += p->player_money;
 
123
        value -= c->current_loan;
 
124
        value += c->money;
138
125
 
139
126
        return max(value, (Money)1);
140
127
}
142
129
/** if update is set to true, the economy is updated with this score
143
130
 *  (also the house is updated, should only be true in the on-tick event)
144
131
 * @param update the economy with calculated score
145
 
 * @param p player been evaluated
146
 
 * @return actual score of this player
 
132
 * @param c company been evaluated
 
133
 * @return actual score of this company
147
134
 * */
148
 
int UpdateCompanyRatingAndValue(Player *p, bool update)
 
135
int UpdateCompanyRatingAndValue(Company *c, bool update)
149
136
{
150
 
        byte owner = p->index;
 
137
        Owner owner = c->index;
151
138
        int score = 0;
152
139
 
153
140
        memset(_score_part[owner], 0, sizeof(_score_part[owner]));
154
141
 
155
 
/* Count vehicles */
 
142
        /* Count vehicles */
156
143
        {
157
144
                Vehicle *v;
158
145
                Money min_profit = 0;
161
148
 
162
149
                FOR_ALL_VEHICLES(v) {
163
150
                        if (v->owner != owner) continue;
164
 
                        if (IsPlayerBuildableVehicleType(v->type) && v->IsPrimaryVehicle()) {
 
151
                        if (IsCompanyBuildableVehicleType(v->type) && v->IsPrimaryVehicle()) {
165
152
                                num++;
166
153
                                if (v->age > 730) {
167
154
                                        /* Find the vehicle with the lowest amount of profit */
181
168
                        _score_part[owner][SCORE_MIN_PROFIT] = ClampToI32(min_profit);
182
169
        }
183
170
 
184
 
/* Count stations */
 
171
        /* Count stations */
185
172
        {
186
173
                uint num = 0;
187
 
                const Station* st;
 
174
                const Station *st;
188
175
 
189
176
                FOR_ALL_STATIONS(st) {
190
177
                        if (st->owner == owner) num += CountBits(st->facilities);
192
179
                _score_part[owner][SCORE_STATIONS] = num;
193
180
        }
194
181
 
195
 
/* Generate statistics depending on recent income statistics */
 
182
        /* Generate statistics depending on recent income statistics */
196
183
        {
197
 
                int numec = min(p->num_valid_stat_ent, 12);
 
184
                int numec = min(c->num_valid_stat_ent, 12);
198
185
                if (numec != 0) {
199
 
                        const PlayerEconomyEntry *pee = p->old_economy;
200
 
                        Money min_income = pee->income + pee->expenses;
201
 
                        Money max_income = pee->income + pee->expenses;
 
186
                        const CompanyEconomyEntry *cee = c->old_economy;
 
187
                        Money min_income = cee->income + cee->expenses;
 
188
                        Money max_income = cee->income + cee->expenses;
202
189
 
203
190
                        do {
204
 
                                min_income = min(min_income, pee->income + pee->expenses);
205
 
                                max_income = max(max_income, pee->income + pee->expenses);
206
 
                        } while (++pee,--numec);
 
191
                                min_income = min(min_income, cee->income + cee->expenses);
 
192
                                max_income = max(max_income, cee->income + cee->expenses);
 
193
                        } while (++cee, --numec);
207
194
 
208
 
                        if (min_income > 0)
 
195
                        if (min_income > 0) {
209
196
                                _score_part[owner][SCORE_MIN_INCOME] = ClampToI32(min_income);
 
197
                        }
210
198
 
211
199
                        _score_part[owner][SCORE_MAX_INCOME] = ClampToI32(max_income);
212
200
                }
213
201
        }
214
202
 
215
 
/* Generate score depending on amount of transported cargo */
 
203
        /* Generate score depending on amount of transported cargo */
216
204
        {
217
 
                const PlayerEconomyEntry* pee;
 
205
                const CompanyEconomyEntry *cee;
218
206
                int numec;
219
207
                uint32 total_delivered;
220
208
 
221
 
                numec = min(p->num_valid_stat_ent, 4);
 
209
                numec = min(c->num_valid_stat_ent, 4);
222
210
                if (numec != 0) {
223
 
                        pee = p->old_economy;
 
211
                        cee = c->old_economy;
224
212
                        total_delivered = 0;
225
213
                        do {
226
 
                                total_delivered += pee->delivered_cargo;
227
 
                        } while (++pee,--numec);
 
214
                                total_delivered += cee->delivered_cargo;
 
215
                        } while (++cee, --numec);
228
216
 
229
217
                        _score_part[owner][SCORE_DELIVERED] = total_delivered;
230
218
                }
231
219
        }
232
220
 
233
 
/* Generate score for variety of cargo */
 
221
        /* Generate score for variety of cargo */
234
222
        {
235
 
                uint num = CountBits(p->cargo_types);
 
223
                uint num = CountBits(c->cargo_types);
236
224
                _score_part[owner][SCORE_CARGO] = num;
237
 
                if (update) p->cargo_types = 0;
 
225
                if (update) c->cargo_types = 0;
238
226
        }
239
227
 
240
 
/* Generate score for player money */
 
228
        /* Generate score for company's money */
241
229
        {
242
 
                if (p->player_money > 0) {
243
 
                        _score_part[owner][SCORE_MONEY] = ClampToI32(p->player_money);
 
230
                if (c->money > 0) {
 
231
                        _score_part[owner][SCORE_MONEY] = ClampToI32(c->money);
244
232
                }
245
233
        }
246
234
 
247
 
/* Generate score for loan */
 
235
        /* Generate score for loan */
248
236
        {
249
 
                _score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - p->current_loan);
 
237
                _score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - c->current_loan);
250
238
        }
251
239
 
252
240
        /* Now we calculate the score for each item.. */
270
258
        }
271
259
 
272
260
        if (update) {
273
 
                p->old_economy[0].performance_history = score;
274
 
                UpdateCompanyHQ(p, score);
275
 
                p->old_economy[0].company_value = CalculateCompanyValue(p);
 
261
                c->old_economy[0].performance_history = score;
 
262
                UpdateCompanyHQ(c, score);
 
263
                c->old_economy[0].company_value = CalculateCompanyValue(c);
276
264
        }
277
265
 
278
266
        InvalidateWindow(WC_PERFORMANCE_DETAIL, 0);
279
267
        return score;
280
268
}
281
269
 
282
 
/*  use PLAYER_SPECTATOR as new_player to delete the player. */
283
 
void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
 
270
/*  use INVALID_OWNER as new_owner to delete the company. */
 
271
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
284
272
{
285
273
        Town *t;
286
 
        PlayerID old = _current_player;
 
274
        CompanyID old = _current_company;
287
275
 
288
 
        assert(old_player != new_player);
 
276
        assert(old_owner != new_owner);
289
277
 
290
278
        {
291
 
                Player *p;
 
279
                Company *c;
292
280
                uint i;
293
281
 
294
 
                /* See if the old_player had shares in other companies */
295
 
                _current_player = old_player;
296
 
                FOR_ALL_PLAYERS(p) {
297
 
                        if (!p->is_active) continue;
 
282
                /* See if the old_owner had shares in other companies */
 
283
                _current_company = old_owner;
 
284
                FOR_ALL_COMPANIES(c) {
298
285
                        for (i = 0; i < 4; i++) {
299
 
                                if (p->share_owners[i] == old_player) {
 
286
                                if (c->share_owners[i] == old_owner) {
300
287
                                        /* Sell his shares */
301
 
                                        CommandCost res = DoCommand(0, p->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
 
288
                                        CommandCost res = DoCommand(0, c->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
302
289
                                        /* Because we are in a DoCommand, we can't just execute an other one and
303
290
                                         *  expect the money to be removed. We need to do it ourself! */
304
 
                                        SubtractMoneyFromPlayer(res);
 
291
                                        SubtractMoneyFromCompany(res);
305
292
                                }
306
293
                        }
307
294
                }
308
295
 
309
296
                /* Sell all the shares that people have on this company */
310
 
                p = GetPlayer(old_player);
 
297
                c = GetCompany(old_owner);
311
298
                for (i = 0; i < 4; i++) {
312
 
                        _current_player = p->share_owners[i];
313
 
                        if (_current_player != PLAYER_SPECTATOR) {
 
299
                        _current_company = c->share_owners[i];
 
300
                        if (_current_company != INVALID_OWNER) {
314
301
                                /* Sell the shares */
315
 
                                CommandCost res = DoCommand(0, old_player, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
 
302
                                CommandCost res = DoCommand(0, old_owner, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
316
303
                                /* Because we are in a DoCommand, we can't just execute an other one and
317
304
                                 *  expect the money to be removed. We need to do it ourself! */
318
 
                                SubtractMoneyFromPlayer(res);
 
305
                                SubtractMoneyFromCompany(res);
319
306
                        }
320
307
                }
321
308
        }
322
309
 
323
 
        _current_player = old_player;
 
310
        _current_company = old_owner;
324
311
 
325
 
        /* Temporarily increase the player's money, to be sure that
 
312
        /* Temporarily increase the company's money, to be sure that
326
313
         * removing his/her property doesn't fail because of lack of money.
327
314
         * Not too drastically though, because it could overflow */
328
 
        if (new_player == PLAYER_SPECTATOR) {
329
 
                GetPlayer(old_player)->player_money = MAX_UVALUE(uint64) >> 2; // jackpot ;p
 
315
        if (new_owner == INVALID_OWNER) {
 
316
                GetCompany(old_owner)->money = UINT64_MAX >> 2; // jackpot ;p
330
317
        }
331
318
 
332
 
        if (new_player == PLAYER_SPECTATOR) {
 
319
        if (new_owner == INVALID_OWNER) {
333
320
                Subsidy *s;
334
321
 
335
322
                for (s = _subsidies; s != endof(_subsidies); s++) {
336
323
                        if (s->cargo_type != CT_INVALID && s->age >= 12) {
337
 
                                if (GetStation(s->to)->owner == old_player) s->cargo_type = CT_INVALID;
 
324
                                if (GetStation(s->to)->owner == old_owner) s->cargo_type = CT_INVALID;
338
325
                        }
339
326
                }
340
327
        }
341
328
 
342
329
        /* Take care of rating in towns */
343
330
        FOR_ALL_TOWNS(t) {
344
 
                /* If a player takes over, give the ratings to that player. */
345
 
                if (new_player != PLAYER_SPECTATOR) {
346
 
                        if (HasBit(t->have_ratings, old_player)) {
347
 
                                if (HasBit(t->have_ratings, new_player)) {
348
 
                                        // use max of the two ratings.
349
 
                                        t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
 
331
                /* If a company takes over, give the ratings to that company. */
 
332
                if (new_owner != INVALID_OWNER) {
 
333
                        if (HasBit(t->have_ratings, old_owner)) {
 
334
                                if (HasBit(t->have_ratings, new_owner)) {
 
335
                                        /* use max of the two ratings. */
 
336
                                        t->ratings[new_owner] = max(t->ratings[new_owner], t->ratings[old_owner]);
350
337
                                } else {
351
 
                                        SetBit(t->have_ratings, new_player);
352
 
                                        t->ratings[new_player] = t->ratings[old_player];
 
338
                                        SetBit(t->have_ratings, new_owner);
 
339
                                        t->ratings[new_owner] = t->ratings[old_owner];
353
340
                                }
354
341
                        }
355
342
                }
356
343
 
357
 
                /* Reset the ratings for the old player */
358
 
                t->ratings[old_player] = 500;
359
 
                ClrBit(t->have_ratings, old_player);
 
344
                /* Reset the ratings for the old owner */
 
345
                t->ratings[old_owner] = RATING_INITIAL;
 
346
                ClrBit(t->have_ratings, old_owner);
360
347
        }
361
348
 
362
349
        {
363
 
                int num_train = 0;
364
 
                int num_road = 0;
365
 
                int num_ship = 0;
366
 
                int num_aircraft = 0;
 
350
                FreeUnitIDGenerator unitidgen[] = {
 
351
                        FreeUnitIDGenerator(VEH_TRAIN, new_owner), FreeUnitIDGenerator(VEH_ROAD,     new_owner),
 
352
                        FreeUnitIDGenerator(VEH_SHIP,  new_owner), FreeUnitIDGenerator(VEH_AIRCRAFT, new_owner)
 
353
                };
 
354
 
367
355
                Vehicle *v;
368
 
 
369
 
                /*  Determine Ids for the new vehicles */
370
 
                FOR_ALL_VEHICLES(v) {
371
 
                        if (v->owner == new_player) {
372
 
                                switch (v->type) {
373
 
                                        case VEH_TRAIN:    if (IsFrontEngine(v)) num_train++; break;
374
 
                                        case VEH_ROAD:     if (IsRoadVehFront(v)) num_road++; break;
375
 
                                        case VEH_SHIP:     num_ship++; break;
376
 
                                        case VEH_AIRCRAFT: if (IsNormalAircraft(v)) num_aircraft++; break;
377
 
                                        default: break;
378
 
                                }
379
 
                        }
380
 
                }
381
 
 
382
 
                FOR_ALL_VEHICLES(v) {
383
 
                        if (v->owner == old_player && IsInsideMM(v->type, VEH_TRAIN, VEH_AIRCRAFT + 1)) {
384
 
                                if (new_player == PLAYER_SPECTATOR) {
385
 
                                        DeleteWindowById(WC_VEHICLE_VIEW, v->index);
386
 
                                        DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
387
 
                                        DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
388
 
 
389
 
                                        if (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && IsFreeWagon(v))) {
390
 
                                                switch (v->type) {
391
 
                                                        default: NOT_REACHED();
392
 
 
393
 
                                                        case VEH_TRAIN: {
394
 
                                                                Vehicle *u = v;
395
 
                                                                do {
396
 
                                                                        Vehicle *next = GetNextVehicle(u);
397
 
                                                                        delete u;
398
 
                                                                        u = next;
399
 
                                                                } while (u != NULL);
400
 
                                                        } break;
401
 
 
402
 
                                                        case VEH_ROAD:
403
 
                                                        case VEH_SHIP:
404
 
                                                                delete v;
405
 
                                                                break;
406
 
 
407
 
                                                        case VEH_AIRCRAFT:
408
 
                                                                DeleteVehicleChain(v);
409
 
                                                                break;
410
 
                                                }
411
 
                                        }
 
356
                FOR_ALL_VEHICLES(v) {
 
357
                        if (v->owner == old_owner && IsCompanyBuildableVehicleType(v->type)) {
 
358
                                if (new_owner == INVALID_OWNER) {
 
359
                                        if (v->Previous() == NULL) delete v;
412
360
                                } else {
413
 
                                        v->owner = new_player;
414
 
                                        v->colormap = PAL_NONE;
415
 
                                        v->group_id = DEFAULT_GROUP;
416
 
                                        if (IsEngineCountable(v)) GetPlayer(new_player)->num_engines[v->engine_type]++;
417
 
                                        switch (v->type) {
418
 
                                                case VEH_TRAIN:    if (IsFrontEngine(v)) v->unitnumber = ++num_train; break;
419
 
                                                case VEH_ROAD:     if (IsRoadVehFront(v)) v->unitnumber = ++num_road; break;
420
 
                                                case VEH_SHIP:     v->unitnumber = ++num_ship; break;
421
 
                                                case VEH_AIRCRAFT: if (IsNormalAircraft(v)) v->unitnumber = ++num_aircraft; break;
422
 
                                                default: NOT_REACHED();
423
 
                                        }
 
361
                                        v->owner = new_owner;
 
362
                                        v->colourmap = PAL_NONE;
 
363
                                        if (IsEngineCountable(v)) GetCompany(new_owner)->num_engines[v->engine_type]++;
 
364
                                        if (v->IsPrimaryVehicle()) v->unitnumber = unitidgen[v->type].NextID();
424
365
                                }
425
366
                        }
426
367
                }
430
371
        {
431
372
                TileIndex tile = 0;
432
373
                do {
433
 
                        ChangeTileOwner(tile, old_player, new_player);
 
374
                        ChangeTileOwner(tile, old_owner, new_owner);
434
375
                } while (++tile != MapSize());
435
376
 
436
 
                if (new_player != PLAYER_SPECTATOR) {
437
 
                        /* Update all signals because there can be new segment that was owned by two players
 
377
                if (new_owner != INVALID_OWNER) {
 
378
                        /* Update all signals because there can be new segment that was owned by two companies
438
379
                         * and signals were not propagated
439
380
                         * Similiar with crossings - it is needed to bar crossings that weren't before
440
381
                         * because of different owner of crossing and approaching train */
441
382
                        tile = 0;
442
383
 
443
384
                        do {
444
 
                                if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, new_player) && HasSignals(tile)) {
 
385
                                if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, new_owner) && HasSignals(tile)) {
445
386
                                        TrackBits tracks = GetTrackBits(tile);
446
387
                                        do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT
447
388
                                                Track track = RemoveFirstTrack(&tracks);
448
 
                                                if (HasSignalOnTrack(tile, track)) AddTrackToSignalBuffer(tile, track, new_player);
 
389
                                                if (HasSignalOnTrack(tile, track)) AddTrackToSignalBuffer(tile, track, new_owner);
449
390
                                        } while (tracks != TRACK_BIT_NONE);
450
 
                                } else if (IsLevelCrossingTile(tile) && IsTileOwner(tile, new_player)) {
 
391
                                } else if (IsLevelCrossingTile(tile) && IsTileOwner(tile, new_owner)) {
451
392
                                        UpdateLevelCrossing(tile);
452
393
                                }
453
394
                        } while (++tile != MapSize());
457
398
                UpdateSignalsInBuffer();
458
399
        }
459
400
 
 
401
        /* convert owner of stations (including deleted ones, but excluding buoys) */
 
402
        Station *st;
 
403
        FOR_ALL_STATIONS(st) {
 
404
                if (st->owner == old_owner) {
 
405
                        /* if a company goes bankrupt, set owner to OWNER_NONE so the sign doesn't disappear immediately
 
406
                         * also, drawing station window would cause reading invalid company's colour */
 
407
                        st->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner;
 
408
                }
 
409
        }
 
410
 
 
411
        /* do the same for waypoints (we need to do this here so deleted waypoints are converted too) */
 
412
        Waypoint *wp;
 
413
        FOR_ALL_WAYPOINTS(wp) {
 
414
                if (wp->owner == old_owner) {
 
415
                        wp->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner;
 
416
                }
 
417
        }
 
418
 
460
419
        /* In all cases clear replace engine rules.
461
420
         * Even if it was copied, it could interfere with new owner's rules */
462
 
        RemoveAllEngineReplacementForPlayer(GetPlayer(old_player));
 
421
        RemoveAllEngineReplacementForCompany(GetCompany(old_owner));
463
422
 
464
 
        if (new_player == PLAYER_SPECTATOR) {
465
 
                RemoveAllGroupsForPlayer(old_player);
 
423
        if (new_owner == INVALID_OWNER) {
 
424
                RemoveAllGroupsForCompany(old_owner);
466
425
        } else {
467
426
                Group *g;
468
427
                FOR_ALL_GROUPS(g) {
469
 
                        if (g->owner == old_player) g->owner = new_player;
 
428
                        if (g->owner == old_owner) g->owner = new_owner;
470
429
                }
471
430
        }
472
431
 
473
432
        Sign *si;
474
433
        FOR_ALL_SIGNS(si) {
475
 
                if (si->owner == old_player) si->owner = new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player;
 
434
                if (si->owner == old_owner) si->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner;
476
435
        }
477
436
 
478
 
        /* Change color of existing windows */
479
 
        if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);
 
437
        /* Change colour of existing windows */
 
438
        if (new_owner != INVALID_OWNER) ChangeWindowOwner(old_owner, new_owner);
480
439
 
481
 
        _current_player = old;
 
440
        _current_company = old;
482
441
 
483
442
        MarkWholeScreenDirty();
484
443
}
485
444
 
486
 
static void ChangeNetworkOwner(PlayerID current_player, PlayerID new_player)
 
445
static void ChangeNetworkOwner(Owner current_owner, Owner new_owner)
487
446
{
488
447
#ifdef ENABLE_NETWORK
489
448
        if (!_networking) return;
490
449
 
491
 
        if (current_player == _local_player) {
492
 
                _network_playas = new_player;
493
 
                SetLocalPlayer(new_player);
 
450
        if (current_owner == _local_company) {
 
451
                _network_playas = new_owner;
 
452
                SetLocalCompany(new_owner);
494
453
        }
495
454
 
496
455
        if (!_network_server) return;
497
456
 
498
 
        /* The server has to handle all administrative issues, for example
499
 
        * updating and notifying all clients of what has happened */
500
 
        NetworkTCPSocketHandler *cs;
501
 
        NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
502
 
 
503
 
        /* The server has just changed from player */
504
 
        if (current_player == ci->client_playas) {
505
 
                ci->client_playas = new_player;
506
 
                NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
507
 
        }
508
 
 
509
 
        /* Find all clients that were in control of this company, and mark them as new_player */
510
 
        FOR_ALL_CLIENTS(cs) {
511
 
                ci = DEREF_CLIENT_INFO(cs);
512
 
                if (current_player == ci->client_playas) {
513
 
                        ci->client_playas = new_player;
514
 
                        NetworkUpdateClientInfo(ci->client_index);
515
 
                }
516
 
        }
 
457
        NetworkServerChangeOwner(current_owner, new_owner);
517
458
#endif /* ENABLE_NETWORK */
518
459
}
519
460
 
520
 
static void PlayersCheckBankrupt(Player *p)
 
461
static void CompanyCheckBankrupt(Company *c)
521
462
{
522
 
        PlayerID owner;
523
 
 
524
 
        /*  If the player has money again, it does not go bankrupt */
525
 
        if (p->player_money >= 0) {
526
 
                p->quarters_of_bankrupcy = 0;
 
463
        /*  If the company has money again, it does not go bankrupt */
 
464
        if (c->money >= 0) {
 
465
                c->quarters_of_bankrupcy = 0;
527
466
                return;
528
467
        }
529
468
 
530
 
        p->quarters_of_bankrupcy++;
531
 
 
532
 
        owner = p->index;
533
 
 
534
 
        switch (p->quarters_of_bankrupcy) {
 
469
        c->quarters_of_bankrupcy++;
 
470
 
 
471
        CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
 
472
        cni->FillData(c);
 
473
 
 
474
        switch (c->quarters_of_bankrupcy) {
 
475
                case 0:
 
476
                case 1:
 
477
                        free(cni);
 
478
                        break;
 
479
 
535
480
                case 2:
536
 
                        AddNewsItem( (StringID)(owner | NB_BTROUBLE),
537
 
                                NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 
481
                        SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
 
482
                        SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
 
483
                        SetDParamStr(2, cni->company_name);
 
484
                        AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, 0, cni);
 
485
                        AI::BroadcastNewEvent(new AIEventCompanyInTrouble(c->index));
538
486
                        break;
539
487
                case 3: {
540
 
                        /* XXX - In multiplayer, should we ask other players if it wants to take
 
488
                        /* XXX - In multiplayer, should we ask other companies if it wants to take
541
489
                          over when it is a human company? -- TrueLight */
542
 
                        if (IsHumanPlayer(owner)) {
543
 
                                AddNewsItem( (StringID)(owner | NB_BTROUBLE),
544
 
                                        NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 
490
                        if (IsHumanCompany(c->index)) {
 
491
                                SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
 
492
                                SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
 
493
                                SetDParamStr(2, cni->company_name);
 
494
                                AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, 0, cni);
545
495
                                break;
546
496
                        }
547
497
 
548
498
                        /* Check if the company has any value.. if not, declare it bankrupt
549
499
                         *  right now */
550
 
                        Money val = CalculateCompanyValue(p);
 
500
                        Money val = CalculateCompanyValue(c);
551
501
                        if (val > 0) {
552
 
                                p->bankrupt_value = val;
553
 
                                p->bankrupt_asked = 1 << owner; // Don't ask the owner
554
 
                                p->bankrupt_timeout = 0;
 
502
                                c->bankrupt_value = val;
 
503
                                c->bankrupt_asked = 1 << c->index; // Don't ask the owner
 
504
                                c->bankrupt_timeout = 0;
 
505
                                free(cni);
555
506
                                break;
556
507
                        }
557
508
                        /* Else, falltrue to case 4... */
558
509
                }
559
 
                case 4: {
 
510
                default:
 
511
                case 4:
 
512
                        if (!_networking && _local_company == c->index) {
 
513
                                /* If we are in offline mode, leave the company playing. Eg. there
 
514
                                 * is no THE-END, otherwise mark the client as spectator to make sure
 
515
                                 * he/she is no long in control of this company. However... when you
 
516
                                 * join another company (cheat) the "unowned" company can bankrupt. */
 
517
                                c->bankrupt_asked = MAX_UVALUE(CompanyMask);
 
518
                                c->bankrupt_timeout = 0x456;
 
519
                                break;
 
520
                        }
 
521
 
560
522
                        /* Close everything the owner has open */
561
 
                        DeletePlayerWindows(owner);
 
523
                        DeleteCompanyWindows(c->index);
562
524
 
563
525
                        /* Show bankrupt news */
564
 
                        SetDParam(0, p->index);
565
 
                        AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
566
 
 
567
 
                        if (IsHumanPlayer(owner)) {
568
 
                                /* XXX - If we are in offline mode, leave the player playing. Eg. there
569
 
                                 * is no THE-END, otherwise mark the player as spectator to make sure
570
 
                                 * he/she is no long in control of this company */
571
 
                                if (!_networking) {
572
 
                                        p->bankrupt_asked = 0xFF;
573
 
                                        p->bankrupt_timeout = 0x456;
574
 
                                        break;
575
 
                                }
576
 
 
577
 
                                ChangeNetworkOwner(owner, PLAYER_SPECTATOR);
578
 
                        }
579
 
 
580
 
                        /* Remove the player */
581
 
                        ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
582
 
                        /* Register the player as not-active */
583
 
                        p->is_active = false;
584
 
 
585
 
                        if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
586
 
                                AI_PlayerDied(owner);
587
 
                }
588
 
        }
589
 
}
590
 
 
591
 
void DrawNewsBankrupcy(Window *w)
592
 
{
593
 
        DrawNewsBorder(w);
594
 
 
595
 
        const NewsItem *ni = WP(w, news_d).ni;
596
 
        Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
597
 
        DrawPlayerFace(p->face, p->player_color, 2, 23);
598
 
        GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
599
 
 
600
 
        SetDParam(0, p->index);
601
 
 
602
 
        DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
603
 
 
604
 
        switch (ni->string_id & 0xF0) {
605
 
        case NB_BTROUBLE:
606
 
                DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
607
 
 
608
 
                SetDParam(0, p->index);
609
 
 
610
 
                DrawStringMultiCenter(
611
 
                        ((w->width - 101) >> 1) + 98,
612
 
                        90,
613
 
                        STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
614
 
                        w->width - 101);
615
 
                break;
616
 
 
617
 
        case NB_BMERGER:
618
 
                DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
619
 
                SetDParam(0, ni->params[0]);
620
 
                SetDParam(1, p->index);
621
 
                SetDParam(2, ni->params[1]);
622
 
                DrawStringMultiCenter(
623
 
                        ((w->width - 101) >> 1) + 98,
624
 
                        90,
625
 
                        ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
626
 
                        w->width - 101);
627
 
                break;
628
 
 
629
 
        case NB_BBANKRUPT:
630
 
                DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
631
 
                SetDParam(0, ni->params[0]);
632
 
                DrawStringMultiCenter(
633
 
                        ((w->width - 101) >> 1) + 98,
634
 
                        90,
635
 
                        STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
636
 
                        w->width - 101);
637
 
                break;
638
 
 
639
 
        case NB_BNEWCOMPANY:
640
 
                DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
641
 
                SetDParam(0, p->index);
642
 
                SetDParam(1, ni->params[0]);
643
 
                DrawStringMultiCenter(
644
 
                        ((w->width - 101) >> 1) + 98,
645
 
                        90,
646
 
                        STR_705F_STARTS_CONSTRUCTION_NEAR,
647
 
                        w->width - 101);
648
 
                break;
649
 
 
650
 
        default:
651
 
                NOT_REACHED();
652
 
        }
653
 
}
654
 
 
655
 
StringID GetNewsStringBankrupcy(const NewsItem *ni)
656
 
{
657
 
        const Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
658
 
 
659
 
        switch (ni->string_id & 0xF0) {
660
 
        case NB_BTROUBLE:
661
 
                SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
662
 
                SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
663
 
                SetDParam(2, p->index);
664
 
                return STR_02B6;
665
 
        case NB_BMERGER:
666
 
                SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
667
 
                SetDParam(1, ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
668
 
                SetDParam(2, ni->params[0]);
669
 
                SetDParam(3, p->index);
670
 
                SetDParam(4, ni->params[1]);
671
 
                return STR_02B6;
672
 
        case NB_BBANKRUPT:
673
 
                SetDParam(0, STR_705C_BANKRUPT);
674
 
                SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
675
 
                SetDParam(2, ni->params[0]);
676
 
                return STR_02B6;
677
 
        case NB_BNEWCOMPANY:
678
 
                SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
679
 
                SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
680
 
                SetDParam(2, p->index);
681
 
                SetDParam(3, ni->params[0]);
682
 
                return STR_02B6;
683
 
        default:
684
 
                NOT_REACHED();
685
 
        }
686
 
}
687
 
 
688
 
static void PlayersGenStatistics()
 
526
                        SetDParam(0, STR_705C_BANKRUPT);
 
527
                        SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
 
528
                        SetDParamStr(2, cni->company_name);
 
529
                        AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, 0, cni);
 
530
 
 
531
                        /* Remove the company */
 
532
                        ChangeNetworkOwner(c->index, COMPANY_SPECTATOR);
 
533
                        ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
 
534
 
 
535
                        if (!IsHumanCompany(c->index)) AI::Stop(c->index);
 
536
 
 
537
                        CompanyID c_index = c->index;
 
538
                        delete c;
 
539
                        AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index));
 
540
        }
 
541
}
 
542
 
 
543
static void CompaniesGenStatistics()
689
544
{
690
545
        Station *st;
691
 
        Player *p;
 
546
        Company *c;
692
547
 
693
548
        FOR_ALL_STATIONS(st) {
694
 
                _current_player = st->owner;
 
549
                _current_company = st->owner;
695
550
                CommandCost cost(EXPENSES_PROPERTY, _price.station_value >> 1);
696
 
                SubtractMoneyFromPlayer(cost);
 
551
                SubtractMoneyFromCompany(cost);
697
552
        }
698
553
 
699
 
        if (!HasBit(1<<0|1<<3|1<<6|1<<9, _cur_month))
 
554
        if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month))
700
555
                return;
701
556
 
702
 
        FOR_ALL_PLAYERS(p) {
703
 
                if (p->is_active) {
704
 
                        memmove(&p->old_economy[1], &p->old_economy[0], sizeof(p->old_economy) - sizeof(p->old_economy[0]));
705
 
                        p->old_economy[0] = p->cur_economy;
706
 
                        memset(&p->cur_economy, 0, sizeof(p->cur_economy));
707
 
 
708
 
                        if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++;
709
 
 
710
 
                        UpdateCompanyRatingAndValue(p, true);
711
 
                        PlayersCheckBankrupt(p);
712
 
 
713
 
                        if (p->block_preview != 0) p->block_preview--;
714
 
                }
 
557
        FOR_ALL_COMPANIES(c) {
 
558
                memmove(&c->old_economy[1], &c->old_economy[0], sizeof(c->old_economy) - sizeof(c->old_economy[0]));
 
559
                c->old_economy[0] = c->cur_economy;
 
560
                memset(&c->cur_economy, 0, sizeof(c->cur_economy));
 
561
 
 
562
                if (c->num_valid_stat_ent != 24) c->num_valid_stat_ent++;
 
563
 
 
564
                UpdateCompanyRatingAndValue(c, true);
 
565
                CompanyCheckBankrupt(c);
 
566
 
 
567
                if (c->block_preview != 0) c->block_preview--;
715
568
        }
716
569
 
717
570
        InvalidateWindow(WC_INCOME_GRAPH, 0);
735
588
        }
736
589
}
737
590
 
738
 
static void AddInflation()
 
591
static void AddInflation(bool check_year = true)
739
592
{
740
593
        /* The cargo payment inflation differs from the normal inflation, so the
741
594
         * relative amount of money you make with a transport decreases slowly over
752
605
         * inflation doesn't add anything after that either; it even makes playing
753
606
         * it impossible due to the diverging cost and income rates.
754
607
         */
755
 
        if ((_cur_year - _patches.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return;
 
608
        if (check_year && (_cur_year - _settings_game.game_creation.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return;
756
609
 
757
610
        /* Approximation for (100 + infl_amount)% ** (1 / 12) - 100%
758
611
         * scaled by 65536
759
612
         * 12 -> months per year
760
613
         * This is only a good approxiamtion for small values
761
614
         */
762
 
        Money inf = _economy.infl_amount * 54;
 
615
        int32 inf = _economy.infl_amount * 54;
763
616
 
764
617
        for (uint i = 0; i != NUM_PRICES; i++) {
765
618
                AddSingleInflation((Money*)&_price + i, _price_frac + i, inf);
784
637
        InvalidateWindow(WC_PAYMENT_RATES, 0);
785
638
}
786
639
 
787
 
static void PlayersPayInterest()
 
640
static void CompaniesPayInterest()
788
641
{
789
 
        const Player* p;
790
 
        int interest = _economy.interest_rate * 54;
791
 
 
792
 
        FOR_ALL_PLAYERS(p) {
793
 
                if (!p->is_active) continue;
794
 
 
795
 
                _current_player = p->index;
796
 
 
797
 
                SubtractMoneyFromPlayer(CommandCost(EXPENSES_LOAN_INT, (Money)BigMulSU(p->current_loan, interest, 16)));
798
 
 
799
 
                SubtractMoneyFromPlayer(CommandCost(EXPENSES_OTHER, _price.station_value >> 2));
 
642
        const Company *c;
 
643
 
 
644
        FOR_ALL_COMPANIES(c) {
 
645
                _current_company = c->index;
 
646
 
 
647
                /* Over a year the paid interest should be "loan * interest percentage",
 
648
                 * but... as that number is likely not dividable by 12 (pay each month),
 
649
                 * one needs to account for that in the monthly fee calculations.
 
650
                 * To easily calculate what one should pay "this" month, you calculate
 
651
                 * what (total) should have been paid up to this month and you substract
 
652
                 * whatever has been paid in the previous months. This will mean one month
 
653
                 * it'll be a bit more and the other it'll be a bit less than the average
 
654
                 * monthly fee, but on average it will be exact. */
 
655
                Money yearly_fee = c->current_loan * _economy.interest_rate / 100;
 
656
                Money up_to_previous_month = yearly_fee * _cur_month / 12;
 
657
                Money up_to_this_month = yearly_fee * (_cur_month + 1) / 12;
 
658
 
 
659
                SubtractMoneyFromCompany(CommandCost(EXPENSES_LOAN_INT, up_to_this_month - up_to_previous_month));
 
660
 
 
661
                SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, _price.station_value >> 2));
800
662
        }
801
663
}
802
664
 
803
665
static void HandleEconomyFluctuations()
804
666
{
805
 
        if (_opt.diff.economy == 0) return;
 
667
        if (_settings_game.difficulty.economy == 0) return;
806
668
 
807
669
        if (--_economy.fluct == 0) {
808
670
                _economy.fluct = -(int)GB(Random(), 0, 2);
809
 
                AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
 
671
                AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NS_ECONOMY, 0, 0);
810
672
        } else if (_economy.fluct == -12) {
811
673
                _economy.fluct = GB(Random(), 0, 8) + 312;
812
 
                AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
 
674
                AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NS_ECONOMY, 0, 0);
813
675
        }
814
676
}
815
677
 
902
764
        price_base_multiplier[price] = factor;
903
765
}
904
766
 
 
767
/**
 
768
 * Initialize the variables that will maintain the daily industry change system.
 
769
 * @param init_counter specifies if the counter is required to be initialized
 
770
 */
 
771
void StartupIndustryDailyChanges(bool init_counter)
 
772
{
 
773
        uint map_size = MapLogX() + MapLogY();
 
774
        /* After getting map size, it needs to be scaled appropriately and divided by 31,
 
775
         * which stands for the days in a month.
 
776
         * Using just 31 will make it so that a monthly reset (based on the real number of days of that month)
 
777
         * would not be needed.
 
778
         * Since it is based on "fractionnal parts", the leftover days will not make much of a difference
 
779
         * on the overall total number of changes performed */
 
780
        _economy.industry_daily_increment = (1 << map_size) / 31;
 
781
 
 
782
        if (init_counter) {
 
783
                /* A new game or a savegame from an older version will require the counter to be initialized */
 
784
                _economy.industry_daily_change_counter = 0;
 
785
        }
 
786
}
 
787
 
905
788
void StartupEconomy()
906
789
{
907
790
        int i;
911
794
        for (i = 0; i != NUM_PRICES; i++) {
912
795
                Money price = _price_base[i];
913
796
                if (_price_category[i] != 0) {
914
 
                        uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
 
797
                        uint mod = _price_category[i] == 1 ? _settings_game.difficulty.vehicle_costs : _settings_game.difficulty.construction_cost;
915
798
                        if (mod < 1) {
916
799
                                price = price * 3 >> 2;
917
800
                        } else if (mod > 1) {
927
810
                _price_frac[i] = 0;
928
811
        }
929
812
 
930
 
        _economy.interest_rate = _opt.diff.initial_interest;
931
 
        _economy.infl_amount = _opt.diff.initial_interest;
932
 
        _economy.infl_amount_pr = max(0, _opt.diff.initial_interest - 1);
933
 
        _economy.max_loan_unround = _economy.max_loan = _opt.diff.max_loan * 1000;
 
813
        _economy.interest_rate = _settings_game.difficulty.initial_interest;
 
814
        _economy.infl_amount = _settings_game.difficulty.initial_interest;
 
815
        _economy.infl_amount_pr = max(0, _settings_game.difficulty.initial_interest - 1);
 
816
        _economy.max_loan_unround = _economy.max_loan = _settings_game.difficulty.max_loan;
934
817
        _economy.fluct = GB(Random(), 0, 8) + 168;
935
 
}
936
 
 
 
818
 
 
819
        StartupIndustryDailyChanges(true); // As we are starting a new game, initialize the counter too
 
820
 
 
821
}
 
822
 
 
823
void ResetEconomy()
 
824
{
 
825
        /* Test if resetting the economy is needed. */
 
826
        bool needed = false;
 
827
 
 
828
        for (CargoID c = 0; c < NUM_CARGO; c++) {
 
829
                const CargoSpec *cs = GetCargo(c);
 
830
                if (!cs->IsValid()) continue;
 
831
                if (_cargo_payment_rates[c] == 0) {
 
832
                        needed = true;
 
833
                        break;
 
834
                }
 
835
        }
 
836
 
 
837
        if (!needed) return;
 
838
 
 
839
        /* Remember old unrounded maximum loan value. NewGRF has the ability
 
840
         * to change all the other inflation affected base costs. */
 
841
        Money old_value = _economy.max_loan_unround;
 
842
 
 
843
        /* Reset the economy */
 
844
        StartupEconomy();
 
845
        InitializeLandscapeVariables(false);
 
846
 
 
847
        /* Reapply inflation, ignoring the year */
 
848
        while (old_value > _economy.max_loan_unround) {
 
849
                AddInflation(false);
 
850
        }
 
851
}
937
852
 
938
853
Money GetPriceByIndex(uint8 index)
939
854
{
943
858
}
944
859
 
945
860
 
946
 
Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode)
 
861
Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
947
862
{
948
863
        TileIndex tile;
949
864
        TileIndex tile2;
1047
962
 
1048
963
static void FindSubsidyPassengerRoute(FoundRoute *fr)
1049
964
{
1050
 
        Town *from,*to;
 
965
        Town *from, *to;
1051
966
 
1052
 
        fr->distance = (uint)-1;
 
967
        fr->distance = UINT_MAX;
1053
968
 
1054
969
        fr->from = from = GetRandomTown();
1055
970
        if (from == NULL || from->population < 400) return;
1067
982
        int trans, total;
1068
983
        CargoID cargo;
1069
984
 
1070
 
        fr->distance = (uint)-1;
 
985
        fr->distance = UINT_MAX;
1071
986
 
1072
987
        fr->from = i = GetRandomIndustry();
1073
988
        if (i == NULL) return;
1120
1035
 
1121
1036
static bool CheckSubsidyDuplicate(Subsidy *s)
1122
1037
{
1123
 
        const Subsidy* ss;
 
1038
        const Subsidy *ss;
1124
1039
 
1125
1040
        for (ss = _subsidies; ss != endof(_subsidies); ss++) {
1126
1041
                if (s != ss &&
1147
1062
        for (s = _subsidies; s != endof(_subsidies); s++) {
1148
1063
                if (s->cargo_type == CT_INVALID) continue;
1149
1064
 
1150
 
                if (s->age == 12-1) {
 
1065
                if (s->age == 12 - 1) {
1151
1066
                        pair = SetupSubsidyDecodeParam(s, 1);
1152
 
                        AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
 
1067
                        AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
1153
1068
                        s->cargo_type = CT_INVALID;
1154
1069
                        modified = true;
1155
 
                } else if (s->age == 2*12-1) {
 
1070
                        AI::BroadcastNewEvent(new AIEventSubsidyOfferExpired(s - _subsidies));
 
1071
                } else if (s->age == 2 * 12 - 1) {
1156
1072
                        st = GetStation(s->to);
1157
 
                        if (st->owner == _local_player) {
 
1073
                        if (st->owner == _local_company) {
1158
1074
                                pair = SetupSubsidyDecodeParam(s, 1);
1159
 
                                AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
 
1075
                                AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
1160
1076
                        }
1161
1077
                        s->cargo_type = CT_INVALID;
1162
1078
                        modified = true;
 
1079
                        AI::BroadcastNewEvent(new AIEventSubsidyExpired(s - _subsidies));
1163
1080
                } else {
1164
1081
                        s->age++;
1165
1082
                }
1166
1083
        }
1167
1084
 
1168
1085
        /* 25% chance to go on */
1169
 
        if (Chance16(1,4)) {
 
1086
        if (Chance16(1, 4)) {
1170
1087
                /*  Find a free slot*/
1171
1088
                s = _subsidies;
1172
1089
                while (s->cargo_type != CT_INVALID) {
1195
1112
                                if (!CheckSubsidyDuplicate(s)) {
1196
1113
                                        s->age = 0;
1197
1114
                                        pair = SetupSubsidyDecodeParam(s, 0);
1198
 
                                        AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
 
1115
                                        AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
 
1116
                                        AI::BroadcastNewEvent(new AIEventSubsidyOffer(s - _subsidies));
1199
1117
                                        modified = true;
1200
1118
                                        break;
1201
1119
                                }
1207
1125
                InvalidateWindow(WC_SUBSIDIES_LIST, 0);
1208
1126
}
1209
1127
 
1210
 
static const SaveLoad _subsidies_desc[] = {
1211
 
            SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
1212
 
            SLE_VAR(Subsidy, age,        SLE_UINT8),
1213
 
        SLE_CONDVAR(Subsidy, from,       SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
1214
 
        SLE_CONDVAR(Subsidy, from,       SLE_UINT16,                5, SL_MAX_VERSION),
1215
 
        SLE_CONDVAR(Subsidy, to,         SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
1216
 
        SLE_CONDVAR(Subsidy, to,         SLE_UINT16,                5, SL_MAX_VERSION),
1217
 
        SLE_END()
1218
 
};
1219
 
 
1220
 
static void Save_SUBS()
1221
 
{
1222
 
        int i;
1223
 
        Subsidy *s;
1224
 
 
1225
 
        for (i = 0; i != lengthof(_subsidies); i++) {
1226
 
                s = &_subsidies[i];
1227
 
                if (s->cargo_type != CT_INVALID) {
1228
 
                        SlSetArrayIndex(i);
1229
 
                        SlObject(s, _subsidies_desc);
1230
 
                }
1231
 
        }
1232
 
}
1233
 
 
1234
 
static void Load_SUBS()
1235
 
{
1236
 
        int index;
1237
 
        while ((index = SlIterateArray()) != -1)
1238
 
                SlObject(&_subsidies[index], _subsidies_desc);
1239
 
}
1240
 
 
1241
1128
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
1242
1129
{
1243
1130
        const CargoSpec *cs = GetCargo(cargo_type);
1260
1147
        }
1261
1148
 
1262
1149
        /* zero the distance (thus income) if it's the bank and very short transport. */
1263
 
        if (_opt.landscape == LT_TEMPERATE && cs->label == 'VALU' && dist < 10) return 0;
 
1150
        if (_settings_game.game_creation.landscape == LT_TEMPERATE && cs->label == 'VALU' && dist < 10) return 0;
1264
1151
 
1265
1152
 
1266
1153
        static const int MIN_TIME_FACTOR = 31;
1268
1155
 
1269
1156
        const int days1 = cs->transit_days[0];
1270
1157
        const int days2 = cs->transit_days[1];
1271
 
        const int days_over_days1 = transit_days - days1;
 
1158
        const int days_over_days1 = max(   transit_days - days1, 0);
 
1159
        const int days_over_days2 = max(days_over_days1 - days2, 0);
1272
1160
 
1273
1161
        /*
1274
1162
         * The time factor is calculated based on the time it took
1280
1168
         *  - linear decreasing with time with a slope of -2 for slow transports
1281
1169
         *
1282
1170
         */
1283
 
        int time_factor;
1284
 
        if (days_over_days1 <= 0) {
1285
 
                time_factor = MAX_TIME_FACTOR;
1286
 
        } else if (days_over_days1 <= days2) {
1287
 
                time_factor = MAX_TIME_FACTOR - days_over_days1;
1288
 
        } else {
1289
 
                time_factor = MAX_TIME_FACTOR - 2 * days_over_days1 + days2;
1290
 
        }
1291
 
 
1292
 
        if (time_factor < MIN_TIME_FACTOR) time_factor = MIN_TIME_FACTOR;
 
1171
        const int time_factor = max(MAX_TIME_FACTOR - days_over_days1 - days_over_days2, MIN_TIME_FACTOR);
1293
1172
 
1294
1173
        return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
1295
1174
}
1296
1175
 
1297
 
static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
1298
 
{
1299
 
        Industry *best = NULL;
1300
 
        Industry *ind;
1301
 
        const IndustrySpec *indspec;
1302
 
        uint best_dist;
1303
 
        uint accepted_cargo_index = 0;  ///< unlikely value, just for warning removing
1304
 
 
1305
 
        /* Check if there's an industry close to the station that accepts the cargo
1306
 
         * XXX - Think of something better to
1307
 
         *       1) Only deliver to industries which are withing the catchment radius
1308
 
         *       2) Distribute between industries if more then one is present */
1309
 
        best_dist = (_patches.station_spread + 8) * 2;
1310
 
        FOR_ALL_INDUSTRIES(ind) {
1311
 
                indspec = GetIndustrySpec(ind->type);
1312
 
                uint i;
1313
 
 
1314
 
                for (i = 0; i < lengthof(ind->accepts_cargo); i++) {
1315
 
                        if (cargo_type == ind->accepts_cargo[i]) break;
1316
 
                }
1317
 
 
1318
 
                /* Check if matching cargo has been found */
1319
 
                if (i == lengthof(ind->accepts_cargo)) continue;
1320
 
 
1321
 
                if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
1322
 
                        uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
1323
 
                        if (res == 0) continue;
1324
 
                }
1325
 
 
1326
 
                uint dist = DistanceManhattan(ind->xy, xy);
1327
 
 
1328
 
                if (dist < best_dist) {
1329
 
                        best = ind;
1330
 
                        best_dist = dist;
1331
 
                        accepted_cargo_index = i;
1332
 
                }
1333
 
        }
1334
 
 
1335
 
        /* Found one? */
1336
 
        if (best != NULL) {
1337
 
                indspec = GetIndustrySpec(best->type);
1338
 
                uint16 callback = indspec->callback_flags;
1339
 
 
1340
 
                best->was_cargo_delivered = true;
1341
 
                best->last_cargo_accepted_at = _date;
1342
 
 
1343
 
                if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
1344
 
                        best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
1345
 
                        if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
1346
 
                                IndustryProductionCallback(best, 0);
1347
 
                        } else {
1348
 
                                InvalidateWindow(WC_INDUSTRY_VIEW, best->index);
1349
 
                        }
1350
 
                } else {
1351
 
                        best->produced_cargo_waiting[0] = min(best->produced_cargo_waiting[0] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][0] / 256), 0xFFFF);
1352
 
                        best->produced_cargo_waiting[1] = min(best->produced_cargo_waiting[1] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][1] / 256), 0xFFFF);
1353
 
                }
1354
 
 
1355
 
                TriggerIndustry(best, INDUSTRY_TRIGGER_RECEIVED_CARGO);
1356
 
                StartStopIndustryTileAnimation(best, IAT_INDUSTRY_RECEIVED_CARGO);
 
1176
 
 
1177
struct FindIndustryToDeliverData {
 
1178
        const Rect *rect;            ///< Station acceptance rectangle
 
1179
        CargoID cargo_type;          ///< Cargo type that was delivered
 
1180
 
 
1181
        Industry *ind;               ///< Returns found industry
 
1182
        const IndustrySpec *indspec; ///< Spec of ind
 
1183
        uint cargo_index;            ///< Index of cargo_type in acceptance list of ind
 
1184
};
 
1185
 
 
1186
static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
 
1187
{
 
1188
        FindIndustryToDeliverData *callback_data = (FindIndustryToDeliverData *)user_data;
 
1189
        const Rect *rect = callback_data->rect;
 
1190
        CargoID cargo_type = callback_data->cargo_type;
 
1191
 
 
1192
        /* Only process industry tiles */
 
1193
        if (!IsTileType(ind_tile, MP_INDUSTRY)) return false;
 
1194
 
 
1195
        /* Only process tiles in the station acceptance rectangle */
 
1196
        int x = TileX(ind_tile);
 
1197
        int y = TileY(ind_tile);
 
1198
        if (x < rect->left || x > rect->right || y < rect->top || y > rect->bottom) return false;
 
1199
 
 
1200
        Industry *ind = GetIndustryByTile(ind_tile);
 
1201
        const IndustrySpec *indspec = GetIndustrySpec(ind->type);
 
1202
 
 
1203
        uint cargo_index;
 
1204
        for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
 
1205
                if (cargo_type == ind->accepts_cargo[cargo_index]) break;
 
1206
        }
 
1207
        /* Check if matching cargo has been found */
 
1208
        if (cargo_index >= lengthof(ind->accepts_cargo)) return false;
 
1209
 
 
1210
        /* Check if industry temporarly refuses acceptance */
 
1211
        if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
 
1212
                uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
 
1213
                if (res == 0) return false;
 
1214
        }
 
1215
 
 
1216
        /* Found industry accepting the cargo */
 
1217
        callback_data->ind = ind;
 
1218
        callback_data->indspec = indspec;
 
1219
        callback_data->cargo_index = cargo_index;
 
1220
        return true;
 
1221
}
 
1222
 
 
1223
/**
 
1224
 * Transfer goods from station to industry.
 
1225
 * All cargo is delivered to the nearest (Manhattan) industry to the station sign, which is inside the acceptance rectangle and actually accepts the cargo.
 
1226
 * @param st The station that accepted the cargo
 
1227
 * @param cargo_type Type of cargo delivered
 
1228
 * @param nun_pieces Amount of cargo delivered
 
1229
 * @param industry_set The destination industry will be inserted into this set
 
1230
 */
 
1231
static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int num_pieces, SmallIndustryList *industry_set)
 
1232
{
 
1233
        if (st->rect.IsEmpty()) return;
 
1234
 
 
1235
        /* Compute acceptance rectangle */
 
1236
        int catchment_radius = st->GetCatchmentRadius();
 
1237
        Rect rect = {
 
1238
                max<int>(st->rect.left   - catchment_radius, 0),
 
1239
                max<int>(st->rect.top    - catchment_radius, 0),
 
1240
                min<int>(st->rect.right  + catchment_radius, MapMaxX()),
 
1241
                min<int>(st->rect.bottom + catchment_radius, MapMaxY())
 
1242
        };
 
1243
 
 
1244
        /* Compute maximum extent of acceptance rectangle wrt. station sign */
 
1245
        TileIndex start_tile = st->xy;
 
1246
        uint max_radius = max(
 
1247
                max(DistanceManhattan(start_tile, TileXY(rect.left , rect.top)), DistanceManhattan(start_tile, TileXY(rect.left , rect.bottom))),
 
1248
                max(DistanceManhattan(start_tile, TileXY(rect.right, rect.top)), DistanceManhattan(start_tile, TileXY(rect.right, rect.bottom)))
 
1249
        );
 
1250
 
 
1251
        FindIndustryToDeliverData callback_data;
 
1252
        callback_data.rect = &rect;
 
1253
        callback_data.cargo_type = cargo_type;
 
1254
        callback_data.ind = NULL;
 
1255
        callback_data.indspec = NULL;
 
1256
        callback_data.cargo_index = 0;
 
1257
 
 
1258
        /* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo.
 
1259
         * This fails in three cases:
 
1260
         *  1) The station accepts the cargo because there are enough houses around it accepting the cargo.
 
1261
         *  2) The industries in the catchment area temporarily reject the cargo, and the daily station loop has not yet updated station acceptance.
 
1262
         *  3) The results of callbacks CBID_INDUSTRY_REFUSE_CARGO and CBID_INDTILE_CARGO_ACCEPTANCE are inconsistent. (documented behaviour)
 
1263
         */
 
1264
        if (CircularTileSearch(&start_tile, 2 * max_radius + 1, FindIndustryToDeliver, &callback_data)) {
 
1265
                Industry *best = callback_data.ind;
 
1266
                uint accepted_cargo_index = callback_data.cargo_index;
 
1267
                assert(best != NULL);
 
1268
 
 
1269
                /* Insert the industry into industry_set, if not yet contained */
 
1270
                if (industry_set != NULL) industry_set->Include(best);
 
1271
 
 
1272
                best->incoming_cargo_waiting[accepted_cargo_index] = min(num_pieces + best->incoming_cargo_waiting[accepted_cargo_index], 0xFFFF);
1357
1273
        }
1358
1274
}
1359
1275
 
1381
1297
                        if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
1382
1298
                                xy = GetTown(s->from)->xy;
1383
1299
                        } else {
1384
 
                                xy = (GetIndustry(s->from))->xy;
 
1300
                                xy = GetIndustry(s->from)->xy;
1385
1301
                        }
1386
1302
                        if (DistanceMax(xy, from->xy) > 9) continue;
1387
1303
 
1409
1325
                        pair = SetupSubsidyDecodeParam(s, 0);
1410
1326
                        InjectDParam(1);
1411
1327
 
1412
 
                        SetDParam(0, _current_player);
 
1328
                        SetDParam(0, _current_company);
1413
1329
                        AddNewsItem(
1414
 
                                STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
1415
 
                                NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
 
1330
                                STR_2031_SERVICE_SUBSIDY_AWARDED + _settings_game.difficulty.subsidy_multiplier,
 
1331
                                NS_SUBSIDIES,
1416
1332
                                pair.a, pair.b
1417
1333
                        );
 
1334
                        AI::BroadcastNewEvent(new AIEventSubsidyAwarded(s - _subsidies));
1418
1335
 
1419
1336
                        InvalidateWindow(WC_SUBSIDIES_LIST, 0);
1420
1337
                        return true;
1423
1340
        return false;
1424
1341
}
1425
1342
 
1426
 
static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit)
 
1343
/**
 
1344
 * Delivers goods to industries/towns and calculates the payment
 
1345
 * @param num_pieces amount of cargo delivered
 
1346
 * @param source Originstation of the cargo
 
1347
 * @param dest Station the cargo has been unloaded
 
1348
 * @param source_tile The origin of the cargo for distance calculation
 
1349
 * @param days_in_transit Travel time
 
1350
 * @param industry_set The delivered industry will be inserted into this set, if not yet contained
 
1351
 * The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery
 
1352
 */
 
1353
static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit, SmallIndustryList *industry_set)
1427
1354
{
1428
1355
        bool subsidised;
1429
1356
        Station *s_from, *s_to;
1431
1358
 
1432
1359
        assert(num_pieces > 0);
1433
1360
 
1434
 
        /* Update player statistics */
 
1361
        /* Update company statistics */
1435
1362
        {
1436
 
                Player *p = GetPlayer(_current_player);
1437
 
                p->cur_economy.delivered_cargo += num_pieces;
1438
 
                SetBit(p->cargo_types, cargo_type);
 
1363
                Company *c = GetCompany(_current_company);
 
1364
                c->cur_economy.delivered_cargo += num_pieces;
 
1365
                SetBit(c->cargo_types, cargo_type);
1439
1366
        }
1440
1367
 
1441
1368
        /* Get station pointers. */
1451
1378
        if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
1452
1379
 
1453
1380
        /* Give the goods to the industry. */
1454
 
        DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
 
1381
        DeliverGoodsToIndustry(s_to, cargo_type, num_pieces, industry_set);
1455
1382
 
1456
1383
        /* Determine profit */
1457
1384
        profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
1458
1385
 
1459
1386
        /* Modify profit if a subsidy is in effect */
1460
1387
        if (subsidised) {
1461
 
                switch (_opt.diff.subsidy_multiplier) {
 
1388
                switch (_settings_game.difficulty.subsidy_multiplier) {
1462
1389
                        case 0:  profit += profit >> 1; break;
1463
1390
                        case 1:  profit *= 2; break;
1464
1391
                        case 2:  profit *= 3; break;
1470
1397
}
1471
1398
 
1472
1399
/**
 
1400
 * Inform the industry about just delivered cargo
 
1401
 * DeliverGoodsToIndustry() silently incremented incoming_cargo_waiting, now it is time to do something with the new cargo.
 
1402
 * @param i The industry to process
 
1403
 */
 
1404
static void TriggerIndustryProduction(Industry *i)
 
1405
{
 
1406
        const IndustrySpec *indspec = GetIndustrySpec(i->type);
 
1407
        uint16 callback = indspec->callback_flags;
 
1408
 
 
1409
        i->was_cargo_delivered = true;
 
1410
        i->last_cargo_accepted_at = _date;
 
1411
 
 
1412
        if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
 
1413
                if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
 
1414
                        IndustryProductionCallback(i, 0);
 
1415
                } else {
 
1416
                        InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
 
1417
                }
 
1418
        } else {
 
1419
                for (uint cargo_index = 0; cargo_index < lengthof(i->incoming_cargo_waiting); cargo_index++) {
 
1420
                        uint cargo_waiting = i->incoming_cargo_waiting[cargo_index];
 
1421
                        if (cargo_waiting == 0) continue;
 
1422
 
 
1423
                        i->produced_cargo_waiting[0] = min(i->produced_cargo_waiting[0] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][0] / 256), 0xFFFF);
 
1424
                        i->produced_cargo_waiting[1] = min(i->produced_cargo_waiting[1] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][1] / 256), 0xFFFF);
 
1425
 
 
1426
                        i->incoming_cargo_waiting[cargo_index] = 0;
 
1427
                }
 
1428
        }
 
1429
 
 
1430
        TriggerIndustry(i, INDUSTRY_TRIGGER_RECEIVED_CARGO);
 
1431
        StartStopIndustryTileAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO);
 
1432
}
 
1433
 
 
1434
/**
1473
1435
 * Performs the vehicle payment _and_ marks the vehicle to be unloaded.
1474
1436
 * @param front_v the vehicle to be unloaded
1475
1437
 */
1485
1447
        Station *st = GetStation(last_visited);
1486
1448
 
1487
1449
        /* The owner of the train wants to be paid */
1488
 
        PlayerID old_player = _current_player;
1489
 
        _current_player = front_v->owner;
 
1450
        CompanyID old_company = _current_company;
 
1451
        _current_company = front_v->owner;
1490
1452
 
1491
1453
        /* At this moment loading cannot be finished */
1492
1454
        ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED);
1494
1456
        /* Start unloading in at the first possible moment */
1495
1457
        front_v->load_unload_time_rem = 1;
1496
1458
 
 
1459
        /* Collect delivered industries */
 
1460
        static SmallIndustryList industry_set;
 
1461
        industry_set.Clear();
 
1462
 
1497
1463
        for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
1498
1464
                /* No cargo to unload */
1499
 
                if (v->cargo_cap == 0 || v->cargo.Empty()) continue;
 
1465
                if (v->cargo_cap == 0 || v->cargo.Empty() || front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) continue;
1500
1466
 
1501
1467
                /* All cargo has already been paid for, no need to pay again */
1502
1468
                if (!v->cargo.UnpaidCargo()) {
1512
1478
                        if (!cp->paid_for &&
1513
1479
                                        cp->source != last_visited &&
1514
1480
                                        HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) &&
1515
 
                                        (front_v->current_order.flags & OFB_TRANSFER) == 0) {
 
1481
                                        (front_v->current_order.GetUnloadType() & OUFB_TRANSFER) == 0) {
1516
1482
                                /* Deliver goods to the station */
1517
1483
                                st->time_since_unload = 0;
1518
1484
 
1519
1485
                                /* handle end of route payment */
1520
 
                                Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit);
 
1486
                                Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit, &industry_set);
1521
1487
                                cp->paid_for = true;
1522
1488
                                route_profit   += profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
1523
1489
                                vehicle_profit += profit - cp->feeder_share;                    // whole vehicle is not payed for transfers picked up earlier
1525
1491
                                result |= 1;
1526
1492
 
1527
1493
                                SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
1528
 
                        } else if (front_v->current_order.flags & (OFB_UNLOAD | OFB_TRANSFER)) {
1529
 
                                if (!cp->paid_for && (front_v->current_order.flags & OFB_TRANSFER) != 0) {
 
1494
                        } else if (front_v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
1495
                                if (!cp->paid_for && (front_v->current_order.GetUnloadType() & OUFB_TRANSFER) != 0) {
1530
1496
                                        Money profit = GetTransportedGoodsIncome(
1531
1497
                                                cp->count,
1532
1498
                                                /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
1547
1513
                v->cargo.InvalidateCache();
1548
1514
        }
1549
1515
 
 
1516
        /* Call the production machinery of industries only once for every vehicle chain */
 
1517
        const Industry * const *isend = industry_set.End();
 
1518
        for (Industry **iid = industry_set.Begin(); iid != isend; iid++) {
 
1519
                TriggerIndustryProduction(*iid);
 
1520
        }
 
1521
 
1550
1522
        if (virtual_profit > 0) {
1551
1523
                ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
1552
1524
        }
1553
1525
 
1554
1526
        if (route_profit != 0) {
1555
1527
                front_v->profit_this_year += vehicle_profit << 8;
1556
 
                SubtractMoneyFromPlayer(CommandCost(front_v->GetExpenseType(true), -route_profit));
 
1528
                SubtractMoneyFromCompany(CommandCost(front_v->GetExpenseType(true), -route_profit));
1557
1529
 
1558
 
                if (IsLocalPlayer() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
 
1530
                if (IsLocalCompany() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
1559
1531
                        SndPlayVehicleFx(SND_14_CASHTILL, front_v);
1560
1532
                }
1561
1533
 
1562
1534
                ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -vehicle_profit);
1563
1535
        }
1564
1536
 
1565
 
        _current_player = old_player;
 
1537
        _current_company = old_company;
1566
1538
}
1567
1539
 
1568
1540
/**
1575
1547
 */
1576
1548
static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
1577
1549
{
1578
 
        assert(v->current_order.type == OT_LOADING);
 
1550
        assert(v->current_order.IsType(OT_LOADING));
1579
1551
 
1580
1552
        /* We have not waited enough time till the next round of loading/unloading */
1581
1553
        if (--v->load_unload_time_rem != 0) {
1582
 
                if (_patches.improved_load && HasBit(v->current_order.flags, OF_FULL_LOAD)) {
 
1554
                if (_settings_game.order.improved_load && (v->current_order.GetLoadType() & OLFB_FULL_LOAD)) {
1583
1555
                        /* 'Reserve' this cargo for this vehicle, because we were first. */
1584
1556
                        for (; v != NULL; v = v->Next()) {
1585
 
                                if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
 
1557
                                int cap_left = v->cargo_cap - v->cargo.Count();
 
1558
                                if (cap_left > 0) cargo_left[v->cargo_type] -= cap_left;
1586
1559
                        }
1587
1560
                }
1588
1561
                return;
1601
1574
        int unloading_time = 0;
1602
1575
        Vehicle *u = v;
1603
1576
        int result = 0;
1604
 
        uint cap;
1605
1577
 
1606
1578
        bool completely_emptied = true;
1607
1579
        bool anything_unloaded = false;
1615
1587
                if (v->cargo_cap == 0) continue;
1616
1588
 
1617
1589
                byte load_amount = EngInfo(v->engine_type)->load_amount;
1618
 
                if (_patches.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) {
 
1590
 
 
1591
                /* The default loadamount for mail is 1/4 of the load amount for passengers */
 
1592
                if (v->type == VEH_AIRCRAFT && !IsNormalAircraft(v)) load_amount = (load_amount + 3) / 4;
 
1593
 
 
1594
                if (_settings_game.order.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) {
1619
1595
                        uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
1620
1596
                        if (cb_load_amount != CALLBACK_FAILED && GB(cb_load_amount, 0, 8) != 0) load_amount = GB(cb_load_amount, 0, 8);
1621
1597
                }
1622
1598
 
1623
1599
                GoodsEntry *ge = &st->goods[v->cargo_type];
1624
1600
 
1625
 
                if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING)) {
 
1601
                if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) && (u->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
1626
1602
                        uint cargo_count = v->cargo.Count();
1627
 
                        uint amount_unloaded = _patches.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
1628
 
                        bool remaining; // Are there cargo entities in this vehicle that can still be unloaded here?
 
1603
                        uint amount_unloaded = _settings_game.order.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
 
1604
                        bool remaining = false; // Are there cargo entities in this vehicle that can still be unloaded here?
 
1605
                        bool accepted  = false; // Is the cargo accepted by the station?
1629
1606
 
1630
 
                        if (HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) && !(u->current_order.flags & OFB_TRANSFER)) {
 
1607
                        if (HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) && !(u->current_order.GetUnloadType() & OUFB_TRANSFER)) {
1631
1608
                                /* The cargo has reached it's final destination, the packets may now be destroyed */
1632
1609
                                remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, last_visited);
1633
1610
 
1634
1611
                                result |= 1;
1635
 
                        } else if (u->current_order.flags & (OFB_UNLOAD | OFB_TRANSFER)) {
 
1612
                                accepted = true;
 
1613
                        }
 
1614
 
 
1615
                        /* The !accepted || v->cargo.Count == cargo_count clause is there
 
1616
                         * to make it possible to force unload vehicles at the station where
 
1617
                         * they were loaded, but to not force unload the vehicle when the
 
1618
                         * station is still accepting the cargo in the vehicle. It doesn't
 
1619
                         * accept cargo that was loaded at the same station. */
 
1620
                        if (u->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER) && (!accepted || v->cargo.Count() == cargo_count)) {
1636
1621
                                remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
1637
1622
                                SetBit(ge->acceptance_pickup, GoodsEntry::PICKUP);
1638
1623
 
1639
1624
                                result |= 2;
1640
 
                        } else {
 
1625
                        } else if (!accepted) {
1641
1626
                                /* The order changed while unloading (unset unload/transfer) or the
1642
1627
                                 * station does not accept goods anymore. */
1643
1628
                                ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
1650
1635
                        unloading_time += amount_unloaded;
1651
1636
 
1652
1637
                        anything_unloaded = true;
1653
 
                        if (_patches.gradual_loading && remaining) {
 
1638
                        if (_settings_game.order.gradual_loading && remaining) {
1654
1639
                                completely_emptied = false;
1655
1640
                        } else {
1656
1641
                                /* We have finished unloading (cargo count == 0) */
1660
1645
                        continue;
1661
1646
                }
1662
1647
 
1663
 
                /* Do not pick up goods that we unloaded */
1664
 
                if (u->current_order.flags & OFB_UNLOAD) continue;
 
1648
                /* Do not pick up goods when we have no-load set. */
 
1649
                if (u->current_order.GetLoadType() & OLFB_NO_LOAD) continue;
1665
1650
 
1666
1651
                /* update stats */
1667
1652
                int t;
1678
1663
 
1679
1664
                /* If there's goods waiting at the station, and the vehicle
1680
1665
                 * has capacity for it, load it on the vehicle. */
1681
 
                if (!ge->cargo.Empty() &&
1682
 
                                (cap = v->cargo_cap - v->cargo.Count()) != 0) {
 
1666
                int cap_left = v->cargo_cap - v->cargo.Count();
 
1667
                if (!ge->cargo.Empty() && cap_left > 0) {
 
1668
                        uint cap = cap_left;
1683
1669
                        uint count = ge->cargo.Count();
1684
1670
 
1685
1671
                        /* Skip loading this vehicle if another train/vehicle is already handling
1686
1672
                         * the same cargo type at this station */
1687
 
                        if (_patches.improved_load && cargo_left[v->cargo_type] <= 0) {
 
1673
                        if (_settings_game.order.improved_load && cargo_left[v->cargo_type] <= 0) {
1688
1674
                                SetBit(cargo_not_full, v->cargo_type);
1689
1675
                                continue;
1690
1676
                        }
1691
1677
 
1692
1678
                        if (cap > count) cap = count;
1693
 
                        if (_patches.gradual_loading) cap = min(cap, load_amount);
1694
 
                        if (_patches.improved_load) {
 
1679
                        if (_settings_game.order.gradual_loading) cap = min(cap, load_amount);
 
1680
                        if (_settings_game.order.improved_load) {
1695
1681
                                /* Don't load stuff that is already 'reserved' for other vehicles */
1696
1682
                                cap = min((uint)cargo_left[v->cargo_type], cap);
1697
1683
                                cargo_left[v->cargo_type] -= cap;
1714
1700
                        st->time_since_load = 0;
1715
1701
                        st->last_vehicle_type = v->type;
1716
1702
 
 
1703
                        StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type);
 
1704
 
1717
1705
                        unloading_time += cap;
1718
1706
 
1719
1707
                        result |= 2;
1720
1708
                }
1721
1709
 
1722
 
                if (v->cargo.Count() == v->cargo_cap) {
 
1710
                if (v->cargo.Count() >= v->cargo_cap) {
1723
1711
                        SetBit(cargo_full, v->cargo_type);
1724
1712
                } else {
1725
1713
                        SetBit(cargo_not_full, v->cargo_type);
1733
1721
         * all wagons at the same time instead of using the same 'improved'
1734
1722
         * loading algorithm for the wagons (only fill wagon when there is
1735
1723
         * enough to fill the previous wagons) */
1736
 
        if (_patches.improved_load && HasBit(u->current_order.flags, OF_FULL_LOAD)) {
 
1724
        if (_settings_game.order.improved_load && (u->current_order.GetLoadType() & OLFB_FULL_LOAD)) {
1737
1725
                /* Update left cargo */
1738
1726
                for (v = u; v != NULL; v = v->Next()) {
1739
 
                        if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
 
1727
                        int cap_left = v->cargo_cap - v->cargo.Count();
 
1728
                        if (cap_left > 0) cargo_left[v->cargo_type] -= cap_left;
1740
1729
                }
1741
1730
        }
1742
1731
 
1743
1732
        v = u;
1744
1733
 
1745
1734
        if (anything_loaded || anything_unloaded) {
1746
 
                if (_patches.gradual_loading) {
 
1735
                if (_settings_game.order.gradual_loading) {
1747
1736
                        /* The time it takes to load one 'slice' of cargo or passengers depends
1748
 
                        * on the vehicle type - the values here are those found in TTDPatch */
 
1737
                         * on the vehicle type - the values here are those found in TTDPatch */
1749
1738
                        const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
1750
1739
 
1751
1740
                        unloading_time = gradual_loading_wait_time[v->type];
1752
1741
                }
1753
1742
        } else {
1754
1743
                bool finished_loading = true;
1755
 
                if (HasBit(v->current_order.flags, OF_FULL_LOAD)) {
1756
 
                        if (_patches.full_load_any) {
 
1744
                if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) {
 
1745
                        if (v->current_order.GetLoadType() == OLF_FULL_LOAD_ANY) {
1757
1746
                                /* if the aircraft carries passengers and is NOT full, then
1758
1747
                                 * continue loading, no matter how much mail is in */
1759
 
                                if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo.Count()) ||
 
1748
                                if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap > v->cargo.Count()) ||
1760
1749
                                                (cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
1761
1750
                                        finished_loading = false;
1762
1751
                                }
1780
1769
 
1781
1770
        /* Calculate the loading indicator fill percent and display
1782
1771
         * In the Game Menu do not display indicators
1783
 
         * If _patches.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 )
1784
 
         * if _patches.loading_indicators == 1, _local_player must be the owner or must be a spectator to show ind., so 1 > 0
1785
 
         * if _patches.loading_indicators == 0, do not display indicators ... 0 is never greater than anything
 
1772
         * If _settings_client.gui.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 )
 
1773
         * if _settings_client.gui.loading_indicators == 1, _local_company must be the owner or must be a spectator to show ind., so 1 > 0
 
1774
         * if _settings_client.gui.loading_indicators == 0, do not display indicators ... 0 is never greater than anything
1786
1775
         */
1787
 
        if (_game_mode != GM_MENU && (_patches.loading_indicators > (uint)(v->owner != _local_player && _local_player != PLAYER_SPECTATOR))) {
 
1776
        if (_game_mode != GM_MENU && (_settings_client.gui.loading_indicators > (uint)(v->owner != _local_company && _local_company != COMPANY_SPECTATOR))) {
1788
1777
                StringID percent_up_down = STR_NULL;
1789
1778
                int percent = CalcPercentVehicleFilled(v, &percent_up_down);
1790
1779
                if (v->fill_percent_te_id == INVALID_TE_ID) {
1801
1790
        }
1802
1791
 
1803
1792
        if (result != 0) {
1804
 
                InvalidateWindow(v->GetVehicleListWindowClass(), v->owner);
 
1793
                InvalidateWindow(GetWindowClassForVehicleType(v->type), v->owner);
1805
1794
                InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
1806
1795
 
1807
1796
                st->MarkTilesDirty(true);
1829
1818
        }
1830
1819
}
1831
1820
 
1832
 
void PlayersMonthlyLoop()
 
1821
void CompaniesMonthlyLoop()
1833
1822
{
1834
 
        PlayersGenStatistics();
1835
 
        if (_patches.inflation && _cur_year < MAX_YEAR)
1836
 
                AddInflation();
1837
 
        PlayersPayInterest();
1838
 
        /* Reset the _current_player flag */
1839
 
        _current_player = OWNER_NONE;
 
1823
        CompaniesGenStatistics();
 
1824
        if (_settings_game.economy.inflation) AddInflation();
 
1825
        CompaniesPayInterest();
 
1826
        /* Reset the _current_company flag */
 
1827
        _current_company = OWNER_NONE;
1840
1828
        HandleEconomyFluctuations();
1841
1829
        SubsidyMonthlyHandler();
1842
1830
}
1843
1831
 
1844
 
static void DoAcquireCompany(Player *p)
 
1832
static void DoAcquireCompany(Company *c)
1845
1833
{
1846
 
        Player *owner;
 
1834
        Company *owner;
1847
1835
        int i;
1848
1836
        Money value;
1849
 
 
1850
 
        SetDParam(0, p->index);
1851
 
        SetDParam(1, p->bankrupt_value);
1852
 
        AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 
1837
        CompanyID ci = c->index;
 
1838
 
 
1839
        CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
 
1840
        cni->FillData(c, GetCompany(_current_company));
 
1841
 
 
1842
        SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
 
1843
        SetDParam(1, c->bankrupt_value == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
 
1844
        SetDParamStr(2, cni->company_name);
 
1845
        SetDParamStr(3, cni->other_company_name);
 
1846
        SetDParam(4, c->bankrupt_value);
 
1847
        AddNewsItem(STR_02B6, NS_COMPANY_MERGER, 0, 0, cni);
 
1848
        AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
1853
1849
 
1854
1850
        /* original code does this a little bit differently */
1855
 
        PlayerID pi = p->index;
1856
 
        ChangeNetworkOwner(pi, _current_player);
1857
 
        ChangeOwnershipOfPlayerItems(pi, _current_player);
 
1851
        ChangeNetworkOwner(ci, _current_company);
 
1852
        ChangeOwnershipOfCompanyItems(ci, _current_company);
1858
1853
 
1859
 
        if (p->bankrupt_value == 0) {
1860
 
                owner = GetPlayer(_current_player);
1861
 
                owner->current_loan += p->current_loan;
 
1854
        if (c->bankrupt_value == 0) {
 
1855
                owner = GetCompany(_current_company);
 
1856
                owner->current_loan += c->current_loan;
1862
1857
        }
1863
1858
 
1864
 
        value = CalculateCompanyValue(p) >> 2;
1865
 
        PlayerID old_player = _current_player;
 
1859
        value = CalculateCompanyValue(c) >> 2;
 
1860
        CompanyID old_company = _current_company;
1866
1861
        for (i = 0; i != 4; i++) {
1867
 
                if (p->share_owners[i] != PLAYER_SPECTATOR) {
1868
 
                        _current_player = p->share_owners[i];
1869
 
                        SubtractMoneyFromPlayer(CommandCost(EXPENSES_OTHER, -value));
 
1862
                if (c->share_owners[i] != COMPANY_SPECTATOR) {
 
1863
                        _current_company = c->share_owners[i];
 
1864
                        SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -value));
1870
1865
                }
1871
1866
        }
1872
 
        _current_player = old_player;
1873
 
 
1874
 
        p->is_active = false;
1875
 
 
1876
 
        DeletePlayerWindows(pi);
1877
 
        RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
 
1867
        _current_company = old_company;
 
1868
 
 
1869
        if (!IsHumanCompany(c->index)) AI::Stop(c->index);
 
1870
 
 
1871
        DeleteCompanyWindows(ci);
 
1872
        InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
1873
        InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 
1874
        InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
1875
        InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 
1876
 
 
1877
        delete c;
1878
1878
}
1879
1879
 
1880
 
extern int GetAmountOwnedBy(const Player *p, PlayerID owner);
 
1880
extern int GetAmountOwnedBy(const Company *c, Owner owner);
1881
1881
 
1882
1882
/** Acquire shares in an opposing company.
1883
1883
 * @param tile unused
1884
1884
 * @param flags type of operation
1885
 
 * @param p1 player to buy the shares from
 
1885
 * @param p1 company to buy the shares from
1886
1886
 * @param p2 unused
1887
1887
 */
1888
 
CommandCost CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
1888
CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1889
1889
{
1890
 
        Player *p;
1891
1890
        CommandCost cost(EXPENSES_OTHER);
1892
1891
 
1893
 
        /* Check if buying shares is allowed (protection against modified clients) */
1894
 
        /* Cannot buy own shares */
1895
 
        if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR;
1896
 
 
1897
 
        p = GetPlayer((PlayerID)p1);
1898
 
 
1899
 
        /* Cannot buy shares of non-existent nor bankrupted company */
1900
 
        if (!p->is_active) return CMD_ERROR;
 
1892
        /* Check if buying shares is allowed (protection against modified clients)
 
1893
         * Cannot buy own shares */
 
1894
        if (!IsValidCompanyID((CompanyID)p1) || !_settings_game.economy.allow_shares || _current_company == (CompanyID)p1) return CMD_ERROR;
 
1895
 
 
1896
        Company *c = GetCompany((CompanyID)p1);
1901
1897
 
1902
1898
        /* Protect new companies from hostile takeovers */
1903
 
        if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_PROTECTED);
 
1899
        if (_cur_year - c->inaugurated_year < 6) return_cmd_error(STR_PROTECTED);
1904
1900
 
1905
1901
        /* Those lines are here for network-protection (clients can be slow) */
1906
 
        if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return cost;
1907
 
 
1908
 
        /* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
1909
 
        if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return cost;
1910
 
 
1911
 
        cost.AddCost(CalculateCompanyValue(p) >> 2);
 
1902
        if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 0) return cost;
 
1903
 
 
1904
        /* We can not buy out a real company (temporarily). TODO: well, enable it obviously */
 
1905
        if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 1 && !c->is_ai) return cost;
 
1906
 
 
1907
        cost.AddCost(CalculateCompanyValue(c) >> 2);
1912
1908
        if (flags & DC_EXEC) {
1913
 
                PlayerByte* b = p->share_owners;
 
1909
                OwnerByte *b = c->share_owners;
1914
1910
                int i;
1915
1911
 
1916
 
                while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
1917
 
                *b = _current_player;
 
1912
                while (*b != COMPANY_SPECTATOR) b++; // share owners is guaranteed to contain at least one COMPANY_SPECTATOR
 
1913
                *b = _current_company;
1918
1914
 
1919
 
                for (i = 0; p->share_owners[i] == _current_player;) {
 
1915
                for (i = 0; c->share_owners[i] == _current_company;) {
1920
1916
                        if (++i == 4) {
1921
 
                                p->bankrupt_value = 0;
1922
 
                                DoAcquireCompany(p);
 
1917
                                c->bankrupt_value = 0;
 
1918
                                DoAcquireCompany(c);
1923
1919
                                break;
1924
1920
                        }
1925
1921
                }
1931
1927
/** Sell shares in an opposing company.
1932
1928
 * @param tile unused
1933
1929
 * @param flags type of operation
1934
 
 * @param p1 player to sell the shares from
 
1930
 * @param p1 company to sell the shares from
1935
1931
 * @param p2 unused
1936
1932
 */
1937
 
CommandCost CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
1933
CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1938
1934
{
1939
 
        Player *p;
1940
 
        Money cost;
1941
 
 
1942
 
        /* Check if selling shares is allowed (protection against modified clients) */
1943
 
        /* Cannot sell own shares */
1944
 
        if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares || _current_player == (PlayerID)p1) return CMD_ERROR;
1945
 
 
1946
 
        p = GetPlayer((PlayerID)p1);
1947
 
 
1948
 
        /* Cannot sell shares of non-existent nor bankrupted company */
1949
 
        if (!p->is_active) return CMD_ERROR;
 
1935
        /* Check if selling shares is allowed (protection against modified clients)
 
1936
         * Cannot sell own shares */
 
1937
        if (!IsValidCompanyID((CompanyID)p1) || !_settings_game.economy.allow_shares || _current_company == (CompanyID)p1) return CMD_ERROR;
 
1938
 
 
1939
        Company *c = GetCompany((CompanyID)p1);
1950
1940
 
1951
1941
        /* Those lines are here for network-protection (clients can be slow) */
1952
 
        if (GetAmountOwnedBy(p, _current_player) == 0) return CommandCost();
 
1942
        if (GetAmountOwnedBy(c, _current_company) == 0) return CommandCost();
1953
1943
 
1954
1944
        /* adjust it a little to make it less profitable to sell and buy */
1955
 
        cost = CalculateCompanyValue(p) >> 2;
 
1945
        Money cost = CalculateCompanyValue(c) >> 2;
1956
1946
        cost = -(cost - (cost >> 7));
1957
1947
 
1958
1948
        if (flags & DC_EXEC) {
1959
 
                PlayerByte* b = p->share_owners;
1960
 
                while (*b != _current_player) b++; // share owners is guaranteed to contain player
1961
 
                *b = PLAYER_SPECTATOR;
 
1949
                OwnerByte *b = c->share_owners;
 
1950
                while (*b != _current_company) b++; // share owners is guaranteed to contain company
 
1951
                *b = COMPANY_SPECTATOR;
1962
1952
                InvalidateWindow(WC_COMPANY, p1);
1963
1953
        }
1964
1954
        return CommandCost(EXPENSES_OTHER, cost);
1967
1957
/** Buy up another company.
1968
1958
 * When a competing company is gone bankrupt you get the chance to purchase
1969
1959
 * that company.
1970
 
 * @todo currently this only works for AI players
 
1960
 * @todo currently this only works for AI companies
1971
1961
 * @param tile unused
1972
1962
 * @param flags type of operation
1973
 
 * @param p1 player/company to buy up
 
1963
 * @param p1 company to buy up
1974
1964
 * @param p2 unused
1975
1965
 */
1976
 
CommandCost CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
1966
CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1977
1967
{
1978
 
        Player *p;
1979
 
        PlayerID pid = (PlayerID)p1;
 
1968
        CompanyID cid = (CompanyID)p1;
1980
1969
 
1981
1970
        /* Disable takeovers in multiplayer games */
1982
 
        if (!IsValidPlayer(pid) || _networking) return CMD_ERROR;
1983
 
 
1984
 
        /* Do not allow players to take over themselves */
1985
 
        if (pid == _current_player) return CMD_ERROR;
1986
 
 
1987
 
        p = GetPlayer(pid);
1988
 
 
1989
 
        if (!p->is_ai) return CMD_ERROR;
 
1971
        if (!IsValidCompanyID(cid) || _networking) return CMD_ERROR;
 
1972
 
 
1973
        /* Do not allow companies to take over themselves */
 
1974
        if (cid == _current_company) return CMD_ERROR;
 
1975
 
 
1976
        Company *c = GetCompany(cid);
 
1977
 
 
1978
        if (!c->is_ai) return CMD_ERROR;
1990
1979
 
1991
1980
        if (flags & DC_EXEC) {
1992
 
                DoAcquireCompany(p);
 
1981
                DoAcquireCompany(c);
1993
1982
        }
1994
 
        return CommandCost(EXPENSES_OTHER, p->bankrupt_value);
1995
 
}
1996
 
 
1997
 
/** Prices */
1998
 
static void SaveLoad_PRIC()
1999
 
{
2000
 
        int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
2001
 
        SlArray(&_price,      NUM_PRICES, vt);
2002
 
        SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
2003
 
}
2004
 
 
2005
 
/** Cargo payment rates */
2006
 
static void SaveLoad_CAPR()
2007
 
{
2008
 
        uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
2009
 
        int vt = CheckSavegameVersion(65) ? (SLE_FILE_I32 | SLE_VAR_I64) : SLE_INT64;
2010
 
        SlArray(&_cargo_payment_rates,      num_cargo, vt);
2011
 
        SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
2012
 
}
2013
 
 
2014
 
static const SaveLoad _economy_desc[] = {
2015
 
        SLE_CONDVAR(Economy, max_loan,         SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
2016
 
        SLE_CONDVAR(Economy, max_loan,         SLE_INT64,                  65, SL_MAX_VERSION),
2017
 
        SLE_CONDVAR(Economy, max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64,  0, 64),
2018
 
        SLE_CONDVAR(Economy, max_loan_unround, SLE_INT64,                  65, SL_MAX_VERSION),
2019
 
        SLE_CONDVAR(Economy, max_loan_unround_fract, SLE_UINT16,           70, SL_MAX_VERSION),
2020
 
            SLE_VAR(Economy, fluct,            SLE_INT16),
2021
 
            SLE_VAR(Economy, interest_rate,    SLE_UINT8),
2022
 
            SLE_VAR(Economy, infl_amount,      SLE_UINT8),
2023
 
            SLE_VAR(Economy, infl_amount_pr,   SLE_UINT8),
2024
 
            SLE_END()
2025
 
};
2026
 
 
2027
 
/** Economy variables */
2028
 
static void SaveLoad_ECMY()
2029
 
{
2030
 
        SlObject(&_economy, _economy_desc);
2031
 
}
2032
 
 
2033
 
extern const ChunkHandler _economy_chunk_handlers[] = {
2034
 
        { 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
2035
 
        { 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
2036
 
        { 'SUBS', Save_SUBS,     Load_SUBS,     CH_ARRAY},
2037
 
        { 'ECMY', SaveLoad_ECMY, SaveLoad_ECMY, CH_RIFF | CH_LAST},
2038
 
};
 
1983
        return CommandCost(EXPENSES_OTHER, c->bankrupt_value);
 
1984
}