Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-12-17 22:42:51 +08:00
16 changed files with 377 additions and 25 deletions

View File

@@ -68,10 +68,12 @@ public:
virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
// Called when the gameobject summon successfully other creature
virtual void JustSummoned(Creature* /*summon*/) { }
virtual void SummonedCreatureDespawn(Creature* /*summon*/) { }
virtual void JustSummoned(Creature* /*summon*/) {}
virtual void SummonedCreatureDespawn(Creature* /*summon*/) {}
virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) { }
virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) {}
virtual void SummonedCreatureEvade(Creature* /*summon*/) {}
};
class NullGameObjectAI : public GameObjectAI

View File

@@ -21,6 +21,7 @@
#include "CreatureAIImpl.h"
#include "CreatureGroups.h"
#include "CreatureTextMgr.h"
#include "GameObjectAI.h"
#include "Log.h"
#include "MapReference.h"
#include "Player.h"
@@ -222,7 +223,7 @@ void CreatureAI::EnterEvadeMode(EvadeReason why)
me->GetVehicleKit()->Reset(true);
}
// despawn bosses at reset - only verified tbc/woltk bosses with this reset type - add bosses in last line respectively (dungeon/raid) and increase array limit
// despawn bosses at reset - only verified tbc/woltk bosses with this reset type
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(me->GetEntry());
if (cInfo && cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_HARD_RESET))
{
@@ -321,6 +322,21 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
formation->MemberEvaded(me);
}
if (TempSummon* summon = me->ToTempSummon())
{
if (WorldObject* summoner = summon->GetSummoner())
{
if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled)
{
summoner->ToCreature()->AI()->SummonedCreatureEvade(me);
}
else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
{
summoner->ToGameObject()->AI()->SummonedCreatureEvade(me);
}
}
}
return true;
}

View File

@@ -137,6 +137,8 @@ public:
virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) {}
virtual void SummonedCreatureDespawnAll() {}
virtual void SummonedCreatureEvade(Creature* /*summon*/) {}
// Called when hit by a spell
virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) {}

View File

@@ -817,6 +817,11 @@ void SmartAI::SummonedCreatureDies(Creature* summon, Unit* /*killer*/)
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_DIES, summon);
}
void SmartAI::SummonedCreatureEvade(Creature* summon)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_EVADE, summon);
}
void SmartAI::AttackStart(Unit* who)
{
// xinef: dont allow charmed npcs to act on their own
@@ -1136,6 +1141,11 @@ void SmartGameObjectAI::SummonedCreatureDies(Creature* summon, Unit* /*killer*/)
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_DIES, summon);
}
void SmartGameObjectAI::SummonedCreatureEvade(Creature* summon)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_EVADE, summon);
}
void SmartGameObjectAI::UpdateAI(uint32 diff)
{
GetScript()->OnUpdate(diff);

View File

@@ -97,6 +97,9 @@ public:
// Called when a summoned unit dies
void SummonedCreatureDies(Creature* summon, Unit* killer) override;
// Called when a summoned unit evades
void SummonedCreatureEvade(Creature* summon) override;
// Tell creature to attack and follow the victim
void AttackStart(Unit* who) override;
@@ -283,6 +286,9 @@ public:
// Called when a summoned unit dies
void SummonedCreatureDies(Creature* summon, Unit* killer) override;
// Called when a summoned unit evades
void SummonedCreatureEvade(Creature* summon) override;
protected:
SmartScript mScript;
};

View File

