2005-07-24 14:12:37 +00:00
/* $Id$ */
2009-08-21 20:21:05 +00:00
/*
* This file is part of OpenTTD .
* OpenTTD is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , version 2.
* OpenTTD is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with OpenTTD . If not , see < http : //www.gnu.org/licenses/>.
*/
2008-05-06 15:11:33 +00:00
/** @file economy.cpp Handling of the economy. */
2007-02-23 18:55:07 +00:00
2004-08-09 17:04:08 +00:00
# include "stdafx.h"
2008-09-30 20:51:04 +00:00
# include "company_func.h"
2007-12-21 21:50:46 +00:00
# include "command_func.h"
2009-08-30 11:47:41 +00:00
# include "industry.h"
2004-08-09 17:04:08 +00:00
# include "town.h"
2008-03-28 08:53:36 +00:00
# include "news_func.h"
2007-01-02 17:34:03 +00:00
# include "network/network.h"
2008-05-30 18:20:26 +00:00
# include "network/network_func.h"
2009-01-12 17:11:45 +00:00
# include "ai/ai.hpp"
2007-01-27 12:29:55 +00:00
# include "aircraft.h"
2011-01-22 14:52:20 +00:00
# include "newgrf_engine.h"
# include "engine_base.h"
# include "ground_vehicle.hpp"
2009-11-05 19:46:17 +00:00
# include "newgrf_cargo.h"
2006-10-01 17:56:38 +00:00
# include "newgrf_sound.h"
2007-07-11 15:03:29 +00:00
# include "newgrf_industrytiles.h"
2008-04-19 23:19:12 +00:00
# include "newgrf_station.h"
2010-02-22 14:16:57 +00:00
# include "newgrf_airporttiles.h"
2010-08-08 10:59:30 +00:00
# include "object.h"
2007-12-21 19:49:27 +00:00
# include "strings_func.h"
2007-12-26 13:50:40 +00:00
# include "date_func.h"
2007-12-27 13:35:39 +00:00
# include "vehicle_func.h"
2007-12-29 09:24:26 +00:00
# include "sound_func.h"
2008-04-26 14:20:39 +00:00
# include "autoreplace_func.h"
2008-09-30 20:51:04 +00:00
# include "company_gui.h"
2008-09-16 20:57:49 +00:00
# include "signs_base.h"
2009-07-01 18:45:05 +00:00
# include "subsidy_base.h"
2009-05-23 15:46:00 +00:00
# include "subsidy_func.h"
2009-06-24 17:39:54 +00:00
# include "station_base.h"
2009-07-22 10:18:19 +00:00
# include "waypoint_base.h"
2009-06-28 15:12:59 +00:00
# include "economy_base.h"
2009-06-29 19:55:36 +00:00
# include "core/pool_func.hpp"
2010-05-31 20:22:57 +00:00
# include "core/backup_type.hpp"
2013-06-09 13:03:48 +00:00
# include "cargo_type.h"
2011-12-03 23:40:46 +00:00
# include "water.h"
2011-12-19 20:59:36 +00:00
# include "game/game.hpp"
2012-07-15 17:05:17 +00:00
# include "cargomonitor.h"
2013-02-10 19:49:04 +00:00
# include "goal_base.h"
2013-06-09 12:19:09 +00:00
# include "story_base.h"
2013-10-22 18:34:10 +00:00
# include "linkgraph/refresh.h"
2004-08-09 17:04:08 +00:00
2008-01-13 01:21:35 +00:00
# include "table/strings.h"
2009-08-02 12:34:26 +00:00
# include "table/pricebase.h"
2008-01-13 01:21:35 +00:00
2009-06-29 19:55:36 +00:00
/* Initialize the cargo payment-pool */
CargoPaymentPool _cargo_payment_pool ( " CargoPayment " ) ;
INSTANTIATE_POOL_METHODS ( CargoPayment )
2007-11-19 20:18:27 +00:00
/**
* Multiply two integer values and shift the results to right .
*
* This function multiplies two integer values . The result is
* shifted by the amount of shift to right .
*
* @ param a The first integer
* @ param b The second integer
* @ param shift The amount to shift the value to right .
* @ return The shifted result
*/
static inline int32 BigMulS ( const int32 a , const int32 b , const uint8 shift )
{
return ( int32 ) ( ( int64 ) a * ( int64 ) b > > shift ) ;
}
2008-12-20 17:21:22 +00:00
typedef SmallVector < Industry * , 16 > SmallIndustryList ;
2010-07-31 19:45:48 +00:00
/**
* Score info , values used for computing the detailed performance rating .
*/
2005-08-01 16:31:19 +00:00
const ScoreInfo _score_info [ ] = {
2010-07-31 19:45:48 +00:00
{ 120 , 100 } , // SCORE_VEHICLES
{ 80 , 100 } , // SCORE_STATIONS
{ 10000 , 100 } , // SCORE_MIN_PROFIT
{ 50000 , 50 } , // SCORE_MIN_INCOME
{ 100000 , 100 } , // SCORE_MAX_INCOME
{ 40000 , 400 } , // SCORE_DELIVERED
{ 8 , 50 } , // SCORE_CARGO
{ 10000000 , 50 } , // SCORE_MONEY
{ 250000 , 50 } , // SCORE_LOAN
{ 0 , 0 } // SCORE_TOTAL
2005-08-01 16:31:19 +00:00
} ;
2008-09-30 20:39:50 +00:00
int _score_part [ MAX_COMPANIES ] [ SCORE_END ] ;
2007-12-21 21:50:46 +00:00
Economy _economy ;
Prices _price ;
2007-12-21 22:50:51 +00:00
Money _additional_cash_required ;
2009-11-24 13:15:58 +00:00
static PriceMultipliers _price_base_multiplier ;
2005-08-01 16:31:19 +00:00
2010-01-24 11:05:26 +00:00
/**
* Calculate the value of the company . That is the value of all
* assets ( vehicles , stations , etc ) and money minus the loan ,
* except when including_loan is \ c false which is useful when
* we want to calculate the value for bankruptcy .
* @ param c the company to get the value of .
* @ param including_loan include the loan in the company value .
* @ return the value of the company .
*/
Money CalculateCompanyValue ( const Company * c , bool including_loan )
2005-09-30 20:37:25 +00:00
{
2008-09-30 20:39:50 +00:00
Owner owner = c - > index ;
2004-09-10 19:02:27 +00:00
2007-10-21 16:44:19 +00:00
Station * st ;
uint num = 0 ;
2004-08-09 17:04:08 +00:00
2007-10-21 16:44:19 +00:00
FOR_ALL_STATIONS ( st ) {
2009-07-04 11:26:57 +00:00
if ( st - > owner = = owner ) num + = CountBits ( ( byte ) st - > facilities ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-02 20:19:10 +00:00
Money value = num * _price [ PR_STATION_VALUE ] * 25 ;
2004-08-09 17:04:08 +00:00
2007-10-21 16:44:19 +00:00
Vehicle * v ;
FOR_ALL_VEHICLES ( v ) {
if ( v - > owner ! = owner ) continue ;
if ( v - > type = = VEH_TRAIN | |
v - > type = = VEH_ROAD | |
2009-07-13 16:37:27 +00:00
( v - > type = = VEH_AIRCRAFT & & Aircraft : : From ( v ) - > IsNormalAircraft ( ) ) | |
2007-10-21 16:44:19 +00:00
v - > type = = VEH_SHIP ) {
value + = v - > value * 3 > > 1 ;
2004-08-09 17:04:08 +00:00
}
}
2007-06-18 21:44:47 +00:00
/* Add real money value */
2010-01-24 11:05:26 +00:00
if ( including_loan ) value - = c - > current_loan ;
2008-09-30 20:39:50 +00:00
value + = c - > money ;
2005-01-15 08:58:31 +00:00
2007-10-21 16:44:19 +00:00
return max ( value , ( Money ) 1 ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* if update is set to true , the economy is updated with this score
2007-02-23 18:55:07 +00:00
* ( also the house is updated , should only be true in the on - tick event )
* @ param update the economy with calculated score
2008-09-30 20:39:50 +00:00
* @ param c company been evaluated
* @ return actual score of this company
2010-08-01 19:44:49 +00:00
*
*/
2008-09-30 20:39:50 +00:00
int UpdateCompanyRatingAndValue ( Company * c , bool update )
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
Owner owner = c - > 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
2008-09-30 20:39:50 +00:00
/* Count vehicles */
2004-08-09 17:04:08 +00:00
{
Vehicle * v ;
2007-06-21 14:32:27 +00:00
Money min_profit = 0 ;
2006-01-06 22:16:17 +00:00
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 ;
2008-09-30 20:39:50 +00:00
if ( IsCompanyBuildableVehicleType ( v - > type ) & & v - > IsPrimaryVehicle ( ) ) {
2009-09-09 08:22:21 +00:00
if ( v - > profit_last_year > 0 ) num + + ; // For the vehicle score only count profitable vehicles
2004-08-09 17:04:08 +00:00
if ( v - > age > 730 ) {
2006-01-06 22:16:17 +00:00
/* Find the vehicle with the lowest amount of profit */
2008-02-20 17:06:58 +00:00
if ( min_profit_first | | min_profit > v - > profit_last_year ) {
min_profit = v - > profit_last_year ;
2006-01-06 22:16:17 +00:00
min_profit_first = false ;
2006-06-27 21:25:53 +00:00
}
2004-08-09 17:04:08 +00:00
}
}
}
2008-02-20 17:06:58 +00:00
min_profit > > = 8 ; // remove the fract part
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 */
2010-07-24 10:14:39 +00:00
if ( min_profit > 0 ) {
2007-06-21 14:32:27 +00:00
_score_part [ owner ] [ SCORE_MIN_PROFIT ] = ClampToI32 ( min_profit ) ;
2010-07-24 10:14:39 +00:00
}
2004-08-09 17:04:08 +00:00
}
2008-09-30 20:39:50 +00:00
/* Count stations */
2004-08-09 17:04:08 +00:00
{
uint num = 0 ;
2009-01-10 00:31:47 +00:00
const Station * st ;
2004-08-09 17:04:08 +00:00
FOR_ALL_STATIONS ( st ) {
2009-09-09 08:22:21 +00:00
/* Only count stations that are actually serviced */
if ( st - > owner = = owner & & ( st - > time_since_load < = 20 | | st - > time_since_unload < = 20 ) ) num + = CountBits ( ( byte ) st - > facilities ) ;
2004-08-09 17:04:08 +00:00
}
2004-08-23 10:59:03 +00:00
_score_part [ owner ] [ SCORE_STATIONS ] = num ;
2004-08-09 17:04:08 +00:00
}
2008-09-30 20:39:50 +00:00
/* Generate statistics depending on recent income statistics */
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
int numec = min ( c - > num_valid_stat_ent , 12 ) ;
2004-08-09 17:04:08 +00:00
if ( numec ! = 0 ) {
2008-09-30 20:39:50 +00:00
const CompanyEconomyEntry * cee = c - > old_economy ;
Money min_income = cee - > income + cee - > expenses ;
Money max_income = cee - > income + cee - > expenses ;
2007-06-18 21:44:47 +00:00
2004-08-09 17:04:08 +00:00
do {
2008-09-30 20:39:50 +00:00
min_income = min ( min_income , cee - > income + cee - > expenses ) ;
max_income = max ( max_income , cee - > income + cee - > expenses ) ;
2009-03-14 18:16:29 +00:00
} while ( + + cee , - - numec ) ;
2004-08-09 17:04:08 +00:00
2008-09-30 20:39:50 +00:00
if ( min_income > 0 ) {
2007-06-21 14:32:27 +00:00
_score_part [ owner ] [ SCORE_MIN_INCOME ] = ClampToI32 ( min_income ) ;
2008-09-30 20:39:50 +00:00
}
2004-08-09 17:04:08 +00:00
2007-06-21 14:32:27 +00:00
_score_part [ owner ] [ SCORE_MAX_INCOME ] = ClampToI32 ( max_income ) ;
2004-08-09 17:04:08 +00:00
}
}
2008-09-30 20:39:50 +00:00
/* Generate score depending on amount of transported cargo */
2004-08-09 17:04:08 +00:00
{
2012-01-20 20:18:19 +00:00
int numec = min ( c - > num_valid_stat_ent , 4 ) ;
2004-08-09 17:04:08 +00:00
if ( numec ! = 0 ) {
2012-01-20 20:18:19 +00:00
const CompanyEconomyEntry * cee = c - > old_economy ;
OverflowSafeInt64 total_delivered = 0 ;
2004-08-09 17:04:08 +00:00
do {
2012-01-20 20:18:19 +00:00
total_delivered + = cee - > delivered_cargo . GetSum < OverflowSafeInt64 > ( ) ;
2009-03-14 18:16:29 +00:00
} while ( + + cee , - - numec ) ;
2004-08-09 17:04:08 +00:00
2012-01-20 20:18:19 +00:00
_score_part [ owner ] [ SCORE_DELIVERED ] = ClampToI32 ( total_delivered ) ;
2004-08-09 17:04:08 +00:00
}
}
2004-08-23 10:59:03 +00:00
2008-09-30 20:39:50 +00:00
/* Generate score for variety of cargo */
2004-08-09 17:04:08 +00:00
{
2012-01-20 20:18:19 +00:00
_score_part [ owner ] [ SCORE_CARGO ] = c - > old_economy - > delivered_cargo . GetCount ( ) ;
2004-08-09 17:04:08 +00:00
}
2008-09-30 20:39:50 +00:00
/* Generate score for company's money */
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
if ( c - > money > 0 ) {
_score_part [ owner ] [ SCORE_MONEY ] = ClampToI32 ( c - > money ) ;
2004-08-09 17:04:08 +00:00
}
}
2008-09-30 20:39:50 +00:00
/* Generate score for loan */
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
_score_part [ owner ] [ SCORE_LOAN ] = ClampToI32 ( _score_info [ SCORE_LOAN ] . needed - c - > 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 */
2007-11-19 18:38:10 +00:00
s = Clamp ( _score_part [ owner ] [ i ] , 0 , _score_info [ i ] . needed ) * _score_info [ i ] . score / _score_info [ i ] . needed ;
2004-08-23 10:59:03 +00:00
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 ) {
2008-09-30 20:39:50 +00:00
c - > old_economy [ 0 ] . performance_history = score ;
2010-08-03 12:36:40 +00:00
UpdateCompanyHQ ( c - > location_of_HQ , score ) ;
2008-09-30 20:39:50 +00:00
c - > old_economy [ 0 ] . company_value = CalculateCompanyValue ( c ) ;
2006-06-27 21:25:53 +00:00
}
2004-09-10 19:02:27 +00:00
2009-09-13 19:15:59 +00:00
SetWindowDirty ( WC_PERFORMANCE_DETAIL , 0 ) ;
2004-09-01 21:54:12 +00:00
return score ;
2004-08-09 17:04:08 +00:00
}
2011-05-02 20:59:54 +00:00
/**
* Change the ownership of all the items of a company .
* @ param old_owner The company that gets removed .
* @ param new_owner The company to merge to , or INVALID_OWNER to remove the company .
*/
2008-09-30 20:39:50 +00:00
void ChangeOwnershipOfCompanyItems ( Owner old_owner , Owner new_owner )
2004-08-09 17:04:08 +00:00
{
2011-02-05 10:38:31 +00:00
/* We need to set _current_company to old_owner before we try to move
* the client . This is needed as it needs to know whether " you " really
* are the current local company . */
Backup < CompanyByte > cur_company ( _current_company , old_owner , FILE_LINE ) ;
2010-04-17 11:39:46 +00:00
# ifdef ENABLE_NETWORK
/* In all cases, make spectators of clients connected to that company */
if ( _networking ) NetworkClientsToSpectators ( old_owner ) ;
# endif /* ENABLE_NETWORK */
2011-07-02 19:31:01 +00:00
if ( old_owner = = _local_company ) {
/* Single player cheated to AI company.
2013-01-08 22:46:42 +00:00
* There are no spectators in single player , so we must pick some other company . */
2011-07-02 19:31:01 +00:00
assert ( ! _networking ) ;
Backup < CompanyByte > cur_company ( _current_company , FILE_LINE ) ;
Company * c ;
FOR_ALL_COMPANIES ( c ) {
if ( c - > index ! = old_owner ) {
SetLocalCompany ( c - > index ) ;
break ;
}
}
cur_company . Restore ( ) ;
assert ( old_owner ! = _local_company ) ;
}
2010-04-17 11:39:46 +00:00
2006-12-08 12:31:34 +00:00
Town * t ;
2007-03-31 12:19:22 +00:00
2008-09-30 20:39:50 +00:00
assert ( old_owner ! = new_owner ) ;
2007-04-01 10:55:31 +00:00
2007-03-31 12:19:22 +00:00
{
2008-09-30 20:39:50 +00:00
Company * c ;
2007-03-31 12:19:22 +00:00
uint i ;
2008-09-30 20:39:50 +00:00
/* See if the old_owner had shares in other companies */
FOR_ALL_COMPANIES ( c ) {
2007-03-31 12:19:22 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2008-09-30 20:39:50 +00:00
if ( c - > share_owners [ i ] = = old_owner ) {
2007-03-31 12:19:22 +00:00
/* Sell his shares */
2011-07-02 19:05:42 +00:00
CommandCost res = DoCommand ( 0 , c - > index , 0 , DC_EXEC | DC_BANKRUPT , CMD_SELL_SHARE_IN_COMPANY ) ;
2010-01-01 18:45:40 +00:00
/* Because we are in a DoCommand, we can't just execute another one and
2007-03-31 12:19:22 +00:00
* expect the money to be removed . We need to do it ourself ! */
2008-09-30 20:39:50 +00:00
SubtractMoneyFromCompany ( res ) ;
2007-03-31 12:19:22 +00:00
}
}
}
/* Sell all the shares that people have on this company */
2010-06-05 12:16:12 +00:00
Backup < CompanyByte > cur_company2 ( _current_company , FILE_LINE ) ;
2009-05-16 23:34:14 +00:00
c = Company : : Get ( old_owner ) ;
2007-03-31 12:19:22 +00:00
for ( i = 0 ; i < 4 ; i + + ) {
2010-05-31 20:22:57 +00:00
cur_company2 . Change ( c - > share_owners [ i ] ) ;
2008-09-30 20:39:50 +00:00
if ( _current_company ! = INVALID_OWNER ) {
2007-03-31 12:19:22 +00:00
/* Sell the shares */
2011-07-02 19:05:42 +00:00
CommandCost res = DoCommand ( 0 , old_owner , 0 , DC_EXEC | DC_BANKRUPT , CMD_SELL_SHARE_IN_COMPANY ) ;
2010-01-01 18:45:40 +00:00
/* Because we are in a DoCommand, we can't just execute another one and
2007-03-31 12:19:22 +00:00
* expect the money to be removed . We need to do it ourself ! */
2008-09-30 20:39:50 +00:00
SubtractMoneyFromCompany ( res ) ;
2007-03-31 12:19:22 +00:00
}
}
2010-05-31 20:22:57 +00:00
cur_company2 . Restore ( ) ;
2007-03-31 12:19:22 +00:00
}
2008-09-30 20:39:50 +00:00
/* Temporarily increase the company'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 */
2008-09-30 20:39:50 +00:00
if ( new_owner = = INVALID_OWNER ) {
2009-05-16 23:34:14 +00:00
Company : : Get ( old_owner ) - > money = UINT64_MAX > > 2 ; // jackpot ;p
2006-08-14 11:44:19 +00:00
}
2009-08-08 16:42:55 +00:00
Subsidy * s ;
FOR_ALL_SUBSIDIES ( s ) {
if ( s - > awarded = = old_owner ) {
if ( new_owner = = INVALID_OWNER ) {
2009-08-08 20:53:36 +00:00
delete s ;
2009-08-08 16:42:55 +00:00
} else {
s - > awarded = new_owner ;
2004-08-09 17:04:08 +00:00
}
}
}
2009-08-08 20:53:36 +00:00
if ( new_owner = = INVALID_OWNER ) RebuildSubsidisedSourceAndDestinationCache ( ) ;
2004-08-09 17:04:08 +00:00
2012-05-06 11:37:43 +00:00
/* Take care of rating and transport rights in towns */
2006-12-08 12:31:34 +00:00
FOR_ALL_TOWNS ( t ) {
2008-09-30 20:39:50 +00:00
/* If a company takes over, give the ratings to that company. */
if ( new_owner ! = INVALID_OWNER ) {
if ( HasBit ( t - > have_ratings , old_owner ) ) {
if ( HasBit ( t - > have_ratings , new_owner ) ) {
2009-03-15 00:32:18 +00:00
/* use max of the two ratings. */
2008-09-30 20:39:50 +00:00
t - > ratings [ new_owner ] = max ( t - > ratings [ new_owner ] , t - > ratings [ old_owner ] ) ;
2006-08-14 11:44:19 +00:00
} else {
2008-09-30 20:39:50 +00:00
SetBit ( t - > have_ratings , new_owner ) ;
t - > ratings [ new_owner ] = t - > ratings [ old_owner ] ;
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
2008-09-30 20:39:50 +00:00
/* Reset the ratings for the old owner */
t - > ratings [ old_owner ] = RATING_INITIAL ;
ClrBit ( t - > have_ratings , old_owner ) ;
2012-05-06 11:37:43 +00:00
/* Transfer exclusive rights */
if ( t - > exclusive_counter > 0 & & t - > exclusivity = = old_owner ) {
if ( new_owner ! = INVALID_OWNER ) {
t - > exclusivity = new_owner ;
} else {
t - > exclusive_counter = 0 ;
t - > exclusivity = INVALID_COMPANY ;
}
}
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
{
2008-12-26 23:53:07 +00:00
Vehicle * v ;
2004-08-09 17:04:08 +00:00
FOR_ALL_VEHICLES ( v ) {
2008-12-26 20:45:02 +00:00
if ( v - > owner = = old_owner & & IsCompanyBuildableVehicleType ( v - > type ) ) {
2008-09-30 20:39:50 +00:00
if ( new_owner = = INVALID_OWNER ) {
2008-12-26 20:45:02 +00:00
if ( v - > Previous ( ) = = NULL ) delete v ;
2004-08-09 17:04:08 +00:00
} else {
2011-10-03 17:22:56 +00:00
if ( v - > IsEngineCountable ( ) ) GroupStatistics : : CountEngine ( v , - 1 ) ;
if ( v - > IsPrimaryVehicle ( ) ) GroupStatistics : : CountVehicle ( v , - 1 ) ;
2011-10-30 20:24:00 +00:00
}
}
}
}
/* In all cases clear replace engine rules.
* Even if it was copied , it could interfere with new owner ' s rules */
RemoveAllEngineReplacementForCompany ( Company : : Get ( old_owner ) ) ;
2011-10-03 17:22:56 +00:00
2011-10-30 20:24:00 +00:00
if ( new_owner = = INVALID_OWNER ) {
RemoveAllGroupsForCompany ( old_owner ) ;
} else {
Group * g ;
FOR_ALL_GROUPS ( g ) {
if ( g - > owner = = old_owner ) g - > owner = new_owner ;
}
}
2011-10-03 17:22:56 +00:00
2011-10-30 20:24:00 +00:00
{
FreeUnitIDGenerator unitidgen [ ] = {
FreeUnitIDGenerator ( VEH_TRAIN , new_owner ) , FreeUnitIDGenerator ( VEH_ROAD , new_owner ) ,
FreeUnitIDGenerator ( VEH_SHIP , new_owner ) , FreeUnitIDGenerator ( VEH_AIRCRAFT , new_owner )
} ;
Vehicle * v ;
FOR_ALL_VEHICLES ( v ) {
if ( v - > owner = = old_owner & & IsCompanyBuildableVehicleType ( v - > type ) ) {
assert ( new_owner ! = INVALID_OWNER ) ;
v - > owner = new_owner ;
2012-01-22 21:17:38 +00:00
/* Owner changes, clear cache */
2011-10-30 20:24:00 +00:00
v - > colourmap = PAL_NONE ;
2012-01-22 21:17:38 +00:00
v - > InvalidateNewGRFCache ( ) ;
2010-12-23 07:17:00 +00:00
2011-10-30 20:24:00 +00:00
if ( v - > IsEngineCountable ( ) ) {
GroupStatistics : : CountEngine ( v , 1 ) ;
2004-08-09 17:04:08 +00:00
}
2011-10-30 20:24:00 +00:00
if ( v - > IsPrimaryVehicle ( ) ) {
GroupStatistics : : CountVehicle ( v , 1 ) ;
v - > unitnumber = unitidgen [ v - > type ] . NextID ( ) ;
}
/* Invalidate the vehicle's cargo payment "owner cache". */
if ( v - > cargo_payment ! = NULL ) v - > cargo_payment - > owner = NULL ;
2004-08-09 17:04:08 +00:00
}
}
2011-10-03 17:26:37 +00:00
if ( new_owner ! = INVALID_OWNER ) GroupStatistics : : UpdateAutoreplace ( new_owner ) ;
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 {
2008-09-30 20:39:50 +00:00
ChangeTileOwner ( tile , old_owner , new_owner ) ;
2005-01-03 18:59:58 +00:00
} while ( + + tile ! = MapSize ( ) ) ;
2008-01-05 22:04:11 +00:00
2008-09-30 20:39:50 +00:00
if ( new_owner ! = INVALID_OWNER ) {
/* Update all signals because there can be new segment that was owned by two companies
2008-01-17 19:49:06 +00:00
* and signals were not propagated
2013-01-08 22:46:42 +00:00
* Similar with crossings - it is needed to bar crossings that weren ' t before
2008-01-17 19:49:06 +00:00
* because of different owner of crossing and approaching train */
2008-01-05 22:04:11 +00:00
tile = 0 ;
do {
2008-09-30 20:39:50 +00:00
if ( IsTileType ( tile , MP_RAILWAY ) & & IsTileOwner ( tile , new_owner ) & & HasSignals ( tile ) ) {
2008-01-05 22:04:11 +00:00
TrackBits tracks = GetTrackBits ( tile ) ;
do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT
Track track = RemoveFirstTrack ( & tracks ) ;
2008-09-30 20:39:50 +00:00
if ( HasSignalOnTrack ( tile , track ) ) AddTrackToSignalBuffer ( tile , track , new_owner ) ;
2008-01-05 22:04:11 +00:00
} while ( tracks ! = TRACK_BIT_NONE ) ;
2008-09-30 20:39:50 +00:00
} else if ( IsLevelCrossingTile ( tile ) & & IsTileOwner ( tile , new_owner ) ) {
2008-01-17 19:49:06 +00:00
UpdateLevelCrossing ( tile ) ;
2008-01-05 22:04:11 +00:00
}
} while ( + + tile ! = MapSize ( ) ) ;
}
2008-01-18 02:16:39 +00:00
/* update signals in buffer */
UpdateSignalsInBuffer ( ) ;
2004-08-09 17:04:08 +00:00
}
2012-01-22 22:21:21 +00:00
/* Add airport infrastructure count of the old company to the new one. */
if ( new_owner ! = INVALID_OWNER ) Company : : Get ( new_owner ) - > infrastructure . airport + = Company : : Get ( old_owner ) - > infrastructure . airport ;
2009-02-26 14:07:42 +00:00
/* convert owner of stations (including deleted ones, but excluding buoys) */
Station * st ;
FOR_ALL_STATIONS ( st ) {
if ( st - > owner = = old_owner ) {
/* if a company goes bankrupt, set owner to OWNER_NONE so the sign doesn't disappear immediately
* also , drawing station window would cause reading invalid company ' s colour */
st - > owner = new_owner = = INVALID_OWNER ? OWNER_NONE : new_owner ;
}
}
/* do the same for waypoints (we need to do this here so deleted waypoints are converted too) */
Waypoint * wp ;
FOR_ALL_WAYPOINTS ( wp ) {
if ( wp - > owner = = old_owner ) {
wp - > owner = new_owner = = INVALID_OWNER ? OWNER_NONE : new_owner ;
}
}
2008-09-16 20:57:49 +00:00
Sign * si ;
FOR_ALL_SIGNS ( si ) {
2008-09-30 20:39:50 +00:00
if ( si - > owner = = old_owner ) si - > owner = new_owner = = INVALID_OWNER ? OWNER_NONE : new_owner ;
2008-09-16 20:57:49 +00:00
}
2013-06-09 12:19:09 +00:00
/* Remove Game Script created Goals, CargoMonitors and Story pages. */
2013-02-10 19:49:04 +00:00
Goal * g ;
FOR_ALL_GOALS ( g ) {
if ( g - > company = = old_owner ) delete g ;
}
ClearCargoPickupMonitoring ( old_owner ) ;
ClearCargoDeliveryMonitoring ( old_owner ) ;
2013-06-09 12:19:09 +00:00
StoryPage * sp ;
FOR_ALL_STORY_PAGES ( sp ) {
if ( sp - > company = = old_owner ) delete sp ;
}
2009-02-09 02:57:15 +00:00
/* Change colour of existing windows */
2008-09-30 20:39:50 +00:00
if ( new_owner ! = INVALID_OWNER ) ChangeWindowOwner ( old_owner , new_owner ) ;
2004-08-09 17:04:08 +00:00
2010-05-31 20:22:57 +00:00
cur_company . Restore ( ) ;
2004-08-09 17:04:08 +00:00
MarkWholeScreenDirty ( ) ;
}
2010-08-02 20:32:39 +00:00
/**
* Check for bankruptcy of a company . Called every three months .
* @ param c Company to check .
*/
2008-09-30 20:39:50 +00:00
static void CompanyCheckBankrupt ( Company * c )
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
/* If the company has money again, it does not go bankrupt */
2012-10-20 21:57:33 +00:00
if ( c - > money - c - > current_loan > = - _economy . max_loan ) {
2012-10-20 22:05:26 +00:00
c - > months_of_bankruptcy = 0 ;
2009-09-01 12:17:02 +00:00
c - > bankrupt_asked = 0 ;
2004-08-09 17:04:08 +00:00
return ;
}
2012-10-20 22:05:26 +00:00
c - > months_of_bankruptcy + + ;
2004-08-09 17:04:08 +00:00
2012-10-20 22:05:26 +00:00
switch ( c - > months_of_bankruptcy ) {
/* All the boring cases (months) with a bad balance where no action is taken */
2008-12-26 21:49:00 +00:00
case 0 :
case 1 :
2012-10-20 22:05:26 +00:00
case 2 :
case 3 :
case 5 :
case 6 :
case 8 :
case 9 :
2008-07-18 16:26:51 +00:00
break ;
2013-01-08 22:46:42 +00:00
/* Warn about bankruptcy after 3 months */
2012-10-20 22:05:26 +00:00
case 4 : {
2011-02-04 10:31:40 +00:00
CompanyNewsInformation * cni = MallocT < CompanyNewsInformation > ( 1 ) ;
cni - > FillData ( c ) ;
2009-04-21 23:40:56 +00:00
SetDParam ( 0 , STR_NEWS_COMPANY_IN_TROUBLE_TITLE ) ;
SetDParam ( 1 , STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION ) ;
2008-07-18 16:26:51 +00:00
SetDParamStr ( 2 , cni - > company_name ) ;
2012-05-26 14:15:46 +00:00
AddCompanyNewsItem ( STR_MESSAGE_NEWS_FORMAT , cni ) ;
2011-11-29 23:15:35 +00:00
AI : : BroadcastNewEvent ( new ScriptEventCompanyInTrouble ( c - > index ) ) ;
2011-12-19 20:59:36 +00:00
Game : : NewEvent ( new ScriptEventCompanyInTrouble ( c - > index ) ) ;
2004-12-04 17:54:56 +00:00
break ;
2011-02-04 10:31:40 +00:00
}
2012-10-20 22:05:26 +00:00
/* Offer company for sale after 6 months */
case 7 : {
2013-01-20 16:17:24 +00:00
/* Don't consider the loan */
2010-01-24 11:05:26 +00:00
Money val = CalculateCompanyValue ( c , false ) ;
2013-01-20 16:17:24 +00:00
c - > bankrupt_value = val ;
c - > bankrupt_asked = 1 < < c - > index ; // Don't ask the owner
c - > bankrupt_timeout = 0 ;
/* The company assets should always have some value */
assert ( c - > bankrupt_value > 0 ) ;
break ;
2004-12-04 17:54:56 +00:00
}
2012-10-20 22:05:26 +00:00
2013-01-08 22:46:42 +00:00
/* Bankrupt company after 6 months (if the company has no value) or latest
2012-10-20 22:05:26 +00:00
* after 9 months ( if it still had value after 6 months ) */
2008-12-26 21:49:00 +00:00
default :
2012-10-20 22:05:26 +00:00
case 10 : {
2008-12-26 21:49:00 +00:00
if ( ! _networking & & _local_company = = c - > index ) {
/* If we are in offline mode, leave the company playing. Eg. there
* is no THE - END , otherwise mark the client as spectator to make sure
* he / she is no long in control of this company . However . . . when you
* join another company ( cheat ) the " unowned " company can bankrupt . */
c - > bankrupt_asked = MAX_UVALUE ( CompanyMask ) ;
break ;
}
2011-02-05 10:38:31 +00:00
/* Actually remove the company, but not when we're a network client.
* In case of network clients we will be getting a command from the
* server . It is done in this way as we are called from the
* StateGameLoop which can ' t change the current company , and thus
* updating the local company triggers an assert later on . In the
* case of a network game the command will be processed at a time
* that changing the current company is okay . In case of single
* player we are sure ( the above check ) that we are not the local
* company and thus we won ' t be moved . */
2011-10-15 20:42:32 +00:00
if ( ! _networking | | _network_server ) DoCommandP ( 0 , 2 | ( c - > index < < 16 ) , CRR_BANKRUPT , CMD_COMPANY_CTRL ) ;
2011-02-04 10:31:40 +00:00
break ;
2012-10-20 22:05:26 +00:00
}
2004-08-09 17:04:08 +00:00
}
}
2010-08-02 20:32:39 +00:00
/**
* Update the finances of all companies .
* Pay for the stations , update the history graph , update ratings and company values , and deal with bankruptcy .
*/
2008-09-30 20:39:50 +00:00
static void CompaniesGenStatistics ( )
2004-08-09 17:04:08 +00:00
{
Station * st ;
2010-06-05 12:16:12 +00:00
Backup < CompanyByte > cur_company ( _current_company , FILE_LINE ) ;
2011-12-03 23:40:46 +00:00
Company * c ;
if ( ! _settings_game . economy . infrastructure_maintenance ) {
FOR_ALL_STATIONS ( st ) {
cur_company . Change ( st - > owner ) ;
CommandCost cost ( EXPENSES_PROPERTY , _price [ PR_STATION_VALUE ] > > 1 ) ;
SubtractMoneyFromCompany ( cost ) ;
}
} else {
/* Improved monthly infrastructure costs. */
FOR_ALL_COMPANIES ( c ) {
cur_company . Change ( c - > index ) ;
CommandCost cost ( EXPENSES_PROPERTY ) ;
2012-02-11 22:43:39 +00:00
uint32 rail_total = c - > infrastructure . GetRailTotal ( ) ;
2011-12-03 23:40:46 +00:00
for ( RailType rt = RAILTYPE_BEGIN ; rt < RAILTYPE_END ; rt + + ) {
2012-02-11 22:43:39 +00:00
if ( c - > infrastructure . rail [ rt ] ! = 0 ) cost . AddCost ( RailMaintenanceCost ( rt , c - > infrastructure . rail [ rt ] , rail_total ) ) ;
2011-12-03 23:40:46 +00:00
}
cost . AddCost ( SignalMaintenanceCost ( c - > infrastructure . signal ) ) ;
for ( RoadType rt = ROADTYPE_BEGIN ; rt < ROADTYPE_END ; rt + + ) {
if ( c - > infrastructure . road [ rt ] ! = 0 ) cost . AddCost ( RoadMaintenanceCost ( rt , c - > infrastructure . road [ rt ] ) ) ;
}
cost . AddCost ( CanalMaintenanceCost ( c - > infrastructure . water ) ) ;
cost . AddCost ( StationMaintenanceCost ( c - > infrastructure . station ) ) ;
cost . AddCost ( AirportMaintenanceCost ( c - > index ) ) ;
SubtractMoneyFromCompany ( cost ) ;
}
2004-08-09 17:04:08 +00:00
}
2010-05-31 20:22:57 +00:00
cur_company . Restore ( ) ;
2004-08-09 17:04:08 +00:00
2012-10-20 22:05:26 +00:00
/* Check for bankruptcy each month */
FOR_ALL_COMPANIES ( c ) {
CompanyCheckBankrupt ( c ) ;
}
2011-02-14 19:52:26 +00:00
/* Only run the economic statics and update company stats every 3rd month (1st of quarter). */
2010-07-24 10:14:39 +00:00
if ( ! HasBit ( 1 < < 0 | 1 < < 3 | 1 < < 6 | 1 < < 9 , _cur_month ) ) return ;
2004-08-09 17:04:08 +00:00
2008-09-30 20:39:50 +00:00
FOR_ALL_COMPANIES ( c ) {
memmove ( & c - > old_economy [ 1 ] , & c - > old_economy [ 0 ] , sizeof ( c - > old_economy ) - sizeof ( c - > old_economy [ 0 ] ) ) ;
c - > old_economy [ 0 ] = c - > cur_economy ;
memset ( & c - > cur_economy , 0 , sizeof ( c - > cur_economy ) ) ;
2004-08-09 17:04:08 +00:00
2011-05-19 21:03:23 +00:00
if ( c - > num_valid_stat_ent ! = MAX_HISTORY_QUARTERS ) c - > num_valid_stat_ent + + ;
2004-08-09 17:04:08 +00:00
2008-09-30 20:39:50 +00:00
UpdateCompanyRatingAndValue ( c , true ) ;
if ( c - > block_preview ! = 0 ) c - > block_preview - - ;
2004-08-09 17:04:08 +00:00
}
2009-09-13 19:15:59 +00:00
SetWindowDirty ( WC_INCOME_GRAPH , 0 ) ;
SetWindowDirty ( WC_OPERATING_PROFIT , 0 ) ;
SetWindowDirty ( WC_DELIVERED_CARGO , 0 ) ;
SetWindowDirty ( WC_PERFORMANCE_HISTORY , 0 ) ;
SetWindowDirty ( WC_COMPANY_VALUE , 0 ) ;
SetWindowDirty ( WC_COMPANY_LEAGUE , 0 ) ;
2004-08-09 17:04:08 +00:00
}
2009-09-06 18:53:57 +00:00
/**
* Add monthly inflation
* @ param check_year Shall the inflation get stopped after 170 years ?
2012-10-01 19:31:55 +00:00
* @ return true if inflation is maxed and nothing was changed
2009-09-06 18:53:57 +00:00
*/
2012-10-01 19:31:55 +00:00
bool AddInflation ( bool check_year )
2004-08-09 17:04:08 +00:00
{
2007-07-13 12:08:37 +00:00
/* The cargo payment inflation differs from the normal inflation, so the
* relative amount of money you make with a transport decreases slowly over
* the 170 years . After a few hundred years we reach a level in which the
* games will become unplayable as the maximum income will be less than
* the minimum running cost .
*
* Furthermore there are a lot of inflation related overflows all over the
* place . Solving them is hardly possible because inflation will always
* reach the overflow threshold some day . So we ' ll just perform the
* inflation mechanism during the first 170 years ( the amount of years that
* one had in the original TTD ) and stop doing the inflation after that
* because it only causes problems that can ' t be solved nicely and the
* inflation doesn ' t add anything after that either ; it even makes playing
* it impossible due to the diverging cost and income rates .
*/
2012-10-01 19:31:55 +00:00
if ( check_year & & ( _cur_year - _settings_game . game_creation . starting_year ) > = ( ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR ) ) return true ;
if ( _economy . inflation_prices = = MAX_INFLATION | | _economy . inflation_payment = = MAX_INFLATION ) return true ;
2007-07-13 12:08:37 +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
2013-01-08 22:46:42 +00:00
* This is only a good approximation for small values
2007-02-23 08:03:30 +00:00
*/
2012-10-01 19:29:31 +00:00
_economy . inflation_prices + = ( _economy . inflation_prices * _economy . infl_amount * 54 ) > > 16 ;
_economy . inflation_payment + = ( _economy . inflation_payment * _economy . infl_amount_pr * 54 ) > > 16 ;
if ( _economy . inflation_prices > MAX_INFLATION ) _economy . inflation_prices = MAX_INFLATION ;
if ( _economy . inflation_payment > MAX_INFLATION ) _economy . inflation_payment = MAX_INFLATION ;
2012-10-01 19:31:55 +00:00
return false ;
2009-09-06 18:53:57 +00:00
}
2004-08-09 17:04:08 +00:00
2009-09-06 18:53:57 +00:00
/**
* Computes all prices , payments and maximum loan .
*/
void RecomputePrices ( )
{
/* Setup maximum loan */
_economy . max_loan = ( _settings_game . difficulty . max_loan * _economy . inflation_prices > > 16 ) / 50000 * 50000 ;
/* Setup price bases */
2009-11-08 12:23:02 +00:00
for ( Price i = PR_BEGIN ; i < PR_END ; i + + ) {
2009-09-06 18:53:57 +00:00
Money price = _price_base_specs [ i ] . start_price ;
/* Apply difficulty settings */
uint mod = 1 ;
switch ( _price_base_specs [ i ] . category ) {
case PCAT_RUNNING :
mod = _settings_game . difficulty . vehicle_costs ;
break ;
case PCAT_CONSTRUCTION :
mod = _settings_game . difficulty . construction_cost ;
break ;
default : break ;
}
2011-07-31 14:13:01 +00:00
switch ( mod ) {
case 0 : price * = 6 ; break ;
case 1 : price * = 8 ; break ; // normalised to 1 below
case 2 : price * = 9 ; break ;
default : NOT_REACHED ( ) ;
2009-09-06 18:53:57 +00:00
}
2004-08-09 17:04:08 +00:00
2009-09-06 18:53:57 +00:00
/* Apply inflation */
price = ( int64 ) price * _economy . inflation_prices ;
2004-09-10 19:02:27 +00:00
2011-07-31 14:13:01 +00:00
/* Apply newgrf modifiers, remove fractional part of inflation, and normalise on medium difficulty. */
int shift = _price_base_multiplier [ i ] - 16 - 3 ;
2009-09-06 18:53:57 +00:00
if ( shift > = 0 ) {
price < < = shift ;
} else {
price > > = - shift ;
}
2004-08-09 17:04:08 +00:00
2010-02-27 16:27:28 +00:00
/* Make sure the price does not get reduced to zero.
* Zero breaks quite a few commands that use a zero
* cost to see whether something got changed or not
* and based on that cause an error . When the price
* is zero that fails even when things are done . */
if ( price = = 0 ) {
price = Clamp ( _price_base_specs [ i ] . start_price , - 1 , 1 ) ;
/* No base price should be zero, but be sure. */
assert ( price ! = 0 ) ;
}
2009-09-06 18:53:57 +00:00
/* Store value */
2009-11-08 12:23:02 +00:00
_price [ i ] = price ;
2009-09-06 18:53:57 +00:00
}
/* Setup cargo payment */
2009-09-06 20:36:17 +00:00
CargoSpec * cs ;
2009-09-06 18:53:57 +00:00
FOR_ALL_CARGOSPECS ( cs ) {
2009-09-06 20:36:17 +00:00
cs - > current_payment = ( ( int64 ) cs - > initial_payment * _economy . inflation_payment ) > > 16 ;
2004-08-09 17:04:08 +00:00
}
2009-09-13 19:15:59 +00:00
SetWindowClassesDirty ( WC_BUILD_VEHICLE ) ;
SetWindowClassesDirty ( WC_REPLACE_VEHICLE ) ;
SetWindowClassesDirty ( WC_VEHICLE_DETAILS ) ;
2011-12-03 23:40:46 +00:00
SetWindowClassesDirty ( WC_COMPANY_INFRASTRUCTURE ) ;
2010-12-29 18:20:19 +00:00
InvalidateWindowData ( WC_PAYMENT_RATES , 0 ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-02 20:47:27 +00:00
/** Let all companies pay the monthly interest on their loan. */
2008-09-30 20:39:50 +00:00
static void CompaniesPayInterest ( )
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
const Company * c ;
2004-08-09 17:04:08 +00:00
2010-06-05 12:16:12 +00:00
Backup < CompanyByte > cur_company ( _current_company , FILE_LINE ) ;
2008-09-30 20:39:50 +00:00
FOR_ALL_COMPANIES ( c ) {
2010-05-31 20:22:57 +00:00
cur_company . Change ( c - > index ) ;
2004-09-10 19:02:27 +00:00
2009-01-04 14:32:30 +00:00
/* Over a year the paid interest should be "loan * interest percentage",
* but . . . as that number is likely not dividable by 12 ( pay each month ) ,
* one needs to account for that in the monthly fee calculations .
* To easily calculate what one should pay " this " month , you calculate
2010-07-31 21:02:56 +00:00
* what ( total ) should have been paid up to this month and you subtract
2009-01-04 14:32:30 +00:00
* whatever has been paid in the previous months . This will mean one month
* it ' ll be a bit more and the other it ' ll be a bit less than the average
2012-10-20 21:58:48 +00:00
* monthly fee , but on average it will be exact .
* In order to prevent cheating or abuse ( just not paying interest by not
* taking a loan we make companies pay interest on negative cash as well
*/
2009-01-04 14:32:30 +00:00
Money yearly_fee = c - > current_loan * _economy . interest_rate / 100 ;
2012-10-20 21:58:48 +00:00
if ( c - > money < 0 ) {
yearly_fee + = - c - > money * _economy . interest_rate / 100 ;
}
2009-01-04 14:32:30 +00:00
Money up_to_previous_month = yearly_fee * _cur_month / 12 ;
Money up_to_this_month = yearly_fee * ( _cur_month + 1 ) / 12 ;
SubtractMoneyFromCompany ( CommandCost ( EXPENSES_LOAN_INT , up_to_this_month - up_to_previous_month ) ) ;
2004-08-09 17:04:08 +00:00
2009-11-07 22:47:54 +00:00
SubtractMoneyFromCompany ( CommandCost ( EXPENSES_OTHER , _price [ PR_STATION_VALUE ] > > 2 ) ) ;
2004-08-09 17:04:08 +00:00
}
2010-05-31 20:22:57 +00:00
cur_company . Restore ( ) ;
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
static void HandleEconomyFluctuations ( )
2004-08-09 17:04:08 +00:00
{
2009-09-05 19:02:34 +00:00
if ( _settings_game . difficulty . economy ! = 0 ) {
/* When economy is Fluctuating, decrease counter */
_economy . fluct - - ;
2010-11-13 09:45:20 +00:00
} else if ( EconomyIsInRecession ( ) ) {
2009-09-05 19:02:34 +00:00
/* When it's Steady and we are in recession, end it now */
_economy . fluct = - 12 ;
} else {
/* No need to do anything else in other cases */
return ;
}
2004-08-09 17:04:08 +00:00
2009-09-05 19:02:34 +00:00
if ( _economy . fluct = = 0 ) {
2005-11-15 08:49:46 +00:00
_economy . fluct = - ( int ) GB ( Random ( ) , 0 , 2 ) ;
2012-05-26 14:16:03 +00:00
AddNewsItem ( STR_NEWS_BEGIN_OF_RECESSION , NT_ECONOMY , NF_NORMAL ) ;
2004-08-09 17:04:08 +00:00
} else if ( _economy . fluct = = - 12 ) {
2005-11-15 08:49:46 +00:00
_economy . fluct = GB ( Random ( ) , 0 , 8 ) + 312 ;
2012-05-26 14:16:03 +00:00
AddNewsItem ( STR_NEWS_END_OF_RECESSION , NT_ECONOMY , NF_NORMAL ) ;
2004-08-09 17:04:08 +00:00
}
}
2005-10-12 07:27:56 +00:00
/**
* 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
{
2009-11-08 18:04:53 +00:00
memset ( _price_base_multiplier , 0 , sizeof ( _price_base_multiplier ) ) ;
2005-10-12 07:27:56 +00:00
}
/**
* Change a price base by the given factor .
2009-11-08 18:04:53 +00:00
* The price base is altered by factors of two .
* NewBaseCost = OldBaseCost * 2 ^ n
2005-10-12 07:27:56 +00:00
* @ param price Index of price base to change .
* @ param factor Amount to change by .
*/
2009-11-08 18:04:53 +00:00
void SetPriceBaseMultiplier ( Price price , int factor )
2005-10-12 07:27:56 +00:00
{
2009-11-08 12:23:02 +00:00
assert ( price < PR_END ) ;
2009-11-08 18:04:53 +00:00
_price_base_multiplier [ price ] = Clamp ( factor , MIN_PRICE_MODIFIER , MAX_PRICE_MODIFIER ) ;
2005-10-12 07:27:56 +00:00
}
2008-09-15 17:18:22 +00:00
/**
* Initialize the variables that will maintain the daily industry change system .
* @ param init_counter specifies if the counter is required to be initialized
*/
2009-01-04 15:32:25 +00:00
void StartupIndustryDailyChanges ( bool init_counter )
2008-09-15 17:18:22 +00:00
{
uint map_size = MapLogX ( ) + MapLogY ( ) ;
/* After getting map size, it needs to be scaled appropriately and divided by 31,
* which stands for the days in a month .
* Using just 31 will make it so that a monthly reset ( based on the real number of days of that month )
* would not be needed .
2013-01-08 22:46:42 +00:00
* Since it is based on " fractional parts " , the leftover days will not make much of a difference
2008-09-15 17:18:22 +00:00
* on the overall total number of changes performed */
_economy . industry_daily_increment = ( 1 < < map_size ) / 31 ;
if ( init_counter ) {
/* A new game or a savegame from an older version will require the counter to be initialized */
_economy . industry_daily_change_counter = 0 ;
}
}
2007-03-07 11:47:46 +00:00
void StartupEconomy ( )
2004-08-09 17:04:08 +00:00
{
2008-05-29 15:13:28 +00:00
_economy . interest_rate = _settings_game . difficulty . initial_interest ;
_economy . infl_amount = _settings_game . difficulty . initial_interest ;
_economy . infl_amount_pr = max ( 0 , _settings_game . difficulty . initial_interest - 1 ) ;
2005-07-21 06:31:02 +00:00
_economy . fluct = GB ( Random ( ) , 0 , 8 ) + 168 ;
2008-09-15 17:18:22 +00:00
2009-09-06 18:53:57 +00:00
/* Set up prices */
RecomputePrices ( ) ;
2008-09-15 17:18:22 +00:00
StartupIndustryDailyChanges ( true ) ; // As we are starting a new game, initialize the counter too
2004-08-09 17:04:08 +00:00
}
2009-09-06 18:53:57 +00:00
/**
* Resets economy to initial values
*/
void InitializeEconomy ( )
2008-07-26 14:58:08 +00:00
{
2009-09-06 18:53:57 +00:00
_economy . inflation_prices = _economy . inflation_payment = 1 < < 16 ;
2012-07-15 17:07:06 +00:00
ClearCargoPickupMonitoring ( ) ;
ClearCargoDeliveryMonitoring ( ) ;
2008-07-26 14:58:08 +00:00
}
2008-02-21 19:09:10 +00:00
2009-11-07 22:47:54 +00:00
/**
2009-11-24 13:12:34 +00:00
* Determine a certain price
* @ param index Price base
* @ param cost_factor Price factor
2009-11-24 13:15:58 +00:00
* @ param grf_file NewGRF to use local price multipliers from .
2009-11-24 13:12:34 +00:00
* @ param shift Extra bit shifting after the computation
* @ return Price
2009-11-07 22:47:54 +00:00
*/
2009-11-24 13:15:58 +00:00
Money GetPrice ( Price index , uint cost_factor , const GRFFile * grf_file , int shift )
2008-02-21 19:09:10 +00:00
{
2009-11-08 12:23:02 +00:00
if ( index > = PR_END ) return 0 ;
2008-02-21 19:09:10 +00:00
2009-11-24 13:12:34 +00:00
Money cost = _price [ index ] * cost_factor ;
2009-11-24 13:15:58 +00:00
if ( grf_file ! = NULL ) shift + = grf_file - > price_base_multipliers [ index ] ;
2009-11-24 13:12:34 +00:00
if ( shift > = 0 ) {
cost < < = shift ;
} else {
cost > > = - shift ;
}
return cost ;
2008-02-21 19:09:10 +00:00
}
2007-06-18 22:09:54 +00:00
Money GetTransportedGoodsIncome ( uint num_pieces , uint dist , byte transit_days , CargoID cargo_type )
2004-08-09 17:04:08 +00:00
{
2009-07-16 19:00:13 +00:00
const CargoSpec * cs = CargoSpec : : Get ( cargo_type ) ;
2009-09-06 20:36:17 +00:00
if ( ! cs - > IsValid ( ) ) {
/* User changed newgrfs and some vehicle still carries some cargo which is no longer available. */
return 0 ;
}
2004-08-09 17:04:08 +00:00
2007-04-12 19:33:05 +00:00
/* Use callback to calculate cargo profit, if available */
2007-11-19 21:02:30 +00:00
if ( HasBit ( cs - > callback_mask , CBM_CARGO_PROFIT_CALC ) ) {
2007-04-12 19:33:05 +00:00
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 */
2009-09-15 17:23:24 +00:00
if ( HasBit ( callback , 14 ) ) result - = 0x4000 ;
2007-04-12 19:33:05 +00:00
/* "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. " */
2009-09-06 20:36:17 +00:00
return result * num_pieces * cs - > current_payment / 8192 ;
2007-04-12 19:33:05 +00:00
}
}
2007-07-25 19:26:33 +00:00
static const int MIN_TIME_FACTOR = 31 ;
static const int MAX_TIME_FACTOR = 255 ;
2004-08-09 17:04:08 +00:00
2007-07-25 19:26:33 +00:00
const int days1 = cs - > transit_days [ 0 ] ;
const int days2 = cs - > transit_days [ 1 ] ;
2008-12-13 16:16:44 +00:00
const int days_over_days1 = max ( transit_days - days1 , 0 ) ;
const int days_over_days2 = max ( days_over_days1 - days2 , 0 ) ;
2007-07-25 19:26:33 +00:00
/*
* The time factor is calculated based on the time it took
* ( transit_days ) compared two cargo - depending values . The
* range is divided into three parts :
*
* - constant for fast transits
* - linear decreasing with time with a slope of - 1 for medium transports
* - linear decreasing with time with a slope of - 2 for slow transports
*
*/
2008-12-13 16:16:44 +00:00
const int time_factor = max ( MAX_TIME_FACTOR - days_over_days1 - days_over_days2 , MIN_TIME_FACTOR ) ;
2007-07-25 19:26:33 +00:00
2009-09-06 20:36:17 +00:00
return BigMulS ( dist * time_factor * num_pieces , cs - > current_payment , 21 ) ;
2004-08-09 17:04:08 +00:00
}
2009-06-28 14:36:25 +00:00
/** The industries we've currently brought cargo to. */
static SmallIndustryList _cargo_delivery_destinations ;
2009-06-25 15:42:03 +00:00
/**
* Transfer goods from station to industry .
* All cargo is delivered to the nearest ( Manhattan ) industry to the station sign , which is inside the acceptance rectangle and actually accepts the cargo .
* @ param st The station that accepted the cargo
* @ param cargo_type Type of cargo delivered
2009-09-19 09:51:14 +00:00
* @ param num_pieces Amount of cargo delivered
* @ param source The source of the cargo
2009-09-06 21:59:20 +00:00
* @ return actually accepted pieces of cargo
2009-06-25 15:42:03 +00:00
*/
2009-09-06 22:05:53 +00:00
static uint DeliverGoodsToIndustry ( const Station * st , CargoID cargo_type , uint num_pieces , IndustryID source )
2009-06-25 15:42:03 +00:00
{
/* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo.
* This fails in three cases :
* 1 ) The station accepts the cargo because there are enough houses around it accepting the cargo .
* 2 ) The industries in the catchment area temporarily reject the cargo , and the daily station loop has not yet updated station acceptance .
* 3 ) The results of callbacks CBID_INDUSTRY_REFUSE_CARGO and CBID_INDTILE_CARGO_ACCEPTANCE are inconsistent . ( documented behaviour )
*/
2009-09-06 21:59:20 +00:00
uint accepted = 0 ;
for ( uint i = 0 ; i < st - > industries_near . Length ( ) & & num_pieces ! = 0 ; i + + ) {
2009-06-25 15:42:03 +00:00
Industry * ind = st - > industries_near [ i ] ;
2009-09-06 22:05:53 +00:00
if ( ind - > index = = source ) continue ;
2009-06-25 15:42:03 +00:00
uint cargo_index ;
for ( cargo_index = 0 ; cargo_index < lengthof ( ind - > accepts_cargo ) ; cargo_index + + ) {
if ( cargo_type = = ind - > accepts_cargo [ cargo_index ] ) break ;
}
/* Check if matching cargo has been found */
if ( cargo_index > = lengthof ( ind - > accepts_cargo ) ) continue ;
/* Check if industry temporarily refuses acceptance */
2010-08-07 20:11:27 +00:00
if ( IndustryTemporarilyRefusesCargo ( ind , cargo_type ) ) continue ;
2007-07-07 08:53:19 +00:00
2009-06-28 14:36:25 +00:00
/* Insert the industry into _cargo_delivery_destinations, if not yet contained */
_cargo_delivery_destinations . Include ( ind ) ;
2007-07-04 18:27:21 +00:00
2009-09-07 10:00:14 +00:00
uint amount = min ( num_pieces , 0xFFFFU - ind - > incoming_cargo_waiting [ cargo_index ] ) ;
2009-09-06 21:59:20 +00:00
ind - > incoming_cargo_waiting [ cargo_index ] + = amount ;
num_pieces - = amount ;
accepted + = amount ;
2004-08-09 17:04:08 +00:00
}
2009-09-06 21:59:20 +00:00
return accepted ;
2004-08-09 17:04:08 +00:00
}
2008-12-20 17:21:22 +00:00
/**
* Delivers goods to industries / towns and calculates the payment
* @ param num_pieces amount of cargo delivered
2009-09-19 09:51:14 +00:00
* @ param cargo_type the type of cargo that is delivered
2008-12-20 17:21:22 +00:00
* @ param dest Station the cargo has been unloaded
* @ param source_tile The origin of the cargo for distance calculation
* @ param days_in_transit Travel time
2009-06-28 14:33:10 +00:00
* @ param company The company delivering the cargo
2009-08-08 16:42:55 +00:00
* @ param src_type Type of source of cargo ( industry , town , headquarters )
* @ param src Index of source of cargo
* @ return Revenue for delivering cargo
* @ note The cargo is just added to the stockpile of the industry . It is due to the caller to trigger the industry ' s production machinery
2008-12-20 17:21:22 +00:00
*/
2009-08-08 16:42:55 +00:00
static Money DeliverGoods ( int num_pieces , CargoID cargo_type , StationID dest , TileIndex source_tile , byte days_in_transit , Company * company , SourceType src_type , SourceID src )
2004-08-09 17:04:08 +00:00
{
2006-06-27 21:25:53 +00:00
assert ( num_pieces > 0 ) ;
2004-08-09 17:04:08 +00:00
2011-06-04 21:21:00 +00:00
Station * st = Station : : Get ( dest ) ;
2004-08-09 17:04:08 +00:00
2007-02-23 18:55:07 +00:00
/* Give the goods to the industry. */
2009-09-06 22:05:53 +00:00
uint accepted = DeliverGoodsToIndustry ( st , cargo_type , num_pieces , src_type = = ST_INDUSTRY ? src : INVALID_INDUSTRY ) ;
2004-09-10 19:02:27 +00:00
2009-09-20 18:52:12 +00:00
/* If this cargo type is always accepted, accept all */
2009-09-20 17:44:33 +00:00
if ( HasBit ( st - > always_accepted , cargo_type ) ) accepted = num_pieces ;
2009-09-07 07:39:08 +00:00
2011-06-04 21:21:00 +00:00
/* Update station statistics */
if ( accepted > 0 ) {
SetBit ( st - > goods [ cargo_type ] . acceptance_pickup , GoodsEntry : : GES_EVER_ACCEPTED ) ;
SetBit ( st - > goods [ cargo_type ] . acceptance_pickup , GoodsEntry : : GES_CURRENT_MONTH ) ;
SetBit ( st - > goods [ cargo_type ] . acceptance_pickup , GoodsEntry : : GES_ACCEPTED_BIGTICK ) ;
}
2009-12-19 15:51:55 +00:00
/* Update company statistics */
2012-01-20 20:18:19 +00:00
company - > cur_economy . delivered_cargo [ cargo_type ] + = accepted ;
2009-12-19 15:51:55 +00:00
2011-11-23 16:05:19 +00:00
/* Increase town's counter for town effects */
2009-12-19 15:51:55 +00:00
const CargoSpec * cs = CargoSpec : : Get ( cargo_type ) ;
2011-11-23 16:05:19 +00:00
st - > town - > received [ cs - > town_effect ] . new_act + = accepted ;
2009-12-19 15:51:55 +00:00
2007-02-23 18:55:07 +00:00
/* Determine profit */
2009-09-06 21:59:20 +00:00
Money profit = GetTransportedGoodsIncome ( accepted , DistanceManhattan ( source_tile , st - > xy ) , days_in_transit , cargo_type ) ;
2004-08-09 17:04:08 +00:00
2012-07-15 17:05:17 +00:00
/* Update the cargo monitor. */
AddCargoDelivery ( cargo_type , company - > index , accepted , src_type , src , st ) ;
2007-02-23 18:55:07 +00:00
/* Modify profit if a subsidy is in effect */
2009-08-08 16:42:55 +00:00
if ( CheckSubsidised ( cargo_type , company - > index , src_type , src , st ) ) {
2008-05-29 15:13:28 +00:00
switch ( _settings_game . difficulty . 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 ;
}
2008-12-20 17:21:22 +00:00
/**
* Inform the industry about just delivered cargo
* DeliverGoodsToIndustry ( ) silently incremented incoming_cargo_waiting , now it is time to do something with the new cargo .
* @ param i The industry to process
*/
static void TriggerIndustryProduction ( Industry * i )
{
const IndustrySpec * indspec = GetIndustrySpec ( i - > type ) ;
2009-09-14 12:22:57 +00:00
uint16 callback = indspec - > callback_mask ;
2008-12-20 17:21:22 +00:00
i - > was_cargo_delivered = true ;
i - > last_cargo_accepted_at = _date ;
if ( HasBit ( callback , CBM_IND_PRODUCTION_CARGO_ARRIVAL ) | | HasBit ( callback , CBM_IND_PRODUCTION_256_TICKS ) ) {
if ( HasBit ( callback , CBM_IND_PRODUCTION_CARGO_ARRIVAL ) ) {
IndustryProductionCallback ( i , 0 ) ;
} else {
2009-09-13 19:15:59 +00:00
SetWindowDirty ( WC_INDUSTRY_VIEW , i - > index ) ;
2008-12-20 17:21:22 +00:00
}
} else {
for ( uint cargo_index = 0 ; cargo_index < lengthof ( i - > incoming_cargo_waiting ) ; cargo_index + + ) {
uint cargo_waiting = i - > incoming_cargo_waiting [ cargo_index ] ;
if ( cargo_waiting = = 0 ) continue ;
i - > produced_cargo_waiting [ 0 ] = min ( i - > produced_cargo_waiting [ 0 ] + ( cargo_waiting * indspec - > input_cargo_multiplier [ cargo_index ] [ 0 ] / 256 ) , 0xFFFF ) ;
i - > produced_cargo_waiting [ 1 ] = min ( i - > produced_cargo_waiting [ 1 ] + ( cargo_waiting * indspec - > input_cargo_multiplier [ cargo_index ] [ 1 ] / 256 ) , 0xFFFF ) ;
i - > incoming_cargo_waiting [ cargo_index ] = 0 ;
}
}
TriggerIndustry ( i , INDUSTRY_TRIGGER_RECEIVED_CARGO ) ;
StartStopIndustryTileAnimation ( i , IAT_INDUSTRY_RECEIVED_CARGO ) ;
}
2009-06-28 15:12:59 +00:00
/**
* Makes us a new cargo payment helper .
* @ param front The front of the train
*/
CargoPayment : : CargoPayment ( Vehicle * front ) :
front ( front ) ,
current_station ( front - > last_station_visited )
{
}
CargoPayment : : ~ CargoPayment ( )
{
2009-06-29 19:55:36 +00:00
if ( this - > CleaningPool ( ) ) return ;
this - > front - > cargo_payment = NULL ;
2013-02-17 14:50:54 +00:00
if ( this - > visual_profit = = 0 & & this - > visual_transfer = = 0 ) return ;
2009-06-28 15:12:59 +00:00
2010-06-05 12:16:12 +00:00
Backup < CompanyByte > cur_company ( _current_company , this - > front - > owner , FILE_LINE ) ;
2009-06-28 15:12:59 +00:00
SubtractMoneyFromCompany ( CommandCost ( this - > front - > GetExpenseType ( true ) , - this - > route_profit ) ) ;
2013-02-17 14:50:54 +00:00
this - > front - > profit_this_year + = ( this - > visual_profit + this - > visual_transfer ) < < 8 ;
2009-06-28 15:12:59 +00:00
2013-02-17 14:50:54 +00:00
if ( this - > route_profit ! = 0 & & IsLocalCompany ( ) & & ! PlayVehicleSound ( this - > front , VSE_LOAD_UNLOAD ) ) {
SndPlayVehicleFx ( SND_14_CASHTILL , this - > front ) ;
}
2009-06-28 15:12:59 +00:00
2013-02-17 14:50:54 +00:00
if ( this - > visual_transfer ! = 0 ) {
ShowFeederIncomeAnimation ( this - > front - > x_pos , this - > front - > y_pos ,
this - > front - > z_pos , this - > visual_transfer , - this - > visual_profit ) ;
} else if ( this - > visual_profit ! = 0 ) {
ShowCostOrIncomeAnimation ( this - > front - > x_pos , this - > front - > y_pos ,
this - > front - > z_pos , - this - > visual_profit ) ;
2009-06-28 15:12:59 +00:00
}
2010-05-31 20:22:57 +00:00
cur_company . Restore ( ) ;
2009-06-28 15:12:59 +00:00
}
/**
* Handle payment for final delivery of the given cargo packet .
* @ param cp The cargo packet to pay for .
* @ param count The number of packets to pay for .
*/
2009-10-06 17:23:15 +00:00
void CargoPayment : : PayFinalDelivery ( const CargoPacket * cp , uint count )
2009-06-28 15:12:59 +00:00
{
if ( this - > owner = = NULL ) {
this - > owner = Company : : Get ( this - > front - > owner ) ;
}
/* Handle end of route payment */
2009-10-20 22:06:33 +00:00
Money profit = DeliverGoods ( count , this - > ct , this - > current_station , cp - > SourceStationXY ( ) , cp - > DaysInTransit ( ) , this - > owner , cp - > SourceSubsidyType ( ) , cp - > SourceSubsidyID ( ) ) ;
2009-06-28 15:12:59 +00:00
this - > route_profit + = profit ;
/* The vehicle's profit is whatever route profit there is minus feeder shares. */
2013-02-17 14:17:06 +00:00
this - > visual_profit + = profit - cp - > FeederShare ( count ) ;
2009-06-28 15:12:59 +00:00
}
/**
* Handle payment for transfer of the given cargo packet .
2009-10-06 17:23:15 +00:00
* @ param cp The cargo packet to pay for ; actual payment won ' t be made ! .
2009-06-28 15:12:59 +00:00
* @ param count The number of packets to pay for .
2009-10-06 17:23:15 +00:00
* @ return The amount of money paid for the transfer .
2009-06-28 15:12:59 +00:00
*/
2009-10-06 17:23:15 +00:00
Money CargoPayment : : PayTransfer ( const CargoPacket * cp , uint count )
2009-06-28 15:12:59 +00:00
{
Money profit = GetTransportedGoodsIncome (
2010-08-02 20:37:32 +00:00
count ,
/* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
DistanceManhattan ( cp - > LoadedAtXY ( ) , Station : : Get ( this - > current_station ) - > xy ) ,
cp - > DaysInTransit ( ) ,
this - > ct ) ;
2009-06-28 15:12:59 +00:00
2010-01-03 21:29:20 +00:00
profit = profit * _settings_game . economy . feeder_payment_share / 100 ;
2013-02-17 14:50:54 +00:00
this - > visual_transfer + = profit ; // accumulate transfer profits for whole vehicle
2009-10-06 17:23:15 +00:00
return profit ; // account for the (virtual) profit already made for the cargo packet
2009-06-28 15:12:59 +00:00
}
2007-05-01 16:45:03 +00:00
/**
2009-06-29 19:55:36 +00:00
* Prepare the vehicle to be unloaded .
2013-06-09 13:03:48 +00:00
* @ param curr_station the station where the consist is at the moment
2007-05-01 16:45:03 +00:00
* @ param front_v the vehicle to be unloaded
*/
2009-06-29 19:55:36 +00:00
void PrepareUnload ( Vehicle * front_v )
2004-08-09 17:04:08 +00:00
{
2013-06-09 13:03:48 +00:00
Station * curr_station = Station : : Get ( front_v - > last_station_visited ) ;
curr_station - > loading_vehicles . push_back ( front_v ) ;
2007-05-02 18:29:11 +00:00
/* At this moment loading cannot be finished */
2007-11-19 21:32:20 +00:00
ClrBit ( front_v - > vehicle_flags , VF_LOADING_FINISHED ) ;
2007-05-02 18:29:11 +00:00
2013-06-09 13:03:48 +00:00
/* Start unloading at the first possible moment */
2010-01-09 14:43:08 +00:00
front_v - > load_unload_ticks = 1 ;
2007-05-02 18:29:11 +00:00
2013-06-09 13:03:48 +00:00
assert ( front_v - > cargo_payment = = NULL ) ;
/* One CargoPayment per vehicle and the vehicle limit equals the
* limit in number of CargoPayments . Can ' t go wrong . */
assert_compile ( CargoPaymentPool : : MAX_SIZE = = VehiclePool : : MAX_SIZE ) ;
assert ( CargoPayment : : CanAllocateItem ( ) ) ;
front_v - > cargo_payment = new CargoPayment ( front_v ) ;
2013-10-20 13:47:58 +00:00
StationIDStack next_station = front_v - > GetNextStoppingStation ( ) ;
2013-06-09 13:03:48 +00:00
if ( front_v - > orders . list = = NULL | | ( front_v - > current_order . GetUnloadType ( ) & OUFB_NO_UNLOAD ) = = 0 ) {
Station * st = Station : : Get ( front_v - > last_station_visited ) ;
2009-06-29 19:55:36 +00:00
for ( Vehicle * v = front_v ; v ! = NULL ; v = v - > Next ( ) ) {
2013-06-09 13:03:48 +00:00
const GoodsEntry * ge = & st - > goods [ v - > cargo_type ] ;
2013-04-13 13:42:08 +00:00
if ( v - > cargo_cap > 0 & & v - > cargo . TotalCount ( ) > 0 ) {
2013-02-17 14:54:50 +00:00
v - > cargo . Stage (
2013-06-09 13:03:48 +00:00
HasBit ( ge - > acceptance_pickup , GoodsEntry : : GES_ACCEPTANCE ) ,
front_v - > last_station_visited , next_station ,
front_v - > current_order . GetUnloadType ( ) , ge ,
front_v - > cargo_payment ) ;
2013-04-06 18:57:18 +00:00
if ( v - > cargo . UnloadCount ( ) > 0 ) SetBit ( v - > vehicle_flags , VF_CARGO_UNLOADING ) ;
2007-05-01 16:45:03 +00:00
}
}
}
}
2007-03-02 18:49:11 +00:00
2013-02-17 14:54:50 +00:00
/**
* Gets the amount of cargo the given vehicle can load in the current tick .
* This is only about loading speed . The free capacity is ignored .
* @ param v Vehicle to be queried .
* @ return Amount of cargo the vehicle can load at once .
*/
2013-06-26 20:38:32 +00:00
static uint GetLoadAmount ( Vehicle * v )
2013-02-17 14:54:50 +00:00
{
const Engine * e = v - > GetEngine ( ) ;
2013-06-28 19:20:45 +00:00
uint load_amount = e - > info . load_amount ;
2013-02-17 14:54:50 +00:00
/* The default loadamount for mail is 1/4 of the load amount for passengers */
2013-06-26 20:38:32 +00:00
bool air_mail = v - > type = = VEH_AIRCRAFT & & ! Aircraft : : From ( v ) - > IsNormalAircraft ( ) ;
if ( air_mail ) load_amount = CeilDiv ( load_amount , 4 ) ;
2013-02-17 14:54:50 +00:00
if ( _settings_game . order . gradual_loading ) {
uint16 cb_load_amount = CALLBACK_FAILED ;
if ( e - > GetGRF ( ) ! = NULL & & e - > GetGRF ( ) - > grf_version > = 8 ) {
/* Use callback 36 */
cb_load_amount = GetVehicleProperty ( v , PROP_VEHICLE_LOAD_AMOUNT , CALLBACK_FAILED ) ;
} else if ( HasBit ( e - > info . callback_mask , CBM_VEHICLE_LOAD_AMOUNT ) ) {
/* Use callback 12 */
cb_load_amount = GetVehicleCallback ( CBID_VEHICLE_LOAD_AMOUNT , 0 , 0 , v - > engine_type , v ) ;
}
if ( cb_load_amount ! = CALLBACK_FAILED ) {
if ( e - > GetGRF ( ) - > grf_version < 8 ) cb_load_amount = GB ( cb_load_amount , 0 , 8 ) ;
if ( cb_load_amount > = 0x100 ) {
ErrorUnknownCallbackResult ( e - > GetGRFID ( ) , CBID_VEHICLE_LOAD_AMOUNT , cb_load_amount ) ;
} else if ( cb_load_amount ! = 0 ) {
load_amount = cb_load_amount ;
}
}
}
2013-06-26 20:38:32 +00:00
/* Scale load amount the same as capacity */
if ( HasBit ( e - > info . misc_flags , EF_NO_DEFAULT_CARGO_MULTIPLIER ) & & ! air_mail ) load_amount = CeilDiv ( load_amount * CargoSpec : : Get ( v - > cargo_type ) - > multiplier , 0x100 ) ;
2013-02-17 14:54:50 +00:00
return load_amount ;
}
/**
* Reserves cargo if the full load order and improved_load is set or if the
* current order allows autorefit .
* @ param st Station where the consist is loading at the moment .
* @ param u Front of the loading vehicle consist .
* @ param consist_capleft If given , save free capacities after reserving there .
2013-10-20 13:47:58 +00:00
* @ param next_station Station ( s ) the vehicle will stop at next .
2013-02-17 14:54:50 +00:00
*/
2013-10-20 13:47:58 +00:00
static void ReserveConsist ( Station * st , Vehicle * u , CargoArray * consist_capleft , StationIDStack next_station )
2013-02-17 14:54:50 +00:00
{
Vehicle * next_cargo = u ;
uint32 seen_cargos = 0 ;
while ( next_cargo ! = NULL ) {
if ( next_cargo - > cargo_cap = = 0 ) {
/* No need to reserve for vehicles without capacity. */
next_cargo = next_cargo - > Next ( ) ;
continue ;
}
CargoID current_cargo = next_cargo - > cargo_type ;
Vehicle * v = next_cargo ;
SetBit ( seen_cargos , current_cargo ) ;
next_cargo = NULL ;
for ( ; v ! = NULL ; v = v - > Next ( ) ) {
if ( v - > cargo_type ! = current_cargo ) {
/* Save start point for next cargo type. */
if ( next_cargo = = NULL & & ! HasBit ( seen_cargos , v - > cargo_type ) ) next_cargo = v ;
continue ;
}
2013-06-07 22:22:52 +00:00
assert ( v - > cargo_cap > = v - > cargo . RemainingCount ( ) ) ;
2013-02-17 14:54:50 +00:00
uint cap = v - > cargo_cap - v - > cargo . RemainingCount ( ) ;
/* Nothing to do if the vehicle is full */
if ( cap > 0 ) {
2013-06-09 13:03:48 +00:00
cap - = st - > goods [ v - > cargo_type ] . cargo . Reserve ( cap , & v - > cargo , st - > xy , next_station ) ;
2013-02-17 14:54:50 +00:00
}
if ( consist_capleft ! = NULL ) {
( * consist_capleft ) [ current_cargo ] + = cap ;
}
}
}
}
2011-12-10 21:00:57 +00:00
/**
* Checks whether an articulated vehicle is empty .
* @ param v Vehicle
* @ return true if all parts are empty .
*/
static bool IsArticulatedVehicleEmpty ( Vehicle * v )
{
v = v - > GetFirstEnginePart ( ) ;
for ( ; v ! = NULL ; v = v - > HasArticulatedPart ( ) ? v - > GetNextArticulatedPart ( ) : NULL ) {
2013-12-30 14:50:09 +00:00
if ( v - > cargo . StoredCount ( ) ! = 0 ) return false ;
2011-12-10 21:00:57 +00:00
}
return true ;
}
2007-05-06 14:59:01 +00:00
/**
* Loads / unload the vehicle if possible .
2011-08-14 13:43:27 +00:00
* @ param front the vehicle to be ( un ) loaded
2007-05-06 14:59:01 +00:00
*/
2013-02-17 14:54:50 +00:00
static void LoadUnloadVehicle ( Vehicle * front )
2007-05-01 16:45:03 +00:00
{
2011-08-14 13:43:27 +00:00
assert ( front - > current_order . IsType ( OT_LOADING ) ) ;
2009-08-19 15:27:55 +00:00
2011-08-14 13:43:27 +00:00
StationID last_visited = front - > last_station_visited ;
2009-05-16 23:34:14 +00:00
Station * st = Station : : Get ( last_visited ) ;
2008-01-09 17:09:53 +00:00
2013-10-20 13:47:58 +00:00
StationIDStack next_station = front - > GetNextStoppingStation ( ) ;
2013-02-17 14:54:50 +00:00
bool use_autorefit = front - > current_order . IsRefit ( ) & & front - > current_order . GetRefitCargo ( ) = = CT_AUTO_REFIT ;
CargoArray consist_capleft ;
if ( _settings_game . order . improved_load & &
( ( front - > current_order . GetLoadType ( ) & OLFB_FULL_LOAD ) ! = 0 | | use_autorefit ) ) {
2013-06-09 13:03:48 +00:00
ReserveConsist ( st , front ,
( use_autorefit & & front - > load_unload_ticks ! = 0 ) ? & consist_capleft : NULL ,
next_station ) ;
2013-02-17 14:54:50 +00:00
}
/* We have not waited enough time till the next round of loading/unloading */
if ( front - > load_unload_ticks ! = 0 ) return ;
2011-08-14 13:43:27 +00:00
if ( front - > type = = VEH_TRAIN & & ( ! IsTileType ( front - > tile , MP_STATION ) | | GetStationIndex ( front - > tile ) ! = st - > index ) ) {
2007-06-10 20:27:28 +00:00
/* The train reversed in the station. Take the "easy" way
* out and let the train just leave as it always did . */
2011-08-14 13:43:27 +00:00
SetBit ( front - > vehicle_flags , VF_LOADING_FINISHED ) ;
front - > load_unload_ticks = 1 ;
2007-06-10 20:27:28 +00:00
return ;
}
2007-05-13 21:24:58 +00:00
int unloading_time = 0 ;
2009-12-19 17:14:35 +00:00
bool dirty_vehicle = false ;
bool dirty_station = false ;
2007-05-02 18:29:11 +00:00
2008-01-10 13:13:18 +00:00
bool completely_emptied = true ;
2013-02-03 12:58:57 +00:00
bool anything_unloaded = false ;
bool anything_loaded = false ;
2010-09-25 12:48:33 +00:00
uint32 full_load_amount = 0 ;
2013-02-03 12:58:57 +00:00
uint32 cargo_not_full = 0 ;
uint32 cargo_full = 0 ;
uint32 reservation_left = 0 ;
2004-08-09 17:04:08 +00:00
2011-08-14 13:43:27 +00:00
front - > cur_speed = 0 ;
2006-12-05 17:53:33 +00:00
2011-08-14 13:43:27 +00:00
CargoPayment * payment = front - > cargo_payment ;
2009-06-29 19:55:36 +00:00
2011-12-10 21:00:57 +00:00
uint artic_part = 0 ; // Articulated part we are currently trying to load. (not counting parts without capacity)
2011-08-14 13:43:27 +00:00
for ( Vehicle * v = front ; v ! = NULL ; v = v - > Next ( ) ) {
2011-12-10 21:00:57 +00:00
if ( v = = front | | ! v - > Previous ( ) - > HasArticulatedPart ( ) ) artic_part = 0 ;
2007-05-12 09:09:10 +00:00
if ( v - > cargo_cap = = 0 ) continue ;
2011-12-10 21:00:57 +00:00
artic_part + + ;
2007-05-12 09:09:10 +00:00
2013-06-26 20:38:32 +00:00
uint load_amount = GetLoadAmount ( v ) ;
2005-11-14 19:48:04 +00:00
2007-05-12 09:09:10 +00:00
GoodsEntry * ge = & st - > goods [ v - > cargo_type ] ;
2004-08-09 17:04:08 +00:00
2011-08-14 13:43:27 +00:00
if ( HasBit ( v - > vehicle_flags , VF_CARGO_UNLOADING ) & & ( front - > current_order . GetUnloadType ( ) & OUFB_NO_UNLOAD ) = = 0 ) {
2013-02-17 14:54:50 +00:00
uint cargo_count = v - > cargo . UnloadCount ( ) ;
2008-05-29 15:13:28 +00:00
uint amount_unloaded = _settings_game . order . gradual_loading ? min ( cargo_count , load_amount ) : cargo_count ;
2009-02-25 00:12:57 +00:00
bool remaining = false ; // Are there cargo entities in this vehicle that can still be unloaded here?
2007-06-22 11:58:59 +00:00
2009-06-29 19:55:36 +00:00
payment - > SetCargo ( v - > cargo_type ) ;
2013-02-17 14:54:50 +00:00
if ( ! HasBit ( ge - > acceptance_pickup , GoodsEntry : : GES_ACCEPTANCE ) & & v - > cargo . ActionCount ( VehicleCargoList : : MTA_DELIVER ) > 0 ) {
/* The station does not accept our goods anymore. */
if ( front - > current_order . GetUnloadType ( ) & ( OUFB_TRANSFER | OUFB_UNLOAD ) ) {
/* Transfer instead of delivering. */
v - > cargo . Reassign ( v - > cargo . ActionCount ( VehicleCargoList : : MTA_DELIVER ) ,
VehicleCargoList : : MTA_DELIVER , VehicleCargoList : : MTA_TRANSFER ) ;
} else {
2013-06-07 22:22:52 +00:00
uint new_remaining = v - > cargo . RemainingCount ( ) + v - > cargo . ActionCount ( VehicleCargoList : : MTA_DELIVER ) ;
if ( v - > cargo_cap < new_remaining ) {
/* Return some of the reserved cargo to not overload the vehicle. */
2013-06-09 13:03:48 +00:00
v - > cargo . Return ( new_remaining - v - > cargo_cap , & ge - > cargo , INVALID_STATION ) ;
2013-06-07 22:22:52 +00:00
}
2013-02-17 14:54:50 +00:00
/* Keep instead of delivering. This may lead to no cargo being unloaded, so ...*/
v - > cargo . Reassign ( v - > cargo . ActionCount ( VehicleCargoList : : MTA_DELIVER ) ,
VehicleCargoList : : MTA_DELIVER , VehicleCargoList : : MTA_KEEP ) ;
/* ... say we unloaded something, otherwise we'll think we didn't unload
* something and we didn ' t load something , so we must be finished
* at this station . Setting the unloaded means that we will get a
* retry for loading in the next cycle . */
anything_unloaded = true ;
2010-11-11 10:34:44 +00:00
}
2004-08-09 17:04:08 +00:00
}
2004-11-17 08:52:47 +00:00
2013-02-17 14:54:50 +00:00
/* Mark the station dirty if we transfer, but not if we only deliver. */
dirty_station = v - > cargo . ActionCount ( VehicleCargoList : : MTA_TRANSFER ) > 0 ;
amount_unloaded = v - > cargo . Unload ( amount_unloaded , & ge - > cargo , payment ) ;
remaining = v - > cargo . UnloadCount ( ) > 0 ;
if ( amount_unloaded > 0 ) {
dirty_vehicle = true ;
anything_unloaded = true ;
unloading_time + = amount_unloaded ;
2004-09-10 19:02:27 +00:00
2013-02-17 14:54:50 +00:00
/* Deliver goods to the station */
st - > time_since_unload = 0 ;
}
2007-05-12 09:09:10 +00:00
2008-05-29 15:13:28 +00:00
if ( _settings_game . order . gradual_loading & & remaining ) {
2008-01-10 13:13:18 +00:00
completely_emptied = false ;
2007-05-12 09:09:10 +00:00
} else {
/* We have finished unloading (cargo count == 0) */
2007-11-19 21:32:20 +00:00
ClrBit ( v - > vehicle_flags , VF_CARGO_UNLOADING ) ;
2007-05-12 09:09:10 +00:00
}
continue ;
}
2007-01-31 22:33:24 +00:00
2010-08-15 22:37:30 +00:00
/* Do not pick up goods when we have no-load set or loading is stopped. */
2011-08-14 13:43:27 +00:00
if ( front - > current_order . GetLoadType ( ) & OLFB_NO_LOAD | | HasBit ( front - > vehicle_flags , VF_STOP_LOADING ) ) continue ;
2006-12-02 16:56:32 +00:00
2011-12-10 21:00:57 +00:00
/* This order has a refit, if this is the first vehicle part carrying cargo and the whole vehicle is empty, try refitting. */
if ( front - > current_order . IsRefit ( ) & & artic_part = = 1 & & IsArticulatedVehicleEmpty ( v ) & &
2013-12-30 14:50:09 +00:00
( v - > type ! = VEH_AIRCRAFT | | ( Aircraft : : From ( v ) - > IsNormalAircraft ( ) & & v - > Next ( ) - > cargo . StoredCount ( ) = = 0 ) ) ) {
bool is_normal_aircraft = ( v - > type = = VEH_AIRCRAFT & & Aircraft : : From ( v ) - > IsNormalAircraft ( ) ) ;
2011-12-10 21:00:57 +00:00
Vehicle * v_start = v - > GetFirstEnginePart ( ) ;
2011-11-04 00:38:51 +00:00
CargoID new_cid = front - > current_order . GetRefitCargo ( ) ;
2012-08-25 14:26:14 +00:00
/* Remove old capacity from consist capacity */
2013-12-30 14:50:09 +00:00
consist_capleft [ v_start - > cargo_type ] - = ( v_start - > cargo_cap - v_start - > cargo . ReservedCount ( ) ) ;
2012-08-25 14:26:14 +00:00
for ( Vehicle * w = v_start ; w - > HasArticulatedPart ( ) ; ) {
w = w - > GetNextArticulatedPart ( ) ;
2013-12-30 14:50:09 +00:00
consist_capleft [ w - > cargo_type ] - = ( w - > cargo_cap - w - > cargo . ReservedCount ( ) ) ;
}
if ( is_normal_aircraft ) {
consist_capleft [ v - > Next ( ) - > cargo_type ] - = ( v - > Next ( ) - > cargo_cap - v - > Next ( ) - > cargo . ReservedCount ( ) ) ;
2012-08-25 14:26:14 +00:00
}
2011-11-04 00:38:51 +00:00
Backup < CompanyByte > cur_company ( _current_company , front - > owner , FILE_LINE ) ;
/* Check if all articulated parts are empty and collect refit mask. */
2013-02-17 14:54:50 +00:00
uint32 refit_mask = v - > GetEngine ( ) - > info . refit_mask ;
2011-12-10 21:00:57 +00:00
Vehicle * w = v_start ;
2011-11-04 00:38:51 +00:00
while ( w - > HasArticulatedPart ( ) ) {
w = w - > GetNextArticulatedPart ( ) ;
refit_mask | = EngInfo ( w - > engine_type ) - > refit_mask ;
}
if ( new_cid = = CT_AUTO_REFIT ) {
2013-06-09 13:03:48 +00:00
/* Get a refittable cargo type with waiting cargo for next_station or INVALID_STATION. */
2011-11-04 00:38:51 +00:00
CargoID cid ;
2013-06-09 13:03:48 +00:00
new_cid = v_start - > cargo_type ;
2011-11-04 00:38:51 +00:00
FOR_EACH_SET_CARGO_ID ( cid , refit_mask ) {
2013-10-20 13:47:58 +00:00
if ( st - > goods [ cid ] . cargo . HasCargoFor ( next_station ) ) {
2011-11-04 00:38:51 +00:00
/* Try to find out if auto-refitting would succeed. In case the refit is allowed,
* the returned refit capacity will be greater than zero . */
2013-02-24 16:41:51 +00:00
DoCommand ( v_start - > tile , v_start - > index , cid | 1U < < 6 | 0xFF < < 8 | 1U < < 16 , DC_QUERY_COST , GetCmdRefitVeh ( v_start ) ) ; // Auto-refit and only this vehicle including artic parts.
2013-06-09 13:03:48 +00:00
/* Try to balance different loadable cargoes between parts of the consist, so that
* all of them can be loaded . Avoid a situation where all vehicles suddenly switch
* to the first loadable cargo for which there is only one packet . */
if ( _returned_refit_capacity > 0 & & consist_capleft [ cid ] < consist_capleft [ new_cid ] ) {
2011-11-04 00:38:51 +00:00
new_cid = cid ;
}
}
}
}
/* Refit if given a valid cargo. */
2013-06-09 13:03:48 +00:00
if ( new_cid < NUM_CARGO & & new_cid ! = v_start - > cargo_type ) {
2013-12-30 14:50:09 +00:00
StationID next_one = StationIDStack ( next_station ) . Pop ( ) ;
v_start - > cargo . Return ( UINT_MAX , & st - > goods [ v_start - > cargo_type ] . cargo , next_one ) ;
for ( w = v_start ; w - > HasArticulatedPart ( ) ; ) {
w = w - > GetNextArticulatedPart ( ) ;
w - > cargo . Return ( UINT_MAX , & st - > goods [ w - > cargo_type ] . cargo , next_one ) ;
}
if ( is_normal_aircraft ) {
v - > Next ( ) - > cargo . Return ( UINT_MAX , & st - > goods [ v - > Next ( ) - > cargo_type ] . cargo , next_one ) ;
}
2013-02-24 16:41:51 +00:00
CommandCost cost = DoCommand ( v_start - > tile , v_start - > index , new_cid | 1U < < 6 | 0xFF < < 8 | 1U < < 16 , DC_EXEC , GetCmdRefitVeh ( v_start ) ) ; // Auto-refit and only this vehicle including artic parts.
2011-11-04 13:21:24 +00:00
if ( cost . Succeeded ( ) ) front - > profit_this_year - = cost . GetCost ( ) < < 8 ;
2011-11-04 00:38:51 +00:00
ge = & st - > goods [ v - > cargo_type ] ;
}
2013-02-17 14:54:50 +00:00
/* Add new capacity to consist capacity and reserve cargo */
w = v_start ;
do {
2013-06-09 13:03:48 +00:00
st - > goods [ w - > cargo_type ] . cargo . Reserve ( w - > cargo_cap , & w - > cargo , st - > xy , next_station ) ;
2013-04-13 13:42:08 +00:00
consist_capleft [ w - > cargo_type ] + = w - > cargo_cap - w - > cargo . RemainingCount ( ) ;
2013-02-17 14:54:50 +00:00
w = w - > HasArticulatedPart ( ) ? w - > GetNextArticulatedPart ( ) : NULL ;
} while ( w ! = NULL ) ;
2013-12-30 14:50:09 +00:00
if ( is_normal_aircraft ) {
consist_capleft [ v - > Next ( ) - > cargo_type ] + = v - > Next ( ) - > cargo_cap - v - > Next ( ) - > cargo . RemainingCount ( ) ;
}
2012-08-25 14:26:14 +00:00
2011-11-04 00:38:51 +00:00
cur_company . Restore ( ) ;
}
2013-07-06 17:01:31 +00:00
/* As we're loading here the following link can carry the full capacity of the vehicle. */
v - > refit_cap = v - > cargo_cap ;
2004-08-09 17:04:08 +00:00
/* update stats */
2007-05-12 09:09:10 +00:00
int t ;
2011-08-14 13:43:27 +00:00
switch ( front - > type ) {
2010-11-06 13:03:17 +00:00
case VEH_TRAIN : /* FALL THROUGH */
case VEH_SHIP :
2011-08-14 13:43:27 +00:00
t = front - > vcache . cached_max_speed ;
2010-11-06 13:03:17 +00:00
break ;
2010-11-06 13:05:11 +00:00
case VEH_ROAD :
2011-08-14 13:43:27 +00:00
t = front - > vcache . cached_max_speed / 2 ;
2010-11-06 13:05:11 +00:00
break ;
case VEH_AIRCRAFT :
2011-08-14 13:43:27 +00:00
t = Aircraft : : From ( front ) - > GetSpeedOldUnits ( ) ; // Convert to old units.
2010-11-06 13:05:11 +00:00
break ;
2009-09-15 19:56:41 +00:00
default : NOT_REACHED ( ) ;
2006-02-06 09:18:04 +00:00
}
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. */
2006-02-06 09:18:04 +00:00
ge - > last_speed = min ( t , 255 ) ;
2012-11-12 18:10:21 +00:00
ge - > last_age = min ( _cur_year - front - > build_year , 255 ) ;
2012-11-12 21:59:02 +00:00
ge - > time_since_pickup = 0 ;
2004-08-09 17:04:08 +00:00
2013-06-09 13:03:48 +00:00
assert ( v - > cargo_cap > = v - > cargo . StoredCount ( ) ) ;
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 . */
2013-06-09 13:03:48 +00:00
uint cap_left = v - > cargo_cap - v - > cargo . StoredCount ( ) ;
2013-04-13 13:42:08 +00:00
if ( cap_left > 0 & & ( v - > cargo . ActionCount ( VehicleCargoList : : MTA_LOAD ) > 0 | | ge - > cargo . AvailableCount ( ) > 0 ) ) {
2013-02-17 14:54:50 +00:00
if ( _settings_game . order . gradual_loading ) cap_left = min ( cap_left , load_amount ) ;
2013-04-13 13:42:08 +00:00
if ( v - > cargo . StoredCount ( ) = = 0 ) TriggerVehicle ( v , VEHICLE_TRIGGER_NEW_CARGO ) ;
2013-02-17 14:54:50 +00:00
2013-06-09 13:03:48 +00:00
uint loaded = ge - > cargo . Load ( cap_left , & v - > cargo , st - > xy , next_station ) ;
2013-02-17 14:54:50 +00:00
if ( v - > cargo . ActionCount ( VehicleCargoList : : MTA_LOAD ) > 0 ) {
/* Remember if there are reservations left so that we don't stop
* loading before they ' re loaded . */
SetBit ( reservation_left , v - > cargo_type ) ;
2007-05-14 20:12:32 +00:00
}
2010-09-25 12:48:33 +00:00
/* Store whether the maximum possible load amount was loaded or not.*/
2013-06-09 13:03:48 +00:00
if ( loaded = = cap_left ) {
2010-09-25 12:48:33 +00:00
SetBit ( full_load_amount , v - > cargo_type ) ;
} else {
ClrBit ( full_load_amount , v - > cargo_type ) ;
}
2007-05-14 20:12:32 +00:00
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
2008-01-10 13:13:18 +00:00
* completely_emptied assignment can then be safely
2004-11-17 08:52:47 +00:00
* removed ; that ' s how TTDPatch behaves too . - - pasky */
2013-02-17 14:54:50 +00:00
if ( loaded > 0 ) {
completely_emptied = false ;
anything_loaded = true ;
2007-03-02 18:49:11 +00:00
2013-02-17 14:54:50 +00:00
st - > time_since_load = 0 ;
st - > last_vehicle_type = v - > type ;
2004-09-10 19:02:27 +00:00
2013-04-13 13:42:08 +00:00
if ( ge - > cargo . TotalCount ( ) = = 0 ) {
2013-02-17 14:54:50 +00:00
TriggerStationRandomisation ( st , st - > xy , SRT_CARGO_TAKEN , v - > cargo_type ) ;
TriggerStationAnimation ( st , st - > xy , SAT_CARGO_TAKEN , v - > cargo_type ) ;
AirportAnimationTrigger ( st , AAT_STATION_CARGO_TAKEN , v - > cargo_type ) ;
}
2008-04-19 23:19:12 +00:00
2013-02-17 14:54:50 +00:00
unloading_time + = loaded ;
2007-08-26 13:55:36 +00:00
2013-02-17 14:54:50 +00:00
dirty_vehicle = dirty_station = true ;
}
2004-08-09 17:04:08 +00:00
}
2007-05-13 21:24:58 +00:00
2013-04-13 13:42:08 +00:00
if ( v - > cargo . StoredCount ( ) > = v - > cargo_cap ) {
2007-11-20 13:35:54 +00:00
SetBit ( cargo_full , v - > cargo_type ) ;
2007-05-13 21:24:58 +00:00
} else {
2007-11-20 13:35:54 +00:00
SetBit ( cargo_not_full , v - > cargo_type ) ;
2007-05-13 21:24:58 +00:00
}
2004-08-09 17:04:08 +00:00
}
2011-08-14 13:47:14 +00:00
if ( anything_loaded | | anything_unloaded ) {
2013-01-11 07:39:25 +00:00
if ( front - > type = = VEH_TRAIN ) {
TriggerStationRandomisation ( st , front - > tile , SRT_TRAIN_LOADS ) ;
TriggerStationAnimation ( st , front - > tile , SAT_TRAIN_LOADS ) ;
}
2011-08-14 13:47:14 +00:00
}
2010-07-31 21:02:56 +00:00
/* Only set completely_emptied, if we just unloaded all remaining cargo */
2008-01-10 13:13:18 +00:00
completely_emptied & = anything_unloaded ;
2009-06-29 19:55:36 +00:00
if ( ! anything_unloaded ) delete payment ;
2011-08-14 13:43:27 +00:00
ClrBit ( front - > vehicle_flags , VF_STOP_LOADING ) ;
2007-05-13 21:24:58 +00:00
if ( anything_loaded | | anything_unloaded ) {
2008-05-29 15:13:28 +00:00
if ( _settings_game . order . gradual_loading ) {
2007-05-13 21:24:58 +00:00
/* The time it takes to load one 'slice' of cargo or passengers depends
2009-03-14 18:16:29 +00:00
* on the vehicle type - the values here are those found in TTDPatch */
2007-05-13 21:24:58 +00:00
const uint gradual_loading_wait_time [ ] = { 40 , 20 , 10 , 20 } ;
2006-12-02 16:56:32 +00:00
2011-08-14 13:43:27 +00:00
unloading_time = gradual_loading_wait_time [ front - > type ] ;
2007-05-13 21:24:58 +00:00
}
2010-09-25 12:48:33 +00:00
/* We loaded less cargo than possible for all cargo types and it's not full
* load and we ' re not supposed to wait any longer : stop loading . */
2013-02-03 12:58:57 +00:00
if ( ! anything_unloaded & & full_load_amount = = 0 & & reservation_left = = 0 & & ! ( front - > current_order . GetLoadType ( ) & OLFB_FULL_LOAD ) & &
2011-08-14 13:43:27 +00:00
front - > current_order_time > = ( uint ) max ( front - > current_order . wait_time - front - > lateness_counter , 0 ) ) {
SetBit ( front - > vehicle_flags , VF_STOP_LOADING ) ;
2010-09-25 12:48:33 +00:00
}
2007-05-13 21:24:58 +00:00
} else {
bool finished_loading = true ;
2011-08-14 13:43:27 +00:00
if ( front - > current_order . GetLoadType ( ) & OLFB_FULL_LOAD ) {
if ( front - > current_order . GetLoadType ( ) = = OLF_FULL_LOAD_ANY ) {
2007-05-13 21:24:58 +00:00
/* if the aircraft carries passengers and is NOT full, then
* continue loading , no matter how much mail is in */
2013-04-13 13:42:08 +00:00
if ( ( front - > type = = VEH_AIRCRAFT & & IsCargoInClass ( front - > cargo_type , CC_PASSENGERS ) & & front - > cargo_cap > front - > cargo . StoredCount ( ) ) | |
2010-08-02 20:47:27 +00:00
( cargo_not_full & & ( cargo_full & ~ cargo_not_full ) = = 0 ) ) { // There are still non-full cargoes
2007-05-13 21:24:58 +00:00
finished_loading = false ;
}
} else if ( cargo_not_full ! = 0 ) {
finished_loading = false ;
2006-12-05 17:53:33 +00:00
}
2013-05-19 14:22:04 +00:00
/* Refresh next hop stats if we're full loading to make the links
* known to the distribution algorithm and allow cargo to be sent
* along them . Otherwise the vehicle could wait for cargo
* indefinitely if it hasn ' t visited the other links yet , or if the
* links die while it ' s loading . */
2013-10-22 18:34:10 +00:00
if ( ! finished_loading ) LinkRefresher : : Run ( front ) ;
2006-12-05 17:53:33 +00:00
}
2007-05-13 21:24:58 +00:00
unloading_time = 20 ;
2011-08-14 13:43:27 +00:00
SB ( front - > vehicle_flags , VF_LOADING_FINISHED , 1 , finished_loading ) ;
2006-12-02 16:56:32 +00:00
}
2011-08-14 13:43:27 +00:00
if ( front - > type = = VEH_TRAIN ) {
2007-02-23 18:55:07 +00:00
/* Each platform tile is worth 2 rail vehicles. */
2011-08-14 13:43:27 +00:00
int overhang = front - > GetGroundVehicleCache ( ) - > cached_total_length - st - > GetPlatformLength ( front - > 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
}
}
2007-09-08 22:04:49 +00:00
/* Calculate the loading indicator fill percent and display
* In the Game Menu do not display indicators
2008-05-29 15:13:28 +00:00
* If _settings_client . gui . loading_indicators = = 2 , show indicators ( bool can be promoted to int as 0 or 1 - results in 2 > 0 , 1 )
2008-09-30 20:39:50 +00:00
* if _settings_client . gui . loading_indicators = = 1 , _local_company must be the owner or must be a spectator to show ind . , so 1 > 0
2008-05-29 15:13:28 +00:00
* if _settings_client . gui . loading_indicators = = 0 , do not display indicators . . . 0 is never greater than anything
2007-09-08 22:04:49 +00:00
*/
2011-08-14 13:43:27 +00:00
if ( _game_mode ! = GM_MENU & & ( _settings_client . gui . loading_indicators > ( uint ) ( front - > owner ! = _local_company & & _local_company ! = COMPANY_SPECTATOR ) ) ) {
2007-06-22 18:28:44 +00:00
StringID percent_up_down = STR_NULL ;
2011-08-14 13:43:27 +00:00
int percent = CalcPercentVehicleFilled ( front , & percent_up_down ) ;
if ( front - > fill_percent_te_id = = INVALID_TE_ID ) {
front - > fill_percent_te_id = ShowFillingPercent ( front - > x_pos , front - > y_pos , front - > z_pos + 20 , percent , percent_up_down ) ;
2007-06-21 16:17:47 +00:00
} else {
2011-08-14 13:43:27 +00:00
UpdateFillingPercent ( front - > fill_percent_te_id , percent , percent_up_down ) ;
2007-06-21 16:17:47 +00:00
}
}
2009-07-24 00:08:48 +00:00
/* Always wait at least 1, otherwise we'll wait 'infinitively' long. */
2011-08-14 13:43:27 +00:00
front - > load_unload_ticks = max ( 1 , unloading_time ) ;
2004-08-09 17:04:08 +00:00
2008-01-10 13:13:18 +00:00
if ( completely_emptied ) {
2013-01-02 22:20:07 +00:00
/* Make sure the vehicle is marked dirty, since we need to update the NewGRF
* properties such as weight , power and TE whenever the trigger runs . */
2013-01-03 18:18:32 +00:00
dirty_vehicle = true ;
2011-08-14 13:43:27 +00:00
TriggerVehicle ( front , VEHICLE_TRIGGER_EMPTY ) ;
2004-11-17 08:52:47 +00:00
}
2009-12-19 17:14:35 +00:00
if ( dirty_vehicle ) {
2011-08-14 13:43:27 +00:00
SetWindowDirty ( GetWindowClassForVehicleType ( front - > type ) , front - > owner ) ;
SetWindowDirty ( WC_VEHICLE_DETAILS , front - > index ) ;
front - > MarkDirty ( ) ;
2009-12-19 17:14:35 +00:00
}
if ( dirty_station ) {
st - > MarkTilesDirty ( true ) ;
SetWindowDirty ( 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 )
{
2009-06-28 14:29:58 +00:00
/* No vehicle is here... */
if ( st - > loading_vehicles . empty ( ) ) return ;
2010-12-11 11:00:42 +00:00
Vehicle * last_loading = NULL ;
std : : list < Vehicle * > : : iterator iter ;
/* Check if anything will be loaded at all. Otherwise we don't need to reserve either. */
for ( iter = st - > loading_vehicles . begin ( ) ; iter ! = st - > loading_vehicles . end ( ) ; + + iter ) {
Vehicle * v = * iter ;
if ( ( v - > vehstatus & ( VS_STOPPED | VS_CRASHED ) ) ) continue ;
assert ( v - > load_unload_ticks ! = 0 ) ;
if ( - - v - > load_unload_ticks = = 0 ) last_loading = v ;
}
/* We only need to reserve and load/unload up to the last loading vehicle.
* Anything else will be forgotten anyway after returning from this function .
*
* Especially this means we do _not_ need to reserve cargo for a single
* consist in a station which is not allowed to load yet because its
* load_unload_ticks is still not 0.
*/
if ( last_loading = = NULL ) return ;
2007-05-14 16:07:05 +00:00
for ( iter = st - > loading_vehicles . begin ( ) ; iter ! = st - > loading_vehicles . end ( ) ; + + iter ) {
Vehicle * v = * iter ;
2013-02-17 14:54:50 +00:00
if ( ! ( v - > vehstatus & ( VS_STOPPED | VS_CRASHED ) ) ) LoadUnloadVehicle ( v ) ;
2010-12-11 11:00:42 +00:00
if ( v = = last_loading ) break ;
2007-05-14 16:07:05 +00:00
}
2009-06-29 19:55:36 +00:00
/* Call the production machinery of industries */
const Industry * const * isend = _cargo_delivery_destinations . End ( ) ;
for ( Industry * * iid = _cargo_delivery_destinations . Begin ( ) ; iid ! = isend ; iid + + ) {
TriggerIndustryProduction ( * iid ) ;
}
_cargo_delivery_destinations . Clear ( ) ;
2007-05-14 16:07:05 +00:00
}
2010-08-01 17:45:53 +00:00
/**
* Monthly update of the economic data ( of the companies as well as economic fluctuations ) .
*/
2008-09-30 20:39:50 +00:00
void CompaniesMonthlyLoop ( )
2004-08-09 17:04:08 +00:00
{
2008-09-30 20:39:50 +00:00
CompaniesGenStatistics ( ) ;
2009-09-06 18:53:57 +00:00
if ( _settings_game . economy . inflation ) {
AddInflation ( ) ;
RecomputePrices ( ) ;
}
2008-09-30 20:39:50 +00:00
CompaniesPayInterest ( ) ;
2004-08-09 17:04:08 +00:00
HandleEconomyFluctuations ( ) ;
}
2008-09-30 20:39:50 +00:00
static void DoAcquireCompany ( Company * c )
2004-08-09 17:04:08 +00:00
{
2009-01-12 17:11:45 +00:00
CompanyID ci = c - > index ;
2004-08-09 17:04:08 +00:00
2008-07-18 16:26:51 +00:00
CompanyNewsInformation * cni = MallocT < CompanyNewsInformation > ( 1 ) ;
2009-05-16 23:34:14 +00:00
cni - > FillData ( c , Company : : Get ( _current_company ) ) ;
2008-07-18 16:26:51 +00:00
2009-04-21 23:40:56 +00:00
SetDParam ( 0 , STR_NEWS_COMPANY_MERGER_TITLE ) ;
SetDParam ( 1 , c - > bankrupt_value = = 0 ? STR_NEWS_MERGER_TAKEOVER_TITLE : STR_NEWS_COMPANY_MERGER_DESCRIPTION ) ;
2008-07-18 16:26:51 +00:00
SetDParamStr ( 2 , cni - > company_name ) ;
SetDParamStr ( 3 , cni - > other_company_name ) ;
2008-09-30 20:39:50 +00:00
SetDParam ( 4 , c - > bankrupt_value ) ;
2012-05-26 14:15:46 +00:00
AddCompanyNewsItem ( STR_MESSAGE_NEWS_FORMAT , cni ) ;
2011-11-29 23:15:35 +00:00
AI : : BroadcastNewEvent ( new ScriptEventCompanyMerger ( ci , _current_company ) ) ;
2011-12-19 20:59:36 +00:00
Game : : NewEvent ( new ScriptEventCompanyMerger ( ci , _current_company ) ) ;
2004-08-09 17:04:08 +00:00
2008-09-30 20:39:50 +00:00
ChangeOwnershipOfCompanyItems ( ci , _current_company ) ;
2004-08-09 17:04:08 +00:00
2008-09-30 20:39:50 +00:00
if ( c - > bankrupt_value = = 0 ) {
2010-08-02 20:19:10 +00:00
Company * owner = Company : : Get ( _current_company ) ;
2008-09-30 20:39:50 +00:00
owner - > current_loan + = c - > current_loan ;
2004-08-09 17:04:08 +00:00
}
2009-06-10 22:05:01 +00:00
if ( c - > is_ai ) AI : : Stop ( c - > index ) ;
2009-01-12 17:11:45 +00:00
2008-09-30 20:39:50 +00:00
DeleteCompanyWindows ( ci ) ;
2008-05-18 16:51:44 +00:00
InvalidateWindowClassesData ( WC_TRAINS_LIST , 0 ) ;
InvalidateWindowClassesData ( WC_SHIPS_LIST , 0 ) ;
InvalidateWindowClassesData ( WC_ROADVEH_LIST , 0 ) ;
InvalidateWindowClassesData ( WC_AIRCRAFT_LIST , 0 ) ;
2008-07-18 16:40:29 +00:00
2008-09-30 20:39:50 +00:00
delete c ;
2004-08-09 17:04:08 +00:00
}
2008-09-30 20:39:50 +00:00
extern int GetAmountOwnedBy ( const Company * c , Owner owner ) ;
2004-12-12 14:00:25 +00:00
2010-08-01 19:22:34 +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
2008-09-30 20:39:50 +00:00
* @ param p1 company to buy the shares from
2005-05-12 00:11:37 +00:00
* @ param p2 unused
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 00:11:37 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuyShareInCompany ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2008-01-09 16:55:48 +00:00
CommandCost cost ( EXPENSES_OTHER ) ;
2010-04-17 13:45:48 +00:00
CompanyID target_company = ( CompanyID ) p1 ;
Company * c = Company : : GetIfValid ( target_company ) ;
2009-05-18 16:21:28 +00:00
2009-03-15 00:32:18 +00:00
/* Check if buying shares is allowed (protection against modified clients)
* Cannot buy own shares */
2010-04-17 13:45:48 +00:00
if ( c = = NULL | | ! _settings_game . economy . allow_shares | | _current_company = = target_company ) return CMD_ERROR ;
2007-08-31 17:15:46 +00:00
2005-05-12 00:11:37 +00:00
/* Protect new companies from hostile takeovers */
2009-08-05 17:59:21 +00:00
if ( _cur_year - c - > inaugurated_year < 6 ) return_cmd_error ( STR_ERROR_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) */
2008-09-30 20:39:50 +00:00
if ( GetAmountOwnedBy ( c , COMPANY_SPECTATOR ) = = 0 ) return cost ;
2005-01-07 23:59:59 +00:00
2010-08-06 20:28:16 +00:00
if ( GetAmountOwnedBy ( c , COMPANY_SPECTATOR ) = = 1 ) {
if ( ! c - > is_ai ) return cost ; // We can not buy out a real company (temporarily). TODO: well, enable it obviously.
if ( GetAmountOwnedBy ( c , _current_company ) = = 3 & & ! MayCompanyTakeOver ( _current_company , target_company ) ) return_cmd_error ( STR_ERROR_TOO_MANY_VEHICLES_IN_GAME ) ;
}
2005-01-15 08:58:31 +00:00
2008-09-30 20:39:50 +00:00
cost . AddCost ( CalculateCompanyValue ( c ) > > 2 ) ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2008-09-30 20:39:50 +00:00
OwnerByte * b = c - > share_owners ;
2005-05-12 00:11:37 +00:00
2009-03-15 00:32:18 +00:00
while ( * b ! = COMPANY_SPECTATOR ) b + + ; // share owners is guaranteed to contain at least one COMPANY_SPECTATOR
2008-09-30 20:39:50 +00:00
* b = _current_company ;
2004-08-09 17:04:08 +00:00
2010-08-02 20:19:10 +00:00
for ( int i = 0 ; c - > share_owners [ i ] = = _current_company ; ) {
2004-08-09 17:04:08 +00:00
if ( + + i = = 4 ) {
2008-09-30 20:39:50 +00:00
c - > bankrupt_value = 0 ;
DoAcquireCompany ( c ) ;
2004-08-09 17:04:08 +00:00
break ;
}
}
2013-02-04 20:29:38 +00:00
InvalidateWindowData ( WC_COMPANY , target_company ) ;
2010-10-17 17:37:45 +00:00
CompanyAdminUpdate ( c ) ;
2004-08-09 17:04:08 +00:00
}
return cost ;
}
2010-08-01 19:22:34 +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
2008-09-30 20:39:50 +00:00
* @ param p1 company to sell the shares from
2005-05-12 00:11:37 +00:00
* @ param p2 unused
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 00:11:37 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdSellShareInCompany ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-04-17 13:45:48 +00:00
CompanyID target_company = ( CompanyID ) p1 ;
Company * c = Company : : GetIfValid ( target_company ) ;
2009-05-18 16:21:28 +00:00
2011-07-02 19:05:42 +00:00
/* Cannot sell own shares */
if ( c = = NULL | | _current_company = = target_company ) return CMD_ERROR ;
/* Check if selling shares is allowed (protection against modified clients).
* However , we must sell shares of companies being closed down . */
if ( ! _settings_game . economy . allow_shares & & ! ( flags & DC_BANKRUPT ) ) return CMD_ERROR ;
2007-08-31 17:15:46 +00:00
2004-12-14 18:17:24 +00:00
/* Those lines are here for network-protection (clients can be slow) */
2008-09-30 20:39:50 +00:00
if ( GetAmountOwnedBy ( c , _current_company ) = = 0 ) return CommandCost ( ) ;
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 */
2008-09-30 20:39:50 +00:00
Money cost = CalculateCompanyValue ( c ) > > 2 ;
2004-08-09 17:04:08 +00:00
cost = - ( cost - ( cost > > 7 ) ) ;
if ( flags & DC_EXEC ) {
2008-09-30 20:39:50 +00:00
OwnerByte * b = c - > share_owners ;
while ( * b ! = _current_company ) b + + ; // share owners is guaranteed to contain company
* b = COMPANY_SPECTATOR ;
2013-02-04 20:29:38 +00:00
InvalidateWindowData ( WC_COMPANY , target_company ) ;
2010-10-17 17:37:45 +00:00
CompanyAdminUpdate ( c ) ;
2004-08-09 17:04:08 +00:00
}
2008-01-09 16:55:48 +00:00
return CommandCost ( EXPENSES_OTHER , cost ) ;
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
* Buy up another company .
2005-05-12 00:11:37 +00:00
* When a competing company is gone bankrupt you get the chance to purchase
* that company .
2008-09-30 20:39:50 +00:00
* @ todo currently this only works for AI companies
2006-04-10 07:15:58 +00:00
* @ param tile unused
2007-04-06 04:10:19 +00:00
* @ param flags type of operation
2008-09-30 20:39:50 +00:00
* @ param p1 company to buy up
2005-05-12 00:11:37 +00:00
* @ param p2 unused
2009-09-18 14:23:58 +00:00
* @ param text unused
* @ return the cost of this operation or an error
2005-05-12 00:11:37 +00:00
*/
2009-02-09 21:20:05 +00:00
CommandCost CmdBuyCompany ( TileIndex tile , DoCommandFlag flags , uint32 p1 , uint32 p2 , const char * text )
2004-08-09 17:04:08 +00:00
{
2010-04-17 13:45:48 +00:00
CompanyID target_company = ( CompanyID ) p1 ;
Company * c = Company : : GetIfValid ( target_company ) ;
2009-09-01 12:57:04 +00:00
if ( c = = NULL ) return CMD_ERROR ;
2005-05-12 00:11:37 +00:00
2009-09-01 12:57:04 +00:00
/* Disable takeovers when not asked */
if ( ! HasBit ( c - > bankrupt_asked , _current_company ) ) return CMD_ERROR ;
/* Disable taking over the local company in single player */
if ( ! _networking & & _local_company = = c - > index ) return CMD_ERROR ;
2007-04-01 10:55:31 +00:00
2008-09-30 20:39:50 +00:00
/* Do not allow companies to take over themselves */
2010-04-17 13:45:48 +00:00
if ( target_company = = _current_company ) return CMD_ERROR ;
2005-05-12 00:11:37 +00:00
2010-08-06 20:26:01 +00:00
/* Disable taking over when not allowed. */
if ( ! MayCompanyTakeOver ( _current_company , target_company ) ) return CMD_ERROR ;
2009-09-14 22:09:50 +00:00
/* Get the cost here as the company is deleted in DoAcquireCompany. */
CommandCost cost ( EXPENSES_OTHER , c - > bankrupt_value ) ;
2005-05-12 00:11:37 +00:00
if ( flags & DC_EXEC ) {
2008-09-30 20:39:50 +00:00
DoAcquireCompany ( c ) ;
2004-08-09 17:04:08 +00:00
}
2009-09-14 22:09:50 +00:00
return cost ;
2004-08-09 17:04:08 +00:00
}