diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index 71d2442e8e5b..2eb34f4e33ec 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -571,6 +571,8 @@ class SceneryWindow final : public Window widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_TERTIARY_COLOUR) + widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; } else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) { @@ -1200,8 +1202,13 @@ class SceneryWindow final : public Window else if (scenerySelection.SceneryType == SCENERY_TYPE_LARGE) { auto sceneryEntry = get_large_scenery_entry(scenerySelection.EntryIndex); - auto imageId = ImageId( - sceneryEntry->image + gWindowSceneryRotation, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); + auto imageId = ImageId(sceneryEntry->image + gWindowSceneryRotation); + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) + imageId = imageId.WithPrimary(gWindowSceneryPrimaryColour); + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + imageId = imageId.WithSecondary(gWindowScenerySecondaryColour); + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_TERTIARY_COLOUR) + imageId = imageId.WithTertiary(gWindowSceneryTertiaryColour); gfx_draw_sprite(&dpi, imageId, { 33, 0 }); } else if (scenerySelection.SceneryType == SCENERY_TYPE_WALL) diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 867cd4e7e0e2..f9ce3e1c0af5 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1066,7 +1066,8 @@ static void RepaintSceneryToolDown(const ScreenCoordsXY& windowPos, rct_widgetin auto repaintScenery = LargeScenerySetColourAction( { info.Loc, info.Element->GetBaseZ(), info.Element->GetDirection() }, - info.Element->AsLargeScenery()->GetSequenceIndex(), gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); + info.Element->AsLargeScenery()->GetSequenceIndex(), gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour, + gWindowSceneryTertiaryColour); GameActions::Execute(&repaintScenery); break; @@ -1947,7 +1948,8 @@ static void WindowTopToolbarSceneryToolDown(const ScreenCoordsXY& windowPos, rct CoordsXYZD loc = { gridPos, gSceneryPlaceZ, direction }; auto sceneryPlaceAction = LargeSceneryPlaceAction( - loc, selectedScenery, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); + loc, selectedScenery, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour, + gWindowSceneryTertiaryColour); auto res = GameActions::Query(&sceneryPlaceAction); if (res.Error == GameActions::Status::Ok) @@ -1972,7 +1974,7 @@ static void WindowTopToolbarSceneryToolDown(const ScreenCoordsXY& windowPos, rct CoordsXYZD loc = { gridPos, gSceneryPlaceZ, direction }; auto sceneryPlaceAction = LargeSceneryPlaceAction( - loc, selectedScenery, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour); + loc, selectedScenery, gWindowSceneryPrimaryColour, gWindowScenerySecondaryColour, gWindowSceneryTertiaryColour); sceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { @@ -2553,12 +2555,12 @@ static money64 TryPlaceGhostWall( } static money64 TryPlaceGhostLargeScenery( - CoordsXYZD loc, ObjectEntryIndex entryIndex, colour_t primaryColour, colour_t secondaryColour) + CoordsXYZD loc, ObjectEntryIndex entryIndex, colour_t primaryColour, colour_t secondaryColour, colour_t tertiaryColour) { scenery_remove_ghost_tool_placement(); // 6e25a7 - auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, entryIndex, primaryColour, secondaryColour); + auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, entryIndex, primaryColour, secondaryColour, tertiaryColour); sceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); auto res = GameActions::Execute(&sceneryPlaceAction); if (res.Error != GameActions::Status::Ok) @@ -2866,7 +2868,7 @@ static void TopToolbarToolUpdateScenery(const ScreenCoordsXY& screenPos) { cost = TryPlaceGhostLargeScenery( { mapTile, gSceneryPlaceZ, direction }, selection.EntryIndex, gWindowSceneryPrimaryColour, - gWindowScenerySecondaryColour); + gWindowScenerySecondaryColour, gWindowSceneryTertiaryColour); if (cost != MONEY64_UNDEFINED) break; diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.cpp b/src/openrct2/actions/LargeSceneryPlaceAction.cpp index 23612ea6bdb3..84297000156d 100644 --- a/src/openrct2/actions/LargeSceneryPlaceAction.cpp +++ b/src/openrct2/actions/LargeSceneryPlaceAction.cpp @@ -20,11 +20,12 @@ #include "../world/Surface.h" LargeSceneryPlaceAction::LargeSceneryPlaceAction( - const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour) + const CoordsXYZD& loc, ObjectEntryIndex sceneryType, uint8_t primaryColour, uint8_t secondaryColour, uint8_t tertiaryColour) : _loc(loc) , _sceneryType(sceneryType) , _primaryColour(primaryColour) , _secondaryColour(secondaryColour) + , _tertiaryColour(tertiaryColour) { } @@ -34,6 +35,7 @@ void LargeSceneryPlaceAction::AcceptParameters(GameActionParameterVisitor& visit visitor.Visit("object", _sceneryType); visitor.Visit("primaryColour", _primaryColour); visitor.Visit("secondaryColour", _secondaryColour); + visitor.Visit("tertiaryColour", _tertiaryColour); } uint16_t LargeSceneryPlaceAction::GetActionFlags() const @@ -45,7 +47,8 @@ void LargeSceneryPlaceAction::Serialise(DataSerialiser& stream) { GameAction::Serialise(stream); - stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour); + stream << DS_TAG(_loc) << DS_TAG(_sceneryType) << DS_TAG(_primaryColour) << DS_TAG(_secondaryColour) + << DS_TAG(_tertiaryColour); } GameActions::Result LargeSceneryPlaceAction::Query() const @@ -62,7 +65,7 @@ GameActions::Result LargeSceneryPlaceAction::Query() const money32 supportsCost = 0; - if (_primaryColour > TILE_ELEMENT_COLOUR_MASK || _secondaryColour > TILE_ELEMENT_COLOUR_MASK) + if (_primaryColour >= COLOUR_COUNT || _secondaryColour >= COLOUR_COUNT || _tertiaryColour >= COLOUR_COUNT) { log_error( "Invalid game command for scenery placement, primaryColour = %u, secondaryColour = %u", _primaryColour, @@ -381,6 +384,7 @@ void LargeSceneryPlaceAction::SetNewLargeSceneryElement(LargeSceneryElement& sce sceneryElement.SetSequenceIndex(tileNum); sceneryElement.SetPrimaryColour(_primaryColour); sceneryElement.SetSecondaryColour(_secondaryColour); + sceneryElement.SetTertiaryColour(_tertiaryColour); if (GetFlags() & GAME_COMMAND_FLAG_GHOST) { diff --git a/src/openrct2/actions/LargeSceneryPlaceAction.h b/src/openrct2/actions/LargeSceneryPlaceAction.h index 4eb294bd79b5..f26eb2268668 100644 --- a/src/openrct2/actions/LargeSceneryPlaceAction.h +++ b/src/openrct2/actions/LargeSceneryPlaceAction.h @@ -27,12 +27,14 @@ class LargeSceneryPlaceAction final : public GameActionBase 31) + if (_primaryColour >= COLOUR_COUNT) { log_error("Invalid primary colour: colour = %u", _primaryColour); return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS, STR_NONE); } - if (_secondaryColour > 31) + if (_secondaryColour >= COLOUR_COUNT) { - log_error("Invalid primary colour: colour = %u", _secondaryColour); + log_error("Invalid secondary colour: colour = %u", _secondaryColour); + return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS, STR_NONE); + } + + if (_tertiaryColour >= COLOUR_COUNT) + { + log_error("Invalid tertiary colour: colour = %u", _tertiaryColour); return GameActions::Result(GameActions::Status::InvalidParameters, STR_CANT_REPAINT_THIS, STR_NONE); } @@ -135,6 +143,7 @@ GameActions::Result LargeScenerySetColourAction::QueryExecute(bool isExecuting) { tileElement->SetPrimaryColour(_primaryColour); tileElement->SetSecondaryColour(_secondaryColour); + tileElement->SetTertiaryColour(_tertiaryColour); map_invalidate_tile_full(currentTile); } diff --git a/src/openrct2/actions/LargeScenerySetColourAction.h b/src/openrct2/actions/LargeScenerySetColourAction.h index d8525706d59d..70481afd21ee 100644 --- a/src/openrct2/actions/LargeScenerySetColourAction.h +++ b/src/openrct2/actions/LargeScenerySetColourAction.h @@ -18,10 +18,12 @@ class LargeScenerySetColourAction final : public GameActionBaseflags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) + { + imageTemplate = imageTemplate.WithPrimary(tileElement.GetPrimaryColour()); + } + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + { + imageTemplate = imageTemplate.WithSecondary(tileElement.GetSecondaryColour()); + } + if (sceneryEntry->flags & LARGE_SCENERY_FLAG_HAS_TERTIARY_COLOUR) + { + imageTemplate = imageTemplate.WithTertiary(tileElement.GetTertiaryColour()); + } } auto boxlengthZ = std::min(tile->z_clearance, 128) - 3; diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index b682c31eac9f..b8af5667b70a 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1127,7 +1127,8 @@ static GameActions::Result TrackDesignPlaceSceneryElement( flags |= GAME_COMMAND_FLAG_REPLAY; } auto sceneryPlaceAction = LargeSceneryPlaceAction( - { mapCoord.x, mapCoord.y, z, rotation }, entryInfo->Index, scenery.primary_colour, scenery.secondary_colour); + { mapCoord.x, mapCoord.y, z, rotation }, entryInfo->Index, scenery.primary_colour, scenery.secondary_colour, + COLOUR_DARK_BROWN); sceneryPlaceAction.SetFlags(flags); auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&sceneryPlaceAction) : GameActions::QueryNested(&sceneryPlaceAction); diff --git a/src/openrct2/world/LargeScenery.cpp b/src/openrct2/world/LargeScenery.cpp index 6103d5b64870..cc0b0101e8f0 100644 --- a/src/openrct2/world/LargeScenery.cpp +++ b/src/openrct2/world/LargeScenery.cpp @@ -26,6 +26,11 @@ colour_t LargeSceneryElement::GetSecondaryColour() const return Colour[1]; } +colour_t LargeSceneryElement::GetTertiaryColour() const +{ + return Colour[2]; +} + void LargeSceneryElement::SetPrimaryColour(colour_t newColour) { assert(newColour <= 31); @@ -38,6 +43,12 @@ void LargeSceneryElement::SetSecondaryColour(colour_t newColour) Colour[1] = newColour; } +void LargeSceneryElement::SetTertiaryColour(colour_t newColour) +{ + assert(newColour <= 31); + Colour[2] = newColour; +} + Banner* LargeSceneryElement::GetBanner() const { return ::GetBanner(GetBannerIndex()); diff --git a/src/openrct2/world/Scenery.h b/src/openrct2/world/Scenery.h index 67fdda736b61..92296ea24439 100644 --- a/src/openrct2/world/Scenery.h +++ b/src/openrct2/world/Scenery.h @@ -97,6 +97,7 @@ enum LARGE_SCENERY_FLAGS LARGE_SCENERY_FLAG_ANIMATED = (1 << 3), // 0x8 LARGE_SCENERY_FLAG_PHOTOGENIC = (1 << 4), // 0x10 LARGE_SCENERY_FLAG_IS_TREE = (1 << 5), // 0x20 + LARGE_SCENERY_FLAG_HAS_TERTIARY_COLOUR = (1 << 6), // 0x40 }; enum WALL_SCENERY_FLAGS diff --git a/src/openrct2/world/TileElement.h b/src/openrct2/world/TileElement.h index e21ff2d9120d..e75a012421bd 100644 --- a/src/openrct2/world/TileElement.h +++ b/src/openrct2/world/TileElement.h @@ -483,6 +483,8 @@ struct LargeSceneryElement : TileElementBase void SetPrimaryColour(colour_t colour); colour_t GetSecondaryColour() const; void SetSecondaryColour(colour_t colour); + colour_t GetTertiaryColour() const; + void SetTertiaryColour(colour_t colour); Banner* GetBanner() const; ::BannerIndex GetBannerIndex() const;