2005-07-24 14:12:37 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/** @file economy.cpp */
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
#include "stdafx.h"
|
2005-06-02 19:30:21 +00:00
|
|
|
#include "openttd.h"
|
2005-08-06 14:59:54 +00:00
|
|
|
#include "currency.h"
|
2005-07-22 07:02:20 +00:00
|
|
|
#include "functions.h"
|
2007-04-12 13:07:15 +00:00
|
|
|
#include "landscape.h"
|
2005-02-06 08:18:00 +00:00
|
|
|
#include "strings.h" // XXX InjectDParam()
|
2004-11-25 10:47:30 +00:00
|
|
|
#include "table/strings.h"
|
2005-07-28 09:17:32 +00:00
|
|
|
#include "table/sprites.h"
|
2004-12-15 22:18:54 +00:00
|
|
|
#include "map.h"
|
2004-08-09 17:04:08 +00:00
|
|
|
#include "news.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "station.h"
|
|
|
|
#include "vehicle.h"
|
|
|
|
#include "window.h"
|
|
|
|
#include "gfx.h"
|
|
|
|
#include "command.h"
|
|
|
|
#include "saveload.h"
|
|
|
|
#include "economy.h"
|
|
|
|
#include "industry.h"
|
|
|
|
#include "town.h"
|
2007-01-02 17:34:03 +00:00
|
|
|
#include "network/network.h"
|
2004-11-05 23:12:33 +00:00
|
|
|
#include "sound.h"
|
2004-11-17 08:52:47 +00:00
|
|
|
#include "engine.h"
|
2007-01-02 17:34:03 +00:00
|
|
|
#include "network/network_data.h"
|
2005-07-21 22:15:02 +00:00
|
|
|
#include "variables.h"
|
|
|
|
#include "vehicle_gui.h"
|
2005-09-07 15:10:11 +00:00
|
|
|
#include "ai/ai.h"
|
2005-11-18 23:41:03 +00:00
|
|
|
#include "train.h"
|
2007-01-27 12:29:55 +00:00
|
|
|
#include "aircraft.h"
|
2006-02-03 12:55:21 +00:00
|
|
|
#include "newgrf_engine.h"
|
2006-10-01 17:56:38 +00:00
|
|
|
#include "newgrf_sound.h"
|
2006-12-02 16:56:32 +00:00
|
|
|
#include "newgrf_callbacks.h"
|
2006-03-31 08:59:19 +00:00
|
|
|
#include "unmovable.h"
|
2006-08-14 14:21:15 +00:00
|
|
|
#include "date.h"
|
2007-02-20 22:09:21 +00:00
|
|
|
#include "cargotype.h"
|
2007-03-02 01:17:11 +00:00
|
|
|
#include "player_face.h"
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Score info */
|
2005-08-01 16:31:19 +00:00
|
|
|
const ScoreInfo _score_info[] = {
|
2006-06-27 21:25:53 +00:00
|
|
|
{ SCORE_VEHICLES, 120, 100 },
|
|
|
|
{ SCORE_STATIONS, 80, 100 },
|
|
|
|
{ SCORE_MIN_PROFIT, 10000, 100 },
|
|
|
|
{ SCORE_MIN_INCOME, 50000, 50 },
|
|
|
|
{ SCORE_MAX_INCOME, 100000, 100 },
|
|
|
|
{ SCORE_DELIVERED, 40000, 400 },
|
|
|
|
{ SCORE_CARGO, 8, 50 },
|
|
|
|
{ SCORE_MONEY, 10000000, 50 },
|
|
|
|
{ SCORE_LOAN, 250000, 50 },
|
|
|
|
{ SCORE_TOTAL, 0, 0 }
|
2005-08-01 16:31:19 +00:00
|
|
|
};
|
|
|
|
|
2007-01-10 18:56:51 +00:00
|
|
|
int _score_part[MAX_PLAYERS][SCORE_END];
|
2005-08-01 16:31:19 +00:00
|
|
|
|
2005-11-14 19:48:04 +00:00
|
|
|
int64 CalculateCompanyValue(const Player* p)
|
2005-09-30 20:37:25 +00:00
|
|
|
{
|
|
|
|
PlayerID owner = p->index;
|
2004-09-11 09:40:19 +00:00
|
|
|
int64 value;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Station *st;
|
|
|
|
uint num = 0;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
FOR_ALL_STATIONS(st) {
|
2006-08-22 15:33:35 +00:00
|
|
|
if (st->owner == owner) {
|
2004-08-09 17:04:08 +00:00
|
|
|
uint facil = st->facilities;
|
|
|
|
do num += (facil&1); while (facil >>= 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
value = num * _price.station_value * 25;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Vehicle *v;
|
|
|
|
|
|
|
|
FOR_ALL_VEHICLES(v) {
|
2006-08-22 15:33:35 +00:00
|
|
|
if (v->owner != owner) continue;
|
|
|
|
|
2007-03-08 16:27:54 +00:00
|
|
|
if (v->type == VEH_TRAIN ||
|
|
|
|
v->type == VEH_ROAD ||
|
|
|
|
(v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) ||
|
|
|
|
v->type == VEH_SHIP) {
|
2004-08-09 17:04:08 +00:00
|
|
|
value += v->value * 3 >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-13 09:55:32 +00:00
|
|
|
value += p->money64 - p->current_loan; // add real money value
|
2005-01-15 08:58:31 +00:00
|
|
|
|
2007-01-11 11:05:01 +00:00
|
|
|
return max(value, 1LL);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/** if update is set to true, the economy is updated with this score
|
|
|
|
* (also the house is updated, should only be true in the on-tick event)
|
|
|
|
* @param update the economy with calculated score
|
|
|
|
* @param p player been evaluated
|
|
|
|
* @return actual score of this player
|
|
|
|
* */
|
2004-09-01 21:54:12 +00:00
|
|
|
int UpdateCompanyRatingAndValue(Player *p, bool update)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
byte owner = p->index;
|
2004-08-23 10:59:03 +00:00
|
|
|
int score = 0;
|
|
|
|
|
|
|
|
memset(_score_part[owner], 0, sizeof(_score_part[owner]));
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
/* Count vehicles */
|
|
|
|
{
|
|
|
|
Vehicle *v;
|
2006-01-06 22:16:17 +00:00
|
|
|
int32 min_profit = 0;
|
|
|
|
bool min_profit_first = true;
|
2004-08-09 17:04:08 +00:00
|
|
|
uint num = 0;
|
|
|
|
|
|
|
|
FOR_ALL_VEHICLES(v) {
|
2006-06-27 21:25:53 +00:00
|
|
|
if (v->owner != owner) continue;
|
2007-03-08 16:27:54 +00:00
|
|
|
if ((v->type == VEH_TRAIN && IsFrontEngine(v)) ||
|
|
|
|
v->type == VEH_ROAD ||
|
|
|
|
(v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) ||
|
|
|
|
v->type == VEH_SHIP) {
|
2004-08-09 17:04:08 +00:00
|
|
|
num++;
|
|
|
|
if (v->age > 730) {
|
2006-01-06 22:16:17 +00:00
|
|
|
/* Find the vehicle with the lowest amount of profit */
|
|
|
|
if (min_profit_first == true) {
|
|
|
|
min_profit = v->profit_last_year;
|
|
|
|
min_profit_first = false;
|
2006-06-27 21:25:53 +00:00
|
|
|
} else if (min_profit > v->profit_last_year) {
|
2004-08-09 17:04:08 +00:00
|
|
|
min_profit = v->profit_last_year;
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_VEHICLES] = num;
|
2006-01-06 22:16:17 +00:00
|
|
|
/* Don't allow negative min_profit to show */
|
2005-02-23 14:12:32 +00:00
|
|
|
if (min_profit > 0)
|
|
|
|
_score_part[owner][SCORE_MIN_PROFIT] = min_profit;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Count stations */
|
|
|
|
{
|
|
|
|
uint num = 0;
|
2006-02-18 14:41:24 +00:00
|
|
|
const Station* st;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
FOR_ALL_STATIONS(st) {
|
2006-08-22 15:33:35 +00:00
|
|
|
if (st->owner == owner) {
|
2004-08-09 17:04:08 +00:00
|
|
|
int facil = st->facilities;
|
|
|
|
do num += facil&1; while (facil>>=1);
|
|
|
|
}
|
|
|
|
}
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_STATIONS] = num;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate statistics depending on recent income statistics */
|
|
|
|
{
|
2006-02-18 14:41:24 +00:00
|
|
|
const PlayerEconomyEntry* pee;
|
2004-08-09 17:04:08 +00:00
|
|
|
int numec;
|
|
|
|
int32 min_income;
|
2004-12-04 17:54:56 +00:00
|
|
|
int32 max_income;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
numec = min(p->num_valid_stat_ent, 12);
|
|
|
|
if (numec != 0) {
|
|
|
|
min_income = 0x7FFFFFFF;
|
|
|
|
max_income = 0;
|
|
|
|
pee = p->old_economy;
|
|
|
|
do {
|
|
|
|
min_income = min(min_income, pee->income + pee->expenses);
|
|
|
|
max_income = max(max_income, pee->income + pee->expenses);
|
|
|
|
} while (++pee,--numec);
|
|
|
|
|
|
|
|
if (min_income > 0)
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_MIN_INCOME] = min_income;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_MAX_INCOME] = max_income;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate score depending on amount of transported cargo */
|
|
|
|
{
|
2006-02-18 14:41:24 +00:00
|
|
|
const PlayerEconomyEntry* pee;
|
2004-08-09 17:04:08 +00:00
|
|
|
int numec;
|
|
|
|
uint32 total_delivered;
|
|
|
|
|
|
|
|
numec = min(p->num_valid_stat_ent, 4);
|
|
|
|
if (numec != 0) {
|
|
|
|
pee = p->old_economy;
|
|
|
|
total_delivered = 0;
|
|
|
|
do {
|
|
|
|
total_delivered += pee->delivered_cargo;
|
|
|
|
} while (++pee,--numec);
|
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_DELIVERED] = total_delivered;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-23 10:59:03 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* Generate score for variety of cargo */
|
|
|
|
{
|
|
|
|
uint cargo = p->cargo_types;
|
|
|
|
uint num = 0;
|
|
|
|
do num += cargo&1; while (cargo>>=1);
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_CARGO] = num;
|
2006-02-18 14:41:24 +00:00
|
|
|
if (update) p->cargo_types = 0;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate score for player money */
|
|
|
|
{
|
|
|
|
int32 money = p->player_money;
|
|
|
|
if (money > 0) {
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_MONEY] = money;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate score for loan */
|
|
|
|
{
|
2005-08-01 16:31:19 +00:00
|
|
|
_score_part[owner][SCORE_LOAN] = _score_info[SCORE_LOAN].needed - p->current_loan;
|
2004-08-23 10:59:03 +00:00
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Now we calculate the score for each item.. */
|
2004-08-23 10:59:03 +00:00
|
|
|
{
|
|
|
|
int total_score = 0;
|
|
|
|
int s;
|
|
|
|
score = 0;
|
2007-01-10 18:56:51 +00:00
|
|
|
for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Skip the total */
|
2004-08-23 10:59:03 +00:00
|
|
|
if (i == SCORE_TOTAL) continue;
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Check the score */
|
2005-08-01 16:31:19 +00:00
|
|
|
s = (_score_part[owner][i] >= _score_info[i].needed) ?
|
|
|
|
_score_info[i].score :
|
2006-02-18 14:41:24 +00:00
|
|
|
_score_part[owner][i] * _score_info[i].score / _score_info[i].needed;
|
2004-08-23 10:59:03 +00:00
|
|
|
if (s < 0) s = 0;
|
|
|
|
score += s;
|
2005-08-01 16:31:19 +00:00
|
|
|
total_score += _score_info[i].score;
|
2004-08-23 10:59:03 +00:00
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
_score_part[owner][SCORE_TOTAL] = score;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* We always want the score scaled to SCORE_MAX (1000) */
|
2006-02-18 14:41:24 +00:00
|
|
|
if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
if (update) {
|
2006-06-27 21:25:53 +00:00
|
|
|
p->old_economy[0].performance_history = score;
|
|
|
|
UpdateCompanyHQ(p, score);
|
|
|
|
p->old_economy[0].company_value = CalculateCompanyValue(p);
|
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
InvalidateWindow(WC_PERFORMANCE_DETAIL, 0);
|
2004-09-01 21:54:12 +00:00
|
|
|
return score;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* use PLAYER_SPECTATOR as new_player to delete the player. */
|
2005-05-12 23:47:45 +00:00
|
|
|
void ChangeOwnershipOfPlayerItems(PlayerID old_player, PlayerID new_player)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-12-08 12:31:34 +00:00
|
|
|
Town *t;
|
2005-05-12 23:47:45 +00:00
|
|
|
PlayerID old = _current_player;
|
2007-03-31 12:19:22 +00:00
|
|
|
|
2007-04-01 10:55:31 +00:00
|
|
|
assert(old_player != new_player);
|
|
|
|
|
2007-03-31 12:19:22 +00:00
|
|
|
{
|
|
|
|
Player *p;
|
|
|
|
uint i;
|
|
|
|
|
|
|
|
/* See if the old_player had shares in other companies */
|
|
|
|
_current_player = old_player;
|
|
|
|
FOR_ALL_PLAYERS(p) {
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
if (p->share_owners[i] == old_player) {
|
|
|
|
/* Sell his shares */
|
|
|
|
int32 res = DoCommand(0, p->index, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
|
|
|
|
/* Because we are in a DoCommand, we can't just execute an other one and
|
|
|
|
* expect the money to be removed. We need to do it ourself! */
|
|
|
|
SubtractMoneyFromPlayer(res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sell all the shares that people have on this company */
|
|
|
|
p = GetPlayer(old_player);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
_current_player = p->share_owners[i];
|
|
|
|
if (_current_player != PLAYER_SPECTATOR) {
|
|
|
|
/* Sell the shares */
|
|
|
|
int32 res = DoCommand(0, old_player, 0, DC_EXEC, CMD_SELL_SHARE_IN_COMPANY);
|
|
|
|
/* Because we are in a DoCommand, we can't just execute an other one and
|
|
|
|
* expect the money to be removed. We need to do it ourself! */
|
|
|
|
SubtractMoneyFromPlayer(res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
_current_player = old_player;
|
|
|
|
|
2006-08-14 11:44:19 +00:00
|
|
|
/* Temporarily increase the player's money, to be sure that
|
2006-09-04 20:40:33 +00:00
|
|
|
* removing his/her property doesn't fail because of lack of money.
|
|
|
|
* Not too drastically though, because it could overflow */
|
2006-10-14 15:49:43 +00:00
|
|
|
if (new_player == PLAYER_SPECTATOR) {
|
2006-09-03 23:02:42 +00:00
|
|
|
GetPlayer(old_player)->money64 = MAX_UVALUE(uint64) >>2; // jackpot ;p
|
2006-08-27 21:20:29 +00:00
|
|
|
UpdatePlayerMoney32(GetPlayer(old_player));
|
2006-08-14 11:44:19 +00:00
|
|
|
}
|
|
|
|
|
2006-10-14 15:49:43 +00:00
|
|
|
if (new_player == PLAYER_SPECTATOR) {
|
2004-08-09 17:04:08 +00:00
|
|
|
Subsidy *s;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2005-05-12 23:47:45 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2005-09-28 19:35:36 +00:00
|
|
|
if (s->cargo_type != CT_INVALID && s->age >= 12) {
|
2006-06-27 21:25:53 +00:00
|
|
|
if (GetStation(s->to)->owner == old_player) s->cargo_type = CT_INVALID;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-12 23:47:45 +00:00
|
|
|
/* Take care of rating in towns */
|
2006-12-08 12:31:34 +00:00
|
|
|
FOR_ALL_TOWNS(t) {
|
|
|
|
/* If a player takes over, give the ratings to that player. */
|
|
|
|
if (new_player != PLAYER_SPECTATOR) {
|
2006-08-22 15:33:35 +00:00
|
|
|
if (HASBIT(t->have_ratings, old_player)) {
|
2006-08-14 11:44:19 +00:00
|
|
|
if (HASBIT(t->have_ratings, new_player)) {
|
|
|
|
// use max of the two ratings.
|
|
|
|
t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
|
|
|
|
} else {
|
|
|
|
SETBIT(t->have_ratings, new_player);
|
|
|
|
t->ratings[new_player] = t->ratings[old_player];
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2006-08-14 11:44:19 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2006-12-08 12:31:34 +00:00
|
|
|
|
|
|
|
/* Reset the ratings for the old player */
|
|
|
|
t->ratings[old_player] = 500;
|
|
|
|
CLRBIT(t->have_ratings, old_player);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
int num_train = 0;
|
|
|
|
int num_road = 0;
|
|
|
|
int num_ship = 0;
|
|
|
|
int num_aircraft = 0;
|
|
|
|
Vehicle *v;
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Determine Ids for the new vehicles */
|
2004-08-09 17:04:08 +00:00
|
|
|
FOR_ALL_VEHICLES(v) {
|
|
|
|
if (v->owner == new_player) {
|
2005-05-12 23:47:45 +00:00
|
|
|
switch (v->type) {
|
2007-03-08 16:27:54 +00:00
|
|
|
case VEH_TRAIN: if (IsFrontEngine(v)) num_train++; break;
|
|
|
|
case VEH_ROAD: num_road++; break;
|
|
|
|
case VEH_SHIP: num_ship++; break;
|
|
|
|
case VEH_AIRCRAFT: if (IsNormalAircraft(v)) num_aircraft++; break;
|
2005-05-12 23:47:45 +00:00
|
|
|
default: break;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FOR_ALL_VEHICLES(v) {
|
2007-03-08 16:27:54 +00:00
|
|
|
if (v->owner == old_player && IS_BYTE_INSIDE(v->type, VEH_TRAIN, VEH_AIRCRAFT + 1)) {
|
2006-10-14 15:49:43 +00:00
|
|
|
if (new_player == PLAYER_SPECTATOR) {
|
2004-08-09 17:04:08 +00:00
|
|
|
DeleteWindowById(WC_VEHICLE_VIEW, v->index);
|
|
|
|
DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
|
|
|
|
DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
|
|
|
|
DeleteVehicle(v);
|
|
|
|
} else {
|
|
|
|
v->owner = new_player;
|
2006-09-19 12:48:12 +00:00
|
|
|
if (IsEngineCountable(v)) GetPlayer(new_player)->num_engines[v->engine_type]++;
|
2006-02-06 09:18:04 +00:00
|
|
|
switch (v->type) {
|
2007-03-08 16:27:54 +00:00
|
|
|
case VEH_TRAIN: if (IsFrontEngine(v)) v->unitnumber = ++num_train; break;
|
|
|
|
case VEH_ROAD: v->unitnumber = ++num_road; break;
|
|
|
|
case VEH_SHIP: v->unitnumber = ++num_ship; break;
|
|
|
|
case VEH_AIRCRAFT: if (IsNormalAircraft(v)) v->unitnumber = ++num_aircraft; break;
|
2007-05-15 11:28:22 +00:00
|
|
|
default: NOT_REACHED();
|
2006-02-06 09:18:04 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Change ownership of tiles */
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-05-12 23:47:45 +00:00
|
|
|
TileIndex tile = 0;
|
2004-08-09 17:04:08 +00:00
|
|
|
do {
|
|
|
|
ChangeTileOwner(tile, old_player, new_player);
|
2005-01-03 18:59:58 +00:00
|
|
|
} while (++tile != MapSize());
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2006-11-13 20:33:51 +00:00
|
|
|
/* Change color of existing windows */
|
|
|
|
if (new_player != PLAYER_SPECTATOR) ChangeWindowOwner(old_player, new_player);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
_current_player = old;
|
|
|
|
|
|
|
|
MarkWholeScreenDirty();
|
|
|
|
}
|
|
|
|
|
2007-03-08 21:05:05 +00:00
|
|
|
static void ChangeNetworkOwner(PlayerID current_player, PlayerID new_player)
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_NETWORK
|
|
|
|
if (!_networking) return;
|
|
|
|
|
|
|
|
if (current_player == _local_player) {
|
|
|
|
_network_playas = new_player;
|
|
|
|
SetLocalPlayer(new_player);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_network_server) return;
|
|
|
|
|
|
|
|
/* The server has to handle all administrative issues, for example
|
|
|
|
* updating and notifying all clients of what has happened */
|
|
|
|
NetworkTCPSocketHandler *cs;
|
|
|
|
NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
|
|
|
|
|
|
|
|
/* The server has just changed from player */
|
|
|
|
if (current_player == ci->client_playas) {
|
|
|
|
ci->client_playas = new_player;
|
|
|
|
NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find all clients that were in control of this company, and mark them as new_player */
|
|
|
|
FOR_ALL_CLIENTS(cs) {
|
|
|
|
ci = DEREF_CLIENT_INFO(cs);
|
|
|
|
if (current_player == ci->client_playas) {
|
|
|
|
ci->client_playas = new_player;
|
|
|
|
NetworkUpdateClientInfo(ci->client_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* ENABLE_NETWORK */
|
|
|
|
}
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
static void PlayersCheckBankrupt(Player *p)
|
|
|
|
{
|
2005-09-30 20:37:25 +00:00
|
|
|
PlayerID owner;
|
2004-09-11 09:40:19 +00:00
|
|
|
int64 val;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* If the player has money again, it does not go bankrupt */
|
2004-08-09 17:04:08 +00:00
|
|
|
if (p->player_money >= 0) {
|
|
|
|
p->quarters_of_bankrupcy = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->quarters_of_bankrupcy++;
|
|
|
|
|
|
|
|
owner = p->index;
|
|
|
|
|
2004-12-04 17:54:56 +00:00
|
|
|
switch (p->quarters_of_bankrupcy) {
|
|
|
|
case 2:
|
2006-10-17 17:59:41 +00:00
|
|
|
AddNewsItem( (StringID)(owner | NB_BTROUBLE),
|
2004-12-04 17:54:56 +00:00
|
|
|
NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
|
|
|
|
break;
|
|
|
|
case 3: {
|
|
|
|
/* XXX - In multiplayer, should we ask other players if it wants to take
|
|
|
|
over when it is a human company? -- TrueLight */
|
2006-10-14 15:15:56 +00:00
|
|
|
if (IsHumanPlayer(owner)) {
|
2006-10-17 17:59:41 +00:00
|
|
|
AddNewsItem( (StringID)(owner | NB_BTROUBLE),
|
2004-12-04 17:54:56 +00:00
|
|
|
NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
|
|
|
|
break;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Check if the company has any value.. if not, declare it bankrupt
|
|
|
|
* right now */
|
2004-12-04 17:54:56 +00:00
|
|
|
val = CalculateCompanyValue(p);
|
|
|
|
if (val > 0) {
|
|
|
|
p->bankrupt_value = val;
|
|
|
|
p->bankrupt_asked = 1 << owner; // Don't ask the owner
|
|
|
|
p->bankrupt_timeout = 0;
|
|
|
|
break;
|
|
|
|
}
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Else, falltrue to case 4... */
|
2004-12-04 17:54:56 +00:00
|
|
|
}
|
|
|
|
case 4: {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Close everything the owner has open */
|
2004-12-04 17:54:56 +00:00
|
|
|
DeletePlayerWindows(owner);
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Show bankrupt news */
|
2004-12-04 17:54:56 +00:00
|
|
|
SetDParam(0, p->name_1);
|
|
|
|
SetDParam(1, p->name_2);
|
2006-10-17 17:59:41 +00:00
|
|
|
AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
|
2004-12-04 17:54:56 +00:00
|
|
|
|
2006-11-10 17:52:51 +00:00
|
|
|
if (IsHumanPlayer(owner)) {
|
|
|
|
/* XXX - If we are in offline mode, leave the player playing. Eg. there
|
|
|
|
* is no THE-END, otherwise mark the player as spectator to make sure
|
|
|
|
* he/she is no long in control of this company */
|
|
|
|
if (!_networking) {
|
|
|
|
p->bankrupt_asked = 0xFF;
|
|
|
|
p->bankrupt_timeout = 0x456;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-03-08 21:05:05 +00:00
|
|
|
ChangeNetworkOwner(owner, PLAYER_SPECTATOR);
|
2006-11-10 17:52:51 +00:00
|
|
|
}
|
2004-12-16 11:36:00 +00:00
|
|
|
|
2006-11-10 17:52:51 +00:00
|
|
|
/* Remove the player */
|
|
|
|
ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
|
|
|
|
/* Register the player as not-active */
|
|
|
|
p->is_active = false;
|
2005-09-07 15:10:11 +00:00
|
|
|
|
2006-11-10 17:52:51 +00:00
|
|
|
if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
|
|
|
|
AI_PlayerDied(owner);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DrawNewsBankrupcy(Window *w)
|
|
|
|
{
|
|
|
|
Player *p;
|
|
|
|
|
2004-09-10 19:02:27 +00:00
|
|
|
DrawNewsBorder(w);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-01-10 18:56:51 +00:00
|
|
|
p = GetPlayer((PlayerID)GB(WP(w,news_d).ni->string_id, 0, 4));
|
2004-08-09 17:04:08 +00:00
|
|
|
DrawPlayerFace(p->face, p->player_color, 2, 23);
|
2007-01-14 19:57:49 +00:00
|
|
|
GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, p->president_name_1);
|
|
|
|
SetDParam(1, p->president_name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
|
|
|
|
|
2006-10-17 17:59:41 +00:00
|
|
|
switch (WP(w,news_d).ni->string_id & 0xF0) {
|
|
|
|
case NB_BTROUBLE:
|
2004-08-09 17:04:08 +00:00
|
|
|
DrawStringCentered(w->width>>1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, 0);
|
|
|
|
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, p->name_1);
|
|
|
|
SetDParam(1, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
DrawStringMultiCenter(
|
|
|
|
((w->width - 101) >> 1) + 98,
|
|
|
|
90,
|
|
|
|
STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
|
|
|
|
w->width - 101);
|
|
|
|
break;
|
|
|
|
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BMERGER: {
|
2004-08-09 17:04:08 +00:00
|
|
|
int32 price;
|
|
|
|
|
|
|
|
DrawStringCentered(w->width>>1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, 0);
|
|
|
|
COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(2, p->name_1);
|
|
|
|
SetDParam(3, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
price = WP(w,news_d).ni->params[2];
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(4, price);
|
2004-08-09 17:04:08 +00:00
|
|
|
DrawStringMultiCenter(
|
|
|
|
((w->width - 101) >> 1) + 98,
|
|
|
|
90,
|
|
|
|
price==0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
|
|
|
|
w->width - 101);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BBANKRUPT:
|
2004-08-09 17:04:08 +00:00
|
|
|
DrawStringCentered(w->width>>1, 1, STR_705C_BANKRUPT, 0);
|
|
|
|
COPY_IN_DPARAM(0,WP(w,news_d).ni->params, 2);
|
|
|
|
DrawStringMultiCenter(
|
|
|
|
((w->width - 101) >> 1) + 98,
|
|
|
|
90,
|
|
|
|
STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
|
|
|
|
w->width - 101);
|
2004-09-10 19:02:27 +00:00
|
|
|
break;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BNEWCOMPANY:
|
2004-08-09 17:04:08 +00:00
|
|
|
DrawStringCentered(w->width>>1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, 0);
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, p->name_1);
|
|
|
|
SetDParam(1, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
COPY_IN_DPARAM(2,WP(w,news_d).ni->params, 2);
|
|
|
|
DrawStringMultiCenter(
|
|
|
|
((w->width - 101) >> 1) + 98,
|
|
|
|
90,
|
|
|
|
STR_705F_STARTS_CONSTRUCTION_NEAR,
|
|
|
|
w->width - 101);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
NOT_REACHED();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-18 20:56:44 +00:00
|
|
|
StringID GetNewsStringBankrupcy(const NewsItem *ni)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-01-10 18:56:51 +00:00
|
|
|
const Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2006-10-17 17:59:41 +00:00
|
|
|
switch (ni->string_id & 0xF0) {
|
|
|
|
case NB_BTROUBLE:
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
|
|
|
|
SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
|
|
|
|
SetDParam(2, p->name_1);
|
|
|
|
SetDParam(3, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
return STR_02B6;
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BMERGER:
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
|
|
|
|
SetDParam(1, STR_705A_HAS_BEEN_SOLD_TO_FOR);
|
2004-08-09 17:04:08 +00:00
|
|
|
COPY_IN_DPARAM(2,ni->params, 2);
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(4, p->name_1);
|
|
|
|
SetDParam(5, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
COPY_IN_DPARAM(6,ni->params + 2, 1);
|
|
|
|
return STR_02B6;
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BBANKRUPT:
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, STR_705C_BANKRUPT);
|
|
|
|
SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
|
2004-08-09 17:04:08 +00:00
|
|
|
COPY_IN_DPARAM(2,ni->params, 2);
|
|
|
|
return STR_02B6;
|
2006-10-17 17:59:41 +00:00
|
|
|
case NB_BNEWCOMPANY:
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
|
|
|
|
SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
|
|
|
|
SetDParam(2, p->name_1);
|
|
|
|
SetDParam(3, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
COPY_IN_DPARAM(4,ni->params, 2);
|
|
|
|
return STR_02B6;
|
|
|
|
default:
|
|
|
|
NOT_REACHED();
|
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* useless, but avoids compiler warning this way */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void PlayersGenStatistics()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Station *st;
|
|
|
|
Player *p;
|
|
|
|
|
|
|
|
FOR_ALL_STATIONS(st) {
|
2006-08-22 15:33:35 +00:00
|
|
|
_current_player = st->owner;
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_PROPERTY);
|
|
|
|
SubtractMoneyFromPlayer(_price.station_value >> 1);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!HASBIT(1<<0|1<<3|1<<6|1<<9, _cur_month))
|
|
|
|
return;
|
|
|
|
|
|
|
|
FOR_ALL_PLAYERS(p) {
|
|
|
|
if (p->is_active) {
|
2006-12-30 00:06:00 +00:00
|
|
|
memmove(&p->old_economy[1], &p->old_economy[0], sizeof(p->old_economy) - sizeof(p->old_economy[0]));
|
|
|
|
p->old_economy[0] = p->cur_economy;
|
2004-08-09 17:04:08 +00:00
|
|
|
memset(&p->cur_economy, 0, sizeof(p->cur_economy));
|
|
|
|
|
2006-12-30 00:06:00 +00:00
|
|
|
if (p->num_valid_stat_ent != 24) p->num_valid_stat_ent++;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2004-08-23 10:59:03 +00:00
|
|
|
UpdateCompanyRatingAndValue(p, true);
|
2004-08-09 17:04:08 +00:00
|
|
|
PlayersCheckBankrupt(p);
|
|
|
|
|
2006-12-30 00:06:00 +00:00
|
|
|
if (p->block_preview != 0) p->block_preview--;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InvalidateWindow(WC_INCOME_GRAPH, 0);
|
|
|
|
InvalidateWindow(WC_OPERATING_PROFIT, 0);
|
|
|
|
InvalidateWindow(WC_DELIVERED_CARGO, 0);
|
|
|
|
InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
|
|
|
|
InvalidateWindow(WC_COMPANY_VALUE, 0);
|
|
|
|
InvalidateWindow(WC_COMPANY_LEAGUE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AddSingleInflation(int32 *value, uint16 *frac, int32 amt)
|
|
|
|
{
|
2007-02-23 08:03:30 +00:00
|
|
|
int64 tmp = (int64)*value * amt + *frac;
|
|
|
|
*frac = GB(tmp, 0, 16);
|
|
|
|
*value += tmp >> 16;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void AddInflation()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-02-23 08:03:30 +00:00
|
|
|
/* Approximation for (100 + infl_amount)% ** (1 / 12) - 100%
|
|
|
|
* scaled by 65536
|
|
|
|
* 12 -> months per year
|
|
|
|
* This is only a good approxiamtion for small values
|
|
|
|
*/
|
2004-08-09 17:04:08 +00:00
|
|
|
int32 inf = _economy.infl_amount * 54;
|
|
|
|
|
2007-02-23 08:03:30 +00:00
|
|
|
for (uint i = 0; i != NUM_PRICES; i++) {
|
2005-11-14 19:48:04 +00:00
|
|
|
AddSingleInflation((int32*)&_price + i, _price_frac + i, inf);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_economy.max_loan_unround += BIGMULUS(_economy.max_loan_unround, inf, 16);
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
if (_economy.max_loan + 50000 <= _economy.max_loan_unround)
|
|
|
|
_economy.max_loan += 50000;
|
|
|
|
|
|
|
|
inf = _economy.infl_amount_pr * 54;
|
2007-03-21 13:19:01 +00:00
|
|
|
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
2004-09-10 19:02:27 +00:00
|
|
|
AddSingleInflation(
|
2005-06-01 11:52:44 +00:00
|
|
|
(int32*)_cargo_payment_rates + i,
|
2004-08-09 17:04:08 +00:00
|
|
|
_cargo_payment_rates_frac + i,
|
|
|
|
inf
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
InvalidateWindowClasses(WC_BUILD_VEHICLE);
|
2005-01-22 23:41:23 +00:00
|
|
|
InvalidateWindowClasses(WC_REPLACE_VEHICLE);
|
2004-08-09 17:04:08 +00:00
|
|
|
InvalidateWindowClasses(WC_VEHICLE_DETAILS);
|
|
|
|
InvalidateWindow(WC_PAYMENT_RATES, 0);
|
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void PlayersPayInterest()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-10-22 06:39:32 +00:00
|
|
|
const Player* p;
|
2004-08-09 17:04:08 +00:00
|
|
|
int interest = _economy.interest_rate * 54;
|
|
|
|
|
|
|
|
FOR_ALL_PLAYERS(p) {
|
2005-11-14 19:48:04 +00:00
|
|
|
if (!p->is_active) continue;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
_current_player = p->index;
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_LOAN_INT);
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
SubtractMoneyFromPlayer(BIGMULUS(p->current_loan, interest, 16));
|
|
|
|
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
|
|
|
SubtractMoneyFromPlayer(_price.station_value >> 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void HandleEconomyFluctuations()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-11-14 19:48:04 +00:00
|
|
|
if (_opt.diff.economy == 0) return;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
if (--_economy.fluct == 0) {
|
2005-11-15 08:49:46 +00:00
|
|
|
_economy.fluct = -(int)GB(Random(), 0, 2);
|
2004-08-09 17:04:08 +00:00
|
|
|
AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
|
|
|
|
} else if (_economy.fluct == -12) {
|
2005-11-15 08:49:46 +00:00
|
|
|
_economy.fluct = GB(Random(), 0, 8) + 312;
|
2004-08-09 17:04:08 +00:00
|
|
|
AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NEWS_FLAGS(NM_NORMAL,0,NT_ECONOMY,0), 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static byte _price_category[NUM_PRICES] = {
|
|
|
|
0, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 1, 1, 1, 1, 1, 1,
|
|
|
|
2,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int32 _price_base[NUM_PRICES] = {
|
2007-02-23 18:55:07 +00:00
|
|
|
100, ///< station_value
|
|
|
|
100, ///< build_rail
|
|
|
|
95, ///< build_road
|
|
|
|
65, ///< build_signals
|
|
|
|
275, ///< build_bridge
|
|
|
|
600, ///< build_train_depot
|
|
|
|
500, ///< build_road_depot
|
|
|
|
700, ///< build_ship_depot
|
|
|
|
450, ///< build_tunnel
|
|
|
|
200, ///< train_station_track
|
|
|
|
180, ///< train_station_length
|
|
|
|
600, ///< build_airport
|
|
|
|
200, ///< build_bus_station
|
|
|
|
200, ///< build_truck_station
|
|
|
|
350, ///< build_dock
|
|
|
|
400000, ///< build_railvehicle
|
|
|
|
2000, ///< build_railwagon
|
|
|
|
700000, ///< aircraft_base
|
|
|
|
14000, ///< roadveh_base
|
|
|
|
65000, ///< ship_base
|
|
|
|
20, ///< build_trees
|
|
|
|
250, ///< terraform
|
|
|
|
20, ///< clear_1
|
|
|
|
40, ///< purchase_land
|
|
|
|
200, ///< clear_2
|
|
|
|
500, ///< clear_3
|
|
|
|
20, ///< remove_trees
|
|
|
|
-70, ///< remove_rail
|
|
|
|
10, ///< remove_signals
|
|
|
|
50, ///< clear_bridge
|
|
|
|
80, ///< remove_train_depot
|
|
|
|
80, ///< remove_road_depot
|
|
|
|
90, ///< remove_ship_depot
|
|
|
|
30, ///< clear_tunnel
|
|
|
|
10000, ///< clear_water
|
|
|
|
50, ///< remove_rail_station
|
|
|
|
30, ///< remove_airport
|
|
|
|
50, ///< remove_bus_station
|
|
|
|
50, ///< remove_truck_station
|
|
|
|
55, ///< remove_dock
|
|
|
|
1600, ///< remove_house
|
|
|
|
40, ///< remove_road
|
|
|
|
5600, ///< running_rail[0] railroad
|
|
|
|
5200, ///< running_rail[1] monorail
|
|
|
|
4800, ///< running_rail[2] maglev
|
|
|
|
9600, ///< aircraft_running
|
|
|
|
1600, ///< roadveh_running
|
|
|
|
5600, ///< ship_running
|
|
|
|
1000000, ///< build_industry
|
2004-08-09 17:04:08 +00:00
|
|
|
};
|
|
|
|
|
2005-10-12 07:27:56 +00:00
|
|
|
static byte price_base_multiplier[NUM_PRICES];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset changes to the price base multipliers.
|
|
|
|
*/
|
2007-03-07 11:47:46 +00:00
|
|
|
void ResetPriceBaseMultipliers()
|
2005-10-12 07:27:56 +00:00
|
|
|
{
|
2005-10-12 09:54:29 +00:00
|
|
|
uint i;
|
2005-10-12 07:27:56 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* 8 means no multiplier. */
|
2005-10-12 07:27:56 +00:00
|
|
|
for (i = 0; i < NUM_PRICES; i++)
|
|
|
|
price_base_multiplier[i] = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change a price base by the given factor.
|
|
|
|
* The price base is altered by factors of two, with an offset of 8.
|
|
|
|
* NewBaseCost = OldBaseCost * 2^(n-8)
|
|
|
|
* @param price Index of price base to change.
|
|
|
|
* @param factor Amount to change by.
|
|
|
|
*/
|
2005-10-12 09:54:29 +00:00
|
|
|
void SetPriceBaseMultiplier(uint price, byte factor)
|
2005-10-12 07:27:56 +00:00
|
|
|
{
|
2005-10-12 09:54:29 +00:00
|
|
|
assert(price < NUM_PRICES);
|
|
|
|
price_base_multiplier[price] = factor;
|
2005-10-12 07:27:56 +00:00
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
void StartupEconomy()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(sizeof(_price) == NUM_PRICES * sizeof(int32));
|
|
|
|
|
2006-02-01 07:36:15 +00:00
|
|
|
for (i = 0; i != NUM_PRICES; i++) {
|
2004-08-09 17:04:08 +00:00
|
|
|
int32 price = _price_base[i];
|
|
|
|
if (_price_category[i] != 0) {
|
|
|
|
uint mod = _price_category[i] == 1 ? _opt.diff.vehicle_costs : _opt.diff.construction_cost;
|
|
|
|
if (mod < 1) {
|
|
|
|
price = price * 3 >> 2;
|
|
|
|
} else if (mod > 1) {
|
|
|
|
price = price * 9 >> 3;
|
|
|
|
}
|
|
|
|
}
|
2005-10-12 07:27:56 +00:00
|
|
|
if (price_base_multiplier[i] > 8) {
|
|
|
|
price <<= price_base_multiplier[i] - 8;
|
|
|
|
} else {
|
|
|
|
price >>= 8 - price_base_multiplier[i];
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
((int32*)&_price)[i] = price;
|
|
|
|
_price_frac[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_economy.interest_rate = _opt.diff.initial_interest;
|
|
|
|
_economy.infl_amount = _opt.diff.initial_interest;
|
|
|
|
_economy.infl_amount_pr = max(0, _opt.diff.initial_interest - 1);
|
|
|
|
_economy.max_loan_unround = _economy.max_loan = _opt.diff.max_loan * 1000;
|
2005-07-21 06:31:02 +00:00
|
|
|
_economy.fluct = GB(Random(), 0, 8) + 168;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2005-11-13 13:43:55 +00:00
|
|
|
Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-06-24 12:38:35 +00:00
|
|
|
TileIndex tile;
|
|
|
|
TileIndex tile2;
|
2004-08-09 17:04:08 +00:00
|
|
|
Pair tp;
|
|
|
|
|
2005-08-02 20:04:09 +00:00
|
|
|
/* if mode is false, use the singular form */
|
2007-02-20 22:09:21 +00:00
|
|
|
const CargoSpec *cs = GetCargo(s->cargo_type);
|
|
|
|
SetDParam(0, mode ? cs->name_plural : cs->name);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
if (s->age < 12) {
|
2007-03-16 17:40:31 +00:00
|
|
|
if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL) {
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(1, STR_INDUSTRY);
|
|
|
|
SetDParam(2, s->from);
|
|
|
|
tile = GetIndustry(s->from)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-03-16 17:40:31 +00:00
|
|
|
if (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD) {
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(4, STR_INDUSTRY);
|
|
|
|
SetDParam(5, s->to);
|
|
|
|
tile2 = GetIndustry(s->to)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
} else {
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(4, STR_TOWN);
|
|
|
|
SetDParam(5, s->to);
|
|
|
|
tile2 = GetTown(s->to)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(1, STR_TOWN);
|
|
|
|
SetDParam(2, s->from);
|
|
|
|
tile = GetTown(s->from)->xy;
|
|
|
|
|
|
|
|
SetDParam(4, STR_TOWN);
|
|
|
|
SetDParam(5, s->to);
|
|
|
|
tile2 = GetTown(s->to)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(1, s->from);
|
|
|
|
tile = GetStation(s->from)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2005-07-15 18:30:13 +00:00
|
|
|
SetDParam(2, s->to);
|
|
|
|
tile2 = GetStation(s->to)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tp.a = tile;
|
|
|
|
tp.b = tile2;
|
|
|
|
|
|
|
|
return tp;
|
|
|
|
}
|
|
|
|
|
2006-12-26 15:28:11 +00:00
|
|
|
void DeleteSubsidyWithTown(TownID index)
|
|
|
|
{
|
|
|
|
Subsidy *s;
|
|
|
|
|
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2007-03-16 17:40:31 +00:00
|
|
|
if (s->cargo_type != CT_INVALID && s->age < 12) {
|
|
|
|
const CargoSpec *cs = GetCargo(s->cargo_type);
|
|
|
|
if (((cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) && (index == s->from || index == s->to)) ||
|
|
|
|
((cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) && index == s->to)) {
|
|
|
|
s->cargo_type = CT_INVALID;
|
|
|
|
}
|
2006-12-26 15:28:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-20 19:31:58 +00:00
|
|
|
void DeleteSubsidyWithIndustry(IndustryID index)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Subsidy *s;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2006-02-01 07:36:15 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2007-03-16 17:40:31 +00:00
|
|
|
if (s->cargo_type != CT_INVALID && s->age < 12) {
|
|
|
|
const CargoSpec *cs = GetCargo(s->cargo_type);
|
|
|
|
if (cs->town_effect != TE_PASSENGERS && cs->town_effect != TE_MAIL &&
|
|
|
|
(index == s->from || (cs->town_effect != TE_GOODS && cs->town_effect != TE_FOOD && index == s->to))) {
|
|
|
|
s->cargo_type = CT_INVALID;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2006-08-20 19:31:58 +00:00
|
|
|
void DeleteSubsidyWithStation(StationID index)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Subsidy *s;
|
|
|
|
bool dirty = false;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2006-02-01 07:36:15 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2005-09-28 19:35:36 +00:00
|
|
|
if (s->cargo_type != CT_INVALID && s->age >= 12 &&
|
2004-08-09 17:04:08 +00:00
|
|
|
(s->from == index || s->to == index)) {
|
2005-09-28 19:35:36 +00:00
|
|
|
s->cargo_type = CT_INVALID;
|
2004-08-09 17:04:08 +00:00
|
|
|
dirty = true;
|
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
if (dirty)
|
|
|
|
InvalidateWindow(WC_SUBSIDIES_LIST, 0);
|
|
|
|
}
|
|
|
|
|
2007-03-07 12:11:48 +00:00
|
|
|
struct FoundRoute {
|
2004-08-09 17:04:08 +00:00
|
|
|
uint distance;
|
2006-03-26 22:23:32 +00:00
|
|
|
CargoID cargo;
|
2004-08-09 17:04:08 +00:00
|
|
|
void *from;
|
|
|
|
void *to;
|
2007-03-07 12:11:48 +00:00
|
|
|
};
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
static void FindSubsidyPassengerRoute(FoundRoute *fr)
|
|
|
|
{
|
|
|
|
Town *from,*to;
|
|
|
|
|
|
|
|
fr->distance = (uint)-1;
|
|
|
|
|
2006-08-22 21:14:45 +00:00
|
|
|
fr->from = from = GetRandomTown();
|
|
|
|
if (from == NULL || from->population < 400) return;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2006-08-22 21:14:45 +00:00
|
|
|
fr->to = to = GetRandomTown();
|
|
|
|
if (from == to || to == NULL || to->population < 400 || to->pct_pass_transported > 42)
|
2004-08-09 17:04:08 +00:00
|
|
|
return;
|
|
|
|
|
2005-01-31 07:23:15 +00:00
|
|
|
fr->distance = DistanceManhattan(from->xy, to->xy);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void FindSubsidyCargoRoute(FoundRoute *fr)
|
|
|
|
{
|
|
|
|
Industry *i;
|
|
|
|
int trans, total;
|
2006-03-26 22:23:32 +00:00
|
|
|
CargoID cargo;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
fr->distance = (uint)-1;
|
|
|
|
|
2006-08-22 21:14:45 +00:00
|
|
|
fr->from = i = GetRandomIndustry();
|
|
|
|
if (i == NULL) return;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Randomize cargo type */
|
2005-09-28 19:35:36 +00:00
|
|
|
if (Random()&1 && i->produced_cargo[1] != CT_INVALID) {
|
2004-08-09 17:04:08 +00:00
|
|
|
cargo = i->produced_cargo[1];
|
|
|
|
trans = i->pct_transported[1];
|
|
|
|
total = i->total_production[1];
|
|
|
|
} else {
|
|
|
|
cargo = i->produced_cargo[0];
|
|
|
|
trans = i->pct_transported[0];
|
|
|
|
total = i->total_production[0];
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Quit if no production in this industry
|
|
|
|
* or if the cargo type is passengers
|
|
|
|
* or if the pct transported is already large enough */
|
2007-03-16 17:40:31 +00:00
|
|
|
if (total == 0 || trans > 42 || cargo == CT_INVALID) return;
|
|
|
|
|
|
|
|
const CargoSpec *cs = GetCargo(cargo);
|
|
|
|
if (cs->town_effect == TE_PASSENGERS) return;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
fr->cargo = cargo;
|
|
|
|
|
2007-03-16 17:40:31 +00:00
|
|
|
if (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* The destination is a town */
|
2006-08-22 21:14:45 +00:00
|
|
|
Town *t = GetRandomTown();
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Only want big towns */
|
2006-08-22 21:14:45 +00:00
|
|
|
if (t == NULL || t->population < 900) return;
|
2006-08-22 15:33:35 +00:00
|
|
|
|
2005-01-31 07:23:15 +00:00
|
|
|
fr->distance = DistanceManhattan(i->xy, t->xy);
|
2004-08-09 17:04:08 +00:00
|
|
|
fr->to = t;
|
|
|
|
} else {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* The destination is an industry */
|
2006-08-22 21:14:45 +00:00
|
|
|
Industry *i2 = GetRandomIndustry();
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* The industry must accept the cargo */
|
2006-08-22 21:14:45 +00:00
|
|
|
if (i == i2 || i == NULL ||
|
2004-08-09 17:04:08 +00:00
|
|
|
(cargo != i2->accepts_cargo[0] &&
|
|
|
|
cargo != i2->accepts_cargo[1] &&
|
|
|
|
cargo != i2->accepts_cargo[2]))
|
|
|
|
return;
|
2005-01-31 07:23:15 +00:00
|
|
|
fr->distance = DistanceManhattan(i->xy, i2->xy);
|
2004-08-09 17:04:08 +00:00
|
|
|
fr->to = i2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-10 19:02:27 +00:00
|
|
|
static bool CheckSubsidyDuplicate(Subsidy *s)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-11-13 13:43:55 +00:00
|
|
|
const Subsidy* ss;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2005-11-14 19:48:04 +00:00
|
|
|
for (ss = _subsidies; ss != endof(_subsidies); ss++) {
|
2004-09-10 19:02:27 +00:00
|
|
|
if (s != ss &&
|
|
|
|
ss->from == s->from &&
|
|
|
|
ss->to == s->to &&
|
2004-08-09 17:04:08 +00:00
|
|
|
ss->cargo_type == s->cargo_type) {
|
2005-09-28 19:35:36 +00:00
|
|
|
s->cargo_type = CT_INVALID;
|
2004-08-09 17:04:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-09-13 22:49:11 +00:00
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void SubsidyMonthlyHandler()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Subsidy *s;
|
|
|
|
Pair pair;
|
|
|
|
Station *st;
|
|
|
|
uint n;
|
|
|
|
FoundRoute fr;
|
|
|
|
bool modified = false;
|
|
|
|
|
2006-02-01 07:36:15 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
|
|
|
if (s->cargo_type == CT_INVALID) continue;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
if (s->age == 12-1) {
|
|
|
|
pair = SetupSubsidyDecodeParam(s, 1);
|
|
|
|
AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
2005-09-28 19:35:36 +00:00
|
|
|
s->cargo_type = CT_INVALID;
|
2004-08-09 17:04:08 +00:00
|
|
|
modified = true;
|
|
|
|
} else if (s->age == 2*12-1) {
|
2005-01-06 22:31:58 +00:00
|
|
|
st = GetStation(s->to);
|
2004-08-09 17:04:08 +00:00
|
|
|
if (st->owner == _local_player) {
|
|
|
|
pair = SetupSubsidyDecodeParam(s, 1);
|
|
|
|
AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
|
|
|
}
|
2005-09-28 19:35:36 +00:00
|
|
|
s->cargo_type = CT_INVALID;
|
2004-08-09 17:04:08 +00:00
|
|
|
modified = true;
|
|
|
|
} else {
|
|
|
|
s->age++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* 25% chance to go on */
|
2004-12-04 17:54:56 +00:00
|
|
|
if (CHANCE16(1,4)) {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Find a free slot*/
|
2004-08-09 17:04:08 +00:00
|
|
|
s = _subsidies;
|
2005-09-28 19:35:36 +00:00
|
|
|
while (s->cargo_type != CT_INVALID) {
|
2004-08-09 17:04:08 +00:00
|
|
|
if (++s == endof(_subsidies))
|
|
|
|
goto no_add;
|
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
n = 1000;
|
|
|
|
do {
|
|
|
|
FindSubsidyPassengerRoute(&fr);
|
|
|
|
if (fr.distance <= 70) {
|
|
|
|
s->cargo_type = CT_PASSENGERS;
|
|
|
|
s->from = ((Town*)fr.from)->index;
|
|
|
|
s->to = ((Town*)fr.to)->index;
|
|
|
|
goto add_subsidy;
|
|
|
|
}
|
|
|
|
FindSubsidyCargoRoute(&fr);
|
|
|
|
if (fr.distance <= 70) {
|
|
|
|
s->cargo_type = fr.cargo;
|
2005-01-06 22:31:58 +00:00
|
|
|
s->from = ((Industry*)fr.from)->index;
|
2007-03-16 17:40:31 +00:00
|
|
|
{
|
|
|
|
const CargoSpec *cs = GetCargo(fr.cargo);
|
|
|
|
s->to = (cs->town_effect == TE_GOODS || cs->town_effect == TE_FOOD) ? ((Town*)fr.to)->index : ((Industry*)fr.to)->index;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
add_subsidy:
|
|
|
|
if (!CheckSubsidyDuplicate(s)) {
|
|
|
|
s->age = 0;
|
|
|
|
pair = SetupSubsidyDecodeParam(s, 0);
|
|
|
|
AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
|
|
|
modified = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-09-13 22:49:11 +00:00
|
|
|
} while (n--);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
no_add:;
|
|
|
|
if (modified)
|
|
|
|
InvalidateWindow(WC_SUBSIDIES_LIST, 0);
|
|
|
|
}
|
|
|
|
|
2005-05-30 22:16:05 +00:00
|
|
|
static const SaveLoad _subsidies_desc[] = {
|
2006-08-22 14:38:37 +00:00
|
|
|
SLE_VAR(Subsidy, cargo_type, SLE_UINT8),
|
|
|
|
SLE_VAR(Subsidy, age, SLE_UINT8),
|
|
|
|
SLE_CONDVAR(Subsidy, from, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
|
|
|
|
SLE_CONDVAR(Subsidy, from, SLE_UINT16, 5, SL_MAX_VERSION),
|
|
|
|
SLE_CONDVAR(Subsidy, to, SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
|
|
|
|
SLE_CONDVAR(Subsidy, to, SLE_UINT16, 5, SL_MAX_VERSION),
|
2004-08-09 17:04:08 +00:00
|
|
|
SLE_END()
|
|
|
|
};
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void Save_SUBS()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Subsidy *s;
|
|
|
|
|
2006-02-01 07:36:15 +00:00
|
|
|
for (i = 0; i != lengthof(_subsidies); i++) {
|
2004-08-09 17:04:08 +00:00
|
|
|
s = &_subsidies[i];
|
2005-09-28 19:35:36 +00:00
|
|
|
if (s->cargo_type != CT_INVALID) {
|
2004-08-09 17:04:08 +00:00
|
|
|
SlSetArrayIndex(i);
|
|
|
|
SlObject(s, _subsidies_desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
static void Load_SUBS()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
int index;
|
|
|
|
while ((index = SlIterateArray()) != -1)
|
|
|
|
SlObject(&_subsidies[index], _subsidies_desc);
|
|
|
|
}
|
|
|
|
|
2006-03-26 22:23:32 +00:00
|
|
|
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-02-20 22:09:21 +00:00
|
|
|
const CargoSpec *cs = GetCargo(cargo_type);
|
2004-08-09 17:04:08 +00:00
|
|
|
byte f;
|
|
|
|
|
2007-04-12 19:33:05 +00:00
|
|
|
/* Use callback to calculate cargo profit, if available */
|
|
|
|
if (HASBIT(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) {
|
|
|
|
uint32 var18 = min(dist, 0xFFFF) | (min(num_pieces, 0xFF) << 16) | (transit_days << 24);
|
|
|
|
uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs);
|
|
|
|
if (callback != CALLBACK_FAILED) {
|
|
|
|
int result = GB(callback, 0, 14);
|
|
|
|
|
|
|
|
/* Simulate a 15 bit signed value */
|
|
|
|
if (HASBIT(callback, 14)) result = 0x4000 - result;
|
|
|
|
|
|
|
|
/* "The result should be a signed multiplier that gets multiplied
|
|
|
|
* by the amount of cargo moved and the price factor, then gets
|
|
|
|
* divided by 8192." */
|
|
|
|
return result * num_pieces * _cargo_payment_rates[cargo_type] / 8192;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* zero the distance if it's the bank and very short transport. */
|
2007-03-22 03:42:43 +00:00
|
|
|
if (_opt.landscape == LT_TEMPERATE && cs->label == 'VALU' && dist < 10)
|
2004-08-09 17:04:08 +00:00
|
|
|
dist = 0;
|
|
|
|
|
|
|
|
f = 255;
|
2007-02-20 22:09:21 +00:00
|
|
|
if (transit_days > cs->transit_days[0]) {
|
|
|
|
transit_days -= cs->transit_days[0];
|
2004-08-09 17:04:08 +00:00
|
|
|
f -= transit_days;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-20 22:09:21 +00:00
|
|
|
if (transit_days > cs->transit_days[1]) {
|
|
|
|
transit_days -= cs->transit_days[1];
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2006-02-13 21:15:00 +00:00
|
|
|
if (f < transit_days) {
|
2004-08-09 17:04:08 +00:00
|
|
|
f = 0;
|
2006-02-13 21:15:00 +00:00
|
|
|
} else {
|
2004-08-09 17:04:08 +00:00
|
|
|
f -= transit_days;
|
2006-02-13 21:15:00 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (f < 31) f = 31;
|
|
|
|
|
2007-03-24 14:42:11 +00:00
|
|
|
return BIGMULSS(dist * f * num_pieces, _cargo_payment_rates[cargo_type], 21);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2006-03-26 22:23:32 +00:00
|
|
|
static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-02-13 21:15:00 +00:00
|
|
|
Industry* best = NULL;
|
|
|
|
Industry* ind;
|
|
|
|
uint u;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Check if there's an industry close to the station that accepts the cargo
|
|
|
|
* XXX - Think of something better to
|
|
|
|
* 1) Only deliver to industries which are withing the catchment radius
|
|
|
|
* 2) Distribute between industries if more then one is present */
|
2006-04-21 20:25:34 +00:00
|
|
|
u = (_patches.station_spread + 8) * 2;
|
2004-12-30 10:03:35 +00:00
|
|
|
FOR_ALL_INDUSTRIES(ind) {
|
2006-02-13 21:15:00 +00:00
|
|
|
uint t;
|
|
|
|
|
2006-08-22 15:33:35 +00:00
|
|
|
if (( cargo_type == ind->accepts_cargo[0] ||
|
2006-02-13 21:15:00 +00:00
|
|
|
cargo_type == ind->accepts_cargo[1] ||
|
|
|
|
cargo_type == ind->accepts_cargo[2]
|
|
|
|
) &&
|
|
|
|
ind->produced_cargo[0] != CT_INVALID &&
|
|
|
|
ind->produced_cargo[0] != cargo_type &&
|
2006-04-21 20:25:34 +00:00
|
|
|
(t = DistanceManhattan(ind->xy, xy)) < u) {
|
2004-08-09 17:04:08 +00:00
|
|
|
u = t;
|
|
|
|
best = ind;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Found one? */
|
|
|
|
if (best != NULL) {
|
|
|
|
best->was_cargo_delivered = true;
|
|
|
|
best->cargo_waiting[0] = min(best->cargo_waiting[0] + num_pieces, 0xFFFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-26 22:23:32 +00:00
|
|
|
static bool CheckSubsidised(Station *from, Station *to, CargoID cargo_type)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Subsidy *s;
|
|
|
|
TileIndex xy;
|
|
|
|
Pair pair;
|
|
|
|
Player *p;
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* check if there is an already existing subsidy that applies to us */
|
2006-02-01 06:32:03 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2004-08-09 17:04:08 +00:00
|
|
|
if (s->cargo_type == cargo_type &&
|
|
|
|
s->age >= 12 &&
|
|
|
|
s->from == from->index &&
|
2006-02-01 06:32:03 +00:00
|
|
|
s->to == to->index) {
|
2004-08-09 17:04:08 +00:00
|
|
|
return true;
|
2006-02-01 06:32:03 +00:00
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check if there's a new subsidy that applies.. */
|
2006-02-01 06:32:03 +00:00
|
|
|
for (s = _subsidies; s != endof(_subsidies); s++) {
|
2004-08-09 17:04:08 +00:00
|
|
|
if (s->cargo_type == cargo_type && s->age < 12) {
|
|
|
|
/* Check distance from source */
|
2007-03-16 17:40:31 +00:00
|
|
|
const CargoSpec *cs = GetCargo(cargo_type);
|
|
|
|
if (cs->town_effect == TE_PASSENGERS || cs->town_effect == TE_MAIL) {
|
2005-01-06 22:31:58 +00:00
|
|
|
xy = GetTown(s->from)->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
} else {
|
2005-01-06 22:31:58 +00:00
|
|
|
xy = (GetIndustry(s->from))->xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2006-02-01 06:32:03 +00:00
|
|
|
if (DistanceMax(xy, from->xy) > 9) continue;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* Check distance from dest */
|
2007-03-16 17:40:31 +00:00
|
|
|
switch (cs->town_effect) {
|
|
|
|
case TE_PASSENGERS:
|
|
|
|
case TE_MAIL:
|
|
|
|
case TE_GOODS:
|
|
|
|
case TE_FOOD:
|
2006-02-06 09:18:04 +00:00
|
|
|
xy = GetTown(s->to)->xy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
xy = GetIndustry(s->to)->xy;
|
|
|
|
break;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2006-02-01 06:32:03 +00:00
|
|
|
if (DistanceMax(xy, to->xy) > 9) continue;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
/* Found a subsidy, change the values to indicate that it's in use */
|
|
|
|
s->age = 12;
|
|
|
|
s->from = from->index;
|
|
|
|
s->to = to->index;
|
|
|
|
|
|
|
|
/* Add a news item */
|
|
|
|
pair = SetupSubsidyDecodeParam(s, 0);
|
2005-02-06 08:18:00 +00:00
|
|
|
InjectDParam(2);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2005-06-21 16:28:17 +00:00
|
|
|
p = GetPlayer(_current_player);
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, p->name_1);
|
|
|
|
SetDParam(1, p->name_2);
|
2004-08-09 17:04:08 +00:00
|
|
|
AddNewsItem(
|
2004-09-10 19:02:27 +00:00
|
|
|
STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
|
2004-08-09 17:04:08 +00:00
|
|
|
NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0),
|
2006-02-01 06:32:03 +00:00
|
|
|
pair.a, pair.b
|
|
|
|
);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
InvalidateWindow(WC_SUBSIDIES_LIST, 0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-01-15 14:42:24 +00:00
|
|
|
static int32 DeliverGoods(int num_pieces, CargoID cargo_type, StationID source, StationID dest, TileIndex source_tile, byte days_in_transit)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
bool subsidised;
|
|
|
|
Station *s_from, *s_to;
|
|
|
|
int32 profit;
|
|
|
|
|
2006-06-27 21:25:53 +00:00
|
|
|
assert(num_pieces > 0);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Update player statistics */
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-06-21 16:28:17 +00:00
|
|
|
Player *p = GetPlayer(_current_player);
|
2004-08-09 17:04:08 +00:00
|
|
|
p->cur_economy.delivered_cargo += num_pieces;
|
|
|
|
SETBIT(p->cargo_types, cargo_type);
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Get station pointers. */
|
2005-01-06 22:31:58 +00:00
|
|
|
s_from = GetStation(source);
|
|
|
|
s_to = GetStation(dest);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Check if a subsidy applies. */
|
2004-08-09 17:04:08 +00:00
|
|
|
subsidised = CheckSubsidised(s_from, s_to, cargo_type);
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Increase town's counter for some special goods types */
|
2007-03-16 17:40:31 +00:00
|
|
|
const CargoSpec *cs = GetCargo(cargo_type);
|
|
|
|
if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
|
|
|
|
if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Give the goods to the industry. */
|
2004-08-09 17:04:08 +00:00
|
|
|
DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Determine profit */
|
2007-01-15 14:42:24 +00:00
|
|
|
profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Modify profit if a subsidy is in effect */
|
2004-08-09 17:04:08 +00:00
|
|
|
if (subsidised) {
|
2006-02-06 09:18:04 +00:00
|
|
|
switch (_opt.diff.subsidy_multiplier) {
|
2006-04-25 06:56:22 +00:00
|
|
|
case 0: profit += profit >> 1; break;
|
|
|
|
case 1: profit *= 2; break;
|
|
|
|
case 2: profit *= 3; break;
|
|
|
|
default: profit *= 4; break;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return profit;
|
|
|
|
}
|
|
|
|
|
2007-05-01 16:45:03 +00:00
|
|
|
/**
|
|
|
|
* Performs the vehicle payment _and_ marks the vehicle to be unloaded.
|
|
|
|
* @param front_v the vehicle to be unloaded
|
|
|
|
*/
|
2007-05-02 18:29:11 +00:00
|
|
|
void VehiclePayment(Vehicle *front_v)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-05-01 16:45:03 +00:00
|
|
|
int result = 0;
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
int profit = 0;
|
2007-05-01 16:45:03 +00:00
|
|
|
int total_veh_profit = 0; // accumulates the profit across the vehicle chain (used by trains)
|
|
|
|
int32 route_profit = 0; // the grand total amount for the route. A-D of transfer chain A-B-C-D
|
|
|
|
int virtual_profit = 0; // virtual profit of one vehicle element for feeder systems
|
|
|
|
int virtual_profit_total = 0; // virtual profit for entire vehicle chain
|
|
|
|
int total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
|
|
|
|
|
|
|
|
int all_vehicles_cargo_feeder_share = front_v->cargo_feeder_share; // used to hold transfer value of complete vehicle chain - used by trains
|
|
|
|
|
|
|
|
StationID last_visited = front_v->last_station_visited;
|
|
|
|
Station *st = GetStation(last_visited);
|
|
|
|
|
2007-05-02 18:29:11 +00:00
|
|
|
/* The owner of the train wants to be paid */
|
|
|
|
PlayerID old_player = _current_player;
|
|
|
|
_current_player = front_v->owner;
|
|
|
|
|
|
|
|
/* At this moment loading cannot be finished */
|
|
|
|
CLRBIT(front_v->vehicle_flags, VF_LOADING_FINISHED);
|
|
|
|
|
|
|
|
/* Start unloading in at the first possible moment */
|
|
|
|
front_v->load_unload_time_rem = 1;
|
|
|
|
|
2007-05-01 16:45:03 +00:00
|
|
|
for (Vehicle *v = front_v; v != NULL; v = v->next) {
|
2007-05-02 18:29:11 +00:00
|
|
|
/* No cargo to unload */
|
2007-05-13 21:24:58 +00:00
|
|
|
if (v->cargo_cap == 0 || v->cargo_count == 0) continue;
|
2007-05-01 16:45:03 +00:00
|
|
|
|
|
|
|
SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
|
2007-05-02 18:29:11 +00:00
|
|
|
/* All cargo has already been paid for, no need to pay again */
|
2007-05-01 16:45:03 +00:00
|
|
|
if (v->cargo_count == v->cargo_paid_for) continue;
|
|
|
|
|
|
|
|
GoodsEntry *ge = &st->goods[v->cargo_type];
|
|
|
|
|
|
|
|
if (v->cargo_source != last_visited &&
|
|
|
|
HASBIT(ge->waiting_acceptance, 15) &&
|
|
|
|
(front_v->current_order.flags & OF_TRANSFER) == 0) {
|
|
|
|
/* Deliver goods to the station */
|
|
|
|
st->time_since_unload = 0;
|
|
|
|
|
|
|
|
/* handle end of route payment */
|
|
|
|
profit += DeliverGoods(v->cargo_count - v->cargo_paid_for, v->cargo_type, v->cargo_source, last_visited, v->cargo_source_xy, v->cargo_days);
|
|
|
|
v->cargo_paid_for = v->cargo_count;
|
|
|
|
route_profit = profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
|
|
|
|
total_veh_profit = profit - all_vehicles_cargo_feeder_share; // whole vehicle is not payed for transfers picked up earlier
|
|
|
|
total_cargo_feeder_share = -all_vehicles_cargo_feeder_share; // total of transfer fees in vehicle chain needs to be zero at end of unload
|
|
|
|
|
|
|
|
v->cargo_feeder_share = 0; // clear transfer cost per vehicle
|
|
|
|
result |= 1;
|
|
|
|
} else if (front_v->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
|
|
|
|
if ((front_v->current_order.flags & OF_TRANSFER) != 0) {
|
|
|
|
virtual_profit = GetTransportedGoodsIncome(
|
|
|
|
v->cargo_count - v->cargo_paid_for,
|
|
|
|
/* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
|
|
|
|
DistanceManhattan(v->cargo_loaded_at_xy, GetStation(last_visited)->xy),
|
|
|
|
v->cargo_days,
|
|
|
|
v->cargo_type);
|
|
|
|
|
2007-05-08 16:42:48 +00:00
|
|
|
front_v->profit_this_year += virtual_profit;
|
|
|
|
ge->feeder_profit += v->cargo_feeder_share + virtual_profit; // transfer cargo transfer fees to station
|
|
|
|
total_cargo_feeder_share -= v->cargo_feeder_share; // accumulate deduction of feeder shares
|
|
|
|
v->cargo_feeder_share = 0; // clear transfer cost
|
2007-05-01 16:45:03 +00:00
|
|
|
|
|
|
|
/* keep total of cargo unloaded (pending) for accurate cargoshare calculation on load */
|
|
|
|
SB(ge->unload_pending, 0, 12, GB(ge->unload_pending, 0, 12) + v->cargo_count);
|
|
|
|
|
|
|
|
virtual_profit_total += virtual_profit; // accumulate transfer profits for whole vehicle
|
|
|
|
v->cargo_paid_for = v->cargo_count; // record how much of the cargo has been paid for to eliminate double counting
|
|
|
|
}
|
|
|
|
result |= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure a negative total is only applied to the vehicle if there is value to reduce. */
|
|
|
|
front_v->cargo_feeder_share = max(front_v->cargo_feeder_share + total_cargo_feeder_share, 0);
|
|
|
|
|
|
|
|
if (virtual_profit_total > 0) {
|
|
|
|
ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit_total);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (route_profit != 0) {
|
|
|
|
front_v->profit_this_year += total_veh_profit;
|
|
|
|
SubtractMoneyFromPlayer(-route_profit);
|
|
|
|
|
|
|
|
if (IsLocalPlayer() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
|
|
|
|
SndPlayVehicleFx(SND_14_CASHTILL, front_v);
|
|
|
|
}
|
|
|
|
|
|
|
|
ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -total_veh_profit);
|
|
|
|
}
|
|
|
|
|
2007-05-02 18:29:11 +00:00
|
|
|
_current_player = old_player;
|
2007-05-01 16:45:03 +00:00
|
|
|
}
|
2007-03-02 18:49:11 +00:00
|
|
|
|
2007-05-06 14:59:01 +00:00
|
|
|
/**
|
|
|
|
* Loads/unload the vehicle if possible.
|
|
|
|
* @param v the vehicle to be (un)loaded
|
2007-05-14 20:12:32 +00:00
|
|
|
* @param cargo_left the amount of each cargo type that is
|
|
|
|
* virtually left on the platform to be
|
|
|
|
* picked up by another vehicle when all
|
|
|
|
* previous vehicles have loaded.
|
2007-05-06 14:59:01 +00:00
|
|
|
*/
|
2007-05-14 20:12:32 +00:00
|
|
|
static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
2007-05-01 16:45:03 +00:00
|
|
|
{
|
2007-05-14 16:07:05 +00:00
|
|
|
assert(v->current_order.type == OT_LOADING);
|
|
|
|
|
|
|
|
/* We have not waited enough time till the next round of loading/unloading */
|
2007-05-14 20:12:32 +00:00
|
|
|
if (--v->load_unload_time_rem != 0) {
|
|
|
|
if (_patches.improved_load && HASBIT(v->current_order.flags, OFB_FULL_LOAD)) {
|
|
|
|
/* 'Reserve' this cargo for this vehicle, because we were first. */
|
|
|
|
for (; v != NULL; v = v->next) {
|
|
|
|
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2007-05-14 16:07:05 +00:00
|
|
|
|
2007-05-13 21:24:58 +00:00
|
|
|
int unloading_time = 0;
|
2004-08-09 17:04:08 +00:00
|
|
|
Vehicle *u = v;
|
|
|
|
int result = 0;
|
2007-05-15 06:20:16 +00:00
|
|
|
int cap;
|
2007-05-02 18:29:11 +00:00
|
|
|
|
2007-05-13 21:24:58 +00:00
|
|
|
bool completely_empty = true;
|
|
|
|
bool anything_unloaded = false;
|
|
|
|
bool anything_loaded = false;
|
|
|
|
uint32 cargo_not_full = 0;
|
|
|
|
uint32 cargo_full = 0;
|
2007-05-01 16:45:03 +00:00
|
|
|
int total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
v->cur_speed = 0;
|
2006-12-05 17:53:33 +00:00
|
|
|
|
2007-03-02 18:49:11 +00:00
|
|
|
StationID last_visited = v->last_station_visited;
|
|
|
|
Station *st = GetStation(last_visited);
|
|
|
|
|
2004-11-24 12:47:25 +00:00
|
|
|
for (; v != NULL; v = v->next) {
|
2007-05-12 09:09:10 +00:00
|
|
|
if (v->cargo_cap == 0) continue;
|
|
|
|
|
|
|
|
byte load_amount = EngInfo(v->engine_type)->load_amount;
|
2007-03-06 19:12:56 +00:00
|
|
|
if (_patches.gradual_loading && HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_LOAD_AMOUNT)) {
|
2006-12-02 16:56:32 +00:00
|
|
|
uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v);
|
|
|
|
if (cb_load_amount != CALLBACK_FAILED) load_amount = cb_load_amount & 0xFF;
|
|
|
|
}
|
2005-11-14 19:48:04 +00:00
|
|
|
|
2007-05-12 09:09:10 +00:00
|
|
|
GoodsEntry *ge = &st->goods[v->cargo_type];
|
2007-05-15 06:20:16 +00:00
|
|
|
int count = GB(ge->waiting_acceptance, 0, 12);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-05-12 09:09:10 +00:00
|
|
|
if (HASBIT(v->vehicle_flags, VF_CARGO_UNLOADING)) {
|
2006-12-05 17:53:33 +00:00
|
|
|
uint16 amount_unloaded = _patches.gradual_loading ? min(v->cargo_count, load_amount) : v->cargo_count;
|
|
|
|
|
2005-11-14 19:48:04 +00:00
|
|
|
if (v->cargo_source != last_visited && ge->waiting_acceptance & 0x8000 && !(u->current_order.flags & OF_TRANSFER)) {
|
2006-12-05 17:53:33 +00:00
|
|
|
result |= 1;
|
2005-11-14 19:48:04 +00:00
|
|
|
} else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
|
2007-05-12 09:09:10 +00:00
|
|
|
if (count == 0) {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* No goods waiting at station */
|
2007-05-12 09:09:10 +00:00
|
|
|
ge->enroute_time = v->cargo_days;
|
|
|
|
ge->enroute_from = v->cargo_source;
|
2007-01-15 14:42:24 +00:00
|
|
|
ge->enroute_from_xy = v->cargo_source_xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
} else {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Goods already waiting at station. Set counters to the worst value. */
|
2007-01-15 14:42:24 +00:00
|
|
|
if (v->cargo_days >= ge->enroute_time) ge->enroute_time = v->cargo_days;
|
|
|
|
|
|
|
|
if (last_visited != ge->enroute_from) {
|
2007-05-12 09:09:10 +00:00
|
|
|
ge->enroute_from = v->cargo_source;
|
2007-01-15 14:42:24 +00:00
|
|
|
ge->enroute_from_xy = v->cargo_source_xy;
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2007-05-12 09:09:10 +00:00
|
|
|
/* Update amount of waiting cargo. There is, however, no sense in
|
|
|
|
* updating the count variable because this vehicle will not be
|
|
|
|
* able to take the cargo. */
|
|
|
|
SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + count, 0xFFF));
|
2006-10-11 18:57:02 +00:00
|
|
|
|
2007-03-02 18:49:11 +00:00
|
|
|
/* if there is not enough to unload from pending, ensure it does not go -ve
|
|
|
|
* else deduct amount actually unloaded from unload_pending */
|
2007-03-02 18:57:54 +00:00
|
|
|
SB(ge->unload_pending, 0, 12, max(GB(ge->unload_pending, 0, 12) - amount_unloaded, 0U));
|
2007-03-02 18:49:11 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
result |= 2;
|
2007-05-12 09:09:10 +00:00
|
|
|
} else {
|
|
|
|
/* The order changed while unloading (unset unload/transfer) or the
|
|
|
|
* station does not accept goods anymore. */
|
|
|
|
CLRBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
|
|
|
|
continue;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2004-11-17 08:52:47 +00:00
|
|
|
|
2007-05-12 09:09:10 +00:00
|
|
|
/* Deliver goods to the station */
|
|
|
|
st->time_since_unload = 0;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-05-12 09:09:10 +00:00
|
|
|
unloading_time += amount_unloaded;
|
|
|
|
|
|
|
|
v->cargo_count -= amount_unloaded;
|
|
|
|
v->cargo_paid_for -= min(amount_unloaded, v->cargo_paid_for);
|
|
|
|
|
2007-05-13 21:24:58 +00:00
|
|
|
anything_unloaded = true;
|
2007-05-12 09:09:10 +00:00
|
|
|
if (_patches.gradual_loading && v->cargo_count != 0) {
|
|
|
|
completely_empty = false;
|
|
|
|
} else {
|
|
|
|
/* We have finished unloading (cargo count == 0) */
|
|
|
|
CLRBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2007-01-31 22:33:24 +00:00
|
|
|
|
|
|
|
/* We cannot have paid for more cargo than there is on board. */
|
|
|
|
assert(v->cargo_paid_for <= v->cargo_count);
|
2006-12-05 17:53:33 +00:00
|
|
|
|
2007-05-12 09:09:10 +00:00
|
|
|
/* Do not pick up goods that we unloaded */
|
2006-12-05 17:53:33 +00:00
|
|
|
if (u->current_order.flags & OF_UNLOAD) continue;
|
2006-12-02 16:56:32 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* update stats */
|
2007-05-12 09:09:10 +00:00
|
|
|
int t;
|
2006-02-06 09:18:04 +00:00
|
|
|
switch (u->type) {
|
2007-03-08 16:27:54 +00:00
|
|
|
case VEH_TRAIN: t = u->u.rail.cached_max_speed; break;
|
|
|
|
case VEH_ROAD: t = u->max_speed / 2; break;
|
2006-02-06 09:18:04 +00:00
|
|
|
default: t = u->max_speed; break;
|
|
|
|
}
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
|
2007-05-12 09:09:10 +00:00
|
|
|
ge->days_since_pickup = 0;
|
2006-02-06 09:18:04 +00:00
|
|
|
ge->last_speed = min(t, 255);
|
2006-08-20 19:05:28 +00:00
|
|
|
ge->last_age = _cur_year - v->build_year;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* If there's goods waiting at the station, and the vehicle
|
|
|
|
* has capacity for it, load it on the vehicle. */
|
2005-10-11 13:54:21 +00:00
|
|
|
if (count != 0 &&
|
2004-08-09 17:04:08 +00:00
|
|
|
(cap = v->cargo_cap - v->cargo_count) != 0) {
|
2005-06-15 16:58:15 +00:00
|
|
|
|
2004-11-29 11:59:09 +00:00
|
|
|
/* Skip loading this vehicle if another train/vehicle is already handling
|
|
|
|
* the same cargo type at this station */
|
2007-05-14 20:12:32 +00:00
|
|
|
if (_patches.improved_load && cargo_left[v->cargo_type] < 0) {
|
2007-05-13 21:24:58 +00:00
|
|
|
SETBIT(cargo_not_full, v->cargo_type);
|
2007-05-02 18:29:11 +00:00
|
|
|
continue;
|
|
|
|
}
|
2004-11-29 11:59:09 +00:00
|
|
|
|
2007-05-14 20:12:32 +00:00
|
|
|
if (cap > count) cap = count;
|
|
|
|
if (_patches.gradual_loading) cap = min(cap, load_amount);
|
|
|
|
if (_patches.improved_load) {
|
|
|
|
/* Don't load stuff that is already 'reserved' for other vehicles */
|
|
|
|
cap = min(cargo_left[v->cargo_type], cap);
|
|
|
|
cargo_left[v->cargo_type] -= cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v->cargo_count == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
|
|
|
|
|
2004-11-17 08:52:47 +00:00
|
|
|
/* TODO: Regarding this, when we do gradual loading, we
|
|
|
|
* should first unload all vehicles and then start
|
|
|
|
* loading them. Since this will cause
|
|
|
|
* VEHICLE_TRIGGER_EMPTY to be called at the time when
|
|
|
|
* the whole vehicle chain is really totally empty, the
|
2007-02-23 18:55:07 +00:00
|
|
|
* completely_empty assignment can then be safely
|
2004-11-17 08:52:47 +00:00
|
|
|
* removed; that's how TTDPatch behaves too. --pasky */
|
|
|
|
completely_empty = false;
|
2006-12-05 17:53:33 +00:00
|
|
|
anything_loaded = true;
|
2004-11-17 08:52:47 +00:00
|
|
|
|
2007-03-02 18:49:11 +00:00
|
|
|
/* cargoshare is proportioned by the amount due to unload
|
|
|
|
* Otherwise, with gradual loading, 100% of credits would be taken immediately,
|
|
|
|
* even if the cargo volume represents a tiny percent of the whole.
|
|
|
|
* ge->unload_pending holds the amount that has been credited, but has not yet been unloaded.
|
|
|
|
*/
|
|
|
|
int cargoshare = cap * 10000 / (ge->waiting_acceptance + ge->unload_pending);
|
|
|
|
int feeder_profit_share = ge->feeder_profit * cargoshare / 10000;
|
2004-08-09 17:04:08 +00:00
|
|
|
v->cargo_count += cap;
|
|
|
|
ge->waiting_acceptance -= cap;
|
2007-03-02 18:49:11 +00:00
|
|
|
|
|
|
|
total_cargo_feeder_share += feeder_profit_share; // store cost for later payment when cargo unloaded
|
|
|
|
v->cargo_loaded_at_xy = st->xy; // retains location of where the cargo was picked up for intermediate payments
|
|
|
|
|
2005-06-15 16:58:15 +00:00
|
|
|
ge->feeder_profit -= feeder_profit_share;
|
2004-08-09 17:04:08 +00:00
|
|
|
unloading_time += cap;
|
|
|
|
st->time_since_load = 0;
|
2004-09-10 19:02:27 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* And record the source of the cargo, and the days in travel. */
|
2006-01-05 11:18:58 +00:00
|
|
|
v->cargo_source = ge->enroute_from;
|
2007-01-15 14:42:24 +00:00
|
|
|
v->cargo_source_xy = ge->enroute_from_xy;
|
2004-08-09 17:04:08 +00:00
|
|
|
v->cargo_days = ge->enroute_time;
|
|
|
|
result |= 2;
|
2006-04-18 08:50:17 +00:00
|
|
|
st->last_vehicle_type = v->type;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
2007-05-13 21:24:58 +00:00
|
|
|
|
|
|
|
if (v->cargo_count == v->cargo_cap) {
|
|
|
|
SETBIT(cargo_full, v->cargo_type);
|
|
|
|
} else {
|
|
|
|
SETBIT(cargo_not_full, v->cargo_type);
|
|
|
|
}
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-05-14 20:12:32 +00:00
|
|
|
/* We update these variables here, so gradual loading still fills
|
|
|
|
* all wagons at the same time instead of using the same 'improved'
|
|
|
|
* loading algorithm for the wagons (only fill wagon when there is
|
|
|
|
* enough to fill the previous wagons) */
|
|
|
|
if (_patches.improved_load && HASBIT(u->current_order.flags, OFB_FULL_LOAD)) {
|
|
|
|
/* Update left cargo */
|
|
|
|
for (v = u; v != NULL; v = v->next) {
|
|
|
|
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
v = u;
|
|
|
|
|
2007-05-01 16:45:03 +00:00
|
|
|
v->cargo_feeder_share += total_cargo_feeder_share;
|
2007-03-02 18:49:11 +00:00
|
|
|
|
2007-05-13 21:24:58 +00:00
|
|
|
if (anything_loaded || anything_unloaded) {
|
|
|
|
if (_patches.gradual_loading) {
|
|
|
|
/* The time it takes to load one 'slice' of cargo or passengers depends
|
|
|
|
* on the vehicle type - the values here are those found in TTDPatch */
|
|
|
|
const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
|
2006-12-02 16:56:32 +00:00
|
|
|
|
2007-05-13 21:24:58 +00:00
|
|
|
unloading_time = gradual_loading_wait_time[v->type];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool finished_loading = true;
|
|
|
|
if (HASBIT(v->current_order.flags, OFB_FULL_LOAD)) {
|
|
|
|
if (_patches.full_load_any) {
|
|
|
|
/* if the aircraft carries passengers and is NOT full, then
|
|
|
|
* continue loading, no matter how much mail is in */
|
|
|
|
if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo_count) ||
|
|
|
|
(cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
|
|
|
|
finished_loading = false;
|
|
|
|
}
|
|
|
|
} else if (cargo_not_full != 0) {
|
|
|
|
finished_loading = false;
|
2006-12-05 17:53:33 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-13 21:24:58 +00:00
|
|
|
unloading_time = 20;
|
|
|
|
|
|
|
|
SB(v->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
|
2006-12-02 16:56:32 +00:00
|
|
|
}
|
|
|
|
|
2007-03-08 16:27:54 +00:00
|
|
|
if (v->type == VEH_TRAIN) {
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Each platform tile is worth 2 rail vehicles. */
|
2007-02-13 16:36:38 +00:00
|
|
|
int overhang = v->u.rail.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
|
2005-11-03 09:22:24 +00:00
|
|
|
if (overhang > 0) {
|
|
|
|
unloading_time <<= 1;
|
|
|
|
unloading_time += (overhang * unloading_time) / 8;
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v->load_unload_time_rem = unloading_time;
|
|
|
|
|
2004-11-17 08:52:47 +00:00
|
|
|
if (completely_empty) {
|
|
|
|
TriggerVehicle(v, VEHICLE_TRIGGER_EMPTY);
|
|
|
|
}
|
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
if (result != 0) {
|
2007-05-02 18:29:11 +00:00
|
|
|
InvalidateWindow(v->GetVehicleListWindowClass(), v->owner);
|
2004-08-09 17:04:08 +00:00
|
|
|
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
2007-05-02 18:29:11 +00:00
|
|
|
|
2007-01-14 19:18:50 +00:00
|
|
|
st->MarkTilesDirty();
|
2007-05-02 18:29:11 +00:00
|
|
|
v->MarkDirty();
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2006-02-01 06:32:03 +00:00
|
|
|
if (result & 2) InvalidateWindow(WC_STATION_VIEW, last_visited);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-14 16:07:05 +00:00
|
|
|
/**
|
|
|
|
* Load/unload the vehicles in this station according to the order
|
|
|
|
* they entered.
|
|
|
|
* @param st the station to do the loading/unloading for
|
|
|
|
*/
|
|
|
|
void LoadUnloadStation(Station *st)
|
|
|
|
{
|
2007-05-14 20:12:32 +00:00
|
|
|
int cargo_left[NUM_CARGO];
|
|
|
|
|
|
|
|
for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = GB(st->goods[i].waiting_acceptance, 0, 12);
|
|
|
|
|
2007-05-14 16:07:05 +00:00
|
|
|
std::list<Vehicle *>::iterator iter;
|
|
|
|
for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
|
|
|
|
Vehicle *v = *iter;
|
2007-05-14 20:12:32 +00:00
|
|
|
if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) LoadUnloadVehicle(v, cargo_left);
|
2007-05-14 16:07:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-07 11:47:46 +00:00
|
|
|
void PlayersMonthlyLoop()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
PlayersGenStatistics();
|
2006-08-16 11:39:55 +00:00
|
|
|
if (_patches.inflation && _cur_year < MAX_YEAR)
|
2004-08-09 17:04:08 +00:00
|
|
|
AddInflation();
|
|
|
|
PlayersPayInterest();
|
2007-02-23 18:55:07 +00:00
|
|
|
/* Reset the _current_player flag */
|
2004-09-11 19:34:11 +00:00
|
|
|
_current_player = OWNER_NONE;
|
2004-08-09 17:04:08 +00:00
|
|
|
HandleEconomyFluctuations();
|
|
|
|
SubsidyMonthlyHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DoAcquireCompany(Player *p)
|
|
|
|
{
|
|
|
|
Player *owner;
|
2007-01-10 18:56:51 +00:00
|
|
|
int i;
|
2004-09-11 09:40:19 +00:00
|
|
|
int64 value;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2004-12-02 22:53:07 +00:00
|
|
|
SetDParam(0, p->name_1);
|
|
|
|
SetDParam(1, p->name_2);
|
|
|
|
SetDParam(2, p->bankrupt_value);
|
2006-10-17 17:59:41 +00:00
|
|
|
AddNewsItem( (StringID)(_current_player | NB_BMERGER), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/* original code does this a little bit differently */
|
2007-01-10 18:56:51 +00:00
|
|
|
PlayerID pi = p->index;
|
2007-03-08 21:05:05 +00:00
|
|
|
ChangeNetworkOwner(pi, _current_player);
|
2004-08-09 17:04:08 +00:00
|
|
|
ChangeOwnershipOfPlayerItems(pi, _current_player);
|
|
|
|
|
|
|
|
if (p->bankrupt_value == 0) {
|
2005-06-21 16:28:17 +00:00
|
|
|
owner = GetPlayer(_current_player);
|
2004-08-09 17:04:08 +00:00
|
|
|
owner->current_loan += p->current_loan;
|
|
|
|
}
|
|
|
|
|
|
|
|
value = CalculateCompanyValue(p) >> 2;
|
2006-02-01 07:36:15 +00:00
|
|
|
for (i = 0; i != 4; i++) {
|
2006-10-14 15:49:43 +00:00
|
|
|
if (p->share_owners[i] != PLAYER_SPECTATOR) {
|
2005-06-21 16:28:17 +00:00
|
|
|
owner = GetPlayer(p->share_owners[i]);
|
2004-08-09 17:04:08 +00:00
|
|
|
owner->money64 += value;
|
|
|
|
owner->yearly_expenses[0][EXPENSES_OTHER] += value;
|
|
|
|
UpdatePlayerMoney32(owner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p->is_active = false;
|
|
|
|
|
|
|
|
DeletePlayerWindows(pi);
|
2006-08-28 18:53:03 +00:00
|
|
|
RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-01-10 18:56:51 +00:00
|
|
|
extern int GetAmountOwnedBy(const Player *p, PlayerID owner);
|
2004-12-12 14:00:25 +00:00
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
/** Acquire shares in an opposing company.
|
2006-04-10 07:15:58 +00:00
|
|
|
* @param tile unused
|
2007-04-06 04:10:19 +00:00
|
|
|
* @param flags type of operation
|
2005-05-12 00:11:37 +00:00
|
|
|
* @param p1 player to buy the shares from
|
|
|
|
* @param p2 unused
|
|
|
|
*/
|
2006-04-10 07:15:58 +00:00
|
|
|
int32 CmdBuyShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Player *p;
|
2004-09-11 09:40:19 +00:00
|
|
|
int64 cost;
|
2005-05-12 00:11:37 +00:00
|
|
|
|
|
|
|
/* Check if buying shares is allowed (protection against modified clients */
|
2006-10-14 22:31:18 +00:00
|
|
|
if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
2007-01-10 18:56:51 +00:00
|
|
|
p = GetPlayer((PlayerID)p1);
|
2005-01-15 08:58:31 +00:00
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
/* Protect new companies from hostile takeovers */
|
2006-08-20 19:05:28 +00:00
|
|
|
if (_cur_year - p->inaugurated_year < 6) return_cmd_error(STR_7080_PROTECTED);
|
2005-01-07 23:59:59 +00:00
|
|
|
|
2004-12-12 14:00:25 +00:00
|
|
|
/* Those lines are here for network-protection (clients can be slow) */
|
2006-10-14 15:49:43 +00:00
|
|
|
if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0) return 0;
|
2005-01-07 23:59:59 +00:00
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
/* We can not buy out a real player (temporarily). TODO: well, enable it obviously */
|
2006-10-14 15:49:43 +00:00
|
|
|
if (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) return 0;
|
2005-01-15 08:58:31 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
cost = CalculateCompanyValue(p) >> 2;
|
|
|
|
if (flags & DC_EXEC) {
|
2007-01-10 18:56:51 +00:00
|
|
|
PlayerByte* b = p->share_owners;
|
2005-05-12 00:11:37 +00:00
|
|
|
int i;
|
|
|
|
|
2006-10-14 15:49:43 +00:00
|
|
|
while (*b != PLAYER_SPECTATOR) b++; /* share owners is guaranteed to contain at least one PLAYER_SPECTATOR */
|
2004-08-09 17:04:08 +00:00
|
|
|
*b = _current_player;
|
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
for (i = 0; p->share_owners[i] == _current_player;) {
|
2004-08-09 17:04:08 +00:00
|
|
|
if (++i == 4) {
|
|
|
|
p->bankrupt_value = 0;
|
|
|
|
DoAcquireCompany(p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-02-13 21:15:00 +00:00
|
|
|
InvalidateWindow(WC_COMPANY, p1);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
/** Sell shares in an opposing company.
|
2006-04-10 07:15:58 +00:00
|
|
|
* @param tile unused
|
2007-04-06 04:10:19 +00:00
|
|
|
* @param flags type of operation
|
2005-05-12 00:11:37 +00:00
|
|
|
* @param p1 player to sell the shares from
|
|
|
|
* @param p2 unused
|
|
|
|
*/
|
2006-04-10 07:15:58 +00:00
|
|
|
int32 CmdSellShareInCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Player *p;
|
2004-09-11 09:40:19 +00:00
|
|
|
int64 cost;
|
2005-05-12 00:11:37 +00:00
|
|
|
|
|
|
|
/* Check if buying shares is allowed (protection against modified clients */
|
2006-10-14 22:31:18 +00:00
|
|
|
if (!IsValidPlayer((PlayerID)p1) || !_patches.allow_shares) return CMD_ERROR;
|
2004-08-09 17:04:08 +00:00
|
|
|
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
2007-01-10 18:56:51 +00:00
|
|
|
p = GetPlayer((PlayerID)p1);
|
2004-08-09 17:04:08 +00:00
|
|
|
|
2004-12-14 18:17:24 +00:00
|
|
|
/* Those lines are here for network-protection (clients can be slow) */
|
2005-05-12 00:11:37 +00:00
|
|
|
if (GetAmountOwnedBy(p, _current_player) == 0) return 0;
|
2004-12-14 18:17:24 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
/* adjust it a little to make it less profitable to sell and buy */
|
|
|
|
cost = CalculateCompanyValue(p) >> 2;
|
|
|
|
cost = -(cost - (cost >> 7));
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
2007-01-10 18:56:51 +00:00
|
|
|
PlayerByte* b = p->share_owners;
|
2007-02-23 18:55:07 +00:00
|
|
|
while (*b != _current_player) b++; // share owners is guaranteed to contain player
|
2006-10-14 15:49:43 +00:00
|
|
|
*b = PLAYER_SPECTATOR;
|
2006-02-13 21:15:00 +00:00
|
|
|
InvalidateWindow(WC_COMPANY, p1);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
2005-05-12 00:11:37 +00:00
|
|
|
/** Buy up another company.
|
|
|
|
* When a competing company is gone bankrupt you get the chance to purchase
|
|
|
|
* that company.
|
|
|
|
* @todo currently this only works for AI players
|
2006-04-10 07:15:58 +00:00
|
|
|
* @param tile unused
|
2007-04-06 04:10:19 +00:00
|
|
|
* @param flags type of operation
|
2005-05-12 00:11:37 +00:00
|
|
|
* @param p1 player/company to buy up
|
|
|
|
* @param p2 unused
|
|
|
|
*/
|
2006-04-10 07:15:58 +00:00
|
|
|
int32 CmdBuyCompany(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
|
|
|
Player *p;
|
2007-04-01 10:55:31 +00:00
|
|
|
PlayerID pid = (PlayerID)p1;
|
2005-05-12 00:11:37 +00:00
|
|
|
|
|
|
|
/* Disable takeovers in multiplayer games */
|
2007-04-01 10:55:31 +00:00
|
|
|
if (!IsValidPlayer(pid) || _networking) return CMD_ERROR;
|
|
|
|
|
|
|
|
/* Do not allow players to take over themselves */
|
|
|
|
if (pid == _current_player) return CMD_ERROR;
|
2005-05-12 00:11:37 +00:00
|
|
|
|
2004-08-09 17:04:08 +00:00
|
|
|
SET_EXPENSES_TYPE(EXPENSES_OTHER);
|
2007-04-01 10:55:31 +00:00
|
|
|
p = GetPlayer(pid);
|
2005-05-12 00:11:37 +00:00
|
|
|
|
|
|
|
if (!p->is_ai) return CMD_ERROR;
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
2004-08-09 17:04:08 +00:00
|
|
|
DoAcquireCompany(p);
|
|
|
|
}
|
|
|
|
return p->bankrupt_value;
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/** Prices */
|
2007-03-07 11:47:46 +00:00
|
|
|
static void SaveLoad_PRIC()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2006-08-22 14:38:37 +00:00
|
|
|
SlArray(&_price, NUM_PRICES, SLE_INT32);
|
2004-08-09 17:04:08 +00:00
|
|
|
SlArray(&_price_frac, NUM_PRICES, SLE_UINT16);
|
|
|
|
}
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/** Cargo payment rates */
|
2007-03-07 11:47:46 +00:00
|
|
|
static void SaveLoad_CAPR()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2007-04-15 16:20:35 +00:00
|
|
|
uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
|
|
|
|
SlArray(&_cargo_payment_rates, num_cargo, SLE_INT32);
|
|
|
|
SlArray(&_cargo_payment_rates_frac, num_cargo, SLE_UINT16);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2005-05-30 22:16:05 +00:00
|
|
|
static const SaveLoad _economy_desc[] = {
|
2006-08-22 14:38:37 +00:00
|
|
|
SLE_VAR(Economy, max_loan, SLE_INT32),
|
|
|
|
SLE_VAR(Economy, max_loan_unround, SLE_INT32),
|
|
|
|
SLE_VAR(Economy, fluct, SLE_FILE_I16 | SLE_VAR_I32),
|
|
|
|
SLE_VAR(Economy, interest_rate, SLE_UINT8),
|
|
|
|
SLE_VAR(Economy, infl_amount, SLE_UINT8),
|
|
|
|
SLE_VAR(Economy, infl_amount_pr, SLE_UINT8),
|
2004-08-09 17:04:08 +00:00
|
|
|
SLE_END()
|
|
|
|
};
|
|
|
|
|
2007-02-23 18:55:07 +00:00
|
|
|
/** Economy variables */
|
2007-03-07 11:47:46 +00:00
|
|
|
static void SaveLoad_ECMY()
|
2004-08-09 17:04:08 +00:00
|
|
|
{
|
2005-05-30 22:16:05 +00:00
|
|
|
SlObject(&_economy, _economy_desc);
|
2004-08-09 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
2007-01-10 18:56:51 +00:00
|
|
|
extern const ChunkHandler _economy_chunk_handlers[] = {
|
2004-08-09 17:04:08 +00:00
|
|
|
{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, CH_RIFF | CH_AUTO_LENGTH},
|
|
|
|
{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, CH_RIFF | CH_AUTO_LENGTH},
|
2006-08-22 14:38:37 +00:00
|
|
|
{ 'SUBS', Save_SUBS, Load_SUBS, CH_ARRAY},
|
2004-08-09 17:04:08 +00:00
|
|
|
{ 'ECMY', SaveLoad_ECMY, SaveLoad_ECMY, CH_RIFF | CH_LAST},
|
|
|
|
};
|