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:
Jonathan G Rennison
2019-07-13 20:34:52 +01:00
50 changed files with 783 additions and 543 deletions

View File

@@ -255,6 +255,7 @@
<td valign=top nowrap>&nbsp;</td> <td valign=top nowrap>&nbsp;</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>&nbsp;</td> <td valign=top nowrap>&nbsp;</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>&nbsp;</td> <td valign=top nowrap>&nbsp;</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>&nbsp;</td> <td valign=top nowrap>&nbsp;</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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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}مجدول

View File

@@ -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}다음 목적지가 너무 멀리 있습니다

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 = &current->path.node; const AyStarNode *node = &current->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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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