@@ -4077,6 +4077,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
}
case SMART_EVENT_SUMMONED_UNIT:
case SMART_EVENT_SUMMONED_UNIT_DIES:
case SMART_EVENT_SUMMONED_UNIT_EVADE:
{
if (!IsCreature(unit))
return;

View File

@@ -345,6 +345,7 @@ void SmartAIMgr::LoadSmartAIFromDB()
case SMART_EVENT_INSTANCE_PLAYER_ENTER:
case SMART_EVENT_TRANSPORT_ADDCREATURE:
case SMART_EVENT_NEAR_PLAYERS:
case SMART_EVENT_SUMMONED_UNIT_EVADE:
return true;
default:
return false;
@@ -454,6 +455,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_ROLE_SELECTION:
case SMART_TARGET_LOOT_RECIPIENTS:
case SMART_EVENT_SUMMONED_UNIT_DIES:
case SMART_EVENT_SUMMONED_UNIT_EVADE:
case SMART_TARGET_PLAYER_RANGE:
case SMART_TARGET_CLOSEST_GAMEOBJECT:
case SMART_TARGET_SELF:
@@ -571,6 +573,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
case SMART_EVENT_NEAR_UNIT_NEGATION: return sizeof(SmartEvent::nearUnitNegation);
case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::minMaxRepeat);
case SMART_EVENT_AREA_RANGE: return sizeof(SmartEvent::minMaxRepeat);
case SMART_EVENT_SUMMONED_UNIT_EVADE: return sizeof(SmartEvent::summoned);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType());
@@ -1060,6 +1063,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_EVENT_SUMMON_DESPAWNED:
case SMART_EVENT_SUMMONED_UNIT:
case SMART_EVENT_SUMMONED_UNIT_DIES:
case SMART_EVENT_SUMMONED_UNIT_EVADE:
if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature))
return false;

View File

@@ -212,8 +212,9 @@ enum SMART_EVENT
SMART_EVENT_NEAR_UNIT_NEGATION = 104, // type (0: creature 1: gob), entry, count, range, timer
SMART_EVENT_AREA_CASTING = 105, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
SMART_EVENT_AREA_RANGE = 106, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
SMART_EVENT_SUMMONED_UNIT_EVADE = 107, // CreatureId(0 all), CooldownMin, CooldownMax
SMART_EVENT_AC_END = 107
SMART_EVENT_AC_END = 108
};
struct SmartEvent
@@ -1840,7 +1841,8 @@ const uint32 SmartAIEventMask[SMART_EVENT_AC_END][2] =
{SMART_EVENT_NEAR_UNIT, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_NEAR_UNIT_NEGATION, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_AREA_CASTING, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_AREA_RANGE, SMART_SCRIPT_TYPE_MASK_CREATURE }
{SMART_EVENT_AREA_RANGE, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_SUMMONED_UNIT_EVADE, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
};
enum SmartEventFlags

View File

