mirror of https://github.com/OpenTTD/OpenTTD
(svn r14528) -Codechange: cache the closest town for all road tiles instead of only roads owned by tiles. This replaces a O(n) search over all towns from the road's tileloop with a O(1) lookup (PhilSophus)
parent
9075a2bbfc
commit
a14ad77a36
|
@ -513,6 +513,7 @@
|
||||||
<td valign=top nowrap> </td>
|
<td valign=top nowrap> </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>m2: Index into the array of towns (owning town for town roads; closest town otherwise, INVALID_TOWN if not yet calculated)</li>
|
||||||
<li>m3 bit 7 set = on snow or desert</li>
|
<li>m3 bit 7 set = on snow or desert</li>
|
||||||
<li>m7 bits 7..5: present road types
|
<li>m7 bits 7..5: present road types
|
||||||
<table>
|
<table>
|
||||||
|
@ -534,7 +535,6 @@
|
||||||
</li>
|
</li>
|
||||||
<li>m5 bits 7 clear: road or level-crossing
|
<li>m5 bits 7 clear: road or level-crossing
|
||||||
<ul>
|
<ul>
|
||||||
<li>m2: Index into the array of towns, 0 for non-town roads</li>
|
|
||||||
<li>m3 bits 6..4:
|
<li>m3 bits 6..4:
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -157,7 +157,7 @@ the array so you can quickly see what is used and what is not.
|
||||||
<td class="caption">road depot</td>
|
<td class="caption">road depot</td>
|
||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</td>
|
||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</td>
|
||||||
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
|
<td class="bits">-inherit-</td>
|
||||||
<td class="bits">X<span class="free">OOO OOOO</span></td>
|
<td class="bits">X<span class="free">OOO 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">XX<span class="free">OO OO</span>XX</td>
|
<td class="bits">XX<span class="free">OO OO</span>XX</td>
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
#include "tree_map.h"
|
#include "tree_map.h"
|
||||||
#include "rail_map.h"
|
#include "rail_map.h"
|
||||||
#include "road_map.h"
|
#include "road_map.h"
|
||||||
|
#include "road_cmd.h"
|
||||||
#include "station_map.h"
|
#include "station_map.h"
|
||||||
#include "town_map.h"
|
#include "town_map.h"
|
||||||
#include "industry_map.h"
|
#include "industry_map.h"
|
||||||
|
@ -2561,6 +2562,9 @@ bool AfterLoadGame()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckSavegameVersion(103)) {
|
if (CheckSavegameVersion(103)) {
|
||||||
|
/* Non-town-owned roads now store the closest town */
|
||||||
|
InvalidateTownForRoadTile();
|
||||||
|
|
||||||
/* signs with invalid owner left from older savegames */
|
/* signs with invalid owner left from older savegames */
|
||||||
Sign *si;
|
Sign *si;
|
||||||
FOR_ALL_SIGNS(si) {
|
FOR_ALL_SIGNS(si) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "openttd.h"
|
#include "openttd.h"
|
||||||
|
#include "map_func.h"
|
||||||
#include "bridge_map.h"
|
#include "bridge_map.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
#include "cmd_helper.h"
|
#include "cmd_helper.h"
|
||||||
|
@ -317,6 +318,11 @@ static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, Roa
|
||||||
/* Includes MarkTileDirtyByTile() */
|
/* Includes MarkTileDirtyByTile() */
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
} else {
|
} else {
|
||||||
|
if (rt == ROADTYPE_ROAD && IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) {
|
||||||
|
/* Promote ownership from tram or highway and invalidate town index */
|
||||||
|
SetRoadOwner(tile, ROADTYPE_ROAD, GetRoadOwner(tile, (HasBit(rts, ROADTYPE_TRAM) ? ROADTYPE_TRAM : ROADTYPE_HWAY)));
|
||||||
|
SetTownIndex(tile, (TownID)INVALID_TOWN);
|
||||||
|
}
|
||||||
SetRoadBits(tile, ROAD_NONE, rt);
|
SetRoadBits(tile, ROAD_NONE, rt);
|
||||||
SetRoadTypes(tile, rts);
|
SetRoadTypes(tile, rts);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
|
@ -354,6 +360,7 @@ static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, Roa
|
||||||
if (reserved) SetTrackReservation(tile, tracks);
|
if (reserved) SetTrackReservation(tile, tracks);
|
||||||
} else {
|
} else {
|
||||||
SetRoadTypes(tile, rts);
|
SetRoadTypes(tile, rts);
|
||||||
|
/* If we ever get HWAY and it is possible without road then we will need to promote ownership and invalidate town index here, too */
|
||||||
}
|
}
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile)));
|
YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile)));
|
||||||
|
@ -479,6 +486,10 @@ CommandCost CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
|
/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
|
||||||
* if a non-company is building the road */
|
* if a non-company is building the road */
|
||||||
if ((IsValidCompanyID(_current_company) && p2 != 0) || (_current_company == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
|
if ((IsValidCompanyID(_current_company) && p2 != 0) || (_current_company == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
|
||||||
|
if (_current_company != OWNER_TOWN) {
|
||||||
|
const Town *town = CalcClosestTownFromTile(tile, UINT_MAX);
|
||||||
|
p2 = (town != NULL) ? town->index : (TownID)INVALID_TOWN;
|
||||||
|
}
|
||||||
|
|
||||||
RoadBits pieces = Extract<RoadBits, 0>(p1);
|
RoadBits pieces = Extract<RoadBits, 0>(p1);
|
||||||
|
|
||||||
|
@ -654,7 +665,7 @@ do_clear:;
|
||||||
if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) {
|
if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) {
|
||||||
SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
|
SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt));
|
||||||
SetRoadOwner(tile, rt, _current_company);
|
SetRoadOwner(tile, rt, _current_company);
|
||||||
if (_current_company == OWNER_TOWN && rt == ROADTYPE_ROAD) SetTownIndex(tile, p2);
|
if (rt == ROADTYPE_ROAD) SetTownIndex(tile, p2);
|
||||||
}
|
}
|
||||||
if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt);
|
if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt);
|
||||||
} break;
|
} break;
|
||||||
|
@ -886,7 +897,7 @@ CommandCost CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2
|
||||||
Depot *dep = new Depot(tile);
|
Depot *dep = new Depot(tile);
|
||||||
dep->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
|
dep->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
|
||||||
|
|
||||||
MakeRoadDepot(tile, _current_company, dir, rt);
|
MakeRoadDepot(tile, _current_company, dir, rt, dep->town_index);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
}
|
}
|
||||||
return cost.AddCost(_price.build_road_depot);
|
return cost.AddCost(_price.build_road_depot);
|
||||||
|
@ -1263,6 +1274,18 @@ void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InvalidateTownForRoadTile()
|
||||||
|
{
|
||||||
|
TileIndex map_size = MapSize();
|
||||||
|
|
||||||
|
for (TileIndex t = 0; t < map_size; t++) {
|
||||||
|
if (IsTileType(t, MP_ROAD) && GetRoadOwner(t, ROADTYPE_ROAD) != OWNER_TOWN) {
|
||||||
|
/* GetRoadOwner(t, ROADTYPE_ROAD) is valid for road tiles even when there is no road */
|
||||||
|
SetTownIndex(t, (TownID)INVALID_TOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y)
|
static uint GetSlopeZ_Road(TileIndex tile, uint x, uint y)
|
||||||
{
|
{
|
||||||
uint z;
|
uint z;
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
#include "direction_type.h"
|
#include "direction_type.h"
|
||||||
|
|
||||||
void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt);
|
void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt);
|
||||||
|
void InvalidateTownForRoadTile();
|
||||||
|
|
||||||
#endif /* ROAD_CMD_H */
|
#endif /* ROAD_CMD_H */
|
||||||
|
|
|
@ -189,7 +189,7 @@ static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o)
|
||||||
|
|
||||||
static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o)
|
static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o)
|
||||||
{
|
{
|
||||||
assert(HasTileRoadType(t, rt));
|
assert(rt == ROADTYPE_ROAD || HasTileRoadType(t, rt));
|
||||||
return (GetRoadOwner(t, rt) == o);
|
return (GetRoadOwner(t, rt) == o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,11 +451,11 @@ static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void MakeRoadDepot(TileIndex t, Owner owner, DiagDirection dir, RoadType rt)
|
static inline void MakeRoadDepot(TileIndex t, Owner owner, DiagDirection dir, RoadType rt, TownID town)
|
||||||
{
|
{
|
||||||
SetTileType(t, MP_ROAD);
|
SetTileType(t, MP_ROAD);
|
||||||
SetTileOwner(t, owner);
|
SetTileOwner(t, owner);
|
||||||
_m[t].m2 = 0;
|
_m[t].m2 = town;
|
||||||
_m[t].m3 = 0;
|
_m[t].m3 = 0;
|
||||||
_m[t].m4 = 0;
|
_m[t].m4 = 0;
|
||||||
_m[t].m5 = ROAD_TILE_DEPOT << 6 | dir;
|
_m[t].m5 = ROAD_TILE_DEPOT << 6 | dir;
|
||||||
|
|
|
@ -1590,7 +1590,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2
|
||||||
/* Rebuild the drive throuhg road stop. As a road stop can only be
|
/* Rebuild the drive throuhg road stop. As a road stop can only be
|
||||||
* removed by the owner of the roadstop, _current_company is the
|
* removed by the owner of the roadstop, _current_company is the
|
||||||
* owner of the road stop. */
|
* owner of the road stop. */
|
||||||
MakeRoadNormal(tile, road_bits, rts, is_towns_road ? ClosestTownFromTile(tile, UINT_MAX)->index : 0,
|
MakeRoadNormal(tile, road_bits, rts, ClosestTownFromTile(tile, UINT_MAX)->index,
|
||||||
is_towns_road ? OWNER_TOWN : _current_company, _current_company, _current_company);
|
is_towns_road ? OWNER_TOWN : _current_company, _current_company, _current_company);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "road_map.h"
|
#include "road_map.h"
|
||||||
#include "road_internal.h" /* Cleaning up road bits */
|
#include "road_internal.h" /* Cleaning up road bits */
|
||||||
|
#include "road_cmd.h"
|
||||||
#include "landscape.h"
|
#include "landscape.h"
|
||||||
#include "town_map.h"
|
#include "town_map.h"
|
||||||
#include "tunnel_map.h"
|
#include "tunnel_map.h"
|
||||||
|
@ -93,6 +94,12 @@ Town::~Town()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_ROAD:
|
case MP_ROAD:
|
||||||
|
if (!IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && GetTownIndex(tile) == this->index) {
|
||||||
|
/* Town-owned roads get cleared soon, anyway */
|
||||||
|
SetTownIndex(tile, (TownID)INVALID_TOWN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall-through */
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE:
|
||||||
if (IsTileOwner(tile, OWNER_TOWN) &&
|
if (IsTileOwner(tile, OWNER_TOWN) &&
|
||||||
ClosestTownFromTile(tile, UINT_MAX) == this)
|
ClosestTownFromTile(tile, UINT_MAX) == this)
|
||||||
|
@ -1558,6 +1565,7 @@ CommandCost CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
Town *t = new Town(tile);
|
Town *t = new Town(tile);
|
||||||
_generating_world = true;
|
_generating_world = true;
|
||||||
DoCreateTown(t, tile, townnameparts, (TownSizeMode)p2, p1);
|
DoCreateTown(t, tile, townnameparts, (TownSizeMode)p2, p1);
|
||||||
|
InvalidateTownForRoadTile();
|
||||||
_generating_world = false;
|
_generating_world = false;
|
||||||
}
|
}
|
||||||
return CommandCost();
|
return CommandCost();
|
||||||
|
@ -2468,6 +2476,19 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold)
|
||||||
IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)
|
IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)
|
||||||
)) {
|
)) {
|
||||||
return GetTownByTile(tile);
|
return GetTownByTile(tile);
|
||||||
|
} else if (IsTileType(tile, MP_ROAD)) {
|
||||||
|
TownID town_id = GetTownIndex(tile);
|
||||||
|
Town *town;
|
||||||
|
|
||||||
|
if (town_id == INVALID_TOWN) {
|
||||||
|
town = CalcClosestTownFromTile(tile, UINT_MAX);
|
||||||
|
if (town != NULL) SetTownIndex(tile, town->index);
|
||||||
|
} else {
|
||||||
|
town = GetTown(town_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (town != NULL && town->IsValid() && DistanceManhattan(tile, town->xy) < threshold) return town;
|
||||||
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
return CalcClosestTownFromTile(tile, threshold);
|
return CalcClosestTownFromTile(tile, threshold);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "tilehighlight_func.h"
|
#include "tilehighlight_func.h"
|
||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
#include "sortlist_type.h"
|
#include "sortlist_type.h"
|
||||||
|
#include "road_cmd.h"
|
||||||
|
|
||||||
#include "table/sprites.h"
|
#include "table/sprites.h"
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
@ -731,6 +732,7 @@ public:
|
||||||
ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
|
ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
ScrollMainWindowToTile(t->xy);
|
ScrollMainWindowToTile(t->xy);
|
||||||
|
InvalidateTownForRoadTile();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -738,7 +740,11 @@ public:
|
||||||
this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
|
this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
|
||||||
|
|
||||||
_generating_world = true;
|
_generating_world = true;
|
||||||
if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
|
if (!GenerateTowns()) {
|
||||||
|
ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
|
||||||
|
} else {
|
||||||
|
InvalidateTownForRoadTile();
|
||||||
|
}
|
||||||
_generating_world = false;
|
_generating_world = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -783,4 +789,3 @@ void ShowBuildTownWindow()
|
||||||
if (_game_mode != GM_EDITOR && !IsValidCompanyID(_current_company)) return;
|
if (_game_mode != GM_EDITOR && !IsValidCompanyID(_current_company)) return;
|
||||||
AllocateWindowDescFront<ScenarioEditorTownGenerationWindow>(&_scen_edit_town_gen_desc, 0);
|
AllocateWindowDescFront<ScenarioEditorTownGenerationWindow>(&_scen_edit_town_gen_desc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue