diff --git a/src/d/actor/d_a_b_gnd.cpp b/src/d/actor/d_a_b_gnd.cpp index f5b03be1b1..9d808c06f9 100644 --- a/src/d/actor/d_a_b_gnd.cpp +++ b/src/d/actor/d_a_b_gnd.cpp @@ -2192,6 +2192,7 @@ static void damage_check(b_gnd_class* i_this) { i_this->mDamageInvulnerabilityTimer = 100; } } + dusk::AchievementSystem::get().signal("ganondorf_foot_hit"); } cXyz hitmark_size(1.0f, 1.0f, 1.0f); @@ -2218,6 +2219,7 @@ static void damage_check(b_gnd_class* i_this) { i_this->field_0xc7c = 0; dScnPly_c::setPauseTimer(7); a_this->health = 100; + dusk::AchievementSystem::get().signal("ganondorf_knocked_down"); } break; } diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index e0b2cc73c8..3979d550a5 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -11,6 +11,7 @@ #include "d/actor/d_a_alink.h" #include "d/actor/d_a_ni.h" #include "d/actor/d_a_npc4.h" +#include "d/actor/d_a_b_gnd.h" #include "d/actor/d_a_b_ob.h" #include "d/actor/d_a_player.h" #include "d/d_demo.h" @@ -849,6 +850,66 @@ std::vector AchievementSystem::makeEntries() { {} }, // Glitched + { + { + "ganondorf_3hit", + "The Triforce of Skill", + "Defeat Ganondorf in the final duel with only 3 sword hits.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + auto& sys = AchievementSystem::get(); + const auto* link = static_cast(daPy_getPlayerActorClass()); + + static int autospinCount = 0; + static int pendingHits = 0; + static bool invalidated = false; + static bool wasInFight = false; + + auto* gnd = static_cast(fopAcM_SearchByName(fpcNm_B_GND_e)); + const bool inFight = gnd != nullptr && !gnd->checkRide(); + + if (inFight && !wasInFight) { + autospinCount = 0; + pendingHits = 0; + invalidated = false; + } + wasInFight = inFight; + + if (!inFight) { + return; + } + + const bool hitOccurred = sys.hasSignal("ganondorf_foot_hit"); + const bool knockedDown = sys.hasSignal("ganondorf_knocked_down"); + + if (hitOccurred && knockedDown) { + // Spin completing an autospin: pendingHits should be exactly 1 (the jump attack) + if (pendingHits == 1) { + autospinCount++; + pendingHits = 0; + } else { + invalidated = true; + } + } else if (hitOccurred) { + pendingHits++; + if (pendingHits > 1) { + invalidated = true; + } + } + + if (link != nullptr && link->mProcID == daAlink_c::PROC_GANON_FINISH) { + if (!invalidated && autospinCount == 3) { + a.progress = 1; + } + autospinCount = 0; + pendingHits = 0; + invalidated = false; + } + }, + {} + }, { { "back_in_time",