@@ -2883,6 +2883,22 @@ void WorldObject::PlayDirectSound(uint32 sound_id, Player* target /*= nullptr*/)
SendMessageToSet(WorldPackets::Misc::Playsound(sound_id).Write(), true);
}
void WorldObject::PlayRadiusSound(uint32 sound_id, float radius)
{
std::list<Player*> targets;
Acore::AnyPlayerInObjectRangeCheck check(this, radius, false);
Acore::PlayerListSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
Cell::VisitWorldObjects(this, searcher, radius);
for (Player* player : targets)
{
if (player)
{
player->SendDirectMessage(WorldPackets::Misc::Playsound(sound_id).Write());
}
}
}
void WorldObject::PlayDirectMusic(uint32 music_id, Player* target /*= nullptr*/)
{
if (target)
@@ -2895,6 +2911,22 @@ void WorldObject::PlayDirectMusic(uint32 music_id, Player* target /*= nullptr*/)
}
}
void WorldObject::PlayRadiusMusic(uint32 music_id, float radius)
{
std::list<Player*> targets;
Acore::AnyPlayerInObjectRangeCheck check(this, radius, false);
Acore::PlayerListSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
Cell::VisitWorldObjects(this, searcher, radius);
for (Player* player : targets)
{
if (player)
{
player->SendDirectMessage(WorldPackets::Misc::PlayMusic(music_id).Write());
}
}
}
void WorldObject::DestroyForNearbyPlayers()
{
if (!IsInWorld())

View File

@@ -487,7 +487,9 @@ public:
void PlayDistanceSound(uint32 sound_id, Player* target = nullptr);
void PlayDirectSound(uint32 sound_id, Player* target = nullptr);
void PlayRadiusSound(uint32 sound_id, float radius);
void PlayDirectMusic(uint32 music_id, Player* target = nullptr);
void PlayRadiusMusic(uint32 music_id, float radius);
void SendObjectDeSpawnAnim(ObjectGuid guid);

View File

@@ -86,11 +86,12 @@ struct boss_the_lurker_below : public BossAI
{
if (action == ACTION_START_EVENT)
{
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->setAttackTimer(BASE_ATTACK, 6000);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetInCombatWithZone();
me->SetStandState(UNIT_STAND_STATE_STAND);
}
}
@@ -135,7 +136,7 @@ struct boss_the_lurker_below : public BossAI
me->SetFacingToObject(me->GetVictim());
me->SetTarget();
scheduler.RescheduleGroup(GROUP_GEYSER, 25s);
scheduler.RescheduleGroup(GROUP_WHIRL, 18s);
scheduler.RescheduleGroup(GROUP_WHIRL, 20s);
scheduler.Schedule(3s, [this](TaskContext)
{
me->InterruptNonMeleeSpells(false);
@@ -146,7 +147,7 @@ struct boss_the_lurker_below : public BossAI
{
//phase2
scheduler.CancelAll();
DoCastSelf(SPELL_SUBMERGE_VISUAL, true);
DoCastSelf(SPELL_SUBMERGE_VISUAL);
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS, true);
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
@@ -225,7 +226,7 @@ public:
if (roll_chance_i(instance->GetBossState(DATA_THE_LURKER_BELOW) != DONE ? 25 : 0) && !instance->IsEncounterInProgress())
{
player->CastSpell(player, SPELL_LURKER_SPAWN_TRIGGER, true);
if (Creature* lurker = go->SummonCreature(NPC_THE_LURKER_BELOW, 40.4058f, -417.108f, -21.5911f, 3.03312f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 604800000))
if (Creature* lurker = go->SummonCreature(NPC_THE_LURKER_BELOW, 38.4567f, -417.324f, -18.916666f, 2.94960f, TEMPSUMMON_MANUAL_DESPAWN))
lurker->AI()->DoAction(ACTION_START_EVENT);
return true;
}
@@ -243,6 +244,11 @@ class spell_lurker_below_spout : public AuraScript
SetDuration(16000);
}
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& /*isPeriodic*/, int32& amplitude)
{
amplitude = 250;
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* creature = GetUnitOwner()->ToCreature())
@@ -265,6 +271,7 @@ class spell_lurker_below_spout : public AuraScript
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_lurker_below_spout::CalcPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
OnEffectApply += AuraEffectApplyFn(spell_lurker_below_spout::HandleEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_lurker_below_spout::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_lurker_below_spout::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
@@ -277,22 +284,9 @@ class spell_lurker_below_spout_cone : public SpellScript
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject const* target) -> bool
targets.remove_if([this](WorldObject const* target) -> bool
{
if (!caster->HasInLine(target, 5.0f) || !target->IsPlayer())
{
return true;
}
LiquidData const& liquidData = target->GetLiquidData();
if (liquidData.Status == LIQUID_MAP_UNDER_WATER)
{
return true;
}
return false;
return !GetCaster()->HasInLine(target, 5.0f) || !target->IsPlayer() || target->ToUnit()->IsInWater();
});
}

View File

@@ -22,6 +22,7 @@
#include "SpellScriptLoader.h"
#include "TemporarySummon.h"
#include "serpent_shrine.h"
#include "ScriptedCreature.h"
DoorData const doorData[] =
{
@@ -308,6 +309,52 @@ class spell_serpentshrine_cavern_coilfang_water : public AuraScript
}
};
struct npc_rancid_mushroom : public ScriptedAI
{
npc_rancid_mushroom(Creature* creature) : ScriptedAI(creature) { }
enum Spells : uint32
{
SPELL_GROW = 31698,
SPELL_SPORE_CLOUD = 38652
};
void InitializeAI() override
{
scheduler.Schedule(1150ms, [this](TaskContext context)
{
DoCastSelf(SPELL_GROW);
context.Repeat(1200ms, 3400ms);
})
.Schedule(22950ms, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_SPORE_CLOUD);
me->KillSelf();
});
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
}
};
class spell_rancid_spore_cloud : public AuraScript
{
PrepareAuraScript(spell_rancid_spore_cloud);
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
GetCaster()->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_rancid_spore_cloud::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
void AddSC_instance_serpentshrine_cavern()
{
new instance_serpent_shrine();
@@ -315,5 +362,7 @@ void AddSC_instance_serpentshrine_cavern()
RegisterSpellAndAuraScriptPair(spell_serpentshrine_cavern_serpentshrine_parasite_trigger, spell_serpentshrine_cavern_serpentshrine_parasite_trigger_aura);
RegisterSpellScript(spell_serpentshrine_cavern_infection);
RegisterSpellScript(spell_serpentshrine_cavern_coilfang_water);
RegisterSerpentShrineAI(npc_rancid_mushroom);
RegisterSpellScript(spell_rancid_spore_cloud);
}