Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More accurate battle animation shake #2136

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions src/battle_animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ void BattleAnimation::Update() {

SetFlashEffect(Main_Data::game_screen->GetFlashColor());

UpdateShake();

frame++;
}

Expand Down Expand Up @@ -144,6 +146,18 @@ void BattleAnimation::ProcessAnimationFlash(const RPG::AnimationTiming& timing)
}
}

void BattleAnimation::ProcessAnimationShake(const RPG::AnimationTiming& timing) {
if (IsOnlySound()) {
return;
}

if (timing.screen_shake == RPG::AnimationTiming::ScreenShake_target) {
target_shake_timing = &timing - animation.timings.data();
} else if (timing.screen_shake == RPG::AnimationTiming::ScreenShake_screen) {
screen_shake_timing = &timing - animation.timings.data();
}
}

void BattleAnimation::ProcessAnimationTiming(const RPG::AnimationTiming& timing) {
// Play the SE.
Game_System::SePlay(timing.se);
Expand All @@ -153,26 +167,7 @@ void BattleAnimation::ProcessAnimationTiming(const RPG::AnimationTiming& timing)

// Flash.
ProcessAnimationFlash(timing);

// Shake (only happens in battle).
if (Game_Battle::IsBattleRunning()) {
switch (timing.screen_shake) {
case RPG::AnimationTiming::ScreenShake_nothing:
break;
case RPG::AnimationTiming::ScreenShake_target:
// FIXME: Estimate, see below for screen shake.
ShakeTargets(3, 5, 32);
break;
case RPG::AnimationTiming::ScreenShake_screen:
Game_Screen* screen = Main_Data::game_screen.get();
// FIXME: This is not proven accurate. Screen captures show that
// the shake effect lasts for 16 animation frames (32 real frames).
// The maximum offset observed was 6 or 7, which makes these numbers
// seem reasonable.
screen->ShakeOnce(3, 5, 32);
break;
}
}
ProcessAnimationShake(timing);
}

static int CalculateFlashPower(int frames, int power) {
Expand All @@ -198,6 +193,16 @@ void BattleAnimation::UpdateFlashGeneric(int timing_idx, int& r, int& g, int& b,
}
}

bool BattleAnimation::CheckShakeGeneric(int timing_idx) {
if (timing_idx >= 0) {
auto& timing = animation.timings[timing_idx];
int start_frame = (timing.frame - 1) * 2;
int delta_frames = GetFrame() - start_frame;
return (delta_frames <= 10);
}
return false;
}

void BattleAnimation::UpdateScreenFlash() {
int r, g, b, p;
UpdateFlashGeneric(screen_flash_timing, r, g, b, p);
Expand Down Expand Up @@ -269,7 +274,8 @@ void BattleAnimationMap::FlashTargets(int r, int g, int b, int p) {
target.Flash(r, g, b, p, 0);
}

void BattleAnimationMap::ShakeTargets(int /* str */, int /* spd */, int /* time */) {
void BattleAnimationMap::UpdateShake() {
// RPG_RT only implements this for battle
}

/////////
Expand Down Expand Up @@ -298,15 +304,22 @@ void BattleAnimationBattle::Draw(Bitmap& dst) {
DrawAt(dst, battler.GetBattleX(), battler.GetBattleY() + offset);
}
}

void BattleAnimationBattle::FlashTargets(int r, int g, int b, int p) {
for (auto& battler: battlers) {
battler->Flash(r, g, b, p, 0);
}
}

void BattleAnimationBattle::ShakeTargets(int str, int spd, int time) {
for (auto& battler: battlers) {
battler->ShakeOnce(str, spd, time);
void BattleAnimationBattle::UpdateShake() {
if (CheckShakeGeneric(screen_shake_timing)) {
Main_Data::game_screen->ShakeOnce(3, 4, 31);
}

if (CheckShakeGeneric(target_shake_timing)) {
for (auto& battler: battlers) {
battler->ShakeOnce(3, 4, 31);
}
}
}

Expand All @@ -315,11 +328,14 @@ void BattleAnimation::SetFrame(int frame) {
int real_frame = frame / 2;
screen_flash_timing = -1;
target_flash_timing = -1;
screen_shake_timing = -1;
target_shake_timing = -1;
for (auto& timing: animation.timings) {
if (timing.frame > real_frame + 1) {
break;
}
ProcessAnimationFlash(timing);
ProcessAnimationShake(timing);
}

this->frame = frame;
Expand Down
10 changes: 7 additions & 3 deletions src/battle_animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,25 @@ class BattleAnimation : public Sprite {
BattleAnimation(const RPG::Animation& anim, bool only_sound = false, int cutoff = -1);

virtual void FlashTargets(int r, int g, int b, int p) = 0;
virtual void ShakeTargets(int str, int spd, int time) = 0;
virtual void UpdateShake() = 0;
void DrawAt(Bitmap& dst, int x, int y);
void ProcessAnimationTiming(const RPG::AnimationTiming& timing);
void ProcessAnimationFlash(const RPG::AnimationTiming& timing);
void ProcessAnimationShake(const RPG::AnimationTiming& timing);
void OnBattleSpriteReady(FileRequestResult* result);
void OnBattle2SpriteReady(FileRequestResult* result);
void UpdateScreenFlash();
void UpdateTargetFlash();
void UpdateFlashGeneric(int timing_idx, int& r, int& g, int& b, int& p);
bool CheckShakeGeneric(int timing_idx);

const RPG::Animation& animation;
int frame = 0;
int num_frames = 0;
int screen_flash_timing = -1;
int target_flash_timing = -1;
int screen_shake_timing = -1;
int target_shake_timing = -1;

FileRequestBinding request_id;
bool only_sound = false;
Expand All @@ -93,7 +97,7 @@ class BattleAnimationMap : public BattleAnimation {
void Draw(Bitmap& dst) override;
protected:
void FlashTargets(int r, int g, int b, int p) override;
void ShakeTargets(int str, int spd, int time) override;
void UpdateShake() override;
void DrawSingle(Bitmap& dst);
void DrawGlobal(Bitmap& dst);

Expand All @@ -108,7 +112,7 @@ class BattleAnimationBattle : public BattleAnimation {
void Draw(Bitmap& dst) override;
protected:
void FlashTargets(int r, int g, int b, int p) override;
void ShakeTargets(int str, int spd, int time) override;
void UpdateShake() override;
std::vector<Game_Battler*> battlers;
};

Expand Down