diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 698a8dc9b0..d5b2edf127 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -4241,7 +4241,7 @@ static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteRe case 0x10: // Flags spec->flags = (ObjectFlags)buf.ReadWord(); - _loaded_newgrf_features.has_2CC |= (spec->flags & OBJECT_FLAG_2CC_COLOUR) != 0; + _loaded_newgrf_features.has_2CC |= spec->flags.Test(ObjectFlag::Uses2CC); break; case 0x11: // Animation info diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 7e0d1cc5ac..18a1122fdd 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -74,7 +74,7 @@ size_t ObjectSpec::Count() bool ObjectSpec::IsEverAvailable() const { return this->IsEnabled() && this->climate.Test(_settings_game.game_creation.landscape) && - (this->flags & ((_game_mode != GM_EDITOR && !_generating_world) ? OBJECT_FLAG_ONLY_IN_SCENEDIT : OBJECT_FLAG_ONLY_IN_GAME)) == 0; + !this->flags.Test((_game_mode != GM_EDITOR && !_generating_world) ? ObjectFlag::OnlyInScenedit : ObjectFlag::OnlyInGame); } /** @@ -438,7 +438,7 @@ uint16_t GetObjectCallback(CallbackID callback, uint32_t param1, uint32_t param2 static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec) { const DrawTileSprites *dts = group->ProcessRegisters(nullptr); - PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour; + PaletteID palette = (spec->flags.Test(ObjectFlag::Uses2CC) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour; SpriteID image = dts->ground.sprite; PaletteID pal = dts->ground.pal; @@ -446,7 +446,7 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou if (GB(image, 0, SPRITE_WIDTH) != 0) { /* If the ground sprite is the default flat water sprite, draw also canal/river borders * Do not do this if the tile's WaterClass is 'land'. */ - if ((image == SPR_FLAT_WATER_TILE || spec->flags & OBJECT_FLAG_DRAW_WATER) && IsTileOnWater(ti->tile)) { + if ((image == SPR_FLAT_WATER_TILE || spec->flags.Test(ObjectFlag::DrawWater)) && IsTileOnWater(ti->tile)) { DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); @@ -490,7 +490,7 @@ void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8_t view) PaletteID palette; if (Company::IsValidID(_local_company)) { /* Get the colours of our company! */ - if (spec->flags & OBJECT_FLAG_2CC_COLOUR) { + if (spec->flags.Test(ObjectFlag::Uses2CC)) { const Livery *l = Company::Get(_local_company)->livery; palette = SPR_2CCMAP_BASE + l->colour1 + l->colour2 * 16; } else { @@ -498,7 +498,7 @@ void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8_t view) } } else { /* There's no company, so just take the base palette. */ - palette = (spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START; + palette = spec->flags.Test(ObjectFlag::Uses2CC) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START; } SpriteID image = dts->ground.sprite; @@ -542,9 +542,9 @@ struct ObjectAnimationBase : public AnimationBaseflags & OBJECT_FLAG_ANIMATION)) return; + if (spec == nullptr || !spec->flags.Test(ObjectFlag::Animation)) return; - ObjectAnimationBase::AnimateTile(spec, Object::GetByTile(tile), tile, (spec->flags & OBJECT_FLAG_ANIM_RANDOM_BITS) != 0); + ObjectAnimationBase::AnimateTile(spec, Object::GetByTile(tile), tile, spec->flags.Test(ObjectFlag::AnimRandomBits)); } /** diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 0414b4dcb3..ca16df4c95 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -21,24 +21,23 @@ #include "newgrf_commons.h" /** Various object behaviours. */ -enum ObjectFlags : uint16_t { - OBJECT_FLAG_NONE = 0, ///< Just nothing. - OBJECT_FLAG_ONLY_IN_SCENEDIT = 1 << 0, ///< Object can only be constructed in the scenario editor. - OBJECT_FLAG_CANNOT_REMOVE = 1 << 1, ///< Object can not be removed. - OBJECT_FLAG_AUTOREMOVE = 1 << 2, ///< Object get automatically removed (like "owned land"). - OBJECT_FLAG_BUILT_ON_WATER = 1 << 3, ///< Object can be built on water (not required). - OBJECT_FLAG_CLEAR_INCOME = 1 << 4, ///< When object is cleared a positive income is generated instead of a cost. - OBJECT_FLAG_HAS_NO_FOUNDATION = 1 << 5, ///< Do not display foundations when on a slope. - OBJECT_FLAG_ANIMATION = 1 << 6, ///< Object has animated tiles. - OBJECT_FLAG_ONLY_IN_GAME = 1 << 7, ///< Object can only be built in game. - OBJECT_FLAG_2CC_COLOUR = 1 << 8, ///< Object wants 2CC colour mapping. - OBJECT_FLAG_NOT_ON_LAND = 1 << 9, ///< Object can not be on land, implicitly sets #OBJECT_FLAG_BUILT_ON_WATER. - OBJECT_FLAG_DRAW_WATER = 1 << 10, ///< Object wants to be drawn on water. - OBJECT_FLAG_ALLOW_UNDER_BRIDGE = 1 << 11, ///< Object can built under a bridge. - OBJECT_FLAG_ANIM_RANDOM_BITS = 1 << 12, ///< Object wants random bits in "next animation frame" callback. - OBJECT_FLAG_SCALE_BY_WATER = 1 << 13, ///< Object count is roughly scaled by water amount at edges. +enum class ObjectFlag : uint8_t { + OnlyInScenedit = 0, ///< Object can only be constructed in the scenario editor. + CannotRemove = 1, ///< Object can not be removed. + Autoremove = 2, ///< Object get automatically removed (like "owned land"). + BuiltOnWater = 3, ///< Object can be built on water (not required). + ClearIncome = 4, ///< When object is cleared a positive income is generated instead of a cost. + HasNoFoundation = 5, ///< Do not display foundations when on a slope. + Animation = 6, ///< Object has animated tiles. + OnlyInGame = 7, ///< Object can only be built in game. + Uses2CC = 8, ///< Object wants 2CC colour mapping. + NotOnLand = 9, ///< Object can not be on land, implicitly sets #ObjectFlag::BuiltOnWater. + DrawWater = 10, ///< Object wants to be drawn on water. + AllowUnderBridge = 11, ///< Object can built under a bridge. + AnimRandomBits = 12, ///< Object wants random bits in "next animation frame" callback. + ScaleByWater = 13, ///< Object count is roughly scaled by water amount at edges. }; -DECLARE_ENUM_AS_BIT_SET(ObjectFlags) +using ObjectFlags = EnumBitSet; static const uint8_t OBJECT_SIZE_1X1 = 0x11; ///< The value of a NewGRF's size property when the object is 1x1 tiles: low nibble for X, high nibble for Y. diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 30e3fbf7dd..a43d89663f 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -107,7 +107,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u } /* If the object wants only one colour, then give it that colour. */ - if ((spec->flags & OBJECT_FLAG_2CC_COLOUR) == 0) o->colour &= 0xF; + if (!spec->flags.Test(ObjectFlag::Uses2CC)) o->colour &= 0xF; if (spec->callback_mask.Test(ObjectCallbackMask::Colour)) { uint16_t res = GetObjectCallback(CBID_OBJECT_COLOUR, o->colour, 0, spec, o, tile); @@ -135,7 +135,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u } Object::IncTypeCount(type); - if (spec->flags & OBJECT_FLAG_ANIMATION) TriggerObjectAnimation(o, OAT_BUILT, spec); + if (spec->flags.Test(ObjectFlag::Animation)) TriggerObjectAnimation(o, OAT_BUILT, spec); } /** @@ -192,7 +192,7 @@ void UpdateObjectColours(const Company *c) if (spec->callback_mask.Test(ObjectCallbackMask::Colour)) continue; const Livery *l = c->livery; - obj->colour = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? (l->colour2 * 16) : 0) + l->colour1; + obj->colour = (spec->flags.Test(ObjectFlag::Uses2CC) ? (l->colour2 * 16) : 0) + l->colour1; } } @@ -216,8 +216,8 @@ CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, if (_game_mode == GM_NORMAL && !spec->IsAvailable() && !_generating_world) return CMD_ERROR; if ((_game_mode == GM_EDITOR || _generating_world) && !spec->WasEverAvailable()) return CMD_ERROR; - if ((spec->flags & OBJECT_FLAG_ONLY_IN_SCENEDIT) != 0 && ((!_generating_world && _game_mode != GM_EDITOR) || _current_company != OWNER_NONE)) return CMD_ERROR; - if ((spec->flags & OBJECT_FLAG_ONLY_IN_GAME) != 0 && (_generating_world || _game_mode != GM_NORMAL || _current_company > MAX_COMPANIES)) return CMD_ERROR; + if (spec->flags.Test(ObjectFlag::OnlyInScenedit) && ((!_generating_world && _game_mode != GM_EDITOR) || _current_company != OWNER_NONE)) return CMD_ERROR; + if (spec->flags.Test(ObjectFlag::OnlyInGame) && (_generating_world || _game_mode != GM_NORMAL || _current_company > MAX_COMPANIES)) return CMD_ERROR; if (view >= spec->views) return CMD_ERROR; if (!Object::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_OBJECTS); @@ -237,8 +237,8 @@ CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, /* Check the surface to build on. At this time we can't actually execute the * the CLEAR_TILE commands since the newgrf callback later on can check * some information about the tiles. */ - bool allow_water = (spec->flags & (OBJECT_FLAG_BUILT_ON_WATER | OBJECT_FLAG_NOT_ON_LAND)) != 0; - bool allow_ground = (spec->flags & OBJECT_FLAG_NOT_ON_LAND) == 0; + bool allow_water = spec->flags.Any({ObjectFlag::BuiltOnWater, ObjectFlag::NotOnLand}); + bool allow_ground = !spec->flags.Test(ObjectFlag::NotOnLand); for (TileIndex t : ta) { if (HasTileWaterGround(t)) { if (!allow_water) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER); @@ -308,7 +308,7 @@ CommandCost CmdBuildObject(DoCommandFlag flags, TileIndex tile, ObjectType type, /* Finally do a check for bridges. */ for (TileIndex t : ta) { if (IsBridgeAbove(t) && ( - !(spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) || + !spec->flags.Test(ObjectFlag::AllowUnderBridge) || (GetTileMaxZ(t) + spec->height >= GetBridgeHeight(GetSouthernBridgeEnd(t))))) { return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } @@ -443,7 +443,7 @@ static void DrawTile_Object(TileInfo *ti) /* Fall back for when the object doesn't exist anymore. */ if (!spec->IsEnabled()) type = OBJECT_TRANSMITTER; - if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); + if (!spec->flags.Test(ObjectFlag::HasNoFoundation)) DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); if (type < NEW_OBJECT_OFFSET) { const DrawTileSprites *dts = nullptr; @@ -457,7 +457,7 @@ static void DrawTile_Object(TileInfo *ti) dts = &_objects[type]; } - if (spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) { + if (spec->flags.Test(ObjectFlag::HasNoFoundation)) { /* If an object has no foundation, but tries to draw a (flat) ground * type... we have to be nice and convert that for them. */ switch (dts->ground.sprite) { @@ -549,7 +549,7 @@ static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) const ObjectSpec *spec = ObjectSpec::Get(type); CommandCost cost(EXPENSES_CONSTRUCTION, spec->GetClearCost() * ta.w * ta.h / 5); - if (spec->flags & OBJECT_FLAG_CLEAR_INCOME) cost.MultiplyCost(-1); // They get an income! + if (spec->flags.Test(ObjectFlag::ClearIncome)) cost.MultiplyCost(-1); // They get an income! /* Towns can't remove any objects. */ if (_current_company == OWNER_TOWN) return CMD_ERROR; @@ -559,18 +559,18 @@ static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) if ((flags & DC_NO_WATER) && IsTileOnWater(tile)) { /* There is water under the object, treat it as water tile. */ return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER); - } else if (!(spec->flags & OBJECT_FLAG_AUTOREMOVE) && (flags & DC_AUTO)) { + } else if (!spec->flags.Test(ObjectFlag::Autoremove) && (flags & DC_AUTO)) { /* No automatic removal by overbuilding stuff. */ return CommandCost(type == OBJECT_HQ ? STR_ERROR_COMPANY_HEADQUARTERS_IN : STR_ERROR_OBJECT_IN_THE_WAY); } else if (_game_mode == GM_EDITOR) { /* No further limitations for the editor. */ } else if (GetTileOwner(tile) == OWNER_NONE) { /* Owned by nobody and unremovable, so we can only remove it with brute force! */ - if (!_cheats.magic_bulldozer.value && (spec->flags & OBJECT_FLAG_CANNOT_REMOVE) != 0) return CMD_ERROR; + if (!_cheats.magic_bulldozer.value && spec->flags.Test(ObjectFlag::CannotRemove)) return CMD_ERROR; } else if (CheckTileOwnership(tile).Failed()) { /* We don't own it!. */ return CommandCost(STR_ERROR_OWNED_BY); - } else if ((spec->flags & OBJECT_FLAG_CANNOT_REMOVE) != 0 && (spec->flags & OBJECT_FLAG_AUTOREMOVE) == 0) { + } else if (spec->flags.All({ObjectFlag::CannotRemove, ObjectFlag::Autoremove})) { /* In the game editor or with cheats we can remove, otherwise we can't. */ if (!_cheats.magic_bulldozer.value) { if (type == OBJECT_HQ) return CommandCost(STR_ERROR_COMPANY_HEADQUARTERS_IN); @@ -580,7 +580,7 @@ static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) /* Removing with the cheat costs more in TTDPatch / the specs. */ cost.MultiplyCost(25); } - } else if ((spec->flags & (OBJECT_FLAG_BUILT_ON_WATER | OBJECT_FLAG_NOT_ON_LAND)) != 0) { + } else if (spec->flags.Any({ObjectFlag::BuiltOnWater, ObjectFlag::NotOnLand})) { /* Water can't remove objects that are buildable on water. */ return CMD_ERROR; } @@ -673,7 +673,7 @@ static void GetTileDesc_Object(TileIndex tile, TileDesc *td) static void TileLoop_Object(TileIndex tile) { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); - if (spec->flags & OBJECT_FLAG_ANIMATION) { + if (spec->flags.Test(ObjectFlag::Animation)) { Object *o = Object::GetByTile(tile); TriggerObjectTileAnimation(o, tile, OAT_TILELOOP, spec); if (o->location.tile == tile) TriggerObjectAnimation(o, OAT_256_TICKS, spec); @@ -840,12 +840,12 @@ void GenerateObjects() uint16_t amount = spec.generate_amount; /* Scale by map size */ - if ((spec.flags & OBJECT_FLAG_SCALE_BY_WATER) && _settings_game.construction.freeform_edges) { + if (spec.flags.Test(ObjectFlag::ScaleByWater) && _settings_game.construction.freeform_edges) { /* Scale the amount of lighthouses with the amount of land at the borders. * The -6 is because the top borders are MP_VOID (-2) and all corners * are counted twice (-4). */ amount = Map::ScaleBySize1D(amount * num_water_tiles) / (2 * Map::MaxY() + 2 * Map::MaxX() - 6); - } else if (spec.flags & OBJECT_FLAG_SCALE_BY_WATER) { + } else if (spec.flags.Test(ObjectFlag::ScaleByWater)) { amount = Map::ScaleBySize1D(amount); } else { amount = Map::ScaleBySize(amount); diff --git a/src/table/object_land.h b/src/table/object_land.h index 23856ee961..f097de619c 100644 --- a/src/table/object_land.h +++ b/src/table/object_land.h @@ -134,11 +134,11 @@ static const DrawTileSprites _object_hq[] = { #define Y LandscapeType::Toyland /** Specification of the original object structures. */ extern const ObjectSpec _original_objects[] = { - M(STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER, 0x11, 0, 0, 10, LandscapeTypes({T,A,S }), 15, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT), - M(STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE, 0x11, 0, 0, 8, LandscapeTypes({T,A }), 8, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT | OBJECT_FLAG_SCALE_BY_WATER), - M(STR_TOWN_BUILDING_NAME_STATUE_1, 0x11, 0, 0, 5, LandscapeTypes({T,S,A,Y}), 0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_ONLY_IN_SCENEDIT), // Yes, we disallow building this everywhere. Happens in "special" case! - M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND, 0x11, 10, 10, 0, LandscapeTypes({T,S,A,Y}), 0, OBJECT_FLAG_AUTOREMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_CLEAR_INCOME | OBJECT_FLAG_HAS_NO_FOUNDATION ), // Only non-silly use case is to use it when you cannot build a station, so disallow bridges - M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS, 0x22, 0, 0, 7, LandscapeTypes({T,S,A,Y}), 0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME), + M(STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER, 0x11, 0, 0, 10, LandscapeTypes({T,A,S }), 15, ObjectFlags({ObjectFlag::CannotRemove, ObjectFlag::OnlyInScenedit})), + M(STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE, 0x11, 0, 0, 8, LandscapeTypes({T,A }), 8, ObjectFlags({ObjectFlag::CannotRemove, ObjectFlag::OnlyInScenedit, ObjectFlag::ScaleByWater})), + M(STR_TOWN_BUILDING_NAME_STATUE_1, 0x11, 0, 0, 5, LandscapeTypes({T,S,A,Y}), 0, ObjectFlags({ObjectFlag::CannotRemove, ObjectFlag::OnlyInGame, ObjectFlag::OnlyInScenedit})), // Yes, we disallow building this everywhere. Happens in "special" case! + M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND, 0x11, 10, 10, 0, LandscapeTypes({T,S,A,Y}), 0, ObjectFlags({ObjectFlag::Autoremove, ObjectFlag::OnlyInGame, ObjectFlag::ClearIncome, ObjectFlag::HasNoFoundation})), // Only non-silly use case is to use it when you cannot build a station, so disallow bridges + M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS, 0x22, 0, 0, 7, LandscapeTypes({T,S,A,Y}), 0, ObjectFlags({ObjectFlag::CannotRemove, ObjectFlag::OnlyInGame})), }; #undef M diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 22bbcfe91c..f7269fd7c7 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -480,7 +480,7 @@ CommandCost CmdBuildBridge(DoCommandFlag flags, TileIndex tile_end, TileIndex ti case MP_OBJECT: { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); - if ((spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) == 0) goto not_valid_below; + if (!spec->flags.Test(ObjectFlag::AllowUnderBridge)) goto not_valid_below; if (GetTileMaxZ(tile) + spec->height > z_start) goto not_valid_below; break; }