diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2fd749087a..0086358db1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1 @@ -blank_issues_enabled: false -contact_links: -- name: Suggestions and ideas? - url: https://www.tt-forums.net/viewforum.php?f=32 - about: Have a suggestion or an idea for a cool new feature? Post them on our forum! +blank_issues_enabled: true diff --git a/.ottdrev-vc b/.ottdrev-vc index b5f76052e1..646fc638c7 100644 --- a/.ottdrev-vc +++ b/.ottdrev-vc @@ -1,2 +1,2 @@ -jgrpp-0.43.1 20211004 0 fe8da3ae3a190cff0a9dcc552fe0825ca28c5850 1 0 2021 -fbeb6b45e2e75ab56dd72ed06410f90827a489b5cf6b3236f3605b51c5747bdc - +jgrpp-0.43.2 20211029 0 6bc3481931dabe2b72a2781e985922c6fecd7763 1 0 2021 +3a352dd8343555b193b112845a82173b65aee14cc6764c51dfe1f6bc8fd25d7b - diff --git a/README.md b/README.md index 56a74337ce..71d549bcc2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## JGR's Patchpack version 0.43.1 +## JGR's Patchpack version 0.43.2 This is a collection of patches applied to [OpenTTD](http://www.openttd.org/) diff --git a/jgrpp-changelog.md b/jgrpp-changelog.md index 27ba1d612c..bccccfb2ed 100644 --- a/jgrpp-changelog.md +++ b/jgrpp-changelog.md @@ -2,6 +2,20 @@ * * * +### v0.43.2 (2021-10-29) +* Fix crash when using the ignore signals button to sent a train the wrong-way on a signalled tunnel or bridge. +* Fix multiplayer desync when using "perfect" tree placement mode in arctic climate. +* Fix aircraft shadows being drawn facing the wrong direction. +* Fix timetabled 0 wait times not being shown for stations/depots in the timetable window. +* Add settings for minimum contiguous landmass size for town and city placement. +* Add current day and current month routing restriction conditionals. +* Add current day and current month conditional orders. +* Company bankruptcy: + * When declining to buy a company, ask the next company immediately instead of after the time period expires. + * Do not wait for companies which have no connected clients to buy a company. + * Add console command to offer a company for sale. +* Add Korean translations by TELK. + ### v0.43.1 (2021-10-04) * Fix multi-aspect signal graphics not being immediately enabled for newly generated maps. * Fix premature PBS reservations with using reverse at waypoint orders with timetabled wait times. diff --git a/src/3rdparty/cpp-btree/btree.h b/src/3rdparty/cpp-btree/btree.h index ddea9e0282..2be24691d0 100644 --- a/src/3rdparty/cpp-btree/btree.h +++ b/src/3rdparty/cpp-btree/btree.h @@ -917,8 +917,7 @@ class btree : public Params::key_compare { typedef std::reverse_iterator reverse_iterator; typedef typename Params::allocator_type allocator_type; - typedef typename allocator_type::template rebind::other - internal_allocator_type; + using internal_allocator_type = typename std::allocator_traits::template rebind_alloc; public: // Default constructor. diff --git a/src/aircraft.h b/src/aircraft.h index c44d02f041..9e9d3106ed 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -96,6 +96,7 @@ struct Aircraft FINAL : public SpecializedVehicle { ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); } void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; + Direction GetMapImageDirection() const { return this->First()->direction; } int GetDisplaySpeed() const { return this->cur_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; } diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 00716a34b0..20113f768f 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -172,6 +172,22 @@ static StationID FindNearestHangar(const Aircraft *v) void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { + if (this->subtype == AIR_SHADOW) { + Aircraft *first = this->First(); + if (first->cur_image_valid_dir != direction || HasBit(first->vcache.cached_veh_flags, VCF_IMAGE_REFRESH)) { + VehicleSpriteSeq seq; + first->UpdateImageState(direction, seq); + if (first->sprite_seq != seq) { + first->sprite_seq = seq; + first->UpdateSpriteSeqBound(); + first->Vehicle::UpdateViewport(true); + } + } + + result->CopyWithoutPalette(first->sprite_seq); // the shadow is never coloured + return; + } + uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { @@ -552,10 +568,8 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z) safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); - u->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured - u->sprite_seq_bounds = v->sprite_seq_bounds; - - u->UpdatePositionAndViewport(); + u->UpdatePosition(); + u->UpdateViewport(true, false); u = u->Next(); if (u != nullptr) { @@ -1364,7 +1378,7 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station) void Aircraft::MarkDirty() { this->colourmap = PAL_NONE; - this->InvalidateImageCache(); + this->InvalidateImageCacheOfChain(); this->UpdateViewport(true, false); if (this->subtype == AIR_HELICOPTER) { Aircraft *rotor = this->Next()->Next(); diff --git a/src/command.cpp b/src/command.cpp index 7dd81541b6..7843339b28 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -144,6 +144,7 @@ CommandProc CmdPause; CommandProc CmdBuyShareInCompany; CommandProc CmdSellShareInCompany; CommandProc CmdBuyCompany; +CommandProc CmdDeclineBuyCompany; CommandProc CmdFoundTown; CommandProc CmdRenameTown; @@ -380,7 +381,8 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdBuyShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_SHARE_IN_COMPANY DEF_CMD(CmdSellShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_SELL_SHARE_IN_COMPANY - DEF_CMD(CmdBuyCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_COMANY + DEF_CMD(CmdBuyCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_COMPANY + DEF_CMD(CmdDeclineBuyCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_DECLINE_BUY_COMPANY DEF_CMD(CmdFoundTown, CMD_DEITY | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_FOUND_TOWN; founding random town can fail only in exec run DEF_CMD(CmdRenameTown, CMD_DEITY | CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_TOWN diff --git a/src/command_type.h b/src/command_type.h index b7b29cde0a..073888428b 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -322,6 +322,7 @@ enum Commands { CMD_BUY_SHARE_IN_COMPANY, ///< buy a share from a company CMD_SELL_SHARE_IN_COMPANY, ///< sell a share from a company CMD_BUY_COMPANY, ///< buy a company which is bankrupt + CMD_DECLINE_BUY_COMPANY, ///< decline to buy a company which is bankrupt CMD_FOUND_TOWN, ///< found a town CMD_RENAME_TOWN, ///< rename a town diff --git a/src/company_base.h b/src/company_base.h index 0d2e0621b8..dc046eb907 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -81,6 +81,7 @@ struct CompanyProperties { Year inaugurated_year; ///< Year of starting the company. byte months_of_bankruptcy; ///< Number of months that the company is unable to pay its debts + CompanyID bankrupt_last_asked; ///< Which company was most recently asked about buying it? CompanyMask bankrupt_asked; ///< which companies were asked about buying it? int16 bankrupt_timeout; ///< If bigger than \c 0, amount of time to wait for an answer on an offer to buy this company. Money bankrupt_value; @@ -107,7 +108,7 @@ struct CompanyProperties { : name_2(0), name_1(0), president_name_1(0), president_name_2(0), face(0), money(0), money_fraction(0), current_loan(0), colour(0), block_preview(0), location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), - months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), + months_of_bankruptcy(0), bankrupt_last_asked(INVALID_COMPANY), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), terraform_limit(0), clear_limit(0), tree_limit(0), purchase_land_limit(0), build_object_limit(0), is_ai(false) {} }; diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 929d6db175..f525cd4521 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -37,6 +37,7 @@ #include "zoning.h" #include "tbtr_template_vehicle_func.h" #include "widgets/statusbar_widget.h" +#include "core/backup_type.hpp" #include "debug_desync.h" #include "table/strings.h" @@ -707,12 +708,18 @@ static void HandleBankruptcyTakeover(Company *c) } SetBit(c->bankrupt_asked, best->index); + c->bankrupt_last_asked = best->index; c->bankrupt_timeout = TAKE_OVER_TIMEOUT; if (best->is_ai) { AI::NewEvent(best->index, new ScriptEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value))); } else if (IsInteractiveCompany(best->index)) { ShowBuyCompanyDialog(c->index); + } else if (!_networking || (_network_server && !NetworkCompanyHasClients(best->index))) { + /* This company can never accept the offer as there are no clients connected, decline the offer on the company's behalf */ + Backup cur_company(_current_company, best->index, FILE_LINE); + DoCommandP(0, c->index, 0, CMD_DECLINE_BUY_COMPANY); + cur_company.Restore(); } } @@ -942,6 +949,18 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 break; } + case CCA_SALE: { + Company *c = Company::GetIfValid(company_id); + if (c == nullptr) return CMD_ERROR; + + if (!(flags & DC_EXEC)) return CommandCost(); + + c->bankrupt_value = CalculateCompanyValue(c, false); + c->bankrupt_asked = 1 << c->index; // Don't ask the owner + c->bankrupt_timeout = 0; + break; + } + default: return CMD_ERROR; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 303b58ee44..37ab10a947 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2791,6 +2791,14 @@ struct BuyCompanyWindow : Window { this->InitNested(window_number); } + ~BuyCompanyWindow() + { + const Company *c = Company::GetIfValid((CompanyID)this->window_number); + if (c != nullptr && HasBit(c->bankrupt_asked, _current_company)) { + DoCommandP(0, this->window_number, 0, CMD_DECLINE_BUY_COMPANY); + } + } + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { diff --git a/src/company_type.h b/src/company_type.h index de2556b914..740663a4cf 100644 --- a/src/company_type.h +++ b/src/company_type.h @@ -65,6 +65,7 @@ enum CompanyCtrlAction { CCA_NEW, ///< Create a new company. CCA_NEW_AI, ///< Create a new AI company. CCA_DELETE, ///< Delete a company. + CCA_SALE, ///< Offer a company for sale. CCA_END, ///< Sentinel for end. }; diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 14670b3e72..563d59b681 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -964,6 +964,30 @@ DEF_CONSOLE_CMD(ConResetCompany) return true; } +DEF_CONSOLE_CMD(ConOfferCompanySale) +{ + if (argc == 0) { + IConsoleHelp("Offer a company for sale. Usage: 'offer_company_sale '"); + IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc."); + return true; + } + + if (argc != 2) return false; + + CompanyID index = (CompanyID)(atoi(argv[1]) - 1); + + /* Check valid range */ + if (!Company::IsValidID(index)) { + IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES); + return true; + } + + DoCommandP(0, CCA_SALE | index << 16, 0, CMD_COMPANY_CTRL); + IConsolePrint(CC_DEFAULT, "Company offered for sale."); + + return true; +} + DEF_CONSOLE_CMD(ConNetworkClients) { if (argc == 0) { @@ -3418,6 +3442,7 @@ void IConsoleStdLibRegister() IConsole::CmdRegister("move", ConMoveClient, ConHookServerOnly); IConsole::CmdRegister("reset_company", ConResetCompany, ConHookServerOnly); IConsole::AliasRegister("clean_company", "reset_company %A"); + IConsole::CmdRegister("offer_company_sale", ConOfferCompanySale, ConHookServerOrNoNetwork); IConsole::CmdRegister("client_name", ConClientNickChange, ConHookServerOnly); IConsole::CmdRegister("kick", ConKick, ConHookServerOnly); IConsole::CmdRegister("ban", ConBan, ConHookServerOnly); diff --git a/src/economy.cpp b/src/economy.cpp index 7b64fb5853..1b23a92538 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -2285,6 +2285,8 @@ static void DoAcquireCompany(Company *c) if (c->is_ai) AI::Stop(c->index); + c->bankrupt_asked = 0; + DeleteCompanyWindows(ci); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); InvalidateWindowClassesData(WC_TRACE_RESTRICT_SLOTS, 0); @@ -2429,6 +2431,31 @@ CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 return cost; } +/** + * Decline to buy up another company. + * When a competing company is gone bankrupt you get the chance to purchase + * that company, actively decline the offer. + * @param tile unused + * @param flags type of operation + * @param p1 company to buy up + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDeclineBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + CompanyID target_company = (CompanyID)p1; + Company *c = Company::GetIfValid(target_company); + if (c == nullptr) return CommandCost(); + + if (flags & DC_EXEC) { + if (c->bankrupt_last_asked == _current_company) { + c->bankrupt_timeout = 0; + } + } + return CommandCost(); +} + uint ScaleQuantity(uint amount, int scale_factor) { scale_factor += 200; // ensure factor is positive diff --git a/src/lang/english.txt b/src/lang/english.txt index 06fa07ed13..e2b917afb9 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1939,6 +1939,12 @@ STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR :Industry cargo STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR_HELPTEXT :Primary industry cargo production is scaled by approximately 2^factor (exponential). This excludes tree-cutting industries.{}This is not guaranteed to be fully compatible with all industry NewGRFs. STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT :No towns above height level: {STRING2} STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT_HELPTEXT :No towns above the specified height level are built during map creation. +STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA :Minimum contiguous land area for towns: {STRING2} +STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA_HELPTEXT :Towns can only be placed on contiguous landmasses of at least this many tiles. +STR_CONFIG_SETTING_MIN_CITY_LAND_AREA :Minimum contiguous land area for cities: {STRING2} +STR_CONFIG_SETTING_MIN_CITY_LAND_AREA_HELPTEXT :Cities can only be placed on contiguous landmasses of at least this many tiles. +STR_CONFIG_SETTING_MIN_LAND_AREA_VALUE :{NUM} +STR_CONFIG_SETTING_MIN_LAND_AREA_ZERO :Off STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In game placement of trees: {STRING2} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills @@ -3075,12 +3081,18 @@ STR_TRACE_RESTRICT_NO_PBS_BACK_PENALTY_CANCEL_SHORT :Cancel no PBS b STR_TRACE_RESTRICT_TIME_MINUTE :current minute (0 - 59) STR_TRACE_RESTRICT_TIME_HOUR :current hour (0 - 23) STR_TRACE_RESTRICT_TIME_HOUR_MINUTE :current hour and minute (0 - 2359) +STR_TRACE_RESTRICT_TIME_DAY :current day (1 - 31) +STR_TRACE_RESTRICT_TIME_MONTH :current month (1 - 12) STR_TRACE_RESTRICT_TIME_MINUTE_ITEM :current minute STR_TRACE_RESTRICT_TIME_HOUR_ITEM :current hour STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_ITEM :current hour and minute +STR_TRACE_RESTRICT_TIME_DAY_ITEM :current day +STR_TRACE_RESTRICT_TIME_MONTH_ITEM :current month STR_TRACE_RESTRICT_TIME_MINUTE_SHORT :minute STR_TRACE_RESTRICT_TIME_HOUR_SHORT :hour STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_SHORT :hour and minute +STR_TRACE_RESTRICT_TIME_DAY_ITEM_SHORT :day +STR_TRACE_RESTRICT_TIME_MONTH_ITEM_SHORT :month STR_TRACE_RESTRICT_TIMETABLE_LATENESS :lateness STR_TRACE_RESTRICT_TIMETABLE_EARLINESS :earliness STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}Value diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 473383d747..a9bb75b857 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -306,12 +306,13 @@ STR_SORT_BY_LENGTH :길이 STR_SORT_BY_LIFE_TIME :남은 수명 STR_SORT_BY_TIMETABLE_DELAY :시간표 지연 STR_SORT_BY_AVG_ORDER_OCCUPANCY :평균 경로 사용률 +STR_SORT_BY_MAX_SPEED_LOADED :최대 속력 (가득) STR_SORT_BY_FACILITY :역 종류 STR_SORT_BY_WAITING_TOTAL :전체 대기 화물량 STR_SORT_BY_WAITING_AVAILABLE :사용 가능한 대기 화물량 STR_SORT_BY_RATING_MAX :높은 화물 등급 STR_SORT_BY_RATING_MIN :낮은 화물 등급 -STR_SORT_BY_VEHICLES_CALLING :호출 차량 수 +STR_SORT_BY_VEHICLES_CALLING :정차 차량 수 STR_SORT_BY_ENGINE_ID :차량ID (기본 정렬) STR_SORT_BY_COST :가격 STR_SORT_BY_POWER :힘 @@ -614,7 +615,7 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}화물 STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}이 화물에 대한 그래프 켜기/끄기 STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} -STR_GRAPH_STATION_CARGO_CAPTION :{WHITE}{STATION} - 대기 화물량 내력 +STR_GRAPH_STATION_CARGO_CAPTION :{WHITE}{STATION} - 대기 화물량 이력 STR_GRAPH_STATION_CARGO_X_LABEL :{TINY_FONT}{BLACK}{NUM}일 동안의 변동 사항 STR_GRAPH_STATION_CARGO_TITLE :{TINY_FONT}{BLACK}역에서 있던 화물량 @@ -1938,6 +1939,12 @@ STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR :산업시설 STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR_HELPTEXT :1차 산업시설이 생산하는 화물의 양을 2^(생성 계수)에 근접하게 조절합니다. 나무를 베는 산업시설에는 적용되지 않습니다.{}모든 산업시설 관련 NewGRF와 모두 호환되지는 않을 수 있습니다. STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT :이 고도 위에는 도시를 생성하지 않음: {STRING} STR_CONFIG_SETTING_TOWN_ABOVE_HEIGHT_HELPTEXT :지도를 생성할 때 특정 고도 위에는 도시를 만들지 않도록 만듭니다. +STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA :도시에 필요한 최소 평지 영역: {STRING} +STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA_HELPTEXT :도시를 배치하려면 최소한 이만큼의 평지가 필요합니다. +STR_CONFIG_SETTING_MIN_CITY_LAND_AREA :대도시에 필요한 최소 평지 영역: {STRING} +STR_CONFIG_SETTING_MIN_CITY_LAND_AREA_HELPTEXT :대도시를 배치하려면 최소한 이만큼의 평지가 필요합니다. +STR_CONFIG_SETTING_MIN_LAND_AREA_VALUE :{NUM} +STR_CONFIG_SETTING_MIN_LAND_AREA_ZERO :끄기 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :나무의 성장과 확장: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :게임 플레이 중 나무의 성장과 확장 여부를 조절합니다. 이 설정을 조정하면, 아열대 기후의 벌목소처럼 나무의 성장에 의존하는 산업시설에 영향을 끼칠 수 있습니다. @@ -2064,6 +2071,7 @@ STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO :이 화물에 STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_PARAM :{STRING}에 대한 화물 분배 형식 덮어쓰기: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_HELPTEXT :"(기본)"은 이 화물 종류에 대한 기본 화물 분배 형식을 따른다는 뜻입니다. "대칭"은 대체로 A역에서 B역으로 가려는 화물의 수가 B에서 A로 가려는 화물의 수와 대체로 같다는 뜻입니다. "비대칭"은 아무 방향이나 임의의 양만큼 가게 됨을 뜻합니다. "수동"은 자동적인 화물 분배가 일어나지 않고 기존 방식을 사용하겠음을 뜻합니다. STR_CONFIG_SETTING_DISTRIBUTION_PER_CARGO_DEFAULT :(기본) +STR_CONFIG_SETTING_DISTRIBUTION_HELPTEXT_EXTRA :{STRING}{}"비대칭 (동일 분포)"는 화물을 받는 각 역이 전체적으로 거의 비슷한 양의 화물을 받도록 분배된다는 뜻입니다. "비대칭 (최근접)"은 그 화물을 받을 수 있는 가장 가까운 역으로 화물을 분배한다는 뜻입니다. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :분배 정확도: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :값이 높으면 높을수록 CPU가 연결 상태를 계산하는 시간이 더 오래 걸립니다. 만약 이 시간이 너무 오래 걸리면 게임이 버벅일 것입니다. 하지만, 낮은 값으로 설정하면 분배가 부정확하게 일어나서, 화물이 원하는 곳으로 분배되지 않을 수 있습니다. STR_CONFIG_SETTING_DEMAND_DISTANCE :거리에 따른 수요 효과: {STRING} @@ -3073,12 +3081,18 @@ STR_TRACE_RESTRICT_NO_PBS_BACK_PENALTY_CANCEL_SHORT :(취소) 후방 STR_TRACE_RESTRICT_TIME_MINUTE :현재 분(0 - 59) STR_TRACE_RESTRICT_TIME_HOUR :현재 시(0 - 23) STR_TRACE_RESTRICT_TIME_HOUR_MINUTE :현재 시&분(0 - 2359) +STR_TRACE_RESTRICT_TIME_DAY :현재 일(1 - 31) +STR_TRACE_RESTRICT_TIME_MONTH :현재 월(1 - 12) STR_TRACE_RESTRICT_TIME_MINUTE_ITEM :현재 분 STR_TRACE_RESTRICT_TIME_HOUR_ITEM :현재 시 STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_ITEM :현재 시&분 +STR_TRACE_RESTRICT_TIME_DAY_ITEM :현재 일 +STR_TRACE_RESTRICT_TIME_MONTH_ITEM :현재 월 STR_TRACE_RESTRICT_TIME_MINUTE_SHORT :분 STR_TRACE_RESTRICT_TIME_HOUR_SHORT :시 STR_TRACE_RESTRICT_TIME_HOUR_MINUTE_SHORT :시분 +STR_TRACE_RESTRICT_TIME_DAY_ITEM_SHORT :일 +STR_TRACE_RESTRICT_TIME_MONTH_ITEM_SHORT :월 STR_TRACE_RESTRICT_TIMETABLE_LATENESS :지연 STR_TRACE_RESTRICT_TIMETABLE_EARLINESS :조착 STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}값 @@ -4205,8 +4219,8 @@ STR_STATION_VIEW_GROUP_D_V_S :도착-경유- STR_STATION_VIEW_DEPARTURES_BUTTON :{BLACK}출발/도착 정보 STR_STATION_VIEW_DEPARTURES_TOOLTIP :{BLACK}출발/도착 정보를 보여줍니다 -STR_STATION_VIEW_HISTORY_BUTTON :{BLACK}화물량 내력 -STR_STATION_VIEW_HISTORY_TOOLTIP :{BLACK}대기 화물량 내력을 보여줍니다 +STR_STATION_VIEW_HISTORY_BUTTON :{BLACK}화물량 이력 +STR_STATION_VIEW_HISTORY_TOOLTIP :{BLACK}대기 화물량 이력을 보여줍니다 ############ range for rating starts STR_CARGO_RATING_APPALLING :형편없음 @@ -6599,7 +6613,7 @@ STR_ZONING_OUTER_INFO :{BLACK}바깥 STR_ZONING_INNER_INFO :{BLACK}안쪽 타일 테두리를 표시할 기준을 선택하세요. STR_ZONING_NO_ZONING :표시 안함 -STR_ZONING_AUTHORITY :권한 +STR_ZONING_AUTHORITY :당국 STR_ZONING_CAN_BUILD :건설 불가 지역 STR_ZONING_STA_CATCH :역세권 STR_ZONING_STA_CATCH_OPEN :역세권 (창이 열린 역만) diff --git a/src/map.cpp b/src/map.cpp index 49b16b642f..4778fd9c5a 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -16,6 +16,7 @@ #include "tunnelbridge_map.h" #include "3rdparty/cpp-btree/btree_map.h" #include +#include #include "safeguards.h" @@ -370,6 +371,58 @@ bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOn return false; } +/** + * Generalized contiguous matching tile area size threshold function. + * Contiguous means directly adjacent by DiagDirection directions. + * + * @param tile to start the search from. + * @param threshold minimum number of matching tiles for success, searching is halted when this is reached. + * @param proc callback testing function pointer. + * @param user_data to be passed to the callback function. Depends on the implementation + * @return whether the contiguous tile area size is >= threshold + * @pre proc != nullptr + */ +bool EnoughContiguousTilesMatchingCondition(TileIndex tile, uint threshold, TestTileOnSearchProc proc, void *user_data) +{ + assert(proc != nullptr); + if (threshold == 0) return true; + + static_assert(MAX_MAP_TILES_BITS <= 30); + + btree::btree_set processed_tiles; + std::deque candidates; + uint matching_count = 0; + + auto process_tile = [&](TileIndex t, DiagDirection exclude_onward_dir) { + auto iter = processed_tiles.lower_bound(t); + if (iter != processed_tiles.end() && *iter == t) { + /* done this tile already */ + } else { + if (proc(t, user_data)) { + matching_count++; + for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { + if (dir == exclude_onward_dir) continue; + TileIndex neighbour_tile = AddTileIndexDiffCWrap(t, TileIndexDiffCByDiagDir(dir)); + if (IsValidTile(neighbour_tile)) { + candidates.push_back(neighbour_tile | (ReverseDiagDir(dir) << 30)); + } + } + } + processed_tiles.insert(iter, t); + } + }; + process_tile(tile, INVALID_DIAGDIR); + + while (matching_count < threshold && !candidates.empty()) { + uint32 next = candidates.front(); + candidates.pop_front(); + TileIndex t = GB(next, 0, 30); + DiagDirection exclude_onward_dir = (DiagDirection)GB(next, 30, 2); + process_tile(t, exclude_onward_dir); + } + return matching_count >= threshold; +} + /** * Finds the distance for the closest tile with water/land given a tile * @param tile the tile to find the distance too diff --git a/src/map_func.h b/src/map_func.h index eebd21fb67..616c972f03 100644 --- a/src/map_func.h +++ b/src/map_func.h @@ -438,6 +438,8 @@ typedef bool TestTileOnSearchProc(TileIndex tile, void *user_data); bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data); bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data); +bool EnoughContiguousTilesMatchingCondition(TileIndex tile, uint threshold, TestTileOnSearchProc proc, void *user_data); + /** * Get a random tile out of a given seed. * @param r the random 'seed' diff --git a/src/network/core/packet.cpp b/src/network/core/packet.cpp index 97c69d7d8f..cef68c902e 100644 --- a/src/network/core/packet.cpp +++ b/src/network/core/packet.cpp @@ -423,7 +423,7 @@ void Packet::Recv_string(std::string &buffer, StringValidationSettings settings) size_t length = ttd_strnlen((const char *)(this->buffer.data() + this->pos), this->Size() - this->pos - 1); buffer.assign((const char *)(this->buffer.data() + this->pos), length); - this->pos += (uint)length + 1; + this->pos += (PacketSize)length + 1; StrMakeValidInPlace(buffer, settings); } diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 06a9dc7ab4..8fb00cc2f1 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -1115,7 +1115,11 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME /* Test if the server supports this option * and if we are at the frame the server is */ - if (p->pos + 1 < p->size) { +#ifdef NETWORK_SEND_DOUBLE_SEED + if (p->CanReadFromPacket(4 + 4 + 8)) { +#else + if (p->CanReadFromPacket(4 + 8)) { +#endif _sync_frame = _frame_counter_server; _sync_seed_1 = p->Recv_uint32(); #ifdef NETWORK_SEND_DOUBLE_SEED diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 19e19b2f75..db54a701c7 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -41,9 +41,6 @@ extern const uint8 _out_of_band_grf_md5[16] { 0x00, 0xB0, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00 }; -/** Mutex for all out threaded udp resolution and such. */ -static std::mutex _network_udp_mutex; - /** Session key to register ourselves to the master server */ static uint64 _session_key = 0; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index c0898f1936..caaa6932d6 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1338,10 +1338,10 @@ uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value) uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v) { const Engine *e = Engine::Get(engine); - if (property < 64 && !HasBit(e->cb36_properties_used, property)) return orig_value; + if (static_cast(property) < 64 && !HasBit(e->cb36_properties_used, property)) return orig_value; VehicleResolverObject object(engine, v, VehicleResolverObject::WO_UNCACHED, false, CBID_VEHICLE_MODIFY_PROPERTY, property, 0); - if (property < 64 && !e->sprite_group_cb36_properties_used.empty()) { + if (static_cast(property) < 64 && !e->sprite_group_cb36_properties_used.empty()) { auto iter = e->sprite_group_cb36_properties_used.find(object.root_spritegroup); if (iter != e->sprite_group_cb36_properties_used.end()) { if (!HasBit(iter->second, property)) return orig_value; diff --git a/src/newgrf_properties.h b/src/newgrf_properties.h index 835a873847..94dde722e7 100644 --- a/src/newgrf_properties.h +++ b/src/newgrf_properties.h @@ -15,7 +15,7 @@ * Names are formatted as PROP__ * @todo Currently the list only contains properties which are used more than once in the code. I.e. they are available for callback 0x36. */ -enum PropertyID { +enum PropertyID : byte { PROP_VEHICLE_LOAD_AMOUNT = 0x07, ///< Loading speed PROP_TRAIN_SPEED = 0x09, ///< Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h diff --git a/src/openttd.cpp b/src/openttd.cpp index dc4a47cf04..632cacad20 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1869,12 +1869,12 @@ void StateGameLoop() CallWindowGameTickEvent(); NewsLoop(); - cur_company.Restore(); for (Company *c : Company::Iterate()) { DEBUG_UPDATESTATECHECKSUM("Company: %u, Money: " OTTD_PRINTF64, c->index, (int64)c->money); UpdateStateChecksum(c->money); } + cur_company.Restore(); } if (_extra_aspects > 0) FlushDeferredAspectUpdates(); diff --git a/src/order_gui.cpp b/src/order_gui.cpp index c8c446df81..e74187a25e 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -757,6 +757,8 @@ static const StringID _order_time_date_dropdown[] = { STR_TRACE_RESTRICT_TIME_MINUTE, STR_TRACE_RESTRICT_TIME_HOUR, STR_TRACE_RESTRICT_TIME_HOUR_MINUTE, + STR_TRACE_RESTRICT_TIME_DAY, + STR_TRACE_RESTRICT_TIME_MONTH, INVALID_STRING_ID }; @@ -837,7 +839,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int if (timetable) { SetDParam(3, STR_EMPTY); - if (order->GetWaitTime() > 0) { + if (order->GetWaitTime() > 0 || order->IsWaitTimetabled()) { SetDParam(7, order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED); SetTimetableParams(8, order->GetWaitTime()); } @@ -890,7 +892,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } if (timetable) { - if (order->GetWaitTime() > 0) { + if (order->GetWaitTime() > 0 || order->IsWaitTimetabled()) { SetDParam(7, order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED); SetTimetableParams(8, order->GetWaitTime()); } @@ -2421,7 +2423,7 @@ public: case WID_O_COND_TIME_DATE: { ShowDropDownMenu(this, _order_time_date_dropdown, this->vehicle->GetOrder(this->OrderGetSel())->GetConditionValue(), - WID_O_COND_TIME_DATE, 0, 0, UINT_MAX); + WID_O_COND_TIME_DATE, _settings_game.game_time.time_in_minutes ? 0 : 7, 0, UINT_MAX); break; } @@ -2481,7 +2483,6 @@ public: _order_conditional_variable[i] == OCV_COUNTER_VALUE) && !_settings_client.gui.show_adv_tracerestrict_features) { continue; } - if (_order_conditional_variable[i] == OCV_TIME_DATE && !_settings_game.game_time.time_in_minutes) continue; } list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + _order_conditional_variable[i], _order_conditional_variable[i], false)); } diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index e0d7c7e31c..a85ee0efb1 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -337,8 +337,10 @@ int GetCurrentThreadName(char *str, const char *last) return 0; } +#if !defined(NO_THREADS) static pthread_t main_thread; static pthread_t game_thread; +#endif void SetSelfAsMainThread() { diff --git a/src/road.cpp b/src/road.cpp index a7f0f804dd..ac6c025a41 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -941,18 +941,18 @@ void PostProcessNetworks(const std::vector>& town_n } std::vector towns(network->towns); - + for (auto town_a : network->towns) { std::sort(towns.begin(), towns.end(), [&](const TileIndex& a, const TileIndex& b) { return DistanceManhattan(a, town_a) < DistanceManhattan(b, town_a); }); - const auto second_clostest_town = *(towns.begin() + 2); - const auto third_clostest_town = *(towns.begin() + 3); + const auto second_closest_town = *(towns.begin() + 2); + const auto third_closest_town = *(towns.begin() + 3); AyStar finder {}; { - FindPath(finder, town_a, second_clostest_town); + FindPath(finder, town_a, second_closest_town); finder.Clear(); - FindPath(finder, town_a, third_clostest_town); + FindPath(finder, town_a, third_closest_town); } finder.Free(); diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index c0a3c80ac9..9bbca2c7fc 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -274,6 +274,7 @@ static const SaveLoad _company_desc[] = { SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8), SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), + SLE_CONDVAR_X(CompanyProperties, bankrupt_last_asked, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_BANKRUPTCY_EXTRA)), SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SLV_104), SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, SLV_104, SL_MAX_VERSION), SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16), diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 108bdcd957..37afb00c9f 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -75,7 +75,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TRACE_RESTRICT_REVERSE, XSCF_NULL, 1, 1, "tracerestrict_reverse", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_NEWSCTRL,XSCF_NULL, 1, 1, "tracerestrict_newsctrl", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_COUNTER, XSCF_NULL, 1, 1, "tracerestrict_counter", nullptr, nullptr, "TRRC" }, - { XSLFI_TRACE_RESTRICT_TIMEDATE,XSCF_NULL, 1, 1, "tracerestrict_timedate", nullptr, nullptr, nullptr }, + { XSLFI_TRACE_RESTRICT_TIMEDATE,XSCF_NULL, 2, 2, "tracerestrict_timedate", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_BRKCND, XSCF_NULL, 2, 2, "tracerestrict_braking_cond",nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_CTGRYCND,XSCF_NULL, 1, 1, "tracerestrict_ctgry_cond", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_PENCTRL, XSCF_NULL, 1, 1, "tracerestrict_pfpenctrl", nullptr, nullptr, nullptr }, @@ -95,7 +95,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_INFRA_SHARING, XSCF_NULL, 2, 2, "infra_sharing", nullptr, nullptr, "CPDP" }, { XSLFI_VARIABLE_DAY_LENGTH, XSCF_NULL, 2, 2, "variable_day_length", nullptr, nullptr, nullptr }, { XSLFI_ORDER_OCCUPANCY, XSCF_NULL, 2, 2, "order_occupancy", nullptr, nullptr, nullptr }, - { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 10, 10, "more_cond_orders", nullptr, nullptr, nullptr }, + { XSLFI_MORE_COND_ORDERS, XSCF_NULL, 11, 11, "more_cond_orders", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", nullptr, nullptr, nullptr }, { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr }, @@ -156,6 +156,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, + { XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 1, 1, "bankruptcy_extra", nullptr, nullptr, nullptr }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index d42986dcce..200f668e20 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -110,6 +110,7 @@ enum SlXvFeatureIndex { XSLFI_EXTRA_STATION_NAMES, ///< Extra station names XSLFI_DEPOT_ORDER_EXTRA_FLAGS, ///< Depot order extra flags XSLFI_EXTRA_SIGNAL_TYPES, ///< Extra signal types + XSLFI_BANKRUPTCY_EXTRA, ///< Extra company bankruptcy fields XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 2ada54cb99..55a8d2f2aa 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -801,7 +801,9 @@ void SlSetLength(size_t length) * * If we have more than 28 bits, use an extra uint32 and * signal this using the extended chunk header */ +#ifdef POINTER_IS_64BIT assert(length < (1LL << 32)); +#endif if (length >= (1 << 28)) { /* write out extended chunk header */ SlWriteByte(CH_EXT_HDR); diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 968b216375..4704b08ae8 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -1240,7 +1240,7 @@ static byte GetIndustryValue(TileIndex tile) case MP_INDUSTRY: { const IndustryType industry_type = Industry::GetByTile(tile)->type; - return GetIndustrySpec(industry_type)->map_colour * static_cast(0x01010101); + return GetIndustrySpec(industry_type)->map_colour; } default: return MKCOLOUR(GREY_SCALE(2)); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 06b3629268..a654a2ff38 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -2054,6 +2054,8 @@ static SettingsContainer &GetSettingsTree() genworld->Add(new SettingEntry("economy.town_layout")); genworld->Add(new SettingEntry("economy.town_min_distance")); genworld->Add(new SettingEntry("economy.max_town_heightlevel")); + genworld->Add(new SettingEntry("economy.min_town_land_area")); + genworld->Add(new SettingEntry("economy.min_city_land_area")); genworld->Add(new SettingEntry("game_creation.build_public_roads")); genworld->Add(new SettingEntry("difficulty.industry_density")); genworld->Add(new SettingEntry("gui.pause_on_newgame")); diff --git a/src/settings_type.h b/src/settings_type.h index fbb44beab6..a76b8f690f 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -641,6 +641,8 @@ struct EconomySettings { bool allow_town_roads; ///< towns are allowed to build roads (always allowed when generating world / in SE) uint16 town_min_distance; ///< minimum distance between towns uint8 max_town_heightlevel; ///< maximum height level for towns + uint16 min_town_land_area; ///< minimum contiguous lang area for towns. + uint16 min_city_land_area; ///< minimum contiguous lang area for cities. TownFounding found_town; ///< town founding. bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance) diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 5fa8c129e5..510b87ed41 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -92,10 +92,26 @@ class NIHVehicle : public NIHelper { /* virtual */ void ExtraInfo(uint index, std::function print) const override { - char buffer[1024]; + Vehicle *v = Vehicle::Get(index); print("Debug Info:"); - seprintf(buffer, lastof(buffer), " Index: %u", index); + this->VehicleInfo(v, print, true); + if (v->type == VEH_AIRCRAFT) { + print(""); + print("Shadow:"); + this->VehicleInfo(v->Next(), print, false); + if (v->Next()->Next() != nullptr) { + print(""); + print("Rotor:"); + this->VehicleInfo(v->Next()->Next(), print, false); + } + } + } + + void VehicleInfo(Vehicle *v, std::function print, bool show_engine) const + { + char buffer[1024]; + seprintf(buffer, lastof(buffer), " Index: %u", v->index); print(buffer); char *b = buffer; b += seprintf(b, lastof(buffer), " Flags: "); @@ -112,8 +128,9 @@ class NIHVehicle : public NIHelper { seprintf(buffer, lastof(buffer), " VirtXYTile: %X (%u x %u)", vtile, TileX(vtile), TileY(vtile)); print(buffer); } - b = buffer + seprintf(buffer, lastof(buffer), " Position: %X, %X, %X", v->x_pos, v->y_pos, v->z_pos); + b = buffer + seprintf(buffer, lastof(buffer), " Position: %X, %X, %X, Direction: %d", v->x_pos, v->y_pos, v->z_pos, v->direction); if (v->type == VEH_TRAIN) seprintf(b, lastof(buffer), ", tile margin: %d", GetTileMarginInFrontOfTrain(Train::From(v))); + if (v->type == VEH_SHIP) seprintf(b, lastof(buffer), ", rotation: %d", Ship::From(v)->rotation); print(buffer); if (v->IsPrimaryVehicle()) { @@ -296,64 +313,67 @@ class NIHVehicle : public NIHelper { } } - seprintf(buffer, lastof(buffer), " Engine: %u", v->engine_type); - print(buffer); - const Engine *e = Engine::GetIfValid(v->engine_type); - if (e != nullptr) { - seprintf(buffer, lastof(buffer), " Callbacks: 0x%X, CB36 Properties: 0x" OTTD_PRINTFHEX64, - e->callbacks_used, e->cb36_properties_used); + if (show_engine) { + seprintf(buffer, lastof(buffer), " Engine: %u", v->engine_type); print(buffer); - uint64 cb36_properties = e->cb36_properties_used; - if (!e->sprite_group_cb36_properties_used.empty()) { - const SpriteGroup *root_spritegroup = nullptr; - if (v->IsGroundVehicle()) root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine); - if (root_spritegroup == nullptr) { - CargoID cargo = v->cargo_type; - assert(cargo < lengthof(e->grf_prop.spritegroup)); - root_spritegroup = e->grf_prop.spritegroup[cargo] != nullptr ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[CT_DEFAULT]; - } - auto iter = e->sprite_group_cb36_properties_used.find(root_spritegroup); - if (iter != e->sprite_group_cb36_properties_used.end()) { - cb36_properties = iter->second; - seprintf(buffer, lastof(buffer), " Current sprite group: CB36 Properties: 0x" OTTD_PRINTFHEX64, iter->second); - print(buffer); - } - } - if (cb36_properties != UINT64_MAX) { - uint64 props = cb36_properties; - while (props) { - PropertyID prop = (PropertyID)FindFirstBit64(props); - props = KillFirstBit(props); - uint16 res = GetVehicleProperty(v, prop, CALLBACK_FAILED); - if (res == CALLBACK_FAILED) { - seprintf(buffer, lastof(buffer), " CB36: 0x%X --> FAILED", prop); - } else { - seprintf(buffer, lastof(buffer), " CB36: 0x%X --> 0x%X", prop, res); + const Engine *e = Engine::GetIfValid(v->engine_type); + if (e != nullptr) { + seprintf(buffer, lastof(buffer), " Callbacks: 0x%X, CB36 Properties: 0x" OTTD_PRINTFHEX64, + e->callbacks_used, e->cb36_properties_used); + print(buffer); + uint64 cb36_properties = e->cb36_properties_used; + if (!e->sprite_group_cb36_properties_used.empty()) { + const SpriteGroup *root_spritegroup = nullptr; + if (v->IsGroundVehicle()) root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine); + if (root_spritegroup == nullptr) { + CargoID cargo = v->cargo_type; + assert(cargo < lengthof(e->grf_prop.spritegroup)); + root_spritegroup = e->grf_prop.spritegroup[cargo] != nullptr ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[CT_DEFAULT]; } + auto iter = e->sprite_group_cb36_properties_used.find(root_spritegroup); + if (iter != e->sprite_group_cb36_properties_used.end()) { + cb36_properties = iter->second; + seprintf(buffer, lastof(buffer), " Current sprite group: CB36 Properties: 0x" OTTD_PRINTFHEX64, iter->second); + print(buffer); + } + } + if (cb36_properties != UINT64_MAX) { + uint64 props = cb36_properties; + while (props) { + PropertyID prop = (PropertyID)FindFirstBit64(props); + props = KillFirstBit(props); + uint16 res = GetVehicleProperty(v, prop, CALLBACK_FAILED); + if (res == CALLBACK_FAILED) { + seprintf(buffer, lastof(buffer), " CB36: 0x%X --> FAILED", prop); + } else { + seprintf(buffer, lastof(buffer), " CB36: 0x%X --> 0x%X", prop, res); + } + print(buffer); + } + } + YearMonthDay ymd; + ConvertDateToYMD(e->intro_date, &ymd); + seprintf(buffer, lastof(buffer), " Intro: %4i-%02i-%02i, Age: %u, Base life: %u, Durations: %u %u %u (sum: %u)", + ymd.year, ymd.month + 1, ymd.day, e->age, e->info.base_life, e->duration_phase_1, e->duration_phase_2, e->duration_phase_3, + e->duration_phase_1 + e->duration_phase_2 + e->duration_phase_3); + print(buffer); + if (e->type == VEH_TRAIN) { + const RailtypeInfo *rti = GetRailTypeInfo(e->u.rail.railtype); + seprintf(buffer, lastof(buffer), " Railtype: %u (0x" OTTD_PRINTFHEX64 "), Compatible: 0x" OTTD_PRINTFHEX64 ", Powered: 0x" OTTD_PRINTFHEX64 ", All compatible: 0x" OTTD_PRINTFHEX64, + e->u.rail.railtype, (static_cast(1) << e->u.rail.railtype), rti->compatible_railtypes, rti->powered_railtypes, rti->all_compatible_railtypes); + print(buffer); + } + if (e->type == VEH_ROAD) { + const RoadTypeInfo* rti = GetRoadTypeInfo(e->u.road.roadtype); + seprintf(buffer, lastof(buffer), " Roadtype: %u (0x" OTTD_PRINTFHEX64 "), Powered: 0x" OTTD_PRINTFHEX64, + e->u.road.roadtype, (static_cast(1) << e->u.road.roadtype), rti->powered_roadtypes); print(buffer); } - } - YearMonthDay ymd; - ConvertDateToYMD(e->intro_date, &ymd); - seprintf(buffer, lastof(buffer), " Intro: %4i-%02i-%02i, Age: %u, Base life: %u, Durations: %u %u %u (sum: %u)", - ymd.year, ymd.month + 1, ymd.day, e->age, e->info.base_life, e->duration_phase_1, e->duration_phase_2, e->duration_phase_3, - e->duration_phase_1 + e->duration_phase_2 + e->duration_phase_3); - print(buffer); - if (e->type == VEH_TRAIN) { - const RailtypeInfo *rti = GetRailTypeInfo(e->u.rail.railtype); - seprintf(buffer, lastof(buffer), " Railtype: %u (0x" OTTD_PRINTFHEX64 "), Compatible: 0x" OTTD_PRINTFHEX64 ", Powered: 0x" OTTD_PRINTFHEX64 ", All compatible: 0x" OTTD_PRINTFHEX64, - e->u.rail.railtype, (static_cast(1) << e->u.rail.railtype), rti->compatible_railtypes, rti->powered_railtypes, rti->all_compatible_railtypes); - print(buffer); - } - if (e->type == VEH_ROAD) { - const RoadTypeInfo* rti = GetRoadTypeInfo(e->u.road.roadtype); - seprintf(buffer, lastof(buffer), " Roadtype: %u (0x" OTTD_PRINTFHEX64 "), Powered: 0x" OTTD_PRINTFHEX64, - e->u.road.roadtype, (static_cast(1) << e->u.road.roadtype), rti->powered_roadtypes); - print(buffer); } } - seprintf(buffer, lastof(buffer), " Current image cacheable: %s", v->cur_image_valid_dir != INVALID_DIR ? "yes" : "no"); + seprintf(buffer, lastof(buffer), " Current image cacheable: %s (%X), spritenum: %X", + v->cur_image_valid_dir != INVALID_DIR ? "yes" : "no", v->cur_image_valid_dir, v->spritenum); print(buffer); } diff --git a/src/table/settings/settings.ini b/src/table/settings/settings.ini index e2af2b39f1..c7b05445bc 100644 --- a/src/table/settings/settings.ini +++ b/src/table/settings/settings.ini @@ -923,6 +923,36 @@ strval = STR_JUST_INT cat = SC_BASIC patxname = ""max_town_heightlevel.economy.max_town_heightlevel"" +[SDT_VAR] +base = GameSettings +var = economy.min_town_land_area +type = SLE_UINT16 +guiflags = SGF_0ISDISABLED +def = 0 +min = 0 +max = 400 +interval = 5 +str = STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA +strhelp = STR_CONFIG_SETTING_MIN_TOWN_LAND_AREA_HELPTEXT +strval = STR_CONFIG_SETTING_MIN_LAND_AREA_VALUE +cat = SC_BASIC +patxname = ""max_town_heightlevel.economy.min_town_land_area"" + +[SDT_VAR] +base = GameSettings +var = economy.min_city_land_area +type = SLE_UINT16 +guiflags = SGF_0ISDISABLED +def = 75 +min = 0 +max = 400 +interval = 5 +str = STR_CONFIG_SETTING_MIN_CITY_LAND_AREA +strhelp = STR_CONFIG_SETTING_MIN_CITY_LAND_AREA_HELPTEXT +strval = STR_CONFIG_SETTING_MIN_LAND_AREA_VALUE +cat = SC_BASIC +patxname = ""max_town_heightlevel.economy.min_city_land_area"" + ; link graph [SDT_VAR] diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index be8227cf24..94ae19bc2b 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2112,7 +2112,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize * @param tile tile to check * @return error value or zero cost */ -static CommandCost TownCanBePlacedHere(TileIndex tile) +static CommandCost TownCanBePlacedHere(TileIndex tile, bool city) { /* Check if too close to the edge of map */ if (DistanceFromEdge(tile) < 12) { @@ -2134,6 +2134,17 @@ static CommandCost TownCanBePlacedHere(TileIndex tile) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } + uint min_land_area = city ? _settings_game.economy.min_city_land_area : _settings_game.economy.min_town_land_area; + if (min_land_area > 0) { + if (!EnoughContiguousTilesMatchingCondition(tile, min_land_area, [](TileIndex t, void *data) -> bool { + if (!HasTileWaterClass(t) || GetWaterClass(t) == WATER_CLASS_INVALID) return true; + if (IsCoastTile(t) && !IsSlopeWithOneCornerRaised(GetTileSlope(t))) return true; + return false; + }, nullptr)) { + return_cmd_error(STR_ERROR_SITE_UNSUITABLE); + } + } + return CommandCost(EXPENSES_OTHER); } @@ -2201,7 +2212,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS); if (!random) { - CommandCost ret = TownCanBePlacedHere(tile); + CommandCost ret = TownCanBePlacedHere(tile, city); if (ret.Failed()) return ret; } @@ -2412,7 +2423,7 @@ static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size } /* Make sure town can be placed here */ - if (TownCanBePlacedHere(tile).Failed()) continue; + if (TownCanBePlacedHere(tile, city).Failed()) continue; /* Allocate a town struct */ Town *t = new Town(tile); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 2696ba1759..e07f09ca2b 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1390,7 +1390,7 @@ public: } } /* put a terminator on the list to make counting easier */ - this->house_sets.push_back((uint)this->size()); + this->house_sets.push_back((uint16)this->size()); } }; diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 08bf306e48..44c19e179c 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -1713,6 +1713,12 @@ int GetTraceRestrictTimeDateValue(TraceRestrictTimeDateValueField type) case TRTDVF_HOUR_MINUTE: return (MINUTES_HOUR(minutes) * 100) + MINUTES_MINUTE(minutes); + case TRTDVF_DAY: + return _cur_date_ymd.day; + + case TRTDVF_MONTH: + return _cur_date_ymd.month + 1; + default: return 0; } diff --git a/src/tracerestrict.h b/src/tracerestrict.h index dc9d2b8ce4..a11b57a09a 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -313,7 +313,9 @@ enum TraceRestrictTimeDateValueField { TRTDVF_MINUTE = 0, ///< Minute TRTDVF_HOUR = 1, ///< Hour TRTDVF_HOUR_MINUTE = 2, ///< Hour and minute - TRTDVF_END = 3, ///< End tag + TRTDVF_DAY = 3, ///< Day + TRTDVF_MONTH = 4, ///< Month + TRTDVF_END = 5, ///< End tag }; /** diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 0597366e23..e8e79bb820 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -346,12 +346,16 @@ static const StringID _time_date_value_str[] = { STR_TRACE_RESTRICT_TIME_MINUTE, STR_TRACE_RESTRICT_TIME_HOUR, STR_TRACE_RESTRICT_TIME_HOUR_MINUTE, + STR_TRACE_RESTRICT_TIME_DAY, + STR_TRACE_RESTRICT_TIME_MONTH, INVALID_STRING_ID }; static const uint _time_date_value_val[] = { TRTDVF_MINUTE, TRTDVF_HOUR, TRTDVF_HOUR_MINUTE, + TRTDVF_DAY, + TRTDVF_MONTH, }; /** value drop down list for time/date types strings and values */ @@ -543,7 +547,6 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG } else { *hide_mask = is_conditional ? 0x1FE0000 : 0x6F0; } - if (is_conditional && !_settings_game.game_time.time_in_minutes) *hide_mask |= 0x800000; if (is_conditional && _settings_game.vehicle.train_braking_model != TBM_REALISTIC) *hide_mask |= 0x1040000; } return is_conditional ? &set_cond : &set_action; @@ -1858,7 +1861,7 @@ public: } case TRVT_TIME_DATE_INT: { - this->ShowDropDownListWithValue(&_time_date_value, GetTraceRestrictValue(item), false, TR_WIDGET_LEFT_AUX_DROPDOWN, 0, 0, UINT_MAX); + this->ShowDropDownListWithValue(&_time_date_value, GetTraceRestrictValue(item), false, TR_WIDGET_LEFT_AUX_DROPDOWN, _settings_game.game_time.time_in_minutes ? 0 : 7, 0, UINT_MAX); break; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index fccf85d250..ec1a018576 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -3398,7 +3398,7 @@ static void UpdateAspectFromBridgeMiddleSignalChange(TileIndex entrance, TileInd static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDirection dir, bool free) { - if (IsBridge(end) && _m[end].m2 != 0) { + if (IsBridge(end) && _m[end].m2 != 0 && IsTunnelBridgeSignalSimulationEntrance(end)) { /* Clearing last bridge signal. */ int signal_offset = GetAndClearLastBridgeEntranceSetSignalIndex(end); if (signal_offset) { @@ -3424,7 +3424,7 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir if (IsTunnelBridgeSignalSimulationEntrance(end)) SetTunnelBridgeEntranceSignalGreen(end); if (IsTunnelBridgeSignalSimulationEntrance(tile)) SetTunnelBridgeEntranceSignalGreen(tile); - } else if (IsTunnel(end) && _extra_aspects > 0) { + } else if (IsTunnel(end) && _extra_aspects > 0 && IsTunnelBridgeSignalSimulationEntrance(end)) { uint signal_count = GetTunnelBridgeLength(tile, end) / GetTunnelBridgeSignalSimulationSpacing(end); if (signal_count > 0) UpdateEntranceAspectFromMiddleSignalChange(end, signal_count - 1); } diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 60e307db51..c2dc98fa39 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -357,6 +357,7 @@ int MaxTreeCount(const TileIndex tile) int max_trees_snow_line_based = 4; if (_settings_game.game_creation.landscape == LT_ARCTIC) { + if (_settings_game.construction.trees_around_snow_line_range != _previous_trees_around_snow_line_range) RecalculateArcticTreeOccuranceArray(); const uint height_above_snow_line = std::max(0, tile_z - _settings_game.game_creation.snow_line_height); max_trees_snow_line_based = (height_above_snow_line < _arctic_tree_occurance.size()) ? (1 + (_arctic_tree_occurance[height_above_snow_line] * 4) / 255) : diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 70e54f0032..34ff5f1f06 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -1387,7 +1387,7 @@ public: inline void UpdateImageStateUsingMapDirection(VehicleSpriteSeq &seq) { - this->UpdateImageState(this->GetMapImageDirection(), seq); + this->UpdateImageState(((T *)this)->GetMapImageDirection(), seq); } private: