mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
fix(scripts): Spider Queen specials follow her stage and wait out the smash (issue 1970)
Every hit started both the rapid fire shooter and the rain of fire timers, from stage 1 on, so the two specials ran in every stage and on top of each other, each turning the boss's AI off and on again under the other's animations. They also wrote the "stoppedFlag" that the no-players-around attack stop uses, which could leave her stopped for good. As the live script: after she comes back down, a skill manager fires the rapid fire shooter in stage 2 and the rain of fire in stage 3 only, again 10 to 15 s after each ends; for 3.1 s after her melee smash (skill 322) a due special waits and fires when the smash ends. The rain of fire keeps her from attacking until its last impact. Check in game: Spider Queen fight: no specials before the first spiderling wave; stage 2 only rapid fire, stage 3 only rain of fire; she never freezes in the smash animation and keeps attacking after each special. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,8 @@ void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) {
|
||||
}
|
||||
}
|
||||
|
||||
SpiderSkillManager(self, false);
|
||||
|
||||
// There is suppose to be a 0.1 second delay here but that may be admitted?
|
||||
auto* controller = Game::entityManager->GetZoneControlEntity();
|
||||
|
||||
@@ -299,19 +301,55 @@ void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) {
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::ToggleForSpecial(Entity* self, const bool state) {
|
||||
self->SetBoolean(u"stoppedFlag", state);
|
||||
|
||||
combat->SetDisabled(state);
|
||||
// Kept apart from "stoppedFlag", which is the no-players-around attack stop (ToggleAttacking)
|
||||
self->SetBoolean(u"isSpecialAttacking", state);
|
||||
UpdateSpecialStun(self);
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) {
|
||||
if (self->GetBoolean(u"stoppedFlag")) {
|
||||
self->AddTimer("ROF", GeneralUtils::GenerateRandomNumber<float>(10, 20));
|
||||
void BossSpiderQueenEnemyServer::SetRainOfFireStun(Entity* self, const bool state) {
|
||||
// Live: a separate "can't attack" stun from the start of a rain of fire until its last impact
|
||||
self->SetBoolean(u"rainOfFireStun", state);
|
||||
UpdateSpecialStun(self);
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::UpdateSpecialStun(Entity* self) {
|
||||
combat->SetDisabled(self->GetBoolean(u"isSpecialAttacking") || self->GetBoolean(u"rainOfFireStun"));
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::SpiderSkillManager(Entity* self, const bool active) {
|
||||
if (!active) {
|
||||
self->CancelTimer("PollSpiderSkillManager");
|
||||
return;
|
||||
}
|
||||
|
||||
// Within smashSkillLength of the melee smash: run the special once the smash is over
|
||||
if (self->GetBoolean(u"bSpecialLock")) {
|
||||
self->SetBoolean(u"bSpecialQueued", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->GetBoolean(u"isWithdrawn")) return;
|
||||
|
||||
// Stage 2 only fires the rapid fire shooter, stage 3 only the rain of fire
|
||||
if (m_CurrentBossStage == 2) {
|
||||
RunRapidFireShooter(self);
|
||||
} else if (m_CurrentBossStage == 3) {
|
||||
RunRainOfFire(self);
|
||||
}
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::OnSkillCast(Entity* self, const uint32_t skillID) {
|
||||
if (skillID != bossSmashSkill) return;
|
||||
|
||||
// The melee smash locks the specials for as long as it lasts
|
||||
self->SetBoolean(u"bSpecialLock", true);
|
||||
self->CancelTimer("UnlockSpecials");
|
||||
self->AddTimer("UnlockSpecials", smashSkillLength);
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) {
|
||||
ToggleForSpecial(self, true);
|
||||
SetRainOfFireStun(self, true);
|
||||
|
||||
impactList.clear();
|
||||
|
||||
@@ -370,9 +408,9 @@ void BossSpiderQueenEnemyServer::RainOfFireManager(Entity* self) {
|
||||
return;
|
||||
}
|
||||
|
||||
ToggleForSpecial(self, false);
|
||||
SetRainOfFireStun(self, false);
|
||||
|
||||
self->AddTimer("ROF", GeneralUtils::GenerateRandomNumber<float>(20, 40));
|
||||
self->AddTimer("PollSpiderSkillManager", static_cast<float>(GeneralUtils::GenerateRandomNumber<int32_t>(s2DelayMin, s2DelayMax)));
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) {
|
||||
@@ -381,8 +419,6 @@ void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) {
|
||||
|
||||
self->AddTimer("RFSTauntComplete", animationTime);
|
||||
|
||||
ToggleForSpecial(self, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -400,16 +436,10 @@ void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) {
|
||||
void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) {
|
||||
const auto targets = self->GetTargetsInPhantom();
|
||||
|
||||
if (self->GetBoolean(u"stoppedFlag")) {
|
||||
self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(5, 10));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (targets.empty()) {
|
||||
LOG("Failed to find RFS targets");
|
||||
|
||||
self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(5, 10));
|
||||
self->AddTimer("PollSpiderSkillManager", static_cast<float>(GeneralUtils::GenerateRandomNumber<int32_t>(s1DelayMin, s1DelayMax)));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -429,8 +459,6 @@ void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) {
|
||||
RapidFireShooterManager(self);
|
||||
|
||||
PlayAnimAndReturnTime(self, spiderSingleShot);
|
||||
|
||||
self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(10, 15));
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string timerName) {
|
||||
@@ -477,31 +505,21 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim
|
||||
|
||||
} else if (timerName == "StartROF") {
|
||||
//Re-enable Spider Boss
|
||||
//ToggleForSpecial(self, false);
|
||||
ToggleForSpecial(self, false);
|
||||
|
||||
RainOfFireManager(self);
|
||||
|
||||
} else if (timerName == "PollSpiderSkillManager") {
|
||||
//Call the skill manager again to attempt to run the current Spider Boss
|
||||
//stage's special attack again
|
||||
//SpiderSkillManager(self, true);
|
||||
PlayAnimAndReturnTime(self, spiderJeerAnim);
|
||||
SpiderSkillManager(self, true);
|
||||
|
||||
} else if (timerName == "RFS") {
|
||||
RunRapidFireShooter(self);
|
||||
} else if (timerName == "ROF") {
|
||||
RunRainOfFire(self);
|
||||
} else if (timerName == "RFSTauntComplete") {
|
||||
//Determine an appropriate random time to check our manager again
|
||||
// local spiderCooldownDelay = math.random(s1DelayMin, s1DelayMax)
|
||||
|
||||
//Set a timer based on our random cooldown determination
|
||||
//to pulse the SpiderSkillManager again
|
||||
|
||||
//GAMEOBJ:GetTimer():AddTimerWithCancel(spiderCooldownDelay, "PollSpiderSkillManager", self)
|
||||
//Set a timer based on a random cooldown to pulse the SpiderSkillManager again
|
||||
self->AddTimer("PollSpiderSkillManager", static_cast<float>(GeneralUtils::GenerateRandomNumber<int32_t>(s1DelayMin, s1DelayMax)));
|
||||
|
||||
//Re-enable Spider Boss
|
||||
//ToggleForSpecial(self, false);
|
||||
ToggleForSpecial(self, false);
|
||||
|
||||
} else if (timerName == "WithdrawComplete") {
|
||||
//Play the Spider Boss' mountain idle anim
|
||||
@@ -591,19 +609,12 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim
|
||||
//Did we queue a spcial attack?
|
||||
if (self->GetBoolean(u"bSpecialQueued")) {
|
||||
self->SetBoolean(u"bSpecialQueued", false);
|
||||
SpiderSkillManager(self, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {
|
||||
if (m_CurrentBossStage > 0 && !self->HasTimer("RFS")) {
|
||||
self->AddTimer("RFS", 5.0f);
|
||||
}
|
||||
|
||||
if (m_CurrentBossStage > 0 && !self->HasTimer("ROF")) {
|
||||
self->AddTimer("ROF", 10.0f);
|
||||
}
|
||||
|
||||
if (m_CurrentBossStage > ThresholdTable.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -616,8 +627,13 @@ void BossSpiderQueenEnemyServer::OnHitOrHealResult(Entity* self, Entity* attacke
|
||||
if (!isWithdrawn) {
|
||||
self->CancelAllTimers();
|
||||
|
||||
// Stop whatever special was running
|
||||
attackTargetTable.clear();
|
||||
impactList.clear();
|
||||
self->SetBoolean(u"isSpecialAttacking", false);
|
||||
self->SetBoolean(u"rainOfFireStun", false);
|
||||
self->SetBoolean(u"bSpecialLock", false);
|
||||
self->SetBoolean(u"bSpecialQueued", false);
|
||||
|
||||
WithdrawSpider(self, true);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,13 @@ public:
|
||||
|
||||
void ToggleForSpecial(Entity* self, bool state);
|
||||
|
||||
void SetRainOfFireStun(Entity* self, bool state);
|
||||
|
||||
// Runs the special attack of the current stage (live SpiderSkillManager); false stops polling
|
||||
void SpiderSkillManager(Entity* self, bool active);
|
||||
|
||||
void OnSkillCast(Entity* self, uint32_t skillID) override;
|
||||
|
||||
void RunRainOfFire(Entity* self);
|
||||
|
||||
void RainOfFireManager(Entity* self);
|
||||
@@ -56,6 +63,7 @@ public:
|
||||
|
||||
private:
|
||||
void ToggleAttacking(Entity& self, bool on);
|
||||
void UpdateSpecialStun(Entity* self);
|
||||
//Regular variables:
|
||||
DestroyableComponent* destroyable = nullptr;
|
||||
ControllablePhysicsComponent* controllable = nullptr;
|
||||
@@ -102,10 +110,11 @@ private:
|
||||
|
||||
const float smashSkillLength = 3.1f; //Time (in seconds) the boss smash skill lasts
|
||||
|
||||
const float s1DelayMin = 10.0f; //Minimum time until calling for another Rapid Fire Shot
|
||||
const float s1DelayMax = 15.0f; //Maximum time until calling for another Rapid Fire Shot
|
||||
const float s2DelayMin = 10.0f; //Minimum time until calling for another Rain Of Fire
|
||||
const float s2DelayMax = 15.0f; //Maximum time until calling for another Rain Of Fire
|
||||
// Whole seconds, as live's math.random(min, max)
|
||||
const int32_t s1DelayMin = 10; //Minimum time until calling for another Rapid Fire Shot
|
||||
const int32_t s1DelayMax = 15; //Maximum time until calling for another Rapid Fire Shot
|
||||
const int32_t s2DelayMin = 10; //Minimum time until calling for another Rain Of Fire
|
||||
const int32_t s2DelayMax = 15; //Maximum time until calling for another Rain Of Fire
|
||||
|
||||
const unsigned int instanceZoneID = 1102; //Zone ID for the Spider Queen fight instance
|
||||
const unsigned int instanceMissionID = 1941; //Achievement to update for beating the instanced Boss
|
||||
|
||||
Reference in New Issue
Block a user