aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/World/npcs_special.cpp272
1 files changed, 101 insertions, 171 deletions
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index dade8cb14be..f15429b0e9c 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -43,57 +43,53 @@
# npc_air_force_bots
#########*/
-enum SpawnType
-{
- SPAWNTYPE_TRIPWIRE_ROOFTOP, // no warning, summon Creature at smaller range
- SPAWNTYPE_ALARMBOT, // cast guards mark and summon npc - if player shows up with that buff duration < 5 seconds attack
-};
-
-struct SpawnAssociation
-{
- uint32 thisCreatureEntry;
- uint32 spawnedCreatureEntry;
- SpawnType spawnType;
-};
-
-enum AirFoceBots
-{
- SPELL_GUARDS_MARK = 38067,
- AURA_DURATION_TIME_LEFT = 30000
-};
-
-float const RANGE_TRIPWIRE = 15.0f;
-float const RANGE_GUARDS_MARK = 100.0f;
-
-SpawnAssociation spawnAssociations[] =
-{
- {2614, 15241, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Alliance)
- {2615, 15242, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Horde)
- {21974, 21976, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Area 52)
- {21993, 15242, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Horde - Bat Rider)
- {21996, 15241, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Alliance - Gryphon)
- {21997, 21976, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Goblin - Area 52 - Zeppelin)
- {21999, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Alliance)
- {22001, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Horde)
- {22002, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Ground (Horde)
- {22003, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Ground (Alliance)
- {22063, 21976, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Goblin - Area 52)
- {22065, 22064, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Ethereal - Stormspire)
- {22066, 22067, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Scryer - Dragonhawk)
- {22068, 22064, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Ethereal - Stormspire)
- {22069, 22064, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Stormspire)
- {22070, 22067, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Scryer)
- {22071, 22067, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Scryer)
- {22078, 22077, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Aldor)
- {22079, 22077, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Aldor - Gryphon)
- {22080, 22077, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Aldor)
- {22086, 22085, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Sporeggar)
- {22087, 22085, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Sporeggar - Spore Bat)
- {22088, 22085, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Sporeggar)
- {22090, 22089, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Toshley's Station - Flying Machine)
- {22124, 22122, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Cenarion)
- {22125, 22122, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Cenarion - Stormcrow)
- {22126, 22122, SPAWNTYPE_ALARMBOT} //Air Force Trip Wire - Rooftop (Cenarion Expedition)
+enum AirForceBots
+{
+ TRIPWIRE, // do not attack flying players, smaller range
+ ALARMBOT, // attack flying players, casts guard's mark
+
+ SPELL_GUARDS_MARK = 38067
+};
+
+float constexpr RANGE_TRIPWIRE = 15.0f;
+float constexpr RANGE_ALARMBOT = 100.0f;
+
+struct AirForceSpawn
+{
+ uint32 myEntry;
+ uint32 otherEntry;
+ AirForceBots type;
+};
+
+AirForceSpawn constexpr airforceSpawns[] =
+{
+ {2614, 15241, ALARMBOT}, // Air Force Alarm Bot (Alliance)
+ {2615, 15242, ALARMBOT}, // Air Force Alarm Bot (Horde)
+ {21974, 21976, ALARMBOT}, // Air Force Alarm Bot (Area 52)
+ {21993, 15242, ALARMBOT}, // Air Force Guard Post (Horde - Bat Rider)
+ {21996, 15241, ALARMBOT}, // Air Force Guard Post (Alliance - Gryphon)
+ {21997, 21976, ALARMBOT}, // Air Force Guard Post (Goblin - Area 52 - Zeppelin)
+ {21999, 15241, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Alliance)
+ {22001, 15242, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Horde)
+ {22002, 15242, TRIPWIRE}, // Air Force Trip Wire - Ground (Horde)
+ {22003, 15241, TRIPWIRE}, // Air Force Trip Wire - Ground (Alliance)
+ {22063, 21976, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Goblin - Area 52)
+ {22065, 22064, ALARMBOT}, // Air Force Guard Post (Ethereal - Stormspire)
+ {22066, 22067, ALARMBOT}, // Air Force Guard Post (Scryer - Dragonhawk)
+ {22068, 22064, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Ethereal - Stormspire)
+ {22069, 22064, ALARMBOT}, // Air Force Alarm Bot (Stormspire)
+ {22070, 22067, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Scryer)
+ {22071, 22067, ALARMBOT}, // Air Force Alarm Bot (Scryer)
+ {22078, 22077, ALARMBOT}, // Air Force Alarm Bot (Aldor)
+ {22079, 22077, ALARMBOT}, // Air Force Guard Post (Aldor - Gryphon)
+ {22080, 22077, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Aldor)
+ {22086, 22085, ALARMBOT}, // Air Force Alarm Bot (Sporeggar)
+ {22087, 22085, ALARMBOT}, // Air Force Guard Post (Sporeggar - Spore Bat)
+ {22088, 22085, TRIPWIRE}, // Air Force Trip Wire - Rooftop (Sporeggar)
+ {22090, 22089, ALARMBOT}, // Air Force Guard Post (Toshley's Station - Flying Machine)
+ {22124, 22122, ALARMBOT}, // Air Force Alarm Bot (Cenarion)
+ {22125, 22122, ALARMBOT}, // Air Force Guard Post (Cenarion - Stormcrow)
+ {22126, 22122, ALARMBOT} // Air Force Trip Wire - Rooftop (Cenarion Expedition)
};
class npc_air_force_bots : public CreatureScript
@@ -101,157 +97,91 @@ class npc_air_force_bots : public CreatureScript
public:
npc_air_force_bots() : CreatureScript("npc_air_force_bots") { }
- struct npc_air_force_botsAI : public ScriptedAI
+ struct npc_air_force_botsAI : public NullCreatureAI
{
- npc_air_force_botsAI(Creature* creature) : ScriptedAI(creature)
+ static AirForceSpawn const& FindSpawnFor(uint32 entry)
{
- SpawnAssoc = nullptr;
- SpawnedGUID.Clear();
-
- // find the correct spawnhandling
- static uint8 constexpr const EntryCount = uint8(std::extent<decltype(spawnAssociations)>::value);
-
- for (uint8 i = 0; i < EntryCount; ++i)
- {
- if (spawnAssociations[i].thisCreatureEntry == creature->GetEntry())
- {
- SpawnAssoc = &spawnAssociations[i];
- break;
- }
- }
-
- if (!SpawnAssoc)
- TC_LOG_ERROR("sql.sql", "TCSR: Creature template entry %u has ScriptName npc_air_force_bots, but it's not handled by that script", creature->GetEntry());
- else
+ for (AirForceSpawn const& spawn : airforceSpawns)
{
- CreatureTemplate const* spawnedTemplate = sObjectMgr->GetCreatureTemplate(SpawnAssoc->spawnedCreatureEntry);
-
- if (!spawnedTemplate)
+ if (spawn.myEntry == entry)
{
- TC_LOG_ERROR("sql.sql", "TCSR: Creature template entry %u does not exist in DB, which is required by npc_air_force_bots", SpawnAssoc->spawnedCreatureEntry);
- SpawnAssoc = nullptr;
- return;
+ ASSERT_NODEBUGINFO(sObjectMgr->GetCreatureTemplate(spawn.otherEntry), "Invalid creature entry %u in 'npc_air_force_bots' script", spawn.otherEntry);
+ return spawn;
}
}
+ ASSERT_NODEBUGINFO(false, "Unhandled creature with entry %u is assigned 'npc_air_force_bots' script", entry);
}
- SpawnAssociation* SpawnAssoc;
- ObjectGuid SpawnedGUID;
+ npc_air_force_botsAI(Creature* creature) : NullCreatureAI(creature), _spawn(FindSpawnFor(creature->GetEntry())) {}
- void Reset() override { }
-
- Creature* SummonGuard()
+ Creature* GetOrSummonGuard()
{
- Creature* summoned = me->SummonCreature(SpawnAssoc->spawnedCreatureEntry, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
+ Creature* guard = ObjectAccessor::GetCreature(*me, _myGuard);
- if (summoned)
- SpawnedGUID = summoned->GetGUID();
- else
- {
- TC_LOG_ERROR("sql.sql", "TCSR: npc_air_force_bots: wasn't able to spawn Creature %u", SpawnAssoc->spawnedCreatureEntry);
- SpawnAssoc = nullptr;
- }
+ if (!guard && (guard = me->SummonCreature(_spawn.otherEntry, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000)))
+ _myGuard = guard->GetGUID();
- return summoned;
+ return guard;
}
- Creature* GetSummonedGuard()
+ void UpdateAI(uint32 /*diff*/) override
{
- Creature* creature = ObjectAccessor::GetCreature(*me, SpawnedGUID);
-
- if (creature && creature->IsAlive())
- return creature;
+ if (_toAttack.empty())
+ return;
- return nullptr;
- }
+ Creature* guard = GetOrSummonGuard();
+ if (!guard)
+ return;
- void UpdateAI(uint32 diff) override
- {
- ScriptedAI::UpdateAI(diff);
+ for (ObjectGuid guid : _toAttack)
+ {
+ Unit* target = ObjectAccessor::GetUnit(*me, guid);
+ if (!target)
+ continue;
+ if (guard->IsEngagedBy(target))
+ continue;
+
+ guard->EngageWithTarget(target);
+ if (_spawn.type == ALARMBOT)
+ guard->CastSpell(target, SPELL_GUARDS_MARK, true);
+ }
- inLineOfSightSinceLastUpdate.clear();
+ _toAttack.clear();
}
void MoveInLineOfSight(Unit* who) override
{
- if (!SpawnAssoc)
+ // guards are only spawned against players
+ if (who->GetTypeId() != TYPEID_PLAYER)
return;
- if (me->IsValidAttackTarget(who))
- {
- Player* playerTarget = who->ToPlayer();
-
- // airforce guards only spawn for players
- if (!playerTarget)
- return;
-
- Creature* lastSpawnedGuard = SpawnedGUID.IsEmpty() ? nullptr : GetSummonedGuard();
-
- // prevent calling Unit::GetUnit at next MoveInLineOfSight call - speedup
- if (!lastSpawnedGuard)
- SpawnedGUID.Clear();
-
- switch (SpawnAssoc->spawnType)
- {
- case SPAWNTYPE_ALARMBOT:
- {
- // handle only 1 change for world update for each target
- if (!inLineOfSightSinceLastUpdate.insert(who->GetGUID()).second)
- return;
-
- if (!who->IsWithinDistInMap(me, RANGE_GUARDS_MARK))
- return;
-
- Aura* markAura = who->GetAura(SPELL_GUARDS_MARK);
- if (markAura)
- {
- // the target wasn't able to move out of our range within 25 seconds
- if (!lastSpawnedGuard)
- {
- lastSpawnedGuard = SummonGuard();
-
- if (!lastSpawnedGuard)
- return;
- }
-
- if (markAura->GetDuration() < AURA_DURATION_TIME_LEFT)
- if (!lastSpawnedGuard->GetVictim())
- lastSpawnedGuard->AI()->AttackStart(who);
- }
- else
- {
- if (!lastSpawnedGuard)
- lastSpawnedGuard = SummonGuard();
-
- if (!lastSpawnedGuard)
- return;
+ // we're already scheduled to attack this player on our next tick, don't bother checking
+ if (_toAttack.find(who->GetGUID()) != _toAttack.end())
+ return;
- lastSpawnedGuard->CastSpell(who, SPELL_GUARDS_MARK, true);
- }
- break;
- }
- case SPAWNTYPE_TRIPWIRE_ROOFTOP:
- {
- if (!who->IsWithinDistInMap(me, RANGE_TRIPWIRE))
- return;
+ // check if they're in range
+ if (!who->IsWithinDistInMap(me, (_spawn.type == ALARMBOT) ? RANGE_ALARMBOT : RANGE_TRIPWIRE))
+ return;
- if (!lastSpawnedGuard)
- lastSpawnedGuard = SummonGuard();
+ // check if they're hostile
+ if (!(me->IsHostileTo(who) || who->IsHostileTo(me)))
+ return;
- if (!lastSpawnedGuard)
- return;
+ // check if they're a valid attack target
+ if (!me->IsValidAttackTarget(who))
+ return;
- // ROOFTOP only triggers if the player is on the ground
- if (!playerTarget->IsFlying() && !lastSpawnedGuard->GetVictim())
- lastSpawnedGuard->AI()->AttackStart(who);
+ if ((_spawn.type == TRIPWIRE) && who->IsFlying())
+ return;
- break;
- }
- }
- }
+ _toAttack.insert(who->GetGUID());
}
- GuidSet inLineOfSightSinceLastUpdate;
+ private:
+ AirForceSpawn const& _spawn;
+ ObjectGuid _myGuard;
+ std::unordered_set<ObjectGuid> _toAttack;
+
};
CreatureAI* GetAI(Creature* creature) const override