|
|
/* $Id$ */
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
#include "openttd.h"
|
|
|
#include "bridge_map.h"
|
|
|
#include "rail_map.h"
|
|
|
#include "road_map.h"
|
|
|
#include "sprite.h"
|
|
|
#include "table/sprites.h"
|
|
|
#include "table/strings.h"
|
|
|
#include "functions.h"
|
|
|
#include "map.h"
|
|
|
#include "tile.h"
|
|
|
#include "town_map.h"
|
|
|
#include "vehicle.h"
|
|
|
#include "viewport.h"
|
|
|
#include "command.h"
|
|
|
#include "player.h"
|
|
|
#include "town.h"
|
|
|
#include "gfx.h"
|
|
|
#include "sound.h"
|
|
|
#include "yapf/yapf.h"
|
|
|
#include "depot.h"
|
|
|
|
|
|
|
|
|
static uint CountRoadBits(RoadBits r)
|
|
|
{
|
|
|
uint count = 0;
|
|
|
|
|
|
if (r & ROAD_NW) ++count;
|
|
|
if (r & ROAD_SW) ++count;
|
|
|
if (r & ROAD_SE) ++count;
|
|
|
if (r & ROAD_NE) ++count;
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
|
|
|
static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool* edge_road)
|
|
|
{
|
|
|
RoadBits present;
|
|
|
RoadBits n;
|
|
|
Owner owner;
|
|
|
*edge_road = true;
|
|
|
|
|
|
if (_game_mode == GM_EDITOR) return true;
|
|
|
|
|
|
// Only do the special processing for actual players.
|
|
|
if (_current_player >= MAX_PLAYERS) return true;
|
|
|
if (!IsValidPlayer(_current_player)) return true;
|
|
|
|
|
|
owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
|
|
|
|
|
|
// Only do the special processing if the road is owned
|
|
|
// by a town
|
|
|
if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
|
|
|
|
|
|
if (_cheats.magic_bulldozer.value) return true;
|
|
|
|
|
|
// Get a bitmask of which neighbouring roads has a tile
|
|
|
n = 0;
|
|
|
present = GetAnyRoadBits(tile);
|
|
|
if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile,-1, 0)) & ROAD_SW) n |= ROAD_NE;
|
|
|
if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE;
|
|
|
if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW;
|
|
|
if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0,-1)) & ROAD_SE) n |= ROAD_NW;
|
|
|
|
|
|
// If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
|
|
|
// then allow it
|
|
|
if ((n & (n - 1)) != 0 && (n & remove) != 0) {
|
|
|
Town *t;
|
|
|
*edge_road = false;
|
|
|
// you can remove all kind of roads with extra dynamite
|
|
|
if (_patches.extra_dynamite) return true;
|
|
|
|
|
|
t = ClosestTownFromTile(tile, _patches.dist_local_authority);
|
|
|
|
|
|
SetDParam(0, t->index);
|
|
|
_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
/** Delete a piece of road.
|
|
|
* @param tile tile where to remove road from
|
|
|
* @param p1 road piece flags
|
|
|
* @param p2 unused
|
|
|
*/
|
|
|
int32 CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
|
|
{
|
|
|
// cost for removing inner/edge -roads
|
|
|
static const uint16 road_remove_cost[2] = {50, 18};
|
|
|
|
|
|
Owner owner;
|
|
|
Town *t;
|
|
@@ -244,97 +244,97 @@ static uint32 CheckRoadSlope(Slope tileh
|
|
|
// force full pieces.
|
|
|
*pieces |= (*pieces & 0xC) >> 2;
|
|
|
*pieces |= (*pieces & 0x3) << 2;
|
|
|
if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
|
|
|
}
|
|
|
return CMD_ERROR;
|
|
|
}
|
|
|
road_bits = *pieces | existing;
|
|
|
|
|
|
// no special foundation
|
|
|
if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == 0) {
|
|
|
// force that all bits are set when we have slopes
|
|
|
if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
|
|
|
return 0; // no extra cost
|
|
|
}
|
|
|
|
|
|
// foundation is used. Whole tile is leveled up
|
|
|
if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == 0) {
|
|
|
return existing != 0 ? 0 : _price.terraform;
|
|
|
}
|
|
|
|
|
|
// partly leveled up tile, only if there's no road on that tile
|
|
|
if (existing == 0 && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
|
|
|
// force full pieces.
|
|
|
*pieces |= (*pieces & 0xC) >> 2;
|
|
|
*pieces |= (*pieces & 0x3) << 2;
|
|
|
if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
|
|
|
}
|
|
|
return CMD_ERROR;
|
|
|
}
|
|
|
|
|
|
/** Build a piece of road.
|
|
|
* @param tile tile where to build road
|
|
|
* @param p1 road piece flags
|
|
|
* @param p2 the town that is building the road (0 if not applicable)
|
|
|
*/
|
|
|
int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
|
|
{
|
|
|
int32 cost = 0;
|
|
|
int32 ret;
|
|
|
RoadBits existing = 0;
|
|
|
RoadBits pieces;
|
|
|
Slope tileh;
|
|
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
|
|
|
|
|
|
/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
|
|
|
* if a non-player is building the road */
|
|
|
if ((p1 >> 4) || (_current_player < MAX_PLAYERS && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
|
|
|
if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
|
|
|
pieces = p1;
|
|
|
|
|
|
tileh = GetTileSlope(tile, NULL);
|
|
|
|
|
|
switch (GetTileType(tile)) {
|
|
|
case MP_STREET:
|
|
|
switch (GetRoadTileType(tile)) {
|
|
|
case ROAD_TILE_NORMAL:
|
|
|
if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
|
|
|
|
|
|
existing = GetRoadBits(tile);
|
|
|
if ((existing & pieces) == pieces) {
|
|
|
return_cmd_error(STR_1007_ALREADY_BUILT);
|
|
|
}
|
|
|
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
|
|
|
break;
|
|
|
|
|
|
case ROAD_TILE_CROSSING:
|
|
|
if (pieces != GetCrossingRoadBits(tile)) { // XXX is this correct?
|
|
|
return_cmd_error(STR_1007_ALREADY_BUILT);
|
|
|
}
|
|
|
goto do_clear;
|
|
|
|
|
|
default:
|
|
|
case ROAD_TILE_DEPOT:
|
|
|
goto do_clear;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case MP_RAILWAY: {
|
|
|
Axis roaddir;
|
|
|
|
|
|
if (IsSteepSlope(tileh)) {
|
|
|
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
|
|
|
}
|
|
|
|
|
|
#define M(x) (1 << (x))
|
|
|
/* Level crossings may only be built on these slopes */
|
|
|
if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
|
|
|
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
|
|
|
}
|
|
|
#undef M
|
|
|
|
|
|
if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
|
|
|
switch (GetTrackBits(tile)) {
|
|
|
case TRACK_BIT_X:
|
|
|
if (pieces & ROAD_X) goto do_clear;
|
|
|
roaddir = AXIS_Y;
|