Merge branch 'jgrpp' into jgrpp-beta

# Conflicts:
#	src/network/core/packet.cpp
#	src/network/core/udp.cpp
pull/332/head
Jonathan G Rennison 3 years ago
commit 61cc60099a

@ -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

@ -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 -

@ -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/)

@ -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.

@ -917,8 +917,7 @@ class btree : public Params::key_compare {
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef typename Params::allocator_type allocator_type;
typedef typename allocator_type::template rebind<char>::other
internal_allocator_type;
using internal_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<char>;
public:
// Default constructor.

@ -96,6 +96,7 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
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; }

@ -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();

@ -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

@ -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

@ -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) {}
};

@ -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<CompanyID> 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;
}

@ -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) {

@ -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.
};

@ -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 <company-id>'");
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);

@ -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

@ -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

@ -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 :역세권 (창이 열린 역만)

@ -16,6 +16,7 @@
#include "tunnelbridge_map.h"
#include "3rdparty/cpp-btree/btree_map.h"
#include <array>
#include <deque>
#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<uint32> processed_tiles;
std::deque<uint32> 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

@ -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'

@ -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);
}

@ -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

@ -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;

@ -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<uint>(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<uint>(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;

@ -15,7 +15,7 @@
* Names are formatted as PROP_<CLASS>_<NAME>
* @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

@ -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();

@ -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));
}

@ -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()
{

@ -941,18 +941,18 @@ void PostProcessNetworks(const std::vector<std::shared_ptr<TownNetwork>>& 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();

@ -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),

@ -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
};

@ -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

@ -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);

@ -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<byte>(0x01010101);
return GetIndustrySpec(industry_type)->map_colour;
}
default:
return MKCOLOUR(GREY_SCALE(2));

@ -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"));

@ -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)

@ -92,10 +92,26 @@ class NIHVehicle : public NIHelper {
/* virtual */ void ExtraInfo(uint index, std::function<void(const char *)> 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<void(const char *)> 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];
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);
}
}
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);
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<RailTypes>(1) << e->u.rail.railtype), rti->compatible_railtypes, rti->powered_railtypes, rti->all_compatible_railtypes);
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);
}
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<RoadTypes>(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<RailTypes>(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<RoadTypes>(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);
}

@ -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]

@ -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);

@ -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());
}
};

@ -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;
}

@ -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
};
/**

@ -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;
}

@ -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);
}

@ -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<int>(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) :

@ -1387,7 +1387,7 @@ public:
inline void UpdateImageStateUsingMapDirection(VehicleSpriteSeq &seq)
{
this->UpdateImageState(this->GetMapImageDirection(), seq);
this->UpdateImageState(((T *)this)->GetMapImageDirection(), seq);
}
private:

Loading…
Cancel
Save