Merge branch 'master' into jgrpp-nrt
Merge trunk multiple docks implementation # Conflicts: # docs/landscape_grid.html # src/order_cmd.cpp # src/pathfinder/npf/npf.cpp # src/pathfinder/yapf/yapf_ship.cpp # src/rail_cmd.cpp # src/saveload/afterload.cpp # src/saveload/oldloader_sl.cpp # src/saveload/station_sl.cpp # src/script/api/script_order.cpp # src/ship_cmd.cpp # src/station.cpp # src/station_base.h # src/station_cmd.cpp # src/tunnelbridge_cmd.cpp
This commit is contained in:
@@ -255,6 +255,7 @@
|
|||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for half-tile with water)</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the tile</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the tile</li>
|
||||||
<li>m2: see signals</li>
|
<li>m2: see signals</li>
|
||||||
<li>m3 bits 7..4: see signals</li>
|
<li>m3 bits 7..4: see signals</li>
|
||||||
@@ -885,6 +886,7 @@
|
|||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for buoys)</li>
|
||||||
<li>m1 bits 6..5: water class for buoys, water part of docks and for airport tiles</li>
|
<li>m1 bits 6..5: water class for buoys, water part of docks and for airport tiles</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the station</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> of the station</li>
|
||||||
<li>m2: index into the array of stations</li>
|
<li>m2: index into the array of stations</li>
|
||||||
@@ -1022,6 +1024,7 @@
|
|||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status</li>
|
||||||
<li>m1 bits 6..5 : Water class (sea, canal or river)
|
<li>m1 bits 6..5 : Water class (sea, canal or river)
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
|
||||||
<li>m2: Depot index (for depots only)</li>
|
<li>m2: Depot index (for depots only)</li>
|
||||||
@@ -1473,6 +1476,7 @@
|
|||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m1 bit 7: Ship docking tile status (for aqueducts)</li>
|
||||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a></li>
|
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a></li>
|
||||||
<li style="color: blue">m2 bits 7..0: custom road bridge heads (flat bridge heads only)<br>
|
<li style="color: blue">m2 bits 7..0: custom road bridge heads (flat bridge heads only)<br>
|
||||||
Road/tram bits below are XORed with the axial bridge direction road bits.<br>
|
Road/tram bits below are XORed with the axial bridge direction road bits.<br>
|
||||||
|
@@ -102,7 +102,7 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="caption">rail</td>
|
<td class="caption">rail</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOO</span>X XXXX</td>
|
<td class="bits">X<span class="free">OO</span>X XXXX</td>
|
||||||
<td class="bits"><span class="free">OOOO</span> XXXX <span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO</span> XXXX <span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO</span> XXXX</td>
|
<td class="bits"><span class="free">OOOO</span> XXXX</td>
|
||||||
@@ -210,7 +210,7 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="caption">rail station</td>
|
<td class="caption">rail station</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX XXXX XXXX</td>
|
<td class="bits">XXXX XXXX XXXX XXXX</td>
|
||||||
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
@@ -302,7 +302,7 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="caption">sea, shore</td>
|
<td class="caption">sea, shore</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">O</span>XXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||||
@@ -356,7 +356,7 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="caption">tunnel entrance</td>
|
<td class="caption">tunnel entrance</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits">XXXX XXXX</td>
|
<td class="bits">XXXX XXXX</td>
|
||||||
<td class="bits"><span class="free">OOO</span>X XXXX</td>
|
<td class="bits">X<span class="free">OO</span>X XXXX</td>
|
||||||
<td class="bits"><span class="used_p">PPPP PPPP PPPP PPPP</span></td>
|
<td class="bits"><span class="used_p">PPPP PPPP PPPP PPPP</span></td>
|
||||||
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
<td class="bits">XXXX <span class="free">OOOO</span></td>
|
||||||
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
<td class="bits"><span class="free">OO</span>XX XXXX</td>
|
||||||
|
@@ -368,7 +368,6 @@
|
|||||||
<ClCompile Include="..\src\departures.cpp" />
|
<ClCompile Include="..\src\departures.cpp" />
|
||||||
<ClCompile Include="..\src\depot.cpp" />
|
<ClCompile Include="..\src\depot.cpp" />
|
||||||
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
||||||
<ClCompile Include="..\src\dock.cpp" />
|
|
||||||
<ClCompile Include="..\src\driver.cpp" />
|
<ClCompile Include="..\src\driver.cpp" />
|
||||||
<ClCompile Include="..\src\economy.cpp" />
|
<ClCompile Include="..\src\economy.cpp" />
|
||||||
<ClCompile Include="..\src\effectvehicle.cpp" />
|
<ClCompile Include="..\src\effectvehicle.cpp" />
|
||||||
@@ -505,7 +504,6 @@
|
|||||||
<ClInclude Include="..\src\direction_type.h" />
|
<ClInclude Include="..\src\direction_type.h" />
|
||||||
<ClInclude Include="..\src\disaster_vehicle.h" />
|
<ClInclude Include="..\src\disaster_vehicle.h" />
|
||||||
<ClInclude Include="..\src\music\dmusic.h" />
|
<ClInclude Include="..\src\music\dmusic.h" />
|
||||||
<ClInclude Include="..\src\dock_base.h" />
|
|
||||||
<ClInclude Include="..\src\driver.h" />
|
<ClInclude Include="..\src\driver.h" />
|
||||||
<ClInclude Include="..\src\economy_base.h" />
|
<ClInclude Include="..\src\economy_base.h" />
|
||||||
<ClInclude Include="..\src\economy_func.h" />
|
<ClInclude Include="..\src\economy_func.h" />
|
||||||
|
@@ -198,9 +198,6 @@
|
|||||||
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\dock.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\src\driver.cpp">
|
<ClCompile Include="..\src\driver.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -609,9 +606,6 @@
|
|||||||
<ClInclude Include="..\src\music\dmusic.h">
|
<ClInclude Include="..\src\music\dmusic.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\src\dock_base.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\src\driver.h">
|
<ClInclude Include="..\src\driver.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -368,7 +368,6 @@
|
|||||||
<ClCompile Include="..\src\departures.cpp" />
|
<ClCompile Include="..\src\departures.cpp" />
|
||||||
<ClCompile Include="..\src\depot.cpp" />
|
<ClCompile Include="..\src\depot.cpp" />
|
||||||
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
||||||
<ClCompile Include="..\src\dock.cpp" />
|
|
||||||
<ClCompile Include="..\src\driver.cpp" />
|
<ClCompile Include="..\src\driver.cpp" />
|
||||||
<ClCompile Include="..\src\economy.cpp" />
|
<ClCompile Include="..\src\economy.cpp" />
|
||||||
<ClCompile Include="..\src\effectvehicle.cpp" />
|
<ClCompile Include="..\src\effectvehicle.cpp" />
|
||||||
@@ -505,7 +504,6 @@
|
|||||||
<ClInclude Include="..\src\direction_type.h" />
|
<ClInclude Include="..\src\direction_type.h" />
|
||||||
<ClInclude Include="..\src\disaster_vehicle.h" />
|
<ClInclude Include="..\src\disaster_vehicle.h" />
|
||||||
<ClInclude Include="..\src\music\dmusic.h" />
|
<ClInclude Include="..\src\music\dmusic.h" />
|
||||||
<ClInclude Include="..\src\dock_base.h" />
|
|
||||||
<ClInclude Include="..\src\driver.h" />
|
<ClInclude Include="..\src\driver.h" />
|
||||||
<ClInclude Include="..\src\economy_base.h" />
|
<ClInclude Include="..\src\economy_base.h" />
|
||||||
<ClInclude Include="..\src\economy_func.h" />
|
<ClInclude Include="..\src\economy_func.h" />
|
||||||
|
@@ -198,9 +198,6 @@
|
|||||||
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\dock.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\src\driver.cpp">
|
<ClCompile Include="..\src\driver.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -609,9 +606,6 @@
|
|||||||
<ClInclude Include="..\src\music\dmusic.h">
|
<ClInclude Include="..\src\music\dmusic.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\src\dock_base.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\src\driver.h">
|
<ClInclude Include="..\src\driver.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -78,16 +78,16 @@
|
|||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
||||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</IntDir>
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</IntDir>
|
||||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
||||||
@@ -368,7 +368,6 @@
|
|||||||
<ClCompile Include="..\src\departures.cpp" />
|
<ClCompile Include="..\src\departures.cpp" />
|
||||||
<ClCompile Include="..\src\depot.cpp" />
|
<ClCompile Include="..\src\depot.cpp" />
|
||||||
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
<ClCompile Include="..\src\disaster_vehicle.cpp" />
|
||||||
<ClCompile Include="..\src\dock.cpp" />
|
|
||||||
<ClCompile Include="..\src\driver.cpp" />
|
<ClCompile Include="..\src\driver.cpp" />
|
||||||
<ClCompile Include="..\src\economy.cpp" />
|
<ClCompile Include="..\src\economy.cpp" />
|
||||||
<ClCompile Include="..\src\effectvehicle.cpp" />
|
<ClCompile Include="..\src\effectvehicle.cpp" />
|
||||||
@@ -505,7 +504,6 @@
|
|||||||
<ClInclude Include="..\src\direction_type.h" />
|
<ClInclude Include="..\src\direction_type.h" />
|
||||||
<ClInclude Include="..\src\disaster_vehicle.h" />
|
<ClInclude Include="..\src\disaster_vehicle.h" />
|
||||||
<ClInclude Include="..\src\music\dmusic.h" />
|
<ClInclude Include="..\src\music\dmusic.h" />
|
||||||
<ClInclude Include="..\src\dock_base.h" />
|
|
||||||
<ClInclude Include="..\src\driver.h" />
|
<ClInclude Include="..\src\driver.h" />
|
||||||
<ClInclude Include="..\src\economy_base.h" />
|
<ClInclude Include="..\src\economy_base.h" />
|
||||||
<ClInclude Include="..\src\economy_func.h" />
|
<ClInclude Include="..\src\economy_func.h" />
|
||||||
|
@@ -198,9 +198,6 @@
|
|||||||
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
<ClCompile Include="..\src\disaster_vehicle.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\dock.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\src\driver.cpp">
|
<ClCompile Include="..\src\driver.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -609,9 +606,6 @@
|
|||||||
<ClInclude Include="..\src\music\dmusic.h">
|
<ClInclude Include="..\src\music\dmusic.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\src\dock_base.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\src\driver.h">
|
<ClInclude Include="..\src\driver.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -78,16 +78,16 @@
|
|||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
||||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</IntDir>
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</IntDir>
|
||||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\objs\$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
@@ -29,9 +29,9 @@
|
|||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\objs\strgen\</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\objs\strgen\</OutDir>
|
||||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\objs\strgen\</IntDir>
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\objs\strgen\</IntDir>
|
||||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
|
||||||
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRules />
|
||||||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
<CodeAnalysisRuleAssemblies />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Midl>
|
<Midl>
|
||||||
|
@@ -30,7 +30,6 @@ dedicated.cpp
|
|||||||
departures.cpp
|
departures.cpp
|
||||||
depot.cpp
|
depot.cpp
|
||||||
disaster_vehicle.cpp
|
disaster_vehicle.cpp
|
||||||
dock.cpp
|
|
||||||
driver.cpp
|
driver.cpp
|
||||||
economy.cpp
|
economy.cpp
|
||||||
effectvehicle.cpp
|
effectvehicle.cpp
|
||||||
@@ -193,7 +192,6 @@ direction_func.h
|
|||||||
direction_type.h
|
direction_type.h
|
||||||
disaster_vehicle.h
|
disaster_vehicle.h
|
||||||
music/dmusic.h
|
music/dmusic.h
|
||||||
dock_base.h
|
|
||||||
driver.h
|
driver.h
|
||||||
economy_base.h
|
economy_base.h
|
||||||
economy_func.h
|
economy_func.h
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "road_map.h"
|
#include "road_map.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
|
#include "water_map.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this is a bridge, instead of a tunnel
|
* Checks if this is a bridge, instead of a tunnel
|
||||||
@@ -129,6 +130,7 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, D
|
|||||||
{
|
{
|
||||||
SetTileType(t, MP_TUNNELBRIDGE);
|
SetTileType(t, MP_TUNNELBRIDGE);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = INVALID_ROADTYPE;
|
_m[t].m4 = INVALID_ROADTYPE;
|
||||||
|
37
src/dock.cpp
37
src/dock.cpp
@@ -1,37 +0,0 @@
|
|||||||
/* $Id: dock.cpp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of OpenTTD.
|
|
||||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
||||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file dock.cpp Implementation of the dock base class. */
|
|
||||||
|
|
||||||
#include "stdafx.h"
|
|
||||||
#include "core/pool_func.hpp"
|
|
||||||
#include "dock_base.h"
|
|
||||||
#include "station_base.h"
|
|
||||||
|
|
||||||
/** The pool of docks. */
|
|
||||||
DockPool _dock_pool("Dock");
|
|
||||||
INSTANTIATE_POOL_METHODS(Dock)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a dock at a given tile.
|
|
||||||
* @param tile Tile with a dock.
|
|
||||||
* @return The dock in the given tile.
|
|
||||||
* @pre IsDockTile()
|
|
||||||
*/
|
|
||||||
/* static */ Dock *Dock::GetByTile(TileIndex tile)
|
|
||||||
{
|
|
||||||
const Station *st = Station::GetByTile(tile);
|
|
||||||
|
|
||||||
for (Dock *d = st->GetPrimaryDock();; d = d->next) {
|
|
||||||
if (d->sloped == tile || d->flat == tile) return d;
|
|
||||||
assert(d->next != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
NOT_REACHED();
|
|
||||||
}
|
|
@@ -1,46 +0,0 @@
|
|||||||
/* $Id: dock_base.h $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of OpenTTD.
|
|
||||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
||||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file dock_base.h Base class for docks. */
|
|
||||||
|
|
||||||
#ifndef DOCK_BASE_H
|
|
||||||
#define DOCK_BASE_H
|
|
||||||
|
|
||||||
#include "station_type.h"
|
|
||||||
#include "tile_type.h"
|
|
||||||
#include "map_func.h"
|
|
||||||
#include "core/pool_type.hpp"
|
|
||||||
|
|
||||||
typedef Pool<Dock, DockID, 32, 64000> DockPool;
|
|
||||||
extern DockPool _dock_pool;
|
|
||||||
|
|
||||||
/** A Dock structure. */
|
|
||||||
struct Dock : DockPool::PoolItem<&_dock_pool> {
|
|
||||||
TileIndex sloped; ///< The sloped tile of the dock.
|
|
||||||
TileIndex flat; ///< Position on the map of the flat tile.
|
|
||||||
Dock *next; ///< Next dock of the given type at this station.
|
|
||||||
|
|
||||||
Dock(TileIndex s = INVALID_TILE, TileIndex f = INVALID_TILE) : sloped(s), flat(f), next(nullptr) { }
|
|
||||||
|
|
||||||
~Dock() {}
|
|
||||||
|
|
||||||
inline Dock *GetNextDock() const { return this->next; }
|
|
||||||
|
|
||||||
inline TileIndex GetDockingTile() const
|
|
||||||
{
|
|
||||||
return this->flat + TileOffsByDiagDir(DiagdirBetweenTiles(this->sloped, this->flat));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Dock *GetByTile(TileIndex tile);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FOR_ALL_DOCKS_FROM(var, start) FOR_ALL_ITEMS_FROM(Dock, dock_index, var, start)
|
|
||||||
#define FOR_ALL_DOCKS(var) FOR_ALL_DOCKS_FROM(var, 0)
|
|
||||||
|
|
||||||
#endif /* DOCK_BASE_H */
|
|
@@ -208,7 +208,7 @@ public:
|
|||||||
LEErrorCode status = LE_NO_ERROR;
|
LEErrorCode status = LE_NO_ERROR;
|
||||||
/* ParagraphLayout does not copy "buff", so it must stay valid.
|
/* 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. */
|
* "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, nullptr, nullptr, nullptr, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
|
icu::ParagraphLayout *p = new icu::ParagraphLayout(buff, length, &runs, nullptr, nullptr, nullptr, _current_text_dir == TD_RTL ? 1 : 0, false, status);
|
||||||
if (status != LE_NO_ERROR) {
|
if (status != LE_NO_ERROR) {
|
||||||
delete p;
|
delete p;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@@ -156,6 +156,13 @@ Industry::~Industry()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->neutral_station != nullptr) {
|
||||||
|
/* Remove possible docking tiles */
|
||||||
|
TILE_AREA_LOOP(tile_cur, this->location) {
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile_cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
|
if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
|
||||||
TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
|
TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
|
||||||
|
|
||||||
|
@@ -282,7 +282,7 @@ STR_SORT_BY_TIMETABLE_DELAY :تاخير جد
|
|||||||
STR_SORT_BY_FACILITY :نوع المحطة
|
STR_SORT_BY_FACILITY :نوع المحطة
|
||||||
STR_SORT_BY_RATING_MAX :اعلى نسبة شحن
|
STR_SORT_BY_RATING_MAX :اعلى نسبة شحن
|
||||||
STR_SORT_BY_RATING_MIN :اقل نسبة شحن
|
STR_SORT_BY_RATING_MIN :اقل نسبة شحن
|
||||||
STR_SORT_BY_ENGINE_ID :نوع المحرك (قياسي(
|
STR_SORT_BY_ENGINE_ID :نوع المحرك (قياسي)
|
||||||
STR_SORT_BY_COST :التكلفة
|
STR_SORT_BY_COST :التكلفة
|
||||||
STR_SORT_BY_POWER :الطاقة
|
STR_SORT_BY_POWER :الطاقة
|
||||||
STR_SORT_BY_TRACTIVE_EFFORT :قوة الجذب
|
STR_SORT_BY_TRACTIVE_EFFORT :قوة الجذب
|
||||||
@@ -1147,7 +1147,7 @@ STR_CONFIG_SETTING_INDUSTRY_DENSITY :الكثافة
|
|||||||
STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :إختر مقدار الصناعات التي يجب تكوينها وعلى اي مستوى يجب ان تكون خلال اللعبة
|
STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :إختر مقدار الصناعات التي يجب تكوينها وعلى اي مستوى يجب ان تكون خلال اللعبة
|
||||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT :ارتفاع خط الثلج: {STRING}
|
STR_CONFIG_SETTING_SNOWLINE_HEIGHT :ارتفاع خط الثلج: {STRING}
|
||||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :تحكم على اي ارتفاع يبدأ نزول الثلج في المناطق القطبية,تؤثر الثلوج على مستوى تطور القطاع الصناعي ونمو المدن
|
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_HELPTEXT :(TerraGenesis only)إختر تكرار الهضبات: الاراض المستويه تحتوي على البضع منها,هضبات موزعه عرضيا اكثر,الاراض الوعرة تحتوي الكثير من الهضاب,التي من الممكن ان تكون متكررة
|
||||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :ناعم جدا
|
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :ناعم جدا
|
||||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :ناعم
|
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :ناعم
|
||||||
@@ -1939,7 +1939,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :بناء الس
|
|||||||
|
|
||||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}بناء سكة حديد
|
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}بناء سكة حديد
|
||||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{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_CONVERT_RAIL_TO_WAYPOINT :{BLACK}غير السكة الى نقطة عبور
|
||||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}بناء محطة قطار. مفتاح كنترول يسمح بضم المحطات
|
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}بناء محطة قطار. مفتاح كنترول يسمح بضم المحطات
|
||||||
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}بناء إشارات السكك الحديدية.
|
STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}بناء إشارات السكك الحديدية.
|
||||||
@@ -2021,7 +2021,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}بناء
|
|||||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}بناء الطرق باستخدام النظام الآلي
|
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}بناء الطرق باستخدام النظام الآلي
|
||||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}بناء سكة القطار باستخدام النظام الآلي
|
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}بناء سكة القطار باستخدام النظام الآلي
|
||||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{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_BUS_STATION :{BLACK}بناء محطة باصات
|
||||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}بناء محطة ركاب ترام.
|
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}بناء محطة ركاب ترام.
|
||||||
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}بناء محطة تحميل عربات. مفتاح كنترول يسمح بمجاورة المحطات.
|
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}بناء محطة تحميل عربات. مفتاح كنترول يسمح بمجاورة المحطات.
|
||||||
@@ -2584,7 +2584,8 @@ STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}ادخل
|
|||||||
# Town directory window
|
# Town directory window
|
||||||
STR_TOWN_DIRECTORY_CAPTION :{WHITE}مدن/ بلدات
|
STR_TOWN_DIRECTORY_CAPTION :{WHITE}مدن/ بلدات
|
||||||
STR_TOWN_DIRECTORY_NONE :{ORANGE}-بدون-
|
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_DIRECTORY_LIST_TOOLTIP :{BLACK}اسم المدينة - اضغط على الاسم لتوسيط الشاشة عليها. اضغط + كنترول لفتح شاشة عرض جديدة للضاحية.
|
||||||
STR_TOWN_POPULATION :{BLACK}سكان العالم: {COMMA}
|
STR_TOWN_POPULATION :{BLACK}سكان العالم: {COMMA}
|
||||||
|
|
||||||
@@ -2672,7 +2673,7 @@ STR_STATION_LIST_STATION :{YELLOW}{STATIO
|
|||||||
STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT}
|
STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT}
|
||||||
STR_STATION_LIST_NONE :{YELLOW}- بدون -
|
STR_STATION_LIST_NONE :{YELLOW}- بدون -
|
||||||
STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}اختر جميع المرافق
|
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}لا يوجد اي شحنة منتظرة
|
STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}لا يوجد اي شحنة منتظرة
|
||||||
|
|
||||||
# Station view window
|
# Station view window
|
||||||
@@ -2897,7 +2898,7 @@ STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}السر
|
|||||||
STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}السرعة في القناة/النهر: {GOLD}{VELOCITY}
|
STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}السرعة في القناة/النهر: {GOLD}{VELOCITY}
|
||||||
STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}تكلفة التشغيل: {GOLD}{CURRENCY_LONG}/ سنة
|
STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}تكلفة التشغيل: {GOLD}{CURRENCY_LONG}/ سنة
|
||||||
STR_PURCHASE_INFO_CAPACITY :{BLACK}السعة: {GOLD}{CARGO_LONG} {STRING}
|
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_DESIGNED_LIFE :{BLACK}تصميم: {GOLD}{NUM}{BLACK} العمر الافتراضي: {GOLD}{COMMA} سنة
|
||||||
STR_PURCHASE_INFO_RELIABILITY :{BLACK}الاعتمادية القصوى: {GOLD}{COMMA}%
|
STR_PURCHASE_INFO_RELIABILITY :{BLACK}الاعتمادية القصوى: {GOLD}{COMMA}%
|
||||||
STR_PURCHASE_INFO_COST :{BLACK}التكلفة: {GOLD}{CURRENCY_LONG}
|
STR_PURCHASE_INFO_COST :{BLACK}التكلفة: {GOLD}{CURRENCY_LONG}
|
||||||
@@ -3199,7 +3200,7 @@ STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK} عرض
|
|||||||
STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}السعة: {LTBLUE}
|
STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}السعة: {LTBLUE}
|
||||||
|
|
||||||
# Vehicle refit
|
# Vehicle refit
|
||||||
STR_REFIT_CAPTION :{WHITE}{VEHICLE} )تغيير(
|
STR_REFIT_CAPTION :{WHITE}{VEHICLE} (تغيير)
|
||||||
STR_REFIT_TITLE :{GOLD}اختر نوع الحمولة ...
|
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_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}
|
STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}السعة الجديدة: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}تكلفة اعادة التهيئة: {RED}{CURRENCY_LONG}
|
||||||
@@ -3421,7 +3422,7 @@ STR_TIMETABLE_RESET_LATENESS :{BLACK}اعد
|
|||||||
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}عدل وقت التاخير للعداد حتى تصل المركبة في الوقت المحدد
|
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}عدل وقت التاخير للعداد حتى تصل المركبة في الوقت المحدد
|
||||||
|
|
||||||
STR_TIMETABLE_AUTOFILL :{BLACK}تهيئة تلقائية
|
STR_TIMETABLE_AUTOFILL :{BLACK}تهيئة تلقائية
|
||||||
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}املأ الجدولة تلقائيا بقيم الرحلة التالية (مفتاح كنترول لمحاولة ابقائ وقت الانتظار).
|
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}مفتاح كنترول لمحاولة ابقائ وقت الانتظار (املأ الجدولة تلقائيا بقيم الرحلة التالية)
|
||||||
|
|
||||||
STR_TIMETABLE_EXPECTED :{BLACK}متوقع
|
STR_TIMETABLE_EXPECTED :{BLACK}متوقع
|
||||||
STR_TIMETABLE_SCHEDULED :{BLACK}مجدول
|
STR_TIMETABLE_SCHEDULED :{BLACK}مجدول
|
||||||
|
@@ -4479,7 +4479,7 @@ STR_VEHICLE_STATUS_STOPPED :{RED}정지함
|
|||||||
STR_VEHICLE_STATUS_BROKEN_DOWN_VEL :{RED}고장 - {STRING}, {LTBLUE} {VELOCITY}
|
STR_VEHICLE_STATUS_BROKEN_DOWN_VEL :{RED}고장 - {STRING}, {LTBLUE} {VELOCITY}
|
||||||
STR_VEHICLE_STATUS_BROKEN_DOWN_VEL_SHORT :{RED}고장 - {STRING}
|
STR_VEHICLE_STATUS_BROKEN_DOWN_VEL_SHORT :{RED}고장 - {STRING}
|
||||||
STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}멈추는 중, {VELOCITY}
|
STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}멈추는 중, {VELOCITY}
|
||||||
STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}기관차 없음
|
STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}동력 없음
|
||||||
STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}빈 경로 탐색중
|
STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}빈 경로 탐색중
|
||||||
STR_VEHICLE_STATUS_TRAIN_STUCK_WAIT_RESTRICTION :{ORANGE}경로 제한 신호기에 의해 대기 중
|
STR_VEHICLE_STATUS_TRAIN_STUCK_WAIT_RESTRICTION :{ORANGE}경로 제한 신호기에 의해 대기 중
|
||||||
STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}다음 목적지가 너무 멀리 있습니다
|
STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}다음 목적지가 너무 멀리 있습니다
|
||||||
|
@@ -1800,6 +1800,7 @@ STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Newid y
|
|||||||
STR_CHEAT_SETUP_PROD :{LTBLUE}Galluogi newid graddfeydd cynhyrchu: {ORANGE}{STRING}
|
STR_CHEAT_SETUP_PROD :{LTBLUE}Galluogi newid graddfeydd cynhyrchu: {ORANGE}{STRING}
|
||||||
|
|
||||||
# Livery window
|
# Livery window
|
||||||
|
STR_LIVERY_CAPTION :{WHITE}{COMPANY} - Cynllun Lliw
|
||||||
|
|
||||||
STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Dangos cynllun lliw cyffredinol
|
STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Dangos cynllun lliw cyffredinol
|
||||||
STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Dangos cynllun lliw trenau
|
STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Dangos cynllun lliw trenau
|
||||||
@@ -2681,6 +2682,7 @@ STR_ABOUT_VERSION :{BLACK}fersiwn
|
|||||||
STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2019 Y tîm OpenTTD
|
STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2019 Y tîm OpenTTD
|
||||||
|
|
||||||
# Framerate display window
|
# Framerate display window
|
||||||
|
STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Nifer o fframiau fideo a lunir bob eiliad.
|
||||||
############ Leave those lines in this order!!
|
############ Leave those lines in this order!!
|
||||||
############ End of leave-in-this-order
|
############ End of leave-in-this-order
|
||||||
############ Leave those lines in this order!!
|
############ Leave those lines in this order!!
|
||||||
@@ -3791,6 +3793,7 @@ STR_ORDER_CONDITIONAL_AGE :Oed (blynyddoed
|
|||||||
STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Angen gwasanaeth
|
STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Angen gwasanaeth
|
||||||
STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Bob tro
|
STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Bob tro
|
||||||
STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Oes yn weddill (blynyddoedd)
|
STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Oes yn weddill (blynyddoedd)
|
||||||
|
STR_ORDER_CONDITIONAL_MAX_RELIABILITY :Dibynadwyedd uchafsymol
|
||||||
|
|
||||||
STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Sut i gymharu'r data cerbyd i'r gwerth a roddwyd
|
STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Sut i gymharu'r data cerbyd i'r gwerth a roddwyd
|
||||||
STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :yn hafal i
|
STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :yn hafal i
|
||||||
@@ -4474,6 +4477,7 @@ STR_BASESOUNDS_DOS_DESCRIPTION :Effeithiau sain
|
|||||||
STR_BASESOUNDS_WIN_DESCRIPTION :Effeithiau sain gwreiddiol fersiwn Windows o Transport Tycoon Deluxe.
|
STR_BASESOUNDS_WIN_DESCRIPTION :Effeithiau sain gwreiddiol fersiwn Windows o Transport Tycoon Deluxe.
|
||||||
STR_BASESOUNDS_NONE_DESCRIPTION :Pecyn sain heb unrhyw effeithiau sain ynddo.
|
STR_BASESOUNDS_NONE_DESCRIPTION :Pecyn sain heb unrhyw effeithiau sain ynddo.
|
||||||
STR_BASEMUSIC_WIN_DESCRIPTION :Cerddoriaeth gwreiddiol fersion Windows o Transport Tycoon Deluxe.
|
STR_BASEMUSIC_WIN_DESCRIPTION :Cerddoriaeth gwreiddiol fersion Windows o Transport Tycoon Deluxe.
|
||||||
|
STR_BASEMUSIC_DOS_DESCRIPTION :Cerddoriaeth gwreiddiol Transport Tycoon Deluxe (fersiwn DOS).
|
||||||
STR_BASEMUSIC_NONE_DESCRIPTION :Pecyn cerddoriaeth heb unrhyw gerddoriaeth ynddo.
|
STR_BASEMUSIC_NONE_DESCRIPTION :Pecyn cerddoriaeth heb unrhyw gerddoriaeth ynddo.
|
||||||
|
|
||||||
##id 0x2000
|
##id 0x2000
|
||||||
|
@@ -542,19 +542,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. */
|
/* Find end of message. */
|
||||||
byte *msg_end = msg_start;
|
const byte *msg_end = msg_start;
|
||||||
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
||||||
msg_end++; // Also include SysEx end byte.
|
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. */
|
/* Buffer is full, clear it and try again. */
|
||||||
_port->PlayBuffer(buffer);
|
_port->PlayBuffer(buffer);
|
||||||
buffer->Flush();
|
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. */
|
/* Update position in buffer. */
|
||||||
@@ -562,9 +562,11 @@ static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *&
|
|||||||
msg_start = msg_end;
|
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. */
|
/** Transmit 'Note off' messages to all MIDI channels. */
|
||||||
@@ -575,27 +577,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_SUSTAINSW, 0);
|
||||||
TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 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);
|
_port->PlayBuffer(_buffer);
|
||||||
_buffer->Flush();
|
_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. */
|
/* Wait until message time has passed. */
|
||||||
Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
|
Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
|
||||||
}
|
}
|
||||||
@@ -620,13 +611,6 @@ static void MidiThreadProc()
|
|||||||
REFERENCE_TIME cur_time;
|
REFERENCE_TIME cur_time;
|
||||||
clock->GetTime(&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);
|
_port->PlayBuffer(_buffer);
|
||||||
_buffer->Flush();
|
_buffer->Flush();
|
||||||
|
|
||||||
@@ -669,7 +653,7 @@ static void MidiThreadProc()
|
|||||||
_playback.do_start = false;
|
_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);
|
clock->GetTime(&cur_time);
|
||||||
TransmitNotesOff(_buffer, block_time, cur_time);
|
TransmitNotesOff(_buffer, block_time, cur_time);
|
||||||
|
|
||||||
@@ -755,7 +739,7 @@ static void MidiThreadProc()
|
|||||||
block_time = playback_start_time + block.realtime * MIDITIME_TO_REFTIME;
|
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));
|
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.data();
|
const byte *data = block.data.data();
|
||||||
size_t remaining = block.data.size();
|
size_t remaining = block.data.size();
|
||||||
byte last_status = 0;
|
byte last_status = 0;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
|
@@ -141,4 +141,19 @@ enum MidiController {
|
|||||||
MIDICT_MODE_POLY = 127,
|
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 */
|
#endif /* MUSIC_MIDI_H */
|
||||||
|
@@ -26,6 +26,37 @@
|
|||||||
|
|
||||||
static MidiFile *_midifile_instance = nullptr;
|
static MidiFile *_midifile_instance = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Owning byte buffer readable as a stream.
|
||||||
* RAII-compliant to make teardown in error situations easier.
|
* RAII-compliant to make teardown in error situations easier.
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include "midifile.hpp"
|
#include "midifile.hpp"
|
||||||
#include "midi.h"
|
#include "midi.h"
|
||||||
#include "../base_media_base.h"
|
#include "../base_media_base.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -32,17 +33,17 @@ static struct {
|
|||||||
UINT time_period; ///< obtained timer precision value
|
UINT time_period; ///< obtained timer precision value
|
||||||
HMIDIOUT midi_out; ///< handle to open midiOut
|
HMIDIOUT midi_out; ///< handle to open midiOut
|
||||||
UINT timer_id; ///< ID of active multimedia timer
|
UINT timer_id; ///< ID of active multimedia timer
|
||||||
CRITICAL_SECTION lock; ///< synchronization for playback status fields
|
std::mutex lock; ///< synchronization for playback status fields
|
||||||
|
|
||||||
bool playing; ///< flag indicating that playback is active
|
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
|
bool do_stop; ///< flag for stopping playback at next opportunity
|
||||||
byte current_volume; ///< current effective volume setting
|
byte current_volume; ///< current effective volume setting
|
||||||
byte new_volume; ///< volume setting to change to
|
byte new_volume; ///< volume setting to change to
|
||||||
|
|
||||||
MidiFile current_file; ///< file currently being played from
|
MidiFile current_file; ///< file currently being played from
|
||||||
PlaybackSegment current_segment; ///< segment info for current playback
|
PlaybackSegment current_segment; ///< segment info for current playback
|
||||||
size_t playback_start_time; ///< timestamp current file began playback
|
DWORD playback_start_time; ///< timestamp current file began playback
|
||||||
size_t current_block; ///< next block index to send
|
size_t current_block; ///< next block index to send
|
||||||
MidiFile next_file; ///< upcoming file to play
|
MidiFile next_file; ///< upcoming file to play
|
||||||
PlaybackSegment next_segment; ///< segment info for upcoming file
|
PlaybackSegment next_segment; ///< segment info for upcoming file
|
||||||
@@ -73,10 +74,10 @@ static void TransmitChannelMsg(byte status, byte p1, byte p2 = 0)
|
|||||||
midiOutShortMsg(_midi.midi_out, status | (p1 << 8) | (p2 << 16));
|
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 */
|
/* find end of message */
|
||||||
byte *msg_end = msg_start;
|
const byte *msg_end = msg_start;
|
||||||
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
|
||||||
msg_end++; /* also include sysex end byte */
|
msg_end++; /* also include sysex end byte */
|
||||||
|
|
||||||
@@ -97,9 +98,11 @@ static void TransmitSysex(byte *&msg_start, size_t &remaining)
|
|||||||
msg_start = msg_end;
|
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,54 +111,65 @@ static void TransmitSysexConst(byte *msg_start, size_t length)
|
|||||||
*/
|
*/
|
||||||
void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR)
|
void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR)
|
||||||
{
|
{
|
||||||
/* Try to check playback status changes.
|
/* Ensure only one timer callback is running at once, and prevent races on status flags */
|
||||||
* If _midi is already locked, skip checking for this cycle and try again
|
std::unique_lock<std::mutex> mutex_lock(_midi.lock, std::defer_lock);
|
||||||
* next cycle, instead of waiting for locks in the realtime callback. */
|
if (!mutex_lock.try_lock()) return;
|
||||||
if (TryEnterCriticalSection(&_midi.lock)) {
|
|
||||||
/* check for stop */
|
/* check for stop */
|
||||||
if (_midi.do_stop) {
|
if (_midi.do_stop) {
|
||||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set");
|
DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set");
|
||||||
midiOutReset(_midi.midi_out);
|
midiOutReset(_midi.midi_out);
|
||||||
_midi.playing = false;
|
_midi.playing = false;
|
||||||
_midi.do_stop = false;
|
_midi.do_stop = false;
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for start/restart/change song */
|
/* check for start/restart/change song */
|
||||||
if (_midi.do_start) {
|
if (_midi.do_start != 0) {
|
||||||
DEBUG(driver, 2, "Win32-MIDI: timer: do_start is set");
|
/* Have a delay between playback start steps, prevents jumbled-together notes at the start of song */
|
||||||
if (_midi.playing) {
|
if (timeGetTime() - _midi.playback_start_time < 50) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DEBUG(driver, 2, "Win32-MIDI: timer: do_start step %d", _midi.do_start);
|
||||||
|
|
||||||
|
if (_midi.do_start == 1) {
|
||||||
|
/* Send "all notes off" */
|
||||||
midiOutReset(_midi.midi_out);
|
midiOutReset(_midi.midi_out);
|
||||||
/* Some songs change the "Pitch bend range" registered
|
_midi.playback_start_time = timeGetTime();
|
||||||
* parameter. If this doesn't get reset, everything else
|
_midi.do_start = 2;
|
||||||
* will start sounding wrong. */
|
|
||||||
for (int ch = 0; ch < 16; ch++) {
|
return;
|
||||||
/* Running status, only need status for first message */
|
} else if (_midi.do_start == 2) {
|
||||||
/* Select RPN 00.00, set value to 02.00, and unselect again */
|
/* Reset the device to General MIDI defaults */
|
||||||
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_RPN_SELECT_LO, 0x00);
|
TransmitStandardSysex(MidiSysexMessage::ResetGM);
|
||||||
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x00);
|
_midi.playback_start_time = timeGetTime();
|
||||||
TransmitChannelMsg(MIDICT_DATAENTRY, 0x02);
|
_midi.do_start = 3;
|
||||||
TransmitChannelMsg(MIDICT_DATAENTRY_LO, 0x00);
|
|
||||||
TransmitChannelMsg(MIDICT_RPN_SELECT_LO, 0x7F);
|
return;
|
||||||
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x7F);
|
} else if (_midi.do_start == 3) {
|
||||||
}
|
/* Set up device-specific effects */
|
||||||
}
|
TransmitStandardSysex(MidiSysexMessage::RolandSetReverb);
|
||||||
|
_midi.playback_start_time = timeGetTime();
|
||||||
|
_midi.do_start = 4;
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (_midi.do_start == 4) {
|
||||||
|
/* Load the new file */
|
||||||
_midi.current_file.MoveFrom(_midi.next_file);
|
_midi.current_file.MoveFrom(_midi.next_file);
|
||||||
std::swap(_midi.next_segment, _midi.current_segment);
|
std::swap(_midi.next_segment, _midi.current_segment);
|
||||||
_midi.current_segment.start_block = 0;
|
_midi.current_segment.start_block = 0;
|
||||||
_midi.playback_start_time = timeGetTime();
|
_midi.playback_start_time = timeGetTime();
|
||||||
_midi.playing = true;
|
_midi.playing = true;
|
||||||
_midi.do_start = false;
|
_midi.do_start = 0;
|
||||||
_midi.current_block = 0;
|
_midi.current_block = 0;
|
||||||
|
|
||||||
MemSetT<byte>(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes));
|
MemSetT<byte>(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes));
|
||||||
|
}
|
||||||
} else if (!_midi.playing) {
|
} else if (!_midi.playing) {
|
||||||
/* not playing, stop the timer */
|
/* not playing, stop the timer */
|
||||||
DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer");
|
DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer");
|
||||||
timeKillEvent(uTimerID);
|
timeKillEvent(uTimerID);
|
||||||
_midi.timer_id = 0;
|
_midi.timer_id = 0;
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,18 +181,14 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
_midi.current_volume = _midi.new_volume;
|
_midi.current_volume = _midi.new_volume;
|
||||||
volume_throttle = 20 / _midi.time_period;
|
volume_throttle = 20 / _midi.time_period;
|
||||||
for (int ch = 0; ch < 16; ch++) {
|
for (int ch = 0; ch < 16; ch++) {
|
||||||
int vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume);
|
byte vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume);
|
||||||
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
|
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
volume_throttle--;
|
volume_throttle--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip beginning of file? */
|
/* skip beginning of file? */
|
||||||
if (_midi.current_segment.start > 0 && _midi.current_block == 0 && _midi.current_segment.start_block == 0) {
|
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
|
/* find first block after start time and pretend playback started earlier
|
||||||
@@ -200,7 +210,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.
|
* 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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +220,7 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
|
|
||||||
/* play pending blocks */
|
/* play pending blocks */
|
||||||
DWORD current_time = timeGetTime();
|
DWORD current_time = timeGetTime();
|
||||||
size_t playback_time = current_time - _midi.playback_start_time;
|
DWORD playback_time = current_time - _midi.playback_start_time;
|
||||||
while (_midi.current_block < _midi.current_file.blocks.size()) {
|
while (_midi.current_block < _midi.current_file.blocks.size()) {
|
||||||
MidiFile::DataBlock &block = _midi.current_file.blocks[_midi.current_block];
|
MidiFile::DataBlock &block = _midi.current_file.blocks[_midi.current_block];
|
||||||
|
|
||||||
@@ -229,7 +239,7 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte *data = block.data.data();
|
const byte *data = block.data.data();
|
||||||
size_t remaining = block.data.size();
|
size_t remaining = block.data.size();
|
||||||
byte last_status = 0;
|
byte last_status = 0;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
@@ -313,56 +323,51 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
void MusicDriver_Win32::PlaySong(const MusicSongInfo &song)
|
void MusicDriver_Win32::PlaySong(const MusicSongInfo &song)
|
||||||
{
|
{
|
||||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: entry");
|
DEBUG(driver, 2, "Win32-MIDI: PlaySong: entry");
|
||||||
EnterCriticalSection(&_midi.lock);
|
|
||||||
|
|
||||||
if (!_midi.next_file.LoadSong(song)) {
|
MidiFile new_song;
|
||||||
LeaveCriticalSection(&_midi.lock);
|
if (!new_song.LoadSong(song)) return;
|
||||||
return;
|
DEBUG(driver, 2, "Win32-MIDI: PlaySong: Loaded song");
|
||||||
}
|
|
||||||
|
|
||||||
|
std::lock_guard mutex_lock(_midi.lock);
|
||||||
|
|
||||||
|
_midi.next_file.MoveFrom(new_song);
|
||||||
_midi.next_segment.start = song.override_start;
|
_midi.next_segment.start = song.override_start;
|
||||||
_midi.next_segment.end = song.override_end;
|
_midi.next_segment.end = song.override_end;
|
||||||
_midi.next_segment.loop = song.loop;
|
_midi.next_segment.loop = song.loop;
|
||||||
|
|
||||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
|
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
|
||||||
_midi.do_stop = _midi.playing;
|
_midi.do_stop = _midi.playing;
|
||||||
_midi.do_start = true;
|
_midi.do_start = 1;
|
||||||
|
|
||||||
if (_midi.timer_id == 0) {
|
if (_midi.timer_id == 0) {
|
||||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer");
|
DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer");
|
||||||
_midi.timer_id = timeSetEvent(_midi.time_period, _midi.time_period, TimerCallback, (DWORD_PTR)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
|
_midi.timer_id = timeSetEvent(_midi.time_period, _midi.time_period, TimerCallback, (DWORD_PTR)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicDriver_Win32::StopSong()
|
void MusicDriver_Win32::StopSong()
|
||||||
{
|
{
|
||||||
DEBUG(driver, 2, "Win32-MIDI: StopSong: entry");
|
DEBUG(driver, 2, "Win32-MIDI: StopSong: entry");
|
||||||
EnterCriticalSection(&_midi.lock);
|
std::lock_guard mutex_lock(_midi.lock);
|
||||||
DEBUG(driver, 2, "Win32-MIDI: StopSong: setting flag");
|
DEBUG(driver, 2, "Win32-MIDI: StopSong: setting flag");
|
||||||
_midi.do_stop = true;
|
_midi.do_stop = true;
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MusicDriver_Win32::IsSongPlaying()
|
bool MusicDriver_Win32::IsSongPlaying()
|
||||||
{
|
{
|
||||||
return _midi.playing || _midi.do_start;
|
return _midi.playing || (_midi.do_start != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicDriver_Win32::SetVolume(byte vol)
|
void MusicDriver_Win32::SetVolume(byte vol)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&_midi.lock);
|
std::lock_guard mutex_lock(_midi.lock);
|
||||||
_midi.new_volume = vol;
|
_midi.new_volume = vol;
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *MusicDriver_Win32::Start(const char * const *parm)
|
const char *MusicDriver_Win32::Start(const char * const *parm)
|
||||||
{
|
{
|
||||||
DEBUG(driver, 2, "Win32-MIDI: Start: initializing");
|
DEBUG(driver, 2, "Win32-MIDI: Start: initializing");
|
||||||
|
|
||||||
InitializeCriticalSection(&_midi.lock);
|
|
||||||
|
|
||||||
int resolution = GetDriverParamInt(parm, "resolution", 5);
|
int resolution = GetDriverParamInt(parm, "resolution", 5);
|
||||||
int port = GetDriverParamInt(parm, "port", -1);
|
int port = GetDriverParamInt(parm, "port", -1);
|
||||||
|
|
||||||
@@ -381,14 +386,6 @@ const char *MusicDriver_Win32::Start(const char * const *parm)
|
|||||||
|
|
||||||
midiOutReset(_midi.midi_out);
|
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 */
|
/* prepare multimedia timer */
|
||||||
TIMECAPS timecaps;
|
TIMECAPS timecaps;
|
||||||
if (timeGetDevCaps(&timecaps, sizeof(timecaps)) == MMSYSERR_NOERROR) {
|
if (timeGetDevCaps(&timecaps, sizeof(timecaps)) == MMSYSERR_NOERROR) {
|
||||||
@@ -405,7 +402,7 @@ const char *MusicDriver_Win32::Start(const char * const *parm)
|
|||||||
|
|
||||||
void MusicDriver_Win32::Stop()
|
void MusicDriver_Win32::Stop()
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&_midi.lock);
|
std::lock_guard mutex_lock(_midi.lock);
|
||||||
|
|
||||||
if (_midi.timer_id) {
|
if (_midi.timer_id) {
|
||||||
timeKillEvent(_midi.timer_id);
|
timeKillEvent(_midi.timer_id);
|
||||||
@@ -415,7 +412,4 @@ void MusicDriver_Win32::Stop()
|
|||||||
timeEndPeriod(_midi.time_period);
|
timeEndPeriod(_midi.time_period);
|
||||||
midiOutReset(_midi.midi_out);
|
midiOutReset(_midi.midi_out);
|
||||||
midiOutClose(_midi.midi_out);
|
midiOutClose(_midi.midi_out);
|
||||||
|
|
||||||
LeaveCriticalSection(&_midi.lock);
|
|
||||||
DeleteCriticalSection(&_midi.lock);
|
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "../../ship.h"
|
#include "../../ship.h"
|
||||||
#include "../../roadstop_base.h"
|
#include "../../roadstop_base.h"
|
||||||
#include "../../infrastructure_func.h"
|
#include "../../infrastructure_func.h"
|
||||||
|
#include "../../vehicle_func.h"
|
||||||
#include "../pathfinder_func.h"
|
#include "../pathfinder_func.h"
|
||||||
#include "../pathfinder_type.h"
|
#include "../pathfinder_type.h"
|
||||||
#include "../follow_track.hpp"
|
#include "../follow_track.hpp"
|
||||||
@@ -166,7 +167,7 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
|||||||
uint dist;
|
uint dist;
|
||||||
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
||||||
|
|
||||||
/* for stations, we are going to aim for the closest station tile */
|
/* aim for the closest station tile */
|
||||||
if (fstd->station_index != INVALID_STATION) {
|
if (fstd->station_index != INVALID_STATION) {
|
||||||
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
||||||
}
|
}
|
||||||
@@ -304,6 +305,15 @@ static void NPFMarkTile(TileIndex tile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||||
|
{
|
||||||
|
uint *count = (uint *)data;
|
||||||
|
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||||
|
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
||||||
{
|
{
|
||||||
/* TileIndex tile = current->tile; */
|
/* TileIndex tile = current->tile; */
|
||||||
@@ -320,6 +330,13 @@ static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *par
|
|||||||
cost += _settings_game.pf.npf.npf_water_curve_penalty;
|
cost += _settings_game.pf.npf.npf_water_curve_penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsDockingTile(current->tile)) {
|
||||||
|
/* Check docking tile for occupancy */
|
||||||
|
uint count = 1;
|
||||||
|
HasVehicleOnPos(current->tile, &count, &CountShipProc);
|
||||||
|
cost += count * 3 * _trackdir_length[trackdir];
|
||||||
|
}
|
||||||
|
|
||||||
/* @todo More penalties? */
|
/* @todo More penalties? */
|
||||||
|
|
||||||
return cost;
|
return cost;
|
||||||
@@ -562,16 +579,22 @@ static int32 NPFFindStationOrTile(const AyStar *as, const OpenListNode *current)
|
|||||||
const AyStarNode *node = ¤t->path.node;
|
const AyStarNode *node = ¤t->path.node;
|
||||||
TileIndex tile = node->tile;
|
TileIndex tile = node->tile;
|
||||||
|
|
||||||
if (fstd->station_index == INVALID_STATION) {
|
if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
|
||||||
return (tile == fstd->dest_coords) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
|
||||||
|
if (fstd->v->type == VEH_SHIP) {
|
||||||
|
/* Ships do not actually reach the destination station, so we check for a docking tile instead. */
|
||||||
|
if (IsDockingTile(tile) && IsShipDestinationTile(tile, fstd->station_index)) return AYSTAR_FOUND_END_NODE;
|
||||||
|
return AYSTAR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (fstd->v->type) {
|
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
||||||
default: NOT_REACHED();
|
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
||||||
case VEH_TRAIN: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
|
||||||
case VEH_ROAD: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index && GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
assert(fstd->v->type == VEH_ROAD);
|
||||||
case VEH_SHIP: return Station::Get(fstd->station_index)->IsDockingTile(tile) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
/* Only if it is a valid station *and* we can stop there */
|
||||||
|
if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE;
|
||||||
}
|
}
|
||||||
|
return AYSTAR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1116,12 +1139,22 @@ void InitializeNPF()
|
|||||||
|
|
||||||
static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
|
static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
|
||||||
{
|
{
|
||||||
/* Fill station_index for station orders, else only dest_coords. */
|
/* Ships don't really reach their stations, but the tile in front. So don't
|
||||||
if (v->current_order.IsType(OT_GOTO_STATION) || (v->type != VEH_SHIP && v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
* save the station id for ships. For roadvehs we don't store it either,
|
||||||
|
* because multistop depends on vehicles actually reaching the exact
|
||||||
|
* dest_tile, not just any stop of that station.
|
||||||
|
* So only for train orders to stations we fill fstd->station_index, for all
|
||||||
|
* others only dest_coords */
|
||||||
|
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT)) {
|
||||||
fstd->station_index = v->current_order.GetDestination();
|
fstd->station_index = v->current_order.GetDestination();
|
||||||
fstd->station_type = (v->type == VEH_SHIP) ? STATION_DOCK :
|
if (v->type == VEH_TRAIN) {
|
||||||
(v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) :
|
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT;
|
||||||
(RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK);
|
} else if (v->type == VEH_ROAD) {
|
||||||
|
fstd->station_type = RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK;
|
||||||
|
} else if (v->type == VEH_SHIP) {
|
||||||
|
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_DOCK : STATION_BUOY;
|
||||||
|
}
|
||||||
|
|
||||||
fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
|
fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
|
||||||
/* Let's take the closest tile of the station as our target for vehicles */
|
/* Let's take the closest tile of the station as our target for vehicles */
|
||||||
fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
|
fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
|
||||||
|
@@ -14,7 +14,19 @@
|
|||||||
|
|
||||||
/** Yapf Node for ships */
|
/** Yapf Node for ships */
|
||||||
template <class Tkey_>
|
template <class Tkey_>
|
||||||
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > { };
|
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > {
|
||||||
|
typedef CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > base;
|
||||||
|
|
||||||
|
TileIndex m_segment_last_tile;
|
||||||
|
Trackdir m_segment_last_td;
|
||||||
|
|
||||||
|
void Set(CYapfShipNodeT *parent, TileIndex tile, Trackdir td, bool is_choice)
|
||||||
|
{
|
||||||
|
base::Set(parent, tile, td, is_choice);
|
||||||
|
m_segment_last_tile = tile;
|
||||||
|
m_segment_last_td = td;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* now define two major node types (that differ by key type) */
|
/* now define two major node types (that differ by key type) */
|
||||||
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
||||||
|
@@ -11,12 +11,96 @@
|
|||||||
|
|
||||||
#include "../../stdafx.h"
|
#include "../../stdafx.h"
|
||||||
#include "../../ship.h"
|
#include "../../ship.h"
|
||||||
|
#include "../../industry.h"
|
||||||
|
#include "../../vehicle_func.h"
|
||||||
|
|
||||||
#include "yapf.hpp"
|
#include "yapf.hpp"
|
||||||
#include "yapf_node_ship.hpp"
|
#include "yapf_node_ship.hpp"
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
|
template <class Types>
|
||||||
|
class CYapfDestinationTileWaterT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||||
|
typedef typename Types::TrackFollower TrackFollower;
|
||||||
|
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||||||
|
typedef typename Node::Key Key; ///< key to hash tables
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TileIndex m_destTile;
|
||||||
|
TrackdirBits m_destTrackdirs;
|
||||||
|
StationID m_destStation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void SetDestination(const Ship *v)
|
||||||
|
{
|
||||||
|
if (v->current_order.IsType(OT_GOTO_STATION)) {
|
||||||
|
m_destStation = v->current_order.GetDestination();
|
||||||
|
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
|
||||||
|
m_destTrackdirs = INVALID_TRACKDIR_BIT;
|
||||||
|
} else {
|
||||||
|
m_destStation = INVALID_STATION;
|
||||||
|
m_destTile = v->dest_tile;
|
||||||
|
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** to access inherited path finder */
|
||||||
|
inline Tpf& Yapf()
|
||||||
|
{
|
||||||
|
return *static_cast<Tpf*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Called by YAPF to detect if node ends in the desired destination */
|
||||||
|
inline bool PfDetectDestination(Node& n)
|
||||||
|
{
|
||||||
|
return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
|
||||||
|
{
|
||||||
|
if (m_destStation != INVALID_STATION) {
|
||||||
|
return IsDockingTile(tile) && IsShipDestinationTile(tile, m_destStation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
||||||
|
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
||||||
|
*/
|
||||||
|
inline bool PfCalcEstimate(Node& n)
|
||||||
|
{
|
||||||
|
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
||||||
|
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
||||||
|
if (PfDetectDestination(n)) {
|
||||||
|
n.m_estimate = n.m_cost;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TileIndex tile = n.m_segment_last_tile;
|
||||||
|
DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
|
||||||
|
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
||||||
|
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
||||||
|
int x2 = 2 * TileX(m_destTile);
|
||||||
|
int y2 = 2 * TileY(m_destTile);
|
||||||
|
int dx = abs(x1 - x2);
|
||||||
|
int dy = abs(y1 - y2);
|
||||||
|
int dmin = min(dx, dy);
|
||||||
|
int dxy = abs(dx - dy);
|
||||||
|
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
||||||
|
n.m_estimate = n.m_cost + d;
|
||||||
|
assert(n.m_estimate >= n.m_parent->m_estimate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Node Follower module of YAPF for ships */
|
/** Node Follower module of YAPF for ships */
|
||||||
template <class Types>
|
template <class Types>
|
||||||
class CYapfFollowShipT
|
class CYapfFollowShipT
|
||||||
@@ -90,12 +174,16 @@ public:
|
|||||||
if (pNode != nullptr) {
|
if (pNode != nullptr) {
|
||||||
uint steps = 0;
|
uint steps = 0;
|
||||||
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
||||||
|
uint skip = 0;
|
||||||
|
if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2;
|
||||||
|
|
||||||
/* walk through the path back to the origin */
|
/* walk through the path back to the origin */
|
||||||
Node *pPrevNode = nullptr;
|
Node *pPrevNode = nullptr;
|
||||||
while (pNode->m_parent != nullptr) {
|
while (pNode->m_parent != nullptr) {
|
||||||
steps--;
|
steps--;
|
||||||
if (steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
/* Skip tiles at end of path near destination. */
|
||||||
|
if (skip > 0) skip--;
|
||||||
|
if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
||||||
path_cache.push_front(pNode->GetTrackdir());
|
path_cache.push_front(pNode->GetTrackdir());
|
||||||
}
|
}
|
||||||
pPrevNode = pNode;
|
pPrevNode = pNode;
|
||||||
@@ -178,6 +266,15 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||||
|
{
|
||||||
|
uint *count = (uint *)data;
|
||||||
|
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||||
|
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by YAPF to calculate the cost from the origin to the given node.
|
* Called by YAPF to calculate the cost from the origin to the given node.
|
||||||
* Calculates only the cost of given node, adds it to the parent node cost
|
* Calculates only the cost of given node, adds it to the parent node cost
|
||||||
@@ -190,6 +287,13 @@ public:
|
|||||||
/* additional penalty for curves */
|
/* additional penalty for curves */
|
||||||
c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir());
|
c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir());
|
||||||
|
|
||||||
|
if (IsDockingTile(n.GetTile())) {
|
||||||
|
/* Check docking tile for occupancy */
|
||||||
|
uint count = 1;
|
||||||
|
HasVehicleOnPos(n.GetTile(), &count, &CountShipProc);
|
||||||
|
c += count * 3 * YAPF_TILE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
/* Skipped tile cost for aqueducts. */
|
/* Skipped tile cost for aqueducts. */
|
||||||
c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
|
c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
|
||||||
|
|
||||||
@@ -204,80 +308,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** YAPF destination provider for ships */
|
|
||||||
template <class Types>
|
|
||||||
class CYapfDestinationShipT
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
|
||||||
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
|
||||||
typedef typename Node::Key Key; ///< key to hash tables
|
|
||||||
|
|
||||||
protected:
|
|
||||||
StationID m_destStation; ///< destinatin station
|
|
||||||
TileIndex m_destTile; ///< destination tile
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** set the destination */
|
|
||||||
void SetDestination(const Ship *v)
|
|
||||||
{
|
|
||||||
if (v->current_order.IsType(OT_GOTO_STATION)) {
|
|
||||||
m_destStation = v->current_order.GetDestination();
|
|
||||||
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
|
|
||||||
} else {
|
|
||||||
m_destStation = INVALID_STATION;
|
|
||||||
m_destTile = v->dest_tile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** to access inherited path finder */
|
|
||||||
Tpf& Yapf()
|
|
||||||
{
|
|
||||||
return *static_cast<Tpf *>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Called by YAPF to detect if node ends in the desired destination */
|
|
||||||
inline bool PfDetectDestination(Node &n)
|
|
||||||
{
|
|
||||||
if (m_destStation == INVALID_STATION) {
|
|
||||||
return n.m_key.m_tile == m_destTile;
|
|
||||||
} else {
|
|
||||||
return Station::Get(m_destStation)->IsDockingTile(n.m_key.m_tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
|
||||||
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
|
||||||
*/
|
|
||||||
inline bool PfCalcEstimate(Node &n)
|
|
||||||
{
|
|
||||||
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
|
||||||
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
|
||||||
if (PfDetectDestination(n)) {
|
|
||||||
n.m_estimate = n.m_cost;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TileIndex tile = n.GetTile();
|
|
||||||
DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir());
|
|
||||||
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
|
||||||
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
|
||||||
int x2 = 2 * TileX(m_destTile);
|
|
||||||
int y2 = 2 * TileY(m_destTile);
|
|
||||||
int dx = abs(x1 - x2);
|
|
||||||
int dy = abs(y1 - y2);
|
|
||||||
int dmin = min(dx, dy);
|
|
||||||
int dxy = abs(dx - dy);
|
|
||||||
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
|
||||||
n.m_estimate = n.m_cost + d;
|
|
||||||
assert(n.m_estimate >= n.m_parent->m_estimate);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config struct of YAPF for ships.
|
* Config struct of YAPF for ships.
|
||||||
* Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
|
* Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
|
||||||
@@ -299,7 +329,7 @@ struct CYapfShip_TypesT
|
|||||||
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
||||||
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
||||||
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
||||||
typedef CYapfDestinationShipT<Types> PfDestination; // destination/distance provider
|
typedef CYapfDestinationTileWaterT<Types> PfDestination; // destination/distance provider
|
||||||
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
||||||
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
||||||
};
|
};
|
||||||
|
@@ -734,6 +734,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
default: {
|
default: {
|
||||||
/* Will there be flat water on the lower halftile? */
|
/* Will there be flat water on the lower halftile? */
|
||||||
bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
|
bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
|
||||||
|
bool docking = IsPossibleDockingTile(tile) && IsDockingTile(tile);
|
||||||
|
|
||||||
CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
|
CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
@@ -750,7 +751,10 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
MakeRailNormal(tile, _current_company, trackbit, railtype);
|
MakeRailNormal(tile, _current_company, trackbit, railtype);
|
||||||
if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
|
if (water_ground) {
|
||||||
|
SetRailGroundType(tile, RAIL_GROUND_WATER);
|
||||||
|
SetDockingTile(tile, docking);
|
||||||
|
}
|
||||||
Company::Get(_current_company)->infrastructure.rail[railtype]++;
|
Company::Get(_current_company)->infrastructure.rail[railtype]++;
|
||||||
DirtyCompanyInfrastructureWindows(_current_company);
|
DirtyCompanyInfrastructureWindows(_current_company);
|
||||||
}
|
}
|
||||||
@@ -882,7 +886,9 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||||||
Slope tileh = GetTileSlope(tile);
|
Slope tileh = GetTileSlope(tile);
|
||||||
/* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
|
/* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
|
||||||
if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
|
if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
|
||||||
|
bool docking = IsDockingTile(tile);
|
||||||
MakeShore(tile);
|
MakeShore(tile);
|
||||||
|
SetDockingTile(tile, docking);
|
||||||
} else {
|
} else {
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
}
|
}
|
||||||
@@ -2041,6 +2047,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
|
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);
|
TileIterator *iter = diagonal ? (TileIterator *)new DiagonalTileIterator(area_start, area_end) : new OrthogonalTileIterator(area_start, area_end);
|
||||||
for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
|
for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
|
||||||
@@ -2155,6 +2162,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
|
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
|
||||||
InvalidateWindowData(WC_BUILD_VEHICLE, tile);
|
InvalidateWindowData(WC_BUILD_VEHICLE, tile);
|
||||||
}
|
}
|
||||||
|
found_convertible_track = true;
|
||||||
cost.AddCost(RailConvertCost(type, totype));
|
cost.AddCost(RailConvertCost(type, totype));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2163,6 +2171,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
/* notify YAPF about the track layout change */
|
/* notify YAPF about the track layout change */
|
||||||
yapf_notify_track_change(tile, GetTrackBits(tile));
|
yapf_notify_track_change(tile, GetTrackBits(tile));
|
||||||
}
|
}
|
||||||
|
found_convertible_track = true;
|
||||||
if (raw_secondary_type != INVALID_RAILTYPE) {
|
if (raw_secondary_type != INVALID_RAILTYPE) {
|
||||||
cost.AddCost(RailConvertCost(type, totype));
|
cost.AddCost(RailConvertCost(type, totype));
|
||||||
cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
||||||
@@ -2196,6 +2205,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint num_primary_pieces = GetTunnelBridgeLength(tile, endtile) + CountBits(GetPrimaryTunnelBridgeTrackBits(tile)) + CountBits(GetPrimaryTunnelBridgeTrackBits(endtile));
|
uint num_primary_pieces = GetTunnelBridgeLength(tile, endtile) + CountBits(GetPrimaryTunnelBridgeTrackBits(tile)) + CountBits(GetPrimaryTunnelBridgeTrackBits(endtile));
|
||||||
|
found_convertible_track = true;
|
||||||
cost.AddCost(num_primary_pieces * RailConvertCost(type, totype));
|
cost.AddCost(num_primary_pieces * RailConvertCost(type, totype));
|
||||||
RailType end_secondary_type = GetTileSecondaryRailTypeIfValid(endtile);
|
RailType end_secondary_type = GetTileSecondaryRailTypeIfValid(endtile);
|
||||||
if (raw_secondary_type != INVALID_RAILTYPE) cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
if (raw_secondary_type != INVALID_RAILTYPE) cost.AddCost(RailConvertCost(raw_secondary_type, totype));
|
||||||
@@ -2238,6 +2248,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
YapfNotifyTrackLayoutChange(tile, track);
|
YapfNotifyTrackLayoutChange(tile, track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found_convertible_track = true;
|
||||||
cost.AddCost(RailConvertCost(type, totype));
|
cost.AddCost(RailConvertCost(type, totype));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2255,7 +2266,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete iter;
|
delete iter;
|
||||||
return (cost.GetCost() == 0) ? error : cost;
|
return found_convertible_track ? cost : error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
|
static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include "signal_func.h"
|
#include "signal_func.h"
|
||||||
#include "track_func.h"
|
#include "track_func.h"
|
||||||
#include "tile_map.h"
|
#include "tile_map.h"
|
||||||
|
#include "water_map.h"
|
||||||
#include "signal_type.h"
|
#include "signal_type.h"
|
||||||
#include "tunnelbridge_map.h"
|
#include "tunnelbridge_map.h"
|
||||||
|
|
||||||
@@ -594,6 +595,7 @@ static inline void MakeRailNormal(TileIndex t, Owner o, TrackBits b, RailType r)
|
|||||||
{
|
{
|
||||||
SetTileType(t, MP_RAILWAY);
|
SetTileType(t, MP_RAILWAY);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
@@ -608,6 +610,7 @@ static inline void MakeRailDepot(TileIndex t, Owner o, DepotID did, DiagDirectio
|
|||||||
{
|
{
|
||||||
SetTileType(t, MP_RAILWAY);
|
SetTileType(t, MP_RAILWAY);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = did;
|
_m[t].m2 = did;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@@ -2554,6 +2554,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
|
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
CommandCost error = CommandCost((rtt == RTT_TRAM) ? STR_ERROR_NO_SUITABLE_TRAMWAY : STR_ERROR_NO_SUITABLE_ROAD); // by default, there is no road to convert.
|
CommandCost error = CommandCost((rtt == RTT_TRAM) ? STR_ERROR_NO_SUITABLE_TRAMWAY : STR_ERROR_NO_SUITABLE_ROAD); // by default, there is no road to convert.
|
||||||
|
bool found_convertible_road = false; // whether we actually did convert any road/tram (see bug #7633)
|
||||||
|
|
||||||
TileIterator *iter = new OrthogonalTileIterator(area_start, area_end);
|
TileIterator *iter = new OrthogonalTileIterator(area_start, area_end);
|
||||||
for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
|
for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
|
||||||
@@ -2609,6 +2610,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint num_pieces = CountBits(GetAnyRoadBits(tile, rtt));;
|
uint num_pieces = CountBits(GetAnyRoadBits(tile, rtt));;
|
||||||
|
found_convertible_road = true;
|
||||||
cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type));
|
cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type));
|
||||||
|
|
||||||
if (flags & DC_EXEC) { // we can safely convert, too
|
if (flags & DC_EXEC) { // we can safely convert, too
|
||||||
@@ -2660,6 +2662,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
|
|
||||||
/* There are 2 pieces on *every* tile of the bridge or tunnel */
|
/* There are 2 pieces on *every* tile of the bridge or tunnel */
|
||||||
uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * 2;
|
uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * 2;
|
||||||
|
found_convertible_road = true;
|
||||||
cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type));
|
cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type));
|
||||||
|
|
||||||
uint tunnel_length = GetTunnelBridgeLength(tile, endtile);
|
uint tunnel_length = GetTunnelBridgeLength(tile, endtile);
|
||||||
@@ -2718,7 +2721,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete iter;
|
delete iter;
|
||||||
return (cost.GetCost() == 0) ? error : cost;
|
return found_convertible_road ? cost : error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -31,7 +31,6 @@
|
|||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../waypoint_base.h"
|
#include "../waypoint_base.h"
|
||||||
#include "../roadstop_base.h"
|
#include "../roadstop_base.h"
|
||||||
#include "../dock_base.h"
|
|
||||||
#include "../tunnelbridge_map.h"
|
#include "../tunnelbridge_map.h"
|
||||||
#include "../pathfinder/yapf/yapf_cache.h"
|
#include "../pathfinder/yapf/yapf_cache.h"
|
||||||
#include "../elrail_func.h"
|
#include "../elrail_func.h"
|
||||||
@@ -63,6 +62,7 @@
|
|||||||
#include "../tracerestrict.h"
|
#include "../tracerestrict.h"
|
||||||
#include "../tunnel_map.h"
|
#include "../tunnel_map.h"
|
||||||
#include "../bridge_signal_map.h"
|
#include "../bridge_signal_map.h"
|
||||||
|
#include "../water.h"
|
||||||
|
|
||||||
|
|
||||||
#include "saveload_internal.h"
|
#include "saveload_internal.h"
|
||||||
@@ -761,7 +761,6 @@ bool AfterLoadGame()
|
|||||||
Station *st;
|
Station *st;
|
||||||
FOR_ALL_STATIONS(st) {
|
FOR_ALL_STATIONS(st) {
|
||||||
if (st->airport.tile == 0) st->airport.tile = INVALID_TILE;
|
if (st->airport.tile == 0) st->airport.tile = INVALID_TILE;
|
||||||
if (st->dock_station.tile == 0) st->dock_station.tile = INVALID_TILE;
|
|
||||||
if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE;
|
if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,7 +889,6 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) {
|
if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) {
|
||||||
/*
|
/*
|
||||||
* Reject huge airports
|
* Reject huge airports
|
||||||
@@ -902,7 +900,7 @@ bool AfterLoadGame()
|
|||||||
if (st->airport.tile == INVALID_TILE) continue;
|
if (st->airport.tile == INVALID_TILE) continue;
|
||||||
StringID err = INVALID_STRING_ID;
|
StringID err = INVALID_STRING_ID;
|
||||||
if (st->airport.type == 9) {
|
if (st->airport.type == 9) {
|
||||||
if (st->dock_station.tile != INVALID_TILE && IsOilRig(st->dock_station.tile)) {
|
if (st->ship_station.tile != INVALID_TILE && IsOilRig(st->ship_station.tile)) {
|
||||||
/* this airport is probably an oil rig, not a huge airport */
|
/* this airport is probably an oil rig, not a huge airport */
|
||||||
} else {
|
} else {
|
||||||
err = STR_GAME_SAVELOAD_ERROR_HUGE_AIRPORTS_PRESENT;
|
err = STR_GAME_SAVELOAD_ERROR_HUGE_AIRPORTS_PRESENT;
|
||||||
@@ -929,7 +927,7 @@ bool AfterLoadGame()
|
|||||||
Aircraft *v;
|
Aircraft *v;
|
||||||
FOR_ALL_AIRCRAFT(v) {
|
FOR_ALL_AIRCRAFT(v) {
|
||||||
Station *st = GetTargetAirportIfValid(v);
|
Station *st = GetTargetAirportIfValid(v);
|
||||||
if (st != nullptr && ((st->dock_station.tile != INVALID_TILE && IsOilRig(st->dock_station.tile)) || st->airport.type == AT_OILRIG)) {
|
if (st != nullptr && ((st->ship_station.tile != INVALID_TILE && IsOilRig(st->ship_station.tile)) || st->airport.type == AT_OILRIG)) {
|
||||||
/* aircraft is on approach to an oil rig, bail out now */
|
/* aircraft is on approach to an oil rig, bail out now */
|
||||||
SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_HELI_OILRIG_BUG);
|
SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_HELI_OILRIG_BUG);
|
||||||
/* Restore the signals */
|
/* Restore the signals */
|
||||||
@@ -939,6 +937,13 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsSavegameVersionBefore(SLV_MULTITILE_DOCKS)) {
|
||||||
|
Station *st;
|
||||||
|
FOR_ALL_STATIONS(st) {
|
||||||
|
st->ship_station.tile = INVALID_TILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Update all vehicles */
|
/* Update all vehicles */
|
||||||
AfterLoadVehicles(true);
|
AfterLoadVehicles(true);
|
||||||
|
|
||||||
@@ -1040,26 +1045,6 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SlXvIsFeatureMissing(XSLFI_MULTIPLE_DOCKS)) {
|
|
||||||
/* Dock type has changed. */
|
|
||||||
Station *st;
|
|
||||||
FOR_ALL_STATIONS(st) {
|
|
||||||
if (st->dock_station.tile == INVALID_TILE) continue;
|
|
||||||
assert(Dock::CanAllocateItem());
|
|
||||||
if (IsOilRig(st->dock_station.tile)) {
|
|
||||||
/* Set dock station tile to dest tile instead of station. */
|
|
||||||
st->docks = new Dock(st->dock_station.tile, st->dock_station.tile + ToTileIndexDiff({ 1, 0 }));
|
|
||||||
} else if (IsDock(st->dock_station.tile)) {
|
|
||||||
/* A normal two-tiles dock. */
|
|
||||||
st->docks = new Dock(st->dock_station.tile, TileAddByDiagDir(st->dock_station.tile, GetDockDirection(st->dock_station.tile)));
|
|
||||||
} else if (IsBuoy(st->dock_station.tile)) {
|
|
||||||
/* A buoy. */
|
|
||||||
} else {
|
|
||||||
NOT_REACHED();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TileIndex t = 0; t < map_size; t++) {
|
for (TileIndex t = 0; t < map_size; t++) {
|
||||||
switch (GetTileType(t)) {
|
switch (GetTileType(t)) {
|
||||||
case MP_STATION: {
|
case MP_STATION: {
|
||||||
@@ -3637,6 +3622,29 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update structures for multitile docks */
|
||||||
|
if (IsSavegameVersionBefore(SLV_MULTITILE_DOCKS)) {
|
||||||
|
for (TileIndex t = 0; t < map_size; t++) {
|
||||||
|
/* Clear docking tile flag from relevant tiles as it
|
||||||
|
* was not previously cleared. */
|
||||||
|
if (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) {
|
||||||
|
SetDockingTile(t, false);
|
||||||
|
}
|
||||||
|
/* Add docks and oilrigs to Station::ship_station. */
|
||||||
|
if (IsTileType(t, MP_STATION)) {
|
||||||
|
if (IsDock(t) || IsOilRig(t)) Station::GetByTile(t)->ship_station.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsSavegameVersionBefore(SLV_MULTITILE_DOCKS) || !SlXvIsFeaturePresent(XSLFI_MULTIPLE_DOCKS, 2)) {
|
||||||
|
/* Scan for docking tiles */
|
||||||
|
Station *st;
|
||||||
|
FOR_ALL_STATIONS(st) {
|
||||||
|
if (st->ship_station.tile != INVALID_TILE) UpdateStationDockingTiles(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
|
/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
|
||||||
Station::RecomputeCatchmentForAll();
|
Station::RecomputeCatchmentForAll();
|
||||||
|
|
||||||
|
@@ -91,7 +91,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
|||||||
{ XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" },
|
{ XSLFI_CHUNNEL, XSCF_NULL, 2, 2, "chunnel", nullptr, nullptr, "TUNN" },
|
||||||
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 1, 1, "scheduled_dispatch", nullptr, nullptr, nullptr },
|
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 1, 1, "scheduled_dispatch", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr },
|
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 1, 1, "multiple_docks", nullptr, nullptr, "DOCK" },
|
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 2, 2, "multiple_docks", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 6, 6, "timetable_extra", nullptr, nullptr, "ORDX" },
|
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 6, 6, "timetable_extra", nullptr, nullptr, "ORDX" },
|
||||||
{ XSLFI_TRAIN_FLAGS_EXTRA, XSCF_NULL, 1, 1, "train_flags_extra", nullptr, nullptr, nullptr },
|
{ XSLFI_TRAIN_FLAGS_EXTRA, XSCF_NULL, 1, 1, "train_flags_extra", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_TRAIN_THROUGH_LOAD, XSCF_NULL, 2, 2, "train_through_load", nullptr, nullptr, nullptr },
|
{ XSLFI_TRAIN_THROUGH_LOAD, XSCF_NULL, 2, 2, "train_through_load", nullptr, nullptr, nullptr },
|
||||||
|
@@ -725,7 +725,7 @@ static const OldChunks station_chunk[] = {
|
|||||||
OCL_NULL( 4 ), ///< bus/lorry tile
|
OCL_NULL( 4 ), ///< bus/lorry tile
|
||||||
OCL_SVAR( OC_TILE, Station, train_station.tile ),
|
OCL_SVAR( OC_TILE, Station, train_station.tile ),
|
||||||
OCL_SVAR( OC_TILE, Station, airport.tile ),
|
OCL_SVAR( OC_TILE, Station, airport.tile ),
|
||||||
OCL_SVAR( OC_TILE, Station, dock_station.tile),
|
OCL_NULL( 4 ), ///< dock tile
|
||||||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ),
|
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ),
|
||||||
|
|
||||||
OCL_NULL( 1 ), ///< sort-index, no longer in use
|
OCL_NULL( 1 ), ///< sort-index, no longer in use
|
||||||
|
@@ -25,7 +25,6 @@
|
|||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../dock_base.h"
|
|
||||||
#include "../thread.h"
|
#include "../thread.h"
|
||||||
#include "../town.h"
|
#include "../town.h"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
@@ -1192,7 +1191,6 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt)
|
|||||||
case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
|
case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
|
||||||
case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
|
case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
|
||||||
case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
|
case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
|
||||||
case REF_DOCKS: return ((const Dock*)obj)->index + 1;
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1258,10 +1256,6 @@ static void *IntToReference(size_t index, SLRefType rt)
|
|||||||
if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
|
if (RoadStop::IsValidID(index)) return RoadStop::Get(index);
|
||||||
SlErrorCorrupt("Referencing invalid RoadStop");
|
SlErrorCorrupt("Referencing invalid RoadStop");
|
||||||
|
|
||||||
case REF_DOCKS:
|
|
||||||
if (Dock::IsValidID(index)) return Dock::Get(index);
|
|
||||||
SlErrorCorrupt("Referencing invalid Dock");
|
|
||||||
|
|
||||||
case REF_ENGINE_RENEWS:
|
case REF_ENGINE_RENEWS:
|
||||||
if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
|
if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index);
|
||||||
SlErrorCorrupt("Referencing invalid EngineRenew");
|
SlErrorCorrupt("Referencing invalid EngineRenew");
|
||||||
|
@@ -304,6 +304,7 @@ enum SaveLoadVersion : uint16 {
|
|||||||
SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types.
|
SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types.
|
||||||
|
|
||||||
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
|
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
|
||||||
|
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
|
||||||
|
|
||||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||||
|
|
||||||
@@ -396,7 +397,6 @@ enum SLRefType {
|
|||||||
REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph.
|
REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph.
|
||||||
REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job.
|
REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job.
|
||||||
REF_TEMPLATE_VEHICLE = 12, ///< Load/save a reference to a template vehicle
|
REF_TEMPLATE_VEHICLE = 12, ///< Load/save a reference to a template vehicle
|
||||||
REF_DOCKS = 13, ///< Load/save a reference to a dock.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Flags of a chunk. */
|
/** Flags of a chunk. */
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../waypoint_base.h"
|
#include "../waypoint_base.h"
|
||||||
#include "../roadstop_base.h"
|
#include "../roadstop_base.h"
|
||||||
#include "../dock_base.h"
|
|
||||||
#include "../vehicle_base.h"
|
#include "../vehicle_base.h"
|
||||||
#include "../newgrf_station.h"
|
#include "../newgrf_station.h"
|
||||||
|
|
||||||
@@ -127,11 +126,6 @@ void AfterLoadStations()
|
|||||||
Station *sta = Station::From(st);
|
Station *sta = Station::From(st);
|
||||||
for (const RoadStop *rs = sta->bus_stops; rs != nullptr; rs = rs->next) sta->bus_station.Add(rs->xy);
|
for (const RoadStop *rs = sta->bus_stops; rs != nullptr; rs = rs->next) sta->bus_station.Add(rs->xy);
|
||||||
for (const RoadStop *rs = sta->truck_stops; rs != nullptr; rs = rs->next) sta->truck_station.Add(rs->xy);
|
for (const RoadStop *rs = sta->truck_stops; rs != nullptr; rs = rs->next) sta->truck_station.Add(rs->xy);
|
||||||
|
|
||||||
for (const Dock *d = sta->docks; d != nullptr; d = d->next) {
|
|
||||||
sta->dock_station.Add(d->sloped);
|
|
||||||
sta->dock_station.Add(d->flat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StationUpdateCachedTriggers(st);
|
StationUpdateCachedTriggers(st);
|
||||||
@@ -175,14 +169,6 @@ static const SaveLoad _roadstop_desc[] = {
|
|||||||
SLE_END()
|
SLE_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SaveLoad _dock_desc[] = {
|
|
||||||
SLE_VAR(Dock, sloped, SLE_UINT32),
|
|
||||||
SLE_VAR(Dock, flat, SLE_UINT32),
|
|
||||||
SLE_REF(Dock, next, REF_DOCKS),
|
|
||||||
|
|
||||||
SLE_END()
|
|
||||||
};
|
|
||||||
|
|
||||||
static const SaveLoad _old_station_desc[] = {
|
static const SaveLoad _old_station_desc[] = {
|
||||||
SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||||
SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
@@ -191,8 +177,8 @@ static const SaveLoad _old_station_desc[] = {
|
|||||||
SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
||||||
SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, dock_station.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
|
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6),
|
||||||
SLE_CONDVAR(Station, dock_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
|
SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS),
|
||||||
SLE_REF(Station, town, REF_TOWN),
|
SLE_REF(Station, town, REF_TOWN),
|
||||||
SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
|
SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16),
|
||||||
SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION),
|
||||||
@@ -447,8 +433,15 @@ static const SaveLoad _station_desc[] = {
|
|||||||
|
|
||||||
SLE_REF(Station, bus_stops, REF_ROADSTOPS),
|
SLE_REF(Station, bus_stops, REF_ROADSTOPS),
|
||||||
SLE_REF(Station, truck_stops, REF_ROADSTOPS),
|
SLE_REF(Station, truck_stops, REF_ROADSTOPS),
|
||||||
SLE_CONDVAR_X(Station, dock_station.tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 0, 0)),
|
SLE_CONDVAR_X(Station, ship_station.tile, SLE_UINT32, SL_MIN_VERSION, SLV_MULTITILE_DOCKS, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 0, 0)),
|
||||||
SLE_CONDREF_X(Station, docks, REF_DOCKS, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 1)),
|
SLE_CONDNULL_X(4, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 1, 1)),
|
||||||
|
SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION),
|
||||||
|
SLE_CONDVARVEC_X(Station, docking_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MULTIPLE_DOCKS, 2)),
|
||||||
SLE_VAR(Station, airport.tile, SLE_UINT32),
|
SLE_VAR(Station, airport.tile, SLE_UINT32),
|
||||||
SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION),
|
||||||
@@ -681,38 +674,15 @@ static void Ptrs_ROADSTOP()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Save_DOCK()
|
|
||||||
{
|
|
||||||
Dock *d;
|
|
||||||
|
|
||||||
FOR_ALL_DOCKS(d) {
|
|
||||||
SlSetArrayIndex(d->index);
|
|
||||||
SlObject(d, _dock_desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Load_DOCK()
|
static void Load_DOCK()
|
||||||
{
|
{
|
||||||
int index;
|
extern void SlSkipArray();
|
||||||
|
SlSkipArray();
|
||||||
while ((index = SlIterateArray()) != -1) {
|
|
||||||
Dock *d = new (index) Dock();
|
|
||||||
|
|
||||||
SlObject(d, _dock_desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Ptrs_DOCK()
|
|
||||||
{
|
|
||||||
Dock *d;
|
|
||||||
FOR_ALL_DOCKS(d) {
|
|
||||||
SlObject(d, _dock_desc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const ChunkHandler _station_chunk_handlers[] = {
|
extern const ChunkHandler _station_chunk_handlers[] = {
|
||||||
{ 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_ARRAY },
|
{ 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_ARRAY },
|
||||||
{ 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY },
|
{ 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY },
|
||||||
{ 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY},
|
{ 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY},
|
||||||
{ 'DOCK', Save_DOCK, Load_DOCK, Ptrs_DOCK, nullptr, CH_ARRAY | CH_LAST},
|
{ 'DOCK', nullptr, Load_DOCK, nullptr, nullptr, CH_ARRAY | CH_LAST},
|
||||||
};
|
};
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../vehicle_base.h"
|
#include "../../vehicle_base.h"
|
||||||
#include "../../roadstop_base.h"
|
#include "../../roadstop_base.h"
|
||||||
#include "../../dock_base.h"
|
|
||||||
#include "../../depot_base.h"
|
#include "../../depot_base.h"
|
||||||
#include "../../station_base.h"
|
#include "../../station_base.h"
|
||||||
#include "../../waypoint_base.h"
|
#include "../../waypoint_base.h"
|
||||||
@@ -262,8 +261,10 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
|||||||
TILE_AREA_LOOP(t, st->train_station) {
|
TILE_AREA_LOOP(t, st->train_station) {
|
||||||
if (st->TileBelongsToRailStation(t)) return t;
|
if (st->TileBelongsToRailStation(t)) return t;
|
||||||
}
|
}
|
||||||
} else if (st->docks != nullptr) {
|
} else if (st->ship_station.tile != INVALID_TILE) {
|
||||||
return st->docks->flat;
|
TILE_AREA_LOOP(t, st->ship_station) {
|
||||||
|
if (IsDockTile(t) && GetStationIndex(t) == st->index) return t;
|
||||||
|
}
|
||||||
} else if (st->bus_stops != nullptr) {
|
} else if (st->bus_stops != nullptr) {
|
||||||
return st->bus_stops->xy;
|
return st->bus_stops->xy;
|
||||||
} else if (st->truck_stops != nullptr) {
|
} else if (st->truck_stops != nullptr) {
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include "script_station.hpp"
|
#include "script_station.hpp"
|
||||||
#include "../../depot_map.h"
|
#include "../../depot_map.h"
|
||||||
#include "../../vehicle_base.h"
|
#include "../../vehicle_base.h"
|
||||||
|
#include "../../train.h"
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ ScriptVehicleList::ScriptVehicleList()
|
|||||||
{
|
{
|
||||||
const Vehicle *v;
|
const Vehicle *v;
|
||||||
FOR_ALL_VEHICLES(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,6 +60,8 @@ struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
|||||||
void SetDestTile(TileIndex tile);
|
void SetDestTile(TileIndex tile);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsShipDestinationTile(TileIndex tile, StationID station);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over all ships.
|
* Iterate over all ships.
|
||||||
* @param var The variable used for iteration.
|
* @param var The variable used for iteration.
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ship.h"
|
#include "ship.h"
|
||||||
#include "dock_base.h"
|
|
||||||
#include "landscape.h"
|
#include "landscape.h"
|
||||||
#include "timetable.h"
|
#include "timetable.h"
|
||||||
#include "news_func.h"
|
#include "news_func.h"
|
||||||
@@ -36,6 +35,8 @@
|
|||||||
#include "tunnelbridge_map.h"
|
#include "tunnelbridge_map.h"
|
||||||
#include "zoom_func.h"
|
#include "zoom_func.h"
|
||||||
#include "framerate_type.h"
|
#include "framerate_type.h"
|
||||||
|
#include "industry.h"
|
||||||
|
#include "industry_map.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -300,7 +301,7 @@ TileIndex Ship::GetOrderStationLocation(StationID station)
|
|||||||
if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
|
if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
|
||||||
|
|
||||||
const Station *st = Station::Get(station);
|
const Station *st = Station::Get(station);
|
||||||
if (st->HasFacilities(FACIL_DOCK)) {
|
if (CanVehicleUseStation(this, st)) {
|
||||||
return st->xy;
|
return st->xy;
|
||||||
} else {
|
} else {
|
||||||
this->IncrementRealOrderIndex();
|
this->IncrementRealOrderIndex();
|
||||||
@@ -764,6 +765,28 @@ static bool ShipMoveUpDownOnLock(Ship *v)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a tile is a docking tile for the given station.
|
||||||
|
* @param tile Docking tile to test.
|
||||||
|
* @param station Destination station.
|
||||||
|
* @return true iff docking tile is next to station.
|
||||||
|
*/
|
||||||
|
bool IsShipDestinationTile(TileIndex tile, StationID station)
|
||||||
|
{
|
||||||
|
assert(IsDockingTile(tile));
|
||||||
|
/* Check each tile adjacent to docking tile. */
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex t = tile + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(t)) continue;
|
||||||
|
if (IsDockTile(t) && GetStationIndex(t) == station && IsValidDockingDirectionForDock(t, d)) return true;
|
||||||
|
if (IsTileType(t, MP_INDUSTRY)) {
|
||||||
|
const Industry *i = Industry::GetByTile(t);
|
||||||
|
if (i->neutral_station != nullptr && i->neutral_station->index == station) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void ShipController(Ship *v)
|
static void ShipController(Ship *v)
|
||||||
{
|
{
|
||||||
uint32 r;
|
uint32 r;
|
||||||
@@ -832,17 +855,18 @@ static void ShipController(Ship *v)
|
|||||||
UpdateVehicleTimetable(v, true);
|
UpdateVehicleTimetable(v, true);
|
||||||
v->IncrementRealOrderIndex();
|
v->IncrementRealOrderIndex();
|
||||||
v->current_order.MakeDummy();
|
v->current_order.MakeDummy();
|
||||||
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
|
} else if (v->current_order.IsType(OT_GOTO_DEPOT) &&
|
||||||
if (v->dest_tile == gp.new_tile && (gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
v->dest_tile == gp.new_tile) {
|
||||||
|
/* Depot orders really need to reach the tile */
|
||||||
|
if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
|
||||||
VehicleEnterDepot(v);
|
VehicleEnterDepot(v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (v->current_order.IsType(OT_GOTO_STATION)) {
|
} else if (v->current_order.IsType(OT_GOTO_STATION) && IsDockingTile(gp.new_tile)) {
|
||||||
Station *st = Station::Get(v->current_order.GetDestination());
|
|
||||||
if (st->IsDockingTile(gp.new_tile)) {
|
|
||||||
v->last_station_visited = v->current_order.GetDestination();
|
|
||||||
|
|
||||||
/* Process station in the orderlist. */
|
/* Process station in the orderlist. */
|
||||||
|
Station *st = Station::Get(v->current_order.GetDestination());
|
||||||
|
if (st->docking_station.Contains(gp.new_tile) && IsShipDestinationTile(gp.new_tile, st->index)) {
|
||||||
|
v->last_station_visited = st->index;
|
||||||
if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
|
if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
|
||||||
ShipArrivesAt(v, st);
|
ShipArrivesAt(v, st);
|
||||||
v->BeginLoading();
|
v->BeginLoading();
|
||||||
|
@@ -24,7 +24,6 @@
|
|||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "station_kdtree.h"
|
#include "station_kdtree.h"
|
||||||
#include "roadstop_base.h"
|
#include "roadstop_base.h"
|
||||||
#include "dock_base.h"
|
|
||||||
#include "industry.h"
|
#include "industry.h"
|
||||||
#include "town.h"
|
#include "town.h"
|
||||||
#include "core/random_func.hpp"
|
#include "core/random_func.hpp"
|
||||||
@@ -75,7 +74,7 @@ Station::Station(TileIndex tile) :
|
|||||||
SpecializedStation<Station, false>(tile),
|
SpecializedStation<Station, false>(tile),
|
||||||
bus_station(INVALID_TILE, 0, 0),
|
bus_station(INVALID_TILE, 0, 0),
|
||||||
truck_station(INVALID_TILE, 0, 0),
|
truck_station(INVALID_TILE, 0, 0),
|
||||||
dock_station(INVALID_TILE, 0, 0),
|
ship_station(INVALID_TILE, 0, 0),
|
||||||
indtype(IT_INVALID),
|
indtype(IT_INVALID),
|
||||||
time_since_load(255),
|
time_since_load(255),
|
||||||
time_since_unload(255)
|
time_since_unload(255)
|
||||||
@@ -337,10 +336,10 @@ uint Station::GetCatchmentRadius() const
|
|||||||
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
|
if (this->bus_stops != nullptr) ret = max<uint>(ret, CA_BUS);
|
||||||
if (this->truck_stops != nullptr) ret = max<uint>(ret, CA_TRUCK);
|
if (this->truck_stops != nullptr) ret = max<uint>(ret, CA_TRUCK);
|
||||||
if (this->train_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_TRAIN);
|
if (this->train_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_TRAIN);
|
||||||
if (this->docks != nullptr) ret = max<uint>(ret, CA_DOCK);
|
if (this->ship_station.tile != INVALID_TILE) ret = max<uint>(ret, CA_DOCK);
|
||||||
if (this->airport.tile != INVALID_TILE) ret = max<uint>(ret, this->airport.GetSpec()->catchment);
|
if (this->airport.tile != INVALID_TILE) ret = max<uint>(ret, this->airport.GetSpec()->catchment);
|
||||||
} else {
|
} else {
|
||||||
if (this->bus_stops != nullptr || this->truck_stops != nullptr || this->train_station.tile != INVALID_TILE || this->docks != nullptr || this->airport.tile != INVALID_TILE) {
|
if (this->bus_stops != nullptr || this->truck_stops != nullptr || this->train_station.tile != INVALID_TILE || this->ship_station.tile != INVALID_TILE || this->airport.tile != INVALID_TILE) {
|
||||||
ret = CA_UNMODIFIED;
|
ret = CA_UNMODIFIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,19 +368,11 @@ Rect Station::GetCatchmentRectUsingRadius(uint catchment_radius) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Station::IsDockingTile(TileIndex tile) const
|
|
||||||
{
|
|
||||||
for (const Dock *d = this->docks; d != nullptr; d = d->next) {
|
|
||||||
if (tile == d->GetDockingTile()) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Station::IsWithinRangeOfDockingTile(TileIndex tile, uint max_distance) const
|
bool Station::IsWithinRangeOfDockingTile(TileIndex tile, uint max_distance) const
|
||||||
{
|
{
|
||||||
if (DistanceManhattan(this->xy, tile) > _settings_game.station.station_spread + max_distance) return false;
|
if (DistanceManhattan(this->xy, tile) > _settings_game.station.station_spread + max_distance) return false;
|
||||||
for (const Dock *d = this->docks; d != nullptr; d = d->next) {
|
for (TileIndex dock_tile : this->docking_tiles) {
|
||||||
if (DistanceManhattan(d->GetDockingTile(), tile) <= max_distance) return true;
|
if (DistanceManhattan(dock_tile, tile) <= max_distance) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -467,10 +467,11 @@ public:
|
|||||||
TileArea bus_station; ///< Tile area the bus 'station' part covers
|
TileArea bus_station; ///< Tile area the bus 'station' part covers
|
||||||
RoadStop *truck_stops; ///< All the truck stops
|
RoadStop *truck_stops; ///< All the truck stops
|
||||||
TileArea truck_station; ///< Tile area the truck 'station' part covers
|
TileArea truck_station; ///< Tile area the truck 'station' part covers
|
||||||
Dock *docks; ///< All the docks
|
|
||||||
TileArea dock_station; ///< Tile area dock 'station' part covers
|
|
||||||
|
|
||||||
Airport airport; ///< Tile area the airport covers
|
Airport airport; ///< Tile area the airport covers
|
||||||
|
TileArea ship_station; ///< Tile area the ship 'station' part covers
|
||||||
|
TileArea docking_station; ///< Tile area the docking tiles cover
|
||||||
|
std::vector<TileIndex> docking_tiles; ///< Tile vector the docking tiles cover
|
||||||
|
|
||||||
IndustryType indtype; ///< Industry type to get the name from
|
IndustryType indtype; ///< Industry type to get the name from
|
||||||
|
|
||||||
@@ -506,8 +507,6 @@ public:
|
|||||||
void RecomputeCatchment();
|
void RecomputeCatchment();
|
||||||
static void RecomputeCatchmentForAll();
|
static void RecomputeCatchmentForAll();
|
||||||
|
|
||||||
Dock *GetPrimaryDock() const { return docks; }
|
|
||||||
|
|
||||||
uint GetCatchmentRadius() const;
|
uint GetCatchmentRadius() const;
|
||||||
Rect GetCatchmentRectUsingRadius(uint radius) const;
|
Rect GetCatchmentRectUsingRadius(uint radius) const;
|
||||||
inline Rect GetCatchmentRect() const
|
inline Rect GetCatchmentRect() const
|
||||||
@@ -533,7 +532,6 @@ public:
|
|||||||
return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
|
return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDockingTile(TileIndex tile) const;
|
|
||||||
bool IsWithinRangeOfDockingTile(TileIndex tile, uint max_distance) const;
|
bool IsWithinRangeOfDockingTile(TileIndex tile, uint max_distance) const;
|
||||||
|
|
||||||
uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const override;
|
uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const override;
|
||||||
|
@@ -40,7 +40,6 @@
|
|||||||
#include "station_base.h"
|
#include "station_base.h"
|
||||||
#include "station_kdtree.h"
|
#include "station_kdtree.h"
|
||||||
#include "roadstop_base.h"
|
#include "roadstop_base.h"
|
||||||
#include "dock_base.h"
|
|
||||||
#include "newgrf_railtype.h"
|
#include "newgrf_railtype.h"
|
||||||
#include "newgrf_roadtype.h"
|
#include "newgrf_roadtype.h"
|
||||||
#include "waypoint_base.h"
|
#include "waypoint_base.h"
|
||||||
@@ -58,6 +57,7 @@
|
|||||||
#include "linkgraph/refresh.h"
|
#include "linkgraph/refresh.h"
|
||||||
#include "widgets/station_widget.h"
|
#include "widgets/station_widget.h"
|
||||||
#include "zoning.h"
|
#include "zoning.h"
|
||||||
|
#include "tunnelbridge_map.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -403,7 +403,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const
|
|||||||
|
|
||||||
case STATION_DOCK:
|
case STATION_DOCK:
|
||||||
case STATION_OILRIG:
|
case STATION_OILRIG:
|
||||||
*ta = this->dock_station;
|
*ta = this->docking_station;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
@@ -1578,16 +1578,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32
|
|||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MakeRailStationAreaSmaller(BaseStation *st)
|
static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex))
|
||||||
{
|
{
|
||||||
TileArea ta = st->train_station;
|
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
|
|
||||||
/* too small? */
|
/* too small? */
|
||||||
if (ta.w != 0 && ta.h != 0) {
|
if (ta.w != 0 && ta.h != 0) {
|
||||||
/* check the left side, x = constant, y changes */
|
/* check the left side, x = constant, y changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.h) {
|
if (++i == ta.h) {
|
||||||
ta.tile += TileDiffXY(1, 0);
|
ta.tile += TileDiffXY(1, 0);
|
||||||
@@ -1597,7 +1595,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check the right side, x = constant, y changes */
|
/* check the right side, x = constant, y changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) {
|
||||||
/* the right side is unused? */
|
/* the right side is unused? */
|
||||||
if (++i == ta.h) {
|
if (++i == ta.h) {
|
||||||
ta.w--;
|
ta.w--;
|
||||||
@@ -1606,7 +1604,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check the upper side, y = constant, x changes */
|
/* check the upper side, y = constant, x changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.w) {
|
if (++i == ta.w) {
|
||||||
ta.tile += TileDiffXY(0, 1);
|
ta.tile += TileDiffXY(0, 1);
|
||||||
@@ -1616,7 +1614,7 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check the lower side, y = constant, x changes */
|
/* check the lower side, y = constant, x changes */
|
||||||
for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) {
|
for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) {
|
||||||
/* the left side is unused? */
|
/* the left side is unused? */
|
||||||
if (++i == ta.w) {
|
if (++i == ta.w) {
|
||||||
ta.h--;
|
ta.h--;
|
||||||
@@ -1627,7 +1625,28 @@ restart:
|
|||||||
ta.Clear();
|
ta.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
st->train_station = ta;
|
return ta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile)
|
||||||
|
{
|
||||||
|
return st->TileBelongsToRailStation(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MakeRailStationAreaSmaller(BaseStation *st)
|
||||||
|
{
|
||||||
|
st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile)
|
||||||
|
{
|
||||||
|
return IsDockTile(tile) && GetStationIndex(tile) == st->index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MakeShipStationAreaSmaller(Station *st)
|
||||||
|
{
|
||||||
|
st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation);
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2756,20 +2775,13 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
/* Distant join */
|
/* Distant join */
|
||||||
if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
|
if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join);
|
||||||
|
|
||||||
if (!Dock::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_DOCKS);
|
|
||||||
|
|
||||||
ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
|
ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
/* Create the dock and insert it into the list of docks. */
|
st->ship_station.Add(tile);
|
||||||
Dock *dock = new Dock(slope_tile, flat_tile);
|
st->ship_station.Add(tile + TileOffsByDiagDir(direction));
|
||||||
dock->next = st->docks;
|
st->AddFacility(FACIL_DOCK, tile);
|
||||||
st->docks = dock;
|
|
||||||
|
|
||||||
st->dock_station.Add(slope_tile);
|
|
||||||
st->dock_station.Add(flat_tile);
|
|
||||||
st->AddFacility(FACIL_DOCK, slope_tile);
|
|
||||||
|
|
||||||
st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
|
st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY);
|
||||||
|
|
||||||
@@ -2780,7 +2792,8 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
}
|
}
|
||||||
Company::Get(st->owner)->infrastructure.station += 2;
|
Company::Get(st->owner)->infrastructure.station += 2;
|
||||||
|
|
||||||
MakeDock(slope_tile, st->owner, st->index, direction, wc);
|
MakeDock(tile, st->owner, st->index, direction, wc);
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
|
|
||||||
st->AfterStationTileSetChange(true, STATION_DOCK);
|
st->AfterStationTileSetChange(true, STATION_DOCK);
|
||||||
ZoningMarkDirtyStationCoverageArea(st);
|
ZoningMarkDirtyStationCoverageArea(st);
|
||||||
@@ -2789,6 +2802,85 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
|
||||||
|
if (IsTileType(tile, MP_STATION)) {
|
||||||
|
UpdateStationDockingTiles(Station::GetByTile(tile));
|
||||||
|
} else if (IsTileType(tile, MP_INDUSTRY)) {
|
||||||
|
UpdateStationDockingTiles(Industry::GetByTile(tile)->neutral_station);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear docking tile status from tiles around a removed dock, if the tile has
|
||||||
|
* no neighbours which would keep it as a docking tile.
|
||||||
|
* @param tile Ex-dock tile to check.
|
||||||
|
*/
|
||||||
|
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
|
||||||
|
{
|
||||||
|
assert(IsValidTile(tile));
|
||||||
|
|
||||||
|
/* Clear and maybe re-set docking tile */
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex docking_tile = tile + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(docking_tile)) continue;
|
||||||
|
|
||||||
|
if (IsPossibleDockingTile(docking_tile)) {
|
||||||
|
SetDockingTile(docking_tile, false);
|
||||||
|
CheckForDockingTile(docking_tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a dock tile can be docked from the given direction.
|
||||||
|
* @param t Tile index of dock.
|
||||||
|
* @param d DiagDirection adjacent to dock being tested.
|
||||||
|
* @return True iff the dock can be docked from the given direction.
|
||||||
|
*/
|
||||||
|
bool IsValidDockingDirectionForDock(TileIndex t, DiagDirection d)
|
||||||
|
{
|
||||||
|
assert(IsDockTile(t));
|
||||||
|
|
||||||
|
/** Bitmap of valid directions for each dock tile part. */
|
||||||
|
static const uint8 _valid_docking_tile[] = {
|
||||||
|
0, 0, 0, 0, // No docking against the slope part.
|
||||||
|
1 << DIAGDIR_NE | 1 << DIAGDIR_SW, // Docking permitted at the end
|
||||||
|
1 << DIAGDIR_NW | 1 << DIAGDIR_SE, // of the flat piers.
|
||||||
|
};
|
||||||
|
|
||||||
|
StationGfx gfx = GetStationGfx(t);
|
||||||
|
assert(gfx < lengthof(_valid_docking_tile));
|
||||||
|
return HasBit(_valid_docking_tile[gfx], d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the part of a dock that is land-based
|
||||||
|
* @param t Dock tile to find land part of
|
||||||
|
* @return tile of land part of dock
|
||||||
|
*/
|
||||||
|
static TileIndex FindDockLandPart(TileIndex t)
|
||||||
|
{
|
||||||
|
assert(IsDockTile(t));
|
||||||
|
|
||||||
|
StationGfx gfx = GetStationGfx(t);
|
||||||
|
if (gfx < GFX_DOCK_BASE_WATER_PART) return t;
|
||||||
|
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
if (!IsDockTile(tile)) continue;
|
||||||
|
if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_TILE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a dock
|
* Remove a dock
|
||||||
* @param tile TileIndex been queried
|
* @param tile TileIndex been queried
|
||||||
@@ -2801,14 +2893,11 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
|||||||
CommandCost ret = CheckOwnership(st->owner);
|
CommandCost ret = CheckOwnership(st->owner);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
Dock *removing_dock = Dock::GetByTile(tile);
|
if (!IsDockTile(tile)) return CMD_ERROR;
|
||||||
assert(removing_dock != nullptr);
|
|
||||||
|
|
||||||
TileIndex tile1 = removing_dock->sloped;
|
TileIndex tile1 = FindDockLandPart(tile);
|
||||||
TileIndex tile2 = removing_dock->flat;
|
if (tile1 == INVALID_TILE) return CMD_ERROR;
|
||||||
|
TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
|
||||||
DiagDirection direction = DiagdirBetweenTiles(removing_dock->sloped, removing_dock->flat);
|
|
||||||
TileIndex docking_location = removing_dock->flat + TileOffsByDiagDir(direction);
|
|
||||||
|
|
||||||
ret = EnsureNoVehicleOnGround(tile1);
|
ret = EnsureNoVehicleOnGround(tile1);
|
||||||
if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
|
if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
|
||||||
@@ -2817,22 +2906,6 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
|||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
ZoningMarkDirtyStationCoverageArea(st);
|
ZoningMarkDirtyStationCoverageArea(st);
|
||||||
|
|
||||||
if (st->docks == removing_dock) {
|
|
||||||
/* The first dock in the list is removed. */
|
|
||||||
st->docks = removing_dock->next;
|
|
||||||
/* Last dock is removed. */
|
|
||||||
if (st->docks == nullptr) {
|
|
||||||
st->facilities &= ~FACIL_DOCK;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Tell the predecessor in the list to skip this dock. */
|
|
||||||
Dock *pred = st->docks;
|
|
||||||
while (pred->next != removing_dock) pred = pred->next;
|
|
||||||
pred->next = removing_dock->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete removing_dock;
|
|
||||||
|
|
||||||
DoClearSquare(tile1);
|
DoClearSquare(tile1);
|
||||||
MarkTileDirtyByTile(tile1);
|
MarkTileDirtyByTile(tile1);
|
||||||
MakeWaterKeepingClass(tile2, st->owner);
|
MakeWaterKeepingClass(tile2, st->owner);
|
||||||
@@ -2840,29 +2913,35 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
|
|||||||
st->rect.AfterRemoveTile(st, tile1);
|
st->rect.AfterRemoveTile(st, tile1);
|
||||||
st->rect.AfterRemoveTile(st, tile2);
|
st->rect.AfterRemoveTile(st, tile2);
|
||||||
|
|
||||||
st->dock_station.Clear();
|
MakeShipStationAreaSmaller(st);
|
||||||
for (Dock *dock = st->docks; dock != nullptr; dock = dock->next) {
|
if (st->ship_station.tile == INVALID_TILE) {
|
||||||
st->dock_station.Add(dock->flat);
|
st->ship_station.Clear();
|
||||||
st->dock_station.Add(dock->sloped);
|
st->docking_station.Clear();
|
||||||
|
st->docking_tiles.clear();
|
||||||
|
st->facilities &= ~FACIL_DOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Company::Get(st->owner)->infrastructure.station -= 2;
|
Company::Get(st->owner)->infrastructure.station -= 2;
|
||||||
|
|
||||||
st->AfterStationTileSetChange(false, STATION_DOCK);
|
st->AfterStationTileSetChange(false, STATION_DOCK);
|
||||||
|
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile1);
|
||||||
|
ClearDockingTilesCheckingNeighbours(tile2);
|
||||||
|
|
||||||
/* All ships that were going to our station, can't go to it anymore.
|
/* All ships that were going to our station, can't go to it anymore.
|
||||||
* Just clear the order, then automatically the next appropriate order
|
* Just clear the order, then automatically the next appropriate order
|
||||||
* will be selected and in case of no appropriate order it will just
|
* will be selected and in case of no appropriate order it will just
|
||||||
* wander around the world. */
|
* wander around the world. */
|
||||||
|
if (!(st->facilities & FACIL_DOCK)) {
|
||||||
Ship *s;
|
Ship *s;
|
||||||
FOR_ALL_SHIPS(s) {
|
FOR_ALL_SHIPS(s) {
|
||||||
if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) {
|
if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
|
||||||
s->LeaveStation();
|
s->LeaveStation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->dest_tile == docking_location) {
|
if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
|
||||||
s->SetDestTile(0);
|
s->SetDestTile(s->GetOrderStationLocation(st->index));
|
||||||
s->current_order.Free();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3111,7 +3190,7 @@ draw_default_foundation:
|
|||||||
} else {
|
} else {
|
||||||
assert_tile(IsDock(ti->tile), ti->tile);
|
assert_tile(IsDock(ti->tile), ti->tile);
|
||||||
TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
|
TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
|
||||||
WaterClass wc = GetWaterClass(water_tile);
|
WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID;
|
||||||
if (wc == WATER_CLASS_SEA) {
|
if (wc == WATER_CLASS_SEA) {
|
||||||
DrawShoreTile(ti->tileh);
|
DrawShoreTile(ti->tileh);
|
||||||
} else {
|
} else {
|
||||||
@@ -4243,6 +4322,33 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc
|
|||||||
return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
|
return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateStationDockingTiles(Station *st)
|
||||||
|
{
|
||||||
|
st->docking_station.Clear();
|
||||||
|
st->docking_tiles.clear();
|
||||||
|
|
||||||
|
/* For neutral stations, start with the industry area instead of dock area */
|
||||||
|
const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station;
|
||||||
|
|
||||||
|
if (area->tile == INVALID_TILE) return;
|
||||||
|
|
||||||
|
int x = TileX(area->tile);
|
||||||
|
int y = TileY(area->tile);
|
||||||
|
|
||||||
|
/* Expand the area by a tile on each side while
|
||||||
|
* making sure that we remain inside the map. */
|
||||||
|
int x2 = min(x + area->w + 1, MapSizeX());
|
||||||
|
int x1 = max(x - 1, 0);
|
||||||
|
|
||||||
|
int y2 = min(y + area->h + 1, MapSizeY());
|
||||||
|
int y1 = max(y - 1, 0);
|
||||||
|
|
||||||
|
TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
|
||||||
|
TILE_AREA_LOOP(tile, ta) {
|
||||||
|
if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BuildOilRig(TileIndex tile)
|
void BuildOilRig(TileIndex tile)
|
||||||
{
|
{
|
||||||
if (!Station::CanAllocateItem()) {
|
if (!Station::CanAllocateItem()) {
|
||||||
@@ -4266,18 +4372,10 @@ void BuildOilRig(TileIndex tile)
|
|||||||
st->owner = OWNER_NONE;
|
st->owner = OWNER_NONE;
|
||||||
st->airport.type = AT_OILRIG;
|
st->airport.type = AT_OILRIG;
|
||||||
st->airport.Add(tile);
|
st->airport.Add(tile);
|
||||||
st->dock_station.tile = tile;
|
st->ship_station.Add(tile);
|
||||||
st->facilities = FACIL_AIRPORT;
|
st->facilities = FACIL_AIRPORT | FACIL_DOCK;
|
||||||
|
|
||||||
if (!Dock::CanAllocateItem()) {
|
|
||||||
DEBUG(misc, 0, "Can't allocate dock for oilrig at 0x%X, reverting to oilrig with airport only", tile);
|
|
||||||
} else {
|
|
||||||
st->docks = new Dock(tile, tile + ToTileIndexDiff({1, 0}));
|
|
||||||
st->dock_station.tile = tile;
|
|
||||||
st->facilities |= FACIL_DOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
st->build_date = _date;
|
st->build_date = _date;
|
||||||
|
UpdateStationDockingTiles(st);
|
||||||
|
|
||||||
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
|
st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
|
||||||
|
|
||||||
@@ -4295,20 +4393,46 @@ void DeleteOilRig(TileIndex tile)
|
|||||||
|
|
||||||
MakeWaterKeepingClass(tile, OWNER_NONE);
|
MakeWaterKeepingClass(tile, OWNER_NONE);
|
||||||
|
|
||||||
st->dock_station.tile = INVALID_TILE;
|
assert(st->facilities == (FACIL_AIRPORT | FACIL_DOCK) && st->airport.type == AT_OILRIG);
|
||||||
if (st->docks != nullptr) {
|
delete st;
|
||||||
delete st->docks;
|
return;
|
||||||
st->docks = nullptr;
|
|
||||||
|
MakeShipStationAreaSmaller(st);
|
||||||
|
if (st->ship_station.tile == INVALID_TILE) {
|
||||||
|
st->ship_station.Clear();
|
||||||
|
st->docking_station.Clear();
|
||||||
|
st->docking_tiles.clear();
|
||||||
|
st->facilities &= ~FACIL_DOCK;
|
||||||
}
|
}
|
||||||
st->airport.Clear();
|
st->airport.Clear();
|
||||||
st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
|
st->facilities &= ~FACIL_AIRPORT;
|
||||||
st->airport.flags = 0;
|
st->airport.flags = 0;
|
||||||
|
|
||||||
st->rect.AfterRemoveTile(st, tile);
|
st->rect.AfterRemoveTile(st, tile);
|
||||||
|
|
||||||
st->UpdateVirtCoord();
|
st->UpdateVirtCoord();
|
||||||
st->RecomputeCatchment();
|
st->RecomputeCatchment();
|
||||||
if (!st->IsInUse()) delete st;
|
if (!st->IsInUse()) {
|
||||||
|
delete st;
|
||||||
|
} else {
|
||||||
|
st->industry = nullptr;
|
||||||
|
/* All ships that were going to our station, can't go to it anymore.
|
||||||
|
* Just clear the order, then automatically the next appropriate order
|
||||||
|
* will be selected and in case of no appropriate order it will just
|
||||||
|
* wander around the world. */
|
||||||
|
if (!(st->facilities & FACIL_DOCK)) {
|
||||||
|
Ship *s;
|
||||||
|
FOR_ALL_SHIPS(s) {
|
||||||
|
if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) {
|
||||||
|
s->LeaveStation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) {
|
||||||
|
s->SetDestTile(s->GetOrderStationLocation(st->index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
|
static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
|
||||||
|
@@ -41,6 +41,10 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro
|
|||||||
bool HasStationInUse(StationID station, bool include_company, CompanyID company);
|
bool HasStationInUse(StationID station, bool include_company, CompanyID company);
|
||||||
|
|
||||||
void DeleteOilRig(TileIndex t);
|
void DeleteOilRig(TileIndex t);
|
||||||
|
void UpdateStationDockingTiles(Station *st);
|
||||||
|
void RemoveDockingTile(TileIndex t);
|
||||||
|
void ClearDockingTilesCheckingNeighbours(TileIndex tile);
|
||||||
|
bool IsValidDockingDirectionForDock(TileIndex t, DiagDirection d);
|
||||||
|
|
||||||
/* Check if a rail station tile is traversable. */
|
/* Check if a rail station tile is traversable. */
|
||||||
bool IsStationTileBlocked(TileIndex tile);
|
bool IsStationTileBlocked(TileIndex tile);
|
||||||
|
@@ -536,6 +536,7 @@ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType
|
|||||||
SetTileType(t, MP_STATION);
|
SetTileType(t, MP_STATION);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, wc);
|
SetWaterClass(t, wc);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = sid;
|
_m[t].m2 = sid;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@@ -23,7 +23,6 @@ typedef uint16 DockID;
|
|||||||
struct BaseStation;
|
struct BaseStation;
|
||||||
struct Station;
|
struct Station;
|
||||||
struct RoadStop;
|
struct RoadStop;
|
||||||
struct Dock;
|
|
||||||
struct StationSpec;
|
struct StationSpec;
|
||||||
struct Waypoint;
|
struct Waypoint;
|
||||||
|
|
||||||
|
@@ -49,6 +49,7 @@
|
|||||||
#include "industry_map.h"
|
#include "industry_map.h"
|
||||||
#include "object_map.h"
|
#include "object_map.h"
|
||||||
#include "newgrf_station.h"
|
#include "newgrf_station.h"
|
||||||
|
#include "station_func.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/bridge_land.h"
|
#include "table/bridge_land.h"
|
||||||
@@ -626,6 +627,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
if (is_new_owner && c != nullptr) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (is_new_owner && c != nullptr) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
MakeAqueductBridgeRamp(tile_start, owner, dir);
|
MakeAqueductBridgeRamp(tile_start, owner, dir);
|
||||||
MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
|
MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
|
||||||
|
CheckForDockingTile(tile_start);
|
||||||
|
CheckForDockingTile(tile_end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1200,6 +1203,9 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
find_train_reservations(endtile);
|
find_train_reservations(endtile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool removetile = false;
|
||||||
|
bool removeendtile = false;
|
||||||
|
|
||||||
/* Update company infrastructure counts. */
|
/* Update company infrastructure counts. */
|
||||||
if (rail) {
|
if (rail) {
|
||||||
SubtractRailTunnelBridgeInfrastructure(tile, endtile);
|
SubtractRailTunnelBridgeInfrastructure(tile, endtile);
|
||||||
@@ -1213,6 +1219,8 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
}
|
}
|
||||||
} else { // Aqueduct
|
} else { // Aqueduct
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
|
removetile = IsDockingTile(tile);
|
||||||
|
removeendtile = IsDockingTile(endtile);
|
||||||
}
|
}
|
||||||
DirtyAllCompanyInfrastructureWindows();
|
DirtyAllCompanyInfrastructureWindows();
|
||||||
|
|
||||||
@@ -1221,6 +1229,9 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
DoClearSquare(endtile);
|
DoClearSquare(endtile);
|
||||||
|
|
||||||
|
if (removetile) RemoveDockingTile(tile);
|
||||||
|
if (removeendtile) RemoveDockingTile(endtile);
|
||||||
for (TileIndex c = tile + delta; c != endtile; c += delta) {
|
for (TileIndex c = tile + delta; c != endtile; c += delta) {
|
||||||
/* do not let trees appear from 'nowhere' after removing bridge */
|
/* do not let trees appear from 'nowhere' after removing bridge */
|
||||||
if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
|
if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
|
||||||
|
@@ -38,6 +38,7 @@ void DrawWaterClassGround(const struct TileInfo *ti);
|
|||||||
void DrawShoreTile(Slope tileh);
|
void DrawShoreTile(Slope tileh);
|
||||||
|
|
||||||
void MakeWaterKeepingClass(TileIndex tile, Owner o);
|
void MakeWaterKeepingClass(TileIndex tile, Owner o);
|
||||||
|
void CheckForDockingTile(TileIndex t);
|
||||||
|
|
||||||
bool RiverModifyDesertZone(TileIndex tile, void *data);
|
bool RiverModifyDesertZone(TileIndex tile, void *data);
|
||||||
static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile.
|
static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile.
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
#include "newgrf_generic.h"
|
#include "newgrf_generic.h"
|
||||||
|
#include "industry.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -148,6 +149,8 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
|||||||
|
|
||||||
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
|
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
|
||||||
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
|
||||||
|
CheckForDockingTile(tile);
|
||||||
|
CheckForDockingTile(tile2);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkTileDirtyByTile(tile2);
|
MarkTileDirtyByTile(tile2);
|
||||||
MakeDefaultName(depot);
|
MakeDefaultName(depot);
|
||||||
@@ -156,6 +159,51 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
|||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPossibleDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
assert(IsValidTile(t));
|
||||||
|
switch (GetTileType(t)) {
|
||||||
|
case MP_WATER:
|
||||||
|
if (IsLock(t) && GetLockPart(t) == LOCK_PART_MIDDLE) return false;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case MP_RAILWAY:
|
||||||
|
case MP_STATION:
|
||||||
|
case MP_TUNNELBRIDGE:
|
||||||
|
return TrackStatusToTrackBits(GetTileTrackStatus(t, TRANSPORT_WATER, 0)) != TRACK_BIT_NONE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the supplied tile as a docking tile if it is suitable for docking.
|
||||||
|
* Tiles surrounding the tile are tested to be docks with correct orientation.
|
||||||
|
* @param t Tile to test.
|
||||||
|
*/
|
||||||
|
void CheckForDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) {
|
||||||
|
TileIndex tile = t + TileOffsByDiagDir(d);
|
||||||
|
if (!IsValidTile(tile)) continue;
|
||||||
|
|
||||||
|
if (IsDockTile(tile) && IsValidDockingDirectionForDock(tile, d)) {
|
||||||
|
Station *st = Station::GetByTile(tile);
|
||||||
|
st->docking_station.Add(t);
|
||||||
|
st->docking_tiles.push_back(t);
|
||||||
|
SetDockingTile(t, true);
|
||||||
|
}
|
||||||
|
if (IsTileType(tile, MP_INDUSTRY)) {
|
||||||
|
Station *st = Industry::GetByTile(tile)->neutral_station;
|
||||||
|
if (st != nullptr) {
|
||||||
|
st->docking_station.Add(t);
|
||||||
|
st->docking_tiles.push_back(t);
|
||||||
|
SetDockingTile(t, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
||||||
{
|
{
|
||||||
WaterClass wc = GetWaterClass(tile);
|
WaterClass wc = GetWaterClass(tile);
|
||||||
@@ -204,6 +252,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wc != WATER_CLASS_INVALID) CheckForDockingTile(tile);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,6 +352,8 @@ static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag
|
|||||||
}
|
}
|
||||||
|
|
||||||
MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
|
MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle);
|
||||||
|
CheckForDockingTile(tile - delta);
|
||||||
|
CheckForDockingTile(tile + delta);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkTileDirtyByTile(tile - delta);
|
MarkTileDirtyByTile(tile - delta);
|
||||||
MarkTileDirtyByTile(tile + delta);
|
MarkTileDirtyByTile(tile + delta);
|
||||||
@@ -462,6 +513,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
}
|
}
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
CheckForDockingTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
cost.AddCost(_price[PR_BUILD_CANAL]);
|
cost.AddCost(_price[PR_BUILD_CANAL]);
|
||||||
@@ -510,8 +562,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
|||||||
Company::Get(owner)->infrastructure.water--;
|
Company::Get(owner)->infrastructure.water--;
|
||||||
DirtyCompanyInfrastructureWindows(owner);
|
DirtyCompanyInfrastructureWindows(owner);
|
||||||
}
|
}
|
||||||
|
bool remove = IsDockingTile(tile);
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
if (remove) RemoveDockingTile(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
|
return CommandCost(EXPENSES_CONSTRUCTION, base_cost);
|
||||||
@@ -531,8 +585,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags)
|
|||||||
ret = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
|
ret = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]);
|
||||||
}
|
}
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
|
bool remove = IsDockingTile(tile);
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
MarkCanalsAndRiversAroundDirty(tile);
|
MarkCanalsAndRiversAroundDirty(tile);
|
||||||
|
if (remove) RemoveDockingTile(tile);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1118,6 +1174,8 @@ void DoFloodTile(TileIndex target)
|
|||||||
|
|
||||||
/* update signals if needed */
|
/* update signals if needed */
|
||||||
UpdateSignalsInBuffer();
|
UpdateSignalsInBuffer();
|
||||||
|
|
||||||
|
if (IsPossibleDockingTile(target)) CheckForDockingTile(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_company.Restore();
|
cur_company.Restore();
|
||||||
|
@@ -69,6 +69,8 @@ enum LockPart {
|
|||||||
LOCK_PART_UPPER = 2, ///< Upper part of a lock.
|
LOCK_PART_UPPER = 2, ///< Upper part of a lock.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsPossibleDockingTile(TileIndex t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the water tile type at a tile.
|
* Get the water tile type at a tile.
|
||||||
* @param t Water tile to query.
|
* @param t Water tile to query.
|
||||||
@@ -346,6 +348,27 @@ static inline bool HasTileWaterGround(TileIndex t)
|
|||||||
return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t);
|
return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the docking tile state of a tile. This is used by pathfinders to reach their destination.
|
||||||
|
* As well as water tiles, half-rail tiles, buoys and aqueduct ends can also be docking tiles.
|
||||||
|
* @param t the tile
|
||||||
|
* @param b the docking tile state
|
||||||
|
*/
|
||||||
|
static inline void SetDockingTile(TileIndex t, bool b)
|
||||||
|
{
|
||||||
|
assert(IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE));
|
||||||
|
SB(_m[t].m1, 7, 1, b ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the tile is marked as a dockling tile.
|
||||||
|
* @return true iff the tile is marked as a docking tile.
|
||||||
|
*/
|
||||||
|
static inline bool IsDockingTile(TileIndex t)
|
||||||
|
{
|
||||||
|
return (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) && HasBit(_m[t].m1, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to make a coast tile.
|
* Helper function to make a coast tile.
|
||||||
@@ -356,6 +379,7 @@ static inline void MakeShore(TileIndex t)
|
|||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, OWNER_WATER);
|
SetTileOwner(t, OWNER_WATER);
|
||||||
SetWaterClass(t, WATER_CLASS_SEA);
|
SetWaterClass(t, WATER_CLASS_SEA);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
@@ -376,6 +400,7 @@ static inline void MakeWater(TileIndex t, Owner o, WaterClass wc, uint8 random_b
|
|||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, wc);
|
SetWaterClass(t, wc);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = random_bits;
|
_m[t].m4 = random_bits;
|
||||||
@@ -429,6 +454,7 @@ static inline void MakeShipDepot(TileIndex t, Owner o, DepotID did, DepotPart pa
|
|||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, original_water_class);
|
SetWaterClass(t, original_water_class);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = did;
|
_m[t].m2 = did;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
@@ -451,6 +477,7 @@ static inline void MakeLockTile(TileIndex t, Owner o, LockPart part, DiagDirecti
|
|||||||
SetTileType(t, MP_WATER);
|
SetTileType(t, MP_WATER);
|
||||||
SetTileOwner(t, o);
|
SetTileOwner(t, o);
|
||||||
SetWaterClass(t, original_water_class);
|
SetWaterClass(t, original_water_class);
|
||||||
|
SetDockingTile(t, false);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = 0;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
|
@@ -336,6 +336,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||||||
if (wp->town == nullptr) MakeDefaultName(wp);
|
if (wp->town == nullptr) MakeDefaultName(wp);
|
||||||
|
|
||||||
MakeBuoy(tile, wp->index, GetWaterClass(tile));
|
MakeBuoy(tile, wp->index, GetWaterClass(tile));
|
||||||
|
CheckForDockingTile(tile);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
|
|
||||||
wp->UpdateVirtCoord();
|
wp->UpdateVirtCoord();
|
||||||
|
Reference in New Issue
Block a user