Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-06-02 15:38:15 +08:00
19 changed files with 244 additions and 165 deletions

View File

@@ -0,0 +1,3 @@
-- DB update 2023_05_29_02 -> 2023_06_01_00
--
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask`|33554432 WHERE `entry` IN (18341, 20267);

View File

@@ -0,0 +1,3 @@
-- DB update 2023_06_01_00 -> 2023_06_01_01
--
UPDATE `creature_template` SET `mechanic_immune_mask` = 663699067 WHERE `entry` IN (17839, 20744, 21140, 22172, 21104, 21148, 22170, 22171);

View File

@@ -0,0 +1,3 @@
-- DB update 2023_06_01_01 -> 2023_06_01_02
--
UPDATE `smart_scripts` SET `action_param1` = 768 WHERE `entryorguid` IN (-151090, -151091, -151092, -151093) AND `source_type` = 0;

View File

@@ -0,0 +1,11 @@
-- DB update 2023_06_01_02 -> 2023_06_01_03
-- 5097: Lupine Delusion (Shadowfang Keep)
-- 6493: Illusionary Phantasm (Scarlet Monastery Graveyard)
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (5097, 6493);
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (5097, 6493));
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(5097, 0, 0, 0, 2, 0, 100, 0, 0, 99, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lupine Delusion - Between 0-99% Health - Despawn Instant'),
(5097, 0, 1, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lupine Delusion - On Just Died - Despawn Instant'),
(6493, 0, 0, 0, 2, 0, 100, 0, 0, 99, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Illusionary Phantasm - Between 0-99% Health - Despawn Instant'),
(6493, 0, 1, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Illusionary Phantasm - On Just Died - Despawn Instant');

View File

@@ -0,0 +1,10 @@
-- DB update 2023_06_01_03 -> 2023_06_01_04
-- Sul'lithuz Abomination and Sandfury Guardian creature formations
DELETE FROM `creature_formations` WHERE `memberGUID` IN (81527, 81565, 37998, 37999, 38000, 38001);
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
(81527, 81527, 0, 0, 3, 0, 0),
(81527, 81565, 0, 0, 3, 0, 0),
(37998, 37998, 0, 0, 3, 0, 0),
(37998, 37999, 0, 0, 3, 0, 0),
(37998, 38000, 0, 0, 3, 0, 0),
(37998, 38001, 0, 0, 3, 0, 0);

View File

@@ -0,0 +1,6 @@
-- DB update 2023_06_01_04 -> 2023_06_01_05
--
DELETE FROM `smart_scripts` WHERE `entryorguid` = 19716 AND `source_type` = 0 AND `id` IN (5, 6);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(19716, 0, 5, 6, 34, 2, 100, 1, 8, 0, 0, 0, 0, 11, 35058, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mechanar Tinkerer - On Reached Point 0 - Cast \'Nether Explosion\' (Phase 2) (No Repeat)'),
(19716, 0, 6, 0, 61, 2, 100, 1, 0, 0, 0, 0, 0, 37, 1001, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mechanar Tinkerer - On Reached Point 0 - Kill Self (Phase 2) (No Repeat)');

View File

@@ -0,0 +1,6 @@
-- DB update 2023_06_01_05 -> 2023_06_01_06
--
DELETE FROM `spell_script_names` WHERE `spell_id` IN (34246, 60779) AND `ScriptName` = 'spell_dru_idol_lifebloom';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(34246, 'spell_dru_idol_lifebloom'),
(60779, 'spell_dru_idol_lifebloom');

View File

@@ -1139,7 +1139,22 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_DIE:
{
if (me && !me->isDead())
if (e.action.die.milliseconds)
{
if (me && !me->isDead())
{
me->m_Events.AddEventAtOffset([&]
{
// We need to check again to see if we didn't die in the process.
if (me && !me->isDead())
{
me->KillSelf();
LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());
}
}, Milliseconds(e.action.die.milliseconds));
}
}
else if (me && !me->isDead())
{
me->KillSelf();
LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());

View File

@@ -641,7 +641,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SET_INST_DATA: return sizeof(SmartAction::setInstanceData);
case SMART_ACTION_SET_INST_DATA64: return sizeof(SmartAction::setInstanceData64);
case SMART_ACTION_UPDATE_TEMPLATE: return sizeof(SmartAction::updateTemplate);
case SMART_ACTION_DIE: return NO_PARAMS;
case SMART_ACTION_DIE: return sizeof(SmartAction::die);
case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: return NO_PARAMS;
case SMART_ACTION_CALL_FOR_HELP: return sizeof(SmartAction::callHelp);
case SMART_ACTION_SET_SHEATH: return sizeof(SmartAction::setSheath);

View File

@@ -559,7 +559,7 @@ enum SMART_ACTION
SMART_ACTION_SET_INST_DATA = 34, // Field, Data
SMART_ACTION_SET_INST_DATA64 = 35, // Field,
SMART_ACTION_UPDATE_TEMPLATE = 36, // Entry, UpdateLevel
SMART_ACTION_DIE = 37, // No Params
SMART_ACTION_DIE = 37, // Milliseconds
SMART_ACTION_SET_IN_COMBAT_WITH_ZONE = 38, // Range (if outside of dungeon)
SMART_ACTION_CALL_FOR_HELP = 39, // Radius, With Emote
SMART_ACTION_SET_SHEATH = 40, // Sheath (0-unarmed, 1-melee, 2-ranged)
@@ -925,6 +925,11 @@ struct SmartAction
SAIBool updateLevel;
} updateTemplate;
struct
{
uint32 milliseconds;
} die;
struct
{
uint32 range;

View File

@@ -12482,32 +12482,6 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
switch (spellProto->SpellFamilyName)
{
case SPELLFAMILY_DRUID:
{
// Nourish vs Idol of the Flourishing Life
if (spellProto->SpellFamilyFlags[1] & 0x02000000)
{
if (AuraEffect const* relicAurEff = GetAuraEffect(64949, EFFECT_0))
{
DoneAdvertisedBenefit += relicAurEff->GetAmount();
}
}
// Lifebloom vs Idol of Lush Moss/Increased Lifebloom Periodic
if (spellProto->SpellFamilyFlags[1] & 00000010)
{
if (AuraEffect const* relicAurEff = GetAuraEffect(60779, EFFECT_0))
{
DoneAdvertisedBenefit += relicAurEff->GetAmount();
}
if (AuraEffect const* relicAurEff = GetAuraEffect(34246, EFFECT_0))
{
DoneAdvertisedBenefit += relicAurEff->GetAmount();
}
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
// Impurity

View File

@@ -439,6 +439,13 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00000040, 0x00000000, 0x00000000);
});
// Idol of the Flourishing Life
ApplySpellFix({ 64949 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00000000, 0x02000000, 0x00000000);
spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
});
ApplySpellFix({
34231, // Libram of the Lightbringer
60792, // Libram of Tolerance

View File

@@ -63,9 +63,9 @@ enum Events
EVENT_PYROBLAST = 6,
// Hack due to trigger spell not in dbc
EVENT_FIRE_SHIELD = 7,
// Make sure all players have aura from altar
EVENT_PLAYER_CHECK = 8,
EVENT_ENTER_COMBAT = 9
EVENT_PRE_ENTER_COMBAT_1 = 8,
EVENT_PRE_ENTER_COMBAT_2 = 9,
EVENT_ENTER_COMBAT = 10
};
class boss_pyroguard_emberseer : public CreatureScript
@@ -101,7 +101,8 @@ public:
switch (data)
{
case 1:
events.ScheduleEvent(EVENT_PLAYER_CHECK, 5s);
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
break;
case 2:
// Close these two doors on Blackhand Incarcerators aggro
@@ -153,14 +154,12 @@ public:
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20)
{
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
me->RemoveAura(SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
Talk(EMOTE_FREE_OF_BONDS);
Talk(YELL_FREE_OF_BONDS);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
events.ScheduleEvent(EVENT_ENTER_COMBAT, 2s);
events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start
// Schedule out the pre-combat scene
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s);
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s);
events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s);
}
}
}
@@ -235,7 +234,7 @@ public:
if (Creature* creature = *itr)
creature->AI()->SetData(1, 1);
}
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 32s);
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s);
break;
}
case EVENT_PRE_FIGHT_2:
@@ -248,25 +247,21 @@ public:
DoCast(me, SPELL_FIRE_SHIELD);
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
break;
case EVENT_PLAYER_CHECK:
{
// Check to see if all players in instance have aura SPELL_EMBERSEER_START before starting event
bool _hasAura = false;
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()->ToPlayer())
if (player->HasAura(SPELL_EMBERSEER_OBJECT_VISUAL))
_hasAura = true;
if (_hasAura)
{
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 1s);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
}
break;
}
case EVENT_PRE_ENTER_COMBAT_1:
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
me->RemoveAura(SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
Talk(EMOTE_FREE_OF_BONDS);
break;
case EVENT_PRE_ENTER_COMBAT_2:
Talk(YELL_FREE_OF_BONDS);
break;
case EVENT_ENTER_COMBAT:
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
DoZoneInCombat();
// re-enable fire shield
events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s);
break;
default:
break;
@@ -347,11 +342,6 @@ public:
_fleedForAssistance = false;
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(10000);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage))
@@ -392,7 +382,6 @@ public:
}
_events.ScheduleEvent(EVENT_STRIKE, 8s, 16s);
_events.ScheduleEvent(EVENT_ENCAGE, 10s, 20s);
}
void UpdateAI(uint32 diff) override

View File

@@ -34,107 +34,70 @@ enum Spells
SPELL_DARK_SHELL = 32358
};
enum Events
enum Groups
{
EVENT_VOID_BLAST = 1,
EVENT_DARK_SHELL
GROUP_VOID_BLAST = 1
};
class boss_pandemonius : public CreatureScript
{
public:
boss_pandemonius() : CreatureScript("boss_pandemonius") { }
constexpr uint8 MAX_VOID_BLAST = 5;
CreatureAI* GetAI(Creature* creature) const override
struct boss_pandemonius : public BossAI
{
boss_pandemonius(Creature* creature) : BossAI(creature, DATA_PANDEMONIUS)
{
return GetManaTombsAI<boss_pandemoniusAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_pandemoniusAI : public ScriptedAI
void JustEngagedWith(Unit* who) override
{
boss_pandemoniusAI(Creature* creature) : ScriptedAI(creature) { }
Talk(SAY_AGGRO);
EventMap events;
void Reset() override
{
events.Reset();
VoidBlastCounter = 0;
}
void JustEngagedWith(Unit*) override
{
me->SetInCombatWithZone();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_DARK_SHELL, 20000);
events.ScheduleEvent(EVENT_VOID_BLAST, urand(8000, 23000));
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
scheduler.
Schedule(20s, GROUP_VOID_BLAST, [this](TaskContext context)
{
case EVENT_VOID_BLAST:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
{
DoCast(target, SPELL_VOID_BLAST);
++VoidBlastCounter;
}
if (me->IsNonMeleeSpellCast(false))
{
me->InterruptNonMeleeSpells(true);
}
if (VoidBlastCounter == 5)
Talk(EMOTE_DARK_SHELL);
DoCastSelf(SPELL_DARK_SHELL);
context.Repeat();
})
.Schedule(8s, 23s, [this](TaskContext context)
{
if (!(context.GetRepeatCounter() % (MAX_VOID_BLAST + 1)))
{
VoidBlastCounter = 0;
events.RescheduleEvent(EVENT_VOID_BLAST, urand(15000, 25000));
context.Repeat(15s, 25s);
}
else
{
events.RescheduleEvent(EVENT_VOID_BLAST, 500);
events.DelayEvents(EVENT_DARK_SHELL, 500);
}
break;
case EVENT_DARK_SHELL:
if (me->IsNonMeleeSpellCast(false))
{
me->InterruptNonMeleeSpells(true);
DoCastRandomTarget(SPELL_VOID_BLAST);
context.Repeat(500ms);
context.DelayGroup(GROUP_VOID_BLAST, 500ms);
}
});
Talk(EMOTE_DARK_SHELL);
DoCast(me, SPELL_DARK_SHELL);
events.RescheduleEvent(EVENT_DARK_SHELL, 20000);
break;
default:
break;
}
BossAI::JustEngagedWith(who);
}
DoMeleeAttackIfReady();
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
}
private:
uint32 VoidBlastCounter;
};
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
};
void AddSC_boss_pandemonius()
{
new boss_pandemonius();
RegisterManaTombsCreatureAI(boss_pandemonius);
}

View File

@@ -104,7 +104,14 @@ struct boss_talon_king_ikiss : public BossAI
context.Repeat(7s, 12s);
}).Schedule(8s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_POLYMORPH);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_POLYMORPH);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* target) -> bool
{
return target && !target->IsImmunedToSpell(spellInfo);
}))
{
DoCast(target, SPELL_POLYMORPH);
}
context.Repeat(15s, 17500ms);
});

View File

@@ -114,7 +114,7 @@ struct boss_grand_warlock_nethekurse : public BossAI
if (!_canAggro)
{
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(true);
}
}
@@ -235,11 +235,13 @@ struct boss_grand_warlock_nethekurse : public BossAI
me->SetInCombatWithZone();
return;
}
else if (action == ACTION_START_INTRO)
else if (action == ACTION_START_INTRO && !_introStarted)
{
// Hack: Prevent from pulling from behind door
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
_canAggro = true;
// Bit of a hack to make sure it can't be started with the areatrigger AND the door opening
_introStarted = true;
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_PEON, 60.0f);
@@ -247,7 +249,7 @@ struct boss_grand_warlock_nethekurse : public BossAI
{
if (creature)
{
creature->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
creature->SetImmuneToAll(false);
}
}
IntroRP();
@@ -258,6 +260,21 @@ struct boss_grand_warlock_nethekurse : public BossAI
{
scheduler.Update(diff);
// this should never be called if the action to start intro has been called
if (!_introStarted)
{
// find the door that is nearest to the entrance
if (GameObject* nethekursedoor = GetClosestGameObjectWithEntry(me, GO_GRAND_WARLOCK_CHAMBER_DOOR_1, 100.0f))
{
// check if door is openened
//this should only happen before the intro, if the door is picked by someone
if(nethekursedoor->GetGoState() == 0)
{
DoAction(ACTION_START_INTRO);
}
}
}
if (!UpdateVictim())
return;
@@ -272,6 +289,7 @@ private:
uint8 PeonEngagedCount = 0;
uint8 PeonKilledCount = 0;
bool _canAggro = false;
bool _introStarted = false;
};
class spell_tsh_shadow_bolt : public SpellScript

View File

@@ -54,6 +54,24 @@ struct boss_nethermancer_sepethrea : public BossAI
});
}
bool CanAIAttack(Unit const* target) const override
{
if (me->GetThreatMgr().GetThreatListSize() > 1)
{
ThreatContainer::StorageType::const_iterator lastRef = me->GetThreatMgr().GetOnlineContainer().GetThreatList().end();
--lastRef;
if (Unit* lastTarget = (*lastRef)->getTarget())
{
if (lastTarget != target)
{
return !target->HasAura(SPELL_DRAGONS_BREATH);
}
}
}
return true;
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();

View File

@@ -500,6 +500,31 @@ class spell_dru_glyph_of_starfire : public SpellScript
}
};
// 34246 - Idol of the Emerald Queen
// 60779 - Idol of Lush Moss
class spell_dru_idol_lifebloom : public AuraScript
{
PrepareAuraScript(spell_dru_idol_lifebloom);
void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)
{
if (!spellMod)
{
spellMod = new SpellModifier(GetAura());
spellMod->op = SPELLMOD_DOT;
spellMod->type = SPELLMOD_FLAT;
spellMod->spellId = GetId();
spellMod->mask = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask;
}
spellMod->value = aurEff->GetAmount() / 7;
}
void Register() override
{
DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_dru_idol_lifebloom::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY);
}
};
// 29166 - Innervate
class spell_dru_innervate : public AuraScript
{
@@ -1158,6 +1183,7 @@ void AddSC_druid_spell_scripts()
RegisterSpellScript(spell_dru_dash);
RegisterSpellScript(spell_dru_enrage);
RegisterSpellScript(spell_dru_glyph_of_starfire);
RegisterSpellScript(spell_dru_idol_lifebloom);
RegisterSpellScript(spell_dru_innervate);
RegisterSpellScript(spell_dru_lifebloom);
RegisterSpellScript(spell_dru_living_seed);

View File

@@ -990,7 +990,7 @@ public:
Reset();
}
void PatientSaved(Creature* /*soldier*/, Player* player, Location* point)
void PatientSaved(Creature* savedPatient, Player* player, Location* point)
{
if (player && PlayerGUID == player->GetGUID())
{
@@ -1004,8 +1004,9 @@ public:
{
for (ObjectGuid const& guid : Patients)
{
if (Creature* patient = ObjectAccessor::GetCreature(*me, guid))
patient->setDeathState(JUST_DIED);
if (guid != savedPatient->GetGUID()) // Don't kill the last guy we just saved
if (Creature* patient = ObjectAccessor::GetCreature(*me, guid))
patient->setDeathState(JUST_DIED);
}
}
@@ -1069,6 +1070,9 @@ public:
//no regen health
me->SetUnitFlag(UNIT_FLAG_IN_COMBAT);
//prevent using normal bandages
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANDAGE, true);
//to make them lay with face down
me->SetUInt32Value(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD);
@@ -1078,18 +1082,26 @@ public:
{
//lower max health
case 12923:
case 12938: //Injured Soldier
me->SetHealth(me->CountPctFromMaxHealth(75));
case 12938: //Injured Soldier, 65 seconds to die
me->SetHealth(me->CountPctFromMaxHealth(65));
break;
case 12924:
case 12936: //Badly injured Soldier
me->SetHealth(me->CountPctFromMaxHealth(50));
case 12936: //Badly injured Soldier, 35 seconds to die
me->SetHealth(me->CountPctFromMaxHealth(35));
break;
case 12925:
case 12937: //Critically injured Soldier
case 12937: //Critically injured Soldier, 25 seconds to die
me->SetHealth(me->CountPctFromMaxHealth(25));
break;
}
// Schedule health reduction every 1 second
_scheduler.Schedule(1s, [this](TaskContext context)
{
// Reduction of 1% per second, matching WotLK Classic timing
me->ModifyHealth(me->CountPctFromMaxHealth(1) * -1);
context.Repeat(1s);
});
}
void JustEngagedWith(Unit* /*who*/) override { }
@@ -1134,13 +1146,12 @@ public:
}
}
void UpdateAI(uint32 /*diff*/) override
void UpdateAI(uint32 diff) override
{
//lower HP on every world tick makes it a useful counter, not officlone though
if (me->IsAlive() && me->GetHealth() > 6)
me->ModifyHealth(-5);
if (me->IsAlive() && me->GetHealth() <= 6)
_scheduler.Update(diff);
if (me->IsAlive() && me->GetHealth() < me->CountPctFromMaxHealth(1))
{
me->RemoveUnitFlag(UNIT_FLAG_IN_COMBAT);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
@@ -1152,6 +1163,10 @@ public:
CAST_AI(npc_doctor::npc_doctorAI, doctor->AI())->PatientDied(Coord);
}
}
private:
TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1162,7 +1177,7 @@ public:
void npc_doctor::npc_doctorAI::UpdateAI(uint32 diff)
{
if (Event && SummonPatientCount >= 20)
if (Event && SummonPatientCount >= 24) // Need to keep the event going long enough to save the last few patients
{
Reset();
return;
@@ -1170,7 +1185,7 @@ void npc_doctor::npc_doctorAI::UpdateAI(uint32 diff)
if (Event)
{
if (SummonPatientTimer <= diff)
if (SummonPatientTimer <= diff || SummonPatientCount < 6) // Starts with 6 beds filled for both factions
{
if (Coordinates.empty())
return;