Merge pull request #5301 from IntelOrca/refactor/duck

Refactor duck
This commit is contained in:
Ted John 2017-03-23 17:54:55 +00:00 committed by GitHub
commit a5744dcaee
8 changed files with 442 additions and 367 deletions

View File

@ -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 = "<group>"; };
8594C05F1D885CF600235E93 /* track_data_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_data_old.c; sourceTree = "<group>"; };
85B468FB1D96822F000F1DB5 /* paint_helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paint_helpers.c; sourceTree = "<group>"; };
A5D1DB5BE280897DCDEBFCED /* Duck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Duck.cpp; sourceTree = "<group>"; };
C606CCAB1DB4054000FE4015 /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = compat.c; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.c; };
C606CCAC1DB4054000FE4015 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = data.c; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.c; };
C606CCAD1DB4054000FE4015 /* data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = data.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@ -1000,7 +1003,6 @@
D44271DA1CC81B3200D84D28 /* banner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = banner.c; sourceTree = "<group>"; };
D44271D91CC81B3200D84D28 /* balloon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = balloon.c; sourceTree = "<group>"; };
D44271DB1CC81B3200D84D28 /* banner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = banner.h; sourceTree = "<group>"; };
D44271DE1CC81B3200D84D28 /* duck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = duck.c; sourceTree = "<group>"; };
D44271DF1CC81B3200D84D28 /* entrance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = entrance.h; sourceTree = "<group>"; };
D44271E01CC81B3200D84D28 /* footpath.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = footpath.c; sourceTree = "<group>"; };
D44271E11CC81B3200D84D28 /* footpath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = footpath.h; sourceTree = "<group>"; };
@ -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;
};

View File

@ -337,8 +337,8 @@
<ClCompile Include="windows\maze_construction.c" />
<ClCompile Include="world\Balloon.cpp" />
<ClCompile Include="world\banner.cpp" />
<ClCompile Include="world\duck.c" />
<ClCompile Include="world\entrance.cpp" />
<ClCompile Include="world\Duck.cpp" />
<ClCompile Include="world\money_effect.c" />
<ClCompile Include="world\particle.c" />
<ClCompile Include="util\sawyercoding.c" />

View File

@ -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
@ -181,18 +181,14 @@ void misc_paint(rct_sprite *misc, sint32 imageDirection)
break;
}
case SPRITE_MISC_DUCK: // 8
{
if (dpi->zoom_level != 0) {
return;
case SPRITE_MISC_DUCK:
if (dpi->zoom_level == 0) {
rct_duck * duck = &misc->duck;
uint32 imageId = duck_get_frame_image(&misc->duck, imageDirection);
if (imageId != 0) {
sub_98196C(imageId, 0, 0, 1, 1, 0, duck->z, get_current_rotation());
}
}
rct_duck duck = misc->duck;
uint8 imageOffset = duck_animations[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;
}
}
}

View File

@ -535,6 +535,13 @@ static const sint32 Unk9A39C4[] = {
1946281152,
};
static const rct_xy16 AvoidCollisionMoveOffset[] = {
{ -1, 0 },
{ 0, 1 },
{ 1, 0 },
{ 0, -1 },
};
static bool vehicle_move_info_valid(sint32 cd, sint32 typeAndDirection, sint32 offset)
{
if (cd >= countof(gTrackVehicleInfo)) {
@ -7017,7 +7024,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 +7130,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 + AvoidCollisionMoveOffset[offsetDirection].x - collideVehicle->x);
uint32 next_y_diff = abs(y + AvoidCollisionMoveOffset[offsetDirection].y - collideVehicle->y);
if (next_x_diff + next_y_diff < x_diff + y_diff){
mayCollide = true;

View File

@ -659,6 +659,8 @@ enum {
SPR_RIDE_DESIGN_PREVIEW_MAZE_ICE_BLOCKS = 21992,
SPR_RIDE_DESIGN_PREVIEW_MAZE_WOODEN_FENCES = 21993,
SPR_DUCK = 23133,
SPR_NEXT_WEATHER = 23189,
SPR_WEATHER_SUN = 23190,
SPR_WEATHER_SUN_CLOUD = 23191,

398
src/openrct2/world/Duck.cpp Normal file
View File

@ -0,0 +1,398 @@
#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/Math.hpp"
#include "../core/Util.hpp"
#include "../sprites.h"
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,
};
constexpr sint32 DUCK_MAX_STATES = 5;
static const rct_xy16 DuckMoveOffset[] =
{
{ -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
};
bool rct_sprite::IsDuck()
{
return this->duck.sprite_identifier == SPRITE_IDENTIFIER_MISC &&
this->duck.misc_identifier == SPRITE_MISC_DUCK;
}
rct_duck * rct_sprite::AsDuck()
{
rct_duck * result = nullptr;
if (IsDuck())
{
return (rct_duck *)result;
}
return result;
}
void rct_duck::Invalidate()
{
invalidate_sprite_0((rct_sprite *)this);
}
void rct_duck::Remove()
{
sprite_remove((rct_sprite *)this);
}
void rct_duck::MoveTo(sint16 destX, sint16 destY, sint16 destZ)
{
sprite_move(destX, destY, destZ, (rct_sprite *)this);
}
void rct_duck::UpdateFlyToWater()
{
if ((gCurrentTicks & 3) != 0) return;
frame++;
if (frame >= Util::CountOf(DuckAnimationFlyToWater))
{
frame = 0;
}
Invalidate();
sint32 manhattanDistance = abs(target_x - x) + abs(target_y - y);
sint32 direction = sprite_direction >> 3;
sint32 newX = x + DuckMoveOffset[direction].x;
sint32 newY = y + DuckMoveOffset[direction].y;
sint32 manhattanDistanceN = abs(target_x - newX) + abs(target_y - newY);
rct_map_element * mapElement = map_get_surface_element_at(target_x >> 5, target_y >> 5);
sint32 waterHeight = mapElement->properties.surface.terrain & 0x1F;
if (waterHeight == 0)
{
state = DUCK_STATE::FLY_AWAY;
UpdateFlyAway();
}
else
{
waterHeight <<= 4;
sint32 newZ = abs(z - waterHeight);
if (manhattanDistanceN <= manhattanDistance)
{
if (newZ > manhattanDistanceN)
{
newZ = z - 2;
if (waterHeight >= z)
{
newZ += 4;
}
frame = 1;
}
else
{
newZ = z;
}
MoveTo(newX, newY, newZ);
Invalidate();
}
else
{
if (newZ > 4)
{
state = DUCK_STATE::FLY_AWAY;
UpdateFlyAway();
}
else
{
state = DUCK_STATE::SWIM;
frame = 0;
UpdateSwim();
}
}
}
}
void rct_duck::UpdateSwim()
{
if (((gCurrentTicks + sprite_index) & 3) != 0) return;
uint32 randomNumber = scenario_rand();
if ((randomNumber & 0xFFFF) < 0x666)
{
if (randomNumber & 0x80000000)
{
state = DUCK_STATE::DOUBLE_DRINK;
frame = -1;
UpdateDoubleDrink();
}
else
{
state = DUCK_STATE::DRINK;
frame = -1;
UpdateDrink();
}
}
else
{
sint32 currentMonth = date_get_month(gDateMonthsElapsed);
if (currentMonth >= MONTH_SEPTEMBER && (randomNumber >> 16) < 218)
{
state = DUCK_STATE::FLY_AWAY;
UpdateFlyAway();
}
else
{
Invalidate();
sint32 landZ = map_element_height(x, y);
sint32 waterZ = (landZ >> 16) & 0xFFFF;
landZ &= 0xFFFF;
if (z < landZ || waterZ == 0)
{
state = DUCK_STATE::FLY_AWAY;
UpdateFlyAway();
}
else
{
z = waterZ;
randomNumber = scenario_rand();
if ((randomNumber & 0xFFFF) <= 0xAAA)
{
randomNumber >>= 16;
sprite_direction = randomNumber & 0x18;
}
sint32 direction = sprite_direction >> 3;
sint32 newX = x + DuckMoveOffset[direction].x;
sint32 newY = y + DuckMoveOffset[direction].y;
landZ = map_element_height(newX, newY);
waterZ = (landZ >> 16) & 0xFFFF;
landZ &= 0xFFFF;
if (z >= landZ && z == waterZ)
{
MoveTo(newX, newY, waterZ);
Invalidate();
}
}
}
}
}
void rct_duck::UpdateDrink()
{
frame++;
if (DuckAnimationDrink[frame] == 0xFF)
{
state = DUCK_STATE::SWIM;
frame = 0;
UpdateSwim();
}
else
{
Invalidate();
}
}
void rct_duck::UpdateDoubleDrink()
{
frame++;
if (DuckAnimationDoubleDrink[frame] == 0xFF)
{
state = DUCK_STATE::SWIM;
frame = 0;
UpdateSwim();
}
else
{
Invalidate();
}
}
void rct_duck::UpdateFlyAway()
{
if ((gCurrentTicks & 3) == 0)
{
frame++;
if (frame >= Util::CountOf(DuckAnimationFlyAway))
{
frame = 0;
}
Invalidate();
sint32 direction = sprite_direction >> 3;
sint32 newX = x + (DuckMoveOffset[direction].x * 2);
sint32 newY = y + (DuckMoveOffset[direction].y * 2);
sint32 newZ = Math::Min(z + 2, 496);
if (map_is_location_valid(newX, newY))
{
MoveTo(newX, newY, newZ);
Invalidate();
}
else
{
Remove();
}
}
}
uint32 rct_duck::GetFrameImage(sint32 direction) const
{
uint32 imageId = 0;
if (state < DUCK_MAX_STATES)
{
// TODO check frame is in range
uint8 imageOffset = DuckAnimations[state][frame];
imageId = SPR_DUCK + (imageOffset * 4) + (direction / 8);
}
return imageId;
}
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 offsetXY = scenario_rand() & 0x1E;
targetX += offsetXY;
targetY += offsetXY;
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->UpdateFlyToWater();
break;
case DUCK_STATE::SWIM:
duck->UpdateSwim();
break;
case DUCK_STATE::DRINK:
duck->UpdateDrink();
break;
case DUCK_STATE::DOUBLE_DRINK:
duck->UpdateDoubleDrink();
break;
case DUCK_STATE::FLY_AWAY:
duck->UpdateFlyAway();
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);
}
}
}
uint32 duck_get_frame_image(const rct_duck * duck, sint32 direction)
{
return duck->GetFrameImage(direction);
}
}

View File

@ -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);
}
}

View File

@ -161,6 +161,19 @@ typedef struct rct_duck {
sint16 target_y; // 0x32
uint8 pad_34[0x14];
uint8 state; // 0x48
#ifdef __cplusplus
void UpdateFlyToWater();
void UpdateSwim();
void UpdateDrink();
void UpdateDoubleDrink();
void UpdateFlyAway();
uint32 GetFrameImage(sint32 direction) const;
void Invalidate();
void Remove();
void MoveTo(sint16 x, sint16 y, sint16 z);
#endif
} rct_duck;
assert_struct_size(rct_duck, 0x49);
@ -347,7 +360,9 @@ typedef union {
#ifdef __cplusplus
bool IsBalloon();
bool IsDuck();
rct_balloon * AsBalloon();
rct_duck * AsDuck();
#endif
} rct_sprite;
@ -439,6 +454,7 @@ void create_duck(sint32 targetX, sint32 targetY);
void duck_update(rct_duck *duck);
void duck_press(rct_duck *duck);
void duck_remove_all();
uint32 duck_get_frame_image(const rct_duck * duck, sint32 direction);
///////////////////////////////////////////////////////////////
// Money effect
@ -457,3 +473,4 @@ void crash_splash_update(rct_crash_splash *splash);
const char *sprite_checksum();
#endif