2009-08-21 22:21:05 +02: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 17:11:33 +02:00
/** @file industry_cmd.cpp Handling of industry tiles. */
2007-03-03 05:04:22 +01:00
2004-08-09 19:04:08 +02:00
# include "stdafx.h"
2006-03-05 11:19:33 +01:00
# include "clear_map.h"
2009-08-30 13:47:41 +02:00
# include "industry.h"
2009-06-24 19:39:54 +02:00
# include "station_base.h"
2012-01-03 22:32:51 +01:00
# include "landscape.h"
2008-01-09 10:57:48 +01:00
# include "viewport_func.h"
2007-12-21 22:50:46 +01:00
# include "command_func.h"
2004-08-09 19:04:08 +02:00
# include "town.h"
2008-03-28 09:53:36 +01:00
# include "news_func.h"
2009-01-31 21:16:06 +01:00
# include "cheat_type.h"
2020-12-22 14:29:48 +01:00
# include "company_base.h"
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
# include "genworld.h"
2007-02-02 16:14:28 +01:00
# include "tree_map.h"
2009-11-05 20:46:17 +01:00
# include "newgrf_cargo.h"
2010-04-24 15:39:11 +02:00
# include "newgrf_debug.h"
2007-06-19 19:33:12 +02:00
# include "newgrf_industrytiles.h"
2007-09-15 00:27:40 +02:00
# include "autoslope.h"
2007-11-24 09:45:04 +01:00
# include "water.h"
2023-06-15 17:09:34 +02:00
# include "strings_internal.h"
2007-12-25 12:26:07 +01:00
# include "window_func.h"
2007-12-27 14:35:39 +01:00
# include "vehicle_func.h"
2007-12-29 10:24:26 +01:00
# include "sound_func.h"
2008-04-20 10:22:59 +02:00
# include "animated_tile_func.h"
2008-04-20 13:12:07 +02:00
# include "effectvehicle_func.h"
2010-01-15 17:41:15 +01:00
# include "effectvehicle_base.h"
2009-01-12 18:11:45 +01:00
# include "ai/ai.hpp"
2009-05-22 17:13:50 +02:00
# include "core/pool_func.hpp"
2009-05-23 17:46:00 +02:00
# include "subsidy_func.h"
2010-05-31 22:22:57 +02:00
# include "core/backup_type.hpp"
2010-09-04 02:16:33 +02:00
# include "object_base.h"
2011-12-19 21:59:36 +01:00
# include "game/game.hpp"
2014-08-13 21:31:45 +02:00
# include "error.h"
2021-01-15 15:38:14 +01:00
# include "string_func.h"
2021-10-05 22:02:27 +02:00
# include "industry_cmd.h"
2021-10-30 01:31:46 +02:00
# include "landscape_cmd.h"
# include "terraform_cmd.h"
2023-04-13 13:56:00 +02:00
# include "timer/timer.h"
# include "timer/timer_game_calendar.h"
2024-01-22 15:04:34 +01:00
# include "timer/timer_game_economy.h"
2023-04-24 18:55:40 +02:00
# include "timer/timer_game_tick.h"
2004-08-09 19:04:08 +02:00
2008-01-13 02:21:35 +01:00
# include "table/strings.h"
# include "table/industry_land.h"
# include "table/build_industry.h"
2014-04-23 22:13:33 +02:00
# include "safeguards.h"
2009-05-22 17:13:50 +02:00
IndustryPool _industry_pool ( " Industry " ) ;
INSTANTIATE_POOL_METHODS ( Industry )
2006-08-26 21:51:49 +02:00
void ShowIndustryViewWindow ( int industry ) ;
void BuildOilRig ( TileIndex tile ) ;
2024-03-16 23:59:32 +01:00
static uint8_t _industry_sound_ctr ;
2006-08-26 21:51:49 +02:00
static TileIndex _industry_sound_tile ;
2023-05-08 19:01:06 +02:00
uint16_t Industry : : counts [ NUM_INDUSTRYTYPES ] ;
2007-06-08 17:48:48 +02:00
2007-05-29 19:41:59 +02:00
IndustrySpec _industry_specs [ NUM_INDUSTRYTYPES ] ;
IndustryTileSpec _industry_tile_specs [ NUM_INDUSTRYTILES ] ;
2010-11-13 16:02:31 +01:00
IndustryBuildData _industry_builder ; ///< In-game manager of industries.
2007-05-29 19:41:59 +02:00
2023-07-16 21:34:42 +02:00
static int WhoCanServiceIndustry ( Industry * ind ) ;
2010-08-01 21:22:34 +02:00
/**
* This function initialize the spec arrays of both
2007-05-29 19:41:59 +02:00
* industry and industry tiles .
* It adjusts the enabling of the industry too , based on climate availability .
2010-08-01 21:44:49 +02:00
* This will allow for clearer testings
*/
2007-05-29 19:41:59 +02:00
void ResetIndustries ( )
{
2023-01-08 02:36:07 +01:00
auto industry_insert = std : : copy ( std : : begin ( _origin_industry_specs ) , std : : end ( _origin_industry_specs ) , std : : begin ( _industry_specs ) ) ;
std : : fill ( industry_insert , std : : end ( _industry_specs ) , IndustrySpec { } ) ;
2019-10-04 21:26:44 +02:00
2023-01-08 02:36:07 +01:00
for ( IndustryType i = 0 ; i < lengthof ( _origin_industry_specs ) ; i + + ) {
2019-10-04 21:26:44 +02:00
/* Enable only the current climate industries */
2023-01-08 02:36:07 +01:00
_industry_specs [ i ] . enabled = HasBit ( _industry_specs [ i ] . climate_availability , _settings_game . game_creation . landscape ) ;
2007-05-29 19:41:59 +02:00
}
2023-01-08 02:36:07 +01:00
auto industry_tile_insert = std : : copy ( std : : begin ( _origin_industry_tile_specs ) , std : : end ( _origin_industry_tile_specs ) , std : : begin ( _industry_tile_specs ) ) ;
std : : fill ( industry_tile_insert , std : : end ( _industry_tile_specs ) , IndustryTileSpec { } ) ;
2007-10-03 02:57:54 +02:00
/* Reset any overrides that have been set. */
_industile_mngr . ResetOverride ( ) ;
_industry_mngr . ResetOverride ( ) ;
2007-05-29 19:41:59 +02:00
}
2006-04-10 23:00:56 +02:00
/**
* Retrieve the type for this industry . Although it is accessed by a tile ,
* it will return the general type of industry , and not the sprite index
* as would do GetIndustryGfx .
* @ param tile that is queried
* @ pre IsTileType ( tile , MP_INDUSTRY )
* @ return general type for this industry , as defined in industry . h
2010-08-01 21:44:49 +02:00
*/
2023-01-21 16:40:28 +01:00
IndustryType GetIndustryType ( Tile tile )
2006-04-10 23:00:56 +02:00
{
assert ( IsTileType ( tile , MP_INDUSTRY ) ) ;
2009-08-30 13:47:41 +02:00
const Industry * ind = Industry : : GetByTile ( tile ) ;
2019-04-10 23:07:06 +02:00
assert ( ind ! = nullptr ) ;
2009-05-22 17:13:50 +02:00
return ind - > type ;
2006-04-10 23:00:56 +02:00
}
2004-08-09 19:04:08 +02:00
2006-04-26 16:58:06 +02:00
/**
* Accessor for array _industry_specs .
* This will ensure at once : proper access and
* not allowing modifications of it .
2006-04-26 23:10:01 +02:00
* @ param thistype of industry ( which is the index in _industry_specs )
2007-04-19 16:50:01 +02:00
* @ pre thistype < NUM_INDUSTRYTYPES
2007-03-03 05:04:22 +01:00
* @ return a pointer to the corresponding industry spec
2010-08-01 21:44:49 +02:00
*/
2006-04-28 23:58:16 +02:00
const IndustrySpec * GetIndustrySpec ( IndustryType thistype )
2006-04-26 16:58:06 +02:00
{
2007-04-19 16:50:01 +02:00
assert ( thistype < NUM_INDUSTRYTYPES ) ;
2006-04-26 16:58:06 +02:00
return & _industry_specs [ thistype ] ;
}
2007-03-03 05:04:22 +01:00
/**
* Accessor for array _industry_tile_specs .
* This will ensure at once : proper access and
* not allowing modifications of it .
2007-07-20 16:49:41 +02:00
* @ param gfx of industrytile ( which is the index in _industry_tile_specs )
2007-05-30 04:08:18 +02:00
* @ pre gfx < INVALID_INDUSTRYTILE
2007-03-03 05:04:22 +01:00
* @ return a pointer to the corresponding industrytile spec
2010-08-01 21:44:49 +02:00
*/
2007-08-22 03:16:08 +02:00
const IndustryTileSpec * GetIndustryTileSpec ( IndustryGfx gfx )
2007-02-21 03:22:43 +01:00
{
2007-05-30 04:08:18 +02:00
assert ( gfx < INVALID_INDUSTRYTILE ) ;
2007-08-22 03:16:08 +02:00
return & _industry_tile_specs [ gfx ] ;
2007-02-21 03:22:43 +01:00
}
2007-08-03 01:21:52 +02:00
Industry : : ~ Industry ( )
2006-08-26 21:51:49 +02:00
{
2007-08-06 16:08:25 +02:00
if ( CleaningPool ( ) ) return ;
2007-08-03 01:21:52 +02:00
/* Industry can also be destroyed when not fully initialized.
2010-03-20 15:30:16 +01:00
* This means that we do not have to clear tiles either .
* Also we must not decrement industry counts in that case . */
2010-01-04 19:21:07 +01:00
if ( this - > location . w = = 0 ) return ;
2007-08-03 01:21:52 +02:00
2019-11-02 22:11:46 +01:00
const bool has_neutral_station = this - > neutral_station ! = nullptr ;
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_cur : this - > location ) {
2006-08-26 21:51:49 +02:00
if ( IsTileType ( tile_cur , MP_INDUSTRY ) ) {
2007-08-03 01:21:52 +02:00
if ( GetIndustryIndex ( tile_cur ) = = this - > index ) {
2023-11-06 21:29:35 +01:00
DeleteNewGRFInspectWindow ( GSF_INDUSTRYTILES , tile_cur . base ( ) ) ;
2010-04-24 15:39:11 +02:00
2008-07-26 18:14:10 +02:00
/* MakeWaterKeepingClass() can also handle 'land' */
MakeWaterKeepingClass ( tile_cur , OWNER_NONE ) ;
2006-08-26 21:51:49 +02:00
}
} else if ( IsTileType ( tile_cur , MP_STATION ) & & IsOilRig ( tile_cur ) ) {
DeleteOilRig ( tile_cur ) ;
}
2009-07-26 23:50:30 +02:00
}
2006-08-26 21:51:49 +02:00
2019-11-02 22:11:46 +01:00
if ( has_neutral_station ) {
2019-03-11 11:37:47 +01:00
/* Remove possible docking tiles */
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_cur : this - > location ) {
2019-03-11 11:37:47 +01:00
ClearDockingTilesCheckingNeighbours ( tile_cur ) ;
}
}
2007-08-03 01:21:52 +02:00
if ( GetIndustrySpec ( this - > type ) - > behaviour & INDUSTRYBEH_PLANT_FIELDS ) {
2019-04-13 15:12:34 +02:00
TileArea ta = TileArea ( this - > location . tile , 0 , 0 ) . Expand ( 21 ) ;
2010-12-12 21:11:46 +01:00
2006-08-26 21:51:49 +02:00
/* Remove the farmland and convert it to regular tiles over time. */
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_cur : ta ) {
2006-08-26 21:51:49 +02:00
if ( IsTileType ( tile_cur , MP_CLEAR ) & & IsClearGround ( tile_cur , CLEAR_FIELDS ) & &
2007-08-03 01:21:52 +02:00
GetIndustryIndexOfField ( tile_cur ) = = this - > index ) {
2006-08-26 21:51:49 +02:00
SetIndustryIndexOfField ( tile_cur , INVALID_INDUSTRY ) ;
}
2009-07-26 23:50:30 +02:00
}
2006-08-26 21:51:49 +02:00
}
2008-12-26 20:37:50 +01:00
/* don't let any disaster vehicle target invalid industry */
ReleaseDisastersTargetingIndustry ( this - > index ) ;
2011-06-12 22:47:45 +02:00
/* Clear the persistent storage. */
delete this - > psa ;
2007-08-03 01:21:52 +02:00
DecIndustryTypeCount ( this - > type ) ;
2007-06-08 17:48:48 +02:00
2009-05-24 18:52:42 +02:00
DeleteIndustryNews ( this - > index ) ;
2021-05-17 15:46:38 +02:00
CloseWindowById ( WC_INDUSTRY_VIEW , this - > index ) ;
2010-04-24 15:39:11 +02:00
DeleteNewGRFInspectWindow ( GSF_INDUSTRIES , this - > index ) ;
2009-06-25 17:42:03 +02:00
2023-04-16 21:00:55 +02:00
DeleteSubsidyWith ( SourceType : : Industry , this - > index ) ;
CargoPacket : : InvalidateAllFrom ( SourceType : : Industry , this - > index ) ;
2019-02-14 22:07:15 +01:00
for ( Station * st : this - > stations_near ) {
2022-02-19 19:08:23 +01:00
st - > RemoveIndustryToDeliver ( this ) ;
2019-02-14 22:07:15 +01:00
}
2009-09-08 14:22:28 +02:00
}
/**
* Invalidating some stuff after removing item from the pool .
* @ param index index of deleted item
*/
2023-09-16 22:20:53 +02:00
void Industry : : PostDestructor ( size_t )
2009-09-08 14:22:28 +02:00
{
2020-01-06 21:31:57 +01:00
InvalidateWindowData ( WC_INDUSTRY_DIRECTORY , 0 , IDIWD_FORCE_REBUILD ) ;
2023-05-11 02:15:21 +02:00
SetWindowDirty ( WC_BUILD_INDUSTRY , 0 ) ;
2006-08-26 21:51:49 +02:00
}
2009-06-26 17:08:54 +02:00
/**
* Return a random valid industry .
2019-04-10 23:07:06 +02:00
* @ return random industry , nullptr if there are no industries
2009-06-26 17:08:54 +02:00
*/
/* static */ Industry * Industry : : GetRandom ( )
{
2019-04-10 23:07:06 +02:00
if ( Industry : : GetNumItems ( ) = = 0 ) return nullptr ;
2023-05-08 19:01:06 +02:00
int num = RandomRange ( ( uint16_t ) Industry : : GetNumItems ( ) ) ;
2009-06-26 17:08:54 +02:00
size_t index = MAX_UVALUE ( size_t ) ;
while ( num > = 0 ) {
num - - ;
index + + ;
/* Make sure we have a valid industry */
while ( ! Industry : : IsValidID ( index ) ) {
index + + ;
assert ( index < Industry : : GetPoolSize ( ) ) ;
}
}
return Industry : : Get ( index ) ;
}
2006-03-22 00:22:21 +01:00
static void IndustryDrawSugarMine ( const TileInfo * ti )
2004-08-09 19:04:08 +02:00
{
2006-03-24 14:46:45 +01:00
if ( ! IsIndustryCompleted ( ti - > tile ) ) return ;
2004-09-11 11:55:19 +02:00
2010-08-26 16:45:45 +02:00
const DrawIndustryAnimationStruct * d = & _draw_industry_spec1 [ GetAnimationFrame ( ti - > tile ) ] ;
2004-08-09 19:04:08 +02:00
2007-01-14 20:57:49 +01:00
AddChildSpriteScreen ( SPR_IT_SUGAR_MINE_SIEVE + d - > image_1 , PAL_NONE , d - > x , 0 ) ;
2004-08-09 19:04:08 +02:00
2007-04-21 04:47:33 +02:00
if ( d - > image_2 ! = 0 ) {
AddChildSpriteScreen ( SPR_IT_SUGAR_MINE_CLOUDS + d - > image_2 - 1 , PAL_NONE , 8 , 41 ) ;
}
2004-08-09 19:04:08 +02:00
2007-04-21 04:47:33 +02:00
if ( d - > image_3 ! = 0 ) {
AddChildSpriteScreen ( SPR_IT_SUGAR_MINE_PILE + d - > image_3 - 1 , PAL_NONE ,
_drawtile_proc1 [ d - > image_3 - 1 ] . x , _drawtile_proc1 [ d - > image_3 - 1 ] . y ) ;
2005-11-14 20:48:04 +01:00
}
2004-08-09 19:04:08 +02:00
}
2006-03-22 00:22:21 +01:00
static void IndustryDrawToffeeQuarry ( const TileInfo * ti )
2004-08-09 19:04:08 +02:00
{
2023-05-08 19:01:06 +02:00
uint8_t x = 0 ;
2004-09-11 11:55:19 +02:00
2006-03-24 14:46:45 +01:00
if ( IsIndustryCompleted ( ti - > tile ) ) {
2010-08-26 16:45:45 +02:00
x = _industry_anim_offs_toffee [ GetAnimationFrame ( ti - > tile ) ] ;
2010-07-24 12:14:39 +02:00
if ( x = = 0xFF ) {
2004-08-09 19:04:08 +02:00
x = 0 ;
2010-07-24 12:14:39 +02:00
}
2004-08-09 19:04:08 +02:00
}
2007-01-14 20:57:49 +01:00
AddChildSpriteScreen ( SPR_IT_TOFFEE_QUARRY_SHOVEL , PAL_NONE , 22 - x , 24 + x ) ;
AddChildSpriteScreen ( SPR_IT_TOFFEE_QUARRY_TOFFEE , PAL_NONE , 6 , 14 ) ;
2004-08-09 19:04:08 +02:00
}
2006-03-22 00:22:21 +01:00
static void IndustryDrawBubbleGenerator ( const TileInfo * ti )
2004-08-09 19:04:08 +02:00
{
2006-03-24 14:46:45 +01:00
if ( IsIndustryCompleted ( ti - > tile ) ) {
2010-08-26 16:45:45 +02:00
AddChildSpriteScreen ( SPR_IT_BUBBLE_GENERATOR_BUBBLE , PAL_NONE , 5 , _industry_anim_offs_bubbles [ GetAnimationFrame ( ti - > tile ) ] ) ;
2004-08-09 19:04:08 +02:00
}
2012-04-09 12:18:10 +02:00
AddChildSpriteScreen ( SPR_IT_BUBBLE_GENERATOR_SPRING , PAL_NONE , 3 , 67 ) ;
2004-08-09 19:04:08 +02:00
}
2006-03-22 00:22:21 +01:00
static void IndustryDrawToyFactory ( const TileInfo * ti )
2004-08-09 19:04:08 +02:00
{
2010-08-26 16:45:45 +02:00
const DrawIndustryAnimationStruct * d = & _industry_anim_offs_toys [ GetAnimationFrame ( ti - > tile ) ] ;
2004-08-09 19:04:08 +02:00
if ( d - > image_1 ! = 0xFF ) {
2007-04-21 04:47:33 +02:00
AddChildSpriteScreen ( SPR_IT_TOY_FACTORY_CLAY , PAL_NONE , d - > x , 96 + d - > image_1 ) ;
2004-08-09 19:04:08 +02:00
}
if ( d - > image_2 ! = 0xFF ) {
2007-01-14 20:57:49 +01:00
AddChildSpriteScreen ( SPR_IT_TOY_FACTORY_ROBOT , PAL_NONE , 16 - d - > image_2 * 2 , 100 + d - > image_2 ) ;
2004-08-09 19:04:08 +02:00
}
2007-01-14 20:57:49 +01:00
AddChildSpriteScreen ( SPR_IT_TOY_FACTORY_STAMP , PAL_NONE , 7 , d - > image_3 ) ;
AddChildSpriteScreen ( SPR_IT_TOY_FACTORY_STAMP_HOLDER , PAL_NONE , 0 , 42 ) ;
2004-08-09 19:04:08 +02:00
}
2006-03-22 00:22:21 +01:00
static void IndustryDrawCoalPlantSparks ( const TileInfo * ti )
2004-08-09 19:04:08 +02:00
{
2006-03-24 14:46:45 +01:00
if ( IsIndustryCompleted ( ti - > tile ) ) {
2023-05-08 19:01:06 +02:00
uint8_t image = GetAnimationFrame ( ti - > tile ) ;
2006-03-24 14:46:45 +01:00
2004-08-09 19:04:08 +02:00
if ( image ! = 0 & & image < 7 ) {
2006-03-22 00:22:21 +01:00
AddChildSpriteScreen ( image + SPR_IT_POWER_PLANT_TRANSFORMERS ,
2007-01-14 20:57:49 +01:00
PAL_NONE ,
2007-04-21 04:47:33 +02:00
_coal_plant_sparks [ image - 1 ] . x ,
_coal_plant_sparks [ image - 1 ] . y
2004-08-09 19:04:08 +02:00
) ;
}
}
}
2005-09-18 22:56:44 +02:00
typedef void IndustryDrawTileProc ( const TileInfo * ti ) ;
2004-08-09 19:04:08 +02:00
static IndustryDrawTileProc * const _industry_draw_tile_procs [ 5 ] = {
2006-03-22 00:22:21 +01:00
IndustryDrawSugarMine ,
IndustryDrawToffeeQuarry ,
IndustryDrawBubbleGenerator ,
IndustryDrawToyFactory ,
IndustryDrawCoalPlantSparks ,
2004-08-09 19:04:08 +02:00
} ;
static void DrawTile_Industry ( TileInfo * ti )
{
2007-06-19 19:33:12 +02:00
IndustryGfx gfx = GetIndustryGfx ( ti - > tile ) ;
2009-08-30 13:47:41 +02:00
Industry * ind = Industry : : GetByTile ( ti - > tile ) ;
2007-06-19 19:33:12 +02:00
const IndustryTileSpec * indts = GetIndustryTileSpec ( gfx ) ;
2004-08-09 19:04:08 +02:00
/* Retrieve pointer to the draw industry tile struct */
2007-06-19 19:33:12 +02:00
if ( gfx > = NEW_INDUSTRYTILEOFFSET ) {
/* Draw the tile using the specialized method of newgrf industrytile.
* DrawNewIndustry will return false if ever the resolver could not
* find any sprite to display . So in this case , we will jump on the
* substitute gfx instead . */
2019-04-10 23:07:06 +02:00
if ( indts - > grf_prop . spritegroup [ 0 ] ! = nullptr & & DrawNewIndustryTile ( ti , ind , gfx , indts ) ) {
2007-06-19 19:33:12 +02:00
return ;
} else {
/* No sprite group (or no valid one) found, meaning no graphics associated.
* Use the substitute one instead */
2007-08-22 02:59:46 +02:00
if ( indts - > grf_prop . subst_id ! = INVALID_INDUSTRYTILE ) {
gfx = indts - > grf_prop . subst_id ;
/* And point the industrytile spec accordingly */
indts = GetIndustryTileSpec ( gfx ) ;
}
2007-06-19 19:33:12 +02:00
}
}
2010-07-30 12:39:24 +02:00
const DrawBuildingsTileStruct * dits = & _industry_draw_tile_data [ gfx < < 2 | ( indts - > anim_state ?
2010-08-26 16:45:45 +02:00
GetAnimationFrame ( ti - > tile ) & INDUSTRY_COMPLETED :
2006-12-30 12:57:52 +01:00
GetIndustryConstructionStage ( ti - > tile ) ) ] ;
2004-08-09 19:04:08 +02:00
2010-01-22 22:52:20 +01:00
SpriteID image = dits - > ground . sprite ;
2004-08-09 19:04:08 +02:00
2013-01-08 23:46:42 +01:00
/* DrawFoundation() modifies ti->z and ti->tileh */
2007-07-26 18:51:10 +02:00
if ( ti - > tileh ! = SLOPE_FLAT ) DrawFoundation ( ti , FOUNDATION_LEVELED ) ;
2004-08-09 19:04:08 +02:00
2008-07-26 18:14:10 +02:00
/* If the ground sprite is the default flat water sprite, draw also canal/river borders.
* Do not do this if the tile ' s WaterClass is ' land ' . */
2010-08-26 21:29:20 +02:00
if ( image = = SPR_FLAT_WATER_TILE & & IsTileOnWater ( ti - > tile ) ) {
2008-07-26 18:14:10 +02:00
DrawWaterClassGround ( ti ) ;
} else {
2010-01-22 22:52:20 +01:00
DrawGroundSprite ( image , GroundSpritePaletteTransform ( image , dits - > ground . pal , GENERAL_SPRITE_COLOUR ( ind - > random_colour ) ) ) ;
2008-07-26 18:14:10 +02:00
}
2007-06-24 12:20:05 +02:00
2008-04-03 21:55:40 +02:00
/* If industries are transparent and invisible, do not draw the upper part */
if ( IsInvisibilitySet ( TO_INDUSTRIES ) ) return ;
2004-08-09 19:04:08 +02:00
/* Add industry on top of the ground? */
2007-01-14 20:57:49 +01:00
image = dits - > building . sprite ;
2005-11-14 20:48:04 +01:00
if ( image ! = 0 ) {
2010-01-22 22:52:20 +01:00
AddSortableSpriteToDraw ( image , SpriteLayoutPaletteTransform ( image , dits - > building . pal , GENERAL_SPRITE_COLOUR ( ind - > random_colour ) ) ,
2005-11-16 12:55:06 +01:00
ti - > x + dits - > subtile_x ,
ti - > y + dits - > subtile_y ,
2007-09-14 23:32:21 +02:00
dits - > width ,
dits - > height ,
2004-08-09 19:04:08 +02:00
dits - > dz ,
2007-07-26 18:51:10 +02:00
ti - > z ,
2007-11-10 02:17:15 +01:00
IsTransparencySet ( TO_INDUSTRIES ) ) ;
2004-08-09 19:04:08 +02:00
2007-11-10 02:17:15 +01:00
if ( IsTransparencySet ( TO_INDUSTRIES ) ) return ;
2004-08-09 19:04:08 +02:00
}
2005-11-14 20:48:04 +01:00
{
2006-04-24 23:10:56 +02:00
int proc = dits - > draw_proc - 1 ;
2005-11-14 20:48:04 +01:00
if ( proc > = 0 ) _industry_draw_tile_procs [ proc ] ( ti ) ;
2004-08-09 19:04:08 +02:00
}
}
2023-09-16 22:20:53 +02:00
static int GetSlopePixelZ_Industry ( TileIndex tile , uint , uint , bool )
2005-10-19 16:49:46 +02:00
{
2011-11-04 11:18:13 +01:00
return GetTileMaxPixelZ ( tile ) ;
2004-08-09 19:04:08 +02:00
}
2007-07-26 18:51:10 +02:00
static Foundation GetFoundation_Industry ( TileIndex tile , Slope tileh )
2005-10-22 08:39:32 +02:00
{
2008-06-01 00:43:42 +02:00
IndustryGfx gfx = GetIndustryGfx ( tile ) ;
/* For NewGRF industry tiles we might not be drawing a foundation. We need to
2008-06-12 23:36:56 +02:00
* account for this , as other structures should
2008-06-01 00:43:42 +02:00
* draw the wall of the foundation in this case .
*/
if ( gfx > = NEW_INDUSTRYTILEOFFSET ) {
const IndustryTileSpec * indts = GetIndustryTileSpec ( gfx ) ;
2019-04-10 23:07:06 +02:00
if ( indts - > grf_prop . spritegroup [ 0 ] ! = nullptr & & HasBit ( indts - > callback_mask , CBM_INDT_DRAW_FOUNDATIONS ) ) {
2023-05-08 19:01:06 +02:00
uint32_t callback_res = GetIndustryTileCallback ( CBID_INDTILE_DRAW_FOUNDATIONS , 0 , 0 , gfx , Industry : : GetByTile ( tile ) , tile ) ;
2011-11-08 18:26:49 +01:00
if ( callback_res ! = CALLBACK_FAILED & & ! ConvertBooleanCallback ( indts - > grf_prop . grffile , CBID_INDTILE_DRAW_FOUNDATIONS , callback_res ) ) return FOUNDATION_NONE ;
2008-06-01 00:43:42 +02:00
}
}
2007-07-26 18:51:10 +02:00
return FlatteningFoundation ( tileh ) ;
2004-08-13 20:27:33 +02:00
}
2018-05-21 23:08:39 +02:00
static void AddAcceptedCargo_Industry ( TileIndex tile , CargoArray & acceptance , CargoTypes * always_accepted )
2004-08-09 19:04:08 +02:00
{
2007-07-08 19:40:04 +02:00
IndustryGfx gfx = GetIndustryGfx ( tile ) ;
const IndustryTileSpec * itspec = GetIndustryTileSpec ( gfx ) ;
2018-07-26 19:29:54 +02:00
const Industry * ind = Industry : : GetByTile ( tile ) ;
2007-07-08 19:40:04 +02:00
2018-07-26 19:29:54 +02:00
/* Starting point for acceptance */
2023-11-28 00:17:55 +01:00
auto accepts_cargo = itspec - > accepts_cargo ;
auto cargo_acceptance = itspec - > acceptance ;
2018-07-26 19:29:54 +02:00
if ( itspec - > special_flags & INDTILE_SPECIAL_ACCEPTS_ALL_CARGO ) {
/* Copy all accepted cargoes from industry itself */
2023-05-25 22:25:46 +02:00
for ( const auto & a : ind - > accepted ) {
2023-11-28 00:17:55 +01:00
auto pos = std : : find ( std : : begin ( accepts_cargo ) , std : : end ( accepts_cargo ) , a . cargo ) ;
if ( pos = = std : : end ( accepts_cargo ) ) {
2018-07-26 19:29:54 +02:00
/* Not found, insert */
2024-01-06 16:15:37 +01:00
pos = std : : find ( std : : begin ( accepts_cargo ) , std : : end ( accepts_cargo ) , INVALID_CARGO ) ;
2023-11-28 00:17:55 +01:00
if ( pos = = std : : end ( accepts_cargo ) ) continue ; // nowhere to place, give up on this one
2023-05-25 22:25:46 +02:00
* pos = a . cargo ;
2018-07-26 19:29:54 +02:00
}
2023-11-28 00:17:55 +01:00
cargo_acceptance [ std : : distance ( std : : begin ( accepts_cargo ) , pos ) ] + = 8 ;
2018-07-26 19:29:54 +02:00
}
}
2007-07-08 19:40:04 +02:00
2009-09-14 14:22:57 +02:00
if ( HasBit ( itspec - > callback_mask , CBM_INDT_ACCEPT_CARGO ) ) {
2018-07-26 19:29:54 +02:00
/* Try callback for accepts list, if success override all existing accepts */
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryTileCallback ( CBID_INDTILE_ACCEPT_CARGO , 0 , 0 , gfx , Industry : : GetByTile ( tile ) , tile ) ;
2007-07-08 19:40:04 +02:00
if ( res ! = CALLBACK_FAILED ) {
2024-01-06 16:15:37 +01:00
accepts_cargo . fill ( INVALID_CARGO ) ;
2018-07-26 19:29:54 +02:00
for ( uint i = 0 ; i < 3 ; i + + ) accepts_cargo [ i ] = GetCargoTranslation ( GB ( res , i * 5 , 5 ) , itspec - > grf_prop . grffile ) ;
2007-07-08 19:40:04 +02:00
}
}
2009-09-14 14:22:57 +02:00
if ( HasBit ( itspec - > callback_mask , CBM_INDT_CARGO_ACCEPTANCE ) ) {
2018-07-26 19:29:54 +02:00
/* Try callback for acceptance list, if success override all existing acceptance */
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryTileCallback ( CBID_INDTILE_CARGO_ACCEPTANCE , 0 , 0 , gfx , Industry : : GetByTile ( tile ) , tile ) ;
2007-07-08 19:40:04 +02:00
if ( res ! = CALLBACK_FAILED ) {
2023-11-28 00:17:55 +01:00
cargo_acceptance . fill ( 0 ) ;
2018-07-26 19:29:54 +02:00
for ( uint i = 0 ; i < 3 ; i + + ) cargo_acceptance [ i ] = GB ( res , i * 4 , 4 ) ;
2007-07-08 19:40:04 +02:00
}
}
2004-08-09 19:04:08 +02:00
2024-03-16 23:59:32 +01:00
for ( uint8_t i = 0 ; i < std : : size ( itspec - > accepts_cargo ) ; i + + ) {
2007-07-08 19:40:04 +02:00
CargoID a = accepts_cargo [ i ] ;
2023-05-04 12:29:21 +02:00
if ( ! IsValidCargoID ( a ) | | cargo_acceptance [ i ] < = 0 ) continue ; // work only with valid cargoes
2009-09-20 20:52:12 +02:00
/* Add accepted cargo */
acceptance [ a ] + = cargo_acceptance [ i ] ;
/* Maybe set 'always accepted' bit (if it's not set already) */
if ( HasBit ( * always_accepted , a ) ) continue ;
2023-05-24 01:52:44 +02:00
/* Test whether the industry itself accepts the cargo type */
if ( ind - > IsCargoAccepted ( a ) ) continue ;
2009-09-20 20:52:12 +02:00
/* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
SetBit ( * always_accepted , a ) ;
2007-05-29 02:15:34 +02:00
}
2004-08-09 19:04:08 +02:00
}
2005-06-24 14:38:35 +02:00
static void GetTileDesc_Industry ( TileIndex tile , TileDesc * td )
2004-08-09 19:04:08 +02:00
{
2009-08-30 13:47:41 +02:00
const Industry * i = Industry : : GetByTile ( tile ) ;
2008-07-26 00:37:34 +02:00
const IndustrySpec * is = GetIndustrySpec ( i - > type ) ;
2004-08-09 19:04:08 +02:00
2008-05-22 00:15:39 +02:00
td - > owner [ 0 ] = i - > owner ;
2008-07-26 00:37:34 +02:00
td - > str = is - > name ;
2006-03-24 14:46:45 +01:00
if ( ! IsIndustryCompleted ( tile ) ) {
2023-06-11 21:16:16 +02:00
td - > dparam = td - > str ;
2009-08-05 19:59:21 +02:00
td - > str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION ;
2004-08-09 19:04:08 +02:00
}
2008-07-26 00:37:34 +02:00
2019-04-10 23:07:06 +02:00
if ( is - > grf_prop . grffile ! = nullptr ) {
2010-02-28 21:28:08 +01:00
td - > grf = GetGRFConfig ( is - > grf_prop . grffile - > grfid ) - > GetName ( ) ;
2008-07-26 00:37:34 +02:00
}
2004-08-09 19:04:08 +02:00
}
2009-02-09 22:20:05 +01:00
static CommandCost ClearTile_Industry ( TileIndex tile , DoCommandFlag flags )
2004-08-09 19:04:08 +02:00
{
2009-08-30 13:47:41 +02:00
Industry * i = Industry : : GetByTile ( tile ) ;
2007-03-28 22:06:28 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( i - > type ) ;
2004-08-09 19:04:08 +02:00
2006-08-28 20:53:03 +02:00
/* water can destroy industries
* in editor you can bulldoze industries
* with magic_bulldozer cheat you can destroy industries
* ( area around OILRIG is water , so water shouldn ' t flood it
*/
2008-09-30 22:39:50 +02:00
if ( ( _current_company ! = OWNER_WATER & & _game_mode ! = GM_EDITOR & &
2004-09-03 19:57:27 +02:00
! _cheats . magic_bulldozer . value ) | |
2007-09-26 16:14:51 +02:00
( ( flags & DC_AUTO ) ! = 0 ) | |
2008-09-30 22:39:50 +02:00
( _current_company = = OWNER_WATER & &
2008-08-17 15:56:11 +02:00
( ( indspec - > behaviour & INDUSTRYBEH_BUILT_ONWATER ) | |
HasBit ( GetIndustryTileSpec ( GetIndustryGfx ( tile ) ) - > slopes_refused , 5 ) ) ) ) {
2010-02-26 11:08:16 +01:00
SetDParam ( 1 , indspec - > name ) ;
2010-08-08 12:59:30 +02:00
return_cmd_error ( flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID ) ;
2004-08-09 19:04:08 +02:00
}
2009-01-12 18:11:45 +01:00
if ( flags & DC_EXEC ) {
2011-11-30 00:15:35 +01:00
AI : : BroadcastNewEvent ( new ScriptEventIndustryClose ( i - > index ) ) ;
2011-12-19 21:59:36 +01:00
Game : : NewEvent ( new ScriptEventIndustryClose ( i - > index ) ) ;
2009-01-12 18:11:45 +01:00
delete i ;
}
2008-01-09 17:55:48 +01:00
return CommandCost ( EXPENSES_CONSTRUCTION , indspec - > GetRemovalCost ( ) ) ;
2004-08-09 19:04:08 +02:00
}
2017-11-25 17:50:28 +01:00
/**
* Move produced cargo from industry to nearby stations .
* @ param tile Industry tile
* @ return true if any cargo was moved .
*/
static bool TransportIndustryGoods ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2009-08-30 13:47:41 +02:00
Industry * i = Industry : : GetByTile ( tile ) ;
2006-04-26 23:10:01 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( i - > type ) ;
2007-10-27 13:20:47 +02:00
bool moved_cargo = false ;
2004-09-11 11:55:19 +02:00
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
uint cw = ClampTo < uint8_t > ( p . waiting ) ;
if ( cw > indspec - > minimal_cargo & & IsValidCargoID ( p . cargo ) ) {
p . waiting - = cw ;
2004-08-09 19:04:08 +02:00
2007-10-27 13:20:47 +02:00
/* fluctuating economy? */
2010-11-13 10:45:20 +01:00
if ( EconomyIsInRecession ( ) ) cw = ( cw + 1 ) / 2 ;
2004-08-09 19:04:08 +02:00
2023-05-25 22:25:46 +02:00
p . history [ THIS_MONTH ] . production + = cw ;
2004-08-09 19:04:08 +02:00
2023-05-25 22:25:46 +02:00
uint am = MoveGoodsToStation ( p . cargo , cw , SourceType : : Industry , i - > index , & i - > stations_near , i - > exclusive_consumer ) ;
p . history [ THIS_MONTH ] . transported + = am ;
2006-03-25 11:38:28 +01:00
2007-10-27 13:20:47 +02:00
moved_cargo | = ( am ! = 0 ) ;
2004-08-09 19:04:08 +02:00
}
}
2017-11-25 17:50:28 +01:00
return moved_cargo ;
2004-08-09 19:04:08 +02:00
}
2023-02-25 17:08:43 +01:00
static void AnimateSugarSieve ( TileIndex tile )
{
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) + 1 ;
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
if ( _settings_client . sound . ambient ) {
switch ( m & 7 ) {
case 2 : SndPlayTileFx ( SND_2D_SUGAR_MINE_1 , tile ) ; break ;
case 6 : SndPlayTileFx ( SND_29_SUGAR_MINE_2 , tile ) ; break ;
}
}
if ( m > = 96 ) {
m = 0 ;
DeleteAnimatedTile ( tile ) ;
}
SetAnimationFrame ( tile , m ) ;
MarkTileDirtyByTile ( tile ) ;
}
static void AnimateToffeeQuarry ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) ;
2007-07-11 17:03:29 +02:00
2023-02-25 17:08:43 +01:00
if ( _industry_anim_offs_toffee [ m ] = = 0xFF & & _settings_client . sound . ambient ) {
SndPlayTileFx ( SND_30_TOFFEE_QUARRY , tile ) ;
2007-07-11 17:03:29 +02:00
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
if ( + + m > = 70 ) {
m = 0 ;
DeleteAnimatedTile ( tile ) ;
}
SetAnimationFrame ( tile , m ) ;
2004-09-11 11:55:19 +02:00
2023-02-25 17:08:43 +01:00
MarkTileDirtyByTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
static void AnimateBubbleCatcher ( TileIndex tile )
{
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) ;
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
if ( + + m > = 40 ) {
m = 0 ;
DeleteAnimatedTile ( tile ) ;
}
SetAnimationFrame ( tile , m ) ;
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
MarkTileDirtyByTile ( tile ) ;
}
2004-09-11 11:55:19 +02:00
2023-02-25 17:08:43 +01:00
static void AnimatePowerPlantSparks ( TileIndex tile )
{
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) ;
2023-02-25 17:08:43 +01:00
if ( m = = 6 ) {
SetAnimationFrame ( tile , 0 ) ;
DeleteAnimatedTile ( tile ) ;
} else {
SetAnimationFrame ( tile , m + 1 ) ;
MarkTileDirtyByTile ( tile ) ;
}
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
static void AnimateToyFactory ( TileIndex tile )
{
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) + 1 ;
2023-02-25 17:08:43 +01:00
switch ( m ) {
case 1 : if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_2C_TOY_FACTORY_1 , tile ) ; break ;
case 23 : if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_2B_TOY_FACTORY_2 , tile ) ; break ;
case 28 : if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_2A_TOY_FACTORY_3 , tile ) ; break ;
default :
if ( m > = 50 ) {
int n = GetIndustryAnimationLoop ( tile ) + 1 ;
2004-08-09 19:04:08 +02:00
m = 0 ;
2023-02-25 17:08:43 +01:00
if ( n > = 8 ) {
n = 0 ;
DeleteAnimatedTile ( tile ) ;
}
SetIndustryAnimationLoop ( tile , n ) ;
2004-08-09 19:04:08 +02:00
}
2023-02-25 17:08:43 +01:00
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
SetAnimationFrame ( tile , m ) ;
MarkTileDirtyByTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
static void AnimatePlasticFountain ( TileIndex tile , IndustryGfx gfx )
{
gfx = ( gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8 ) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1 ;
SetIndustryGfx ( tile , gfx ) ;
MarkTileDirtyByTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
static void AnimateOilWell ( TileIndex tile , IndustryGfx gfx )
{
bool b = Chance16 ( 1 , 7 ) ;
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) + 1 ;
2023-02-25 17:08:43 +01:00
if ( m = = 4 & & ( m = 0 , + + gfx ) = = GFX_OILWELL_ANIMATED_3 + 1 & & ( gfx = GFX_OILWELL_ANIMATED_1 , b ) ) {
SetIndustryGfx ( tile , GFX_OILWELL_NOT_ANIMATED ) ;
SetIndustryConstructionStage ( tile , 3 ) ;
DeleteAnimatedTile ( tile ) ;
} else {
SetAnimationFrame ( tile , m ) ;
SetIndustryGfx ( tile , gfx ) ;
MarkTileDirtyByTile ( tile ) ;
}
}
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
static void AnimateMineTower ( TileIndex tile )
{
2023-04-24 18:55:40 +02:00
int state = TimerGameTick : : counter & 0x7FF ;
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
if ( ( state - = 0x400 ) < 0 ) return ;
if ( state < 0x1A0 ) {
if ( state < 0x20 | | state > = 0x180 ) {
2024-03-16 23:59:32 +01:00
uint8_t m = GetAnimationFrame ( tile ) ;
2023-02-25 17:08:43 +01:00
if ( ! ( m & 0x40 ) ) {
SetAnimationFrame ( tile , m | 0x40 ) ;
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_0B_MINE , tile ) ;
2004-08-09 19:04:08 +02:00
}
2023-02-25 17:08:43 +01:00
if ( state & 7 ) return ;
} else {
if ( state & 3 ) return ;
2004-08-09 19:04:08 +02:00
}
2024-03-16 23:59:32 +01:00
uint8_t m = ( GetAnimationFrame ( tile ) + 1 ) | 0x40 ;
2023-02-25 17:08:43 +01:00
if ( m > 0xC2 ) m = 0xC0 ;
SetAnimationFrame ( tile , m ) ;
MarkTileDirtyByTile ( tile ) ;
} else if ( state > = 0x200 & & state < 0x3A0 ) {
int i = ( state < 0x220 | | state > = 0x380 ) ? 7 : 3 ;
if ( state & i ) return ;
2024-03-16 23:59:32 +01:00
uint8_t m = ( GetAnimationFrame ( tile ) & 0xBF ) - 1 ;
2023-02-25 17:08:43 +01:00
if ( m < 0x80 ) m = 0x82 ;
SetAnimationFrame ( tile , m ) ;
MarkTileDirtyByTile ( tile ) ;
}
}
static void AnimateTile_Industry ( TileIndex tile )
{
IndustryGfx gfx = GetIndustryGfx ( tile ) ;
if ( GetIndustryTileSpec ( gfx ) - > animation . status ! = ANIM_STATUS_NO_ANIMATION ) {
AnimateNewIndustryTile ( tile ) ;
return ;
}
switch ( gfx ) {
case GFX_SUGAR_MINE_SIEVE :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 1 ) = = 0 ) AnimateSugarSieve ( tile ) ;
2004-08-09 19:04:08 +02:00
break ;
2023-02-25 17:08:43 +01:00
case GFX_TOFFEE_QUARY :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 3 ) = = 0 ) AnimateToffeeQuarry ( tile ) ;
2023-02-25 17:08:43 +01:00
break ;
2004-08-09 19:04:08 +02:00
2023-02-25 17:08:43 +01:00
case GFX_BUBBLE_CATCHER :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 1 ) = = 0 ) AnimateBubbleCatcher ( tile ) ;
2023-02-25 17:08:43 +01:00
break ;
case GFX_POWERPLANT_SPARKS :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 3 ) = = 0 ) AnimatePowerPlantSparks ( tile ) ;
2023-02-25 17:08:43 +01:00
break ;
case GFX_TOY_FACTORY :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 1 ) = = 0 ) AnimateToyFactory ( tile ) ;
2004-08-09 19:04:08 +02:00
break ;
2006-12-30 12:41:54 +01:00
case GFX_PLASTIC_FOUNTAIN_ANIMATED_1 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_2 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_3 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_4 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_5 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_6 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_7 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_8 :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 3 ) = = 0 ) AnimatePlasticFountain ( tile , gfx ) ;
2004-08-09 19:04:08 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_OILWELL_ANIMATED_1 :
case GFX_OILWELL_ANIMATED_2 :
case GFX_OILWELL_ANIMATED_3 :
2023-04-24 18:55:40 +02:00
if ( ( TimerGameTick : : counter & 7 ) = = 0 ) AnimateOilWell ( tile , gfx ) ;
2004-08-09 19:04:08 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_COAL_MINE_TOWER_ANIMATED :
case GFX_COPPER_MINE_TOWER_ANIMATED :
2023-02-25 17:08:43 +01:00
case GFX_GOLD_MINE_TOWER_ANIMATED :
AnimateMineTower ( tile ) ;
break ;
2004-08-09 19:04:08 +02:00
}
}
2008-04-20 13:12:07 +02:00
static void CreateChimneySmoke ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2006-05-07 09:55:05 +02:00
uint x = TileX ( tile ) * TILE_SIZE ;
uint y = TileY ( tile ) * TILE_SIZE ;
2011-11-04 12:52:19 +01:00
int z = GetTileMaxPixelZ ( tile ) ;
2006-05-07 09:55:05 +02:00
CreateEffectVehicle ( x + 15 , y + 14 , z + 59 , EV_CHIMNEY_SMOKE ) ;
2004-08-09 19:04:08 +02:00
}
2006-04-10 17:09:56 +02:00
static void MakeIndustryTileBigger ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2024-03-16 23:59:32 +01:00
uint8_t cnt = GetIndustryConstructionCounter ( tile ) + 1 ;
2006-04-10 17:09:56 +02:00
if ( cnt ! = 4 ) {
SetIndustryConstructionCounter ( tile , cnt ) ;
2004-08-09 19:04:08 +02:00
return ;
}
2024-03-16 23:59:32 +01:00
uint8_t stage = GetIndustryConstructionStage ( tile ) + 1 ;
2006-04-10 17:09:56 +02:00
SetIndustryConstructionCounter ( tile , 0 ) ;
SetIndustryConstructionStage ( tile , stage ) ;
2007-07-11 17:03:29 +02:00
StartStopIndustryTileAnimation ( tile , IAT_CONSTRUCTION_STATE_CHANGE ) ;
2014-04-12 13:43:04 +02:00
if ( stage = = INDUSTRY_COMPLETED ) SetIndustryCompleted ( tile ) ;
2004-09-11 11:55:19 +02:00
2004-08-09 19:04:08 +02:00
MarkTileDirtyByTile ( tile ) ;
2006-03-24 14:46:45 +01:00
if ( ! IsIndustryCompleted ( tile ) ) return ;
2004-08-09 19:04:08 +02:00
2007-07-11 17:03:29 +02:00
IndustryGfx gfx = GetIndustryGfx ( tile ) ;
if ( gfx > = NEW_INDUSTRYTILEOFFSET ) {
2007-11-11 01:53:59 +01:00
/* New industries are already animated on construction. */
2007-07-11 17:03:29 +02:00
return ;
}
switch ( gfx ) {
2006-09-09 00:12:57 +02:00
case GFX_POWERPLANT_CHIMNEY :
2008-04-20 13:12:07 +02:00
CreateChimneySmoke ( tile ) ;
2004-08-09 19:04:08 +02:00
break ;
2009-09-13 12:58:41 +02:00
case GFX_OILRIG_1 : {
/* Do not require an industry tile to be after the first two GFX_OILRIG_1
* tiles ( like the default oil rig ) . Do a proper check to ensure the
* tiles belong to the same industry and based on that build the oil rig ' s
* station . */
TileIndex other = tile + TileDiffXY ( 0 , 1 ) ;
if ( IsTileType ( other , MP_INDUSTRY ) & &
GetIndustryGfx ( other ) = = GFX_OILRIG_1 & &
GetIndustryIndex ( tile ) = = GetIndustryIndex ( other ) ) {
BuildOilRig ( tile ) ;
}
2010-08-01 20:53:30 +02:00
break ;
}
2004-08-09 19:04:08 +02:00
2006-04-14 03:54:07 +02:00
case GFX_TOY_FACTORY :
case GFX_BUBBLE_CATCHER :
case GFX_TOFFEE_QUARY :
2010-08-26 16:45:45 +02:00
SetAnimationFrame ( tile , 0 ) ;
2006-04-12 20:10:54 +02:00
SetIndustryAnimationLoop ( tile , 0 ) ;
2004-08-09 19:04:08 +02:00
break ;
2006-12-30 12:41:54 +01:00
case GFX_PLASTIC_FOUNTAIN_ANIMATED_1 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_2 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_3 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_4 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_5 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_6 :
case GFX_PLASTIC_FOUNTAIN_ANIMATED_7 : case GFX_PLASTIC_FOUNTAIN_ANIMATED_8 :
2004-08-09 19:04:08 +02:00
AddAnimatedTile ( tile ) ;
break ;
}
}
2006-03-22 00:22:21 +01:00
static void TileLoopIndustry_BubbleGenerator ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2023-05-08 19:01:06 +02:00
static const int8_t _bubble_spawn_location [ 3 ] [ 4 ] = {
2008-04-20 13:12:07 +02:00
{ 11 , 0 , - 4 , - 14 } ,
{ - 4 , - 10 , - 4 , 1 } ,
{ 49 , 59 , 60 , 65 } ,
2004-08-09 19:04:08 +02:00
} ;
2021-02-20 19:01:04 +01:00
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_2E_BUBBLE_GENERATOR , tile ) ;
2004-09-11 11:55:19 +02:00
2009-05-22 20:56:25 +02:00
int dir = Random ( ) & 3 ;
2004-08-09 19:04:08 +02:00
2009-05-22 20:56:25 +02:00
EffectVehicle * v = CreateEffectVehicleAbove (
2008-04-20 13:12:07 +02:00
TileX ( tile ) * TILE_SIZE + _bubble_spawn_location [ 0 ] [ dir ] ,
TileY ( tile ) * TILE_SIZE + _bubble_spawn_location [ 1 ] [ dir ] ,
_bubble_spawn_location [ 2 ] [ dir ] ,
2005-02-12 16:53:32 +01:00
EV_BUBBLE
2004-08-09 19:04:08 +02:00
) ;
2019-04-10 23:07:06 +02:00
if ( v ! = nullptr ) v - > animation_substate = dir ;
2004-08-09 19:04:08 +02:00
}
2005-06-24 14:38:35 +02:00
static void TileLoop_Industry ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2010-08-26 21:29:20 +02:00
if ( IsTileOnWater ( tile ) ) TileLoop_Water ( tile ) ;
2008-07-26 18:14:10 +02:00
2010-09-06 17:23:16 +02:00
/* Normally this doesn't happen, but if an industry NewGRF is removed
* an industry that was previously build on water can now be flooded .
* If this happens the tile is no longer an industry tile after
* returning from TileLoop_Water . */
if ( ! IsTileType ( tile , MP_INDUSTRY ) ) return ;
2007-11-11 18:56:37 +01:00
TriggerIndustryTile ( tile , INDTILE_TRIGGER_TILE_LOOP ) ;
2006-03-24 14:46:45 +01:00
if ( ! IsIndustryCompleted ( tile ) ) {
2006-04-10 17:09:56 +02:00
MakeIndustryTileBigger ( tile ) ;
2004-08-09 19:04:08 +02:00
return ;
}
2005-11-14 20:48:04 +01:00
if ( _game_mode = = GM_EDITOR ) return ;
2004-08-09 19:04:08 +02:00
2017-11-25 17:50:28 +01:00
if ( TransportIndustryGoods ( tile ) & & ! StartStopIndustryTileAnimation ( Industry : : GetByTile ( tile ) , IAT_INDUSTRY_DISTRIBUTES_CARGO ) ) {
uint newgfx = GetIndustryTileSpec ( GetIndustryGfx ( tile ) ) - > anim_production ;
if ( newgfx ! = INDUSTRYTILE_NOANIM ) {
ResetIndustryConstructionStage ( tile ) ;
SetIndustryCompleted ( tile ) ;
SetIndustryGfx ( tile , newgfx ) ;
MarkTileDirtyByTile ( tile ) ;
return ;
}
}
2004-08-09 19:04:08 +02:00
2007-07-11 17:03:29 +02:00
if ( StartStopIndustryTileAnimation ( tile , IAT_TILELOOP ) ) return ;
2010-07-30 12:39:24 +02:00
IndustryGfx newgfx = GetIndustryTileSpec ( GetIndustryGfx ( tile ) ) - > anim_next ;
2007-05-29 19:41:59 +02:00
if ( newgfx ! = INDUSTRYTILE_NOANIM ) {
2006-04-10 17:09:56 +02:00
ResetIndustryConstructionStage ( tile ) ;
2006-03-25 11:38:28 +01:00
SetIndustryGfx ( tile , newgfx ) ;
2004-08-09 19:04:08 +02:00
MarkTileDirtyByTile ( tile ) ;
return ;
}
2010-07-30 12:39:24 +02:00
IndustryGfx gfx = GetIndustryGfx ( tile ) ;
2006-12-30 12:51:37 +01:00
switch ( gfx ) {
2006-09-09 00:12:57 +02:00
case GFX_COAL_MINE_TOWER_NOT_ANIMATED :
case GFX_COPPER_MINE_TOWER_NOT_ANIMATED :
case GFX_GOLD_MINE_TOWER_NOT_ANIMATED :
2023-04-24 18:55:40 +02:00
if ( ! ( TimerGameTick : : counter & 0x400 ) & & Chance16 ( 1 , 2 ) ) {
2006-12-30 12:51:37 +01:00
switch ( gfx ) {
case GFX_COAL_MINE_TOWER_NOT_ANIMATED : gfx = GFX_COAL_MINE_TOWER_ANIMATED ; break ;
case GFX_COPPER_MINE_TOWER_NOT_ANIMATED : gfx = GFX_COPPER_MINE_TOWER_ANIMATED ; break ;
case GFX_GOLD_MINE_TOWER_NOT_ANIMATED : gfx = GFX_GOLD_MINE_TOWER_ANIMATED ; break ;
}
SetIndustryGfx ( tile , gfx ) ;
2010-08-26 16:45:45 +02:00
SetAnimationFrame ( tile , 0x80 ) ;
2006-12-30 12:51:37 +01:00
AddAnimatedTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_OILWELL_NOT_ANIMATED :
2007-11-25 16:35:25 +01:00
if ( Chance16 ( 1 , 6 ) ) {
2006-12-30 12:51:37 +01:00
SetIndustryGfx ( tile , GFX_OILWELL_ANIMATED_1 ) ;
2010-08-26 16:45:45 +02:00
SetAnimationFrame ( tile , 0 ) ;
2006-12-30 12:51:37 +01:00
AddAnimatedTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_COAL_MINE_TOWER_ANIMATED :
case GFX_COPPER_MINE_TOWER_ANIMATED :
case GFX_GOLD_MINE_TOWER_ANIMATED :
2023-04-24 18:55:40 +02:00
if ( ! ( TimerGameTick : : counter & 0x400 ) ) {
2006-12-30 12:51:37 +01:00
switch ( gfx ) {
case GFX_COAL_MINE_TOWER_ANIMATED : gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED ; break ;
case GFX_COPPER_MINE_TOWER_ANIMATED : gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED ; break ;
case GFX_GOLD_MINE_TOWER_ANIMATED : gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED ; break ;
}
SetIndustryGfx ( tile , gfx ) ;
2014-04-12 13:43:04 +02:00
SetIndustryCompleted ( tile ) ;
2006-12-30 12:51:37 +01:00
SetIndustryConstructionStage ( tile , 3 ) ;
DeleteAnimatedTile ( tile ) ;
}
2004-08-09 19:04:08 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_POWERPLANT_SPARKS :
2007-11-25 16:35:25 +01:00
if ( Chance16 ( 1 , 3 ) ) {
2021-02-20 19:01:04 +01:00
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_0C_POWER_STATION , tile ) ;
2004-08-09 19:04:08 +02:00
AddAnimatedTile ( tile ) ;
}
break ;
2006-09-09 00:12:57 +02:00
case GFX_COPPER_MINE_CHIMNEY :
2011-05-28 11:45:12 +02:00
CreateEffectVehicleAbove ( TileX ( tile ) * TILE_SIZE + 6 , TileY ( tile ) * TILE_SIZE + 6 , 43 , EV_COPPER_MINE_SMOKE ) ;
2005-11-14 20:48:04 +01:00
break ;
2004-08-09 19:04:08 +02:00
2006-09-09 00:12:57 +02:00
case GFX_TOY_FACTORY : {
2009-08-30 13:47:41 +02:00
Industry * i = Industry : : GetByTile ( tile ) ;
2004-08-09 19:04:08 +02:00
if ( i - > was_cargo_delivered ) {
i - > was_cargo_delivered = false ;
2006-04-12 20:10:54 +02:00
SetIndustryAnimationLoop ( tile , 0 ) ;
2004-08-09 19:04:08 +02:00
AddAnimatedTile ( tile ) ;
}
}
break ;
2006-09-09 00:12:57 +02:00
case GFX_BUBBLE_GENERATOR :
2006-03-22 00:22:21 +01:00
TileLoopIndustry_BubbleGenerator ( tile ) ;
2004-09-11 11:55:19 +02:00
break ;
2006-09-09 00:12:57 +02:00
case GFX_TOFFEE_QUARY :
2004-08-09 19:04:08 +02:00
AddAnimatedTile ( tile ) ;
break ;
2006-09-09 00:12:57 +02:00
case GFX_SUGAR_MINE_SIEVE :
2007-11-25 16:35:25 +01:00
if ( Chance16 ( 1 , 3 ) ) AddAnimatedTile ( tile ) ;
2004-08-09 19:04:08 +02:00
break ;
}
}
2009-01-02 23:42:05 +01:00
static bool ClickTile_Industry ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2006-03-24 09:00:45 +01:00
ShowIndustryViewWindow ( GetIndustryIndex ( tile ) ) ;
2009-01-02 23:42:05 +01:00
return true ;
2004-08-09 19:04:08 +02:00
}
2023-09-16 22:20:53 +02:00
static TrackStatus GetTileTrackStatus_Industry ( TileIndex , TransportType , uint , DiagDirection )
2004-08-09 19:04:08 +02:00
{
return 0 ;
}
2008-09-30 22:39:50 +02:00
static void ChangeTileOwner_Industry ( TileIndex tile , Owner old_owner , Owner new_owner )
2004-08-09 19:04:08 +02:00
{
2007-07-07 10:53:19 +02:00
/* If the founder merges, the industry was created by the merged company */
2009-08-30 13:47:41 +02:00
Industry * i = Industry : : GetByTile ( tile ) ;
2008-09-30 22:39:50 +02:00
if ( i - > founder = = old_owner ) i - > founder = ( new_owner = = INVALID_OWNER ) ? OWNER_NONE : new_owner ;
2020-12-22 14:29:48 +01:00
if ( i - > exclusive_supplier = = old_owner ) i - > exclusive_supplier = new_owner ;
if ( i - > exclusive_consumer = = old_owner ) i - > exclusive_consumer = new_owner ;
2004-08-09 19:04:08 +02:00
}
2011-10-21 21:10:35 +02:00
/**
* Check whether the tile is a forest .
* @ param tile the tile to investigate .
* @ return true if and only if the tile is a forest
*/
bool IsTileForestIndustry ( TileIndex tile )
{
/* Check for industry tile */
if ( ! IsTileType ( tile , MP_INDUSTRY ) ) return false ;
const Industry * ind = Industry : : GetByTile ( tile ) ;
/* Check for organic industry (i.e. not processing or extractive) */
if ( ( GetIndustrySpec ( ind - > type ) - > life_type & INDUSTRYLIFE_ORGANIC ) = = 0 ) return false ;
/* Check for wood production */
2024-02-04 11:16:08 +01:00
return std : : any_of ( std : : begin ( ind - > produced ) , std : : end ( ind - > produced ) , [ ] ( const auto & p ) { return IsValidCargoID ( p . cargo ) & & CargoSpec : : Get ( p . cargo ) - > label = = CT_WOOD ; } ) ;
2011-10-21 21:10:35 +02:00
}
2024-03-16 23:59:32 +01:00
static const uint8_t _plantfarmfield_type [ ] = { 1 , 1 , 1 , 1 , 1 , 3 , 3 , 4 , 4 , 4 , 5 , 5 , 5 , 6 , 6 , 6 } ;
2004-08-09 19:04:08 +02:00
2013-10-13 00:17:11 +02:00
/**
* Check whether the tile can be replaced by a farm field .
* @ param tile the tile to investigate .
* @ param allow_fields if true , the method will return true even if
* the tile is a farm tile , otherwise the tile may not be a farm tile
* @ return true if the tile can become a farm field
*/
static bool IsSuitableForFarmField ( TileIndex tile , bool allow_fields )
2004-08-09 19:04:08 +02:00
{
2005-01-29 16:12:40 +01:00
switch ( GetTileType ( tile ) ) {
2013-10-13 00:17:11 +02:00
case MP_CLEAR : return ! IsClearGround ( tile , CLEAR_SNOW ) & & ! IsClearGround ( tile , CLEAR_DESERT ) & & ( allow_fields | | ! IsClearGround ( tile , CLEAR_FIELDS ) ) ;
case MP_TREES : return GetTreeGround ( tile ) ! = TREE_GROUND_SHORE ;
default : return false ;
2004-08-09 19:04:08 +02:00
}
}
2013-10-13 00:28:38 +02:00
/**
* Build farm field fence
* @ param tile the tile to position the fence on
* @ param size the size of the field being planted in tiles
* @ param type type of fence to set
* @ param side the side of the tile to attempt placement
*/
2024-03-16 23:59:32 +01:00
static void SetupFarmFieldFence ( TileIndex tile , int size , uint8_t type , DiagDirection side )
2004-08-09 19:04:08 +02:00
{
2013-10-13 00:28:38 +02:00
TileIndexDiff diff = ( DiagDirToAxis ( side ) = = AXIS_Y ? TileDiffXY ( 1 , 0 ) : TileDiffXY ( 0 , 1 ) ) ;
2024-02-08 19:32:44 +01:00
TileIndexDiff neighbour_diff = TileOffsByDiagDir ( side ) ;
2013-10-13 00:28:38 +02:00
2004-08-09 19:04:08 +02:00
do {
2023-01-21 11:05:19 +01:00
tile = Map : : WrapToMap ( tile ) ;
2004-09-11 11:55:19 +02:00
2011-11-08 20:48:47 +01:00
if ( IsTileType ( tile , MP_CLEAR ) & & IsClearGround ( tile , CLEAR_FIELDS ) ) {
2024-02-08 19:32:44 +01:00
TileIndex neighbour = tile + neighbour_diff ;
if ( ! IsTileType ( neighbour , MP_CLEAR ) | | ! IsClearGround ( neighbour , CLEAR_FIELDS ) | | GetFence ( neighbour , ReverseDiagDir ( side ) ) = = 0 ) {
/* Add fence as long as neighbouring tile does not already have a fence in the same position. */
2024-03-16 23:59:32 +01:00
uint8_t or_ = type ;
2004-09-11 11:55:19 +02:00
2024-02-08 19:32:44 +01:00
if ( or_ = = 1 & & Chance16 ( 1 , 7 ) ) or_ = 2 ;
2004-08-09 19:04:08 +02:00
2024-02-08 19:32:44 +01:00
SetFence ( tile , side , or_ ) ;
}
2004-08-09 19:04:08 +02:00
}
2004-09-11 11:55:19 +02:00
2013-10-13 00:28:38 +02:00
tile + = diff ;
2004-08-09 19:04:08 +02:00
} while ( - - size ) ;
}
2006-08-20 21:31:58 +02:00
static void PlantFarmField ( TileIndex tile , IndustryID industry )
2004-08-09 19:04:08 +02:00
{
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape = = LT_ARCTIC ) {
2011-11-04 11:25:58 +01:00
if ( GetTileZ ( tile ) + 2 > = GetSnowLine ( ) ) return ;
2004-08-09 19:04:08 +02:00
}
/* determine field size */
2023-05-08 19:01:06 +02:00
uint32_t r = ( Random ( ) & 0x303 ) + 0x404 ;
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape = = LT_ARCTIC ) r + = 0x404 ;
2010-07-30 12:39:24 +02:00
uint size_x = GB ( r , 0 , 8 ) ;
uint size_y = GB ( r , 8 , 8 ) ;
2004-08-09 19:04:08 +02:00
2021-01-08 11:16:18 +01:00
TileArea ta ( tile - TileDiffXY ( std : : min ( TileX ( tile ) , size_x / 2 ) , std : : min ( TileY ( tile ) , size_y / 2 ) ) , size_x , size_y ) ;
2010-12-12 21:11:46 +01:00
ta . ClampToMap ( ) ;
2004-09-11 11:55:19 +02:00
2010-12-12 21:11:46 +01:00
if ( ta . w = = 0 | | ta . h = = 0 ) return ;
2009-01-21 03:31:55 +01:00
2004-08-09 19:04:08 +02:00
/* check the amount of bad tiles */
2010-12-12 21:11:46 +01:00
int count = 0 ;
2021-05-12 16:45:28 +02:00
for ( TileIndex cur_tile : ta ) {
2023-01-21 10:43:03 +01:00
assert ( cur_tile < Map : : Size ( ) ) ;
2013-10-13 00:17:11 +02:00
count + = IsSuitableForFarmField ( cur_tile , false ) ;
2009-07-26 23:50:30 +02:00
}
2013-10-13 00:17:11 +02:00
if ( count * 2 < ta . w * ta . h ) return ;
2004-08-09 19:04:08 +02:00
/* determine type of field */
r = Random ( ) ;
2010-07-30 12:39:24 +02:00
uint counter = GB ( r , 5 , 3 ) ;
uint field_type = GB ( r , 8 , 8 ) * 9 > > 8 ;
2004-08-09 19:04:08 +02:00
/* make field */
2021-05-12 16:45:28 +02:00
for ( TileIndex cur_tile : ta ) {
2023-01-21 10:43:03 +01:00
assert ( cur_tile < Map : : Size ( ) ) ;
2013-10-13 00:17:11 +02:00
if ( IsSuitableForFarmField ( cur_tile , true ) ) {
2006-08-20 20:44:26 +02:00
MakeField ( cur_tile , field_type , industry ) ;
2006-02-05 12:54:25 +01:00
SetClearCounter ( cur_tile , counter ) ;
MarkTileDirtyByTile ( cur_tile ) ;
2004-08-09 19:04:08 +02:00
}
2009-07-26 23:50:30 +02:00
}
2004-09-11 11:55:19 +02:00
2010-07-30 12:39:24 +02:00
int type = 3 ;
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape ! = LT_ARCTIC & & _settings_game . game_creation . landscape ! = LT_TROPIC ) {
2004-08-09 19:04:08 +02:00
type = _plantfarmfield_type [ Random ( ) & 0xF ] ;
}
2013-10-13 00:28:38 +02:00
SetupFarmFieldFence ( ta . tile , ta . h , type , DIAGDIR_NE ) ;
SetupFarmFieldFence ( ta . tile , ta . w , type , DIAGDIR_NW ) ;
SetupFarmFieldFence ( ta . tile + TileDiffXY ( ta . w - 1 , 0 ) , ta . h , type , DIAGDIR_SW ) ;
SetupFarmFieldFence ( ta . tile + TileDiffXY ( 0 , ta . h - 1 ) , ta . w , type , DIAGDIR_SE ) ;
2004-08-09 19:04:08 +02:00
}
2006-08-20 20:44:26 +02:00
void PlantRandomFarmField ( const Industry * i )
{
2010-01-04 19:21:07 +01:00
int x = i - > location . w / 2 + Random ( ) % 31 - 16 ;
int y = i - > location . h / 2 + Random ( ) % 31 - 16 ;
2006-08-20 20:44:26 +02:00
2010-01-04 19:21:07 +01:00
TileIndex tile = TileAddWrap ( i - > location . tile , x , y ) ;
2006-08-20 20:44:26 +02:00
if ( tile ! = INVALID_TILE ) PlantFarmField ( tile , i - > index ) ;
}
2006-11-18 00:01:58 +01:00
/**
* Search callback function for ChopLumberMillTrees
* @ param tile to test
2007-03-03 05:04:22 +01:00
* @ return the result of the test
2006-11-18 00:01:58 +01:00
*/
2023-09-16 22:20:53 +02:00
static bool SearchLumberMillTrees ( TileIndex tile , void * )
2004-08-09 19:04:08 +02:00
{
2007-02-02 16:14:28 +01:00
if ( IsTileType ( tile , MP_TREES ) & & GetTreeGrowth ( tile ) > 2 ) { ///< 3 and up means all fully grown trees
2006-11-18 00:01:58 +01:00
/* found a tree */
2004-08-09 19:04:08 +02:00
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_NONE ) ;
2010-05-31 22:22:57 +02:00
2006-11-18 00:01:58 +01:00
_industry_sound_ctr = 1 ;
_industry_sound_tile = tile ;
2021-02-20 19:01:04 +01:00
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_38_LUMBER_MILL_1 , tile ) ;
2005-11-14 20:48:04 +01:00
2021-11-21 23:02:29 +01:00
Command < CMD_LANDSCAPE_CLEAR > : : Do ( DC_EXEC , tile ) ;
2005-11-14 20:48:04 +01:00
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2006-11-18 00:01:58 +01:00
return true ;
}
return false ;
}
2004-08-09 19:04:08 +02:00
2006-11-18 00:01:58 +01:00
/**
* Perform a circular search around the Lumber Mill in order to find trees to cut
* @ param i industry
*/
static void ChopLumberMillTrees ( Industry * i )
{
2023-11-29 22:30:19 +01:00
/* Don't process lumber mill if cargo is not set up correctly. */
auto itp = std : : begin ( i - > produced ) ;
if ( itp = = std : : end ( i - > produced ) | | ! IsValidCargoID ( itp - > cargo ) ) return ;
2023-09-18 23:43:03 +02:00
2011-12-09 17:12:38 +01:00
/* We only want to cut trees if all tiles are completed. */
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_cur : i - > location ) {
2011-12-09 17:12:38 +01:00
if ( i - > TileBelongsToIndustry ( tile_cur ) ) {
if ( ! IsIndustryCompleted ( tile_cur ) ) return ;
}
}
2004-09-25 19:37:32 +02:00
2011-12-09 17:12:38 +01:00
TileIndex tile = i - > location . tile ;
2019-04-10 23:07:06 +02:00
if ( CircularTileSearch ( & tile , 40 , SearchLumberMillTrees , nullptr ) ) { // 40x40 tiles to search.
2023-11-29 22:30:19 +01:00
itp - > waiting = ClampTo < uint16_t > ( itp - > waiting + ScaleByCargoScale ( 45 , false ) ) ; // Found a tree, add according value to waiting cargo.
2024-01-30 21:11:46 +01:00
}
}
/**
* Helper for ProduceIndustryGoods that scales and produces cargos .
* @ param i The industry
* @ param scale Should we scale production of this cargo directly ?
*/
static void ProduceIndustryGoodsHelper ( Industry * i , bool scale )
{
for ( auto & p : i - > produced ) {
if ( ! IsValidCargoID ( p . cargo ) ) continue ;
uint16_t amount = p . rate ;
if ( scale ) amount = ScaleByCargoScale ( amount , false ) ;
p . waiting = ClampTo < uint16_t > ( p . waiting + amount ) ;
2010-07-24 12:14:39 +02:00
}
2004-08-09 19:04:08 +02:00
}
static void ProduceIndustryGoods ( Industry * i )
{
2007-05-20 02:50:06 +02:00
const IndustrySpec * indsp = GetIndustrySpec ( i - > type ) ;
2004-08-09 19:04:08 +02:00
/* play a sound? */
if ( ( i - > counter & 0x3F ) = = 0 ) {
2023-05-08 19:01:06 +02:00
uint32_t r ;
2019-10-12 10:16:16 +02:00
if ( Chance16R ( 1 , 14 , r ) & & indsp - > number_of_sounds ! = 0 & & _settings_client . sound . ambient ) {
2023-05-25 22:25:46 +02:00
if ( std : : any_of ( std : : begin ( i - > produced ) , std : : end ( i - > produced ) , [ ] ( const auto & p ) { return p . history [ LAST_MONTH ] . production > 0 ; } ) ) {
/* Play sound since last month had production */
SndPlayTileFx (
( SoundFx ) ( indsp - > random_sounds [ ( ( r > > 16 ) * indsp - > number_of_sounds ) > > 16 ] ) ,
i - > location . tile ) ;
2019-10-12 10:16:16 +02:00
}
2004-08-09 19:04:08 +02:00
}
}
i - > counter - - ;
2024-01-30 21:11:46 +01:00
/* If using an industry callback, scale the callback interval by cargo scale percentage. */
if ( HasBit ( indsp - > callback_mask , CBM_IND_PRODUCTION_256_TICKS ) ) {
if ( i - > counter % ScaleByInverseCargoScale ( Ticks : : INDUSTRY_PRODUCE_TICKS , false ) = = 0 ) {
IndustryProductionCallback ( i , 1 ) ;
ProduceIndustryGoodsHelper ( i , false ) ;
}
}
/*
* All other production and special effects happen every 256 ticks , and cargo production is just scaled by the cargo scale percentage .
* This keeps a slow trickle of production to avoid confusion at low scale factors when the industry seems to be doing nothing for a long period of time .
*/
2023-08-16 15:01:24 +02:00
if ( ( i - > counter % Ticks : : INDUSTRY_PRODUCE_TICKS ) = = 0 ) {
2024-01-30 21:11:46 +01:00
/* Handle non-callback cargo production. */
if ( ! HasBit ( indsp - > callback_mask , CBM_IND_PRODUCTION_256_TICKS ) ) ProduceIndustryGoodsHelper ( i , true ) ;
2007-07-05 07:41:56 +02:00
2007-10-19 23:14:38 +02:00
IndustryBehaviour indbehav = indsp - > behaviour ;
2004-08-09 19:04:08 +02:00
2007-07-08 21:54:51 +02:00
if ( ( indbehav & INDUSTRYBEH_PLANT_FIELDS ) ! = 0 ) {
2023-05-08 19:01:06 +02:00
uint16_t cb_res = CALLBACK_FAILED ;
2009-09-14 14:22:57 +02:00
if ( HasBit ( indsp - > callback_mask , CBM_IND_SPECIAL_EFFECT ) ) {
2011-11-08 18:26:49 +01:00
cb_res = GetIndustryCallback ( CBID_INDUSTRY_SPECIAL_EFFECT , Random ( ) , 0 , i , i - > type , i - > location . tile ) ;
}
bool plant ;
if ( cb_res ! = CALLBACK_FAILED ) {
plant = ConvertBooleanCallback ( indsp - > grf_prop . grffile , CBID_INDUSTRY_SPECIAL_EFFECT , cb_res ) ;
2007-07-08 21:54:51 +02:00
} else {
2007-11-25 16:35:25 +01:00
plant = Chance16 ( 1 , 8 ) ;
2007-07-08 21:54:51 +02:00
}
if ( plant ) PlantRandomFarmField ( i ) ;
}
if ( ( indbehav & INDUSTRYBEH_CUT_TREES ) ! = 0 ) {
2023-05-08 19:01:06 +02:00
uint16_t cb_res = CALLBACK_FAILED ;
2009-09-14 14:22:57 +02:00
if ( HasBit ( indsp - > callback_mask , CBM_IND_SPECIAL_EFFECT ) ) {
2011-11-08 18:26:49 +01:00
cb_res = GetIndustryCallback ( CBID_INDUSTRY_SPECIAL_EFFECT , Random ( ) , 1 , i , i - > type , i - > location . tile ) ;
}
bool cut ;
if ( cb_res ! = CALLBACK_FAILED ) {
cut = ConvertBooleanCallback ( indsp - > grf_prop . grffile , CBID_INDUSTRY_SPECIAL_EFFECT , cb_res ) ;
} else {
2023-08-16 15:01:24 +02:00
cut = ( ( i - > counter % Ticks : : INDUSTRY_CUT_TREE_TICKS ) = = 0 ) ;
2007-07-08 21:54:51 +02:00
}
if ( cut ) ChopLumberMillTrees ( i ) ;
2005-11-14 20:48:04 +01:00
}
2008-04-23 02:14:49 +02:00
TriggerIndustry ( i , INDUSTRY_TRIGGER_INDUSTRY_TICK ) ;
StartStopIndustryTileAnimation ( i , IAT_INDUSTRY_TICK ) ;
2004-08-09 19:04:08 +02:00
}
}
2007-03-07 12:47:46 +01:00
void OnTick_Industry ( )
2004-08-09 19:04:08 +02:00
{
if ( _industry_sound_ctr ! = 0 ) {
_industry_sound_ctr + + ;
if ( _industry_sound_ctr = = 75 ) {
2021-02-20 19:01:04 +01:00
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_37_LUMBER_MILL_2 , _industry_sound_tile ) ;
2004-08-09 19:04:08 +02:00
} else if ( _industry_sound_ctr = = 160 ) {
2004-09-11 11:55:19 +02:00
_industry_sound_ctr = 0 ;
2021-02-20 19:01:04 +01:00
if ( _settings_client . sound . ambient ) SndPlayTileFx ( SND_36_LUMBER_MILL_3 , _industry_sound_tile ) ;
2004-08-09 19:04:08 +02:00
}
}
2005-11-14 20:48:04 +01:00
if ( _game_mode = = GM_EDITOR ) return ;
2004-08-09 19:04:08 +02:00
2019-12-16 18:51:20 +01:00
for ( Industry * i : Industry : : Iterate ( ) ) {
2006-08-22 17:33:35 +02:00
ProduceIndustryGoods ( i ) ;
2004-08-09 19:04:08 +02:00
}
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_NOTHING ( Always succeeds ) .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2023-09-16 22:20:53 +02:00
static CommandCost CheckNewIndustry_NULL ( TileIndex )
2004-08-09 19:04:08 +02:00
{
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_FOREST ( Industry should be build above snow - line in arctic climate ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_Forest ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape = = LT_ARCTIC ) {
2011-11-04 12:30:37 +01:00
if ( GetTileZ ( tile ) < HighestSnowLine ( ) + 2 ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED ) ;
2004-08-09 19:04:08 +02:00
}
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2019-04-15 18:06:25 +02:00
/**
* Check if a tile is within a distance from map edges , scaled by map dimensions independently .
* Each dimension is checked independently , and dimensions smaller than 256 are not scaled .
* @ param tile Which tile to check distance of .
* @ param maxdist Normal distance on a 256 x256 map .
* @ return True if the tile is near the map edge .
*/
static bool CheckScaledDistanceFromEdge ( TileIndex tile , uint maxdist )
{
uint maxdist_x = maxdist ;
uint maxdist_y = maxdist ;
2023-01-21 10:43:03 +01:00
if ( Map : : SizeX ( ) > 256 ) maxdist_x * = Map : : SizeX ( ) / 256 ;
if ( Map : : SizeY ( ) > 256 ) maxdist_y * = Map : : SizeY ( ) / 256 ;
2019-04-15 18:06:25 +02:00
if ( DistanceFromEdgeDir ( tile , DIAGDIR_NE ) < maxdist_x ) return true ;
if ( DistanceFromEdgeDir ( tile , DIAGDIR_NW ) < maxdist_y ) return true ;
if ( DistanceFromEdgeDir ( tile , DIAGDIR_SW ) < maxdist_x ) return true ;
if ( DistanceFromEdgeDir ( tile , DIAGDIR_SE ) < maxdist_y ) return true ;
return false ;
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_REFINERY ( Industry should be positioned near edge of the map ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_OilRefinery ( TileIndex tile )
2006-05-20 18:46:37 +02:00
{
2010-02-16 23:01:23 +01:00
if ( _game_mode = = GM_EDITOR ) return CommandCost ( ) ;
2019-04-15 18:06:25 +02:00
2024-03-10 14:51:08 +01:00
if ( CheckScaledDistanceFromEdge ( TileAddXY ( tile , 1 , 1 ) , _settings_game . game_creation . oil_refinery_limit ) ) return CommandCost ( ) ;
2006-05-20 18:46:37 +02:00
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_POSITIONED ) ;
2006-05-20 18:46:37 +02:00
}
2004-08-10 18:12:40 +02:00
extern bool _ignore_restrictions ;
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_OIL_RIG ( Industries at sea should be positioned near edge of the map ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_OilRig ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2010-02-16 23:01:23 +01:00
if ( _game_mode = = GM_EDITOR & & _ignore_restrictions ) return CommandCost ( ) ;
2019-04-15 18:06:25 +02:00
2006-05-20 18:46:37 +02:00
if ( TileHeight ( tile ) = = 0 & &
2024-03-10 14:51:08 +01:00
CheckScaledDistanceFromEdge ( TileAddXY ( tile , 1 , 1 ) , _settings_game . game_creation . oil_refinery_limit ) ) return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_POSITIONED ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_FARM ( Industry should be below snow - line in arctic ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_Farm ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2008-05-29 17:13:28 +02:00
if ( _settings_game . game_creation . landscape = = LT_ARCTIC ) {
2011-11-04 11:25:58 +01:00
if ( GetTileZ ( tile ) + 2 > = HighestSnowLine ( ) ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2004-08-09 19:04:08 +02:00
}
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_PLANTATION ( Industry should NOT be in the desert ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_Plantation ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2006-03-30 21:16:44 +02:00
if ( GetTropicZone ( tile ) = = TROPICZONE_DESERT ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2004-08-09 19:04:08 +02:00
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_WATER ( Industry should be in the desert ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_Water ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2006-03-30 21:16:44 +02:00
if ( GetTropicZone ( tile ) ! = TROPICZONE_DESERT ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT ) ;
2004-08-09 19:04:08 +02:00
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_LUMBERMILL ( Industry should be in the rain forest ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_Lumbermill ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2006-03-30 21:16:44 +02:00
if ( GetTropicZone ( tile ) ! = TROPICZONE_RAINFOREST ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST ) ;
2004-08-09 19:04:08 +02:00
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Check the conditions of # CHECK_BUBBLEGEN ( Industry should be in low land ) .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to perform the checking .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
static CommandCost CheckNewIndustry_BubbleGen ( TileIndex tile )
2004-08-09 19:04:08 +02:00
{
2011-11-04 11:31:46 +01:00
if ( GetTileZ ( tile ) > 4 ) {
2010-02-16 23:01:23 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS ) ;
2010-02-15 11:28:40 +01:00
}
2010-02-16 23:01:23 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Industrytype check function signature .
2010-02-15 10:49:10 +01:00
* @ param tile % Tile to check .
2010-02-16 23:01:23 +01:00
* @ return Succeeded or failed command .
2010-02-15 10:49:10 +01:00
*/
2010-02-16 23:01:23 +01:00
typedef CommandCost CheckNewIndustryProc ( TileIndex tile ) ;
2010-02-15 10:49:10 +01:00
/** Check functions for different types of industry. */
2006-04-26 19:01:27 +02:00
static CheckNewIndustryProc * const _check_new_industry_procs [ CHECK_END ] = {
2010-02-15 10:49:10 +01:00
CheckNewIndustry_NULL , ///< CHECK_NOTHING
CheckNewIndustry_Forest , ///< CHECK_FOREST
CheckNewIndustry_OilRefinery , ///< CHECK_REFINERY
CheckNewIndustry_Farm , ///< CHECK_FARM
CheckNewIndustry_Plantation , ///< CHECK_PLANTATION
CheckNewIndustry_Water , ///< CHECK_WATER
CheckNewIndustry_Lumbermill , ///< CHECK_LUMBERMILL
CheckNewIndustry_BubbleGen , ///< CHECK_BUBBLEGEN
CheckNewIndustry_OilRig , ///< CHECK_OIL_RIG
2004-08-09 19:04:08 +02:00
} ;
2010-08-01 21:22:34 +02:00
/**
* Find a town for the industry , while checking for multiple industries in the same town .
2010-02-15 12:04:27 +01:00
* @ param tile Position of the industry to build .
* @ param type Industry type .
2019-04-10 23:07:06 +02:00
* @ param [ out ] t Pointer to return town for the new industry , \ c nullptr is written if no good town can be found .
2010-02-21 15:57:27 +01:00
* @ return Succeeded or failed command .
*
2019-04-10 23:07:06 +02:00
* @ pre \ c * t ! = nullptr
* @ post \ c * t points to a town on success , and \ c nullptr on failure .
2010-02-15 12:04:27 +01:00
*/
2011-06-12 22:31:44 +02:00
static CommandCost FindTownForIndustry ( TileIndex tile , int type , Town * * t )
2004-08-09 19:04:08 +02:00
{
2010-02-21 15:57:27 +01:00
* t = ClosestTownFromTile ( tile , UINT_MAX ) ;
2004-08-09 19:04:08 +02:00
2010-02-21 15:57:27 +01:00
if ( _settings_game . economy . multiple_industry_per_town ) return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
2019-12-16 18:51:20 +01:00
for ( const Industry * i : Industry : : Iterate ( ) ) {
2024-03-16 23:59:32 +01:00
if ( i - > type = = ( uint8_t ) type & & i - > town = = * t ) {
2019-04-10 23:07:06 +02:00
* t = nullptr ;
2010-02-21 15:57:27 +01:00
return_cmd_error ( STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN ) ;
2004-08-09 19:04:08 +02:00
}
}
2010-02-21 15:57:27 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2007-10-02 18:56:45 +02:00
bool IsSlopeRefused ( Slope current , Slope refused )
{
2007-10-15 20:36:20 +02:00
if ( IsSteepSlope ( current ) ) return true ;
2007-10-02 18:56:45 +02:00
if ( current ! = SLOPE_FLAT ) {
2007-12-07 22:16:38 +01:00
if ( IsSteepSlope ( refused ) ) return true ;
2007-10-02 18:56:45 +02:00
Slope t = ComplementSlope ( current ) ;
2009-06-01 13:43:36 +02:00
if ( ( refused & SLOPE_W ) & & ( t & SLOPE_NW ) ) return true ;
if ( ( refused & SLOPE_S ) & & ( t & SLOPE_NE ) ) return true ;
if ( ( refused & SLOPE_E ) & & ( t & SLOPE_SW ) ) return true ;
if ( ( refused & SLOPE_N ) & & ( t & SLOPE_SE ) ) return true ;
2007-10-02 18:56:45 +02:00
}
return false ;
}
2010-08-01 21:22:34 +02:00
/**
* Are the tiles of the industry free ?
2018-10-28 03:17:36 +01:00
* @ param tile Position to check .
2019-10-04 21:26:44 +02:00
* @ param layout Industry tiles table .
2018-10-28 03:17:36 +01:00
* @ param type Type of the industry .
2010-02-21 16:27:11 +01:00
* @ return Failed or succeeded command .
*/
2022-09-01 18:13:43 +02:00
static CommandCost CheckIfIndustryTilesAreFree ( TileIndex tile , const IndustryTileLayout & layout , IndustryType type )
2004-08-09 19:04:08 +02:00
{
2022-09-01 18:13:43 +02:00
IndustryBehaviour ind_behav = GetIndustrySpec ( type ) - > behaviour ;
2004-08-09 19:04:08 +02:00
2019-10-04 21:26:44 +02:00
for ( const IndustryTileLayoutTile & it : layout ) {
IndustryGfx gfx = GetTranslatedIndustryTileID ( it . gfx ) ;
TileIndex cur_tile = TileAddWrap ( tile , it . ti . x , it . ti . y ) ;
2005-06-24 14:38:35 +02:00
2004-08-09 19:04:08 +02:00
if ( ! IsValidTile ( cur_tile ) ) {
2010-02-26 10:55:53 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2004-08-09 19:04:08 +02:00
}
2004-09-11 11:55:19 +02:00
2007-08-26 02:23:32 +02:00
if ( gfx = = GFX_WATERTILE_SPECIALCHECK ) {
2017-04-02 19:36:53 +02:00
if ( ! IsWaterTile ( cur_tile ) | |
2013-10-13 00:07:58 +02:00
! IsTileFlat ( cur_tile ) ) {
2010-02-26 10:55:53 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2006-03-22 20:04:04 +01:00
}
2004-08-09 19:04:08 +02:00
} else {
2010-03-05 22:20:22 +01:00
CommandCost ret = EnsureNoVehicleOnGround ( cur_tile ) ;
if ( ret . Failed ( ) ) return ret ;
2014-09-21 13:24:51 +02:00
if ( IsBridgeAbove ( cur_tile ) ) return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2007-06-13 17:22:28 +02:00
2007-09-06 05:02:38 +02:00
const IndustryTileSpec * its = GetIndustryTileSpec ( gfx ) ;
2007-10-19 23:05:25 +02:00
/* Perform land/water check if not disabled */
2010-09-05 18:00:04 +02:00
if ( ! HasBit ( its - > slopes_refused , 5 ) & & ( ( HasTileWaterClass ( cur_tile ) & & IsTileOnWater ( cur_tile ) ) = = ! ( ind_behav & INDUSTRYBEH_BUILT_ONWATER ) ) ) return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2007-10-19 23:05:25 +02:00
2009-01-09 16:11:35 +01:00
if ( ( ind_behav & ( INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE ) ) | | // Tile must be a house
( ( ind_behav & INDUSTRYBEH_ONLY_NEARTOWN ) & & IsTileType ( cur_tile , MP_HOUSE ) ) ) { // Tile is allowed to be a house (and it is a house)
2007-07-09 20:53:43 +02:00
if ( ! IsTileType ( cur_tile , MP_HOUSE ) ) {
2010-02-21 16:27:11 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS ) ;
2004-08-09 19:04:08 +02:00
}
2008-11-23 17:34:27 +01:00
/* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_TOWN ) ;
2023-01-28 20:06:51 +01:00
ret = Command < CMD_LANDSCAPE_CLEAR > : : Do ( DC_NONE , cur_tile ) ;
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2008-11-23 17:34:27 +01:00
2010-02-26 10:55:53 +01:00
if ( ret . Failed ( ) ) return ret ;
2009-01-09 16:11:35 +01:00
} else {
2009-02-11 21:09:29 +01:00
/* Clear the tiles, but do not affect town ratings */
2023-01-28 20:06:51 +01:00
ret = Command < CMD_LANDSCAPE_CLEAR > : : Do ( DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING , cur_tile ) ;
2022-09-01 18:13:43 +02:00
if ( ret . Failed ( ) ) return ret ;
}
}
}
return CommandCost ( ) ;
}
2008-11-23 17:34:27 +01:00
2022-09-01 18:13:43 +02:00
/**
* Check slope requirements for industry tiles .
* @ param tile Position to check .
* @ param layout Industry tiles table .
* @ param layout_index The index of the layout to build / fund
* @ param type Type of the industry .
* @ param initial_random_bits The random bits the industry is going to have after construction .
* @ param founder Industry founder
* @ param creation_type The circumstances the industry is created under .
* @ param [ out ] custom_shape_check Perform custom check for the site .
* @ return Failed or succeeded command .
*/
2023-05-08 19:01:06 +02:00
static CommandCost CheckIfIndustryTileSlopes ( TileIndex tile , const IndustryTileLayout & layout , size_t layout_index , int type , uint16_t initial_random_bits , Owner founder , IndustryAvailabilityCallType creation_type , bool * custom_shape_check = nullptr )
2022-09-01 18:13:43 +02:00
{
bool refused_slope = false ;
bool custom_shape = false ;
for ( const IndustryTileLayoutTile & it : layout ) {
IndustryGfx gfx = GetTranslatedIndustryTileID ( it . gfx ) ;
TileIndex cur_tile = TileAddWrap ( tile , it . ti . x , it . ti . y ) ;
assert ( IsValidTile ( cur_tile ) ) ; // checked before in CheckIfIndustryTilesAreFree
if ( gfx ! = GFX_WATERTILE_SPECIALCHECK ) {
const IndustryTileSpec * its = GetIndustryTileSpec ( gfx ) ;
if ( HasBit ( its - > callback_mask , CBM_INDT_SHAPE_CHECK ) ) {
custom_shape = true ;
CommandCost ret = PerformIndustryTileSlopeCheck ( tile , cur_tile , its , type , gfx , layout_index , initial_random_bits , founder , creation_type ) ;
2010-02-26 10:55:53 +01:00
if ( ret . Failed ( ) ) return ret ;
2022-09-01 18:13:43 +02:00
} else {
Slope tileh = GetTileSlope ( cur_tile ) ;
refused_slope | = IsSlopeRefused ( tileh , its - > slopes_refused ) ;
2007-07-09 20:53:43 +02:00
}
2004-08-09 19:04:08 +02:00
}
2019-10-04 21:26:44 +02:00
}
2004-08-09 19:04:08 +02:00
2019-04-10 23:07:06 +02:00
if ( custom_shape_check ! = nullptr ) * custom_shape_check = custom_shape ;
2007-10-02 19:48:17 +02:00
/* It is almost impossible to have a fully flat land in TG, so what we
* do is that we check if we can make the land flat later on . See
* CheckIfCanLevelIndustryPlatform ( ) . */
2010-02-21 16:27:11 +01:00
if ( ! refused_slope | | ( _settings_game . game_creation . land_generator = = LG_TERRAGENESIS & & _generating_world & & ! custom_shape & & ! _ignore_restrictions ) ) {
return CommandCost ( ) ;
}
2010-02-26 10:55:53 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Is the industry allowed to be built at this place for the town ?
2010-02-21 14:32:14 +01:00
* @ param tile Tile to construct the industry .
* @ param type Type of the industry .
* @ param t Town authority that the industry belongs to .
* @ return Succeeded or failed command .
*/
static CommandCost CheckIfIndustryIsAllowed ( TileIndex tile , int type , const Town * t )
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
{
2012-04-25 22:50:13 +02:00
if ( ( GetIndustrySpec ( type ) - > behaviour & INDUSTRYBEH_TOWN1200_MORE ) & & t - > cache . population < 1200 ) {
2010-02-21 14:32:14 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2007-03-28 22:06:28 +02:00
if ( ( GetIndustrySpec ( type ) - > behaviour & INDUSTRYBEH_ONLY_NEARTOWN ) & & DistanceMax ( t - > xy , tile ) > 9 ) {
2012-03-17 20:48:26 +01:00
return_cmd_error ( STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2010-02-21 14:32:14 +01:00
return CommandCost ( ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
static bool CheckCanTerraformSurroundingTiles ( TileIndex tile , uint height , int internal )
{
/* Check if we don't leave the map */
if ( TileX ( tile ) = = 0 | | TileY ( tile ) = = 0 | | GetTileType ( tile ) = = MP_VOID ) return false ;
2010-12-12 21:11:46 +01:00
TileArea ta ( tile - TileDiffXY ( 1 , 1 ) , 2 , 2 ) ;
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_walk : ta ) {
2010-07-30 12:39:24 +02:00
uint curh = TileHeight ( tile_walk ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* Is the tile clear? */
2010-07-24 12:14:39 +02:00
if ( ( GetTileType ( tile_walk ) ! = MP_CLEAR ) & & ( GetTileType ( tile_walk ) ! = MP_TREES ) ) return false ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* Don't allow too big of a change if this is the sub-tile check */
2007-11-26 17:01:29 +01:00
if ( internal ! = 0 & & Delta ( curh , height ) > 1 ) return false ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* Different height, so the surrounding tiles of this tile
* has to be correct too ( in level , or almost in level )
* else you get a chain - reaction of terraforming . */
if ( internal = = 0 & & curh ! = height ) {
2010-07-24 12:14:39 +02:00
if ( TileX ( tile_walk ) = = 0 | | TileY ( tile_walk ) = = 0 | | ! CheckCanTerraformSurroundingTiles ( tile_walk + TileDiffXY ( - 1 , - 1 ) , height , internal + 1 ) ) {
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
return false ;
2010-07-24 12:14:39 +02:00
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2009-07-26 23:50:30 +02:00
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
return true ;
}
/**
* This function tries to flatten out the land below an industry , without
* damaging the surroundings too much .
*/
2023-09-16 23:27:16 +02:00
static bool CheckIfCanLevelIndustryPlatform ( TileIndex tile , DoCommandFlag flags , const IndustryTileLayout & layout )
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
{
int max_x = 0 ;
int max_y = 0 ;
/* Finds dimensions of largest variant of this industry */
2019-10-04 21:26:44 +02:00
for ( const IndustryTileLayoutTile & it : layout ) {
if ( it . gfx = = GFX_WATERTILE_SPECIALCHECK ) continue ; // watercheck tiles don't count for footprint size
if ( it . ti . x > max_x ) max_x = it . ti . x ;
if ( it . ti . y > max_y ) max_y = it . ti . y ;
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* Remember level height */
2010-07-30 12:39:24 +02:00
uint h = TileHeight ( tile ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2010-12-12 21:11:46 +01:00
if ( TileX ( tile ) < = _settings_game . construction . industry_platform + 1U | | TileY ( tile ) < = _settings_game . construction . industry_platform + 1U ) return false ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* Check that all tiles in area and surrounding are clear
* this determines that there are no obstructing items */
2010-08-28 20:37:49 +02:00
2019-04-13 15:12:34 +02:00
/* TileArea::Expand is not used here as we need to abort
* instead of clamping if the bounds cannot expanded . */
2010-12-12 21:11:46 +01:00
TileArea ta ( tile + TileDiffXY ( - _settings_game . construction . industry_platform , - _settings_game . construction . industry_platform ) ,
max_x + 2 + 2 * _settings_game . construction . industry_platform , max_y + 2 + 2 * _settings_game . construction . industry_platform ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2023-01-21 10:43:03 +01:00
if ( TileX ( ta . tile ) + ta . w > = Map : : MaxX ( ) | | TileY ( ta . tile ) + ta . h > = Map : : MaxY ( ) ) return false ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2008-09-30 22:39:50 +02:00
/* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
2009-02-11 21:09:29 +01:00
* Perform terraforming as OWNER_TOWN to disable autoslope and town ratings . */
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_TOWN ) ;
2007-09-26 16:32:06 +02:00
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_walk : ta ) {
2010-07-30 12:39:24 +02:00
uint curh = TileHeight ( tile_walk ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
if ( curh ! = h ) {
/* This tile needs terraforming. Check if we can do that without
* damaging the surroundings too much . */
2007-09-26 16:32:06 +02:00
if ( ! CheckCanTerraformSurroundingTiles ( tile_walk , h , 0 ) ) {
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2007-09-26 16:32:06 +02:00
return false ;
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/* This is not 100% correct check, but the best we can do without modifying the map.
* What is missing , is if the difference in height is more than 1. . */
2021-12-01 00:44:57 +01:00
if ( std : : get < 0 > ( Command < CMD_TERRAFORM_LAND > : : Do ( flags & ~ DC_EXEC , tile_walk , SLOPE_N , curh < = h ) ) . Failed ( ) ) {
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2007-09-26 16:32:06 +02:00
return false ;
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2009-07-26 23:50:30 +02:00
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
if ( flags & DC_EXEC ) {
/* Terraform the land under the industry */
2021-05-12 16:45:28 +02:00
for ( TileIndex tile_walk : ta ) {
2010-07-30 12:39:24 +02:00
uint curh = TileHeight ( tile_walk ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
while ( curh ! = h ) {
/* We give the terraforming for free here, because we can't calculate
* exact cost in the test - round , and as we all know , that will cause
* a nice assert if they don ' t match ; ) */
2021-11-21 23:02:29 +01:00
Command < CMD_TERRAFORM_LAND > : : Do ( flags , tile_walk , SLOPE_N , curh < = h ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
curh + = ( curh > h ) ? - 1 : 1 ;
}
2009-07-26 23:50:30 +02:00
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
return true ;
}
2010-08-01 21:22:34 +02:00
/**
* Check that the new industry is far enough from conflicting industries .
2010-02-21 14:32:14 +01:00
* @ param tile Tile to construct the industry .
* @ param type Type of the new industry .
* @ return Succeeded or failed command .
*/
2010-03-21 16:16:05 +01:00
static CommandCost CheckIfFarEnoughFromConflictingIndustry ( TileIndex tile , int type )
2004-08-09 19:04:08 +02:00
{
2006-04-26 23:10:01 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( type ) ;
2014-02-06 22:05:00 +01:00
/* On a large map with many industries, it may be faster to check an area. */
2014-02-10 18:13:54 +01:00
static const int dmax = 14 ;
2014-02-06 22:05:00 +01:00
if ( Industry : : GetNumItems ( ) > ( size_t ) ( dmax * dmax * 2 ) ) {
2024-01-03 22:33:38 +01:00
const Industry * i = nullptr ;
2019-04-13 15:12:34 +02:00
TileArea tile_area = TileArea ( tile , 1 , 1 ) . Expand ( dmax ) ;
2021-05-12 16:45:28 +02:00
for ( TileIndex atile : tile_area ) {
2014-02-06 22:05:00 +01:00
if ( GetTileType ( atile ) = = MP_INDUSTRY ) {
const Industry * i2 = Industry : : GetByTile ( atile ) ;
if ( i = = i2 ) continue ;
i = i2 ;
2014-02-10 18:13:54 +01:00
if ( DistanceMax ( tile , i - > location . tile ) > ( uint ) dmax ) continue ;
2014-02-06 22:05:00 +01:00
if ( i - > type = = indspec - > conflicting [ 0 ] | |
i - > type = = indspec - > conflicting [ 1 ] | |
i - > type = = indspec - > conflicting [ 2 ] ) {
return_cmd_error ( STR_ERROR_INDUSTRY_TOO_CLOSE ) ;
}
}
}
return CommandCost ( ) ;
}
2019-12-16 18:51:20 +01:00
for ( const Industry * i : Industry : : Iterate ( ) ) {
2008-01-09 19:35:18 +01:00
/* Within 14 tiles from another industry is considered close */
2010-03-19 22:23:54 +01:00
if ( DistanceMax ( tile , i - > location . tile ) > 14 ) continue ;
2008-01-09 19:35:18 +01:00
/* check if there are any conflicting industry types around */
2010-03-19 22:23:54 +01:00
if ( i - > type = = indspec - > conflicting [ 0 ] | |
2008-01-09 19:35:18 +01:00
i - > type = = indspec - > conflicting [ 1 ] | |
2010-03-19 22:23:54 +01:00
i - > type = = indspec - > conflicting [ 2 ] ) {
2010-02-21 14:32:14 +01:00
return_cmd_error ( STR_ERROR_INDUSTRY_TOO_CLOSE ) ;
2004-08-09 19:04:08 +02:00
}
}
2010-02-21 14:32:14 +01:00
return CommandCost ( ) ;
2004-08-09 19:04:08 +02:00
}
2012-04-28 18:07:28 +02:00
/**
* Advertise about a new industry opening .
* @ param ind Industry being opened .
*/
static void AdvertiseIndustryOpening ( const Industry * ind )
{
const IndustrySpec * ind_spc = GetIndustrySpec ( ind - > type ) ;
SetDParam ( 0 , ind_spc - > name ) ;
if ( ind_spc - > new_industry_text > STR_LAST_STRINGID ) {
SetDParam ( 1 , STR_TOWN_NAME ) ;
SetDParam ( 2 , ind - > town - > index ) ;
} else {
SetDParam ( 1 , ind - > town - > index ) ;
}
2012-05-26 16:16:03 +02:00
AddIndustryNewsItem ( ind_spc - > new_industry_text , NT_INDUSTRY_OPEN , ind - > index ) ;
2012-04-28 18:07:28 +02:00
AI : : BroadcastNewEvent ( new ScriptEventIndustryOpen ( ind - > index ) ) ;
Game : : NewEvent ( new ScriptEventIndustryOpen ( ind - > index ) ) ;
}
2019-02-14 22:07:15 +01:00
/**
* Populate an industry ' s list of nearby stations , and if it accepts any cargo , also
* add the industry to each station ' s nearby industry list .
* @ param ind Industry
*/
static void PopulateStationsNearby ( Industry * ind )
{
2019-04-10 23:07:06 +02:00
if ( ind - > neutral_station ! = nullptr & & ! _settings_game . station . serve_neutral_industries ) {
2019-02-14 22:07:15 +01:00
/* Industry has a neutral station. Use it and ignore any other nearby stations. */
ind - > stations_near . insert ( ind - > neutral_station ) ;
ind - > neutral_station - > industries_near . clear ( ) ;
2022-02-19 19:08:23 +01:00
ind - > neutral_station - > industries_near . insert ( IndustryListEntry { 0 , ind } ) ;
2019-02-14 22:07:15 +01:00
return ;
}
2020-05-12 01:21:14 +02:00
ForAllStationsAroundTiles ( ind - > location , [ ind ] ( Station * st , TileIndex tile ) {
if ( ! IsTileType ( tile , MP_INDUSTRY ) | | GetIndustryIndex ( tile ) ! = ind - > index ) return false ;
2022-04-25 00:58:24 +02:00
ind - > stations_near . insert ( st ) ;
2022-02-19 19:08:23 +01:00
st - > AddIndustryToDeliver ( ind , tile ) ;
return false ;
2020-05-12 00:36:28 +02:00
} ) ;
2019-02-14 22:07:15 +01:00
}
2010-03-01 20:34:04 +01:00
/**
* Put an industry on the map .
2019-10-04 21:26:44 +02:00
* @ param i Just allocated poolitem , mostly empty .
* @ param tile North tile of the industry .
* @ param type Type of the industry .
* @ param layout Industrylayout to build .
* @ param layout_index Number of the industry layout .
* @ param t Nearest town .
* @ param founder Founder of the industry ; OWNER_NONE in case of random construction .
2010-05-01 15:09:49 +02:00
* @ param initial_random_bits Random bits for the industry .
2010-03-01 20:34:04 +01:00
*/
2023-05-08 19:01:06 +02:00
static void DoCreateNewIndustry ( Industry * i , TileIndex tile , IndustryType type , const IndustryTileLayout & layout , size_t layout_index , Town * t , Owner founder , uint16_t initial_random_bits )
2004-08-09 19:04:08 +02:00
{
2006-04-26 23:10:01 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( type ) ;
2004-08-09 19:04:08 +02:00
2010-01-04 19:21:07 +01:00
i - > location = TileArea ( tile , 1 , 1 ) ;
2004-08-09 19:04:08 +02:00
i - > type = type ;
2010-03-20 15:30:16 +01:00
Industry : : IncIndustryTypeCount ( type ) ;
2004-08-09 19:04:08 +02:00
2023-07-14 12:49:11 +02:00
for ( size_t index = 0 ; index < lengthof ( indspec - > produced_cargo ) ; + + index ) {
if ( ! IsValidCargoID ( indspec - > produced_cargo [ index ] ) ) break ;
Industry : : ProducedCargo & p = i - > produced . emplace_back ( ) ;
p . cargo = indspec - > produced_cargo [ index ] ;
p . rate = indspec - > production_rate [ index ] ;
2023-05-25 22:25:46 +02:00
}
2018-07-25 19:20:17 +02:00
2023-07-14 12:49:11 +02:00
for ( size_t index = 0 ; index < lengthof ( indspec - > accepts_cargo ) ; + + index ) {
if ( ! IsValidCargoID ( indspec - > accepts_cargo [ index ] ) ) break ;
Industry : : AcceptedCargo & a = i - > accepted . emplace_back ( ) ;
a . cargo = indspec - > accepts_cargo [ index ] ;
2023-05-25 22:25:46 +02:00
}
2004-08-09 19:04:08 +02:00
2020-12-14 23:35:07 +01:00
/* Randomize inital production if non-original economy is used and there are no production related callbacks. */
if ( ! indspec - > UsesOriginalEconomy ( ) ) {
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
2024-03-16 23:59:32 +01:00
p . rate = ClampTo < uint8_t > ( ( RandomRange ( 256 ) + 128 ) * p . rate > > 8 ) ;
2018-07-25 19:20:17 +02:00
}
2004-08-09 19:04:08 +02:00
}
i - > town = t ;
2010-03-01 20:34:04 +01:00
i - > owner = OWNER_NONE ;
2004-08-09 19:04:08 +02:00
2023-05-08 19:01:06 +02:00
uint16_t r = Random ( ) ;
2024-01-21 14:23:04 +01:00
i - > random_colour = static_cast < Colours > ( GB ( r , 0 , 4 ) ) ;
2007-11-11 19:22:06 +01:00
i - > counter = GB ( r , 4 , 12 ) ;
2010-05-01 15:09:49 +02:00
i - > random = initial_random_bits ;
2004-08-09 19:04:08 +02:00
i - > was_cargo_delivered = false ;
2024-01-22 15:04:34 +01:00
i - > last_prod_year = TimerGameEconomy : : year ;
2009-02-11 21:09:29 +01:00
i - > founder = founder ;
2020-12-22 14:21:31 +01:00
i - > ctlflags = INDCTL_NONE ;
2007-09-27 23:47:38 +02:00
2023-04-24 17:56:01 +02:00
i - > construction_date = TimerGameCalendar : : date ;
2010-05-30 14:26:32 +02:00
i - > construction_type = ( _game_mode = = GM_EDITOR ) ? ICT_SCENARIO_EDITOR :
( _generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY ) ;
/* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
* 0 = created prior of newindustries
* else , chosen layout + 1 */
2024-03-16 23:59:32 +01:00
i - > selected_layout = ( uint8_t ) ( layout_index + 1 ) ;
2010-05-30 14:26:32 +02:00
2020-12-22 14:29:48 +01:00
i - > exclusive_supplier = INVALID_OWNER ;
i - > exclusive_consumer = INVALID_OWNER ;
2010-05-30 14:26:32 +02:00
i - > prod_level = PRODLEVEL_DEFAULT ;
/* Call callbacks after the regular fields got initialised. */
2012-04-28 18:44:01 +02:00
if ( HasBit ( indspec - > callback_mask , CBM_IND_PROD_CHANGE_BUILD ) ) {
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryCallback ( CBID_INDUSTRY_PROD_CHANGE_BUILD , 0 , Random ( ) , i , type , INVALID_TILE ) ;
2012-04-28 18:44:01 +02:00
if ( res ! = CALLBACK_FAILED ) {
if ( res < PRODLEVEL_MINIMUM | | res > PRODLEVEL_MAXIMUM ) {
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_PROD_CHANGE_BUILD , res ) ;
} else {
i - > prod_level = res ;
i - > RecomputeProductionMultipliers ( ) ;
}
}
}
if ( _generating_world ) {
2019-03-25 20:30:23 +01:00
if ( HasBit ( indspec - > callback_mask , CBM_IND_PRODUCTION_256_TICKS ) ) {
IndustryProductionCallback ( i , 1 ) ;
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
p . history [ LAST_MONTH ] . production = p . waiting * 8 ;
p . waiting = 0 ;
2019-03-25 20:30:23 +01:00
}
}
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
2024-01-30 21:11:46 +01:00
p . history [ LAST_MONTH ] . production + = ScaleByCargoScale ( p . rate * 8 , false ) ;
2018-07-25 19:20:17 +02:00
}
2012-04-28 18:44:01 +02:00
}
2009-09-14 14:22:57 +02:00
if ( HasBit ( indspec - > callback_mask , CBM_IND_DECIDE_COLOUR ) ) {
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryCallback ( CBID_INDUSTRY_DECIDE_COLOUR , 0 , 0 , i , type , INVALID_TILE ) ;
2011-11-08 18:27:13 +01:00
if ( res ! = CALLBACK_FAILED ) {
if ( GB ( res , 4 , 11 ) ! = 0 ) ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_DECIDE_COLOUR , res ) ;
2024-01-21 14:23:04 +01:00
i - > random_colour = static_cast < Colours > ( GB ( res , 0 , 4 ) ) ;
2011-11-08 18:27:13 +01:00
}
2007-09-28 19:09:50 +02:00
}
2009-09-14 14:22:57 +02:00
if ( HasBit ( indspec - > callback_mask , CBM_IND_INPUT_CARGO_TYPES ) ) {
2018-07-26 19:29:54 +02:00
/* Clear all input cargo types */
2023-07-14 12:49:11 +02:00
i - > accepted . clear ( ) ;
2018-07-26 19:29:54 +02:00
/* Query actual types */
2024-04-13 00:07:07 +02:00
uint maxcargoes = ( indspec - > behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED ) ? INDUSTRY_NUM_INPUTS : 3 ;
2018-07-26 19:29:54 +02:00
for ( uint j = 0 ; j < maxcargoes ; j + + ) {
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryCallback ( CBID_INDUSTRY_INPUT_CARGO_TYPES , j , 0 , i , type , INVALID_TILE ) ;
2024-02-04 11:16:08 +01:00
if ( res = = CALLBACK_FAILED | | GB ( res , 0 , 8 ) = = UINT8_MAX ) break ;
2011-11-08 18:27:13 +01:00
if ( indspec - > grf_prop . grffile - > grf_version > = 8 & & res > = 0x100 ) {
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_INPUT_CARGO_TYPES , res ) ;
break ;
}
2018-07-26 19:29:54 +02:00
CargoID cargo = GetCargoTranslation ( GB ( res , 0 , 8 ) , indspec - > grf_prop . grffile ) ;
2019-12-29 14:36:45 +01:00
/* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
* They need to be able to blank out specific slots without aborting the callback sequence ,
* and solve this by returning undefined cargo indexes . Skip these . */
2023-07-14 12:49:11 +02:00
if ( ! IsValidCargoID ( cargo ) & & ! ( indspec - > behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED ) ) {
/* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
Industry : : AcceptedCargo & a = i - > accepted . emplace_back ( ) ;
a . cargo = INVALID_CARGO ;
continue ;
}
2019-12-29 14:36:45 +01:00
/* Verify valid cargo */
2024-04-07 23:01:46 +02:00
if ( std : : find ( std : : begin ( indspec - > accepts_cargo ) , std : : end ( indspec - > accepts_cargo ) , cargo ) = = std : : end ( indspec - > accepts_cargo ) ) {
2018-07-26 19:29:54 +02:00
/* Cargo not in spec, error in NewGRF */
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_INPUT_CARGO_TYPES , res ) ;
break ;
}
2023-05-25 22:25:46 +02:00
if ( std : : any_of ( std : : begin ( i - > accepted ) , std : : begin ( i - > accepted ) + j , [ & cargo ] ( const auto & a ) { return a . cargo = = cargo ; } ) ) {
2018-07-26 19:29:54 +02:00
/* Duplicate cargo */
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_INPUT_CARGO_TYPES , res ) ;
break ;
}
2023-07-14 12:49:11 +02:00
Industry : : AcceptedCargo & a = i - > accepted . emplace_back ( ) ;
a . cargo = cargo ;
2007-09-27 23:47:38 +02:00
}
}
2009-09-14 14:22:57 +02:00
if ( HasBit ( indspec - > callback_mask , CBM_IND_OUTPUT_CARGO_TYPES ) ) {
2018-07-26 19:29:54 +02:00
/* Clear all output cargo types */
2023-07-14 12:49:11 +02:00
i - > produced . clear ( ) ;
2018-07-26 19:29:54 +02:00
/* Query actual types */
2024-04-13 00:07:07 +02:00
uint maxcargoes = ( indspec - > behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED ) ? INDUSTRY_NUM_OUTPUTS : 2 ;
2018-07-26 19:29:54 +02:00
for ( uint j = 0 ; j < maxcargoes ; j + + ) {
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryCallback ( CBID_INDUSTRY_OUTPUT_CARGO_TYPES , j , 0 , i , type , INVALID_TILE ) ;
2024-02-04 11:16:08 +01:00
if ( res = = CALLBACK_FAILED | | GB ( res , 0 , 8 ) = = UINT8_MAX ) break ;
2011-11-08 18:27:13 +01:00
if ( indspec - > grf_prop . grffile - > grf_version > = 8 & & res > = 0x100 ) {
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_OUTPUT_CARGO_TYPES , res ) ;
break ;
}
2018-07-26 19:29:54 +02:00
CargoID cargo = GetCargoTranslation ( GB ( res , 0 , 8 ) , indspec - > grf_prop . grffile ) ;
2019-12-29 14:36:45 +01:00
/* Allow older GRFs to skip slots. */
2023-07-14 12:49:11 +02:00
if ( ! IsValidCargoID ( cargo ) & & ! ( indspec - > behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED ) ) {
/* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
Industry : : ProducedCargo & p = i - > produced . emplace_back ( ) ;
p . cargo = INVALID_CARGO ;
continue ;
}
2019-12-29 14:36:45 +01:00
/* Verify valid cargo */
2024-04-07 23:01:46 +02:00
if ( std : : find ( std : : begin ( indspec - > produced_cargo ) , std : : end ( indspec - > produced_cargo ) , cargo ) = = std : : end ( indspec - > produced_cargo ) ) {
2018-07-26 19:29:54 +02:00
/* Cargo not in spec, error in NewGRF */
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_OUTPUT_CARGO_TYPES , res ) ;
break ;
}
2023-05-25 22:25:46 +02:00
if ( std : : any_of ( std : : begin ( i - > produced ) , std : : begin ( i - > produced ) + j , [ & cargo ] ( const auto & p ) { return p . cargo = = cargo ; } ) ) {
2018-07-26 19:29:54 +02:00
/* Duplicate cargo */
ErrorUnknownCallbackResult ( indspec - > grf_prop . grffile - > grfid , CBID_INDUSTRY_OUTPUT_CARGO_TYPES , res ) ;
break ;
}
2023-07-14 12:49:11 +02:00
Industry : : ProducedCargo & p = i - > produced . emplace_back ( ) ;
p . cargo = cargo ;
2007-09-27 23:47:38 +02:00
}
}
2010-05-30 14:26:32 +02:00
/* Plant the tiles */
2004-08-09 19:04:08 +02:00
2019-10-04 21:26:44 +02:00
for ( const IndustryTileLayoutTile & it : layout ) {
TileIndex cur_tile = tile + ToTileIndexDiff ( it . ti ) ;
2004-08-09 19:04:08 +02:00
2019-10-04 21:26:44 +02:00
if ( it . gfx ! = GFX_WATERTILE_SPECIALCHECK ) {
2010-01-04 19:21:07 +01:00
i - > location . Add ( cur_tile ) ;
2004-08-09 19:04:08 +02:00
2008-07-26 18:14:10 +02:00
WaterClass wc = ( IsWaterTile ( cur_tile ) ? GetWaterClass ( cur_tile ) : WATER_CLASS_INVALID ) ;
2021-11-21 23:02:29 +01:00
Command < CMD_LANDSCAPE_CLEAR > : : Do ( DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING , cur_tile ) ;
2004-08-09 19:04:08 +02:00
2019-10-04 21:26:44 +02:00
MakeIndustry ( cur_tile , i - > index , it . gfx , Random ( ) , wc ) ;
2007-11-11 01:53:59 +01:00
2006-12-30 12:51:37 +01:00
if ( _generating_world ) {
SetIndustryConstructionCounter ( cur_tile , 3 ) ;
SetIndustryConstructionStage ( cur_tile , 2 ) ;
2007-11-11 19:22:06 +01:00
}
2008-01-16 16:06:48 +01:00
/* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
2019-10-04 21:26:44 +02:00
IndustryGfx cur_gfx = GetTranslatedIndustryTileID ( it . gfx ) ;
2008-01-16 16:06:48 +01:00
const IndustryTileSpec * its = GetIndustryTileSpec ( cur_gfx ) ;
2010-08-26 17:31:40 +02:00
if ( its - > animation . status ! = ANIM_STATUS_NO_ANIMATION ) AddAnimatedTile ( cur_tile ) ;
2004-08-09 19:04:08 +02:00
}
2019-10-04 21:26:44 +02:00
}
2004-08-09 19:04:08 +02:00
2007-03-28 22:06:28 +02:00
if ( GetIndustrySpec ( i - > type ) - > behaviour & INDUSTRYBEH_PLANT_ON_BUILT ) {
2010-03-01 20:34:04 +01:00
for ( uint j = 0 ; j ! = 50 ; j + + ) PlantRandomFarmField ( i ) ;
2004-08-09 19:04:08 +02:00
}
2020-01-06 21:31:57 +01:00
InvalidateWindowData ( WC_INDUSTRY_DIRECTORY , 0 , IDIWD_FORCE_REBUILD ) ;
2023-05-11 02:15:21 +02:00
SetWindowDirty ( WC_BUILD_INDUSTRY , 0 ) ;
2009-06-25 17:42:03 +02:00
2019-02-14 22:07:15 +01:00
if ( ! _generating_world ) PopulateStationsNearby ( i ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Helper function for Build / Fund an industry
2007-03-03 05:04:22 +01:00
* @ param tile tile where industry is built
* @ param type of industry to build
* @ param flags of operations to conduct
* @ param indspec pointer to industry specifications
2019-10-04 21:26:44 +02:00
* @ param layout_index the index of the itsepc to build / fund
2018-10-28 03:17:36 +01:00
* @ param random_var8f random seed ( possibly ) used by industries
* @ param random_initial_bits The random bits the industry is going to have after construction .
2009-02-11 21:09:29 +01:00
* @ param founder Founder of the industry
2010-10-16 15:15:54 +02:00
* @ param creation_type The circumstances the industry is created under .
2018-10-28 03:17:36 +01:00
* @ param [ out ] ip Pointer to store newly created industry .
2010-02-27 13:12:01 +01:00
* @ return Succeeded or failed command .
*
2019-04-10 23:07:06 +02:00
* @ post \ c * ip contains the newly created industry if all checks are successful and the \ a flags request actual creation , else it contains \ c nullptr afterwards .
2007-03-03 05:04:22 +01:00
*/
2023-05-08 19:01:06 +02:00
static CommandCost CreateNewIndustryHelper ( TileIndex tile , IndustryType type , DoCommandFlag flags , const IndustrySpec * indspec , size_t layout_index , uint32_t random_var8f , uint16_t random_initial_bits , Owner founder , IndustryAvailabilityCallType creation_type , Industry * * ip )
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
{
2019-10-04 21:26:44 +02:00
assert ( layout_index < indspec - > layouts . size ( ) ) ;
const IndustryTileLayout & layout = indspec - > layouts [ layout_index ] ;
2007-07-09 20:53:43 +02:00
2019-04-10 23:07:06 +02:00
* ip = nullptr ;
2010-02-27 13:12:01 +01:00
2022-09-01 18:13:43 +02:00
/* 1. Cheap: Built-in checks on industry level. */
CommandCost ret = CheckIfFarEnoughFromConflictingIndustry ( tile , type ) ;
if ( ret . Failed ( ) ) return ret ;
Town * t = nullptr ;
ret = FindTownForIndustry ( tile , type , & t ) ;
if ( ret . Failed ( ) ) return ret ;
assert ( t ! = nullptr ) ;
ret = CheckIfIndustryIsAllowed ( tile , type , t ) ;
if ( ret . Failed ( ) ) return ret ;
/* 2. Built-in checks on industry tiles. */
2019-03-03 18:30:09 +01:00
std : : vector < ClearedObjectArea > object_areas ( _cleared_object_areas ) ;
2022-09-01 18:13:43 +02:00
ret = CheckIfIndustryTilesAreFree ( tile , layout , type ) ;
2010-09-04 02:16:33 +02:00
_cleared_object_areas = object_areas ;
2010-02-27 13:12:01 +01:00
if ( ret . Failed ( ) ) return ret ;
2007-07-09 20:53:43 +02:00
2022-09-01 18:13:43 +02:00
/* 3. NewGRF-defined checks on industry level. */
2009-09-14 14:22:57 +02:00
if ( HasBit ( GetIndustrySpec ( type ) - > callback_mask , CBM_IND_LOCATION ) ) {
2019-10-04 21:26:44 +02:00
ret = CheckIfCallBackAllowsCreation ( tile , type , layout_index , random_var8f , random_initial_bits , founder , creation_type ) ;
2007-07-09 20:53:43 +02:00
} else {
2010-02-21 16:27:11 +01:00
ret = _check_new_industry_procs [ indspec - > check_proc ] ( tile ) ;
2007-07-09 15:21:49 +02:00
}
2010-02-27 13:12:01 +01:00
if ( ret . Failed ( ) ) return ret ;
2022-09-01 18:13:43 +02:00
/* 4. Expensive: NewGRF-defined checks on industry tiles. */
bool custom_shape_check = false ;
ret = CheckIfIndustryTileSlopes ( tile , layout , layout_index , type , random_initial_bits , founder , creation_type , & custom_shape_check ) ;
if ( ret . Failed ( ) ) return ret ;
2010-02-27 13:12:01 +01:00
if ( ! custom_shape_check & & _settings_game . game_creation . land_generator = = LG_TERRAGENESIS & & _generating_world & &
2023-09-16 23:27:16 +02:00
! _ignore_restrictions & & ! CheckIfCanLevelIndustryPlatform ( tile , DC_NO_WATER , layout ) ) {
2010-02-27 13:12:01 +01:00
return_cmd_error ( STR_ERROR_SITE_UNSUITABLE ) ;
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2010-02-27 13:12:01 +01:00
if ( ! Industry : : CanAllocateItem ( ) ) return_cmd_error ( STR_ERROR_TOO_MANY_INDUSTRIES ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
if ( flags & DC_EXEC ) {
2010-02-27 13:12:01 +01:00
* ip = new Industry ( tile ) ;
2023-09-16 23:27:16 +02:00
if ( ! custom_shape_check ) CheckIfCanLevelIndustryPlatform ( tile , DC_NO_WATER | DC_EXEC , layout ) ;
2019-10-04 21:26:44 +02:00
DoCreateNewIndustry ( * ip , tile , type , layout , layout_index , t , founder , random_initial_bits ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2010-02-27 13:12:01 +01:00
return CommandCost ( ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Build / Fund an industry
2007-03-03 05:04:22 +01:00
* @ param flags of operations to conduct
2021-10-10 02:08:52 +02:00
* @ param tile tile where industry is built
2021-11-21 23:03:44 +01:00
* @ param it industry type see build_industry . h and see industry . h
* @ param first_layout first layout to try
* @ param fund false = prospect , true = fund ( only valid if current company is DEITY )
* @ param seed seed to use for desyncfree randomisations
2009-09-18 16:23:58 +02:00
* @ return the cost of this operation or an error
2005-05-11 02:00:27 +02:00
*/
2023-05-08 19:01:06 +02:00
CommandCost CmdBuildIndustry ( DoCommandFlag flags , TileIndex tile , IndustryType it , uint32_t first_layout , bool fund , uint32_t seed )
2004-08-09 19:04:08 +02:00
{
2009-09-04 22:02:35 +02:00
if ( it > = NUM_INDUSTRYTYPES ) return CMD_ERROR ;
const IndustrySpec * indspec = GetIndustrySpec ( it ) ;
2005-11-14 20:48:04 +01:00
2006-10-27 17:54:24 +02:00
/* Check if the to-be built/founded industry is available for this climate. */
2019-10-04 21:26:44 +02:00
if ( ! indspec - > enabled | | indspec - > layouts . empty ( ) ) return CMD_ERROR ;
2004-08-09 19:04:08 +02:00
2009-02-08 13:25:13 +01:00
/* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2007-07-07 00:33:16 +02:00
* Raw material industries are industries that do not accept cargo ( at least for now ) */
2012-10-22 20:56:21 +02:00
if ( _game_mode ! = GM_EDITOR & & _current_company ! = OWNER_DEITY & & _settings_game . construction . raw_industry_construction = = 0 & & indspec - > IsRawIndustry ( ) ) {
2005-11-14 16:22:12 +01:00
return CMD_ERROR ;
}
2004-08-09 19:04:08 +02:00
2012-10-22 20:56:21 +02:00
if ( _game_mode ! = GM_EDITOR & & GetIndustryProbabilityCallback ( it , _current_company = = OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION , 1 ) = = 0 ) {
2010-04-23 23:47:03 +02:00
return CMD_ERROR ;
}
2010-05-01 15:09:49 +02:00
Randomizer randomizer ;
2021-11-21 23:03:44 +01:00
randomizer . SetSeed ( seed ) ;
2023-05-08 19:01:06 +02:00
uint16_t random_initial_bits = GB ( seed , 0 , 16 ) ;
uint32_t random_var8f = randomizer . Next ( ) ;
2019-10-04 21:26:44 +02:00
size_t num_layouts = indspec - > layouts . size ( ) ;
2011-02-07 21:47:58 +01:00
CommandCost ret = CommandCost ( STR_ERROR_SITE_UNSUITABLE ) ;
2021-11-21 23:03:44 +01:00
const bool deity_prospect = _current_company = = OWNER_DEITY & & ! fund ;
2010-05-01 15:09:49 +02:00
2019-04-10 23:07:06 +02:00
Industry * ind = nullptr ;
2012-10-22 20:56:21 +02:00
if ( deity_prospect | | ( _game_mode ! = GM_EDITOR & & _current_company ! = OWNER_DEITY & & _settings_game . construction . raw_industry_construction = = 2 & & indspec - > IsRawIndustry ( ) ) ) {
2007-07-06 09:24:10 +02:00
if ( flags & DC_EXEC ) {
/* Prospecting has a chance to fail, however we cannot guarantee that something can
* be built on the map , so the chance gets lower when the map is fuller , but there
* is nothing we can really do about that . */
2022-12-25 23:12:06 +01:00
bool prospect_success = deity_prospect | | Random ( ) < = indspec - > prospecting_chance ;
if ( prospect_success ) {
/* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2023-01-17 23:33:03 +01:00
IndustryAvailabilityCallType calltype = _current_company = = OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION ;
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_TOWN ) ;
2007-07-06 09:24:10 +02:00
for ( int i = 0 ; i < 5000 ; i + + ) {
2007-12-28 17:21:29 +01:00
/* We should not have more than one Random() in a function call
* because parameter evaluation order is not guaranteed in the c + + standard
*/
tile = RandomTile ( ) ;
2011-02-07 21:47:58 +01:00
/* Start with a random layout */
2023-05-08 19:01:06 +02:00
size_t layout = RandomRange ( ( uint32_t ) num_layouts ) ;
2011-02-07 21:47:58 +01:00
/* Check now each layout, starting with the random one */
2019-10-26 01:34:19 +02:00
for ( size_t j = 0 ; j < num_layouts ; j + + ) {
2011-02-07 21:47:58 +01:00
layout = ( layout + 1 ) % num_layouts ;
2023-01-17 23:33:03 +01:00
ret = CreateNewIndustryHelper ( tile , it , flags , indspec , layout , random_var8f , random_initial_bits , cur_company . GetOriginalValue ( ) , calltype , & ind ) ;
2011-02-07 21:47:58 +01:00
if ( ret . Succeeded ( ) ) break ;
}
2010-02-27 13:12:01 +01:00
if ( ret . Succeeded ( ) ) break ;
2007-07-06 09:24:10 +02:00
}
2022-12-25 23:12:06 +01:00
cur_company . Restore ( ) ;
}
2023-01-12 20:03:39 +01:00
if ( ret . Failed ( ) & & IsLocalCompany ( ) ) {
2022-12-25 23:12:06 +01:00
if ( prospect_success ) {
ShowErrorMessage ( STR_ERROR_CAN_T_PROSPECT_INDUSTRY , STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING , WL_INFO ) ;
} else {
ShowErrorMessage ( STR_ERROR_CAN_T_PROSPECT_INDUSTRY , STR_ERROR_PROSPECTING_WAS_UNLUCKY , WL_INFO ) ;
}
2007-07-06 09:24:10 +02:00
}
}
} else {
2021-11-21 23:03:44 +01:00
size_t layout = first_layout ;
2011-02-07 21:47:06 +01:00
if ( layout > = num_layouts ) return CMD_ERROR ;
2007-07-06 09:24:10 +02:00
2011-02-07 21:47:06 +01:00
/* Check subsequently each layout, starting with the given layout in p1 */
2019-10-26 01:34:19 +02:00
for ( size_t i = 0 ; i < num_layouts ; i + + ) {
2011-02-07 21:47:06 +01:00
layout = ( layout + 1 ) % num_layouts ;
2012-10-22 20:56:21 +02:00
ret = CreateNewIndustryHelper ( tile , it , flags , indspec , layout , random_var8f , random_initial_bits , _current_company , _current_company = = OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION , & ind ) ;
2011-02-07 21:47:06 +01:00
if ( ret . Succeeded ( ) ) break ;
}
2004-08-09 19:04:08 +02:00
2011-02-07 21:47:06 +01:00
/* If it still failed, there's no suitable layout to build here, return the error */
2010-02-27 13:12:01 +01:00
if ( ret . Failed ( ) ) return ret ;
2008-07-29 01:37:19 +02:00
}
2019-04-10 23:07:06 +02:00
if ( ( flags & DC_EXEC ) & & ind ! = nullptr & & _game_mode ! = GM_EDITOR ) {
2012-04-28 18:07:28 +02:00
AdvertiseIndustryOpening ( ind ) ;
2007-07-06 09:24:10 +02:00
}
2004-09-11 11:55:19 +02:00
2008-01-09 17:55:48 +01:00
return CommandCost ( EXPENSES_OTHER , indspec - > GetConstructionCost ( ) ) ;
2004-08-09 19:04:08 +02:00
}
2020-12-22 14:21:31 +01:00
/**
2023-02-14 11:29:11 +01:00
* Set industry control flags .
* @ param flags Type of operation .
* @ param ind_id IndustryID
* @ param ctlflags IndustryControlFlags
* @ return Empty cost or an error .
*/
CommandCost CmdIndustrySetFlags ( DoCommandFlag flags , IndustryID ind_id , IndustryControlFlags ctlflags )
{
if ( _current_company ! = OWNER_DEITY ) return CMD_ERROR ;
Industry * ind = Industry : : GetIfValid ( ind_id ) ;
if ( ind = = nullptr ) return CMD_ERROR ;
if ( flags & DC_EXEC ) ind - > ctlflags = ctlflags & INDCTL_MASK ;
return CommandCost ( ) ;
}
2023-07-16 21:34:42 +02:00
/**
* Set industry production .
* @ param flags Type of operation .
* @ param ind_id IndustryID
* @ param prod_level Production level .
* @ param show_news Show a news message on production change .
2023-08-06 16:05:04 +02:00
* @ param custom_news Custom news message text .
2023-07-16 21:34:42 +02:00
* @ return Empty cost or an error .
*/
2024-03-16 23:59:32 +01:00
CommandCost CmdIndustrySetProduction ( DoCommandFlag flags , IndustryID ind_id , uint8_t prod_level , bool show_news , const std : : string & custom_news )
2023-07-16 21:34:42 +02:00
{
if ( _current_company ! = OWNER_DEITY ) return CMD_ERROR ;
if ( prod_level < PRODLEVEL_MINIMUM | | prod_level > PRODLEVEL_MAXIMUM ) return CMD_ERROR ;
Industry * ind = Industry : : GetIfValid ( ind_id ) ;
if ( ind = = nullptr ) return CMD_ERROR ;
if ( flags & DC_EXEC ) {
StringID str = STR_NULL ;
if ( prod_level > ind - > prod_level ) {
str = GetIndustrySpec ( ind - > type ) - > production_up_text ;
} else if ( prod_level < ind - > prod_level ) {
str = GetIndustrySpec ( ind - > type ) - > production_down_text ;
}
2023-08-06 16:05:04 +02:00
if ( prod_level ! = ind - > prod_level & & ! custom_news . empty ( ) ) str = STR_NEWS_CUSTOM_ITEM ;
2023-07-16 21:34:42 +02:00
ind - > ctlflags | = INDCTL_EXTERNAL_PROD_LEVEL ;
ind - > prod_level = prod_level ;
ind - > RecomputeProductionMultipliers ( ) ;
/* Show news message if requested. */
if ( show_news & & str ! = STR_NULL ) {
NewsType nt ;
switch ( WhoCanServiceIndustry ( ind ) ) {
case 0 : nt = NT_INDUSTRY_NOBODY ; break ;
case 1 : nt = NT_INDUSTRY_OTHER ; break ;
case 2 : nt = NT_INDUSTRY_COMPANY ; break ;
default : NOT_REACHED ( ) ;
}
/* Set parameters of news string */
2023-08-06 16:05:04 +02:00
NewsAllocatedData * data = nullptr ;
if ( str = = STR_NEWS_CUSTOM_ITEM ) {
NewsStringData * news = new NewsStringData ( custom_news ) ;
SetDParamStr ( 0 , news - > string ) ;
} else if ( str > STR_LAST_STRINGID ) {
2023-07-16 21:34:42 +02:00
SetDParam ( 0 , STR_TOWN_NAME ) ;
SetDParam ( 1 , ind - > town - > index ) ;
SetDParam ( 2 , GetIndustrySpec ( ind - > type ) - > name ) ;
} else {
SetDParam ( 0 , ind - > index ) ;
}
2023-08-06 16:05:04 +02:00
AddIndustryNewsItem ( str , nt , ind - > index , data ) ;
2023-07-16 21:34:42 +02:00
}
}
return CommandCost ( ) ;
}
2023-02-14 11:29:11 +01:00
/**
* Change exclusive consumer or supplier for the industry .
2020-12-22 14:21:31 +01:00
* @ param flags Type of operation .
2021-11-21 23:03:44 +01:00
* @ param ind_id IndustryID
* @ param company_id CompanyID to set or INVALID_OWNER ( available to everyone ) or
* OWNER_NONE ( neutral stations only ) or OWNER_DEITY ( no one )
2023-02-14 11:29:11 +01:00
* @ param consumer Set exclusive consumer if true , supplier if false .
2020-12-22 14:21:31 +01:00
* @ return Empty cost or an error .
*/
2023-02-14 11:29:11 +01:00
CommandCost CmdIndustrySetExclusivity ( DoCommandFlag flags , IndustryID ind_id , Owner company_id , bool consumer )
2020-12-22 14:21:31 +01:00
{
if ( _current_company ! = OWNER_DEITY ) return CMD_ERROR ;
2021-11-21 23:03:44 +01:00
Industry * ind = Industry : : GetIfValid ( ind_id ) ;
2020-12-22 14:21:31 +01:00
if ( ind = = nullptr ) return CMD_ERROR ;
2023-02-14 11:29:11 +01:00
if ( company_id ! = OWNER_NONE & & company_id ! = INVALID_OWNER & & company_id ! = OWNER_DEITY
& & ! Company : : IsValidID ( company_id ) ) return CMD_ERROR ;
2020-12-22 14:21:31 +01:00
2023-02-14 11:29:11 +01:00
if ( flags & DC_EXEC ) {
if ( consumer ) {
ind - > exclusive_consumer = company_id ;
} else {
ind - > exclusive_supplier = company_id ;
2020-12-22 14:21:31 +01:00
}
2023-02-14 11:29:11 +01:00
}
2020-12-22 14:21:31 +01:00
2020-12-22 14:29:48 +01:00
2023-02-14 11:29:11 +01:00
return CommandCost ( ) ;
}
2020-12-22 14:29:48 +01:00
2023-02-14 11:29:11 +01:00
/**
* Change additional industry text .
* @ param flags Type of operation .
* @ param ind_id IndustryID
* @ param text - Additional industry text .
* @ return Empty cost or an error .
*/
CommandCost CmdIndustrySetText ( DoCommandFlag flags , IndustryID ind_id , const std : : string & text )
{
if ( _current_company ! = OWNER_DEITY ) return CMD_ERROR ;
2020-12-22 14:29:48 +01:00
2023-02-14 11:29:11 +01:00
Industry * ind = Industry : : GetIfValid ( ind_id ) ;
if ( ind = = nullptr ) return CMD_ERROR ;
2021-01-15 15:38:14 +01:00
2023-02-14 11:29:11 +01:00
if ( flags & DC_EXEC ) {
ind - > text . clear ( ) ;
if ( ! text . empty ( ) ) ind - > text = text ;
InvalidateWindowData ( WC_INDUSTRY_VIEW , ind - > index ) ;
2020-12-22 14:21:31 +01:00
}
return CommandCost ( ) ;
}
2004-08-09 19:04:08 +02:00
2010-10-16 15:15:54 +02:00
/**
* Create a new industry of random layout .
* @ param tile The location to build the industry .
* @ param type The industry type to build .
* @ param creation_type The circumstances the industry is created under .
2019-04-10 23:07:06 +02:00
* @ return the created industry or nullptr if it failed .
2010-10-16 15:15:54 +02:00
*/
static Industry * CreateNewIndustry ( TileIndex tile , IndustryType type , IndustryAvailabilityCallType creation_type )
2004-08-09 19:04:08 +02:00
{
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( type ) ;
2004-09-11 11:55:19 +02:00
2023-05-08 19:01:06 +02:00
uint32_t seed = Random ( ) ;
uint32_t seed2 = Random ( ) ;
2019-04-10 23:07:06 +02:00
Industry * i = nullptr ;
2023-05-08 19:01:06 +02:00
size_t layout_index = RandomRange ( ( uint32_t ) indspec - > layouts . size ( ) ) ;
2021-06-03 16:55:08 +02:00
[[maybe_unused]] CommandCost ret = CreateNewIndustryHelper ( tile , type , DC_EXEC , indspec , layout_index , seed , GB ( seed2 , 0 , 16 ) , OWNER_NONE , creation_type , & i ) ;
2019-04-10 23:07:06 +02:00
assert ( i ! = nullptr | | ret . Failed ( ) ) ;
2010-02-27 13:12:01 +01:00
return i ;
2004-08-09 19:04:08 +02:00
}
2010-02-13 15:06:01 +01:00
/**
* Compute the appearance probability for an industry during map creation .
2010-09-04 13:16:40 +02:00
* @ param it Industry type to compute .
2018-10-28 03:17:36 +01:00
* @ param [ out ] force_at_least_one Returns whether at least one instance should be forced on map creation .
2010-09-04 13:16:40 +02:00
* @ return Relative probability for the industry to appear .
2010-02-13 15:06:01 +01:00
*/
2023-05-08 19:01:06 +02:00
static uint32_t GetScaledIndustryGenerationProbability ( IndustryType it , bool * force_at_least_one )
2010-02-13 15:06:01 +01:00
{
const IndustrySpec * ind_spc = GetIndustrySpec ( it ) ;
2023-05-08 19:01:06 +02:00
uint32_t chance = ind_spc - > appear_creation [ _settings_game . game_creation . landscape ] ;
2019-10-04 21:26:44 +02:00
if ( ! ind_spc - > enabled | | ind_spc - > layouts . empty ( ) | |
2011-11-08 18:26:13 +01:00
( _game_mode ! = GM_EDITOR & & _settings_game . difficulty . industry_density = = ID_FUND_ONLY ) | |
( chance = GetIndustryProbabilityCallback ( it , IACT_MAPGENERATION , chance ) ) = = 0 ) {
2010-02-13 15:06:01 +01:00
* force_at_least_one = false ;
return 0 ;
} else {
2020-09-20 22:30:04 +02:00
chance * = 16 ; // to increase precision
2010-02-13 15:06:01 +01:00
/* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
* For simplicity we scale in both cases , though scaling the probabilities of all industries has no effect . */
2023-01-21 10:43:03 +01:00
chance = ( ind_spc - > check_proc = = CHECK_REFINERY | | ind_spc - > check_proc = = CHECK_OIL_RIG ) ? Map : : ScaleBySize1D ( chance ) : Map : : ScaleBySize ( chance ) ;
2010-02-13 15:06:01 +01:00
2010-09-01 21:04:06 +02:00
* force_at_least_one = ( chance > 0 ) & & ! ( ind_spc - > behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION ) & & ( _game_mode ! = GM_EDITOR ) ;
2010-02-13 15:06:01 +01:00
return chance ;
}
}
2007-07-27 05:07:05 +02:00
2010-09-04 13:29:42 +02:00
/**
* Compute the probability for constructing a new industry during game play .
* @ param it Industry type to compute .
2018-10-28 03:17:36 +01:00
* @ param [ out ] min_number Minimal number of industries that should exist at the map .
2010-09-04 13:29:42 +02:00
* @ return Relative probability for the industry to appear .
*/
2024-03-16 23:59:32 +01:00
static uint16_t GetIndustryGamePlayProbability ( IndustryType it , uint8_t * min_number )
2010-09-04 13:29:42 +02:00
{
2011-02-06 19:26:50 +01:00
if ( _settings_game . difficulty . industry_density = = ID_FUND_ONLY ) {
2010-11-13 16:21:55 +01:00
* min_number = 0 ;
return 0 ;
}
2010-11-13 16:04:58 +01:00
2010-09-04 13:29:42 +02:00
const IndustrySpec * ind_spc = GetIndustrySpec ( it ) ;
2024-03-16 23:59:32 +01:00
uint8_t chance = ind_spc - > appear_ingame [ _settings_game . game_creation . landscape ] ;
2019-10-04 21:26:44 +02:00
if ( ! ind_spc - > enabled | | ind_spc - > layouts . empty ( ) | |
2023-04-24 17:56:01 +02:00
( ( ind_spc - > behaviour & INDUSTRYBEH_BEFORE_1950 ) & & TimerGameCalendar : : year > 1950 ) | |
( ( ind_spc - > behaviour & INDUSTRYBEH_AFTER_1960 ) & & TimerGameCalendar : : year < 1960 ) | |
2011-11-08 18:26:13 +01:00
( chance = GetIndustryProbabilityCallback ( it , IACT_RANDOMCREATION , chance ) ) = = 0 ) {
2010-11-13 16:21:55 +01:00
* min_number = 0 ;
2010-09-04 13:29:42 +02:00
return 0 ;
}
2010-11-13 16:21:55 +01:00
* min_number = ( ind_spc - > behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE ) ? 1 : 0 ;
2010-09-04 13:29:42 +02:00
return chance ;
}
2010-09-04 14:09:12 +02:00
/**
* Get wanted number of industries on the map .
* @ return Wanted number of industries at the map .
*/
static uint GetNumberOfIndustries ( )
{
/* Number of industries on a 256x256 map. */
2023-05-08 19:01:06 +02:00
static const uint16_t numof_industry_table [ ] = {
2010-09-04 14:09:12 +02:00
0 , // none
2011-02-05 11:28:31 +01:00
0 , // minimal
2010-09-04 14:09:12 +02:00
10 , // very low
25 , // low
55 , // normal
80 , // high
2023-01-14 11:12:29 +01:00
0 , // custom
2010-09-04 14:09:12 +02:00
} ;
2011-02-06 19:11:39 +01:00
assert ( lengthof ( numof_industry_table ) = = ID_END ) ;
2011-02-06 19:26:50 +01:00
uint difficulty = ( _game_mode ! = GM_EDITOR ) ? _settings_game . difficulty . industry_density : ( uint ) ID_VERY_LOW ;
2023-01-14 11:12:29 +01:00
if ( difficulty = = ID_CUSTOM ) return std : : min < uint > ( IndustryPool : : MAX_SIZE , _settings_game . game_creation . custom_industry_number ) ;
2023-01-21 10:43:03 +01:00
return std : : min < uint > ( IndustryPool : : MAX_SIZE , Map : : ScaleBySize ( numof_industry_table [ difficulty ] ) ) ;
2010-09-04 14:09:12 +02:00
}
2004-08-09 19:04:08 +02:00
2010-09-04 13:59:12 +02:00
/**
* Try to place the industry in the game .
* Since there is no feedback why placement fails , there is no other option
* than to try a few times before concluding it does not work .
* @ param type Industry type of the desired industry .
* @ param try_hard Try very hard to find a place . ( Used to place at least one industry per type . )
2019-04-10 23:07:06 +02:00
* @ return Pointer to created industry , or \ c nullptr if creation failed .
2010-09-04 13:59:12 +02:00
*/
2010-10-16 15:15:54 +02:00
static Industry * PlaceIndustry ( IndustryType type , IndustryAvailabilityCallType creation_type , bool try_hard )
2010-09-04 13:59:12 +02:00
{
uint tries = try_hard ? 10000u : 2000u ;
for ( ; tries > 0 ; tries - - ) {
2010-10-16 15:15:54 +02:00
Industry * ind = CreateNewIndustry ( RandomTile ( ) , type , creation_type ) ;
2019-04-10 23:07:06 +02:00
if ( ind ! = nullptr ) return ind ;
2010-09-04 13:59:12 +02:00
}
2019-04-10 23:07:06 +02:00
return nullptr ;
2010-09-04 13:59:12 +02:00
}
2010-02-13 15:06:01 +01:00
/**
* Try to build a industry on the map .
2007-04-09 03:43:29 +02:00
* @ param type IndustryType of the desired industry
2010-02-13 15:06:01 +01:00
* @ param try_hard Try very hard to find a place . ( Used to place at least one industry per type )
*/
static void PlaceInitialIndustry ( IndustryType type , bool try_hard )
2004-08-09 19:04:08 +02:00
{
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_NONE ) ;
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2010-02-13 15:06:01 +01:00
IncreaseGeneratingWorldProgress ( GWP_INDUSTRY ) ;
2010-10-16 15:15:54 +02:00
PlaceIndustry ( type , IACT_MAPGENERATION , try_hard ) ;
2010-02-06 21:19:59 +01:00
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-11-13 16:17:55 +01:00
/**
* Get total number of industries existing in the game .
* @ return Number of industries currently in the game .
*/
static uint GetCurrentTotalNumberOfIndustries ( )
{
int total = 0 ;
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) total + = Industry : : GetIndustryTypeCount ( it ) ;
return total ;
}
2010-11-13 16:15:25 +01:00
/** Reset the entry. */
void IndustryTypeBuildData : : Reset ( )
{
this - > probability = 0 ;
2010-11-13 16:21:55 +01:00
this - > min_number = 0 ;
2010-11-13 16:15:25 +01:00
this - > target_count = 0 ;
2010-11-13 16:20:57 +01:00
this - > max_wait = 1 ;
this - > wait_count = 0 ;
2010-11-13 16:15:25 +01:00
}
/** Completely reset the industry build data. */
void IndustryBuildData : : Reset ( )
{
2010-11-13 16:17:55 +01:00
this - > wanted_inds = GetCurrentTotalNumberOfIndustries ( ) < < 16 ;
2010-11-13 16:15:25 +01:00
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
this - > builddata [ it ] . Reset ( ) ;
}
}
2010-11-13 16:17:55 +01:00
/** Monthly update of industry build data. */
2024-01-22 15:04:34 +01:00
void IndustryBuildData : : EconomyMonthlyLoop ( )
2010-11-13 16:17:55 +01:00
{
static const int NEWINDS_PER_MONTH = 0x38000 / ( 10 * 12 ) ; // lower 16 bits is a float fraction, 3.5 industries per decade, divided by 10 * 12 months.
2012-01-01 18:22:32 +01:00
if ( _settings_game . difficulty . industry_density = = ID_FUND_ONLY ) return ; // 'no industries' setting.
2010-11-13 16:17:55 +01:00
/* To prevent running out of unused industries for the player to connect,
* add a fraction of new industries each month , but only if the manager can keep up . */
2023-01-21 10:43:03 +01:00
uint max_behind = 1 + std : : min ( 99u , Map : : ScaleBySize ( 3 ) ) ; // At most 2 industries for small maps, and 100 at the biggest map (about 6 months industry build attempts).
2010-11-13 16:17:55 +01:00
if ( GetCurrentTotalNumberOfIndustries ( ) + max_behind > = ( this - > wanted_inds > > 16 ) ) {
2023-01-21 10:43:03 +01:00
this - > wanted_inds + = Map : : ScaleBySize ( NEWINDS_PER_MONTH ) ;
2010-11-13 16:17:55 +01:00
}
}
2010-02-13 15:06:01 +01:00
/**
* This function will create random industries during game creation .
* It will scale the amount of industries by mapsize and difficulty level .
*/
2007-03-07 12:47:46 +01:00
void GenerateIndustries ( )
2004-08-09 19:04:08 +02:00
{
2011-02-06 19:26:50 +01:00
if ( _game_mode ! = GM_EDITOR & & _settings_game . difficulty . industry_density = = ID_FUND_ONLY ) return ; // No industries in the game.
2010-02-13 15:06:01 +01:00
2023-05-08 19:01:06 +02:00
uint32_t industry_probs [ NUM_INDUSTRYTYPES ] ;
2010-02-13 15:06:01 +01:00
bool force_at_least_one [ NUM_INDUSTRYTYPES ] ;
2023-05-08 19:01:06 +02:00
uint32_t total_prob = 0 ;
2010-02-13 15:06:01 +01:00
uint num_forced = 0 ;
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
2010-09-04 13:16:40 +02:00
industry_probs [ it ] = GetScaledIndustryGenerationProbability ( it , force_at_least_one + it ) ;
2010-02-13 15:06:01 +01:00
total_prob + = industry_probs [ it ] ;
if ( force_at_least_one [ it ] ) num_forced + + ;
}
2011-02-05 11:28:31 +01:00
uint total_amount = GetNumberOfIndustries ( ) ;
2010-02-13 15:06:01 +01:00
if ( total_prob = = 0 | | total_amount < num_forced ) {
/* Only place the forced ones */
total_amount = num_forced ;
2007-04-09 03:43:29 +02:00
}
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
2010-02-06 21:50:50 +01:00
SetGeneratingWorldProgress ( GWP_INDUSTRY , total_amount ) ;
2004-08-09 19:04:08 +02:00
2010-02-13 15:06:01 +01:00
/* Try to build one industry per type independent of any probabilities */
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
if ( force_at_least_one [ it ] ) {
assert ( total_amount > 0 ) ;
total_amount - - ;
PlaceInitialIndustry ( it , true ) ;
}
}
/* Add the remaining industries according to their probabilities */
for ( uint i = 0 ; i < total_amount ; i + + ) {
2023-05-08 19:01:06 +02:00
uint32_t r = RandomRange ( total_prob ) ;
2010-02-13 15:06:01 +01:00
IndustryType it = 0 ;
2010-11-13 11:11:47 +01:00
while ( r > = industry_probs [ it ] ) {
2010-02-13 15:06:01 +01:00
r - = industry_probs [ it ] ;
it + + ;
2010-11-13 11:11:47 +01:00
assert ( it < NUM_INDUSTRYTYPES ) ;
2007-05-30 03:55:11 +02:00
}
2010-11-13 11:11:47 +01:00
assert ( industry_probs [ it ] > 0 ) ;
2010-02-13 15:06:01 +01:00
PlaceInitialIndustry ( it , false ) ;
2007-07-15 02:26:12 +02:00
}
2010-11-13 16:15:25 +01:00
_industry_builder . Reset ( ) ;
2004-08-09 19:04:08 +02:00
}
2010-08-01 19:45:53 +02:00
/**
* Monthly update of industry statistics .
* @ param i Industry to update .
*/
2004-08-09 19:04:08 +02:00
static void UpdateIndustryStatistics ( Industry * i )
{
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
if ( IsValidCargoID ( p . cargo ) ) {
2024-01-22 15:04:34 +01:00
if ( p . history [ THIS_MONTH ] . production ! = 0 ) i - > last_prod_year = TimerGameEconomy : : year ;
2004-08-09 19:04:08 +02:00
2023-05-25 22:25:46 +02:00
/* Move history from this month to last month. */
std : : rotate ( std : : rbegin ( p . history ) , std : : rbegin ( p . history ) + 1 , std : : rend ( p . history ) ) ;
p . history [ THIS_MONTH ] . production = 0 ;
p . history [ THIS_MONTH ] . transported = 0 ;
2004-09-11 11:55:19 +02:00
}
2004-08-09 19:04:08 +02:00
}
}
2010-10-04 21:23:50 +02:00
/**
* Recompute # production_rate for current # prod_level .
* This function is only valid when not using smooth economy .
*/
void Industry : : RecomputeProductionMultipliers ( )
{
const IndustrySpec * indspec = GetIndustrySpec ( this - > type ) ;
2020-12-14 23:35:07 +01:00
assert ( indspec - > UsesOriginalEconomy ( ) ) ;
2010-10-04 21:23:50 +02:00
/* Rates are rounded up, so e.g. oilrig always produces some passengers */
2023-05-25 22:25:46 +02:00
for ( auto & p : this - > produced ) {
p . rate = ClampTo < uint8_t > ( CeilDiv ( indspec - > production_rate [ & p - this - > produced . data ( ) ] * this - > prod_level , PRODLEVEL_DEFAULT ) ) ;
2018-07-25 19:20:17 +02:00
}
2010-10-04 21:23:50 +02:00
}
2020-01-06 21:40:31 +01:00
void Industry : : FillCachedName ( ) const
{
2023-06-13 23:46:08 +02:00
auto tmp_params = MakeParameters ( this - > index ) ;
2023-06-13 23:52:43 +02:00
this - > cached_name = GetStringWithArgs ( STR_INDUSTRY_NAME , tmp_params ) ;
2020-01-06 21:40:31 +01:00
}
void ClearAllIndustryCachedNames ( )
{
for ( Industry * ind : Industry : : Iterate ( ) ) {
ind - > cached_name . clear ( ) ;
}
}
2010-11-13 16:04:58 +01:00
/**
2010-11-13 16:21:55 +01:00
* Set the # probability and # min_number fields for the industry type \ a it for a running game .
2010-11-13 16:04:58 +01:00
* @ param it Industry type .
2010-11-13 16:21:55 +01:00
* @ return At least one of the fields has changed value .
2010-11-13 16:04:58 +01:00
*/
2010-11-13 16:19:43 +01:00
bool IndustryTypeBuildData : : GetIndustryTypeData ( IndustryType it )
2010-11-13 16:04:58 +01:00
{
2024-03-16 23:59:32 +01:00
uint8_t min_number ;
2023-05-08 19:01:06 +02:00
uint32_t probability = GetIndustryGamePlayProbability ( it , & min_number ) ;
2010-11-13 16:21:55 +01:00
bool changed = min_number ! = this - > min_number | | probability ! = this - > probability ;
this - > min_number = min_number ;
2010-11-13 16:19:43 +01:00
this - > probability = probability ;
return changed ;
2010-11-13 16:04:58 +01:00
}
2007-04-06 04:12:15 +02:00
2010-11-13 16:07:34 +01:00
/** Decide how many industries of each type are needed. */
void IndustryBuildData : : SetupTargetCount ( )
{
2010-11-13 16:19:43 +01:00
bool changed = false ;
uint num_planned = 0 ; // Number of industries planned in the industry build data.
2010-11-13 16:07:34 +01:00
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
2010-11-13 16:19:43 +01:00
changed | = this - > builddata [ it ] . GetIndustryTypeData ( it ) ;
num_planned + = this - > builddata [ it ] . target_count ;
2010-11-13 16:07:34 +01:00
}
2010-11-13 16:17:55 +01:00
uint total_amount = this - > wanted_inds > > 16 ; // Desired total number of industries.
2010-11-13 16:19:43 +01:00
changed | = num_planned ! = total_amount ;
if ( ! changed ) return ; // All industries are still the same, no need to re-randomize.
2010-11-13 16:21:55 +01:00
/* Initialize the target counts. */
uint force_build = 0 ; // Number of industries that should always be available.
2023-05-08 19:01:06 +02:00
uint32_t total_prob = 0 ; // Sum of probabilities.
2010-11-13 16:07:34 +01:00
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
2010-11-13 16:21:55 +01:00
IndustryTypeBuildData * ibd = this - > builddata + it ;
force_build + = ibd - > min_number ;
ibd - > target_count = ibd - > min_number ;
total_prob + = ibd - > probability ;
2010-11-13 16:07:34 +01:00
}
2010-11-20 13:20:59 +01:00
if ( total_prob = = 0 ) return ; // No buildable industries.
2010-11-13 16:21:55 +01:00
/* Subtract forced industries from the number of industries available for construction. */
total_amount = ( total_amount < = force_build ) ? 0 : total_amount - force_build ;
2010-11-13 16:07:34 +01:00
/* Assign number of industries that should be aimed for, by using the probability as a weight. */
while ( total_amount > 0 ) {
2023-05-08 19:01:06 +02:00
uint32_t r = RandomRange ( total_prob ) ;
2010-11-13 16:07:34 +01:00
IndustryType it = 0 ;
while ( r > = this - > builddata [ it ] . probability ) {
r - = this - > builddata [ it ] . probability ;
it + + ;
assert ( it < NUM_INDUSTRYTYPES ) ;
}
assert ( this - > builddata [ it ] . probability > 0 ) ;
this - > builddata [ it ] . target_count + + ;
total_amount - - ;
}
}
2007-04-04 02:32:40 +02:00
/**
* Try to create a random industry , during gameplay
*/
2010-11-13 16:02:31 +01:00
void IndustryBuildData : : TryBuildNewIndustry ( )
2007-04-04 02:32:40 +02:00
{
2010-11-13 16:07:34 +01:00
this - > SetupTargetCount ( ) ;
2010-11-13 16:04:58 +01:00
2010-11-13 16:07:34 +01:00
int missing = 0 ; // Number of industries that need to be build.
2010-11-13 16:04:58 +01:00
uint count = 0 ; // Number of industry types eligible for build.
2023-05-08 19:01:06 +02:00
uint32_t total_prob = 0 ; // Sum of probabilities.
2010-11-13 16:21:55 +01:00
IndustryType forced_build = NUM_INDUSTRYTYPES ; // Industry type that should be forcibly build.
2010-11-13 16:04:58 +01:00
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
2010-11-13 16:07:34 +01:00
int difference = this - > builddata [ it ] . target_count - Industry : : GetIndustryTypeCount ( it ) ;
missing + = difference ;
2010-11-13 16:20:57 +01:00
if ( this - > builddata [ it ] . wait_count > 0 ) continue ; // This type may not be built now.
2010-11-13 16:07:34 +01:00
if ( difference > 0 ) {
2010-11-13 16:21:55 +01:00
if ( Industry : : GetIndustryTypeCount ( it ) = = 0 & & this - > builddata [ it ] . min_number > 0 ) {
/* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
if ( forced_build = = NUM_INDUSTRYTYPES | |
difference > this - > builddata [ forced_build ] . target_count - Industry : : GetIndustryTypeCount ( forced_build ) ) {
forced_build = it ;
}
}
2010-11-13 16:07:34 +01:00
total_prob + = difference ;
2010-11-13 16:04:58 +01:00
count + + ;
2007-04-04 02:32:40 +02:00
}
}
2004-08-09 19:04:08 +02:00
2010-11-13 16:21:55 +01:00
if ( EconomyIsInRecession ( ) | | ( forced_build = = NUM_INDUSTRYTYPES & & ( missing < = 0 | | total_prob = = 0 ) ) ) count = 0 ; // Skip creation of an industry.
2010-11-13 16:07:34 +01:00
2010-11-13 16:04:58 +01:00
if ( count > = 1 ) {
2010-11-13 16:21:55 +01:00
/* If not forced, pick a weighted random industry to build.
2010-11-13 16:04:58 +01:00
* For the case that count = = 1 , there is no need to draw a random number . */
IndustryType it ;
2010-11-13 16:21:55 +01:00
if ( forced_build ! = NUM_INDUSTRYTYPES ) {
it = forced_build ;
} else {
/* Non-forced, select an industry type to build (weighted random). */
2023-05-08 19:01:06 +02:00
uint32_t r = 0 ; // Initialized to silence the compiler.
2010-11-13 16:21:55 +01:00
if ( count > 1 ) r = RandomRange ( total_prob ) ;
for ( it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
if ( this - > builddata [ it ] . wait_count > 0 ) continue ; // Type may not be built now.
int difference = this - > builddata [ it ] . target_count - Industry : : GetIndustryTypeCount ( it ) ;
if ( difference < = 0 ) continue ; // Too many of this kind.
if ( count = = 1 ) break ;
if ( r < ( uint ) difference ) break ;
r - = difference ;
}
assert ( it < NUM_INDUSTRYTYPES & & this - > builddata [ it ] . target_count > Industry : : GetIndustryTypeCount ( it ) ) ;
2010-11-13 16:04:58 +01:00
}
2009-04-11 16:54:03 +02:00
2010-11-13 16:04:58 +01:00
/* Try to create the industry. */
const Industry * ind = PlaceIndustry ( it , IACT_RANDOMCREATION , false ) ;
2019-04-10 23:07:06 +02:00
if ( ind = = nullptr ) {
2010-11-13 16:20:57 +01:00
this - > builddata [ it ] . wait_count = this - > builddata [ it ] . max_wait + 1 ; // Compensate for decrementing below.
2021-01-08 11:16:18 +01:00
this - > builddata [ it ] . max_wait = std : : min ( 1000 , this - > builddata [ it ] . max_wait + 2 ) ;
2010-11-13 16:20:57 +01:00
} else {
2010-11-13 16:04:58 +01:00
AdvertiseIndustryOpening ( ind ) ;
2021-01-08 11:16:18 +01:00
this - > builddata [ it ] . max_wait = std : : max ( this - > builddata [ it ] . max_wait / 2 , 1 ) ; // Reduce waiting time of the industry type.
2010-11-13 16:04:58 +01:00
}
2007-04-04 02:32:40 +02:00
}
2010-11-13 16:20:57 +01:00
/* Decrement wait counters. */
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
if ( this - > builddata [ it ] . wait_count > 0 ) this - > builddata [ it ] . wait_count - - ;
}
2004-08-09 19:04:08 +02:00
}
2007-09-22 23:59:02 +02:00
/**
* Protects an industry from closure if the appropriate flags and conditions are met
* INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set ( which , by default , it is not ) and the
* count of industries of this type must one ( or lower ) in order to be protected
* against closure .
* @ param type IndustryType been queried
* @ result true if protection is on , false otherwise ( except for oil wells )
*/
static bool CheckIndustryCloseDownProtection ( IndustryType type )
2004-08-09 19:04:08 +02:00
{
2006-04-26 23:10:01 +02:00
const IndustrySpec * indspec = GetIndustrySpec ( type ) ;
2004-09-11 11:55:19 +02:00
2007-09-22 23:59:02 +02:00
/* oil wells (or the industries with that flag set) are always allowed to closedown */
2009-06-01 13:43:36 +02:00
if ( ( indspec - > behaviour & INDUSTRYBEH_DONT_INCR_PROD ) & & _settings_game . game_creation . landscape = = LT_TEMPERATE ) return false ;
2010-03-20 15:30:16 +01:00
return ( indspec - > behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE ) = = 0 & & Industry : : GetIndustryTypeCount ( type ) < = 1 ;
2007-09-22 23:59:02 +02:00
}
2007-11-15 23:20:33 +01:00
/**
2009-03-14 19:16:29 +01:00
* Can given cargo type be accepted or produced by the industry ?
* @ param cargo : Cargo type
* @ param ind : Industry
* @ param * c_accepts : Pointer to boolean for acceptance of cargo
* @ param * c_produces : Pointer to boolean for production of cargo
* @ return : \ c * c_accepts is set when industry accepts the cargo type ,
* \ c * c_produces is set when the industry produces the cargo type
*/
2007-11-15 23:20:33 +01:00
static void CanCargoServiceIndustry ( CargoID cargo , Industry * ind , bool * c_accepts , bool * c_produces )
{
2023-05-04 12:29:21 +02:00
if ( ! IsValidCargoID ( cargo ) ) return ;
2007-11-15 23:20:33 +01:00
/* Check for acceptance of cargo */
2023-05-24 01:52:44 +02:00
if ( ind - > IsCargoAccepted ( cargo ) & & ! IndustryTemporarilyRefusesCargo ( ind , cargo ) ) * c_accepts = true ;
2007-11-15 23:20:33 +01:00
/* Check for produced cargo */
2023-05-24 01:52:44 +02:00
if ( ind - > IsCargoProduced ( cargo ) ) * c_produces = true ;
2007-11-15 23:20:33 +01:00
}
/**
2009-03-14 19:16:29 +01:00
* Compute who can service the industry .
*
2021-05-08 12:02:30 +02:00
* Here , ' can service ' means that they have trains and stations close enough
2009-03-14 19:16:29 +01:00
* to the industry with the right cargo type and the right orders ( ie has the
* technical means ) .
*
* @ param ind : Industry being investigated .
*
* @ return : 0 if nobody can service the industry , 2 if the local company can
* service the industry , and 1 otherwise ( only competitors can service the
* industry )
*/
2023-07-16 21:34:42 +02:00
int WhoCanServiceIndustry ( Industry * ind )
2007-11-15 23:20:33 +01:00
{
2023-10-20 20:09:58 +02:00
if ( ind - > stations_near . empty ( ) ) return 0 ; // No stations found at all => nobody services
2007-11-15 23:20:33 +01:00
int result = 0 ;
2019-12-17 03:37:43 +01:00
for ( const Vehicle * v : Vehicle : : Iterate ( ) ) {
2007-11-15 23:20:33 +01:00
/* Is it worthwhile to try this vehicle? */
2008-09-30 22:39:50 +02:00
if ( v - > owner ! = _local_company & & result ! = 0 ) continue ;
2007-11-15 23:20:33 +01:00
/* Check whether it accepts the right kind of cargo */
bool c_accepts = false ;
bool c_produces = false ;
2011-01-29 18:30:25 +01:00
if ( v - > type = = VEH_TRAIN & & v - > IsFrontEngine ( ) ) {
2019-04-10 23:07:06 +02:00
for ( const Vehicle * u = v ; u ! = nullptr ; u = u - > Next ( ) ) {
2007-11-15 23:20:33 +01:00
CanCargoServiceIndustry ( u - > cargo_type , ind , & c_accepts , & c_produces ) ;
2008-05-21 14:06:05 +02:00
}
2007-11-15 23:20:33 +01:00
} else if ( v - > type = = VEH_ROAD | | v - > type = = VEH_SHIP | | v - > type = = VEH_AIRCRAFT ) {
CanCargoServiceIndustry ( v - > cargo_type , ind , & c_accepts , & c_produces ) ;
} else {
continue ;
}
if ( ! c_accepts & & ! c_produces ) continue ; // Wrong cargo
/* Check orders of the vehicle.
* We cannot check the first of shared orders only , since the first vehicle in such a chain
* may have a different cargo type .
*/
2020-12-27 00:13:56 +01:00
for ( const Order * o : v - > Orders ( ) ) {
2008-04-07 22:03:46 +02:00
if ( o - > IsType ( OT_GOTO_STATION ) & & ! ( o - > GetUnloadType ( ) & OUFB_TRANSFER ) ) {
2007-11-15 23:20:33 +01:00
/* Vehicle visits a station to load or unload */
2009-05-17 01:34:14 +02:00
Station * st = Station : : Get ( o - > GetDestination ( ) ) ;
2019-04-10 23:07:06 +02:00
assert ( st ! = nullptr ) ;
2007-11-15 23:20:33 +01:00
/* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2008-04-07 22:03:46 +02:00
if ( ( o - > GetUnloadType ( ) & OUFB_UNLOAD ) & & ! c_accepts ) break ;
2007-11-15 23:20:33 +01:00
2019-02-14 22:07:15 +01:00
if ( ind - > stations_near . find ( st ) ! = ind - > stations_near . end ( ) ) {
2008-09-30 22:39:50 +02:00
if ( v - > owner = = _local_company ) return 2 ; // Company services industry
2007-11-15 23:20:33 +01:00
result = 1 ; // Competitor services industry
}
}
}
}
return result ;
}
/**
2009-03-14 19:16:29 +01:00
* Report news that industry production has changed significantly
*
* @ param ind : Industry with changed production
* @ param type : Cargo type that has changed
* @ param percent : Percentage of change ( > 0 means increase , < 0 means decrease )
*/
2007-11-15 23:20:33 +01:00
static void ReportNewsProductionChangeIndustry ( Industry * ind , CargoID type , int percent )
{
2012-05-26 16:16:03 +02:00
NewsType nt ;
2007-11-15 23:20:33 +01:00
switch ( WhoCanServiceIndustry ( ind ) ) {
2012-05-26 16:16:03 +02:00
case 0 : nt = NT_INDUSTRY_NOBODY ; break ;
case 1 : nt = NT_INDUSTRY_OTHER ; break ;
case 2 : nt = NT_INDUSTRY_COMPANY ; break ;
2009-05-26 17:46:24 +02:00
default : NOT_REACHED ( ) ;
2007-11-15 23:20:33 +01:00
}
SetDParam ( 2 , abs ( percent ) ) ;
2009-07-16 21:00:13 +02:00
SetDParam ( 0 , CargoSpec : : Get ( type ) - > name ) ;
2007-11-15 23:20:33 +01:00
SetDParam ( 1 , ind - > index ) ;
2009-05-24 18:52:42 +02:00
AddIndustryNewsItem (
2009-04-22 01:40:56 +02:00
percent > = 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH ,
2012-05-26 16:16:03 +02:00
nt ,
2009-05-24 18:52:42 +02:00
ind - > index
2007-11-15 23:20:33 +01:00
) ;
}
2010-05-13 12:14:29 +02:00
static const uint PERCENT_TRANSPORTED_60 = 153 ;
static const uint PERCENT_TRANSPORTED_80 = 204 ;
2007-11-23 13:12:07 +01:00
2010-08-01 21:22:34 +02:00
/**
* Change industry production or do closure
2007-09-22 23:59:02 +02:00
* @ param i Industry for which changes are performed
* @ param monthly true if it ' s the monthly call , false if it ' s the random call
*/
static void ChangeIndustryProduction ( Industry * i , bool monthly )
{
StringID str = STR_NULL ;
bool closeit = false ;
const IndustrySpec * indspec = GetIndustrySpec ( i - > type ) ;
2009-01-17 15:49:31 +01:00
bool standard = false ;
2007-09-23 01:40:35 +02:00
bool suppress_message = false ;
2009-01-16 12:32:35 +01:00
bool recalculate_multipliers = false ; ///< reinitialize production_rate to match prod_level
2020-12-14 23:35:07 +01:00
/* use original economy for industries using production related callbacks */
bool original_economy = indspec - > UsesOriginalEconomy ( ) ;
2024-03-16 23:59:32 +01:00
uint8_t div = 0 ;
uint8_t mul = 0 ;
2023-05-08 19:01:06 +02:00
int8_t increment = 0 ;
2007-09-23 01:40:35 +02:00
2009-09-14 14:22:57 +02:00
bool callback_enabled = HasBit ( indspec - > callback_mask , monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE ) ;
2009-01-17 15:49:31 +01:00
if ( callback_enabled ) {
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryCallback ( monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE , 0 , Random ( ) , i , i - > type , i - > location . tile ) ;
2009-01-17 15:49:31 +01:00
if ( res ! = CALLBACK_FAILED ) { // failed callback means "do nothing"
2007-11-19 22:02:30 +01:00
suppress_message = HasBit ( res , 7 ) ;
2007-09-23 01:40:35 +02:00
/* Get the custom message if any */
2007-11-19 22:02:30 +01:00
if ( HasBit ( res , 8 ) ) str = MapGRFStringID ( indspec - > grf_prop . grffile - > grfid , GB ( GetRegister ( 0x100 ) , 0 , 16 ) ) ;
2007-09-23 01:40:35 +02:00
res = GB ( res , 0 , 4 ) ;
2009-08-09 16:40:34 +02:00
switch ( res ) {
2007-09-23 01:40:35 +02:00
default : NOT_REACHED ( ) ;
case 0x0 : break ; // Do nothing, but show the custom message if any
case 0x1 : div = 1 ; break ; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
case 0x2 : mul = 1 ; break ; // Double industry production if it hasn't reached eight times of the original yet.
case 0x3 : closeit = true ; break ; // The industry announces imminent closure, and is physically removed from the map next month.
case 0x4 : standard = true ; break ; // Do the standard random production change as if this industry was a primary one.
case 0x5 : case 0x6 : case 0x7 : // Divide production by 4, 8, 16
2007-11-23 05:17:41 +01:00
case 0x8 : div = res - 0x3 ; break ; // Divide production by 32
2007-09-23 01:40:35 +02:00
case 0x9 : case 0xA : case 0xB : // Multiply production by 4, 8, 16
2007-11-23 05:17:41 +01:00
case 0xC : mul = res - 0x7 ; break ; // Multiply production by 32
2007-11-27 05:16:08 +01:00
case 0xD : // decrement production
case 0xE : // increment production
increment = res = = 0x0D ? - 1 : 1 ;
break ;
2008-11-03 21:23:51 +01:00
case 0xF : // Set production to third byte of register 0x100
i - > prod_level = Clamp ( GB ( GetRegister ( 0x100 ) , 16 , 8 ) , PRODLEVEL_MINIMUM , PRODLEVEL_MAXIMUM ) ;
2009-01-16 12:32:35 +01:00
recalculate_multipliers = true ;
2008-11-03 20:25:52 +01:00
break ;
2007-09-23 01:40:35 +02:00
}
}
2009-01-17 15:49:31 +01:00
} else {
2020-12-14 23:35:07 +01:00
if ( monthly = = original_economy ) return ;
if ( ! original_economy & & _settings_game . economy . type = = ET_FROZEN ) return ;
2009-01-17 15:49:31 +01:00
if ( indspec - > life_type = = INDUSTRYLIFE_BLACK_HOLE ) return ;
2007-09-23 01:40:35 +02:00
}
2007-09-22 23:59:02 +02:00
2009-01-17 15:49:31 +01:00
if ( standard | | ( ! callback_enabled & & ( indspec - > life_type & ( INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE ) ) ! = 0 ) ) {
2007-07-03 21:16:34 +02:00
/* decrease or increase */
2008-05-29 17:13:28 +02:00
bool only_decrease = ( indspec - > behaviour & INDUSTRYBEH_DONT_INCR_PROD ) & & _settings_game . game_creation . landscape = = LT_TEMPERATE ;
2004-08-09 19:04:08 +02:00
2020-12-14 23:35:07 +01:00
if ( original_economy ) {
if ( only_decrease | | Chance16 ( 1 , 3 ) ) {
/* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2023-11-29 22:30:19 +01:00
if ( ! only_decrease & & ( i - > GetProduced ( 0 ) . history [ LAST_MONTH ] . PctTransported ( ) > PERCENT_TRANSPORTED_60 ) ! = Chance16 ( 1 , 3 ) ) {
2020-12-14 23:35:07 +01:00
mul = 1 ; // Increase production
} else {
div = 1 ; // Decrease production
}
}
} else if ( _settings_game . economy . type = = ET_SMOOTH ) {
2020-12-22 14:21:31 +01:00
closeit = ! ( i - > ctlflags & ( INDCTL_NO_CLOSURE | INDCTL_NO_PRODUCTION_DECREASE ) ) ;
2023-05-25 22:25:46 +02:00
for ( auto & p : i - > produced ) {
if ( ! IsValidCargoID ( p . cargo ) ) continue ;
2023-05-08 19:01:06 +02:00
uint32_t r = Random ( ) ;
2007-09-22 23:59:02 +02:00
int old_prod , new_prod , percent ;
2008-01-06 02:06:12 +01:00
/* If over 60% is transported, mult is 1, else mult is -1. */
2023-05-25 22:25:46 +02:00
int mult = ( p . history [ LAST_MONTH ] . PctTransported ( ) > PERCENT_TRANSPORTED_60 ) ? 1 : - 1 ;
2004-09-11 11:55:19 +02:00
2023-05-25 22:25:46 +02:00
new_prod = old_prod = p . rate ;
2004-09-11 11:55:19 +02:00
2008-01-06 02:06:12 +01:00
/* For industries with only_decrease flags (temperate terrain Oil Wells),
* the multiplier will always be - 1 so they will only decrease . */
2007-11-26 20:23:53 +01:00
if ( only_decrease ) {
mult = - 1 ;
2008-01-06 02:06:12 +01:00
/* For normal industries, if over 60% is transported, 33% chance for decrease.
* Bonus for very high station ratings ( over 80 % ) : 16 % chance for decrease . */
2023-05-25 22:25:46 +02:00
} else if ( Chance16I ( 1 , ( ( p . history [ LAST_MONTH ] . PctTransported ( ) > PERCENT_TRANSPORTED_80 ) ? 6 : 3 ) , r ) ) {
2007-11-26 20:23:53 +01:00
mult * = - 1 ;
}
2007-11-23 13:12:07 +01:00
2008-01-06 02:06:12 +01:00
/* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
* determined by mult value . If mult = 1 prod . increases , else ( - 1 ) it decreases . */
if ( Chance16I ( 1 , 22 , r > > 16 ) ) {
2021-01-08 11:16:18 +01:00
new_prod + = mult * ( std : : max ( ( ( RandomRange ( 50 ) + 10 ) * old_prod ) > > 8 , 1U ) ) ;
2007-09-22 23:59:02 +02:00
}
2004-08-09 19:04:08 +02:00
2007-11-23 13:12:07 +01:00
/* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2007-11-19 19:38:10 +01:00
new_prod = Clamp ( new_prod , 1 , 255 ) ;
2024-02-04 11:16:08 +01:00
if ( IsValidCargoID ( p . cargo ) & & p . cargo = = GetCargoIDByLabel ( CT_PASSENGERS ) & & ! ( indspec - > behaviour & INDUSTRYBEH_NO_PAX_PROD_CLAMP ) ) {
2007-11-23 13:12:07 +01:00
new_prod = Clamp ( new_prod , 0 , 16 ) ;
2010-07-24 12:14:39 +02:00
}
2007-11-23 13:12:07 +01:00
2020-12-22 14:21:31 +01:00
/* If override flags are set, prevent actually changing production if any was decided on */
if ( ( i - > ctlflags & INDCTL_NO_PRODUCTION_DECREASE ) & & new_prod < old_prod ) continue ;
if ( ( i - > ctlflags & INDCTL_NO_PRODUCTION_INCREASE ) & & new_prod > old_prod ) continue ;
2007-09-22 23:59:02 +02:00
/* Do not stop closing the industry when it has the lowest possible production rate */
if ( new_prod = = old_prod & & old_prod > 1 ) {
closeit = false ;
continue ;
}
2004-08-09 19:04:08 +02:00
2007-09-22 23:59:02 +02:00
percent = ( old_prod = = 0 ) ? 100 : ( new_prod * 100 / old_prod - 100 ) ;
2023-05-25 22:25:46 +02:00
p . rate = new_prod ;
2007-09-22 23:59:02 +02:00
/* Close the industry when it has the lowest possible production rate */
if ( new_prod > 1 ) closeit = false ;
2007-11-15 23:20:33 +01:00
if ( abs ( percent ) > = 10 ) {
2023-05-25 22:25:46 +02:00
ReportNewsProductionChangeIndustry ( i , p . cargo , percent ) ;
2007-07-03 21:16:34 +02:00
}
2007-09-22 23:59:02 +02:00
}
2007-07-03 21:16:34 +02:00
}
}
2007-09-22 23:59:02 +02:00
2020-12-22 14:21:31 +01:00
/* If override flags are set, prevent actually changing production if any was decided on */
if ( ( i - > ctlflags & INDCTL_NO_PRODUCTION_DECREASE ) & & ( div > 0 | | increment < 0 ) ) return ;
if ( ( i - > ctlflags & INDCTL_NO_PRODUCTION_INCREASE ) & & ( mul > 0 | | increment > 0 ) ) return ;
2023-07-16 21:34:42 +02:00
if ( i - > ctlflags & INDCTL_EXTERNAL_PROD_LEVEL ) {
div = 0 ;
mul = 0 ;
increment = 0 ;
}
2020-12-22 14:21:31 +01:00
2009-06-01 13:43:36 +02:00
if ( ! callback_enabled & & ( indspec - > life_type & INDUSTRYLIFE_PROCESSING ) ) {
2024-01-22 15:04:34 +01:00
if ( TimerGameEconomy : : year - i - > last_prod_year > = PROCESSING_INDUSTRY_ABANDONMENT_YEARS & & Chance16 ( 1 , original_economy ? 2 : 180 ) ) {
2007-09-22 23:59:02 +02:00
closeit = true ;
2007-07-03 21:16:34 +02:00
}
2005-02-06 16:07:29 +01:00
}
2007-09-23 01:40:35 +02:00
/* Increase if needed */
2008-02-09 04:03:09 +01:00
while ( mul - - ! = 0 & & i - > prod_level < PRODLEVEL_MAXIMUM ) {
2021-01-08 11:16:18 +01:00
i - > prod_level = std : : min < int > ( i - > prod_level * 2 , PRODLEVEL_MAXIMUM ) ;
2009-01-16 12:32:35 +01:00
recalculate_multipliers = true ;
2007-09-23 01:40:35 +02:00
if ( str = = STR_NULL ) str = indspec - > production_up_text ;
}
/* Decrease if needed */
while ( div - - ! = 0 & & ! closeit ) {
2008-02-09 04:03:09 +01:00
if ( i - > prod_level = = PRODLEVEL_MINIMUM ) {
2007-09-23 01:40:35 +02:00
closeit = true ;
2020-12-22 14:21:31 +01:00
break ;
2007-09-23 01:40:35 +02:00
} else {
2021-01-08 11:16:18 +01:00
i - > prod_level = std : : max < int > ( i - > prod_level / 2 , PRODLEVEL_MINIMUM ) ;
2009-01-16 12:32:35 +01:00
recalculate_multipliers = true ;
2007-09-23 01:40:35 +02:00
if ( str = = STR_NULL ) str = indspec - > production_down_text ;
}
}
2008-01-24 19:16:04 +01:00
/* Increase or Decreasing the production level if needed */
2007-11-27 05:16:08 +01:00
if ( increment ! = 0 ) {
2008-02-09 04:03:09 +01:00
if ( increment < 0 & & i - > prod_level = = PRODLEVEL_MINIMUM ) {
2008-01-24 19:16:04 +01:00
closeit = true ;
} else {
2008-02-09 04:03:09 +01:00
i - > prod_level = ClampU ( i - > prod_level + increment , PRODLEVEL_MINIMUM , PRODLEVEL_MAXIMUM ) ;
2009-01-16 12:32:35 +01:00
recalculate_multipliers = true ;
2008-01-24 19:16:04 +01:00
}
2007-11-27 05:16:08 +01:00
}
2009-01-16 12:32:35 +01:00
/* Recalculate production_rate
* For non - smooth economy these should always be synchronized with prod_level */
2010-10-04 21:23:50 +02:00
if ( recalculate_multipliers ) i - > RecomputeProductionMultipliers ( ) ;
2009-01-16 12:32:35 +01:00
2007-09-22 23:59:02 +02:00
/* Close if needed and allowed */
2020-12-22 14:21:31 +01:00
if ( closeit & & ! CheckIndustryCloseDownProtection ( i - > type ) & & ! ( i - > ctlflags & INDCTL_NO_CLOSURE ) ) {
2008-02-09 04:03:09 +01:00
i - > prod_level = PRODLEVEL_CLOSURE ;
2013-05-12 21:38:30 +02:00
SetWindowDirty ( WC_INDUSTRY_VIEW , i - > index ) ;
2007-09-22 23:59:02 +02:00
str = indspec - > closure_text ;
}
2007-09-23 01:40:35 +02:00
if ( ! suppress_message & & str ! = STR_NULL ) {
2012-05-26 16:16:03 +02:00
NewsType nt ;
2007-11-15 23:20:33 +01:00
/* Compute news category */
if ( closeit ) {
2012-05-26 16:16:03 +02:00
nt = NT_INDUSTRY_CLOSE ;
2011-11-30 00:15:35 +01:00
AI : : BroadcastNewEvent ( new ScriptEventIndustryClose ( i - > index ) ) ;
2011-12-19 21:59:36 +01:00
Game : : NewEvent ( new ScriptEventIndustryClose ( i - > index ) ) ;
2007-11-15 23:20:33 +01:00
} else {
switch ( WhoCanServiceIndustry ( i ) ) {
2012-05-26 16:16:03 +02:00
case 0 : nt = NT_INDUSTRY_NOBODY ; break ;
case 1 : nt = NT_INDUSTRY_OTHER ; break ;
case 2 : nt = NT_INDUSTRY_COMPANY ; break ;
2009-05-26 17:46:24 +02:00
default : NOT_REACHED ( ) ;
2007-11-15 23:20:33 +01:00
}
}
/* Set parameters of news string */
2007-10-18 22:35:59 +02:00
if ( str > STR_LAST_STRINGID ) {
2009-07-20 13:21:57 +02:00
SetDParam ( 0 , STR_TOWN_NAME ) ;
2007-10-18 22:35:59 +02:00
SetDParam ( 1 , i - > town - > index ) ;
SetDParam ( 2 , indspec - > name ) ;
2007-11-12 19:32:04 +01:00
} else if ( closeit ) {
2009-07-20 13:21:57 +02:00
SetDParam ( 0 , STR_FORMAT_INDUSTRY_NAME ) ;
2007-11-12 19:32:04 +01:00
SetDParam ( 1 , i - > town - > index ) ;
SetDParam ( 2 , indspec - > name ) ;
2007-10-18 22:35:59 +02:00
} else {
SetDParam ( 0 , i - > index ) ;
}
2007-11-15 23:20:33 +01:00
/* and report the news to the user */
2012-05-26 16:15:57 +02:00
if ( closeit ) {
2012-05-26 16:16:03 +02:00
AddTileNewsItem ( str , nt , i - > location . tile + TileDiffXY ( 1 , 1 ) ) ;
2012-05-26 16:15:57 +02:00
} else {
2012-05-26 16:16:03 +02:00
AddIndustryNewsItem ( str , nt , i - > index ) ;
2012-05-26 16:15:57 +02:00
}
2004-08-09 19:04:08 +02:00
}
}
2010-08-01 19:45:53 +02:00
/**
2024-01-22 15:04:34 +01:00
* Every economy day handler for the industry changes
2008-09-15 19:18:22 +02:00
* Taking the original map size of 256 * 256 , the number of random changes was always of just one unit .
* But it cannot be the same on smaller or bigger maps . That number has to be scaled up or down .
* For small maps , it implies that less than one change per month is required , while on bigger maps ,
2010-08-01 19:45:53 +02:00
* it would be way more . The daily loop handles those changes .
*/
2024-01-22 15:04:34 +01:00
static IntervalTimer < TimerGameEconomy > _economy_industries_daily ( { TimerGameEconomy : : DAY , TimerGameEconomy : : Priority : : INDUSTRY } , [ ] ( auto )
2008-09-15 19:18:22 +02:00
{
_economy . industry_daily_change_counter + = _economy . industry_daily_increment ;
/* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
* the lower 16 bit are a fractional part that might accumulate over several days until it
* is sufficient for an industry . */
2023-05-08 19:01:06 +02:00
uint16_t change_loop = _economy . industry_daily_change_counter > > 16 ;
2008-09-15 19:18:22 +02:00
2013-01-08 23:46:42 +01:00
/* Reset the active part of the counter, just keeping the "fractional part" */
2008-09-15 19:18:22 +02:00
_economy . industry_daily_change_counter & = 0xFFFF ;
if ( change_loop = = 0 ) {
return ; // Nothing to do? get out
}
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_NONE ) ;
2008-09-15 19:18:22 +02:00
/* perform the required industry changes for the day */
2010-11-13 16:17:55 +01:00
uint perc = 3 ; // Between 3% and 9% chance of creating a new industry.
if ( ( _industry_builder . wanted_inds > > 16 ) > GetCurrentTotalNumberOfIndustries ( ) ) {
2021-01-08 11:16:18 +01:00
perc = std : : min ( 9u , perc + ( _industry_builder . wanted_inds > > 16 ) - GetCurrentTotalNumberOfIndustries ( ) ) ;
2010-11-13 16:17:55 +01:00
}
2023-05-08 19:01:06 +02:00
for ( uint16_t j = 0 ; j < change_loop ; j + + ) {
2010-11-13 16:17:55 +01:00
if ( Chance16 ( perc , 100 ) ) {
2010-11-13 16:02:31 +01:00
_industry_builder . TryBuildNewIndustry ( ) ;
2008-09-15 19:18:22 +02:00
} else {
2009-06-26 17:08:54 +02:00
Industry * i = Industry : : GetRandom ( ) ;
2019-04-10 23:07:06 +02:00
if ( i ! = nullptr ) {
2010-03-17 19:52:56 +01:00
ChangeIndustryProduction ( i , false ) ;
SetWindowDirty ( WC_INDUSTRY_VIEW , i - > index ) ;
}
2008-09-15 19:18:22 +02:00
}
}
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2008-09-15 19:18:22 +02:00
/* production-change */
2020-01-06 21:31:57 +01:00
InvalidateWindowData ( WC_INDUSTRY_DIRECTORY , 0 , IDIWD_PRODUCTION_CHANGE ) ;
2023-04-13 13:56:00 +02:00
} ) ;
2008-09-15 19:18:22 +02:00
2024-01-22 15:04:34 +01:00
static IntervalTimer < TimerGameEconomy > _economy_industries_monthly ( { TimerGameEconomy : : MONTH , TimerGameEconomy : : Priority : : INDUSTRY } , [ ] ( auto )
2004-08-09 19:04:08 +02:00
{
2024-01-17 03:33:23 +01:00
Backup < CompanyID > cur_company ( _current_company , OWNER_NONE ) ;
2004-08-09 19:04:08 +02:00
2024-01-22 15:04:34 +01:00
_industry_builder . EconomyMonthlyLoop ( ) ;
2010-11-13 16:17:55 +01:00
2019-12-16 18:51:20 +01:00
for ( Industry * i : Industry : : Iterate ( ) ) {
2006-08-22 17:33:35 +02:00
UpdateIndustryStatistics ( i ) ;
2008-02-09 04:03:09 +01:00
if ( i - > prod_level = = PRODLEVEL_CLOSURE ) {
2007-09-22 23:59:02 +02:00
delete i ;
} else {
ChangeIndustryProduction ( i , true ) ;
2010-03-17 19:52:56 +01:00
SetWindowDirty ( WC_INDUSTRY_VIEW , i - > index ) ;
2007-09-22 23:59:02 +02:00
}
2004-08-09 19:04:08 +02:00
}
2010-05-31 22:22:57 +02:00
cur_company . Restore ( ) ;
2004-09-16 17:15:04 +02:00
2007-03-03 05:04:22 +01:00
/* production-change */
2020-01-06 21:31:57 +01:00
InvalidateWindowData ( WC_INDUSTRY_DIRECTORY , 0 , IDIWD_PRODUCTION_CHANGE ) ;
2023-04-13 13:56:00 +02:00
} ) ;
2004-08-09 19:04:08 +02:00
2007-03-07 12:47:46 +01:00
void InitializeIndustries ( )
2004-08-09 19:04:08 +02:00
{
2010-03-20 15:30:16 +01:00
Industry : : ResetIndustryCounts ( ) ;
2006-09-10 10:28:32 +02:00
_industry_sound_tile = 0 ;
2010-11-13 16:15:25 +01:00
_industry_builder . Reset ( ) ;
2004-08-09 19:04:08 +02:00
}
2014-08-13 21:31:45 +02:00
/** Verify whether the generated industries are complete, and warn the user if not. */
void CheckIndustries ( )
{
int count = 0 ;
for ( IndustryType it = 0 ; it < NUM_INDUSTRYTYPES ; it + + ) {
if ( Industry : : GetIndustryTypeCount ( it ) > 0 ) continue ; // Types of existing industries can be skipped.
bool force_at_least_one ;
2023-05-08 19:01:06 +02:00
uint32_t chance = GetScaledIndustryGenerationProbability ( it , & force_at_least_one ) ;
2014-08-13 21:31:45 +02:00
if ( chance = = 0 | | ! force_at_least_one ) continue ; // Types that are not available can be skipped.
const IndustrySpec * is = GetIndustrySpec ( it ) ;
SetDParam ( 0 , is - > name ) ;
ShowErrorMessage ( STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES , STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION , WL_WARNING ) ;
count + + ;
if ( count > = 3 ) break ; // Don't swamp the user with errors.
}
}
2011-01-18 23:31:06 +01:00
/**
* Is an industry with the spec a raw industry ?
* @ return true if it should be handled as a raw industry
*/
2007-07-07 00:33:16 +02:00
bool IndustrySpec : : IsRawIndustry ( ) const
{
2012-09-08 14:14:00 +02:00
return ( this - > life_type & ( INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC ) ) ! = 0 ;
}
/**
* Is an industry with the spec a processing industry ?
* @ return true if it should be handled as a processing industry
*/
bool IndustrySpec : : IsProcessingIndustry ( ) const
{
/* Lumber mills are neither raw nor processing */
return ( this - > life_type & INDUSTRYLIFE_PROCESSING ) ! = 0 & &
2007-07-07 00:33:16 +02:00
( this - > behaviour & INDUSTRYBEH_CUT_TREES ) = = 0 ;
}
2011-01-18 23:31:06 +01:00
/**
* Get the cost for constructing this industry
* @ return the cost ( inflation corrected etc )
*/
2007-07-07 00:33:16 +02:00
Money IndustrySpec : : GetConstructionCost ( ) const
{
2009-11-24 23:15:42 +01:00
/* Building raw industries like secondary uses different price base */
return ( _price [ ( _settings_game . construction . raw_industry_construction = = 1 & & this - > IsRawIndustry ( ) ) ?
PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY ] * this - > cost_multiplier ) > > 8 ;
2007-07-07 00:33:16 +02:00
}
2007-11-27 18:13:49 +01:00
2011-01-18 23:31:06 +01:00
/**
* Get the cost for removing this industry
* Take note that the cost will always be zero for non - grf industries .
* Only if the grf author did specified a cost will it be applicable .
* @ return the cost ( inflation corrected etc )
*/
2007-11-27 18:13:49 +01:00
Money IndustrySpec : : GetRemovalCost ( ) const
{
2009-11-24 23:15:42 +01:00
return ( _price [ PR_CLEAR_INDUSTRY ] * this - > removal_cost_multiplier ) > > 8 ;
2007-11-27 18:13:49 +01:00
}
2007-07-07 00:33:16 +02:00
2011-01-18 23:31:06 +01:00
/**
2020-12-14 23:35:07 +01:00
* Determines whether this industrytype uses standard / newgrf production changes .
* @ return true if original economy is used .
2011-01-18 23:31:06 +01:00
*/
2020-12-14 23:35:07 +01:00
bool IndustrySpec : : UsesOriginalEconomy ( ) const
2010-09-26 13:04:30 +02:00
{
2020-12-14 23:35:07 +01:00
return _settings_game . economy . type = = ET_ORIGINAL | |
HasBit ( this - > callback_mask , CBM_IND_PRODUCTION_256_TICKS ) | | HasBit ( this - > callback_mask , CBM_IND_PRODUCTION_CARGO_ARRIVAL ) | | // production callbacks
HasBit ( this - > callback_mask , CBM_IND_MONTHLYPROD_CHANGE ) | | HasBit ( this - > callback_mask , CBM_IND_PRODUCTION_CHANGE ) | | HasBit ( this - > callback_mask , CBM_IND_PROD_CHANGE_BUILD ) ; // production change callbacks
2010-09-26 13:04:30 +02:00
}
2019-10-04 21:26:44 +02:00
IndustrySpec : : ~ IndustrySpec ( )
{
if ( HasBit ( this - > cleanup_flag , CLEAN_RANDOMSOUNDS ) ) {
free ( this - > random_sounds ) ;
}
}
2011-11-04 12:36:10 +01:00
static CommandCost TerraformTile_Industry ( TileIndex tile , DoCommandFlag flags , int z_new , Slope tileh_new )
2007-08-30 19:17:04 +02:00
{
2007-09-15 00:27:40 +02:00
if ( AutoslopeEnabled ( ) ) {
/* We imitate here TTDP's behaviour:
* - Both new and old slope must not be steep .
* - TileMaxZ must not be changed .
* - Allow autoslope by default .
* - Disallow autoslope if callback succeeds and returns non - zero .
*/
2011-11-04 11:22:27 +01:00
Slope tileh_old = GetTileSlope ( tile ) ;
2007-09-15 00:27:40 +02:00
/* TileMaxZ must not be changed. Slopes must not be steep. */
2011-11-04 11:30:10 +01:00
if ( ! IsSteepSlope ( tileh_old ) & & ! IsSteepSlope ( tileh_new ) & & ( GetTileMaxZ ( tile ) = = z_new + GetSlopeMaxZ ( tileh_new ) ) ) {
2007-09-15 00:27:40 +02:00
const IndustryGfx gfx = GetIndustryGfx ( tile ) ;
const IndustryTileSpec * itspec = GetIndustryTileSpec ( gfx ) ;
/* Call callback 3C 'disable autosloping for industry tiles'. */
2009-09-14 14:22:57 +02:00
if ( HasBit ( itspec - > callback_mask , CBM_INDT_AUTOSLOPE ) ) {
2007-09-15 00:27:40 +02:00
/* If the callback fails, allow autoslope. */
2023-05-08 19:01:06 +02:00
uint16_t res = GetIndustryTileCallback ( CBID_INDTILE_AUTOSLOPE , 0 , 0 , gfx , Industry : : GetByTile ( tile ) , tile ) ;
2011-11-08 18:26:49 +01:00
if ( res = = CALLBACK_FAILED | | ! ConvertBooleanCallback ( itspec - > grf_prop . grffile , CBID_INDTILE_AUTOSLOPE , res ) ) return CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_FOUNDATION ] ) ;
2007-09-15 00:27:40 +02:00
} else {
2007-11-15 23:20:33 +01:00
/* allow autoslope */
2009-11-24 23:15:42 +01:00
return CommandCost ( EXPENSES_CONSTRUCTION , _price [ PR_BUILD_FOUNDATION ] ) ;
2007-09-15 00:27:40 +02:00
}
}
}
2021-11-21 23:02:29 +01:00
return Command < CMD_LANDSCAPE_CLEAR > : : Do ( flags , tile ) ;
2007-08-30 19:17:04 +02:00
}
2007-07-07 00:33:16 +02:00
2007-01-10 19:56:51 +01:00
extern const TileTypeProcs _tile_type_industry_procs = {
2009-03-15 01:32:18 +01:00
DrawTile_Industry , // draw_tile_proc
2011-11-04 11:18:13 +01:00
GetSlopePixelZ_Industry , // get_slope_z_proc
2009-03-15 01:32:18 +01:00
ClearTile_Industry , // clear_tile_proc
2009-06-25 21:23:09 +02:00
AddAcceptedCargo_Industry , // add_accepted_cargo_proc
2009-03-15 01:32:18 +01:00
GetTileDesc_Industry , // get_tile_desc_proc
GetTileTrackStatus_Industry , // get_tile_track_status_proc
ClickTile_Industry , // click_tile_proc
AnimateTile_Industry , // animate_tile_proc
TileLoop_Industry , // tile_loop_proc
ChangeTileOwner_Industry , // change_tile_owner_proc
2019-04-10 23:07:06 +02:00
nullptr , // add_produced_cargo_proc
nullptr , // vehicle_enter_tile_proc
2009-03-15 01:32:18 +01:00
GetFoundation_Industry , // get_foundation_proc
TerraformTile_Industry , // terraform_tile_proc
2004-08-09 19:04:08 +02:00
} ;
2019-02-24 20:16:24 +01:00
2022-02-19 19:08:23 +01:00
bool IndustryCompare : : operator ( ) ( const IndustryListEntry & lhs , const IndustryListEntry & rhs ) const
2019-02-24 20:16:24 +01:00
{
2022-02-19 19:08:23 +01:00
/* Compare by distance first and use index as a tiebreaker. */
return std : : tie ( lhs . distance , lhs . industry - > index ) < std : : tie ( rhs . distance , rhs . industry - > index ) ;
2019-02-24 20:16:24 +01:00
}
2023-07-14 12:49:11 +02:00
/**
* Remove unused industry accepted / produced slots - - entries after the last slot with valid cargo .
* @ param ind Industry to trim slots .
*/
void TrimIndustryAcceptedProduced ( Industry * ind )
{
auto ita = std : : find_if ( std : : rbegin ( ind - > accepted ) , std : : rend ( ind - > accepted ) , [ ] ( const auto & a ) { return IsValidCargoID ( a . cargo ) ; } ) ;
ind - > accepted . erase ( ita . base ( ) , std : : end ( ind - > accepted ) ) ;
ind - > accepted . shrink_to_fit ( ) ;
auto itp = std : : find_if ( std : : rbegin ( ind - > produced ) , std : : rend ( ind - > produced ) , [ ] ( const auto & p ) { return IsValidCargoID ( p . cargo ) ; } ) ;
ind - > produced . erase ( itp . base ( ) , std : : end ( ind - > produced ) ) ;
ind - > produced . shrink_to_fit ( ) ;
}