diff options
Diffstat (limited to 'road_cmd.c')
-rw-r--r-- | road_cmd.c | 187 |
1 files changed, 100 insertions, 87 deletions
diff --git a/road_cmd.c b/road_cmd.c index 762547c2e..0a89492da 100644 --- a/road_cmd.c +++ b/road_cmd.c @@ -124,8 +124,10 @@ uint GetRoadBitsByTile(TileIndex tile) return (byte)(r | (r >> 8)); } -/* Delete a piece of road - * p1 = piece type +/** Delete a piece of road. + * @param x,y tile coordinates for road construction + * @param p1 road piece flags + * @param p2 unused */ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) { @@ -137,13 +139,16 @@ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) TileIndex tile; byte owner; Town *t; - /* true if the roadpiece was always removeable, - false if it was a center piece. Affects town ratings drop - */ + /* true if the roadpiece was always removeable, + * false if it was a center piece. Affects town ratings drop */ bool edge_road; + byte pieces = (byte)p1; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); + /* Road pieces are max 4 bitset values (NE, NW, SE, SW) */ + if (pieces >> 4) return CMD_ERROR; + FindLandscapeHeight(&ti, x, y); tile = ti.tile; @@ -169,10 +174,9 @@ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) { bool b; _road_special_gettrackstatus = true; - b = CheckAllowRemoveRoad(tile, p1, &edge_road); + b = CheckAllowRemoveRoad(tile, pieces, &edge_road); _road_special_gettrackstatus = false; - if (!b) - return CMD_ERROR; + if (!b) return CMD_ERROR; } if (ti.type == MP_TUNNELBRIDGE) { @@ -180,9 +184,9 @@ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) return CMD_ERROR; if ((ti.map5 & 0xE9) == 0xE8) { - if (p1 & 10) goto return_error; + if (pieces & 10) goto return_error; } else if ((ti.map5 & 0xE9) == 0xE9) { - if (p1 & 5) goto return_error; + if (pieces & 5) goto return_error; } else goto return_error; @@ -202,7 +206,7 @@ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) // XXX - change cascading ifs to switch when doing rewrite if ((ti.map5 & 0xF0) == 0) { // normal road - uint c = p1, t2; + byte c = pieces, t2; if (ti.tileh != 0 && (ti.map5 == 5 || ti.map5 == 10)) { c |= (c & 0xC) >> 2; @@ -235,10 +239,10 @@ int32 CmdRemoveRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) if (!(ti.map5 & 8)) { c = 2; - if (p1 & 5) goto return_error; + if (pieces & 5) goto return_error; } else { c = 1; - if (p1 & 10) goto return_error; + if (pieces & 10) goto return_error; } cost = _price.remove_road * 2; @@ -340,30 +344,33 @@ static uint32 CheckRoadSlope(int tileh, byte *pieces, byte existing) return CMD_ERROR; } -/* Build a piece of road - * p1 = piece flags - * p2 = town which is building the road +/** Build a piece of road. + * @param x,y tile coordinates for road construction + * @param p1 road piece flags + * @param p2 the town that is building the road (0 if not applicable) */ - int32 CmdBuildRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileInfo ti; int32 cost; byte pieces = (byte)p1, existing = 0; - uint tile; + TileIndex tile; 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 ((pieces >> 4) || (_current_player < MAX_PLAYERS && p2 != 0) || !IsTownIndex(p2)) return CMD_ERROR; + FindLandscapeHeight(&ti, x, y); tile = ti.tile; // allow building road under bridge - if (ti.type != MP_TUNNELBRIDGE && !EnsureNoVehicle(tile)) - return CMD_ERROR; + if (ti.type != MP_TUNNELBRIDGE && !EnsureNoVehicle(tile)) return CMD_ERROR; if (ti.type == MP_STREET) { if (!(ti.map5 & 0xF0)) { - if ( ((pieces) & (byte)(ti.map5)) == (pieces)) + if ( (pieces & (byte)(ti.map5)) == (pieces)) return_cmd_error(STR_1007_ALREADY_BUILT); existing = ti.map5; } else { @@ -433,12 +440,12 @@ int32 CmdBuildRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) return cost; } else { do_clear:; - if (DoCommandByTile(tile, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR) == CMD_ERROR) + if (CmdFailed(DoCommandByTile(tile, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR))) return CMD_ERROR; } cost = CheckRoadSlope(ti.tileh, &pieces, existing); - if (cost == CMD_ERROR) return_cmd_error(STR_1800_LAND_SLOPED_IN_WRONG_DIRECTION); + if (CmdFailed(cost)) return_cmd_error(STR_1800_LAND_SLOPED_IN_WRONG_DIRECTION); if (cost && (!_patches.build_on_slopes || (!_patches.ainew_active && _is_ai_player))) return CMD_ERROR; @@ -494,123 +501,130 @@ int32 DoConvertStreetRail(uint tile, uint totype, bool exec) } -// Build a long piece of road. -// x,y = end tile -// p1 = start tile -// p2&1 = start tile starts in the 2nd half -// p2&2 = end tile starts in the 2nd half -// p2&4 = direction (0 = along x, 1=along y) +/** Build a long piece of road. + * @param x,y end tile of drag + * @param p1 start tile of drag + * @param p2 various bitstuffed elements + * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) + * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) + * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) + */ int32 CmdBuildLongRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - uint start_tile, end_tile, tile; - int mode; - int32 cost,ret; + TileIndex start_tile, end_tile, tile; + int32 cost, ret; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); + if (p1 > MapSize()) return CMD_ERROR; + start_tile = p1; end_tile = TILE_FROM_XY(x, y); - if (start_tile > end_tile || (start_tile == end_tile && (p2&1))) { - uint t = start_tile; start_tile = end_tile; end_tile = t; + /* Only drag in X or Y direction dictated by the direction variable */ + if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis + if (HASBIT(p2, 2) && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis + + /* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */ + if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) { + TileIndex t = start_tile; + start_tile = end_tile; + end_tile = t; p2 ^= IS_INT_INSIDE(p2&3, 1, 3) ? 3 : 0; } cost = 0; tile = start_tile; // Start tile is the small number. - for(;;) { - mode = (p2&4) ? 5 : 10; - - if (tile == start_tile && (p2&1)) - mode &= (4+2); - else if (tile == end_tile && !(p2&2)) - mode &= (1+8); - - ret = DoCommandByTile(tile, mode, 0, flags, CMD_BUILD_ROAD); - if (ret == CMD_ERROR) { - if (_error_message != STR_1007_ALREADY_BUILT) - return CMD_ERROR; - } else { + for (;;) { + uint bits = HASBIT(p2, 2) ? ROAD_SE | ROAD_NW : ROAD_SW | ROAD_NE; + if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE; + if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW; + + ret = DoCommandByTile(tile, bits, 0, flags, CMD_BUILD_ROAD); + if (CmdFailed(ret)) { + if (_error_message != STR_1007_ALREADY_BUILT) return CMD_ERROR; + } else cost += ret; - } - if (tile == end_tile) - break; + if (tile == end_tile) break; - tile += (p2&4)?TILE_XY(0,1):TILE_XY(1,0); + tile += HASBIT(p2, 2) ? TILE_XY(0, 1) : TILE_XY(1, 0); } - // already built? - if (cost == 0) - return CMD_ERROR; - - return cost; + return (cost == 0) ? CMD_ERROR : cost; } -// Remove a long piece of road. -// x,y = end tile -// p1 = start tile -// p2&1 = start tile starts in the 2nd half -// p2&2 = end tile starts in the 2nd half -// p2&4 = direction (0 = along x, 1=along y) +/** Remove a long piece of road. + * @param x,y end tile of drag + * @param p1 start tile of drag + * @param p2 various bitstuffed elements + * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) + * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) + * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) + */ int32 CmdRemoveLongRoad(int x, int y, uint32 flags, uint32 p1, uint32 p2) { - uint start_tile, end_tile, tile; - int32 cost,ret; + TileIndex start_tile, end_tile, tile; + int32 cost, ret; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); + if (p1 > MapSize()) return CMD_ERROR; + start_tile = p1; end_tile = TILE_FROM_XY(x, y); - if (start_tile > end_tile || (start_tile == end_tile && (p2&1))) { - uint t = start_tile; start_tile = end_tile; end_tile = t; + /* Only drag in X or Y direction dictated by the direction variable */ + if (!HASBIT(p2, 2) && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis + if (HASBIT(p2, 2) && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis + + /* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */ + if (start_tile > end_tile || (start_tile == end_tile && HASBIT(p2, 0))) { + TileIndex t = start_tile; + start_tile = end_tile; + end_tile = t; p2 ^= IS_INT_INSIDE(p2&3, 1, 3) ? 3 : 0; } cost = 0; tile = start_tile; // Start tile is the small number. - for(;;) { - uint bits = (p2 & 4) ? ROAD_SE | ROAD_NW : ROAD_SW | ROAD_NE; - if (tile == end_tile && !(p2&2)) bits &= ROAD_NW | ROAD_NE; - if (tile == start_tile && (p2&1)) bits &= ROAD_SE | ROAD_SW; + for (;;) { + uint bits = HASBIT(p2, 2) ? ROAD_SE | ROAD_NW : ROAD_SW | ROAD_NE; + if (tile == end_tile && !HASBIT(p2, 1)) bits &= ROAD_NW | ROAD_NE; + if (tile == start_tile && HASBIT(p2, 0)) bits &= ROAD_SE | ROAD_SW; // try to remove the halves. if (bits) { ret = DoCommandByTile(tile, bits, 0, flags, CMD_REMOVE_ROAD); - if (ret != CMD_ERROR) - cost += ret; + if (!CmdFailed(ret)) cost += ret; } - if (tile == end_tile) - break; + if (tile == end_tile) break; - tile += (p2&4)?TILE_XY(0,1):TILE_XY(1,0); + tile += HASBIT(p2, 2) ? TILE_XY(0, 1) : TILE_XY(1, 0); } - // already built? - if (cost == 0) - return CMD_ERROR; - - return cost; + return (cost == 0) ? CMD_ERROR : cost; } -/* Build a road depot - * p1 - direction (0-3) - * p2 - unused +/** Build a road depot. + * @param x,y tile coordinates where the depot will be built + * @param p1 depot direction (0 through 3), where 0 is NW, 1 is NE, etc. + * @param p2 unused */ - int32 CmdBuildRoadDepot(int x, int y, uint32 flags, uint32 p1, uint32 p2) { TileInfo ti; int32 cost; Depot *dep; - uint tile; + TileIndex tile; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); + if (p2 > 3) return CMD_ERROR; // check direction + FindLandscapeHeight(&ti, x, y); tile = ti.tile; @@ -624,8 +638,7 @@ int32 CmdBuildRoadDepot(int x, int y, uint32 flags, uint32 p1, uint32 p2) } cost = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); - if (cost == CMD_ERROR) - return CMD_ERROR; + if (CmdFailed(cost)) return CMD_ERROR; dep = AllocateDepot(); if (dep == NULL) |