root/trunk/src/bindings/scripts/include/sc_creature.cpp

Revision 279, 27.1 kB (checked in by yumileroy, 17 years ago)

Merged commit 269 (5f0e38da128a).

Original author: gvcoman
Date: 2008-11-21 14:34:05-05:00

Line 
1/* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
2 *
3 * Thanks to the original authors: ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
4 *
5 * This program is free software licensed under GPL version 2
6 * Please see the included DOCS/LICENSE.TXT for more information */
7
8#include "precompiled.h"
9#include "Item.h"
10#include "Spell.h"
11
12// Spell summary for ScriptedAI::SelectSpell
13struct TSpellSummary {
14    uint8 Targets;                                          // set of enum SelectTarget
15    uint8 Effects;                                          // set of enum SelectEffect
16} *SpellSummary;
17
18void SummonList::Despawn(Creature *summon)
19{
20    uint64 guid = summon->GetGUID();
21    for(iterator i = begin(); i != end(); ++i)
22    {
23        if(*i == guid)
24        {
25            erase(i);
26            return;
27        }
28    }
29}
30
31void SummonList::DespawnEntry(uint32 entry)
32{
33    for(iterator i = begin(); i != end(); ++i)
34    {
35        if(Creature *summon = (Creature*)Unit::GetUnit(*m_creature, *i))
36        {
37            if(summon->GetEntry() == entry)
38            {
39                summon->setDeathState(JUST_DIED);
40                summon->RemoveCorpse();
41                i = erase(i);
42                --i;
43            }
44        }
45        else
46        {
47            i = erase(i);
48            --i;
49        }
50    }
51}
52
53void SummonList::DespawnAll()
54{
55    for(iterator i = begin(); i != end(); ++i)
56    {
57        if(Creature *summon = (Creature*)Unit::GetUnit(*m_creature, *i))
58        {
59            summon->setDeathState(JUST_DIED);
60            summon->RemoveCorpse();
61        }
62    }
63    clear();
64}
65
66bool ScriptedAI::IsVisible(Unit* who) const
67{
68    if (!who)
69        return false;
70
71    return (m_creature->GetDistance(who) < VISIBLE_RANGE) && who->isVisibleForOrDetect(m_creature,true);
72}
73
74void ScriptedAI::MoveInLineOfSight(Unit *who)
75{
76    if(!m_creature->getVictim() && m_creature->canStartAttack(who))
77        AttackStart(who);
78}
79
80void ScriptedAI::AttackStart(Unit* who, bool melee)
81{
82    if (!who)
83        return;
84
85    if (m_creature->Attack(who, melee))
86    {
87        m_creature->AddThreat(who, 0.0f);
88        m_creature->SetInCombatWith(who);
89        who->SetInCombatWith(m_creature);
90
91        if (!InCombat)
92        {
93            InCombat = true;
94            Aggro(who);
95        }
96
97        if(melee)
98            DoStartMovement(who);
99        else
100            DoStartNoMovement(who);
101    }
102}
103
104void ScriptedAI::AttackStart(Unit* who)
105{
106    if (!who)
107        return;
108
109    if (m_creature->Attack(who, true))
110    {
111        m_creature->AddThreat(who, 0.0f);
112        m_creature->SetInCombatWith(who);
113        who->SetInCombatWith(m_creature);
114
115        if (!InCombat)
116        {
117            InCombat = true;
118            Aggro(who);
119        }
120
121        DoStartMovement(who);
122    }
123}
124
125void ScriptedAI::UpdateAI(const uint32 diff)
126{
127    //Check if we have a current target
128    if (m_creature->isAlive() && m_creature->SelectHostilTarget() && m_creature->getVictim())
129    {
130        if (m_creature->isAttackReady() )
131        {
132            //If we are within range melee the target
133            if (m_creature->IsWithinCombatDist(m_creature->getVictim(), ATTACK_DISTANCE))
134            {
135                m_creature->AttackerStateUpdate(m_creature->getVictim());
136                m_creature->resetAttackTimer();
137            }
138        }
139    }
140}
141
142void ScriptedAI::EnterEvadeMode()
143{
144    m_creature->InterruptNonMeleeSpells(true);
145    m_creature->RemoveAllAuras();
146    m_creature->DeleteThreatList();
147    m_creature->CombatStop();
148    m_creature->LoadCreaturesAddon();
149
150    if (m_creature->isAlive())
151        m_creature->GetMotionMaster()->MoveTargetedHome();
152
153    m_creature->SetLootRecipient(NULL);
154
155    InCombat = false;
156    Reset();
157}
158
159void ScriptedAI::JustRespawned()
160{
161    InCombat = false;
162    Reset();
163}
164
165void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle)
166{
167    if (!victim)
168        return;
169
170    m_creature->GetMotionMaster()->MoveChase(victim, distance, angle);
171}
172
173void ScriptedAI::DoStartNoMovement(Unit* victim)
174{
175    if (!victim)
176        return;
177
178    m_creature->GetMotionMaster()->MoveIdle();
179    m_creature->StopMoving();
180}
181
182
183void ScriptedAI::DoMeleeAttackIfReady()
184{
185    //Make sure our attack is ready and we aren't currently casting before checking distance
186    if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))
187    {
188        //If we are within range melee the target
189        if (m_creature->IsWithinCombatDist(m_creature->getVictim(), ATTACK_DISTANCE))
190        {
191            m_creature->AttackerStateUpdate(m_creature->getVictim());
192            m_creature->resetAttackTimer();
193        }
194    }
195    if (m_creature->haveOffhandWeapon() && m_creature->isAttackReady(OFF_ATTACK) && !m_creature->IsNonMeleeSpellCasted(false))
196    {
197        //If we are within range melee the target
198        if (m_creature->IsWithinCombatDist(m_creature->getVictim(), ATTACK_DISTANCE))
199        {
200            m_creature->AttackerStateUpdate(m_creature->getVictim(), OFF_ATTACK);
201            m_creature->resetAttackTimer(OFF_ATTACK);
202        }
203    }
204}
205
206void ScriptedAI::DoStopAttack()
207{
208    if (m_creature->getVictim() != NULL)
209    {
210        m_creature->AttackStop();
211    }
212}
213
214void ScriptedAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
215{
216    if (!victim || m_creature->IsNonMeleeSpellCasted(false))
217        return;
218
219    m_creature->StopMoving();
220    m_creature->CastSpell(victim, spellId, triggered);
221}
222
223void ScriptedAI::DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered)
224{
225    if (!who || m_creature->IsNonMeleeSpellCasted(false))
226        return;
227
228    m_creature->StopMoving();
229    m_creature->CastSpell(who, spellInfo, triggered);
230}
231
232void ScriptedAI::DoSay(const char* text, uint32 language, Unit* target)
233{
234    if (target) m_creature->Say(text, language, target->GetGUID());
235    else m_creature->Say(text, language, 0);
236}
237
238void ScriptedAI::DoYell(const char* text, uint32 language, Unit* target)
239{
240    if (target) m_creature->Yell(text, language, target->GetGUID());
241    else m_creature->Yell(text, language, 0);
242}
243
244void ScriptedAI::DoTextEmote(const char* text, Unit* target, bool IsBossEmote)
245{
246    if (target) m_creature->TextEmote(text, target->GetGUID(), IsBossEmote);
247    else m_creature->TextEmote(text, 0, IsBossEmote);
248}
249
250void ScriptedAI::DoWhisper(const char* text, Unit* reciever, bool IsBossWhisper)
251{
252    if (!reciever || reciever->GetTypeId() != TYPEID_PLAYER)
253        return;
254
255    m_creature->Whisper(text, reciever->GetGUID(), IsBossWhisper);
256}
257
258void ScriptedAI::DoPlaySoundToSet(Unit* unit, uint32 sound)
259{
260    if (!unit)
261        return;
262
263    if (!GetSoundEntriesStore()->LookupEntry(sound))
264    {
265        error_log("SD2: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)", sound, unit->GetTypeId(), unit->GetGUID());
266        return;
267    }
268
269    WorldPacket data(4);
270    data.SetOpcode(SMSG_PLAY_SOUND);
271    data << uint32(sound);
272    unit->SendMessageToSet(&data,false);
273}
274
275Creature* ScriptedAI::DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime)
276{
277    return m_creature->SummonCreature(id,m_creature->GetPositionX() + x,m_creature->GetPositionY() + y,m_creature->GetPositionZ() + z, angle, (TempSummonType)type, despawntime);
278}
279
280Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position)
281{
282    //ThreatList m_threatlist;
283    std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
284    std::list<HostilReference*>::iterator i = m_threatlist.begin();
285    std::list<HostilReference*>::reverse_iterator r = m_threatlist.rbegin();
286
287    if (position >= m_threatlist.size() || !m_threatlist.size())
288        return NULL;
289
290    switch (target)
291    {
292    case SELECT_TARGET_RANDOM:
293        advance ( i , position +  (rand() % (m_threatlist.size() - position ) ));
294        return Unit::GetUnit((*m_creature),(*i)->getUnitGuid());
295        break;
296
297    case SELECT_TARGET_TOPAGGRO:
298        advance ( i , position);
299        return Unit::GetUnit((*m_creature),(*i)->getUnitGuid());
300        break;
301
302    case SELECT_TARGET_BOTTOMAGGRO:
303        advance ( r , position);
304        return Unit::GetUnit((*m_creature),(*r)->getUnitGuid());
305        break;
306    }
307
308    return NULL;
309}
310
311struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool>
312{
313    const Unit* me;
314    TargetDistanceOrder(const Unit* Target) : me(Target) {};
315    // functor for operator ">"
316    bool operator()(const Unit* _Left, const Unit* _Right) const
317    {
318        return (me->GetDistance(_Left) < me->GetDistance(_Right));
319    }
320};
321
322Unit* ScriptedAI::SelectUnit(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly)
323{
324    if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
325    {
326        std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList();
327        if(m_threatlist.empty()) return NULL;
328        std::list<Unit*> targetList;
329        std::list<HostilReference*>::iterator itr = m_threatlist.begin();
330        for(; itr!= m_threatlist.end(); ++itr)
331        {
332            Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
333            if(!target
334                || playerOnly && target->GetTypeId() != TYPEID_PLAYER
335                || dist && !m_creature->IsWithinDistInMap(target, dist))
336            {
337                continue;
338            }
339            targetList.push_back(target);
340        }
341        if(position >= targetList.size())
342            return NULL;
343        targetList.sort(TargetDistanceOrder(m_creature));
344        if(targetType == SELECT_TARGET_NEAREST)
345        {
346            std::list<Unit*>::iterator i = targetList.begin();
347            advance(i, position);
348            return *i;
349        }
350        else
351        {
352            std::list<Unit*>::reverse_iterator i = targetList.rbegin();
353            advance(i, position);
354            return *i;
355        }
356    }
357    else
358    {
359        std::list<HostilReference*> m_threatlist = m_creature->getThreatManager().getThreatList();
360        std::list<HostilReference*>::iterator i;
361        Unit *target;
362        while(position < m_threatlist.size())
363        {
364            if(targetType == SELECT_TARGET_BOTTOMAGGRO)
365            {
366                i = m_threatlist.end();
367                advance(i, - (int32)position - 1);
368            }
369            else
370            {
371                i = m_threatlist.begin();
372                if(targetType == SELECT_TARGET_TOPAGGRO)
373                    advance(i, position);
374                else // random
375                    advance(i, position + rand()%(m_threatlist.size() - position));
376            }
377
378            target = Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
379            if(!target
380                || playerOnly && target->GetTypeId() != TYPEID_PLAYER
381                || dist && !m_creature->IsWithinDistInMap(target, dist))
382            {
383                m_threatlist.erase(i);
384            }
385            else
386            {
387                return target;
388            }
389        }
390    }
391
392    return NULL;
393}
394
395void ScriptedAI::SelectUnitList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly)
396{
397    if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
398    {
399        std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList();
400        if(m_threatlist.empty()) return;
401        std::list<HostilReference*>::iterator itr = m_threatlist.begin();
402        for(; itr!= m_threatlist.end(); ++itr)
403        {
404            Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
405            if(!target
406                || playerOnly && target->GetTypeId() != TYPEID_PLAYER
407                || dist && !m_creature->IsWithinDistInMap(target, dist))
408            {
409                continue;
410            }
411            targetList.push_back(target);
412        }
413        targetList.sort(TargetDistanceOrder(m_creature));
414        targetList.resize(num);
415        if(targetType == SELECT_TARGET_FARTHEST)
416            targetList.reverse();
417    }
418    else
419    {
420        std::list<HostilReference*> m_threatlist = m_creature->getThreatManager().getThreatList();
421        std::list<HostilReference*>::iterator i;
422        Unit *target;
423        while(m_threatlist.size())
424        {
425            if(targetType == SELECT_TARGET_BOTTOMAGGRO)
426            {
427                i = m_threatlist.end();
428                --i;
429            }
430            else
431            {
432                i = m_threatlist.begin();
433                if(targetType == SELECT_TARGET_RANDOM)
434                    advance(i, rand()%m_threatlist.size());
435            }
436
437            target = Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
438            m_threatlist.erase(i);
439            if(!target
440                || playerOnly && target->GetTypeId() != TYPEID_PLAYER
441                || dist && !m_creature->IsWithinDistInMap(target, dist))
442            {
443                continue;               
444            }
445            targetList.push_back(target);
446        }
447    }
448}
449
450SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects)
451{
452    //No target so we can't cast
453    if (!Target)
454        return false;
455
456    //Silenced so we can't cast
457    if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
458        return false;
459
460    //Using the extended script system we first create a list of viable spells
461    SpellEntry const* Spell[4];
462    Spell[0] = 0;
463    Spell[1] = 0;
464    Spell[2] = 0;
465    Spell[3] = 0;
466
467    uint32 SpellCount = 0;
468
469    SpellEntry const* TempSpell;
470    SpellRangeEntry const* TempRange;
471
472    //Check if each spell is viable(set it to null if not)
473    for (uint32 i = 0; i < 4; i++)
474    {
475        TempSpell = GetSpellStore()->LookupEntry(m_creature->m_spells[i]);
476
477        //This spell doesn't exist
478        if (!TempSpell)
479            continue;
480
481        // Targets and Effects checked first as most used restrictions
482        //Check the spell targets if specified
483        if ( Targets && !(SpellSummary[m_creature->m_spells[i]].Targets & (1 << (Targets-1))) )
484            continue;
485
486        //Check the type of spell if we are looking for a specific spell type
487        if ( Effects && !(SpellSummary[m_creature->m_spells[i]].Effects & (1 << (Effects-1))) )
488            continue;
489
490        //Check for school if specified
491        if (School >= 0 && TempSpell->SchoolMask & School)
492            continue;
493
494        //Check for spell mechanic if specified
495        if (Mechanic >= 0 && TempSpell->Mechanic != Mechanic)
496            continue;
497
498        //Make sure that the spell uses the requested amount of power
499        if (PowerCostMin &&  TempSpell->manaCost < PowerCostMin)
500            continue;
501
502        if (PowerCostMax && TempSpell->manaCost > PowerCostMax)
503            continue;
504
505        //Continue if we don't have the mana to actually cast this spell
506        if (TempSpell->manaCost > m_creature->GetPower((Powers)TempSpell->powerType))
507            continue;
508
509        //Get the Range
510        TempRange = GetSpellRangeStore()->LookupEntry(TempSpell->rangeIndex);
511
512        //Spell has invalid range store so we can't use it
513        if (!TempRange)
514            continue;
515
516        //Check if the spell meets our range requirements
517        if (RangeMin && TempRange->maxRange < RangeMin)
518            continue;
519        if (RangeMax && TempRange->maxRange > RangeMax)
520            continue;
521
522        //Check if our target is in range
523        if (m_creature->IsWithinDistInMap(Target, TempRange->minRange) || !m_creature->IsWithinDistInMap(Target, TempRange->maxRange))
524            continue;
525
526        //All good so lets add it to the spell list
527        Spell[SpellCount] = TempSpell;
528        SpellCount++;
529    }
530
531    //We got our usable spells so now lets randomly pick one
532    if (!SpellCount)
533        return NULL;
534
535    return Spell[rand()%SpellCount];
536}
537
538bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered)
539{
540    //No target so we can't cast
541    if (!Target || !Spell)
542        return false;
543
544    //Silenced so we can't cast
545    if (!Triggered && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
546        return false;
547
548    //Check for power
549    if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell->manaCost)
550        return false;
551
552    SpellRangeEntry const *TempRange = NULL;
553
554    TempRange = GetSpellRangeStore()->LookupEntry(Spell->rangeIndex);
555
556    //Spell has invalid range store so we can't use it
557    if (!TempRange)
558        return false;
559
560    //Unit is out of range of this spell
561    if (m_creature->GetDistance(Target) > TempRange->maxRange || m_creature->GetDistance(Target) < TempRange->minRange)
562        return false;
563
564    return true;
565}
566
567void FillSpellSummary()
568{
569    SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()];
570
571    SpellEntry const* TempSpell;
572
573    for (int i=0; i < GetSpellStore()->GetNumRows(); i++ )
574    {
575        SpellSummary[i].Effects = 0;
576        SpellSummary[i].Targets = 0;
577
578        TempSpell = GetSpellStore()->LookupEntry(i);
579        //This spell doesn't exist
580        if (!TempSpell)
581            continue;
582
583        for (int j=0; j<3; j++)
584        {
585            //Spell targets self
586            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF )
587                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1);
588
589            //Spell targets a single enemy
590            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE ||
591                TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES )
592                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1);
593
594            //Spell targets AoE at enemy
595            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA ||
596                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
597                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER ||
598                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED )
599                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1);
600
601            //Spell targets an enemy
602            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE ||
603                TempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES ||
604                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA ||
605                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
606                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER ||
607                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED )
608                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1);
609
610            //Spell targets a single friend(or self)
611            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF ||
612                TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND ||
613                TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY )
614                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1);
615
616            //Spell targets aoe friends
617            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER ||
618                TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY ||
619                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER)
620                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1);
621
622            //Spell targets any friend(or self)
623            if ( TempSpell->EffectImplicitTargetA[j] == TARGET_SELF ||
624                TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND ||
625                TempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY ||
626                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER ||
627                TempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY ||
628                TempSpell->EffectImplicitTargetA[j] == TARGET_ALL_AROUND_CASTER)
629                SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1);
630
631            //Make sure that this spell includes a damage effect
632            if ( TempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || 
633                TempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || 
634                TempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || 
635                TempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH )
636                SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1);
637
638            //Make sure that this spell includes a healing effect (or an apply aura with a periodic heal)
639            if ( TempSpell->Effect[j] == SPELL_EFFECT_HEAL || 
640                TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || 
641                TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL ||
642                (TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA  && TempSpell->EffectApplyAuraName[j]== 8 ))
643                SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1);
644
645            //Make sure that this spell applies an aura
646            if ( TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA )
647                SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1);
648        }
649    }
650}
651
652void ScriptedAI::DoZoneInCombat(Unit* pUnit)
653{
654    if (!pUnit)
655        pUnit = m_creature;
656
657    Map *map = pUnit->GetMap();
658
659    if (!map->IsDungeon())                                  //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
660    {
661        error_log("SD2: DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
662        return;
663    }
664
665    if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty())
666    {
667        error_log("SD2: DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
668
669        return;
670    }
671
672    Map::PlayerList const &PlayerList = map->GetPlayers();
673    for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
674        if (Player* i_pl = i->getSource())
675            if (!i_pl->isAlive())
676                pUnit->AddThreat(i_pl, 0.0f);
677}
678
679void ScriptedAI::DoResetThreat()
680{
681    if (!m_creature->CanHaveThreatList() || m_creature->getThreatManager().isThreatListEmpty())
682    {
683        error_log("SD2: DoResetThreat called for creature that either cannot have threat list or has empty threat list (m_creature entry = %d)", m_creature->GetEntry());
684
685        return;
686    }
687
688    std::list<HostilReference*>& m_threatlist = m_creature->getThreatManager().getThreatList();
689    std::list<HostilReference*>::iterator itr;
690
691    for(itr = m_threatlist.begin(); itr != m_threatlist.end(); ++itr)
692    {
693        Unit* pUnit = NULL;
694        pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid());
695        if(pUnit && m_creature->getThreatManager().getThreat(pUnit))
696            m_creature->getThreatManager().modifyThreatPercent(pUnit, -100);
697    }
698}
699
700void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o)
701{
702    if(!pUnit || pUnit->GetTypeId() != TYPEID_PLAYER)
703    {
704        if(pUnit)
705            error_log("SD2: Creature %u (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: %u) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGUID(), m_creature->GetEntry(), pUnit->GetTypeId(), pUnit->GetGUID(), x, y, z, o);
706        return;
707    }
708
709    ((Player*)pUnit)->TeleportTo(pUnit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT);
710}
711
712void ScriptedAI::DoTeleportAll(float x, float y, float z, float o)
713{
714    Map *map = m_creature->GetMap();
715    if (!map->IsDungeon())
716        return;
717
718    Map::PlayerList const &PlayerList = map->GetPlayers();
719    for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
720        if (Player* i_pl = i->getSource())
721            if (!i_pl->isAlive())
722                i_pl->TeleportTo(m_creature->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT);
723}
724
725
726Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff)
727{
728    CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
729    Cell cell(p);
730    cell.data.Part.reserved = ALL_DISTRICT;
731    cell.SetNoCreate();
732
733    Unit* pUnit = NULL;
734
735    Trinity::MostHPMissingInRange u_check(m_creature, range, MinHPDiff);
736    Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(pUnit, u_check);
737
738    /*
739    typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes;
740    This means that if we only search grid then we cannot possibly return pets or players so this is safe
741    */
742    TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange>, GridTypeMapContainer >  grid_unit_searcher(searcher);
743
744    CellLock<GridReadGuard> cell_lock(cell, p);
745    cell_lock->Visit(cell_lock, grid_unit_searcher, *(m_creature->GetMap()));
746    return pUnit;
747}
748
749std::list<Creature*> ScriptedAI::DoFindFriendlyCC(float range)
750{
751    CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
752    Cell cell(p);
753    cell.data.Part.reserved = ALL_DISTRICT;
754    cell.SetNoCreate();
755
756    std::list<Creature*> pList;
757
758    Trinity::FriendlyCCedInRange u_check(m_creature, range);
759    Trinity::CreatureListSearcher<Trinity::FriendlyCCedInRange> searcher(pList, u_check);
760
761    TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::FriendlyCCedInRange>, GridTypeMapContainer >  grid_creature_searcher(searcher);
762
763    CellLock<GridReadGuard> cell_lock(cell, p);
764    cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap()));
765   
766    return pList;
767}
768
769std::list<Creature*> ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 spellid)
770{
771    CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY()));
772    Cell cell(p);
773    cell.data.Part.reserved = ALL_DISTRICT;
774    cell.SetNoCreate();
775
776    std::list<Creature*> pList;
777
778    Trinity::FriendlyMissingBuffInRange u_check(m_creature, range, spellid);
779    Trinity::CreatureListSearcher<Trinity::FriendlyMissingBuffInRange> searcher(pList, u_check);
780
781    TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::FriendlyMissingBuffInRange>, GridTypeMapContainer >  grid_creature_searcher(searcher);
782
783    CellLock<GridReadGuard> cell_lock(cell, p);
784    cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap()));
785   
786    return pList;
787}
788
789void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who)
790{
791    if( !m_creature->getVictim() && m_creature->canAttack(who) && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
792    {
793        if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
794            return;
795
796        float attackRadius = m_creature->GetAttackDistance(who);
797        if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
798        {
799            who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
800            AttackStart(who);
801        }
802    }
803}
804
805void Scripted_NoMovementAI::AttackStart(Unit* who)
806{
807    if (!who)
808        return;
809
810    if (m_creature->Attack(who, true))
811    {
812        m_creature->AddThreat(who, 0.0f);
813        m_creature->SetInCombatWith(who);
814        who->SetInCombatWith(m_creature);
815
816        if (!InCombat)
817        {
818            InCombat = true;
819            Aggro(who);
820        }
821
822        DoStartNoMovement(who);
823    }
824}
Note: See TracBrowser for help on using the browser.