Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a82f21f24d | ||
|
|
46908fb63a | ||
|
|
8efa99f445 | ||
|
|
c6251426d9 | ||
|
|
9026736cc1 | ||
|
|
b7a2166962 | ||
|
|
8ea68421b1 | ||
|
|
afc5962881 | ||
|
|
9239381d56 | ||
|
|
9dded61af9 | ||
|
|
8fbc5c090b | ||
|
|
00bdd316d7 | ||
|
|
f34284f1a0 | ||
|
|
c77659c995 | ||
|
|
e6877d0823 | ||
|
|
beba12f9d6 | ||
|
|
95fd4ec649 | ||
|
|
0fa41c7493 | ||
|
|
60cbcf0742 | ||
|
|
e38a4e1e57 | ||
|
|
5965f184c2 | ||
|
|
db20c7f461 | ||
|
|
e2e8872e82 | ||
|
|
4750d2836c | ||
|
|
b1c31f9500 | ||
|
|
a6879e9180 | ||
|
|
5eb7d49024 | ||
|
|
69c0332813 | ||
|
|
b11942cf44 | ||
|
|
ef6995e8d4 | ||
|
|
c0fd2b969b | ||
|
|
683778fd7a | ||
|
|
63eeadef17 | ||
|
|
e526b2ccd3 |
@@ -38,10 +38,14 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
commit-checker: {}
|
||||
linux-amd64-clang-3.8: {}
|
||||
linux-amd64-gcc-6: {}
|
||||
linux-i386-gcc-6: {}
|
||||
commit-checker:
|
||||
Tag: 'commit-checker'
|
||||
linux-amd64-clang-3.8:
|
||||
Tag: 'linux-amd64-clang-3.8'
|
||||
linux-amd64-gcc-6:
|
||||
Tag: 'linux-amd64-gcc-6'
|
||||
linux-i386-gcc-6:
|
||||
Tag: 'linux-i386-gcc-6'
|
||||
|
||||
steps:
|
||||
- template: azure-pipelines/templates/ci-git-rebase.yml
|
||||
@@ -50,7 +54,7 @@ jobs:
|
||||
- template: azure-pipelines/templates/linux-build.yml
|
||||
parameters:
|
||||
Image: compile-farm-ci
|
||||
Tag: $(Agent.JobName)
|
||||
Tag: $(Tag)
|
||||
|
||||
- job: macos
|
||||
displayName: 'MacOS'
|
||||
|
||||
@@ -24,7 +24,7 @@ steps:
|
||||
${{ if eq(parameters.Image, 'compile-farm-ci') }}:
|
||||
displayName: 'Build and test'
|
||||
# Run the commit-checker only if it is a Pull Request
|
||||
condition: and(succeeded(), or(ne(variables['Agent.JobName'], 'commit-checker'), eq(variables['Build.Reason'], 'PullRequest')))
|
||||
condition: and(succeeded(), or(not(contains(variables['Agent.JobName'], 'commit-checker')), eq(variables['Build.Reason'], 'PullRequest')))
|
||||
inputs:
|
||||
command: 'Run an image'
|
||||
imageName: openttd/${{ parameters.Image }}:${{ parameters.Tag }}
|
||||
|
||||
@@ -110,14 +110,22 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
linux-ubuntu-xenial-i386-gcc: {}
|
||||
linux-ubuntu-xenial-amd64-gcc: {}
|
||||
linux-ubuntu-bionic-i386-gcc: {}
|
||||
linux-ubuntu-bionic-amd64-gcc: {}
|
||||
linux-debian-jessie-i386-gcc: {}
|
||||
linux-debian-jessie-amd64-gcc: {}
|
||||
linux-debian-stretch-i386-gcc: {}
|
||||
linux-debian-stretch-amd64-gcc: {}
|
||||
linux-ubuntu-xenial-i386-gcc:
|
||||
Tag: 'linux-ubuntu-xenial-i386-gcc'
|
||||
linux-ubuntu-xenial-amd64-gcc:
|
||||
Tag: 'linux-ubuntu-xenial-amd64-gcc'
|
||||
linux-ubuntu-bionic-i386-gcc:
|
||||
Tag: 'linux-ubuntu-bionic-i386-gcc'
|
||||
linux-ubuntu-bionic-amd64-gcc:
|
||||
Tag: 'linux-ubuntu-bionic-amd64-gcc'
|
||||
linux-debian-jessie-i386-gcc:
|
||||
Tag: 'linux-debian-jessie-i386-gcc'
|
||||
linux-debian-jessie-amd64-gcc:
|
||||
Tag: 'linux-debian-jessie-amd64-gcc'
|
||||
linux-debian-stretch-i386-gcc:
|
||||
Tag: 'linux-debian-stretch-i386-gcc'
|
||||
linux-debian-stretch-amd64-gcc:
|
||||
Tag: 'linux-debian-stretch-amd64-gcc'
|
||||
|
||||
steps:
|
||||
- template: release-fetch-source.yml
|
||||
@@ -125,7 +133,7 @@ jobs:
|
||||
parameters:
|
||||
Image: compile-farm
|
||||
ContainerCommand: '$(Build.BuildNumber)'
|
||||
Tag: $(Agent.JobName)
|
||||
Tag: $(Tag)
|
||||
- template: linux-claim-bundles.yml
|
||||
- template: release-bundles.yml
|
||||
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
1.9.2 (2019-07-07)
|
||||
------------------------------------------------------------------------
|
||||
- Change: Set default setting in server browser of "Advertised" to "Yes" (#7568)
|
||||
- Change: Allow building road stops over self-owned one-way/blocked road (#7547)
|
||||
- Fix #7463: Promote scroll mode setting to basic category (#7586)
|
||||
- Fix: Inconsistent GUI scaling (#7539)
|
||||
- Fix #7491: Send company update admin message when bankruptcy counter changes (#7492)
|
||||
- Fix #7553: Check bounds when loading strings (#7554)
|
||||
- Fix: Really increase the maximum number of GameScript texts to 64k (#7555)
|
||||
- Fix: Crash when attempting to load old save game with GRFs set (#7546)
|
||||
- Fix #6507: Don't try to load invalid depots from older savegames (#7546)
|
||||
- Fix: Railtype bits were moved too late, leading to rails under bridges losing their type (#7546)
|
||||
- Fix: Bounds check access to railtype_map (#7529)
|
||||
- Fix: Spurious errors when using more than 32 railtypes (#7533)
|
||||
- Fix #7633: Allow zero-cost track conversion to succeed (#7634)
|
||||
- Fix #7577: Check if linkgraph station index is valid before dereferencing (#7583)
|
||||
- Fix #7224: Drag and drop vehicle group creation does not work correctly (#7581)
|
||||
- Fix #7570: Show Github URL in the crashlog window (#7571)
|
||||
- Fix: Clicking on scrollbar 'thumb' moved position up instantly (#7549)
|
||||
- Fix #7255: Prevent crashlog corruption by only printing the 32 most recent news messages (#7542)
|
||||
- Fix #5685: Check for free wagons in ScriptVehicleList (#7617)
|
||||
- Fix: Make GSGoal.QuestionClient work correctly at least for clients with ID < 2**16 (#7560)
|
||||
- Fix #6666: Mismatched parentheses in RTL languages (#7480)
|
||||
- Fix: [Windows] Various reliability and correctness improvements to MIDI on Windows (#7620)
|
||||
|
||||
|
||||
1.9.1 (2019-04-08)
|
||||
------------------------------------------------------------------------
|
||||
- Fix #6564: Enforce types of arguments for station name strings (#7419)
|
||||
@@ -8,6 +34,7 @@
|
||||
- Fix: [Windows] Incorrect error handling could lead to cascading error windows (#7482)
|
||||
- Fix #7478: Don't remove NewGRF objects on company take-over. (#7483)
|
||||
|
||||
|
||||
1.9.0 (2019-04-01)
|
||||
------------------------------------------------------------------------
|
||||
- Fix #7411: Use industry production callback (if used) on initial industry cargo generation (#7412)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
OpenTTD's known bugs
|
||||
Last updated: 2019-04-08
|
||||
Release version: 1.9.1
|
||||
Last updated: 2019-07-07
|
||||
Release version: 1.9.2
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
openttd (1.9.2-0) unstable; urgency=low
|
||||
|
||||
* New upstream release 1.9.2
|
||||
|
||||
-- OpenTTD <info@openttd.org> Sun, 07 Jul 2019 23:00:00 +0200
|
||||
|
||||
openttd (1.9.1-0) unstable; urgency=low
|
||||
|
||||
* New upstream release 1.9.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
|
||||
set OPENTTD_VERSION=1.9.1
|
||||
set OPENTTD_VERSION=1.9.2
|
||||
set OPENSFX_VERSION=0.8.0
|
||||
set NOSOUND_VERSION=0.8.0
|
||||
set OPENGFX_VERSION=1.2.0
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
#
|
||||
|
||||
Name: openttd
|
||||
Version: 1.9.1
|
||||
Version: 1.9.2
|
||||
Release: 0
|
||||
%define srcver 1.9.1
|
||||
%define srcver 1.9.2
|
||||
Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe
|
||||
License: GPL-2.0
|
||||
Group: Amusements/Games/Strategy/Other
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Version numbers to update
|
||||
!define APPV_MAJOR 1
|
||||
!define APPV_MINOR 9
|
||||
!define APPV_MAINT 1
|
||||
!define APPV_MAINT 2
|
||||
!define APPV_BUILD 0
|
||||
!define APPV_EXTRA ""
|
||||
|
||||
|
||||
@@ -12,18 +12,20 @@
|
||||
#ifndef ENUM_TYPE_HPP
|
||||
#define ENUM_TYPE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
/** Some enums need to have allowed incrementing (i.e. StationClassID) */
|
||||
#define DECLARE_POSTFIX_INCREMENT(type) \
|
||||
inline type operator ++(type& e, int) \
|
||||
#define DECLARE_POSTFIX_INCREMENT(enum_type) \
|
||||
inline enum_type operator ++(enum_type& e, int) \
|
||||
{ \
|
||||
type e_org = e; \
|
||||
e = (type)((int)e + 1); \
|
||||
enum_type e_org = e; \
|
||||
e = (enum_type)((std::underlying_type<enum_type>::type)e + 1); \
|
||||
return e_org; \
|
||||
} \
|
||||
inline type operator --(type& e, int) \
|
||||
inline enum_type operator --(enum_type& e, int) \
|
||||
{ \
|
||||
type e_org = e; \
|
||||
e = (type)((int)e - 1); \
|
||||
enum_type e_org = e; \
|
||||
e = (enum_type)((std::underlying_type<enum_type>::type)e - 1); \
|
||||
return e_org; \
|
||||
}
|
||||
|
||||
@@ -31,13 +33,13 @@
|
||||
|
||||
/** Operators to allow to work with enum as with type safe bit set in C++ */
|
||||
# define DECLARE_ENUM_AS_BIT_SET(mask_t) \
|
||||
inline mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((int)m1 | m2);} \
|
||||
inline mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((int)m1 & m2);} \
|
||||
inline mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((int)m1 ^ m2);} \
|
||||
inline mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 | m2);} \
|
||||
inline mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 & m2);} \
|
||||
inline mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 ^ m2);} \
|
||||
inline mask_t& operator |= (mask_t& m1, mask_t m2) {m1 = m1 | m2; return m1;} \
|
||||
inline mask_t& operator &= (mask_t& m1, mask_t m2) {m1 = m1 & m2; return m1;} \
|
||||
inline mask_t& operator ^= (mask_t& m1, mask_t m2) {m1 = m1 ^ m2; return m1;} \
|
||||
inline mask_t operator ~(mask_t m) {return (mask_t)(~(int)m);}
|
||||
inline mask_t operator ~(mask_t m) {return (mask_t)(~(std::underlying_type<mask_t>::type)m);}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -303,7 +303,7 @@ char *CrashLog::LogGamelog(char *buffer, const char *last) const
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes any recent news messages to the buffer.
|
||||
* Writes up to 32 recent news messages to the buffer, with the most recent first.
|
||||
* @param buffer The begin where to write at.
|
||||
* @param last The last position in the buffer to write to.
|
||||
* @return the position of the \c '\0' character after the buffer.
|
||||
@@ -312,7 +312,8 @@ char *CrashLog::LogRecentNews(char *buffer, const char *last) const
|
||||
{
|
||||
buffer += seprintf(buffer, last, "Recent news messages:\n");
|
||||
|
||||
for (NewsItem *news = _oldest_news; news != NULL; news = news->next) {
|
||||
int i = 0;
|
||||
for (NewsItem *news = _latest_news; i < 32 && news != NULL; news = news->prev, i++) {
|
||||
YearMonthDay ymd;
|
||||
ConvertDateToYMD(news->date, &ymd);
|
||||
buffer += seprintf(buffer, last, "(%i-%02i-%02i) StringID: %u, Type: %u, Ref1: %u, %u, Ref2: %u, %u\n",
|
||||
|
||||
@@ -572,8 +572,10 @@ static void CompanyCheckBankrupt(Company *c)
|
||||
{
|
||||
/* If the company has money again, it does not go bankrupt */
|
||||
if (c->money - c->current_loan >= -_economy.max_loan) {
|
||||
int previous_months_of_bankruptcy = CeilDiv(c->months_of_bankruptcy, 3);
|
||||
c->months_of_bankruptcy = 0;
|
||||
c->bankrupt_asked = 0;
|
||||
if (previous_months_of_bankruptcy != 0) CompanyAdminUpdate(c);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -642,10 +644,15 @@ static void CompanyCheckBankrupt(Company *c)
|
||||
* that changing the current company is okay. In case of single
|
||||
* player we are sure (the above check) that we are not the local
|
||||
* company and thus we won't be moved. */
|
||||
if (!_networking || _network_server) DoCommandP(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, CMD_COMPANY_CTRL);
|
||||
if (!_networking || _network_server) {
|
||||
DoCommandP(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, CMD_COMPANY_CTRL);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CeilDiv(c->months_of_bankruptcy, 3) != CeilDiv(c->months_of_bankruptcy - 1, 3)) CompanyAdminUpdate(c);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -308,7 +308,7 @@ GameStrings *LoadTranslations()
|
||||
/** Compile the language. */
|
||||
void GameStrings::Compile()
|
||||
{
|
||||
StringData data(1);
|
||||
StringData data(32);
|
||||
StringListReader master_reader(data, this->raw_strings[0], true, false);
|
||||
master_reader.ParseFile();
|
||||
if (_errors != 0) throw std::exception();
|
||||
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
LEErrorCode status = LE_NO_ERROR;
|
||||
/* ParagraphLayout does not copy "buff", so it must stay valid.
|
||||
* "runs" is copied according to the ICU source, but the documentation does not specify anything, so this might break somewhen. */
|
||||
icu::ParagraphLayout *p = new icu::ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
|
||||
icu::ParagraphLayout *p = new icu::ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? 1 : 0, false, status);
|
||||
if (status != LE_NO_ERROR) {
|
||||
delete p;
|
||||
return NULL;
|
||||
|
||||
27
src/goal.cpp
27
src/goal.cpp
@@ -236,10 +236,11 @@ CommandCost CmdSetGoalCompleted(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
* @param flags type of operation
|
||||
* @param p1 various bitstuffed elements
|
||||
* - p1 = (bit 0 - 15) - Unique ID to use for this question.
|
||||
* - p1 = (bit 16 - 23) - Company or client for which this question is.
|
||||
* - p1 = (bit 24 - 25) - Question type.
|
||||
* - p1 = (bit 31) - Question target: 0 - company, 1 - client.
|
||||
* @param p2 Buttons of the question.
|
||||
* - p1 = (bit 16 - 31) - Company or client for which this question is.
|
||||
* @param p2 various bitstuffed elements
|
||||
* - p2 = (bit 0 - 17) - Buttons of the question.
|
||||
* - p2 = (bit 29 - 30) - Question type.
|
||||
* - p2 = (bit 31) - Question target: 0 - company, 1 - client.
|
||||
* @param text Text of the question.
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
@@ -248,36 +249,38 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
||||
uint16 uniqueid = (GoalType)GB(p1, 0, 16);
|
||||
CompanyID company = (CompanyID)GB(p1, 16, 8);
|
||||
#ifdef ENABLE_NETWORK
|
||||
ClientIndex client = (ClientIndex)GB(p1, 16, 8);
|
||||
ClientID client = (ClientID)GB(p1, 16, 16);
|
||||
#endif
|
||||
byte type = GB(p1, 24, 2);
|
||||
bool is_client = HasBit(p1, 31);
|
||||
|
||||
assert_compile(GOAL_QUESTION_BUTTON_COUNT < 29);
|
||||
uint32 button_mask = GB(p2, 0, GOAL_QUESTION_BUTTON_COUNT);
|
||||
byte type = GB(p2, 29, 2);
|
||||
bool is_client = HasBit(p2, 31);
|
||||
|
||||
if (_current_company != OWNER_DEITY) return CMD_ERROR;
|
||||
if (StrEmpty(text)) return CMD_ERROR;
|
||||
if (is_client) {
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (!NetworkClientInfo::IsValidID(client)) return CMD_ERROR;
|
||||
if (NetworkClientInfo::GetByClientID(client) == nullptr) return CMD_ERROR;
|
||||
#else
|
||||
return CMD_ERROR;
|
||||
#endif
|
||||
} else {
|
||||
if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR;
|
||||
}
|
||||
if (CountBits(p2) < 1 || CountBits(p2) > 3) return CMD_ERROR;
|
||||
if (p2 >= (1 << GOAL_QUESTION_BUTTON_COUNT)) return CMD_ERROR;
|
||||
if (CountBits(button_mask) < 1 || CountBits(button_mask) > 3) return CMD_ERROR;
|
||||
if (type >= GOAL_QUESTION_TYPE_COUNT) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
if (is_client) {
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (NetworkClientInfo::Get(client)->client_id != _network_own_client_id) return CommandCost();
|
||||
if (client != _network_own_client_id) return CommandCost();
|
||||
#endif
|
||||
} else {
|
||||
if (company == INVALID_COMPANY && !Company::IsValidID(_local_company)) return CommandCost();
|
||||
if (company != INVALID_COMPANY && company != _local_company) return CommandCost();
|
||||
}
|
||||
ShowGoalQuestion(uniqueid, type, p2, text);
|
||||
ShowGoalQuestion(uniqueid, type, button_mask, text);
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
|
||||
@@ -536,7 +536,7 @@ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
|
||||
if (new_g == NEW_GROUP) {
|
||||
/* Create new group. */
|
||||
CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL);
|
||||
CommandCost ret = CmdCreateGroup(0, flags, v->type, INVALID_GROUP, NULL);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
new_g = _new_group_id;
|
||||
|
||||
@@ -282,7 +282,7 @@ STR_SORT_BY_TIMETABLE_DELAY :تاخير جد
|
||||
STR_SORT_BY_FACILITY :نوع المحطة
|
||||
STR_SORT_BY_RATING_MAX :اعلى نسبة شحن
|
||||
STR_SORT_BY_RATING_MIN :اقل نسبة شحن
|
||||
STR_SORT_BY_ENGINE_ID :نوع المحرك (قياسي(
|
||||
STR_SORT_BY_ENGINE_ID :نوع المحرك (قياسي)
|
||||
STR_SORT_BY_COST :التكلفة
|
||||
STR_SORT_BY_POWER :الطاقة
|
||||
STR_SORT_BY_TRACTIVE_EFFORT :قوة الجذب
|
||||
@@ -1147,7 +1147,7 @@ STR_CONFIG_SETTING_INDUSTRY_DENSITY :الكثافة
|
||||
STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :إختر مقدار الصناعات التي يجب تكوينها وعلى اي مستوى يجب ان تكون خلال اللعبة
|
||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT :ارتفاع خط الثلج: {STRING}
|
||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :تحكم على اي ارتفاع يبدأ نزول الثلج في المناطق القطبية,تؤثر الثلوج على مستوى تطور القطاع الصناعي ونمو المدن
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :خشونة التضاريس (صفر التكوين فقط ) :({STRING}
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :خشونة التضاريس: {STRING}
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesis only)إختر تكرار الهضبات: الاراض المستويه تحتوي على البضع منها,هضبات موزعه عرضيا اكثر,الاراض الوعرة تحتوي الكثير من الهضاب,التي من الممكن ان تكون متكررة
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :ناعم جدا
|
||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :ناعم
|
||||
@@ -1946,7 +1946,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :بناء الس
|
||||
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}بناء سكة حديد
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}بناء سكة القطار باستخدام البناء التلقائي
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}بناء ورشة قطارات (لصيانة و شراء القطارات).
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}بناء ورشة قطارات (لصيانة و شراء القطارات)
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}غير السكة الى نقطة عبور
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}بناء محطة قطار. مفتاح كنترول يسمح بضم المحطات
|
||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}بناء إشارات السكك الحديدية.
|
||||
@@ -2028,7 +2028,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}بناء
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}بناء الطرق باستخدام النظام الآلي
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}بناء سكة القطار باستخدام النظام الآلي
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}بناء ورشة صيانة لعربات الطرق (لشراء و صيانة العربات).
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}بناء ورشة لصيانة عربات الترام (لشراء و صيانة عربات الترام).
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}بناء ورشة لصيانة عربات الترام (لشراء و صيانة عربات الترام)
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}بناء محطة باصات
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}بناء محطة ركاب ترام.
|
||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}بناء محطة تحميل عربات. مفتاح كنترول يسمح بمجاورة المحطات.
|
||||
@@ -2590,7 +2590,8 @@ STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}ادخل
|
||||
# Town directory window
|
||||
STR_TOWN_DIRECTORY_CAPTION :{WHITE}مدن/ بلدات
|
||||
STR_TOWN_DIRECTORY_NONE :{ORANGE}-بدون-
|
||||
STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ) {COMMA})
|
||||
STR_TOWN_DIRECTORY_TOWN :{ORANGE}{RLE}{TOWN}{BLACK} {RLM}({COMMA})
|
||||
STR_TOWN_DIRECTORY_CITY :{ORANGE}{RLE}{TOWN}{YELLOW} (مدينة){BLACK} {RLM}({COMMA})
|
||||
STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}اسم المدينة - اضغط على الاسم لتوسيط الشاشة عليها. اضغط + كنترول لفتح شاشة عرض جديدة للضاحية.
|
||||
STR_TOWN_POPULATION :{BLACK}سكان العالم: {COMMA}
|
||||
|
||||
@@ -2678,7 +2679,7 @@ STR_STATION_LIST_STATION :{YELLOW}{STATIO
|
||||
STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT}
|
||||
STR_STATION_LIST_NONE :{YELLOW}- بدون -
|
||||
STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}اختر جميع المرافق
|
||||
STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}اختر كل انواع الشحن (حتى غير المنتظرة(
|
||||
STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}اختر كل انواع الشحن (حتى غير المنتظرة)
|
||||
STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}لا يوجد اي شحنة منتظرة
|
||||
|
||||
# Station view window
|
||||
@@ -2897,7 +2898,7 @@ STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}السر
|
||||
STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}السرعة في القناة/النهر: {GOLD}{VELOCITY}
|
||||
STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}تكلفة التشغيل: {GOLD}{CURRENCY_LONG}/ سنة
|
||||
STR_PURCHASE_INFO_CAPACITY :{BLACK}السعة: {GOLD}{CARGO_LONG} {STRING}
|
||||
STR_PURCHASE_INFO_REFITTABLE :)قابل لتغيير(
|
||||
STR_PURCHASE_INFO_REFITTABLE :(قابل لتغيي)
|
||||
STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}تصميم: {GOLD}{NUM}{BLACK} العمر الافتراضي: {GOLD}{COMMA} سنة
|
||||
STR_PURCHASE_INFO_RELIABILITY :{BLACK}الاعتمادية القصوى: {GOLD}{COMMA}%
|
||||
STR_PURCHASE_INFO_COST :{BLACK}التكلفة: {GOLD}{CURRENCY_LONG}
|
||||
@@ -3193,7 +3194,7 @@ STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK} عرض
|
||||
STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}السعة: {LTBLUE}
|
||||
|
||||
# Vehicle refit
|
||||
STR_REFIT_CAPTION :{WHITE}{VEHICLE} )تغيير(
|
||||
STR_REFIT_CAPTION :{WHITE}{VEHICLE} (تغيير)
|
||||
STR_REFIT_TITLE :{GOLD}اختر نوع الحمولة ...
|
||||
STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}السعة الجديدة: {GOLD}{CARGO_LONG}{}{BLACK}تكلفة التغيير: {RED}{CURRENCY_LONG}
|
||||
STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}السعة الجديدة: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}تكلفة اعادة التهيئة: {RED}{CURRENCY_LONG}
|
||||
@@ -3415,7 +3416,7 @@ STR_TIMETABLE_RESET_LATENESS :{BLACK}اعد
|
||||
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}عدل وقت التاخير للعداد حتى تصل المركبة في الوقت المحدد
|
||||
|
||||
STR_TIMETABLE_AUTOFILL :{BLACK}تهيئة تلقائية
|
||||
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}املأ الجدولة تلقائيا بقيم الرحلة التالية (مفتاح كنترول لمحاولة ابقائ وقت الانتظار).
|
||||
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}مفتاح كنترول لمحاولة ابقائ وقت الانتظار (املأ الجدولة تلقائيا بقيم الرحلة التالية)
|
||||
|
||||
STR_TIMETABLE_EXPECTED :{BLACK}متوقع
|
||||
STR_TIMETABLE_SCHEDULED :{BLACK}مجدول
|
||||
|
||||
@@ -4586,7 +4586,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... гэ
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... няправільны кірунак дарогі
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... на прахадных прыпынках нельга рабіць павароты
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... на прахадных прыпынках нельга рабіць скрыжаваньнi
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... дарога аднабаковая ці заблакавана
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Немагчыма выдаліць частку станцыi...
|
||||
|
||||
@@ -4276,7 +4276,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... é u
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... rua na direção errada
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... paradas "drive-thru" não podem ter esquinas
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... paradas "drive-thru" não podem ter junções
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... rua é mão única ou está bloqueada
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Impossível remover parte da estação...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... aque
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... sentit de la carretera en la direcció incorrecta
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... les estacions d'autobús de pas no poden tenir cantonades
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... les estacions d'autobús de pas no poden tenir interseccions
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... la carretera és d'un sol sentit o està blocada.
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}No es pot treure part de la estació...
|
||||
|
||||
@@ -4413,7 +4413,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ovo
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... cesta je orijentirana u krivom smjeru
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... prolazne postaje ne mogu imati zavoje
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... prolazne postaje ne mogu imati raskrižja
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... cesta je jednosmjerna ili je blokirana
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Nije moguće ukloniti dio postaje...
|
||||
|
||||
@@ -4339,7 +4339,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... tato
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... silnice je otočena jiným směrem
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... průjezdné zastávky nemohou být v zatáčce
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... průjezdné zastávky nemohou být na křižovatce
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... silnice je jednosměrná nebo uzavřená.
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Nelze odstranit část stanice...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... denn
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... vejen peger i den forkerte retning
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive-through stops kan ikke have hjørner
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive-through stops kan ikke have kryds
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}vejen er ensrettet eller blokeret
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kan ikke fjerne en del af en station...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... deze
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... weg is in de verkeerde richting
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... doorrij haltes kunnen geen bochten hebben
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... doorrij haltes kunnen geen kruisingen hebben
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... weg is eenrichtingsverkeer of geblokkeerd
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kan deel van station niet verwijderen...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive through stops can't have junctions
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... road is one way or blocked
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Can't remove part of station...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive through stops can't have junctions
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... road is one way or blocked
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Can't remove part of station...
|
||||
|
||||
@@ -4284,7 +4284,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... see
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... tee on vales suunas
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... nurgad ei saa läbisõidupeatustes olla
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... ristmikud ei saa olla läbisõidupeatustes
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... tee on ühesuunaline või blokeeritud
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Siinset jaamablokki ei saa lammutada...
|
||||
|
||||
@@ -4317,7 +4317,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... kunt
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... tie on väärin päin
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... läpiajettavissa pysäkeissä ei voi olla mutkia
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... läpiajettavissa pysäkeissä ei voi olla risteyksiä
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... tie on yksisuuntainen tai suljettu
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Aseman osaa ei voi poistaa...
|
||||
|
||||
@@ -4318,7 +4318,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... cett
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... mauvaise orientation de la route
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... les arrêts ne peuvent pas avoir de virages
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... les arrêts ne peuvent pas avoir de jonctions
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... la route est à sens unique ou bloquée
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Impossible de supprimer une partie de la gare...
|
||||
|
||||
@@ -4496,7 +4496,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... tha
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... tha comhair an rathaid cearr
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... chan urrainn dha dh’oiseanan a bhith aig stèiseanan draibhidh troimhe
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... chan urrainn dha ghoibhlean a bhith aig stèiseanan draibhidh troimhe
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... rathad aon-shligheach no bacte
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Cha ghabh pàirt dhen stèisean toirt air falbh...
|
||||
|
||||
@@ -4302,7 +4302,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... dies
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... Straße verläuft in die falsche Richtung
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... Bus- und Lkw-Haltestellen können nicht um die Kurve gehen
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... Bus- und Lkw-Haltestellen können keine Abzweigung haben
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}...Einbahnstraße oder blockierter Weg
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Dieser Teil der Station kann nicht entfernt werden...
|
||||
|
||||
@@ -4430,7 +4430,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... αυ
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... ο δρόμος βλέπει σε λάθος κατεύθυνση
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... οι μη τερματικοί σταθμοί δε μπορούν να έχουν στροφές
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... οι μη τερματικοί σταθμοί δε μπορούν να έχουν διασταυρώσεις
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... ο δρόμος είναι μονόδρομος η μπλοκαρισμένος
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Δεν μπορεί να αφαιρεθεί μέρος του σταθμού...
|
||||
|
||||
@@ -4275,7 +4275,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... כב
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}הכביש פונה לכיוון לא נכון...
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... לתחנות "על הדרך" לא יכולות להיות פינות
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... לתחנות "על הדרך" לא יכולות להיות צמתים
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... הדרך חד כיוונית או חסומה
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}... לא ניתן לבטל חלק מהתחנה
|
||||
|
||||
@@ -4381,7 +4381,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ez e
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... az út a másik irányba vezet
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... áthaladó megállóhelyeken nem lehet kanyar
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... áthaladó megállóhelyeken nem lehet elágazás
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... az út egyirányú vagy blokkolt
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Nem lehet eltávolítani az állomás részét...
|
||||
|
||||
@@ -4249,7 +4249,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... jala
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... menghadap pada arah yang salah
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... terminal lintas-lalu tak bisa memiliki sudut
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... terminal lintas-lalu tak bisa memiliki simpangan
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... jalannya satu arah atau terhalang
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Tidak dapat menghapus bagian dari stasiun...
|
||||
|
||||
@@ -4347,7 +4347,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ques
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... strada rivolta nella direzione sbagliata
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... le fermate passanti non possono trovarsi in curva
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... le fermate passanti non possono avere raccordi
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... la strada è bloccata o a senso unico
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Impossibile rimuovere parte della stazione...
|
||||
|
||||
@@ -4318,7 +4318,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... 여
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... 도로의 방향과 일치하지 않습니다.
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... 도로 통과 정류장은 곡선도로에 건설할 수 없습니다.
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... 도로 통과 정류장은 교차로에 건설할 수 없습니다.
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... 도로가 일방통행이거나 막혔습니다
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}역의 일부를 제거할 수 없습니다...
|
||||
|
||||
@@ -4479,7 +4479,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... via
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... viae directio non convenit
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... stationi perviae non licet esse curva
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... stationi perviae non licet compita habere
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... via est monodromus vel obstructa
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Non licet partem stationis removere...
|
||||
|
||||
@@ -4276,7 +4276,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... d'St
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... Strooss geet an dei falsch Richtung
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... Duerchfahrtstops kënnen keng Kéiren hunn
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... Duerchfahrtstops kënnen keng Kräizungen hunn
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... Einbahnstrooss oder blockéiert
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kann den Deel vun der Gare net ofrappen...
|
||||
|
||||
@@ -4322,7 +4322,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... denn
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... veien vender i feil retning
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... gjennomkjøringsstopper kan ikke ha hjørner
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... gjennomkjøringsstopper kan ikke ha kryss
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... veien er enveiskjørt eller blokkert
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kan ikke fjerne del av stasjonen...
|
||||
|
||||
@@ -4666,7 +4666,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ta d
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... droga jest zorientowana w złym kierunku
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... przystanki przelotowe nie mogą mieć zakrętów
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... przystanki przelotowe nie mogą mieć skrzyżowań
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... droga jest jednokierunkowa lub zablokowana
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Nie można usunąć części stacji...
|
||||
|
||||
@@ -4318,7 +4318,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... esta
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... estrada orientada na direcção incorrecta
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... estações de passagem não podem ter curvas
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... estações de passagem não podem ter cruzamentos
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... estrada de sentido único ou bloqueada
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Não é possível remover parte da estação...
|
||||
|
||||
@@ -4507,7 +4507,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... эт
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... неверное направление дороги
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... на проходных остановках нельзя делать повороты
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... на проходных остановках нельзя делать перекрёстки
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... дорога односторонняя или заблокирована
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Невозможно удалить часть станции...
|
||||
|
||||
@@ -4443,7 +4443,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ova
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... ulica je okrenuta u drugom pravcu
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... stajalište ne može biti na krivini
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... stajalište ne može biti na raskrsnici
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... put je jednosmeran ili blokiran.
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Deo stanice se ne može ukloniti...
|
||||
|
||||
@@ -4268,7 +4268,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... esta
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... carretera en la dirección incorrecta
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... las estaciones de autobús de paso no pueden tener esquinas
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... las estaciones de autobús de paso no pueden tener intersecciones
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... carretera de un solo sentido o bloqueada
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}No se puede retirar parte de la estación...
|
||||
|
||||
@@ -4318,7 +4318,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... esta
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... carretera en el sentido incorrecto
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... las estaciones y paradas intermedias no pueden ponerse sobre esquinas
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... las estaciones y paradas intermedias no pueden ponerse sobre intersecciones
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... la carretera está bloqueada o es de un solo sentido
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}No se puede quitar parte de la estación...
|
||||
|
||||
@@ -4301,7 +4301,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... dett
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... vägen pekar i fel riktning
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... genomfartshållplatser kan inte ha gatuhörn
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... genomfartshållplatser kan inte ha korsningar
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... vägen är enkelriktad eller blockerad
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kan ej ta bort del av station...
|
||||
|
||||
@@ -4310,7 +4310,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... bu y
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... yol yanlış yönde
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... yol üstü duraklar köşe üzerine inşa edilemez
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... yol üstü duraklar kavşak üzerine inşa edilemez
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... yol tek yön ya da engellenmiş
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}İstasyonun parçasi kaldırılamaz...
|
||||
|
||||
@@ -4446,7 +4446,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ця
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... дорога не в тому напрямку
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... проїзні зупинки не можуть мати поворотів
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... проїзні зупинки не можуть мати перехресть
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... дорога одностороння або заблокована
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Не можна зруйнувати частину станції...
|
||||
|
||||
@@ -4279,7 +4279,6 @@ STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... đâ
|
||||
STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... đường quay mặt sai hướng
|
||||
STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... đi qua điểm dừng không thể đi qua góc
|
||||
STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... đi qua điểm dừng không thể có ngã rẽ
|
||||
STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD :{WHITE}... đường 1 chiều hoặc bị chặn
|
||||
|
||||
# Station destruction related errors
|
||||
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Không thể xoá bỏ một phần của ga...
|
||||
|
||||
@@ -205,6 +205,16 @@ void ZoomInOrOutToCursorWindow(bool in, Window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void FixTitleGameZoom()
|
||||
{
|
||||
if (_game_mode != GM_MENU) return;
|
||||
|
||||
ViewPort *vp = FindWindowByClass(WC_MAIN_WINDOW)->viewport;
|
||||
vp->zoom = _gui_zoom;
|
||||
vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
|
||||
vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
|
||||
}
|
||||
|
||||
static const struct NWidgetPart _nested_main_window_widgets[] = {
|
||||
NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_M_VIEWPORT), SetResize(1, 1),
|
||||
};
|
||||
|
||||
@@ -538,19 +538,19 @@ static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, by
|
||||
}
|
||||
}
|
||||
|
||||
static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *&msg_start, size_t &remaining)
|
||||
static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, const byte *&msg_start, size_t &remaining)
|
||||
{
|
||||
/* Find end of message. */
|
||||
byte *msg_end = msg_start;
|
||||
const byte *msg_end = msg_start;
|
||||
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
||||
msg_end++; // Also include SysEx end byte.
|
||||
|
||||
if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, msg_start) == E_OUTOFMEMORY) {
|
||||
if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
|
||||
/* Buffer is full, clear it and try again. */
|
||||
_port->PlayBuffer(buffer);
|
||||
buffer->Flush();
|
||||
|
||||
buffer->PackUnstructured(rt, 0, msg_end - msg_start, msg_start);
|
||||
buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
|
||||
}
|
||||
|
||||
/* Update position in buffer. */
|
||||
@@ -558,9 +558,11 @@ static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *&
|
||||
msg_start = msg_end;
|
||||
}
|
||||
|
||||
static void TransmitSysexConst(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *msg_start, size_t length)
|
||||
static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
|
||||
{
|
||||
TransmitSysex(buffer, rt, msg_start, length);
|
||||
size_t length = 0;
|
||||
const byte *data = MidiGetStandardSysexMessage(msg, length);
|
||||
TransmitSysex(buffer, rt, data, length);
|
||||
}
|
||||
|
||||
/** Transmit 'Note off' messages to all MIDI channels. */
|
||||
@@ -571,27 +573,16 @@ static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_ti
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
|
||||
}
|
||||
/* Explicitly flush buffer to make sure the note off messages are processed
|
||||
* before we send any additional control messages. */
|
||||
|
||||
/* Performing a GM reset stops all sound and resets all parameters. */
|
||||
TransmitStandardSysex(_buffer, block_time + 20, MidiSysexMessage::ResetGM);
|
||||
TransmitStandardSysex(_buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
|
||||
|
||||
/* Explicitly flush buffer to make sure the messages are processed,
|
||||
* as we want sound to stop immediately. */
|
||||
_port->PlayBuffer(_buffer);
|
||||
_buffer->Flush();
|
||||
|
||||
/* Some songs change the "Pitch bend range" registered parameter. If
|
||||
* this doesn't get reset, everything else will start sounding wrong. */
|
||||
for (int ch = 0; ch < 16; ch++) {
|
||||
/* Running status, only need status for first message
|
||||
* Select RPN 00.00, set value to 02.00, and de-select again */
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_RPN_SELECT_LO, 0x00);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_HI, 0x00);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDICT_DATAENTRY, 0x02);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDICT_DATAENTRY_LO, 0x00);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_LO, 0x7F);
|
||||
TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_HI, 0x7F);
|
||||
|
||||
_port->PlayBuffer(_buffer);
|
||||
_buffer->Flush();
|
||||
}
|
||||
|
||||
/* Wait until message time has passed. */
|
||||
Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
|
||||
}
|
||||
@@ -616,13 +607,6 @@ static void MidiThreadProc(void *)
|
||||
REFERENCE_TIME cur_time;
|
||||
clock->GetTime(&cur_time);
|
||||
|
||||
/* Standard "Enable General MIDI" message */
|
||||
static byte gm_enable_sysex[] = { 0xF0, 0x7E, 0x00, 0x09, 0x01, 0xF7 };
|
||||
TransmitSysexConst(_buffer, cur_time, &gm_enable_sysex[0], sizeof(gm_enable_sysex));
|
||||
/* Roland-specific reverb room control, used by the original game */
|
||||
static byte roland_reverb_sysex[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x30, 0x02, 0x04, 0x00, 0x40, 0x40, 0x00, 0x00, 0x09, 0xF7 };
|
||||
TransmitSysexConst(_buffer, cur_time, &roland_reverb_sysex[0], sizeof(roland_reverb_sysex));
|
||||
|
||||
_port->PlayBuffer(_buffer);
|
||||
_buffer->Flush();
|
||||
|
||||
@@ -665,7 +649,7 @@ static void MidiThreadProc(void *)
|
||||
_playback.do_start = false;
|
||||
}
|
||||
|
||||
/* Turn all notes off in case we are seeking between music titles. */
|
||||
/* Reset playback device between songs. */
|
||||
clock->GetTime(&cur_time);
|
||||
TransmitNotesOff(_buffer, block_time, cur_time);
|
||||
|
||||
@@ -751,7 +735,7 @@ static void MidiThreadProc(void *)
|
||||
block_time = playback_start_time + block.realtime * MIDITIME_TO_REFTIME;
|
||||
DEBUG(driver, 9, "DMusic thread: Streaming block " PRINTF_SIZE " (cur=" OTTD_PRINTF64 ", block=" OTTD_PRINTF64 ")", current_block, (long long)(current_time / MS_TO_REFTIME), (long long)(block_time / MS_TO_REFTIME));
|
||||
|
||||
byte *data = block.data.Begin();
|
||||
const byte *data = block.data.Begin();
|
||||
size_t remaining = block.data.Length();
|
||||
byte last_status = 0;
|
||||
while (remaining > 0) {
|
||||
|
||||
@@ -141,4 +141,19 @@ enum MidiController {
|
||||
MIDICT_MODE_POLY = 127,
|
||||
};
|
||||
|
||||
|
||||
/** Well-known MIDI system exclusive message values for use with the MidiGetStandardSysexMessage function. */
|
||||
enum class MidiSysexMessage {
|
||||
/** Reset device to General MIDI defaults */
|
||||
ResetGM,
|
||||
/** Reset device to (Roland) General Standard defaults */
|
||||
ResetGS,
|
||||
/** Reset device to (Yamaha) XG defaults */
|
||||
ResetXG,
|
||||
/** Set up Roland SoundCanvas reverb room as TTD does */
|
||||
RolandSetReverb,
|
||||
};
|
||||
|
||||
const byte *MidiGetStandardSysexMessage(MidiSysexMessage msg, size_t &length);
|
||||
|
||||
#endif /* MUSIC_MIDI_H */
|
||||
|
||||
@@ -27,6 +27,37 @@
|
||||
|
||||
static MidiFile *_midifile_instance = NULL;
|
||||
|
||||
/**
|
||||
* Retrieve a well-known MIDI system exclusive message.
|
||||
* @param msg Which sysex message to retrieve
|
||||
* @param[out] length Receives the length of the returned buffer
|
||||
* @return Pointer to byte buffer with sysex message
|
||||
*/
|
||||
const byte *MidiGetStandardSysexMessage(MidiSysexMessage msg, size_t &length)
|
||||
{
|
||||
static byte reset_gm_sysex[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 };
|
||||
static byte reset_gs_sysex[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7 };
|
||||
static byte reset_xg_sysex[] = { 0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7 };
|
||||
static byte roland_reverb_sysex[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x30, 0x02, 0x04, 0x00, 0x40, 0x40, 0x00, 0x00, 0x09, 0xF7 };
|
||||
|
||||
switch (msg) {
|
||||
case MidiSysexMessage::ResetGM:
|
||||
length = lengthof(reset_gm_sysex);
|
||||
return reset_gm_sysex;
|
||||
case MidiSysexMessage::ResetGS:
|
||||
length = lengthof(reset_gs_sysex);
|
||||
return reset_gs_sysex;
|
||||
case MidiSysexMessage::ResetXG:
|
||||
length = lengthof(reset_xg_sysex);
|
||||
return reset_xg_sysex;
|
||||
case MidiSysexMessage::RolandSetReverb:
|
||||
length = lengthof(roland_reverb_sysex);
|
||||
return roland_reverb_sysex;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owning byte buffer readable as a stream.
|
||||
* RAII-compliant to make teardown in error situations easier.
|
||||
|
||||
@@ -35,7 +35,7 @@ static struct {
|
||||
CRITICAL_SECTION lock; ///< synchronization for playback status fields
|
||||
|
||||
bool playing; ///< flag indicating that playback is active
|
||||
bool do_start; ///< flag for starting playback of next_file at next opportunity
|
||||
int do_start; ///< flag for starting playback of next_file at next opportunity
|
||||
bool do_stop; ///< flag for stopping playback at next opportunity
|
||||
byte current_volume; ///< current effective volume setting
|
||||
byte new_volume; ///< volume setting to change to
|
||||
@@ -73,10 +73,10 @@ static void TransmitChannelMsg(byte status, byte p1, byte p2 = 0)
|
||||
midiOutShortMsg(_midi.midi_out, status | (p1 << 8) | (p2 << 16));
|
||||
}
|
||||
|
||||
static void TransmitSysex(byte *&msg_start, size_t &remaining)
|
||||
static void TransmitSysex(const byte *&msg_start, size_t &remaining)
|
||||
{
|
||||
/* find end of message */
|
||||
byte *msg_end = msg_start;
|
||||
const byte *msg_end = msg_start;
|
||||
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
||||
msg_end++; /* also include sysex end byte */
|
||||
|
||||
@@ -97,9 +97,11 @@ static void TransmitSysex(byte *&msg_start, size_t &remaining)
|
||||
msg_start = msg_end;
|
||||
}
|
||||
|
||||
static void TransmitSysexConst(byte *msg_start, size_t length)
|
||||
static void TransmitStandardSysex(MidiSysexMessage msg)
|
||||
{
|
||||
TransmitSysex(msg_start, length);
|
||||
size_t length = 0;
|
||||
const byte *data = MidiGetStandardSysexMessage(msg, length);
|
||||
TransmitSysex(data, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,82 +110,94 @@ static void TransmitSysexConst(byte *msg_start, size_t length)
|
||||
*/
|
||||
void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR)
|
||||
{
|
||||
/* Try to check playback status changes.
|
||||
* If _midi is already locked, skip checking for this cycle and try again
|
||||
* next cycle, instead of waiting for locks in the realtime callback. */
|
||||
if (TryEnterCriticalSection(&_midi.lock)) {
|
||||
/* check for stop */
|
||||
if (_midi.do_stop) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set");
|
||||
midiOutReset(_midi.midi_out);
|
||||
_midi.playing = false;
|
||||
_midi.do_stop = false;
|
||||
/* Ensure only one timer callback is running at once, and prevent races on status flags */
|
||||
if (!TryEnterCriticalSection(&_midi.lock)) return;
|
||||
|
||||
/* check for stop */
|
||||
if (_midi.do_stop) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set");
|
||||
midiOutReset(_midi.midi_out);
|
||||
_midi.playing = false;
|
||||
_midi.do_stop = false;
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for start/restart/change song */
|
||||
if (_midi.do_start != 0) {
|
||||
/* Have a delay between playback start steps, prevents jumbled-together notes at the start of song */
|
||||
if (timeGetTime() - _midi.playback_start_time < 50) {
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
}
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_start step %d", _midi.do_start);
|
||||
|
||||
/* check for start/restart/change song */
|
||||
if (_midi.do_start) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_start is set");
|
||||
if (_midi.playing) {
|
||||
midiOutReset(_midi.midi_out);
|
||||
/* Some songs change the "Pitch bend range" registered
|
||||
* parameter. If this doesn't get reset, everything else
|
||||
* will start sounding wrong. */
|
||||
for (int ch = 0; ch < 16; ch++) {
|
||||
/* Running status, only need status for first message */
|
||||
/* Select RPN 00.00, set value to 02.00, and unselect again */
|
||||
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_RPN_SELECT_LO, 0x00);
|
||||
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x00);
|
||||
TransmitChannelMsg(MIDICT_DATAENTRY, 0x02);
|
||||
TransmitChannelMsg(MIDICT_DATAENTRY_LO, 0x00);
|
||||
TransmitChannelMsg(MIDICT_RPN_SELECT_LO, 0x7F);
|
||||
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x7F);
|
||||
}
|
||||
}
|
||||
if (_midi.do_start == 1) {
|
||||
/* Send "all notes off" */
|
||||
midiOutReset(_midi.midi_out);
|
||||
_midi.playback_start_time = timeGetTime();
|
||||
_midi.do_start = 2;
|
||||
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
} else if (_midi.do_start == 2) {
|
||||
/* Reset the device to General MIDI defaults */
|
||||
TransmitStandardSysex(MidiSysexMessage::ResetGM);
|
||||
_midi.playback_start_time = timeGetTime();
|
||||
_midi.do_start = 3;
|
||||
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
} else if (_midi.do_start == 3) {
|
||||
/* Set up device-specific effects */
|
||||
TransmitStandardSysex(MidiSysexMessage::RolandSetReverb);
|
||||
_midi.playback_start_time = timeGetTime();
|
||||
_midi.do_start = 4;
|
||||
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
} else if (_midi.do_start == 4) {
|
||||
/* Load the new file */
|
||||
_midi.current_file.MoveFrom(_midi.next_file);
|
||||
std::swap(_midi.next_segment, _midi.current_segment);
|
||||
_midi.current_segment.start_block = 0;
|
||||
_midi.playback_start_time = timeGetTime();
|
||||
_midi.playing = true;
|
||||
_midi.do_start = false;
|
||||
_midi.do_start = 0;
|
||||
_midi.current_block = 0;
|
||||
|
||||
MemSetT<byte>(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes));
|
||||
} else if (!_midi.playing) {
|
||||
/* not playing, stop the timer */
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer");
|
||||
timeKillEvent(uTimerID);
|
||||
_midi.timer_id = 0;
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for volume change */
|
||||
static int volume_throttle = 0;
|
||||
if (_midi.current_volume != _midi.new_volume) {
|
||||
if (volume_throttle == 0) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: volume change");
|
||||
_midi.current_volume = _midi.new_volume;
|
||||
volume_throttle = 20 / _midi.time_period;
|
||||
for (int ch = 0; ch < 16; ch++) {
|
||||
int vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume);
|
||||
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
volume_throttle--;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!_midi.playing) {
|
||||
/* not playing, stop the timer */
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer");
|
||||
timeKillEvent(uTimerID);
|
||||
_midi.timer_id = 0;
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for volume change */
|
||||
static int volume_throttle = 0;
|
||||
if (_midi.current_volume != _midi.new_volume) {
|
||||
if (volume_throttle == 0) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: volume change");
|
||||
_midi.current_volume = _midi.new_volume;
|
||||
volume_throttle = 20 / _midi.time_period;
|
||||
for (int ch = 0; ch < 16; ch++) {
|
||||
byte vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume);
|
||||
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
|
||||
}
|
||||
} else {
|
||||
volume_throttle--;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip beginning of file? */
|
||||
if (_midi.current_segment.start > 0 && _midi.current_block == 0 && _midi.current_segment.start_block == 0) {
|
||||
/* find first block after start time and pretend playback started earlier
|
||||
* this is to allow all blocks prior to the actual start to still affect playback,
|
||||
* as they may contain important controller and program changes */
|
||||
* this is to allow all blocks prior to the actual start to still affect playback,
|
||||
* as they may contain important controller and program changes */
|
||||
uint preload_bytes = 0;
|
||||
for (size_t bl = 0; bl < _midi.current_file.blocks.size(); bl++) {
|
||||
MidiFile::DataBlock &block = _midi.current_file.blocks[bl];
|
||||
@@ -200,7 +214,7 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
||||
* The delay compensation is needed to avoid time-compression of following messages.
|
||||
*/
|
||||
DEBUG(driver, 2, "Win32-MIDI: timer: start from block %d (ticktime %d, realtime %.3f, bytes %d)", (int)bl, (int)block.ticktime, ((int)block.realtime) / 1000.0, (int)preload_bytes);
|
||||
_midi.playback_start_time -= block.realtime / 1000 - preload_bytes * 1000 / 3125;
|
||||
_midi.playback_start_time -= block.realtime / 1000 - (DWORD)(preload_bytes * 1000 / 3125);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -229,7 +243,7 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
||||
break;
|
||||
}
|
||||
|
||||
byte *data = block.data.Begin();
|
||||
const byte *data = block.data.Begin();
|
||||
size_t remaining = block.data.Length();
|
||||
byte last_status = 0;
|
||||
while (remaining > 0) {
|
||||
@@ -308,25 +322,28 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
||||
_midi.do_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
}
|
||||
|
||||
void MusicDriver_Win32::PlaySong(const MusicSongInfo &song)
|
||||
{
|
||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: entry");
|
||||
|
||||
MidiFile new_song;
|
||||
if (!new_song.LoadSong(song)) return;
|
||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: Loaded song");
|
||||
|
||||
EnterCriticalSection(&_midi.lock);
|
||||
|
||||
if (!_midi.next_file.LoadSong(song)) {
|
||||
LeaveCriticalSection(&_midi.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
_midi.next_file.MoveFrom(new_song);
|
||||
_midi.next_segment.start = song.override_start;
|
||||
_midi.next_segment.end = song.override_end;
|
||||
_midi.next_segment.loop = song.loop;
|
||||
|
||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
|
||||
_midi.do_stop = _midi.playing;
|
||||
_midi.do_start = true;
|
||||
_midi.do_start = 1;
|
||||
|
||||
if (_midi.timer_id == 0) {
|
||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer");
|
||||
@@ -347,7 +364,7 @@ void MusicDriver_Win32::StopSong()
|
||||
|
||||
bool MusicDriver_Win32::IsSongPlaying()
|
||||
{
|
||||
return _midi.playing || _midi.do_start;
|
||||
return _midi.playing || (_midi.do_start != 0);
|
||||
}
|
||||
|
||||
void MusicDriver_Win32::SetVolume(byte vol)
|
||||
@@ -381,14 +398,6 @@ const char *MusicDriver_Win32::Start(const char * const *parm)
|
||||
|
||||
midiOutReset(_midi.midi_out);
|
||||
|
||||
/* Standard "Enable General MIDI" message */
|
||||
static byte gm_enable_sysex[] = { 0xF0, 0x7E, 0x00, 0x09, 0x01, 0xF7 };
|
||||
TransmitSysexConst(&gm_enable_sysex[0], sizeof(gm_enable_sysex));
|
||||
|
||||
/* Roland-specific reverb room control, used by the original game */
|
||||
static byte roland_reverb_sysex[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x30, 0x02, 0x04, 0x00, 0x40, 0x40, 0x00, 0x00, 0x09, 0xF7 };
|
||||
TransmitSysexConst(&roland_reverb_sysex[0], sizeof(roland_reverb_sysex));
|
||||
|
||||
/* prepare multimedia timer */
|
||||
TIMECAPS timecaps;
|
||||
if (timeGetDevCaps(&timecaps, sizeof(timecaps)) == MMSYSERR_NOERROR) {
|
||||
|
||||
@@ -5480,7 +5480,8 @@ static void RailTypeMapSpriteGroup(ByteReader *buf, uint8 idcount)
|
||||
{
|
||||
uint8 *railtypes = AllocaM(uint8, idcount);
|
||||
for (uint i = 0; i < idcount; i++) {
|
||||
railtypes[i] = _cur.grffile->railtype_map[buf->ReadByte()];
|
||||
uint8 id = buf->ReadByte();
|
||||
railtypes[i] = id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE;
|
||||
}
|
||||
|
||||
uint8 cidcount = buf->ReadByte();
|
||||
|
||||
@@ -163,7 +163,7 @@ struct GRFLoadedFeatures {
|
||||
uint64 used_liveries; ///< Bitmask of #LiveryScheme used by the defined engines.
|
||||
bool has_newhouses; ///< Set if there are any newhouses loaded.
|
||||
bool has_newindustries; ///< Set if there are any newindustries loaded.
|
||||
ShoreReplacement shore; ///< It which way shore sprites were replaced.
|
||||
ShoreReplacement shore; ///< In which way shore sprites were replaced.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,8 +45,8 @@ const NewsItem *_statusbar_news_item = NULL;
|
||||
|
||||
static uint MIN_NEWS_AMOUNT = 30; ///< preferred minimum amount of news messages
|
||||
static uint _total_news = 0; ///< current number of news items
|
||||
NewsItem *_oldest_news = NULL; ///< head of news items queue
|
||||
static NewsItem *_latest_news = NULL; ///< tail of news items queue
|
||||
static NewsItem *_oldest_news = NULL; ///< head of news items queue
|
||||
NewsItem *_latest_news = NULL; ///< tail of news items queue
|
||||
|
||||
/**
|
||||
* Forced news item.
|
||||
@@ -54,7 +54,7 @@ static NewsItem *_latest_news = NULL; ///< tail of news items queue
|
||||
* If the message being shown was forced by the user, a pointer is stored
|
||||
* in _forced_news. Otherwise, \a _forced_news variable is NULL.
|
||||
*/
|
||||
static const NewsItem *_forced_news = NULL; ///< item the user has asked for
|
||||
static const NewsItem *_forced_news = NULL;
|
||||
|
||||
/** Current news item (last item shown regularly). */
|
||||
static const NewsItem *_current_news = NULL;
|
||||
@@ -331,6 +331,11 @@ struct NewsWindow : Window {
|
||||
*size = maxdim(*size, GetSpriteSize(SPR_GRADIENT));
|
||||
break;
|
||||
|
||||
case WID_N_MGR_NAME:
|
||||
SetDParamStr(0, static_cast<const CompanyNewsInformation *>(this->ni->free_data)->president_name);
|
||||
str = STR_JUST_RAW_STRING;
|
||||
break;
|
||||
|
||||
case WID_N_MESSAGE:
|
||||
CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
|
||||
str = this->ni->string_id;
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
void ShowLastNewsMessage();
|
||||
void ShowMessageHistory();
|
||||
|
||||
extern NewsItem *_oldest_news;
|
||||
extern NewsItem *_latest_news;
|
||||
|
||||
#endif /* NEWS_GUI_H */
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#include "town.h"
|
||||
#include "subsidy_func.h"
|
||||
#include "gfx_layout.h"
|
||||
#include "viewport_func.h"
|
||||
#include "viewport_sprite_sorter.h"
|
||||
#include "framerate_type.h"
|
||||
|
||||
@@ -339,6 +340,7 @@ static void LoadIntroGame(bool load_newgrfs = true)
|
||||
SetLocalCompany(COMPANY_FIRST);
|
||||
}
|
||||
|
||||
FixTitleGameZoom();
|
||||
_pause_mode = PM_UNPAUSED;
|
||||
_cursor.fix_at = false;
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ public:
|
||||
char message[1024];
|
||||
seprintf(message, lastof(message),
|
||||
"Please send the generated crash information and the last (auto)save to the developers. "
|
||||
"This will greatly help debugging. The correct place to do this is http://bugs.openttd.org.\n\n"
|
||||
"This will greatly help debugging. The correct place to do this is https://github.com/OpenTTD/OpenTTD/issues.\n\n"
|
||||
"Generated file(s):\n%s\n%s\n%s",
|
||||
this->filename_log, this->filename_save, this->filename_screenshot);
|
||||
|
||||
|
||||
@@ -582,7 +582,7 @@ static bool _expanded;
|
||||
static const TCHAR _crash_desc[] =
|
||||
_T("A serious fault condition occurred in the game. The game will shut down.\n")
|
||||
_T("Please send the crash information and the crash.dmp file (if any) to the developers.\n")
|
||||
_T("This will greatly help debugging. The correct place to do this is http://bugs.openttd.org. ")
|
||||
_T("This will greatly help debugging. The correct place to do this is https://github.com/OpenTTD/OpenTTD/issues. ")
|
||||
_T("The information contained in the report is displayed below.\n")
|
||||
_T("Press \"Emergency save\" to attempt saving the game. Generated file(s):\n")
|
||||
_T("%s");
|
||||
|
||||
@@ -79,8 +79,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,9,1,!!ISODATE!!
|
||||
PRODUCTVERSION 1,9,1,!!ISODATE!!
|
||||
FILEVERSION 1,9,2,!!ISODATE!!
|
||||
PRODUCTVERSION 1,9,2,!!ISODATE!!
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -1565,6 +1565,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
|
||||
bool found_convertible_track = false; // whether we actually did convert some track (see bug #7633)
|
||||
|
||||
TileIterator *iter = diagonal ? (TileIterator *)new DiagonalTileIterator(area_start, area_end) : new OrthogonalTileIterator(area_start, area_end);
|
||||
for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
|
||||
@@ -1660,6 +1661,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
|
||||
InvalidateWindowData(WC_BUILD_VEHICLE, tile);
|
||||
}
|
||||
found_convertible_track = true;
|
||||
cost.AddCost(RailConvertCost(type, totype));
|
||||
break;
|
||||
|
||||
@@ -1671,6 +1673,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
|
||||
}
|
||||
}
|
||||
found_convertible_track = true;
|
||||
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
|
||||
break;
|
||||
}
|
||||
@@ -1733,6 +1736,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
}
|
||||
|
||||
found_convertible_track = true;
|
||||
cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
|
||||
break;
|
||||
}
|
||||
@@ -1743,6 +1747,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
}
|
||||
|
||||
found_convertible_track = true;
|
||||
cost.AddCost(RailConvertCost(type, totype));
|
||||
break;
|
||||
}
|
||||
@@ -1760,7 +1765,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
|
||||
delete iter;
|
||||
return (cost.GetCost() == 0) ? error : cost;
|
||||
return found_convertible_track ? cost : error;
|
||||
}
|
||||
|
||||
static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
|
||||
|
||||
@@ -82,7 +82,7 @@ const byte _openttd_revision_tagged = !!ISTAG!!;
|
||||
* final release will always have a lower version number than the released
|
||||
* version, thus making comparisons on specific revisions easy.
|
||||
*/
|
||||
const uint32 _openttd_newgrf_version = 1 << 28 | 9 << 24 | 1 << 20 | !!ISSTABLETAG!! << 19 | 28004;
|
||||
const uint32 _openttd_newgrf_version = 1 << 28 | 9 << 24 | 2 << 20 | !!ISSTABLETAG!! << 19 | 28004;
|
||||
|
||||
#ifdef __MORPHOS__
|
||||
/**
|
||||
|
||||
@@ -1132,6 +1132,38 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
/* Railtype moved from m3 to m8 in version SLV_EXTEND_RAILTYPES. */
|
||||
if (IsSavegameVersionBefore(SLV_EXTEND_RAILTYPES)) {
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
switch (GetTileType(t)) {
|
||||
case MP_RAILWAY:
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
break;
|
||||
|
||||
case MP_ROAD:
|
||||
if (IsLevelCrossing(t)) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_STATION:
|
||||
if (HasStationRail(t)) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_42)) {
|
||||
Vehicle *v;
|
||||
|
||||
@@ -1213,38 +1245,6 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
/* Railtype moved from m3 to m8 in version SLV_EXTEND_RAILTYPES. */
|
||||
if (IsSavegameVersionBefore(SLV_EXTEND_RAILTYPES)) {
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
switch (GetTileType(t)) {
|
||||
case MP_RAILWAY:
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
break;
|
||||
|
||||
case MP_ROAD:
|
||||
if (IsLevelCrossing(t)) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_STATION:
|
||||
if (HasStationRail(t)) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
|
||||
SetRailType(t, (RailType)GB(_m[t].m3, 0, 4));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Elrails got added in rev 24 */
|
||||
if (IsSavegameVersionBefore(SLV_24)) {
|
||||
RailType min_rail = RAILTYPE_ELECTRIC;
|
||||
@@ -1893,6 +1893,7 @@ bool AfterLoadGame()
|
||||
}
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_62)) {
|
||||
GroupStatistics::UpdateAfterLoad(); // Ensure statistics pool is initialised before trying to delete vehicles
|
||||
/* Remove all trams from savegames without tram support.
|
||||
* There would be trams without tram track under causing crashes sooner or later. */
|
||||
RoadVehicle *v;
|
||||
@@ -2304,6 +2305,14 @@ bool AfterLoadGame()
|
||||
if (IsSavegameVersionBefore(SLV_128)) {
|
||||
const Depot *d;
|
||||
FOR_ALL_DEPOTS(d) {
|
||||
/* At some point, invalid depots were saved into the game (possibly those removed in the past?)
|
||||
* Remove them here, so they don't cause issues further down the line */
|
||||
if (!IsDepotTile(d->xy)) {
|
||||
DEBUG(sl, 0, "Removing invalid depot %d at %d, %d", d->index, TileX(d->xy), TileY(d->xy));
|
||||
delete d;
|
||||
d = nullptr;
|
||||
continue;
|
||||
}
|
||||
_m[d->xy].m2 = d->index;
|
||||
if (IsTileType(d->xy, MP_WATER)) _m[GetOtherShipDepotTile(d->xy)].m2 = d->index;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,8 @@ void AfterLoadLinkGraphs()
|
||||
LinkGraph *lg;
|
||||
FOR_ALL_LINK_GRAPHS(lg) {
|
||||
for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
|
||||
(*lg)[node_id].UpdateLocation(Station::Get((*lg)[node_id].Station())->xy);
|
||||
const Station *st = Station::GetIfValid((*lg)[node_id].Station());
|
||||
if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +242,8 @@ void AfterLoadLinkGraphs()
|
||||
FOR_ALL_LINK_GRAPH_JOBS(lgj) {
|
||||
lg = &(const_cast<LinkGraph &>(lgj->Graph()));
|
||||
for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
|
||||
(*lg)[node_id].UpdateLocation(Station::Get((*lg)[node_id].Station())->xy);
|
||||
const Station *st = Station::GetIfValid((*lg)[node_id].Station());
|
||||
if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2889,36 +2889,3 @@ void FileToSaveLoad::SetTitle(const char *title)
|
||||
{
|
||||
strecpy(this->title, title, lastof(this->title));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Function to get the type of the savegame by looking at the file header.
|
||||
* NOTICE: Not used right now, but could be used if extensions of savegames are garbled
|
||||
* @param file Savegame to be checked
|
||||
* @return SL_OLD_LOAD or SL_LOAD of the file
|
||||
*/
|
||||
int GetSavegameType(char *file)
|
||||
{
|
||||
const SaveLoadFormat *fmt;
|
||||
uint32 hdr;
|
||||
FILE *f;
|
||||
int mode = SL_OLD_LOAD;
|
||||
|
||||
f = fopen(file, "rb");
|
||||
if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
|
||||
DEBUG(sl, 0, "Savegame is obsolete or invalid format");
|
||||
mode = SL_LOAD; // don't try to get filename, just show name as it is written
|
||||
} else {
|
||||
/* see if we have any loader for this type. */
|
||||
for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) {
|
||||
if (fmt->tag == hdr) {
|
||||
mode = SL_LOAD; // new type of savegame
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return mode;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
return g != NULL && g->completed;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGoal::DoQuestion(uint16 uniqueid, uint8 target, bool is_client, Text *question, QuestionType type, int buttons)
|
||||
/* static */ bool ScriptGoal::DoQuestion(uint16 uniqueid, uint32 target, bool is_client, Text *question, QuestionType type, uint32 buttons)
|
||||
{
|
||||
CCountedPtr<Text> counter(question);
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
EnforcePrecondition(false, buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT));
|
||||
EnforcePrecondition(false, (int)type < ::GOAL_QUESTION_TYPE_COUNT);
|
||||
|
||||
return ScriptObject::DoCommand(0, uniqueid | (target << 16) | (type << 24) | (is_client ? (1 << 31) : 0), buttons, CMD_GOAL_QUESTION, text);
|
||||
return ScriptObject::DoCommand(0, uniqueid | (target << 16), buttons | (type << 29) | (is_client ? (1 << 31) : 0), CMD_GOAL_QUESTION, text);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons)
|
||||
@@ -138,8 +138,9 @@
|
||||
EnforcePrecondition(false, ScriptGame::IsMultiplayer());
|
||||
EnforcePrecondition(false, ScriptClient::ResolveClientID(client) != ScriptClient::CLIENT_INVALID);
|
||||
#ifdef ENABLE_NETWORK
|
||||
ClientIndex c = NetworkClientInfo::GetByClientID((::ClientID)client)->index;
|
||||
return DoQuestion(uniqueid, c, true, question, type, buttons);
|
||||
/* Can only send 16 bits of client_id before proper fix is implemented */
|
||||
EnforcePrecondition(false, client < (1 << 16));
|
||||
return DoQuestion(uniqueid, client, true, question, type, buttons);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -211,7 +211,7 @@ protected:
|
||||
/**
|
||||
* Does common checks and asks the question.
|
||||
*/
|
||||
static bool DoQuestion(uint16 uniqueid, uint8 target, bool is_client, Text *question, QuestionType type, int buttons);
|
||||
static bool DoQuestion(uint16 uniqueid, uint32 target, bool is_client, Text *question, QuestionType type, uint32 buttons);
|
||||
};
|
||||
|
||||
#endif /* SCRIPT_GOAL_HPP */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "script_station.hpp"
|
||||
#include "../../depot_map.h"
|
||||
#include "../../vehicle_base.h"
|
||||
#include "../../train.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
@@ -23,7 +24,7 @@ ScriptVehicleList::ScriptVehicleList()
|
||||
{
|
||||
const Vehicle *v;
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle()) this->AddItem(v->index);
|
||||
if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon()))) this->AddItem(v->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "stringfilter_type.h"
|
||||
#include "querystring_gui.h"
|
||||
#include "fontcache.h"
|
||||
#include "zoom_func.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -557,6 +558,7 @@ struct GameOptionsWindow : Window {
|
||||
_gui_zoom = (ZoomLevel)(ZOOM_LVL_OUT_4X - index);
|
||||
UpdateCursorSize();
|
||||
UpdateAllVirtCoords();
|
||||
FixTitleGameZoom();
|
||||
ReInitAllWindows();
|
||||
break;
|
||||
|
||||
|
||||
@@ -995,9 +995,12 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD));
|
||||
}
|
||||
|
||||
if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_ONEWAY_ROAD);
|
||||
if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE) {
|
||||
CommandCost ret = CheckOwnership(road_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* There is a tram, check if we can build road+tram stop over it. */
|
||||
if (HasBit(cur_rts, ROADTYPE_TRAM)) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "toolbar_gui.h"
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "guitimer_func.h"
|
||||
#include "zoom_func.h"
|
||||
|
||||
#include "widgets/statusbar_widget.h"
|
||||
|
||||
@@ -166,7 +167,7 @@ struct StatusBarWindow : Window {
|
||||
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_PAUSED, TC_FROMSTRING, SA_HOR_CENTER);
|
||||
} else if (this->ticker_scroll < TICKER_STOP && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item != NULL && _statusbar_news_item->string_id != 0) {
|
||||
/* Draw the scrolling news text */
|
||||
if (!DrawScrollingStatusText(_statusbar_news_item, this->ticker_scroll, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) {
|
||||
if (!DrawScrollingStatusText(_statusbar_news_item, ScaleGUITrad(this->ticker_scroll), r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) {
|
||||
InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED);
|
||||
if (Company::IsValidID(_local_company)) {
|
||||
/* This is the default text */
|
||||
|
||||
21
src/stdafx.h
21
src/stdafx.h
@@ -257,6 +257,13 @@
|
||||
# if !defined(FT_EXPORT)
|
||||
# define FT_EXPORT( x ) extern "C" x CDECL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* liblzma from vcpkg (before 5.2.4-2) used to patch lzma.h to define LZMA_API_STATIC for static builds */
|
||||
# if defined(WITH_LZMA)
|
||||
# if !defined(LZMA_API_STATIC)
|
||||
# define LZMA_API_STATIC
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#define strcasecmp stricmp
|
||||
@@ -319,13 +326,15 @@
|
||||
|
||||
/* MSVCRT of course has to have a different syntax for long long *sigh* */
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define OTTD_PRINTF64 "%I64d"
|
||||
#define OTTD_PRINTFHEX64 "%I64x"
|
||||
#define PRINTF_SIZE "%Iu"
|
||||
# define OTTD_PRINTF64 "%I64d"
|
||||
# define OTTD_PRINTFHEX64 "%I64x"
|
||||
# define PRINTF_SIZE "%Iu"
|
||||
# define PRINTF_SIZEX "%IX"
|
||||
#else
|
||||
#define OTTD_PRINTF64 "%lld"
|
||||
#define OTTD_PRINTFHEX64 "%llx"
|
||||
#define PRINTF_SIZE "%zu"
|
||||
# define OTTD_PRINTF64 "%lld"
|
||||
# define OTTD_PRINTFHEX64 "%llx"
|
||||
# define PRINTF_SIZE "%zu"
|
||||
# define PRINTF_SIZEX "%zX"
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
@@ -29,12 +29,12 @@ struct LangString {
|
||||
char *name; ///< Name of the string.
|
||||
char *english; ///< English text.
|
||||
char *translated; ///< Translated text.
|
||||
uint16 hash_next; ///< Next hash entry.
|
||||
uint16 index; ///< The index in the language file.
|
||||
size_t hash_next; ///< Next hash entry.
|
||||
size_t index; ///< The index in the language file.
|
||||
int line; ///< Line of string in source-file.
|
||||
Case *translated_case; ///< Cases of the translation.
|
||||
|
||||
LangString(const char *name, const char *english, int index, int line);
|
||||
LangString(const char *name, const char *english, size_t index, int line);
|
||||
~LangString();
|
||||
void FreeTranslation();
|
||||
};
|
||||
@@ -42,10 +42,10 @@ struct LangString {
|
||||
/** Information about the currently known strings. */
|
||||
struct StringData {
|
||||
LangString **strings; ///< Array of all known strings.
|
||||
uint16 *hash_heads; ///< Hash table for the strings.
|
||||
size_t *hash_heads; ///< Hash table for the strings.
|
||||
size_t tabs; ///< The number of 'tabs' of strings.
|
||||
size_t max_strings; ///< The maximum number of strings.
|
||||
int next_string_id; ///< The next string ID to allocate.
|
||||
size_t next_string_id;///< The next string ID to allocate.
|
||||
|
||||
StringData(size_t tabs);
|
||||
~StringData();
|
||||
|
||||
@@ -58,7 +58,7 @@ Case::~Case()
|
||||
* @param index The index in the string table.
|
||||
* @param line The line this string was found on.
|
||||
*/
|
||||
LangString::LangString(const char *name, const char *english, int index, int line) :
|
||||
LangString::LangString(const char *name, const char *english, size_t index, int line) :
|
||||
name(stredup(name)), english(stredup(english)), translated(NULL),
|
||||
hash_next(0), index(index), line(line), translated_case(NULL)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ void LangString::FreeTranslation()
|
||||
StringData::StringData(size_t tabs) : tabs(tabs), max_strings(tabs * TAB_SIZE)
|
||||
{
|
||||
this->strings = CallocT<LangString *>(max_strings);
|
||||
this->hash_heads = CallocT<uint16>(max_strings);
|
||||
this->hash_heads = CallocT<size_t>(max_strings);
|
||||
this->next_string_id = 0;
|
||||
}
|
||||
|
||||
@@ -144,9 +144,9 @@ void StringData::Add(const char *s, LangString *ls)
|
||||
*/
|
||||
LangString *StringData::Find(const char *s)
|
||||
{
|
||||
int idx = this->hash_heads[this->HashStr(s)];
|
||||
size_t idx = this->hash_heads[this->HashStr(s)];
|
||||
|
||||
while (--idx >= 0) {
|
||||
while (idx-- > 0) {
|
||||
LangString *ls = this->strings[idx];
|
||||
|
||||
if (strcmp(ls->name, s) == 0) return ls;
|
||||
@@ -764,7 +764,7 @@ void StringReader::HandleString(char *str)
|
||||
}
|
||||
|
||||
if (this->data.strings[this->data.next_string_id] != NULL) {
|
||||
strgen_error("String ID 0x%X for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name);
|
||||
strgen_error("String ID 0x" PRINTF_SIZEX " for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -830,11 +830,15 @@ void StringReader::ParseFile()
|
||||
strecpy(_lang.digit_decimal_separator, ".", lastof(_lang.digit_decimal_separator));
|
||||
|
||||
_cur_line = 1;
|
||||
while (this->ReadLine(buf, lastof(buf)) != NULL) {
|
||||
while (this->data.next_string_id < this->data.max_strings && this->ReadLine(buf, lastof(buf)) != NULL) {
|
||||
rstrip(buf);
|
||||
this->HandleString(buf);
|
||||
_cur_line++;
|
||||
}
|
||||
|
||||
if (this->data.next_string_id == this->data.max_strings) {
|
||||
strgen_error("Too many strings, maximum allowed is " PRINTF_SIZE, this->data.max_strings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -333,6 +333,7 @@ bool FindSubsidyTownCargoRoute()
|
||||
|
||||
/* Select a random town. */
|
||||
const Town *src_town = Town::GetRandom();
|
||||
if (src_town->cache.population < SUBSIDY_CARGO_MIN_POPULATION) return false;
|
||||
|
||||
CargoTypes town_cargo_produced = src_town->cargo_produced;
|
||||
|
||||
|
||||
@@ -2574,6 +2574,7 @@ max = 3
|
||||
str = STR_CONFIG_SETTING_SCROLLMODE
|
||||
strhelp = STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT
|
||||
strval = STR_CONFIG_SETTING_SCROLLMODE_DEFAULT
|
||||
cat = SC_BASIC
|
||||
|
||||
[SDTC_BOOL]
|
||||
var = gui.smooth_scroll
|
||||
@@ -3730,7 +3731,7 @@ var = network.lan_internet
|
||||
type = SLE_UINT8
|
||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||
guiflags = SGF_NETWORK_ONLY
|
||||
def = 0
|
||||
def = 1
|
||||
min = 0
|
||||
max = 1
|
||||
|
||||
|
||||
@@ -1991,7 +1991,7 @@ static const char * const _name_romanian_real[] = {
|
||||
"Motru",
|
||||
"N\xC4\x83s\xC4\x83ud",
|
||||
"N\xC4\x83vodari",
|
||||
"Odobe\xC8x99ti",
|
||||
"Odobe\xC8\x99ti",
|
||||
"Olteni\xC8\x9B""a",
|
||||
"One\xC8\x99ti",
|
||||
"Oradea",
|
||||
|
||||
@@ -34,6 +34,7 @@ void MarkAllViewportsDirty(int left, int top, int right, int bottom);
|
||||
bool DoZoomInOutWindow(ZoomStateChange how, Window *w);
|
||||
void ZoomInOrOutToCursorWindow(bool in, Window * w);
|
||||
Point GetTileZoomCenterWindow(bool in, Window * w);
|
||||
void FixTitleGameZoom();
|
||||
void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2634,7 +2634,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest,
|
||||
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
|
||||
if (nwrb != NULL) {
|
||||
assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0);
|
||||
nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y);
|
||||
nwrb->SetMinimalSize(ScaleGUITrad(parts->u.xy.x), ScaleGUITrad(parts->u.xy.y));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2664,7 +2664,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest,
|
||||
}
|
||||
|
||||
case WPT_PADDING:
|
||||
if (*dest != NULL) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left);
|
||||
if (*dest != NULL) (*dest)->SetPadding(ScaleGUITrad(parts->u.padding.top), ScaleGUITrad(parts->u.padding.right), ScaleGUITrad(parts->u.padding.bottom), ScaleGUITrad(parts->u.padding.left));
|
||||
break;
|
||||
|
||||
case WPT_PIPSPACE: {
|
||||
|
||||
@@ -2414,7 +2414,7 @@ static void HandleScrollbarScrolling(Window *w)
|
||||
}
|
||||
|
||||
/* Find the item we want to move to and make sure it's inside bounds. */
|
||||
int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity()));
|
||||
int pos = min(RoundDivSU(max(0, i + _scrollbar_start_pos) * sb->GetCount(), _scrollbar_size), max(0, sb->GetCount() - sb->GetCapacity()));
|
||||
if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos);
|
||||
if (pos != sb->GetPosition()) {
|
||||
sb->SetPosition(pos);
|
||||
|
||||
Reference in New Issue
Block a user