diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 77a1acdb16..258ee09f66 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -19,6 +19,7 @@ #include "viewport.h" #include "gfx.h" #include "player.h" +#include "road.h" #include "command.h" #include "news.h" #include "town.h" @@ -930,7 +931,7 @@ static void ToolbarBuildRoadClick(Window *w) { const Player *p = GetPlayer(_local_player); /* The standard road button is *always* available */ - Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | 1)); + Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD)); WP(w2, menu_d).sel_index = _last_built_roadtype; } diff --git a/src/player.h b/src/player.h index ecafe12c79..98f3f6f83f 100644 --- a/src/player.h +++ b/src/player.h @@ -8,8 +8,11 @@ #include "oldpool.h" #include "aystar.h" #include "rail.h" +#include "road.h" #include "engine.h" #include "livery.h" +#include "genworld.h" +#include "gfx.h" struct PlayerEconomyEntry { Money income; @@ -253,12 +256,34 @@ static inline bool IsValidPlayer(PlayerID pi) byte GetPlayerRailtypes(PlayerID p); byte GetPlayerRoadtypes(PlayerID p); -/** Finds out if a Player has a certain railtype available */ -static inline bool HasRailtypeAvail(const Player *p, RailType Railtype) +/** Finds out if a Player has a certain railtype available + * @param p Player in question + * @param Railtype requested RailType + * @return true if player has requested RailType available + */ +static inline bool HasRailtypeAvail(const Player *p, const RailType Railtype) { return HASBIT(p->avail_railtypes, Railtype); } +/** Finds out, whether given player has all given RoadTypes available + * @param PlayerID ID of player + * @param rts RoadTypes to test + * @return true if player has all requested RoadTypes available + */ +static inline bool HasRoadTypesAvail(const PlayerID p, const RoadTypes rts) +{ + RoadTypes avail_roadtypes; + + if (p == OWNER_TOWN || _game_mode == GM_EDITOR || IsGeneratingWorld()) { + avail_roadtypes = ROADTYPES_ROAD; + } else { + if (!IsValidPlayer(p)) return false; + avail_roadtypes = (RoadTypes)GetPlayer(p)->avail_roadtypes | ROADTYPES_ROAD; // road is available for always for everybody + } + return (rts & ~avail_roadtypes) == 0; +} + static inline bool IsHumanPlayer(PlayerID pi) { return !GetPlayer(pi)->is_ai; @@ -272,7 +297,10 @@ static inline bool IsInteractivePlayer(PlayerID pi) void DrawPlayerIcon(PlayerID p, int x, int y); /* Validate functions for rail building */ -static inline bool ValParamRailtype(uint32 rail) { return HASBIT(GetPlayer(_current_player)->avail_railtypes, rail);} +static inline bool ValParamRailtype(const uint32 rail) { return HASBIT(GetPlayer(_current_player)->avail_railtypes, rail);} + +/* Validate functions for road building */ +static inline bool ValParamRoadType(const RoadType rt) { return HasRoadTypesAvail(_current_player, RoadTypeToRoadTypes(rt));} /** Returns the "best" railtype a player can build. * As the AI doesn't know what the BEST one is, we have our own priority list diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 68ec7d9570..0ae4da4afc 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -405,7 +405,7 @@ CommandCost CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) RoadBits pieces = Extract(p1); RoadType rt = (RoadType)GB(p1, 4, 2); - if (!IsValidRoadType(rt)) return CMD_ERROR; + if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2); @@ -636,7 +636,7 @@ CommandCost CmdBuildLongRoad(TileIndex end_tile, uint32 flags, uint32 p1, uint32 start_tile = p1; RoadType rt = (RoadType)GB(p2, 3, 2); - if (!IsValidRoadType(rt)) return CMD_ERROR; + if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; /* 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 @@ -786,7 +786,7 @@ CommandCost CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2 DiagDirection dir = Extract(p1); RoadType rt = (RoadType)GB(p1, 2, 2); - if (!IsValidRoadType(rt)) return CMD_ERROR; + if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; tileh = GetTileSlope(tile, NULL); if (tileh != SLOPE_FLAT && ( diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index dcf3f1f53d..edb8876b44 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1318,7 +1318,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) bool town_owned_road = build_over_road && IsTileOwner(tile, OWNER_TOWN); RoadTypes rts = (RoadTypes)GB(p2, 2, 3); - if (rts == ROADTYPES_NONE || HASBIT(rts, ROADTYPE_HWAY)) return CMD_ERROR; + if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR; /* Trams only have drive through stops */ if (!is_drive_through && HASBIT(rts, ROADTYPE_TRAM)) return CMD_ERROR; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index d5ff51d954..1bd4322f51 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -213,7 +213,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p if (HASBIT(p2, 15)) { railtype = INVALID_RAILTYPE; // road bridge roadtypes = (RoadTypes)GB(p2, 8, 3); - if (!AreValidRoadTypes(roadtypes)) return CMD_ERROR; + if (!AreValidRoadTypes(roadtypes) || !HasRoadTypesAvail(_current_player, roadtypes)) return CMD_ERROR; } else { if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR; railtype = (RailType)GB(p2, 8, 8); @@ -464,8 +464,9 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, uint32 flags, uint32 p1, uint32 _build_tunnel_endtile = 0; if (!HASBIT(p1, 9)) { if (!ValParamRailtype(p1)) return CMD_ERROR; - } else if (!AreValidRoadTypes((RoadTypes)GB(p1, 0, 3))) { - return CMD_ERROR; + } else { + const RoadTypes rts = (RoadTypes)GB(p1, 0, 3); + if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR; } start_tileh = GetTileSlope(start_tile, &start_z);