diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index dfd88ffc1b..bc5cf801c7 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 4CB832AB1EFFB8D100B88761 /* ttf_sdlport.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CB832A81EFFB8D100B88761 /* ttf_sdlport.c */; }; 4CB832AC1EFFB8D100B88761 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CB832A91EFFB8D100B88761 /* ttf.c */; }; 4CF788C01F1B787700C611BF /* Painter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF788BE1F1B787700C611BF /* Painter.cpp */; }; + 4CFBCD5E1F27CD8000D74FB6 /* SmallScenery.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CFBCD5D1F27CD8000D74FB6 /* SmallScenery.cpp */; }; C606CCBE1DB4054000FE4015 /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAB1DB4054000FE4015 /* compat.c */; }; C606CCBF1DB4054000FE4015 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAC1DB4054000FE4015 /* data.c */; }; C606CCC01DB4054000FE4015 /* FunctionCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAE1DB4054000FE4015 /* FunctionCall.cpp */; }; @@ -581,6 +582,7 @@ 4CB832AA1EFFB8D100B88761 /* ttf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ttf.h; sourceTree = ""; }; 4CF788BE1F1B787700C611BF /* Painter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Painter.cpp; sourceTree = ""; }; 4CF788BF1F1B787700C611BF /* Painter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Painter.h; sourceTree = ""; }; + 4CFBCD5D1F27CD8000D74FB6 /* SmallScenery.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallScenery.cpp; sourceTree = ""; }; C606CCAB1DB4054000FE4015 /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = compat.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; C606CCAC1DB4054000FE4015 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = data.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; C606CCAD1DB4054000FE4015 /* data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = data.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -2505,6 +2507,7 @@ F76C85731EC4E7CD00FA49E2 /* particle.c */, F76C85741EC4E7CD00FA49E2 /* scenery.c */, F76C85751EC4E7CD00FA49E2 /* scenery.h */, + 4CFBCD5D1F27CD8000D74FB6 /* SmallScenery.cpp */, F76C85761EC4E7CD00FA49E2 /* sprite.c */, F76C85771EC4E7CD00FA49E2 /* sprite.h */, F76C85781EC4E7CD00FA49E2 /* tile_inspector.c */, @@ -3021,6 +3024,7 @@ F76C88871EC5324E00FA49E2 /* SwapFramebuffer.cpp in Sources */, F76C88881EC5324E00FA49E2 /* TextureCache.cpp in Sources */, F76C88891EC5324E00FA49E2 /* SoftwareDrawingEngine.cpp in Sources */, + 4CFBCD5E1F27CD8000D74FB6 /* SmallScenery.cpp in Sources */, F76C888A1EC5324E00FA49E2 /* TextComposition.cpp in Sources */, F76C888B1EC5324E00FA49E2 /* Ui.cpp in Sources */, F76C888C1EC5324E00FA49E2 /* UiContext.cpp in Sources */, diff --git a/src/openrct2/interface/viewport_interaction.c b/src/openrct2/interface/viewport_interaction.c index 49803a8058..11b72efa8f 100644 --- a/src/openrct2/interface/viewport_interaction.c +++ b/src/openrct2/interface/viewport_interaction.c @@ -265,7 +265,7 @@ sint32 viewport_interaction_get_item_right(sint32 x, sint32 y, viewport_interact case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: sceneryEntry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF); - if (sceneryEntry->large_scenery.var_11 != 255) { + if (sceneryEntry->large_scenery.scrolling_mode != 255) { set_map_tooltip_format_arg(0, rct_string_id, STR_MAP_TOOLTIP_STRINGID_CLICK_TO_MODIFY); set_map_tooltip_format_arg(2, rct_string_id, sceneryEntry->name); return info->type; @@ -515,7 +515,7 @@ static void viewport_interaction_remove_large_scenery(rct_map_element *mapElemen { rct_scenery_entry *sceneryEntry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK); - if (sceneryEntry->large_scenery.var_11 != 0xFF){ + if (sceneryEntry->large_scenery.scrolling_mode != 0xFF){ sint32 id = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); diff --git a/src/openrct2/object/LargeSceneryObject.cpp b/src/openrct2/object/LargeSceneryObject.cpp index c9e220ecc5..7dc6c061ce 100644 --- a/src/openrct2/object/LargeSceneryObject.cpp +++ b/src/openrct2/object/LargeSceneryObject.cpp @@ -39,7 +39,7 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre _legacyType.large_scenery.removal_price = stream->ReadValue(); stream->Seek(5, STREAM_SEEK_CURRENT); _legacyType.large_scenery.scenery_tab_id = 0xFF; - _legacyType.large_scenery.var_11 = stream->ReadValue(); + _legacyType.large_scenery.scrolling_mode = stream->ReadValue(); stream->Seek(4, STREAM_SEEK_CURRENT); GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); diff --git a/src/openrct2/object/SmallSceneryObject.cpp b/src/openrct2/object/SmallSceneryObject.cpp index 7f32c5d97c..5e13248847 100644 --- a/src/openrct2/object/SmallSceneryObject.cpp +++ b/src/openrct2/object/SmallSceneryObject.cpp @@ -27,7 +27,7 @@ extern "C" SmallSceneryObject::~SmallSceneryObject() { - Memory::Free(_var10data); + Memory::Free(_frameOffsets); } void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream) @@ -39,9 +39,9 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre _legacyType.small_scenery.price = stream->ReadValue(); _legacyType.small_scenery.removal_price = stream->ReadValue(); stream->Seek(4, STREAM_SEEK_CURRENT); - _legacyType.small_scenery.var_14 = stream->ReadValue(); - _legacyType.small_scenery.var_16 = stream->ReadValue(); - _legacyType.small_scenery.var_18 = stream->ReadValue(); + _legacyType.small_scenery.animation_delay = stream->ReadValue(); + _legacyType.small_scenery.animation_mask = stream->ReadValue(); + _legacyType.small_scenery.num_frames = stream->ReadValue(); _legacyType.small_scenery.scenery_tab_id = 0xFF; GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); @@ -49,9 +49,9 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre rct_object_entry sgEntry = stream->ReadValue(); SetPrimarySceneryGroup(&sgEntry); - if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) + if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS) { - _var10data = ReadVar10(stream); + _frameOffsets = ReadFrameOffsets(stream); } GetImageTable()->Read(context, stream); @@ -80,9 +80,9 @@ void SmallSceneryObject::Load() _legacyType.small_scenery.scenery_tab_id = 0xFF; - if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) + if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS) { - _legacyType.small_scenery.var_10 = _var10data; + _legacyType.small_scenery.frame_offsets = _frameOffsets; } } @@ -141,15 +141,15 @@ void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint } } -uint8 * SmallSceneryObject::ReadVar10(IStream * stream) +uint8 * SmallSceneryObject::ReadFrameOffsets(IStream * stream) { - uint8 b; + uint8 frameOffset; auto data = std::vector(); data.push_back(stream->ReadValue()); - while ((b = stream->ReadValue()) != 0xFF) + while ((frameOffset = stream->ReadValue()) != 0xFF) { - data.push_back(b); + data.push_back(frameOffset); } - data.push_back(b); + data.push_back(frameOffset); return Memory::Duplicate(data.data(), data.size()); } diff --git a/src/openrct2/object/SmallSceneryObject.h b/src/openrct2/object/SmallSceneryObject.h index 754a0b6189..aa2c5c2a49 100644 --- a/src/openrct2/object/SmallSceneryObject.h +++ b/src/openrct2/object/SmallSceneryObject.h @@ -27,7 +27,7 @@ class SmallSceneryObject final : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; - uint8 * _var10data = nullptr; + uint8 * _frameOffsets = nullptr; public: explicit SmallSceneryObject(const rct_object_entry &entry) : SceneryObject(entry) { } @@ -42,5 +42,5 @@ public: void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; private: - static uint8 * ReadVar10(IStream * stream); + static uint8 * ReadFrameOffsets(IStream * stream); }; diff --git a/src/openrct2/paint/map_element/scenery.c b/src/openrct2/paint/map_element/scenery.c index c2376696af..d2a50d8a1b 100644 --- a/src/openrct2/paint/map_element/scenery.c +++ b/src/openrct2/paint/map_element/scenery.c @@ -70,7 +70,7 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) sint8 x_offset = 0; sint8 y_offset = 0; if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) { - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG24) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_HALF_SPACE) { // 6DFFE3: boxoffset.x = offsets[direction].x; boxoffset.y = offsets[direction].y; @@ -109,7 +109,7 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) if (boxlength.z > 128 || boxlength.z < 0) { boxlength.z = 128; } - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG6) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_WITHER) { if (mapElement->properties.scenery.age >= 40) { baseImageid += 4; } @@ -126,7 +126,7 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) if (dword_F64EB0 != 0) { baseImageid = (baseImageid & 0x7FFFF) | dword_F64EB0; } - if (!(entry->small_scenery.flags & SMALL_SCENERY_FLAG21)) { + if (!(entry->small_scenery.flags & SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED)) { sub_98197C(baseImageid, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); } @@ -141,9 +141,9 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED) { rct_drawpixelinfo* dpi = unk_140E9A8; - if ( (entry->small_scenery.flags & SMALL_SCENERY_FLAG21) || (dpi->zoom_level <= 1) ) { + if ( (entry->small_scenery.flags & SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED) || (dpi->zoom_level <= 1) ) { // 6E01A9: - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG12) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1) { // 6E0512: sint32 image_id = ((gCurrentTicks / 2) & 0xF) + entry->image + 4; if (dword_F64EB0 != 0) { @@ -151,7 +151,7 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) } sub_98199C(image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); } else - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG13) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4) { // 6E043B: sint32 image_id = ((gCurrentTicks / 2) & 0xF) + entry->image + 8; if (dword_F64EB0 != 0) { @@ -203,7 +203,7 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) } sub_98199C(image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); } else - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG15) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_SWAMP_GOO) { // 6E02F6: sint32 image_id = gCurrentTicks; image_id += gUnk9DE568 / 4; @@ -214,27 +214,25 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) image_id = (image_id & 0x7FFFF) | dword_F64EB0; } sub_98199C(image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); - } else { - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG16) { - // nothing - } - sint32 esi = gCurrentTicks; - if (!(entry->small_scenery.flags & SMALL_SCENERY_FLAG22)) { + } + else if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS) + { + sint32 frame = gCurrentTicks; + if (!(entry->small_scenery.flags & SMALL_SCENERY_FLAG_COG)) { // 6E01F8: - esi += ((gUnk9DE568 / 4) + (gUnk9DE56C / 4)); - esi += (mapElement->type & 0xC0) / 16; + frame += ((gUnk9DE568 / 4) + (gUnk9DE56C / 4)); + frame += (mapElement->type & 0xC0) / 16; } // 6E0222: - uint16 cx = entry->small_scenery.var_14; - uint8 cl = cx & 0xFF; - esi >>= cl; - esi &= entry->small_scenery.var_16; + uint16 delay = entry->small_scenery.animation_delay & 0xFF; + frame >>= delay; + frame &= entry->small_scenery.animation_mask; sint32 image_id = 0; - if (esi < entry->small_scenery.var_18) { - image_id = entry->small_scenery.var_10[esi]; + if (frame < entry->small_scenery.num_frames) { + image_id = entry->small_scenery.frame_offsets[frame]; } image_id = (image_id * 4) + direction + entry->image; - if (entry->small_scenery.flags & (SMALL_SCENERY_FLAG21 | SMALL_SCENERY_FLAG17)) { + if (entry->small_scenery.flags & (SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED | SMALL_SCENERY_FLAG17)) { image_id += 4; } if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) { @@ -246,9 +244,10 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) if (dword_F64EB0 != 0) { image_id = (image_id & 0x7FFFF) | dword_F64EB0; } - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG21) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED) { sub_98197C(image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); - } else { + } + else { sub_98199C(image_id, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, rotation); } } @@ -279,13 +278,10 @@ void scenery_paint(uint8 direction, sint32 height, rct_map_element* mapElement) } // 6E05D1: height += entry->small_scenery.height; - uint16 word_F64F2A = height; - height += 7; - height &= 0xFFF8; - paint_util_set_general_support_height(height, 0x20); + + paint_util_set_general_support_height(ceil2(height, 8), 0x20); // 6E05FF: - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG23) { - height = word_F64F2A; + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP) { if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) { // 6E0825: paint_util_set_segment_support_height(SEGMENT_C4, height, 0x20); diff --git a/src/openrct2/paint/map_element/scenery_multiple.c b/src/openrct2/paint/map_element/scenery_multiple.c index 64a26dbd27..973ec0c48c 100644 --- a/src/openrct2/paint/map_element/scenery_multiple.c +++ b/src/openrct2/paint/map_element/scenery_multiple.c @@ -231,7 +231,7 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map boxlength.y = s98E3C4[esi].length.y; boxlength.z = ah; sub_98197C(image_id, 0, 0, boxlength.x, boxlength.y, ah, height, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); - if (entry->large_scenery.var_11 == 0xFF || direction == 1 || direction == 2) { + if (entry->large_scenery.scrolling_mode == 0xFF || direction == 1 || direction == 2) { scenery_multiple_paint_supports(direction, height, mapElement, dword_F4387C, tile); return; } @@ -347,7 +347,7 @@ void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *map // 6B809A: set_format_arg(7, uint8, textColour); uint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); - uint16 scrollMode = entry->large_scenery.var_11 + ((direction + 1) & 0x3); + uint16 scrollMode = entry->large_scenery.scrolling_mode + ((direction + 1) & 0x3); rct_banner *banner = &gBanners[bannerIndex]; set_format_arg(0, rct_string_id, banner->string_idx); if (banner->flags & BANNER_FLAG_LINKED_TO_RIDE) { diff --git a/src/openrct2/peep/peep.c b/src/openrct2/peep/peep.c index 854f7ba52b..f115437835 100644 --- a/src/openrct2/peep/peep.c +++ b/src/openrct2/peep/peep.c @@ -11455,7 +11455,7 @@ static bool peep_find_ride_to_look_at(rct_peep *peep, uint8 edge, uint8 *rideToV } if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { - if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG5)) { + if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG_PHOTOGENIC)) { continue; } @@ -11539,7 +11539,7 @@ static bool peep_find_ride_to_look_at(rct_peep *peep, uint8 edge, uint8 *rideToV } if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { - if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG5)) { + if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG_PHOTOGENIC)) { continue; } @@ -11622,7 +11622,7 @@ static bool peep_find_ride_to_look_at(rct_peep *peep, uint8 edge, uint8 *rideToV } if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { - if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG5)) { + if (!(get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF)->large_scenery.flags & LARGE_SCENERY_FLAG_PHOTOGENIC)) { continue; } diff --git a/src/openrct2/ride/track_design.c b/src/openrct2/ride/track_design.c index f34f556cd1..f9a2c47c82 100644 --- a/src/openrct2/ride/track_design.c +++ b/src/openrct2/ride/track_design.c @@ -416,7 +416,7 @@ static void track_design_mirror_scenery(rct_track_td6 *td6) case OBJECT_TYPE_SMALL_SCENERY: scenery->y = -scenery->y; - if (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9) { + if (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_DIAGONAL) { scenery->flags ^= (1 << 0); if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)) { scenery->flags ^= (1 << 2); @@ -654,8 +654,8 @@ static sint32 track_design_place_scenery(rct_td6_scenery_element *scenery_start, rct_scenery_entry* small_scenery = get_small_scenery_entry(entry_index); if (!(!(small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) && - (small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG9)) && - (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25))) + (small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG_DIAGONAL)) && + (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS))) { bh &= 0x3F; } diff --git a/src/openrct2/windows/sign.c b/src/openrct2/windows/sign.c index db053f5c40..e10e53ebe2 100644 --- a/src/openrct2/windows/sign.c +++ b/src/openrct2/windows/sign.c @@ -168,7 +168,7 @@ void window_sign_open(rct_windownumber number) while (1){ if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { rct_scenery_entry* scenery_entry = get_large_scenery_entry(map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK); - if (scenery_entry->large_scenery.var_11 != 0xFF){ + if (scenery_entry->large_scenery.scrolling_mode != 0xFF){ sint32 id = (map_element->type & 0xC0) | ((map_element->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((map_element->properties.scenerymultiple.colour[1] & 0xE0) >> 5); @@ -231,7 +231,7 @@ static void window_sign_mouseup(rct_window *w, rct_widgetindex widgetIndex) while (1){ if (map_element_get_type(map_element) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { rct_scenery_entry* scenery_entry = get_large_scenery_entry(map_element->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK); - if (scenery_entry->large_scenery.var_11 != 0xFF){ + if (scenery_entry->large_scenery.scrolling_mode != 0xFF){ sint32 id = (map_element->type & 0xC0) | ((map_element->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((map_element->properties.scenerymultiple.colour[1] & 0xE0) >> 5); diff --git a/src/openrct2/windows/tile_inspector.c b/src/openrct2/windows/tile_inspector.c index 06d5ff0607..991b574f20 100644 --- a/src/openrct2/windows/tile_inspector.c +++ b/src/openrct2/windows/tile_inspector.c @@ -1882,7 +1882,7 @@ static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi) // Banner info rct_scenery_entry *largeSceneryEntry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & MAP_ELEMENT_LARGE_TYPE_MASK); - if (largeSceneryEntry->large_scenery.var_11 != 0xFF) { + if (largeSceneryEntry->large_scenery.scrolling_mode != 0xFF) { const sint32 bannerIndex = (mapElement->type & 0xC0) | ((mapElement->properties.scenerymultiple.colour[0] & 0xE0) >> 2) | ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); diff --git a/src/openrct2/world/SmallScenery.cpp b/src/openrct2/world/SmallScenery.cpp new file mode 100644 index 0000000000..281fc6db04 --- /dev/null +++ b/src/openrct2/world/SmallScenery.cpp @@ -0,0 +1,565 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* OpenRCT2 is the work of many authors, a full list can be found in contributors.md +* For more information, visit https://github.com/OpenRCT2/OpenRCT2 +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* A full copy of the GNU General Public License can be found in licence.txt +*****************************************************************************/ +#pragma endregion + +#include "../network/network.h" + +#include "../rct2.h" +#include "../network/network.h" + +extern "C" +{ + #include "footpath.h" + #include "scenery.h" + #include "map.h" + #include "park.h" + #include "../cheats.h" + #include "../ride/track_design.h" +} + +static money32 SmallSceneryRemove(sint16 x, sint16 y, sint8 baseHeight, uint8 quadrant, uint8 sceneryType, uint8 flags) +{ + if (!map_is_location_valid(x, y)) + { + return MONEY32_UNDEFINED; + } + money32 cost; + + rct_scenery_entry *entry = get_small_scenery_entry(sceneryType); + if (entry == (rct_scenery_entry *)-1) + { + log_warning("Invalid game command for scenery removal, scenery_type = %u", sceneryType); + return MONEY32_UNDEFINED; + } + cost = entry->small_scenery.removal_price * 10; + + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + gCommandPosition.x = x + 16; + gCommandPosition.y = y + 16; + gCommandPosition.z = baseHeight * 8; + + if (!(flags & GAME_COMMAND_FLAG_GHOST) && + game_is_paused() && + !gCheatsBuildInPauseMode) + { + gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && + !(flags & GAME_COMMAND_FLAG_GHOST) && + !gCheatsSandboxMode) + { + // Check if allowed to remove item + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + if (entry->small_scenery.height > 64) + { + gGameCommandErrorText = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + return MONEY32_UNDEFINED; + } + } + + // Check if the land is owned + if (!map_is_location_owned(x, y, gCommandPosition.z)) + { + return MONEY32_UNDEFINED; + } + } + + bool sceneryFound = false; + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if ((mapElement->type >> 6) != quadrant) + continue; + if (mapElement->base_height != baseHeight) + continue; + if (mapElement->properties.scenery.type != sceneryType) + continue; + if ((flags & GAME_COMMAND_FLAG_GHOST) && + !(mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + + sceneryFound = true; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (sceneryFound == false) + { + return 0; + } + + // Remove element + if (flags & GAME_COMMAND_FLAG_APPLY) + { + if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) + { + rct_xyz16 coord; + coord.x = x + 16; + coord.y = y + 16; + coord.z = map_element_height(coord.x, coord.y); + network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); + } + + map_invalidate_tile_full(x, y); + map_element_remove(mapElement); + } + return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost; +} + +static money32 SmallScenerySetColour(sint16 x, sint16 y, sint8 baseHeight, uint8 quadrant, uint8 sceneryType, uint8 primaryColour, uint8 secondaryColour, uint8 flags) +{ + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + sint32 z = baseHeight * 8; + gCommandPosition.x = x + 16; + gCommandPosition.y = y + 16; + gCommandPosition.z = z; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) + { + if (!map_is_location_owned(x, y, z)) + { + return MONEY32_UNDEFINED; + } + } + + rct_map_element *mapElement = map_get_small_scenery_element_at(x, y, baseHeight, sceneryType, quadrant); + + if (mapElement == NULL) + { + return 0; + } + + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) + { + return 0; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + { + mapElement->properties.scenery.colour_1 &= 0xE0; + mapElement->properties.scenery.colour_1 |= primaryColour; + mapElement->properties.scenery.colour_2 &= 0xE0; + mapElement->properties.scenery.colour_2 |= secondaryColour; + map_invalidate_tile_full(x, y); + } + + return 0; +} + +static money32 SmallSceneryPlace(sint16 x, + sint16 y, + sint16 targetHeight, + uint8 quadrant, + uint8 rotation, + uint8 sceneryType, + uint8 primaryColour, + uint8 secondaryColour, + uint8 flags) +{ + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + + money32 clearCost = 0; + bool isOnWater = false; + bool supportsRequired = false; + if (targetHeight != 0) + { + supportsRequired = true; + } + sint32 baseHeight = map_element_height(x, y); + // If on water + if (baseHeight & 0xFFFF0000) + { + baseHeight >>= 16; + } + gCommandPosition.x = x; + gCommandPosition.y = y; + gCommandPosition.z = baseHeight; + if (targetHeight != 0) + { + baseHeight = targetHeight; + gCommandPosition.z = baseHeight; + } + gCommandPosition.x += 16; + gCommandPosition.y += 16; + + if (game_is_paused() && !gCheatsBuildInPauseMode) + { + gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + return MONEY32_UNDEFINED; + } + + if (!map_check_free_elements_and_reorganise(1)) + { + return MONEY32_UNDEFINED; + } + + if (!byte_9D8150 && (x > gMapSizeMaxXY || y > gMapSizeMaxXY)) + { + return MONEY32_UNDEFINED; + } + + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(sceneryType); + if (sceneryEntry == NULL) + { + return MONEY32_UNDEFINED; + } + + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE || + !(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_DIAGONAL)) + { + if (sceneryEntry->small_scenery.flags & + (SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS)) + { + quadrant = 0; + } + } + + // Check if sub tile height is any different compared to actual surface tile height + sint32 x2 = x; + sint32 y2 = y; + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) + { + x2 += 16; + y2 += 16; + } + else + { + x2 += ScenerySubTileOffsets[quadrant & 3].x - 1; + y2 += ScenerySubTileOffsets[quadrant & 3].y - 1; + } + baseHeight = map_element_height(x2, y2); + // If on water + if (baseHeight & 0xFFFF0000) + { + // base_height2 is now the water height + baseHeight >>= 16; + if (targetHeight == 0) + { + isOnWater = true; + } + } + if (targetHeight == 0) + { + targetHeight = baseHeight; + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && + !gCheatsSandboxMode && + !map_is_location_owned(x, y, targetHeight)) + { + + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY && !(flags & GAME_COMMAND_FLAG_GHOST)) + { + footpath_remove_litter(x, y, targetHeight); + if (!gCheatsDisableClearanceChecks && (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS)) + { + wall_remove_at(x, y, targetHeight, targetHeight + sceneryEntry->small_scenery.height); + } + } + + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + + if (!gCheatsDisableClearanceChecks && (surfaceElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK)) + { + sint32 water_height = ((surfaceElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16) - 1; + if (water_height > targetHeight) + { + gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + } + + if (!gCheatsDisableClearanceChecks && !(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_STACKABLE)) + { + if (isOnWater) + { + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + return MONEY32_UNDEFINED; + } + + if (surfaceElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) + { + if (((surfaceElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16) > targetHeight) + { + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + return MONEY32_UNDEFINED; + } + } + } + + if (!gCheatsDisableClearanceChecks && + (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) && + !supportsRequired && + !isOnWater && + (surfaceElement->properties.surface.slope & 0x1F)) + { + + gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; + return MONEY32_UNDEFINED; + } + + if (!gCheatsDisableSupportLimits && + !(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_STACKABLE) && + supportsRequired) + { + + if (!isOnWater) + { + if ((surfaceElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) || + (surfaceElement->base_height * 8) != targetHeight) + { + + gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; + return MONEY32_UNDEFINED; + } + + } + else + { + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; + return MONEY32_UNDEFINED; + } + } + + sint32 zLow = targetHeight / 8; + sint32 zHigh = zLow + ceil2(sceneryEntry->small_scenery.height, 8) / 8; + uint8 collisionQuadrants = 0xF; + uint8 blSupports = 0; + if (!(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)) + { + collisionQuadrants = 1 << (quadrant ^ 2); + } + if (!(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HALF_SPACE)) + { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_DIAGONAL && + sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) + { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_THREE_QUARTERS) + { + collisionQuadrants = 0xF & rol8(0xBB, ((quadrant ^ 2) + rotation) & 3); + } + else + { + collisionQuadrants = 0xA >> ((quadrant + rotation) & 1); + } + } + } + else + { + collisionQuadrants = 0xF & rol8(0x33, ((quadrant ^ 2) + rotation) & 3); + } + if (!supportsRequired) + { + blSupports |= 0xF0; + } + + if (!gCheatsDisableClearanceChecks && + !map_can_construct_with_clear_at( + x, + y, + zLow, + zHigh, + &map_place_scenery_clear_func, + blSupports | collisionQuadrants, + flags, + &clearCost)) + { + return MONEY32_UNDEFINED; + } + + gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); + + money32 cost = (sceneryEntry->small_scenery.price * 10) + clearCost; + if (gParkFlags & PARK_FLAGS_NO_MONEY) + { + cost = 0; + } + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + { + return cost; + } + + if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) + { + rct_xyz16 coord; + coord.x = x + 16; + coord.y = y + 16; + coord.z = map_element_height(coord.x, coord.y); + network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); + } + + rct_map_element* newElement = map_element_insert(x / 32, y / 32, zLow, collisionQuadrants); + assert(newElement != NULL); + gSceneryMapElement = newElement; + uint8 type = quadrant << 6; + type |= MAP_ELEMENT_TYPE_SCENERY; + type |= rotation; + newElement->type = type; + newElement->properties.scenery.type = sceneryType; + newElement->properties.scenery.age = 0; + newElement->properties.scenery.colour_1 = primaryColour; + newElement->properties.scenery.colour_2 = secondaryColour; + newElement->clearance_height = newElement->base_height + ((sceneryEntry->small_scenery.height + 7) / 8); + + if (supportsRequired) + { + newElement->properties.scenery.colour_1 |= 0x20; + } + + if (flags & GAME_COMMAND_FLAG_GHOST) + { + newElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + map_invalidate_tile_full(x, y); + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED) + { + map_animation_create(2, x, y, newElement->base_height); + } + + return cost; +} + +extern "C" +{ + /** + * + * rct2: 0x006E0E01 + */ + void game_command_remove_scenery(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) + { + *ebx = SmallSceneryRemove( + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + ((*ebx >> 8) & 0xFF) >> 6, + (*edx >> 8) & 0xFF, + *ebx & 0xFF + ); + } + + /** + * + * rct2: 0x006E0F26 + */ + void game_command_set_scenery_colour(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) + { + *ebx = SmallScenerySetColour( + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + ((*ebx >> 8) & 0xFF) >> 6, + (*edx >> 8) & 0xFF, + *ebp & 0xFF, + (*ebp >> 8) & 0xFF, + *ebx & 0xFF + ); + } + + /** + * + * rct2: 0x006E0D6E, 0x006B8D88 + */ + sint32 map_place_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price) + { + if (map_element_get_type(*map_element) != MAP_ELEMENT_TYPE_SCENERY) + return 1; + + if (!(flags & GAME_COMMAND_FLAG_PATH_SCENERY)) + return 1; + + rct_scenery_entry* scenery = get_small_scenery_entry((*map_element)->properties.scenery.type); + + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + if (scenery->small_scenery.height > 64) + return 1; + } + + if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) + *price += scenery->small_scenery.removal_price * 10; + + if (flags & GAME_COMMAND_FLAG_GHOST) + return 0; + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + return 0; + + map_invalidate_tile(x, y, (*map_element)->base_height * 8, (*map_element)->clearance_height * 8); + + map_element_remove(*map_element); + + (*map_element)--; + return 0; + } + + /** + * + * rct2: 0x006C5A4F, 0x006CDE57, 0x006A6733, 0x0066637E + */ + sint32 map_place_non_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price) + { + if (map_element_get_type(*map_element) != MAP_ELEMENT_TYPE_SCENERY) + return 1; + + rct_scenery_entry* scenery = get_small_scenery_entry((*map_element)->properties.scenery.type); + + if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) + { + if (scenery->small_scenery.height > 64) + return 1; + } + + if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) + *price += scenery->small_scenery.removal_price * 10; + + if (flags & GAME_COMMAND_FLAG_GHOST) + return 0; + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + return 0; + + map_invalidate_tile(x, y, (*map_element)->base_height * 8, (*map_element)->clearance_height * 8); + + map_element_remove(*map_element); + + (*map_element)--; + return 0; + } + + /** + * + * rct2: 0x006E08F4 + */ + void game_command_place_scenery(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) + { + *ebx = SmallSceneryPlace( + *eax & 0xFFFF, + *ecx & 0xFFFF, + *ebp & 0xFFFF, + *edx & 0xFF, + *edi & 0xFF, + (*ebx >> 8) & 0xFF, + (*edx >> 8) & 0xFF, + (*edi >> 16) & 0xFF, + *ebx & 0xFF + ); + } +} \ No newline at end of file diff --git a/src/openrct2/world/map.c b/src/openrct2/world/map.c index 8df058dd03..000b58d4e6 100644 --- a/src/openrct2/world/map.c +++ b/src/openrct2/world/map.c @@ -846,98 +846,6 @@ bool map_is_location_owned_or_has_rights(sint32 x, sint32 y) return false; } -/** - * - * rct2: 0x006E0E01 - */ -void game_command_remove_scenery(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) -{ - sint32 x = *eax; - sint32 y = *ecx; - if (!map_is_location_valid(x, y)) { - *ebx = MONEY32_UNDEFINED; - return; - } - uint8 base_height = *edx; - uint8 scenery_type = *edx >> 8; - uint8 map_element_type = *ebx >> 8; - uint8 flags = *ebx & 0xFF; - money32 cost; - - rct_scenery_entry *entry = get_small_scenery_entry(scenery_type); - if (entry == (rct_scenery_entry *)-1) - { - log_warning("Invalid game command for scenery removal, scenery_type = %u", scenery_type); - *ebx = MONEY32_UNDEFINED; - return; - } - cost = entry->small_scenery.removal_price * 10; - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = base_height * 8; - - if (!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode) { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) { - // Check if allowed to remove item - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) { - if (entry->small_scenery.height > 64) { - gGameCommandErrorText = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; - *ebx = MONEY32_UNDEFINED; - return; - } - } - - // Check if the land is owned - if (!map_is_location_owned(x, y, gCommandPosition.z)){ - *ebx = MONEY32_UNDEFINED; - return; - } - } - - bool sceneryFound = false; - rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - do { - if (map_element->type != map_element_type) - continue; - if (map_element->base_height != base_height) - continue; - if (map_element->properties.scenery.type != scenery_type) - continue; - if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) - continue; - - sceneryFound = true; - break; - } while (!map_element_is_last_for_tile(map_element++)); - - if (sceneryFound == false) { - *ebx = 0; - return; - } - - // Remove element - if (flags & GAME_COMMAND_FLAG_APPLY) { - if (gGameCommandNestLevel == 1 && !(*ebx & GAME_COMMAND_FLAG_GHOST)) { - rct_xyz16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = map_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - map_invalidate_tile_full(x, y); - map_element_remove(map_element); - } - *ebx = (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost; -} - /** * * rct2: 0x006B8E1B @@ -1091,57 +999,6 @@ void game_command_remove_large_scenery(sint32* eax, sint32* ebx, sint32* ecx, si return; } -/** - * - * rct2: 0x006E0F26 - */ -void game_command_set_scenery_colour(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - sint32 x = *eax; - sint32 y = *ecx; - uint8 base_height = *edx; - uint8 scenery_type = *edx >> 8; - uint8 colour1 = *ebp; - uint8 colour2 = *ebp >> 8; - uint8 flags = *ebx & 0xFF; - // Note this function is passed type. - uint8 quadrant = ((*ebx >> 8) & 0xFF) >> 6; - sint32 z = base_height * 8; - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = z; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode){ - if (!map_is_location_owned(x, y, z)){ - *ebx = MONEY32_UNDEFINED; - return; - } - } - - rct_map_element *map_element = map_get_small_scenery_element_at(x, y, base_height, scenery_type, quadrant); - - if (map_element == NULL) { - *ebx = 0; - return; - } - - if((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ - *ebx = 0; - return; - } - - if(flags & GAME_COMMAND_FLAG_APPLY){ - map_element->properties.scenery.colour_1 &= 0xE0; - map_element->properties.scenery.colour_1 |= colour1; - map_element->properties.scenery.colour_2 &= 0xE0; - map_element->properties.scenery.colour_2 |= colour2; - map_invalidate_tile_full(x, y); - } - - *ebx = 0; -} - /** * * rct2: 0x006B909A @@ -2629,308 +2486,6 @@ void game_command_set_water_height(sint32* eax, sint32* ebx, sint32* ecx, sint32 } } -/** - * - * rct2: 0x006E0D6E, 0x006B8D88 - */ -static sint32 map_place_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price) { - if (map_element_get_type(*map_element) != MAP_ELEMENT_TYPE_SCENERY) - return 1; - - if (!(flags & GAME_COMMAND_FLAG_PATH_SCENERY)) - return 1; - - rct_scenery_entry* scenery = get_small_scenery_entry((*map_element)->properties.scenery.type); - - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) { - if (scenery->small_scenery.height > 64) - return 1; - } - - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) - *price += scenery->small_scenery.removal_price * 10; - - if (flags & GAME_COMMAND_FLAG_GHOST) - return 0; - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) - return 0; - - map_invalidate_tile(x, y, (*map_element)->base_height * 8, (*map_element)->clearance_height * 8); - - map_element_remove(*map_element); - - (*map_element)--; - return 0; -} - -/** - * - * rct2: 0x006C5A4F, 0x006CDE57, 0x006A6733, 0x0066637E - */ -sint32 map_place_non_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price) { - if (map_element_get_type(*map_element) != MAP_ELEMENT_TYPE_SCENERY) - return 1; - - rct_scenery_entry* scenery = get_small_scenery_entry((*map_element)->properties.scenery.type); - - if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL) { - if (scenery->small_scenery.height > 64) - return 1; - } - - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) - *price += scenery->small_scenery.removal_price * 10; - - if (flags & GAME_COMMAND_FLAG_GHOST) - return 0; - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) - return 0; - - map_invalidate_tile(x, y, (*map_element)->base_height * 8, (*map_element)->clearance_height * 8); - - map_element_remove(*map_element); - - (*map_element)--; - return 0; -} - -/** - * - * rct2: 0x006E08F4 - */ -void game_command_place_scenery(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - sint32 x = (uint16)*eax; - sint32 y = (uint16)*ecx; - uint8 colour2 = *edi >> 16; - uint8 rotation = *edi; - uint8 scenery_type = *ebx >> 8; - uint8 flags = *ebx & 0xFF; - uint8 quadrant = *edx; - uint8 colour1 = *edx >> 8; - money32 clearCost = 0; - bool isOnWater = false; - sint32 targetHeight = *ebp; - bool supportsRequired = false; - if (targetHeight != 0) { - supportsRequired = true; - } - sint32 base_height = map_element_height(x, y); - // If on water - if(base_height & 0xFFFF0000){ - base_height >>= 16; - } - gCommandPosition.x = x; - gCommandPosition.y = y; - gCommandPosition.z = base_height; - if(targetHeight != 0){ - base_height = targetHeight; - gCommandPosition.z = base_height; - } - gCommandPosition.x += 16; - gCommandPosition.y += 16; - - if (game_is_paused() && !gCheatsBuildInPauseMode) { - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!map_check_free_elements_and_reorganise(1)) { - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!byte_9D8150 && (x > gMapSizeMaxXY || y > gMapSizeMaxXY)) { - *ebx = MONEY32_UNDEFINED; - return; - } - - rct_scenery_entry* scenery_entry = get_small_scenery_entry(scenery_type); - if (scenery_entry == NULL) { - *ebx = MONEY32_UNDEFINED; - return; - } - - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE || !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9)){ - if(scenery_entry->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ - quadrant = 0; - } - } - - // Check if sub tile height is any different compared to actual surface tile height - sint32 x2 = x; - sint32 y2 = y; - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ - x2 += 16; - y2 += 16; - }else{ - x2 += ScenerySubTileOffsets[quadrant & 3].x - 1; - y2 += ScenerySubTileOffsets[quadrant & 3].y - 1; - } - base_height = map_element_height(x2, y2); - // If on water - if(base_height & 0xFFFF0000){ - // base_height2 is now the water height - base_height >>= 16; - if(targetHeight == 0){ - isOnWater = true; - } - } - if(targetHeight == 0){ - targetHeight = base_height; - } - - if(!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && - !gCheatsSandboxMode && - !map_is_location_owned(x, y, targetHeight)){ - - *ebx = MONEY32_UNDEFINED; - return; - } - - if(flags & GAME_COMMAND_FLAG_APPLY && !(flags & GAME_COMMAND_FLAG_GHOST)){ - footpath_remove_litter(x, y, targetHeight); - if(!gCheatsDisableClearanceChecks && (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS)) { - wall_remove_at(x, y, targetHeight, targetHeight + scenery_entry->small_scenery.height); - } - } - - rct_map_element* surface_element = map_get_surface_element_at(x / 32, y / 32); - - if(!gCheatsDisableClearanceChecks && (surface_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK)){ - sint32 water_height = ((surface_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16) - 1; - if(water_height > targetHeight){ - gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; - *ebx = MONEY32_UNDEFINED; - return; - } - } - - if(!gCheatsDisableClearanceChecks && !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_STACKABLE)){ - if(isOnWater){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - *ebx = MONEY32_UNDEFINED; - return; - } - - if(surface_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ - if(((surface_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 16) > targetHeight){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - *ebx = MONEY32_UNDEFINED; - return; - } - } - } - - if (!gCheatsDisableClearanceChecks && - (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) && - !supportsRequired && - !isOnWater && - (surface_element->properties.surface.slope & 0x1F)) { - - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!gCheatsDisableSupportLimits && - !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_STACKABLE) && - supportsRequired) { - - if(!isOnWater){ - if((surface_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) || - (surface_element->base_height * 8) != targetHeight){ - - gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED; - *ebx = MONEY32_UNDEFINED; - return; - } - - }else{ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ON_LAND; - *ebx = MONEY32_UNDEFINED; - return; - } - } - - sint32 zLow = targetHeight / 8; - sint32 zHigh = zLow + ceil2(scenery_entry->small_scenery.height, 8) / 8; - uint8 collisionQuadrants = 0xF; - uint8 unk_bl = 0; - if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ - collisionQuadrants = 1 << (quadrant ^ 2); - } - if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG24)){ - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9 && scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){ - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG25){ - collisionQuadrants = 0xF & rol8(0xBB, ((quadrant ^ 2) + rotation) & 3); - }else{ - collisionQuadrants = 0xA >> ((quadrant + rotation) & 1); - } - } - }else{ - collisionQuadrants = 0xF & rol8(0x33, ((quadrant ^ 2) + rotation) & 3); - } - if(!supportsRequired){ - unk_bl |= 0xF0; - } - - if (!gCheatsDisableClearanceChecks && - !map_can_construct_with_clear_at(x, y, zLow, zHigh, &map_place_scenery_clear_func, unk_bl | collisionQuadrants, flags, &clearCost)) { - *ebx = MONEY32_UNDEFINED; - return; - } - - gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_ABOVE_GROUND | ELEMENT_IS_UNDERGROUND); - - *ebx = (scenery_entry->small_scenery.price * 10) + clearCost; - if(gParkFlags & PARK_FLAGS_NO_MONEY){ - *ebx = 0; - } - - if (!(flags & GAME_COMMAND_FLAG_APPLY)) { - return; - } - - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) { - rct_xyz16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = map_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - rct_map_element* new_map_element = map_element_insert(x / 32, y / 32, zLow, collisionQuadrants); - assert(new_map_element != NULL); - gSceneryMapElement = new_map_element; - uint8 type = quadrant << 6; - type |= MAP_ELEMENT_TYPE_SCENERY; - type |= rotation; - new_map_element->type = type; - new_map_element->properties.scenery.type = scenery_type; - new_map_element->properties.scenery.age = 0; - new_map_element->properties.scenery.colour_1 = colour1; - new_map_element->properties.scenery.colour_2 = colour2; - new_map_element->clearance_height = new_map_element->base_height + ((scenery_entry->small_scenery.height + 7) / 8); - - if(supportsRequired){ - new_map_element->properties.scenery.colour_1 |= 0x20; - } - - if(flags & GAME_COMMAND_FLAG_GHOST){ - new_map_element->flags |= MAP_ELEMENT_FLAG_GHOST; - } - - map_invalidate_tile_full(x, y); - if(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED){ - map_animation_create(2, x, y, new_map_element->base_height); - } -} - bool map_is_location_at_edge(sint32 x, sint32 y) { return x < 32 || y < 32 || x >= ((MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32) || y >= ((MAXIMUM_MAP_SIZE_TECHNICAL - 1) * 32); @@ -2979,7 +2534,7 @@ void game_command_place_large_scenery(sint32* eax, sint32* ebx, sint32* ecx, sin *ebx = MONEY32_UNDEFINED; return; } - if(scenery_entry->large_scenery.var_11 != 0xFF){ + if(scenery_entry->large_scenery.scrolling_mode != 0xFF){ banner_id = create_new_banner(flags); if (banner_id == MAX_BANNERS) { @@ -3773,7 +3328,7 @@ sint32 map_element_get_banner_index(rct_map_element *mapElement) switch (map_element_get_type(mapElement)) { case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: sceneryEntry = get_large_scenery_entry(mapElement->properties.scenerymultiple.type & 0x3FF); - if (sceneryEntry->large_scenery.var_11 == 0xFF) + if (sceneryEntry->large_scenery.scrolling_mode == 0xFF) return -1; return diff --git a/src/openrct2/world/map.h b/src/openrct2/world/map.h index cf47e4f9c8..ee32cfccf8 100644 --- a/src/openrct2/world/map.h +++ b/src/openrct2/world/map.h @@ -452,6 +452,7 @@ bool map_element_check_address(const rct_map_element * const element); typedef sint32 (CLEAR_FUNC)(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price); sint32 map_place_non_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price); +sint32 map_place_scenery_clear_func(rct_map_element** map_element, sint32 x, sint32 y, uint8 flags, money32* price); sint32 map_can_construct_with_clear_at(sint32 x, sint32 y, sint32 zLow, sint32 zHigh, CLEAR_FUNC *clearFunc, uint8 bl, uint8 flags, money32 *price); sint32 map_can_construct_at(sint32 x, sint32 y, sint32 zLow, sint32 zHigh, uint8 bl); void rotate_map_coordinates(sint16 *x, sint16 *y, sint32 rotation); diff --git a/src/openrct2/world/map_animation.c b/src/openrct2/world/map_animation.c index cc4249071c..3575fe4da9 100644 --- a/src/openrct2/world/map_animation.c +++ b/src/openrct2/world/map_animation.c @@ -184,7 +184,7 @@ static bool map_animation_invalidate_small_scenery(sint32 x, sint32 y, sint32 ba continue; sceneryEntry = get_small_scenery_entry(mapElement->properties.scenery.type); - if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG12 | SMALL_SCENERY_FLAG13 | SMALL_SCENERY_FLAG15 | SMALL_SCENERY_FLAG16)) { + if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 | SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 | SMALL_SCENERY_FLAG_SWAMP_GOO | SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS)) { map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); return false; } diff --git a/src/openrct2/world/scenery.h b/src/openrct2/world/scenery.h index 4c679482b7..c745b4b877 100644 --- a/src/openrct2/world/scenery.h +++ b/src/openrct2/world/scenery.h @@ -39,10 +39,10 @@ typedef struct rct_small_scenery_entry { uint8 tool_id; // 0x0B sint16 price; // 0x0C sint16 removal_price; // 0x0E - uint8 *var_10; - uint16 var_14; - uint16 var_16; - uint16 var_18; + uint8 *frame_offsets; // 0x10 + uint16 animation_delay; // 0x14 + uint16 animation_mask; // 0x16 + uint16 num_frames; // 0x18 uint8 scenery_tab_id; // 0x1A } rct_small_scenery_entry; #ifdef PLATFORM_32BIT @@ -55,27 +55,27 @@ typedef enum { SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE = (1 << 2), // 0x4 SMALL_SCENERY_FLAG_ROTATABLE = (1 << 3), // 0x8; when set, user can set rotation, otherwise rotation is automatic SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10 - SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20 + SMALL_SCENERY_FLAG_CAN_WITHER = (1 << 5), // 0x20 SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40 SMALL_SCENERY_FLAG_ANIMATED_FG = (1 << 7), // 0x80 - SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100 + SMALL_SCENERY_FLAG_DIAGONAL = (1 << 8), // 0x100 SMALL_SCENERY_FLAG_HAS_GLASS = (1 << 9), // 0x200 SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400 - SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800 - SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000 + SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 = (1 << 11), // 0x800 + SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 = (1 << 12), // 0x1000 SMALL_SCENERY_FLAG_IS_CLOCK = (1 << 13), // 0x2000 - SMALL_SCENERY_FLAG15 = (1 << 14), // 0x4000 - SMALL_SCENERY_FLAG16 = (1 << 15), // 0x8000 + SMALL_SCENERY_FLAG_SWAMP_GOO = (1 << 14), // 0x4000 + SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS = (1 << 15), // 0x8000 SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000 SMALL_SCENERY_FLAG_STACKABLE = (1 << 17), // 0x20000; means scenery item can be placed in the air and over water SMALL_SCENERY_FLAG_ALLOW_WALLS = (1 << 18), // 0x40000 SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000 SMALL_SCENERY_FLAG_NO_SUPPORTS = (1 << 20), // 0x100000 - SMALL_SCENERY_FLAG21 = (1 << 21), // 0x200000 - SMALL_SCENERY_FLAG22 = (1 << 22), // 0x400000 - SMALL_SCENERY_FLAG23 = (1 << 23), // 0x800000 - SMALL_SCENERY_FLAG24 = (1 << 24), // 0x1000000 - SMALL_SCENERY_FLAG25 = (1 << 25), // 0x2000000 + SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED = (1 << 21), // 0x200000 + SMALL_SCENERY_FLAG_COG = (1 << 22), // 0x400000 + SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP = (1 << 23), // 0x800000 + SMALL_SCENERY_FLAG_HALF_SPACE = (1 << 24), // 0x1000000 + SMALL_SCENERY_FLAG_THREE_QUARTERS = (1 << 25), // 0x2000000 SMALL_SCENERY_FLAG_PAINT_SUPPORTS = (1 << 26), // 0x4000000; used for scenery items which are support structures SMALL_SCENERY_FLAG27 = (1 << 27), // 0x8000000 } SMALL_SCENERY_FLAGS; @@ -113,26 +113,26 @@ typedef enum { } LARGE_SCENERY_TEXT_FLAGS; typedef struct rct_large_scenery_entry { - uint8 tool_id; // 0x06 - uint8 flags; // 0x07 - sint16 price; // 0x08 - sint16 removal_price; // 0x0A + uint8 tool_id; // 0x06 + uint8 flags; // 0x07 + sint16 price; // 0x08 + sint16 removal_price; // 0x0A rct_large_scenery_tile* tiles; // 0x0C - uint8 scenery_tab_id; // 0x10 - uint8 var_11; - rct_large_scenery_text* text; // 0x12 - uint32 text_image; // 0x16 + uint8 scenery_tab_id; // 0x10 + uint8 scrolling_mode; // 0x11 + rct_large_scenery_text* text; // 0x12 + uint32 text_image; // 0x16 } rct_large_scenery_entry; #ifdef PLATFORM_32BIT assert_struct_size(rct_large_scenery_entry, 20); #endif typedef enum { - LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 0), // 0x1 - LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 1), // 0x2 - LARGE_SCENERY_FLAG_3D_TEXT = (1 << 2), // 0x4 - LARGE_SCENERY_FLAG_ANIMATED = (1 << 3), // 0x8 - LARGE_SCENERY_FLAG5 = (1 << 4), // 0x10 + LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 0), // 0x1 + LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 1), // 0x2 + LARGE_SCENERY_FLAG_3D_TEXT = (1 << 2), // 0x4 + LARGE_SCENERY_FLAG_ANIMATED = (1 << 3), // 0x8 + LARGE_SCENERY_FLAG_PHOTOGENIC = (1 << 4), // 0x10 } LARGE_SCENERY_FLAGS; typedef struct rct_wall_scenery_entry {