diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index eae891bf00..5da7cb2bfc 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 85B468FC1D96822F000F1DB5 /* paint_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 85B468FB1D96822F000F1DB5 /* paint_helpers.c */; }; 85B468FD1D96822F000F1DB5 /* paint_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 85B468FB1D96822F000F1DB5 /* paint_helpers.c */; }; 8DED2F20E0D63A1DCFCE0197 /* banner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEAE6E8AC49B6F288E69B40 /* banner.cpp */; }; + B94C3C5FC4DBBB864434DE83 /* Duck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5D1DB5BE280897DCDEBFCED /* Duck.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 */; }; @@ -485,6 +486,7 @@ D4F5B5EF1DAD8A4300AB6075 /* CursorData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4F5B5EC1DAD8A4300AB6075 /* CursorData.cpp */; }; D4F5B5F01DAD8A4300AB6075 /* Cursors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4F5B5ED1DAD8A4300AB6075 /* Cursors.cpp */; }; F2CC500E17C9411FBA859888 /* Climate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 242F470FE91956ACA4078F6A /* Climate.cpp */; }; + F408D5E134FE5B423BE5443F /* Duck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5D1DB5BE280897DCDEBFCED /* Duck.cpp */; }; F61331C839858250899F1E9B /* Balloon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 437490DBD74ECF60C3363559 /* Balloon.cpp */; }; /* End PBXBuildFile section */ @@ -549,6 +551,7 @@ 791166FA1D7486EF005912EA /* NetworkServerAdvertiser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkServerAdvertiser.h; sourceTree = ""; }; 8594C05F1D885CF600235E93 /* track_data_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_data_old.c; sourceTree = ""; }; 85B468FB1D96822F000F1DB5 /* paint_helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paint_helpers.c; sourceTree = ""; }; + A5D1DB5BE280897DCDEBFCED /* Duck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Duck.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; }; @@ -1000,7 +1003,6 @@ D44271DA1CC81B3200D84D28 /* banner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = banner.c; sourceTree = ""; }; D44271D91CC81B3200D84D28 /* balloon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = balloon.c; sourceTree = ""; }; D44271DB1CC81B3200D84D28 /* banner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = banner.h; sourceTree = ""; }; - D44271DE1CC81B3200D84D28 /* duck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = duck.c; sourceTree = ""; }; D44271DF1CC81B3200D84D28 /* entrance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = entrance.h; sourceTree = ""; }; D44271E01CC81B3200D84D28 /* footpath.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = footpath.c; sourceTree = ""; }; D44271E11CC81B3200D84D28 /* footpath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = footpath.h; sourceTree = ""; }; @@ -2046,6 +2048,7 @@ D44271D81CC81B3200D84D28 /* world */ = { isa = PBXGroup; children = ( + A5D1DB5BE280897DCDEBFCED /* Duck.cpp */, EC3C3FED9FA55B65F65D706F /* Climate.h */, 242F470FE91956ACA4078F6A /* Climate.cpp */, 437490DBD74ECF60C3363559 /* Balloon.cpp */, @@ -2702,6 +2705,7 @@ 6876808CD662C4B16392A9B4 /* Balloon.cpp in Sources */, 7D02D519C9A56A1FB9854FE7 /* Climate.cpp in Sources */, 689149B0417A68D6765F09CD /* banner.cpp in Sources */, + F408D5E134FE5B423BE5443F /* Duck.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2727,7 +2731,6 @@ 791166FB1D7486EF005912EA /* NetworkServerAdvertiser.cpp in Sources */, D44272441CC81B3200D84D28 /* cable_lift.c in Sources */, C647C6911E1D0CA000C7FB21 /* AudioMixer.cpp in Sources */, - D442729C1CC81B3200D84D28 /* duck.c in Sources */, C65A88921E1B1148000368D7 /* AudioChannel.cpp in Sources */, C686F91D1CDBC3B7009F9BFC /* multi_dimension_roller_coaster.c in Sources */, C686F8B31CDBC37E009F9BFC /* surface.c in Sources */, @@ -3061,6 +3064,7 @@ F61331C839858250899F1E9B /* Balloon.cpp in Sources */, F2CC500E17C9411FBA859888 /* Climate.cpp in Sources */, 8DED2F20E0D63A1DCFCE0197 /* banner.cpp in Sources */, + B94C3C5FC4DBBB864434DE83 /* Duck.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 448829cc8d..e39e496dfc 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -337,8 +337,8 @@ - + diff --git a/src/openrct2/paint/sprite/misc.c b/src/openrct2/paint/sprite/misc.c index 55c49237a6..7ec2a305a2 100644 --- a/src/openrct2/paint/sprite/misc.c +++ b/src/openrct2/paint/sprite/misc.c @@ -32,7 +32,7 @@ const uint32 vehicle_particle_base_sprites[] = { 22577, 22589, 22601, 22613, 22625 }; -extern const uint8 * duck_animations[]; +extern const uint8 * DuckAnimations[]; /** * rct2: 0x00672AC9 @@ -189,7 +189,7 @@ void misc_paint(rct_sprite *misc, sint32 imageDirection) rct_duck duck = misc->duck; - uint8 imageOffset = duck_animations[duck.state][duck.frame]; + uint8 imageOffset = DuckAnimations[duck.state][duck.frame]; uint32 imageId = 23133 + (imageOffset * 4) + (imageDirection / 8); sub_98196C(imageId, 0, 0, 1, 1, 0, duck.z, get_current_rotation()); break; diff --git a/src/openrct2/ride/vehicle.c b/src/openrct2/ride/vehicle.c index 3b73375a35..7bea98d097 100644 --- a/src/openrct2/ride/vehicle.c +++ b/src/openrct2/ride/vehicle.c @@ -7017,7 +7017,7 @@ static void sub_6DB807(rct_vehicle *vehicle) sprite_move(x, y, z, (rct_sprite*)vehicle); } -extern const rct_xy16 duck_move_offset[4]; +extern const rct_xy16 DuckMoveOffset[4]; /** * Collision Detection @@ -7123,8 +7123,8 @@ static bool vehicle_update_motion_collision_detection( uint32 offsetSpriteDirection = (vehicle->sprite_direction + 4) & 31; uint32 offsetDirection = offsetSpriteDirection >> 3; - uint32 next_x_diff = abs(x + duck_move_offset[offsetDirection].x - collideVehicle->x); - uint32 next_y_diff = abs(y + duck_move_offset[offsetDirection].y - collideVehicle->y); + uint32 next_x_diff = abs(x + DuckMoveOffset[offsetDirection].x - collideVehicle->x); + uint32 next_y_diff = abs(y + DuckMoveOffset[offsetDirection].y - collideVehicle->y); if (next_x_diff + next_y_diff < x_diff + y_diff){ mayCollide = true; diff --git a/src/openrct2/world/Duck.cpp b/src/openrct2/world/Duck.cpp new file mode 100644 index 0000000000..46b8714815 --- /dev/null +++ b/src/openrct2/world/Duck.cpp @@ -0,0 +1,362 @@ +#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 "../core/Util.hpp" + +extern "C" +{ + #include "../audio/audio.h" + #include "../game.h" + #include "../localisation/date.h" + #include "../scenario/scenario.h" + #include "sprite.h" +} + +enum DUCK_STATE +{ + FLY_TO_WATER, + SWIM, + DRINK, + DOUBLE_DRINK, + FLY_AWAY +}; + +static void duck_update_fly_to_water(rct_duck * duck); +static void duck_update_swim(rct_duck * duck); +static void duck_update_drink(rct_duck * duck); +static void duck_update_double_drink(rct_duck * duck); +static void duck_update_fly_away(rct_duck * duck); + +static const rct_xy16 DuckMoveOffset[4] = +{ + { -1, 0 }, + { 0, 1 }, + { 1, 0 }, + { 0, -1 }, +}; + +static const uint8 DuckAnimationFlyToWater[] = +{ + 8, 9, 10, 11, 12, 13 +}; + +static const uint8 DuckAnimationSwim[] = +{ + 0 +}; + +static const uint8 DuckAnimationDrink[] = +{ + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0xFF +}; + +static const uint8 DuckAnimationDoubleDrink[] = +{ + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, + 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 0, 0, 0, 0, 0xFF +}; + +static const uint8 DuckAnimationFlyAway[] = +{ + 8, 9, 10, 11, 12, 13 +}; + +static const uint8 * DuckAnimations[] = +{ + DuckAnimationFlyToWater, // FLY_TO_WATER + DuckAnimationSwim, // SWIM + DuckAnimationDrink, // DRINK + DuckAnimationDoubleDrink, // DOUBLE_DRINK + DuckAnimationFlyAway, // FLY_AWAY +}; + +static void duck_invalidate(rct_duck *duck) +{ + invalidate_sprite_0((rct_sprite *)duck); +} + +static void duck_update_fly_to_water(rct_duck *duck) +{ + if ((gCurrentTicks & 3) != 0) return; + + duck->frame++; + if (duck->frame >= Util::CountOf(DuckAnimationFlyToWater)) + { + duck->frame = 0; + } + + duck_invalidate(duck); + sint32 manhattanDistance = abs(duck->target_x - duck->x) + abs(duck->target_y - duck->y); + sint32 direction = duck->sprite_direction >> 3; + sint32 x = duck->x + DuckMoveOffset[direction].x; + sint32 y = duck->y + DuckMoveOffset[direction].y; + sint32 manhattanDistanceN = abs(duck->target_x - x) + abs(duck->target_y - y); + + rct_map_element * mapElement = map_get_surface_element_at(duck->target_x >> 5, duck->target_y >> 5); + sint32 waterHeight = mapElement->properties.surface.terrain & 0x1F; + if (waterHeight == 0) + { + duck->state = DUCK_STATE::FLY_AWAY; + duck_update_fly_away(duck); + } + else + { + waterHeight <<= 4; + sint32 z = abs(duck->z - waterHeight); + + if (manhattanDistanceN <= manhattanDistance) + { + if (z > manhattanDistanceN) + { + z = duck->z - 2; + if (waterHeight >= duck->z) + { + z += 4; + } + duck->frame = 1; + } + else + { + z = duck->z; + } + sprite_move(x, y, z, (rct_sprite*)duck); + duck_invalidate(duck); + } + else + { + if (z > 4) + { + duck->state = DUCK_STATE::FLY_AWAY; + duck_update_fly_away(duck); + } + else + { + duck->state = DUCK_STATE::SWIM; + duck->frame = 0; + duck_update_swim(duck); + } + } + } +} + +/** + * + * rct2: 0x00674282 + */ +static void duck_update_swim(rct_duck *duck) +{ + if ((gCurrentTicks + duck->sprite_index) & 3) + return; + + uint32 randomNumber = scenario_rand(); + if ((randomNumber & 0xFFFF) < 0x666) + { + if (randomNumber & 0x80000000) + { + duck->state = DUCK_STATE::DOUBLE_DRINK; + duck->frame = -1; + duck_update_double_drink(duck); + } + else + { + duck->state = DUCK_STATE::DRINK; + duck->frame = -1; + duck_update_drink(duck); + } + } + else + { + sint32 currentMonth = date_get_month(gDateMonthsElapsed); + if (currentMonth >= MONTH_SEPTEMBER && (randomNumber >> 16) < 218) + { + duck->state = DUCK_STATE::FLY_AWAY; + duck_update_fly_away(duck); + } + else + { + duck_invalidate(duck); + sint32 landZ = map_element_height(duck->x, duck->y); + sint32 waterZ = (landZ >> 16) & 0xFFFF; + landZ &= 0xFFFF; + + if (duck->z < landZ || waterZ == 0) + { + duck->state = DUCK_STATE::FLY_AWAY; + duck_update_fly_away(duck); + } + else + { + duck->z = waterZ; + randomNumber = scenario_rand(); + if ((randomNumber & 0xFFFF) <= 0xAAA) + { + randomNumber >>= 16; + duck->sprite_direction = randomNumber & 0x18; + } + + sint32 direction = duck->sprite_direction >> 3; + sint32 x = duck->x + DuckMoveOffset[direction].x; + sint32 y = duck->y + DuckMoveOffset[direction].y; + landZ = map_element_height(x, y); + waterZ = (landZ >> 16) & 0xFFFF; + landZ &= 0xFFFF; + + if (duck->z >= landZ && duck->z == waterZ) + { + sprite_move(x, y, waterZ, (rct_sprite*)duck); + duck_invalidate(duck); + } + } + } + } +} + +static void duck_update_drink(rct_duck * duck) +{ + duck->frame++; + if (DuckAnimationDrink[duck->frame] == 0xFF) + { + duck->state = DUCK_STATE::SWIM; + duck->frame = 0; + duck_update_swim(duck); + } + else + { + duck_invalidate(duck); + } +} + +static void duck_update_double_drink(rct_duck * duck) +{ + duck->frame++; + if (DuckAnimationDoubleDrink[duck->frame] == 0xFF) + { + duck->state = DUCK_STATE::SWIM; + duck->frame = 0; + duck_update_swim(duck); + } + else + { + duck_invalidate(duck); + } +} + +static void duck_update_fly_away(rct_duck * duck) +{ + if ((gCurrentTicks & 3) == 0) + { + duck->frame++; + if (duck->frame >= Util::CountOf(DuckAnimationFlyAway)) + { + duck->frame = 0; + } + + duck_invalidate(duck); + sint32 direction = duck->sprite_direction >> 3; + sint32 x = duck->x + (DuckMoveOffset[direction].x * 2); + sint32 y = duck->y + (DuckMoveOffset[direction].y * 2); + if (map_is_location_valid(x, y)) + { + sprite_remove((rct_sprite *)duck); + } + else + { + sint32 z = min(duck->z + 2, 496); + sprite_move(x, y, z, (rct_sprite*)duck); + duck_invalidate(duck); + } + } +} + +extern "C" +{ + void create_duck(sint32 targetX, sint32 targetY) + { + rct_sprite * sprite = create_sprite(2); + if (sprite != nullptr) + { + sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite->duck.misc_identifier = SPRITE_MISC_DUCK; + sprite->duck.var_14 = 9; + sprite->duck.var_09 = 0xC; + sprite->duck.var_15 = 9; + sint32 offset_xy = scenario_rand() & 0x1E; + targetX += offset_xy; + targetY += offset_xy; + sprite->duck.target_x = targetX; + sprite->duck.target_y = targetY; + uint8 direction = scenario_rand() & 3; + switch (direction) { + case 0: + targetX = 8191 - (scenario_rand() & 0x3F); + break; + case 1: + targetY = scenario_rand() & 0x3F; + break; + case 2: + targetX = scenario_rand() & 0x3F; + break; + case 3: + targetY = 8191 - (scenario_rand() & 0x3F); + break; + } + sprite->duck.sprite_direction = direction << 3; + sprite_move(targetX, targetY, 496, sprite); + sprite->duck.state = DUCK_STATE::FLY_TO_WATER; + sprite->duck.frame = 0; + } + } + + void duck_update(rct_duck * duck) + { + switch ((DUCK_STATE)duck->state) { + case DUCK_STATE::FLY_TO_WATER: + duck_update_fly_to_water(duck); + break; + case DUCK_STATE::SWIM: + duck_update_swim(duck); + break; + case DUCK_STATE::DRINK: + duck_update_drink(duck); + break; + case DUCK_STATE::DOUBLE_DRINK: + duck_update_double_drink(duck); + break; + case DUCK_STATE::FLY_AWAY: + duck_update_fly_away(duck); + break; + } + } + + void duck_press(rct_duck * duck) + { + audio_play_sound_at_location(SOUND_QUACK, duck->x, duck->y, duck->z); + } + + void duck_remove_all() + { + uint16 nextSpriteIndex; + for (uint16 spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) + { + rct_unk_sprite * sprite = &(get_sprite(spriteIndex)->unknown); + nextSpriteIndex = sprite->next; + if (sprite->misc_identifier == SPRITE_MISC_DUCK) + { + sprite_remove((rct_sprite *)sprite); + } + } + } +} diff --git a/src/openrct2/world/duck.c b/src/openrct2/world/duck.c deleted file mode 100644 index 33c7428320..0000000000 --- a/src/openrct2/world/duck.c +++ /dev/null @@ -1,349 +0,0 @@ -#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 "../audio/audio.h" -#include "../game.h" -#include "../localisation/date.h" -#include "../scenario/scenario.h" -#include "sprite.h" - -enum { - DUCK_STATE_FLY_TO_WATER, - DUCK_STATE_SWIM, - DUCK_STATE_DRINK, - DUCK_STATE_DOUBLE_DRINK, - DUCK_STATE_FLY_AWAY -}; - -static void duck_update_fly_to_water(rct_duck *duck); -static void duck_update_swim(rct_duck *duck); -static void duck_update_drink(rct_duck *duck); -static void duck_update_double_drink(rct_duck *duck); -static void duck_update_fly_away(rct_duck *duck); - -// rct2: 0x009A3B04 -const rct_xy16 duck_move_offset[4] = { - { -1, 0 }, - { 0, 1 }, - { 1, 0 }, - { 0, -1 } -}; - -/** rct2: 0x0097F06C */ -static const uint8 duck_fly_to_water_animation[] = { - 8, 9, 10, 11, 12, 13 -}; - -/** rct2: 0x0097F072 */ -static const uint8 duck_swim_animation[] = { - 0 -}; - -// rct2: 0x0097F073 -static const uint8 duck_drink_animation[] = { - 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0xFF -}; - -// rct2: 0x0097F08C -static const uint8 duck_double_drink_animation[] = { - 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, - 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 0, 0, 0, 0, 0xFF -}; - -/** rct2: 0x0097F0B4 */ -static const uint8 duck_fly_away_animation[] = { - 8, 9, 10, 11, 12, 13 -}; - -/** rct2: 0x0097F058 */ -const uint8 * duck_animations[] = { - duck_fly_to_water_animation, // DUCK_STATE_FLY_TO_WATER - duck_swim_animation, // DUCK_STATE_SWIM - duck_drink_animation, // DUCK_STATE_DRINK - duck_double_drink_animation, // DUCK_STATE_DOUBLE_DRINK - duck_fly_away_animation, // DUCK_STATE_FLY_AWAY -}; - -/** - * - * rct2: 0x0067440F - */ -void create_duck(sint32 targetX, sint32 targetY) -{ - rct_sprite* sprite = create_sprite(2); - if (sprite != NULL) { - sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC; - sprite->duck.misc_identifier = SPRITE_MISC_DUCK; - sprite->duck.var_14 = 9; - sprite->duck.var_09 = 0xC; - sprite->duck.var_15 = 9; - sint32 offset_xy = scenario_rand() & 0x1E; - targetX += offset_xy; - targetY += offset_xy; - sprite->duck.target_x = targetX; - sprite->duck.target_y = targetY; - uint8 direction = scenario_rand() & 3; - switch (direction) { - case 0: - targetX = 8191 - (scenario_rand() & 0x3F); - break; - case 1: - targetY = scenario_rand() & 0x3F; - break; - case 2: - targetX = scenario_rand() & 0x3F; - break; - case 3: - targetY = 8191 - (scenario_rand() & 0x3F); - break; - } - sprite->duck.sprite_direction = direction << 3; - sprite_move(targetX, targetY, 496, sprite); - sprite->duck.state = DUCK_STATE_FLY_TO_WATER; - sprite->duck.frame = 0; - } -} - -/** - * - * rct2: 0x006740E8 - */ -void duck_update(rct_duck *duck) -{ - switch (duck->state) { - case DUCK_STATE_FLY_TO_WATER: - duck_update_fly_to_water(duck); - break; - case DUCK_STATE_SWIM: - duck_update_swim(duck); - break; - case DUCK_STATE_DRINK: - duck_update_drink(duck); - break; - case DUCK_STATE_DOUBLE_DRINK: - duck_update_double_drink(duck); - break; - case DUCK_STATE_FLY_AWAY: - duck_update_fly_away(duck); - break; - } -} - -static void duck_invalidate(rct_duck *duck) -{ - invalidate_sprite_0((rct_sprite*)duck); -} - -/** - * - * rct2: 0x00674108 - */ -static void duck_update_fly_to_water(rct_duck *duck) -{ - if (gCurrentTicks & 3) - return; - - duck->frame++; - if (duck->frame >= countof(duck_fly_to_water_animation)) - duck->frame = 0; - - duck_invalidate(duck); - sint32 manhattanDistance = abs(duck->target_x - duck->x) + abs(duck->target_y - duck->y); - sint32 direction = duck->sprite_direction >> 3; - sint32 x = duck->x + duck_move_offset[direction].x; - sint32 y = duck->y + duck_move_offset[direction].y; - sint32 manhattanDistanceN = abs(duck->target_x - x) + abs(duck->target_y - y); - - rct_map_element *mapElement = map_get_surface_element_at(duck->target_x >> 5, duck->target_y >> 5); - sint32 waterHeight = mapElement->properties.surface.terrain & 0x1F; - if (waterHeight == 0) { - duck->state = DUCK_STATE_FLY_AWAY; - duck_update_fly_away(duck); - return; - } - waterHeight <<= 4; - sint32 z = abs(duck->z - waterHeight); - - if (manhattanDistanceN <= manhattanDistance) { - if (z > manhattanDistanceN) { - z = duck->z - 2; - if (waterHeight >= duck->z) - z += 4; - - duck->frame = 1; - } else { - z = duck->z; - } - sprite_move(x, y, z, (rct_sprite*)duck); - duck_invalidate(duck); - } else { - if (z > 4) { - duck->state = DUCK_STATE_FLY_AWAY; - duck_update_fly_away(duck); - } else { - duck->state = DUCK_STATE_SWIM; - duck->frame = 0; - duck_update_swim(duck); - } - } -} - -/** - * - * rct2: 0x00674282 - */ -static void duck_update_swim(rct_duck *duck) -{ - if ((gCurrentTicks + duck->sprite_index) & 3) - return; - - uint32 randomNumber = scenario_rand(); - if ((randomNumber & 0xFFFF) < 0x666) { - if (randomNumber & 0x80000000) { - duck->state = DUCK_STATE_DOUBLE_DRINK; - duck->frame = -1; - duck_update_double_drink(duck); - } else { - duck->state = DUCK_STATE_DRINK; - duck->frame = -1; - duck_update_drink(duck); - } - return; - } - - sint32 currentMonth = date_get_month(gDateMonthsElapsed); - if (currentMonth >= MONTH_SEPTEMBER && (randomNumber >> 16) < 218) { - duck->state = DUCK_STATE_FLY_AWAY; - duck_update_fly_away(duck); - return; - } - - duck_invalidate(duck); - sint32 landZ = map_element_height(duck->x, duck->y); - sint32 waterZ = (landZ >> 16) & 0xFFFF; - landZ &= 0xFFFF; - - if (duck->z < landZ || waterZ == 0) { - duck->state = DUCK_STATE_FLY_AWAY; - duck_update_fly_away(duck); - return; - } - - duck->z = waterZ; - randomNumber = scenario_rand(); - if ((randomNumber & 0xFFFF) <= 0xAAA) { - randomNumber >>= 16; - duck->sprite_direction = randomNumber & 0x18; - } - - sint32 direction = duck->sprite_direction >> 3; - sint32 x = duck->x + duck_move_offset[direction].x; - sint32 y = duck->y + duck_move_offset[direction].y; - landZ = map_element_height(x, y); - waterZ = (landZ >> 16) & 0xFFFF; - landZ &= 0xFFFF; - - if (duck->z < landZ || duck->z != waterZ) - return; - - sprite_move(x, y, waterZ, (rct_sprite*)duck); - duck_invalidate(duck); -} - -/** - * - * rct2: 0x00674357 - */ -static void duck_update_drink(rct_duck *duck) -{ - duck->frame++; - if (duck_drink_animation[duck->frame] == 0xFF) { - duck->state = DUCK_STATE_SWIM; - duck->frame = 0; - duck_update_swim(duck); - } else { - duck_invalidate(duck); - } -} - -/** - * - * rct2: 0x00674372 - */ -static void duck_update_double_drink(rct_duck *duck) -{ - duck->frame++; - if (duck_double_drink_animation[duck->frame] == 0xFF) { - duck->state = DUCK_STATE_SWIM; - duck->frame = 0; - duck_update_swim(duck); - } else { - duck_invalidate(duck); - } -} - -/** - * - * rct2: 0x0067438D - */ -static void duck_update_fly_away(rct_duck *duck) -{ - if (gCurrentTicks & 3) - return; - - duck->frame++; - if (duck->frame >= countof(duck_fly_away_animation)) - duck->frame = 0; - - duck_invalidate(duck); - sint32 direction = duck->sprite_direction >> 3; - sint32 x = duck->x + (duck_move_offset[direction].x * 2); - sint32 y = duck->y + (duck_move_offset[direction].y * 2); - if (x < 0 || y < 0 || x >= (32 * 256) || y >= (32 * 256)) { - sprite_remove((rct_sprite*)duck); - return; - } - - sint32 z = min(duck->z + 2, 496); - sprite_move(x, y, z, (rct_sprite*)duck); - duck_invalidate(duck); -} - -/** - * - * rct2: 0x006E895D - */ -void duck_press(rct_duck *duck) -{ - audio_play_sound_at_location(SOUND_QUACK, duck->x, duck->y, duck->z); -} - -/** - * - * rct2: 0x00674576 - */ -void duck_remove_all() -{ - rct_unk_sprite* sprite; - uint16 spriteIndex, nextSpriteIndex; - - for (spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) { - sprite = &(get_sprite(spriteIndex)->unknown); - nextSpriteIndex = sprite->next; - if (sprite->misc_identifier == SPRITE_MISC_DUCK) - sprite_remove((rct_sprite*)sprite); - } -}