src/road_cmd.cpp
changeset 8734 cf2c240d2e1b
parent 8732 0262169b6bc9
child 8744 099f75f4b51f
equal deleted inserted replaced
8733:e60ce9c3ae47 8734:cf2c240d2e1b
    45 
    45 
    46 Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
    46 Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
    47 
    47 
    48 bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
    48 bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
    49 {
    49 {
    50 	RoadBits present;
       
    51 	RoadBits n;
       
    52 	*edge_road = true;
    50 	*edge_road = true;
    53 
    51 
    54 	if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return true;
    52 	if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return true;
    55 
    53 
    56 	/* Water can always flood and towns can always remove "normal" road pieces.
    54 	/* Water can always flood and towns can always remove "normal" road pieces.
    64 	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
    62 	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
    65 
    63 
    66 	if (_cheats.magic_bulldozer.value) return true;
    64 	if (_cheats.magic_bulldozer.value) return true;
    67 
    65 
    68 	/* Get a bitmask of which neighbouring roads has a tile */
    66 	/* Get a bitmask of which neighbouring roads has a tile */
    69 	n = ROAD_NONE;
    67 	RoadBits n = ROAD_NONE;
    70 	present = GetAnyRoadBits(tile, rt);
    68 	RoadBits present = GetAnyRoadBits(tile, rt);
    71 	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1,  0), rt) & ROAD_SW) n |= ROAD_NE;
    69 	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1,  0), rt) & ROAD_SW) n |= ROAD_NE;
    72 	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile,  0,  1), rt) & ROAD_NW) n |= ROAD_SE;
    70 	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile,  0,  1), rt) & ROAD_NW) n |= ROAD_SE;
    73 	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile,  1,  0), rt) & ROAD_NE) n |= ROAD_SW;
    71 	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile,  1,  0), rt) & ROAD_NE) n |= ROAD_SW;
    74 	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile,  0, -1), rt) & ROAD_SE) n |= ROAD_NW;
    72 	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile,  0, -1), rt) & ROAD_SE) n |= ROAD_NW;
    75 
    73 
    76 	/* If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
    74 	/* If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
    77 	 * then allow it */
    75 	 * then allow it */
    78 	if ((n & (n - 1)) != 0 && (n & remove) != 0) {
    76 	if (KillFirstBit(n) != ROAD_NONE && (n & remove) != ROAD_NONE) {
    79 		Town *t;
       
    80 		*edge_road = false;
    77 		*edge_road = false;
    81 		/* you can remove all kind of roads with extra dynamite */
    78 		/* you can remove all kind of roads with extra dynamite */
    82 		if (_patches.extra_dynamite) return true;
    79 		if (_patches.extra_dynamite) return true;
    83 
    80 
    84 		t = ClosestTownFromTile(tile, (uint)-1);
    81 		const Town *t = ClosestTownFromTile(tile, (uint)-1);
    85 
    82 
    86 		SetDParam(0, t->index);
    83 		SetDParam(0, t->index);
    87 		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
    84 		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
    88 		return false;
    85 		return false;
    89 	}
    86 	}
   177 	}
   174 	}
   178 
   175 
   179 	switch (GetRoadTileType(tile)) {
   176 	switch (GetRoadTileType(tile)) {
   180 		case ROAD_TILE_NORMAL: {
   177 		case ROAD_TILE_NORMAL: {
   181 			RoadBits present = GetRoadBits(tile, rt);
   178 			RoadBits present = GetRoadBits(tile, rt);
   182 			RoadBits c = pieces;
       
   183 
   179 
   184 			if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
   180 			if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
   185 
   181 
   186 			if (GetTileSlope(tile, NULL) != SLOPE_FLAT  &&
   182 			if (GetTileSlope(tile, NULL) != SLOPE_FLAT && IsStraightRoad(present)) {
   187 					(present == ROAD_Y || present == ROAD_X)) {
   183 				pieces |= MirrorRoadBits(pieces);
   188 				c |= (RoadBits)((c & 0xC) >> 2);
       
   189 				c |= (RoadBits)((c & 0x3) << 2);
       
   190 			}
   184 			}
   191 
   185 
   192 			/* limit the bits to delete to the existing bits. */
   186 			/* limit the bits to delete to the existing bits. */
   193 			c &= present;
   187 			pieces &= present;
   194 			if (c == ROAD_NONE) return CMD_ERROR;
   188 			if (pieces == ROAD_NONE) return CMD_ERROR;
   195 
   189 
   196 			ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
   190 			ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
   197 			if (flags & DC_EXEC) {
   191 			if (flags & DC_EXEC) {
   198 				present ^= c;
   192 				present ^= pieces;
   199 				if (present == ROAD_NONE) {
   193 				if (present == ROAD_NONE) {
   200 					RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
   194 					RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
   201 					if (rts == ROADTYPES_NONE) {
   195 					if (rts == ROADTYPES_NONE) {
   202 						/* Includes MarkTileDirtyByTile() */
   196 						/* Includes MarkTileDirtyByTile() */
   203 						DoClearSquare(tile);
   197 						DoClearSquare(tile);
   213 					if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE);
   207 					if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE);
   214 					SetRoadBits(tile, present, rt);
   208 					SetRoadBits(tile, present, rt);
   215 					MarkTileDirtyByTile(tile);
   209 					MarkTileDirtyByTile(tile);
   216 				}
   210 				}
   217 			}
   211 			}
   218 			return CommandCost(EXPENSES_CONSTRUCTION, CountBits(c) * _price.remove_road);
   212 			return CommandCost(EXPENSES_CONSTRUCTION, CountBits(pieces) * _price.remove_road);
   219 		}
   213 		}
   220 
   214 
   221 		case ROAD_TILE_CROSSING: {
   215 		case ROAD_TILE_CROSSING: {
   222 			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
   216 			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
   223 				return CMD_ERROR;
   217 				return CMD_ERROR;
   348  * @param existing The existent RoadBits
   342  * @param existing The existent RoadBits
   349  * @return The costs for these RoadBits on this slope
   343  * @return The costs for these RoadBits on this slope
   350  */
   344  */
   351 static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
   345 static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
   352 {
   346 {
       
   347 	/* Proceed steep Slopes first to reduce lookup table size */
   353 	if (IsSteepSlope(tileh)) {
   348 	if (IsSteepSlope(tileh)) {
   354 		/* Force straight roads. */
   349 		/* Force straight roads. */
   355 		*pieces |= MirrorRoadBits(*pieces);
   350 		*pieces |= MirrorRoadBits(*pieces);
   356 
   351 
   357 		if (existing == ROAD_NONE || existing == *pieces) {
   352 		if (existing == ROAD_NONE || existing == *pieces) {
   404 {
   399 {
   405 	CommandCost cost(EXPENSES_CONSTRUCTION);
   400 	CommandCost cost(EXPENSES_CONSTRUCTION);
   406 	CommandCost ret;
   401 	CommandCost ret;
   407 	RoadBits existing = ROAD_NONE;
   402 	RoadBits existing = ROAD_NONE;
   408 	RoadBits all_bits = ROAD_NONE;
   403 	RoadBits all_bits = ROAD_NONE;
   409 	Slope tileh;
       
   410 
   404 
   411 	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
   405 	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
   412 	 * if a non-player is building the road */
   406 	 * if a non-player is building the road */
   413 	if ((IsValidPlayer(_current_player) && p2 != 0) || (_current_player == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
   407 	if ((IsValidPlayer(_current_player) && p2 != 0) || (_current_player == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
   414 
   408 
   420 	RoadType rt = (RoadType)GB(p1, 4, 2);
   414 	RoadType rt = (RoadType)GB(p1, 4, 2);
   421 	if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
   415 	if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
   422 
   416 
   423 	DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2);
   417 	DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2);
   424 
   418 
   425 	tileh = GetTileSlope(tile, NULL);
   419 	Slope tileh = GetTileSlope(tile, NULL);
   426 
   420 
   427 	switch (GetTileType(tile)) {
   421 	switch (GetTileType(tile)) {
   428 		case MP_ROAD:
   422 		case MP_ROAD:
   429 			switch (GetRoadTileType(tile)) {
   423 			switch (GetRoadTileType(tile)) {
   430 				case ROAD_TILE_NORMAL: {
   424 				case ROAD_TILE_NORMAL: {
   432 
   426 
   433 					all_bits = GetAllRoadBits(tile);
   427 					all_bits = GetAllRoadBits(tile);
   434 					if (!HasTileRoadType(tile, rt)) break;
   428 					if (!HasTileRoadType(tile, rt)) break;
   435 
   429 
   436 					existing = GetRoadBits(tile, rt);
   430 					existing = GetRoadBits(tile, rt);
   437 					RoadBits merged = existing | pieces;
   431 					bool crossing = !IsStraightRoad(existing | pieces);
   438 					bool crossing = (merged != ROAD_X && merged != ROAD_Y);
       
   439 					if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) {
   432 					if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) {
   440 						/* Junctions cannot be one-way */
   433 						/* Junctions cannot be one-way */
   441 						return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
   434 						return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
   442 					}
   435 					}
   443 					if ((existing & pieces) == pieces) {
   436 					if ((existing & pieces) == pieces) {
   446 							if (crossing) return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
   439 							if (crossing) return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
   447 
   440 
   448 							if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
   441 							if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
   449 
   442 
   450 							/* Ignore half built tiles */
   443 							/* Ignore half built tiles */
   451 							if (flags & DC_EXEC && rt != ROADTYPE_TRAM && (existing == ROAD_X || existing == ROAD_Y)) {
   444 							if (flags & DC_EXEC && rt != ROADTYPE_TRAM && IsStraightRoad(existing)) {
   452 								SetDisallowedRoadDirections(tile, GetDisallowedRoadDirections(tile) ^ toggle_drd);
   445 								SetDisallowedRoadDirections(tile, GetDisallowedRoadDirections(tile) ^ toggle_drd);
   453 								MarkTileDirtyByTile(tile);
   446 								MarkTileDirtyByTile(tile);
   454 							}
   447 							}
   455 							return CommandCost();
   448 							return CommandCost();
   456 						}
   449 						}
   606 				break;
   599 				break;
   607 		}
   600 		}
   608 
   601 
   609 		if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) {
   602 		if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) {
   610 			existing |= pieces;
   603 			existing |= pieces;
   611 			SetDisallowedRoadDirections(tile, (existing == ROAD_X || existing == ROAD_Y) ?
   604 			SetDisallowedRoadDirections(tile, IsStraightRoad(existing) ?
   612 					GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE);
   605 					GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE);
   613 		}
   606 		}
   614 
   607 
   615 		MarkTileDirtyByTile(tile);
   608 		MarkTileDirtyByTile(tile);
   616 	}
   609 	}
   898 	byte subcoord_y;
   891 	byte subcoord_y;
   899 };
   892 };
   900 
   893 
   901 #include "table/road_land.h"
   894 #include "table/road_land.h"
   902 
   895 
   903 
   896 /**
       
   897  * Get the foundationtype of a RoadBits Slope combination
       
   898  *
       
   899  * @param tileh The Slope part
       
   900  * @param bits The RoadBits part
       
   901  * @return The resulting Foundation
       
   902  */
   904 Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
   903 Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
   905 {
   904 {
       
   905 	/* Flat land and land without a road doesn't require a foundation */
       
   906 	if (tileh == SLOPE_FLAT || bits == ROAD_NONE) return FOUNDATION_NONE;
       
   907 
   906 	if (!IsSteepSlope(tileh)) {
   908 	if (!IsSteepSlope(tileh)) {
   907 		if ((~_valid_tileh_slopes_road[0][tileh] & bits) == 0) {
   909 		if ((~_valid_tileh_slopes_road[0][tileh] & bits) == ROAD_NONE) {
   908 			/* As one can remove a single road piece when in a corner on a foundation as
   910 			/* As one can remove a single road piece when in a corner on a foundation as
   909 			 * it is on a sloped piece of landscape, one creates a state that cannot be
   911 			 * it is on a sloped piece of landscape, one creates a state that cannot be
   910 			 * created directly, but the state itself is still perfectly drawable.
   912 			 * created directly, but the state itself is still perfectly drawable.
   911 			 * However, as we do not want this to be build directly, we need to check
   913 			 * However, as we do not want this to be build directly, we need to check
   912 			 * for that situation in here. */
   914 			 * for that situation in here. */
   913 			return (tileh != 0 && CountBits(bits) == 1) ? FOUNDATION_LEVELED : FOUNDATION_NONE;
   915 			return (CountBits(bits) == 1) ? FOUNDATION_LEVELED : FOUNDATION_NONE;
   914 		}
   916 		}
   915 		if ((~_valid_tileh_slopes_road[1][tileh] & bits) == 0) return FOUNDATION_LEVELED;
   917 		if ((~_valid_tileh_slopes_road[1][tileh] & bits) == ROAD_NONE) return FOUNDATION_LEVELED;
   916 	}
   918 	}
   917 
   919 
   918 	return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
   920 	return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
   919 }
   921 }
   920 
   922