root/trunk/src/arcemu-world/Creature.cpp @ 3131

Revision 3131, 53.7 kB (checked in by Hypersniper, 8 months ago)

* APPLIED:
- Alterac Valley patch by Artox
- Copyrights patch by Terrorblade
- Earth shield patch by Jackpoz
- Energize patch by Arch1s
- Opcode fix by Sadikum
- Optional config fix by Psychobandit
- Various spells by Catti
- Various spells by Mesox/Ogchaos
- "Summon Myzrael" fix by this_is_junk
- "Torgos" fix by dzjhenghiz
- Worldstates patch by eggnrice
Good work community!

  • Property svn:eol-style set to native
  • Property ff set to
    *.cpp = svn:eol-style=native
    Makefile = svn:eol-style=native
    README = svn:eol-style=native
    CHANGELOG = svn:eol-style=native
    LICENSE = svn:eol-style=native
  • Property svn:keywords set to Date Author Rev
Line 
1/*
2 * ArcEmu MMORPG Server
3 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
4 * Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "StdAfx.h"
22
23#define M_PI       3.14159265358979323846
24
25
26///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
27// float CalcHPCoefficient( MapInfo *mi, uint32 mode, bool boss )
28//  Returns the HP coefficient that is suited for the map, mode, and creature
29//
30// Parameters:
31//  MapInfo *mi         -               pointer to the mapinfo structure
32//      uint32  mode    -               numeric representation of the version of the map (normal, heroic, 10-25 men, etc )
33//      bool    boss    -               true if the creature is a boss, false if not
34//
35// Return Values:
36//      Returns the hp coefficient in a float
37//
38///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
39float CalcHPCoefficient( MapInfo *mi, uint32 mode, bool boss ){
40        float coeff = 1.0f;
41
42        if( mi == NULL )
43                return 1.0f;
44
45        // This calculation is purely speculation as we have no way of finding out how Blizzard generates these values
46        // These cases are based on simple observation of trash/boss hp values for different modes
47        // If you know they are wrong AND you know a better calculation formula then DO change it.
48
49        // raid
50        if( mi->type == INSTANCE_RAID ){
51                bool hasheroic = false;
52
53                // check if we have heroic mode avaiable
54                if( mi->HasFlag( WMI_INSTANCE_HAS_HEROIC_10MEN ) && mi->HasFlag( WMI_INSTANCE_HAS_HEROIC_25MEN ) )
55                        hasheroic = true;
56               
57                // boss hp coeff calculations
58                if( boss == true ){
59
60                        switch( mode ){
61                                case MODE_NORMAL_10MEN:
62                                        coeff = 1.0f; break;
63
64                                case MODE_HEROIC_10MEN:
65                                        coeff = 1.25f; break;
66
67                                case MODE_NORMAL_25MEN:
68                                        if( hasheroic )
69                                                coeff = 5.0f;
70                                        else
71                                                coeff = 3.0f;
72                                        break;
73
74                                case MODE_HEROIC_25MEN:
75                                        coeff = 5.0f * 1.25f;
76                        }
77
78                        // trash hp coeff calculation
79                }else{
80                        switch( mode ){
81                                case MODE_NORMAL_10MEN:
82                                        coeff = 1.0f; break;
83
84                                case MODE_HEROIC_10MEN:
85                                        coeff = 1.5f; break;
86
87                                case MODE_NORMAL_25MEN:
88                                        coeff = 2.0f; break;
89
90                                case MODE_HEROIC_25MEN:
91                                        coeff = 2.5f; break;
92                        }
93                }
94        }
95
96        // heroic dungeon
97        if( mi->type == INSTANCE_MULTIMODE ){
98               
99                if( mode > 0 )
100                        coeff = 1.5f;
101                else
102                        coeff = 1.0f;
103        }
104
105        return coeff;
106}
107
108
109////////////////////////////////////////////////////////////////////////////////////////////////////////////
110// float CalcDMGCoefficient( MapInfo *mi, uint32 mode )
111//  Calculates the creature damage coefficient that is suitable for the map type and difficulty
112//
113// Parameters:
114//  MapInfo *mi         -               pointer to the MapInfo structure
115//  uint32 mode         -               numeric representation of the version of the map (normal, heroic, 10-25 men, etc )
116//
117// Return Value:
118//  Returns the suitable damage coefficient in a float
119//
120/////////////////////////////////////////////////////////////////////////////////////////////////////////////
121float CalcDMGCoefficient( MapInfo *mi, uint32 mode ){
122       
123        // This calculation is purely speculation as we have no way of finding out how Blizzard generates these values
124        // These cases are based on simple observation of trash/boss damage values for different modes
125        // If you know they are wrong AND you know a better calculation formula then DO change it.
126
127        if( mi == NULL )
128                return 1.0f;
129
130        switch( mode ){
131                case MODE_NORMAL_10MEN:
132                        return 1.0f; break;
133
134                case MODE_NORMAL_25MEN:
135                        if( mi->type == INSTANCE_MULTIMODE )
136                                return 1.5f;
137                        else
138                                return 2.0;
139
140                        break;
141
142                case MODE_HEROIC_10MEN:
143                        return 1.5f; break;
144
145                case MODE_HEROIC_25MEN:
146                        return 2.5f; break;
147        }
148
149        return 1.0f;
150}
151
152Creature::Creature(uint64 guid)
153{
154        proto = 0;
155        m_valuesCount = UNIT_END;
156        m_objectTypeId = TYPEID_UNIT;
157        m_uint32Values = _fields;
158        memset(m_uint32Values, 0,(UNIT_END)*sizeof(uint32));
159        m_updateMask.SetCount(UNIT_END);
160        SetUInt32Value( OBJECT_FIELD_TYPE,TYPE_UNIT|TYPE_OBJECT);
161    SetGUID( guid );
162        m_wowGuid.Init(GetGUID());
163
164
165        m_quests = NULL;
166        proto = NULL;
167        spawnid= 0;
168
169        creature_info= NULL;
170        m_H_regenTimer= 0;
171        m_P_regenTimer= 0;
172        m_useAI = true;
173        mTaxiNode = 0;
174
175        Tagged = false;
176        TaggerGuid = 0;
177
178        Skinned = false;
179    m_isPet = false;
180    m_enslaveCount = 0;
181        m_enslaveSpell = 0;
182
183        for(uint32 x= 0;x<7;x++)
184        {
185                FlatResistanceMod[x]= 0;
186                BaseResistanceModPct[x]= 0;
187                ResistanceModPct[x]= 0;
188                ModDamageDone[x]= 0;
189                ModDamageDonePct[x]=1.0;
190        }
191
192        for(uint32 x= 0;x<5;x++)
193        {
194                TotalStatModPct[x]= 0;
195                StatModPct[x]= 0;
196                FlatStatMod[x]= 0;
197        }
198
199        totemOwner = NULL;
200        totemSlot = -1;
201
202    m_owner = NULL;
203
204        m_PickPocketed = false;
205        m_SellItems = NULL;
206        _myScriptClass = NULL;
207        m_TaxiNode = 0;
208        myFamily = 0;
209
210        loot.gold = 0;
211        haslinkupevent = false;
212        original_emotestate = 0;
213        mTrainer = 0;
214        m_spawn = 0;
215        spawnid = 0;
216        auctionHouse = 0;
217        has_waypoint_text = has_combat_text = false;
218        SetAttackPowerMultiplier(0.0f);
219        SetRangedAttackPowerMultiplier(0.0f);
220        m_custom_waypoint_map = 0;
221        m_escorter = 0;
222        m_limbostate = false;
223        m_corpseEvent=false;
224        m_respawnCell= NULL;
225        m_walkSpeed = 2.5f;
226        m_runSpeed = MONSTER_NORMAL_RUN_SPEED;
227        m_base_runSpeed = m_runSpeed;
228        m_base_walkSpeed = m_walkSpeed;
229        m_noRespawn=false;
230        m_respawnTimeOverride= 0;
231    m_canRegenerateHP = true;
232        m_transportGuid = 0;
233        m_transportPosition = NULL;
234        BaseAttackType = SCHOOL_NORMAL;
235        m_lootMethod = -1;
236        m_healthfromspell = 0;
237        m_speedFromHaste = 0;
238}
239
240
241Creature::~Creature()
242{
243        sEventMgr.RemoveEvents(this);
244
245        if( IsTotem() )
246                totemOwner->m_TotemSlots[totemSlot] = 0;
247
248        if(m_custom_waypoint_map != 0)
249        {
250                for(WayPointMap::iterator itr = m_custom_waypoint_map->begin(); itr != m_custom_waypoint_map->end(); ++itr)
251                {
252                        if( (*itr) )
253                                delete (*itr);
254                }
255                //delete m_custom_waypoint_map;
256                m_custom_waypoint_map->clear();
257        }
258        if( m_respawnCell != NULL )
259                m_respawnCell->_respawnObjects.erase(this);
260
261        if (m_escorter != NULL)
262                m_escorter = NULL;
263
264        // remove our reference from owner
265        if( m_owner != NULL )
266        {
267                m_owner->RemoveGuardianRef( this );
268                m_owner = NULL;
269        }
270}
271
272void Creature::Update( uint32 p_time )
273{
274        Unit::Update( p_time );
275        if(IsTotem() && IsDead())
276        {
277        DeleteMe();
278                return;
279        }
280
281        if(m_corpseEvent)
282        {
283                sEventMgr.RemoveEvents(this);
284                if(this->GetProto()== NULL)
285                        sEventMgr.AddEvent(this, &Creature::OnRemoveCorpse, EVENT_CREATURE_REMOVE_CORPSE, 1000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
286                else if (this->creature_info->Rank == ELITE_WORLDBOSS)
287                        sEventMgr.AddEvent(this, &Creature::OnRemoveCorpse, EVENT_CREATURE_REMOVE_CORPSE, TIME_CREATURE_REMOVE_BOSSCORPSE, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
288                else if ( this->creature_info->Rank == ELITE_RAREELITE || this->creature_info->Rank == ELITE_RARE)
289                        sEventMgr.AddEvent(this, &Creature::OnRemoveCorpse, EVENT_CREATURE_REMOVE_CORPSE, TIME_CREATURE_REMOVE_RARECORPSE, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
290                else
291                        sEventMgr.AddEvent(this, &Creature::OnRemoveCorpse, EVENT_CREATURE_REMOVE_CORPSE, TIME_CREATURE_REMOVE_CORPSE, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
292
293                m_corpseEvent=false;
294        }
295}
296
297void Creature::SafeDelete()
298{
299        sEventMgr.RemoveEvents(this);
300       
301        delete this;
302}
303
304void Creature::DeleteMe()
305{
306        if(IsInWorld())
307                RemoveFromWorld(false, true);
308    else
309        SafeDelete();
310}
311
312void Creature::OnRemoveCorpse()
313{
314        // time to respawn!
315        if (IsInWorld() && (int32)m_mapMgr->GetInstanceID() == m_instanceId)
316        {
317
318                sLog.outDetail("Removing corpse of "I64FMT"...", GetGUID());
319
320                setDeathState(DEAD);
321                m_position = m_spawnLocation;
322
323                        if((GetMapMgr()->GetMapInfo() && GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID &&  proto != NULL && proto->boss) || m_noRespawn)
324                        {
325                                RemoveFromWorld(false, true);
326                        }
327                        else
328                        {
329                                if((proto && proto->RespawnTime) || m_respawnTimeOverride)
330                                        RemoveFromWorld(true, false);
331                                else
332                                        RemoveFromWorld(false, true);
333                        }
334        }
335        else
336        {
337                // if we got here it's pretty bad
338                Arcemu::Util::ARCEMU_ASSERT( false );
339        }
340}
341
342void Creature::OnRespawn(MapMgr * m)
343{
344        if( m_noRespawn )
345                return;
346
347        InstanceBossInfoMap *bossInfoMap = objmgr.m_InstanceBossInfoMap[m->GetMapId()];
348        Instance *pInstance = m->pInstance;
349        if( bossInfoMap != NULL && pInstance != NULL )
350        {
351                bool skip = false;
352                for( std::set<uint32>::iterator killedNpc = pInstance->m_killedNpcs.begin(); killedNpc != pInstance->m_killedNpcs.end(); ++killedNpc )
353                {
354                        // Is killed boss?
355                        if(creature_info && (*killedNpc) == creature_info->Id)
356                        {
357                                skip = true;
358                                break;
359                        }
360                        // Is add from killed boss?
361                        InstanceBossInfoMap::const_iterator bossInfo = bossInfoMap->find((*killedNpc));
362                        if(bossInfo != bossInfoMap->end() && bossInfo->second->trash.find(this->spawnid) != bossInfo->second->trash.end())
363                        {
364                                skip = true;
365                                break;
366                        }
367                }
368                if(skip)
369                {
370                        m_noRespawn = true;
371                        DeleteMe();
372                        return;
373                }
374        }
375
376        sLog.outDetail("Respawning "I64FMT"...", GetGUID());
377        SetHealth( GetMaxHealth());
378        SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); // not tagging shit
379        if(proto && m_spawn)
380        {
381                SetUInt32Value(UNIT_NPC_FLAGS, proto->NPCFLags);
382                SetEmoteState(m_spawn->emote_state);
383        }
384
385        RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
386        Skinned = false;
387        Tagged = false;
388        TaggerGuid = 0;
389        m_lootMethod = -1;
390
391        /* creature death state */
392        if(proto && proto->death_state == 1)
393        {
394                /*uint32 newhealth = m_uint32Values[UNIT_FIELD_HEALTH] / 100;
395                if(!newhealth)
396                        newhealth = 1;*/
397                SetHealth( 1);
398                m_limbostate = true;
399                setDeathState( CORPSE );
400                SetEmoteState(EMOTE_STATE_DEAD);
401        }
402
403        //empty loot
404        loot.items.clear();
405
406        setDeathState(ALIVE);
407        GetAIInterface()->StopMovement(0); // after respawn monster can move
408        m_PickPocketed = false;
409        PushToWorld(m);
410}
411
412void Creature::Create (const char* name, uint32 mapid, float x, float y, float z, float ang)
413{
414        Object::_Create( mapid, x, y, z, ang );
415}
416
417void Creature::CreateWayPoint (uint32 WayPointID, uint32 mapid, float x, float y, float z, float ang)
418{
419        Object::_Create( mapid, x, y, z, ang);
420}
421
422///////////
423/// Looting
424
425void Creature::generateLoot()
426{
427        if ( !loot.items.empty() )
428                return;
429
430        if( m_mapMgr != NULL )
431                lootmgr.FillCreatureLoot( &loot, GetEntry(), m_mapMgr->iInstanceMode );
432        else
433                lootmgr.FillCreatureLoot( &loot, GetEntry(), 0 );
434
435        loot.gold = proto ? proto->money : 0;
436
437        // Master Looting Ninja Checker
438        if(sWorld.antiMasterLootNinja && this->m_lootMethod == PARTY_LOOT_MASTER)
439        {
440                Player *looter = objmgr.GetPlayer((uint32)this->TaggerGuid);
441                if(looter && looter->GetGroup())
442                {
443                        uint16 lootThreshold = looter->GetGroup()->GetThreshold();
444
445                        for(vector<__LootItem>::iterator itr = loot.items.begin(); itr != loot.items.end(); itr++)
446                        {
447                                if(itr->item.itemproto->Quality < lootThreshold)
448                                        continue;
449
450                                // Master Loot Stuff - Let the rest of the raid know what dropped..
451                                //TODO: Shouldn't we move this array to a global position? Or maybe it already exists^^ (VirtualAngel) --- I can see (dead) talking pigs...^^
452                                const char* itemColours[8] = { "9d9d9d", "ffffff", "1eff00", "0070dd", "a335ee", "ff8000", "e6cc80", "e6cc80" };
453                                char buffer[256];
454                                sprintf(buffer, "\174cff%s\174Hitem:%u:0:0:0:0:0:0:0\174h[%s]\174h\174r", itemColours[itr->item.itemproto->Quality], itr->item.itemproto->ItemId, itr->item.itemproto->Name1);
455                                this->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, buffer);
456                        }
457                }
458        }
459
460        /*
461         * If there's an amount given, take it as an expected value and
462         * generated a corresponding random value. The random value is
463         * something similar to a normal distribution.
464         *
465         * You'd get a ``better'' distribution if you called `rand()' for each
466         * copper individually. However, if the loot was 1G we'd call `rand()'
467         * 15000 times, which is not ideal. So we use one call to `rand()' to
468         * (hopefully) get 24 random bits, which is then used to create a
469         * normal distribution over 1/24th of the difference.
470         */
471        if (( loot.gold > 0 ) && ( loot.gold < 12 ))
472        {
473                /* Don't use the below formula for very small cash - rouding
474                 * errors will be too bad.. */
475        }
476        else if ( loot.gold >= 12 )
477        {
478                uint32 random_bits;
479                double chunk_size;
480                double gold_fp;
481
482                /* Split up the difference into 12 chunks.. */
483                chunk_size = ((double) loot.gold) / 12.0;
484
485                /* Get 24 random bits. We use the low order bits, because we're
486                 * too lazy to check how many random bits the system actually
487                 * returned. */
488                random_bits = rand () & 0x00ffffff;
489
490                gold_fp = 0.0;
491                while (random_bits != 0)
492                {
493                        /* If last bit is one .. */
494                        if ((random_bits & 0x01) == 1)
495                                /* .. increase loot by 1/12th of expected value */
496                                gold_fp += chunk_size;
497
498                        /* Shift away the LSB */
499                        random_bits >>= 1;
500                }
501
502                /* To hide your discrete values a bit, add another random
503                 * amount between -(chunk_size/2) and +(chunk_size/2). */
504                gold_fp += chunk_size
505                        * ((((double) rand ()) / (((double) RAND_MAX) + 1.0)) - .5);
506
507                /*
508                 * In theory we can end up with a negative amount. Give at
509                 * least one chunk_size here to prevent this from happening. In
510                 * case you're interested, the probability is around 2.98e-8.
511                 */
512                if (gold_fp < chunk_size)
513                        gold_fp = chunk_size;
514
515                /* Convert the floating point gold value to an integer again
516                 * and we're done. */
517                loot.gold = (uint32) (.5 + gold_fp);
518        }
519        else /* if(!loot.gold) */
520        {
521                CreatureInfo *info=GetCreatureInfo();
522                if (info && info->Type != UNIT_TYPE_BEAST)
523                {
524                        if(m_uint32Values[UNIT_FIELD_MAXHEALTH] <= 1667)
525                                //generate copper
526                                loot.gold = (uint32)((info->Rank+1)*getLevel()*(rand()%5 + 1)); 
527                        else
528                                loot.gold = (uint32)((info->Rank+1)*getLevel()*(rand()%5 + 1)*(this->GetMaxHealth()*0.0006)); //generate copper
529                }
530        }
531
532        if ( loot.gold )
533                loot.gold = int32(float ( loot.gold ) * sWorld.getRate( RATE_MONEY ));
534}
535
536void Creature::SaveToDB()
537{
538        if( !spawnid )
539                spawnid = objmgr.GenerateCreatureSpawnID();
540
541        std::stringstream ss;
542
543        ss << "DELETE FROM creature_spawns WHERE id = ";
544        ss << spawnid;
545        ss << ";";
546
547        WorldDatabase.Execute( ss.str().c_str() );
548
549        ss.rdbuf()->str("");
550
551        ss << "INSERT INTO creature_spawns VALUES("
552                << spawnid << ","
553                << GetEntry() << ","
554                << GetMapId() << ","
555                << m_position.x << ","
556                << m_position.y << ","
557                << m_position.z << ","
558                << m_position.o << ","
559                << m_aiInterface->getMoveType() << ","
560                << m_uint32Values[UNIT_FIELD_DISPLAYID] << ","
561                << GetFaction() << ","
562                << m_uint32Values[UNIT_FIELD_FLAGS] << ","
563                << m_uint32Values[UNIT_FIELD_BYTES_0] << ","
564                << m_uint32Values[UNIT_FIELD_BYTES_1] << ","
565                << m_uint32Values[UNIT_FIELD_BYTES_2] << ","
566                << m_uint32Values[UNIT_NPC_EMOTESTATE] << ",0,";
567               
568        if ( m_spawn )
569                ss << m_spawn->channel_spell << "," << m_spawn->channel_target_go << "," << m_spawn->channel_target_creature << ",";
570        else
571                ss << "0,0,0,";
572
573        ss << uint32(GetStandState()) << ","
574                << m_uint32Values[UNIT_FIELD_MOUNTDISPLAYID] << ","
575                << GetEquippedItem(MELEE) << ","
576                << GetEquippedItem(OFFHAND) << ","
577                << GetEquippedItem(RANGED) << ",";
578
579        if(GetAIInterface()->m_moveFly)
580                ss << 1 << ",";
581        else
582                ss << 0 << ",";
583
584        ss << m_phase << ")";
585
586        WorldDatabase.Execute(ss.str().c_str());
587}
588
589
590void Creature::LoadScript()
591{
592        _myScriptClass = sScriptMgr.CreateAIScriptClassForEntry(this);
593}
594
595void Creature::DeleteFromDB()
596{
597        if ( !GetSQL_id() )
598                return;
599
600        WorldDatabase.Execute("DELETE FROM creature_spawns WHERE id = %u", GetSQL_id() );
601        WorldDatabase.Execute("DELETE FROM creature_waypoints WHERE spawnid = %u",GetSQL_id() );
602}
603
604
605/////////////
606/// Quests
607
608void Creature::AddQuest(QuestRelation *Q)
609{
610        m_quests->push_back(Q);
611}
612
613void Creature::DeleteQuest(QuestRelation *Q)
614{
615        list<QuestRelation *>::iterator it;
616        for ( it = m_quests->begin(); it != m_quests->end(); ++it )
617        {
618                if ((( *it )->type == Q->type) && (( *it )->qst == Q->qst ))
619                {
620                        delete ( *it );
621                        m_quests->erase( it );
622                        break;
623                }
624        }
625}
626
627Quest* Creature::FindQuest(uint32 quest_id, uint8 quest_relation)
628{
629        list<QuestRelation *>::iterator it;
630        for (it = m_quests->begin(); it != m_quests->end(); ++it)
631        {
632                QuestRelation *ptr = (*it);
633
634                if (( ptr->qst->id == quest_id ) && ( ptr->type & quest_relation ))
635                {
636                        return ptr->qst;
637                }
638        }
639        return NULL;
640}
641
642uint16 Creature::GetQuestRelation(uint32 quest_id)
643{
644        uint16 quest_relation = 0;
645        list<QuestRelation *>::iterator it;
646
647        for (it = m_quests->begin(); it != m_quests->end(); ++it)
648        {
649                if (( *it )->qst->id == quest_id )
650                {
651                        quest_relation |= ( *it )->type;
652                }
653        }
654        return quest_relation;
655}
656
657uint32 Creature::NumOfQuests()
658{
659        return (uint32)m_quests->size();
660}
661
662void Creature::_LoadQuests()
663{
664        sQuestMgr.LoadNPCQuests(this);
665}
666
667void Creature::setDeathState(DeathState s)
668{
669        if( s == ALIVE )
670                this->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DEAD);
671
672        if ( s == JUST_DIED )
673        {
674
675                GetAIInterface()->SetUnitToFollow( NULL );
676                m_deathState = CORPSE;
677                m_corpseEvent = true;
678
679                /*sEventMgr.AddEvent(this, &Creature::OnRemoveCorpse, EVENT_CREATURE_REMOVE_CORPSE, 180000, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);*/
680                if ( m_enslaveSpell )
681                        RemoveEnslave();
682
683                if ( m_currentSpell )
684                        m_currentSpell->cancel();
685
686                if ( lootmgr.IsSkinnable(GetEntry()))
687                        SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
688
689
690        }
691       
692        else m_deathState = s;
693}
694
695void Creature::AddToWorld()
696{
697        // force set faction
698        if  (m_faction == 0 || m_factionDBC == 0 )
699                _setFaction();
700
701        if ( creature_info == 0 )
702                creature_info = CreatureNameStorage.LookupEntry( GetEntry() );
703
704        if ( creature_info == 0 )
705                return;
706
707        if ( m_faction == 0 || m_factionDBC == 0 )
708                return;
709
710        Object::AddToWorld();
711}
712
713void Creature::AddToWorld(MapMgr * pMapMgr)
714{
715        // force set faction
716        if ( m_faction == 0 || m_factionDBC == 0 )
717                _setFaction();
718
719        if ( creature_info == 0 )
720                creature_info = CreatureNameStorage.LookupEntry( GetEntry() );
721
722        if ( creature_info == 0)
723                return;
724
725        if ( m_faction == 0 || m_factionDBC == 0 )
726                return;
727
728        Object::AddToWorld(pMapMgr);
729}
730
731bool Creature::CanAddToWorld()
732{
733        if(m_factionDBC == 0 || m_faction == 0)
734                _setFaction();
735
736        if(creature_info == 0 || m_faction == 0 || m_factionDBC == 0 || proto == 0)
737                return false;
738
739        return true;
740}
741
742void Creature::RemoveFromWorld( bool addrespawnevent, bool free_guid )
743{
744
745    //remove ai stuff
746        sEventMgr.RemoveEvents( this, EVENT_CREATURE_AISPELL );
747
748        if( GetScript() != NULL )
749        {
750                GetScript()->Destroy();
751                _myScriptClass = NULL;
752        }
753
754        RemoveAllAuras();
755       
756        // If we have a summons then let's remove them
757        RemoveAllGuardians();
758       
759        // remove our reference from owner
760        if( m_owner != NULL )
761        {
762                m_owner->RemoveGuardianRef( this );
763                m_owner = NULL;
764        }
765
766        if( IsInWorld() )
767        {
768                if( IsPet() )
769                {
770                        static_cast<Pet*>(this)->ScheduledForDeletion = true;
771                        Unit::RemoveFromWorld( true );
772            SafeDelete();
773                        return;
774                }
775               
776                uint32 delay = 0;
777                if( addrespawnevent && ( m_respawnTimeOverride > 0 || ( proto && proto->RespawnTime > 0 ) ) )
778                        delay = m_respawnTimeOverride > 0 ? m_respawnTimeOverride : proto->RespawnTime;
779
780                Despawn( 0, delay );
781        }
782}
783
784void Creature::EnslaveExpire()
785{
786
787        m_enslaveCount++;
788
789    uint64 charmer = GetCharmedByGUID();
790
791    Player *caster = objmgr.GetPlayer( Arcemu::Util::GUID_LOPART( charmer ) );
792        if(caster)
793        {
794        caster->SetCharmedUnitGUID( 0 );
795        caster->SetSummonedUnitGUID( 0 );
796
797                WorldPacket data(SMSG_PET_SPELLS, 8 );
798
799                data << uint64(0);
800                data << uint32(0);
801
802                caster->SendPacket(&data);
803        }
804        SetCharmedByGUID( 0 );
805        SetSummonedByGUID( 0 );
806
807        m_walkSpeed = m_base_walkSpeed;
808        m_runSpeed = m_base_runSpeed;
809
810        switch(GetCreatureInfo()->Type)
811        {
812        case UNIT_TYPE_DEMON:
813                SetFaction(90);
814                break;
815        default:
816                SetFaction(954);
817                break;
818        };
819        _setFaction();
820
821        GetAIInterface()->Init(((Unit *)this), AITYPE_AGRO, MOVEMENTTYPE_NONE);
822
823        UpdateOppFactionSet();
824        UpdateSameFactionSet();
825}
826
827bool Creature::RemoveEnslave()
828{
829        return RemoveAura(m_enslaveSpell);
830}
831
832void Creature::AddInRangeObject(Object* pObj)
833{
834        Unit::AddInRangeObject(pObj);
835}
836
837void Creature::OnRemoveInRangeObject(Object* pObj)
838{
839        if(totemOwner == pObj)          // player gone out of range of the totem
840        {
841                // Expire next loop.
842                event_ModifyTimeLeft(EVENT_TOTEM_EXPIRE, 1);
843        }
844
845        if(m_escorter == pObj)
846        {
847                // we lost our escorter, return to the spawn.
848                m_aiInterface->StopMovement(10000);
849                m_escorter = NULL;
850                GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
851                //DestroyCustomWaypointMap(); //function not needed at all, crashing on delete(*int)
852                //GetAIInterface()->deleteWaypoints();//this can repleace DestroyCustomWaypointMap, but it's crashing on delete too
853                Despawn(1000, 1000);
854        }
855
856        Unit::OnRemoveInRangeObject(pObj);
857}
858
859void Creature::ClearInRangeSet()
860{
861        Unit::ClearInRangeSet();
862}
863
864void Creature::CalcResistance(uint32 type)
865{
866        int32 pos = 0;
867        int32 neg = 0;
868
869        if( BaseResistanceModPct[ type ] < 0 )
870                neg = ( BaseResistance[ type ] * abs(BaseResistanceModPct[ type ]) / 100 );
871        else
872                pos = ( BaseResistance[ type ] * BaseResistanceModPct[ type ] ) / 100;
873
874        if( IsPet() && isAlive() && IsInWorld() )
875        {
876                Pet * pet = static_cast< Pet* >( this );
877                if (pet->IsPet()) // HACK
878                {
879                        Player * owner = pet->GetPetOwner();
880                        if( type == 0 && owner )
881                                pos += int32(0.35f * owner->GetResistance(type ));
882                        else if( owner )
883                                pos += int32(0.40f * owner->GetResistance(type ));
884                }
885        }
886
887        if( ResistanceModPct[ type ] < 0 )
888                neg += ( BaseResistance[ type ] + pos - neg ) * abs(ResistanceModPct[ type ]) / 100;
889        else
890                pos += ( BaseResistance[ type ] + pos - neg ) * ResistanceModPct[ type ] / 100;
891
892        if( FlatResistanceMod[ type ] < 0 )
893                neg += abs(FlatResistanceMod[ type ]);
894        else
895                pos += FlatResistanceMod[ type ];
896
897        SetUInt32Value( UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + type, pos );
898        SetUInt32Value( UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + type, neg );
899
900    int32 tot = BaseResistance[ type ] + pos - neg;
901
902        SetResistance(type, tot > 0 ? tot : 0);
903}
904
905void Creature::CalcStat(uint32 type)
906{
907        int32 pos = 0;
908        int32 neg = 0;
909
910        if( StatModPct[ type ] < 0 )
911                neg = ( BaseStats[ type ] * abs(StatModPct[ type ]) / 100 );
912        else
913                pos = ( BaseStats[ type ] * StatModPct[ type ] ) / 100;
914
915        if( IsPet() )
916        {
917                Player* owner = static_cast< Pet* >( this )->GetPetOwner();
918                if( type == STAT_STAMINA && owner )
919                        pos += int32( 0.45f * owner->GetStat(STAT_STAMINA) );
920                else if( type == STAT_INTELLECT && owner && GetCreatedBySpell() )
921                        pos += int32( 0.30f * owner->GetStat(STAT_INTELLECT) );
922        }
923
924        if( TotalStatModPct[ type ] < 0 )
925                neg += ( BaseStats[ type ] + pos - neg ) * abs(TotalStatModPct[ type ]) / 100;
926        else
927                pos += ( BaseStats[ type ] + pos - neg ) * TotalStatModPct[ type ] / 100;
928
929        if( FlatStatMod[ type ] < 0 )
930                neg += abs(FlatStatMod[ type ]);
931        else
932                pos += FlatStatMod[ type ];
933
934        SetUInt32Value( UNIT_FIELD_POSSTAT0 + type, pos );
935        SetUInt32Value( UNIT_FIELD_NEGSTAT0 + type, neg );
936
937    int32 tot = BaseStats[ type ] + pos - neg;
938        SetStat(type, tot > 0 ? tot : 0);
939
940        switch( type )
941        {
942        case STAT_STRENGTH:
943                {
944                        //Attack Power
945                        if( !IsPet() )//We calculate pet's later
946                        {
947                                uint32 str = GetStat(STAT_STRENGTH);
948                                int32 AP = ( str * 2 - 20 );
949                                if( AP < 0 ) AP = 0;
950                                SetAttackPower(AP );
951                        }
952                        CalcDamage();
953                }break;
954        case STAT_AGILITY:
955                {
956                        //Ranged Attack Power (Does any creature use this?)
957                        int32 RAP = getLevel() + GetStat(STAT_AGILITY) - 10;
958                        if( RAP < 0 ) RAP = 0;
959                        SetRangedAttackPower(RAP );
960                }break;
961        case STAT_STAMINA:
962                {
963                        //Health
964                        uint32 hp = GetBaseHealth();
965                        uint32 stat_bonus = GetUInt32Value( UNIT_FIELD_POSSTAT2 ) - GetUInt32Value( UNIT_FIELD_NEGSTAT2 );
966                        if ( stat_bonus < 0 ) stat_bonus = 0;
967
968                        uint32 bonus = stat_bonus * 10 + m_healthfromspell;
969                        uint32 res = hp + bonus;
970
971                        if( res < hp ) res = hp;
972                        SetUInt32Value( UNIT_FIELD_MAXHEALTH, res );
973                        if( GetUInt32Value( UNIT_FIELD_HEALTH ) > GetUInt32Value( UNIT_FIELD_MAXHEALTH ) )
974                                SetHealth(GetUInt32Value( UNIT_FIELD_MAXHEALTH ) );
975                }break;
976        case STAT_INTELLECT:
977                {
978                        if( GetPowerType() == POWER_TYPE_MANA )
979                        {
980                                uint32 mana = GetBaseMana();
981                                uint32 stat_bonus = ( GetUInt32Value( UNIT_FIELD_POSSTAT3 ) - GetUInt32Value( UNIT_FIELD_NEGSTAT3 ) );
982                                if( stat_bonus < 0 ) stat_bonus = 0;
983
984                                uint32 bonus = stat_bonus * 15;
985                                uint32 res = mana + bonus;
986
987                                if( res < mana ) res = mana;
988                                SetMaxPower(POWER_TYPE_MANA, res );
989                        }
990                }break;
991        }
992}
993
994void Creature::RegenerateHealth()
995{
996        if(m_limbostate || !m_canRegenerateHP)
997                return;
998
999        uint32 cur=GetHealth();
1000        uint32 mh=GetMaxHealth();
1001        if(cur>=mh)return;
1002
1003        //though creatures have their stats we use some weird formula for amt
1004        float amt = 0.0f;
1005        uint32 lvl = getLevel();
1006
1007        amt = lvl*2.0f;
1008        if (PctRegenModifier)
1009                amt+= (amt * PctRegenModifier) / 100;
1010
1011        if (GetCreatureInfo() && GetCreatureInfo()->Rank == 3)
1012                amt *= 10000.0f;
1013        //Apply shit from conf file
1014        amt*=sWorld.getRate(RATE_HEALTH);
1015
1016        if(amt<=1.0f)//this fixes regen like 0.98
1017                cur++;
1018        else
1019                cur+=(uint32)amt;
1020        SetHealth((cur>=mh)?mh:cur);
1021}
1022
1023void Creature::RegenerateMana()
1024{
1025        float amt;
1026        if (m_interruptRegen)
1027                return;
1028
1029        uint32 cur = GetPower( POWER_TYPE_MANA );
1030        uint32 mm = GetMaxPower( POWER_TYPE_MANA );
1031        if(cur>=mm)return;
1032        amt=(getLevel()+10)*PctPowerRegenModifier[POWER_TYPE_MANA];
1033
1034
1035        amt*=sWorld.getRate(RATE_POWER1);
1036        if( amt <= 1.0 )//this fixes regen like 0.98
1037                cur++;
1038        else
1039                cur += (uint32)amt;
1040
1041    if( cur >= mm )
1042        SetPower( POWER_TYPE_MANA, mm );
1043    else
1044        SetPower( POWER_TYPE_MANA, cur );
1045}
1046
1047void Creature::RegenerateFocus()
1048{
1049        if (m_interruptRegen)
1050                return;
1051
1052        uint32 cur=GetPower(POWER_TYPE_FOCUS);
1053        uint32 mm=GetMaxPower(POWER_TYPE_FOCUS);
1054        if(cur>=mm)return;
1055        float regenrate = sWorld.getRate(RATE_POWER3);
1056        float amt = 25.0f * PctPowerRegenModifier[POWER_TYPE_FOCUS] * regenrate;
1057        cur+=(uint32)amt;
1058        SetPower(POWER_TYPE_FOCUS,(cur>=mm)?mm:cur);
1059}
1060
1061void Creature::CallScriptUpdate()
1062{
1063        Arcemu::Util::ARCEMU_ASSERT(   _myScriptClass != NULL );
1064        if(!IsInWorld())
1065                return;
1066
1067        _myScriptClass->AIUpdate();
1068}
1069
1070void Creature::AddVendorItem(uint32 itemid, uint32 amount, ItemExtendedCostEntry * ec)
1071{
1072        CreatureItem ci;
1073        ci.amount = amount;
1074        ci.itemid = itemid;
1075        ci.available_amount = 0;
1076        ci.max_amount = 0;
1077        ci.incrtime = 0;
1078        ci.extended_cost = ec;
1079        if(!m_SellItems)
1080        {
1081                m_SellItems = new vector<CreatureItem>;
1082                objmgr.SetVendorList(GetEntry(), m_SellItems);
1083        }
1084        m_SellItems->push_back(ci);
1085}
1086void Creature::ModAvItemAmount(uint32 itemid, uint32 value)
1087{
1088        for(std::vector<CreatureItem>::iterator itr = m_SellItems->begin(); itr != m_SellItems->end(); ++itr)
1089        {
1090                if(itr->itemid == itemid)
1091                {
1092                        if(itr->available_amount)
1093                        {
1094                                if(value > itr->available_amount)       // shouldn't happen
1095                                {
1096                                        itr->available_amount= 0;
1097                                        return;
1098                                }
1099                                else
1100                                        itr->available_amount -= value;
1101
1102                                if(!event_HasEvent(EVENT_ITEM_UPDATE))
1103                                        sEventMgr.AddEvent(this, &Creature::UpdateItemAmount, itr->itemid, EVENT_ITEM_UPDATE, itr->incrtime, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
1104                        }
1105                        return;
1106                }
1107        }
1108}
1109void Creature::UpdateItemAmount(uint32 itemid)
1110{
1111        for(std::vector<CreatureItem>::iterator itr = m_SellItems->begin(); itr != m_SellItems->end(); ++itr)
1112        {
1113                if(itr->itemid == itemid)
1114                {
1115                        if (itr->max_amount== 0)                // shouldn't happen
1116                                itr->available_amount= 0;
1117                        else
1118                        {
1119                                itr->available_amount = itr->max_amount;
1120                        }
1121                        return;
1122                }
1123        }
1124}
1125
1126void Creature::TotemExpire()
1127{
1128        Player *pOwner = NULL;
1129        if( totemOwner != NULL )
1130        {
1131                pOwner = totemOwner;
1132                if(GetCreatedBySpell() == 6495) // sentry totem
1133                        pOwner->RemoveAura(6495);
1134                totemOwner->m_TotemSlots[totemSlot] = 0;
1135    }
1136
1137        totemSlot = -1;
1138        totemOwner = NULL;
1139
1140 
1141
1142        if(pOwner != NULL)
1143                DestroyForPlayer(pOwner); //make sure the client knows it's gone...
1144
1145    DeleteMe();
1146}
1147
1148void Creature::FormationLinkUp(uint32 SqlId)
1149{
1150        if(!m_mapMgr)           // shouldn't happen
1151                return;
1152
1153        Creature * creature = m_mapMgr->GetSqlIdCreature(SqlId);
1154        if(creature != 0)
1155        {
1156                m_aiInterface->m_formationLinkTarget = creature;
1157                haslinkupevent = false;
1158                event_RemoveEvents(EVENT_CREATURE_FORMATION_LINKUP);
1159        }
1160}
1161
1162void Creature::ChannelLinkUpGO(uint32 SqlId)
1163{
1164        if(!m_mapMgr)           // shouldn't happen
1165                return;
1166
1167        GameObject * go = m_mapMgr->GetSqlIdGameObject(SqlId);
1168        if(go != 0)
1169        {
1170                event_RemoveEvents(EVENT_CREATURE_CHANNEL_LINKUP);
1171        SetChannelSpellTargetGUID( go->GetGUID());
1172        SetChannelSpellId( m_spawn->channel_spell);
1173        }
1174}
1175
1176void Creature::ChannelLinkUpCreature(uint32 SqlId)
1177{
1178        if(!m_mapMgr)           // shouldn't happen
1179                return;
1180
1181        Creature * go = m_mapMgr->GetSqlIdCreature(SqlId);
1182        if(go != 0)
1183        {
1184                event_RemoveEvents(EVENT_CREATURE_CHANNEL_LINKUP);
1185                SetChannelSpellTargetGUID( go->GetGUID() );
1186                SetChannelSpellId( m_spawn->channel_spell );
1187        }
1188}
1189
1190WayPoint * Creature::CreateWaypointStruct()
1191{
1192        return new WayPoint();
1193}
1194//#define SAFE_FACTIONS
1195
1196bool Creature::isattackable(CreatureSpawn *spawn){
1197    if(spawn == NULL)
1198       return false;
1199
1200    if( (spawn->flags & 2 ) || (spawn->flags & 128 ) || (spawn->flags & 256 ) || (spawn->flags & 65536 ))
1201        return false;
1202        else return true;
1203}
1204
1205uint8 get_byte(uint32 buffer, uint32 index){
1206        uint32 mask = uint32(~0ul);
1207        if(index > sizeof(uint32)-1)
1208                return 0;
1209
1210        buffer = buffer >> index*8;
1211        mask   = mask   >> 3*8;
1212        buffer = buffer & mask;
1213
1214        return (uint8)buffer;
1215}
1216
1217bool Creature::Load(CreatureSpawn *spawn, uint32 mode, MapInfo *info)
1218{
1219        m_spawn = spawn;
1220        proto = CreatureProtoStorage.LookupEntry(spawn->entry);
1221        if( proto == NULL )
1222                return false;
1223        creature_info = CreatureNameStorage.LookupEntry(spawn->entry);
1224        if( creature_info == NULL )
1225                return false;
1226
1227        spawnid = spawn->id;
1228        m_phase = spawn->phase;
1229       
1230        m_walkSpeed = m_base_walkSpeed = proto->walk_speed; //set speeds
1231        m_runSpeed = m_base_runSpeed = proto->run_speed; //set speeds
1232        m_flySpeed = proto->fly_speed;
1233
1234        //Set fields
1235        SetEntry( proto->Id);
1236        SetScale( proto->Scale);
1237
1238        //SetHealth( (mode ? long2int32(proto->Health * 1.5)  : proto->Health));
1239        //SetBaseHealth((mode ? long2int32(proto->Health * 1.5)  : proto->Health));
1240        //SetMaxHealth( (mode ? long2int32(proto->Health * 1.5)  : proto->Health));
1241        if( proto->MinHealth > proto->MaxHealth )
1242        {
1243                proto->MaxHealth = proto->MinHealth+1;
1244                SaveToDB();
1245        }
1246
1247        uint32 health = proto->MinHealth + RandomUInt(proto->MaxHealth - proto->MinHealth);
1248       
1249        // difficutly coefficient
1250        float diff_coeff = 1.0f;
1251       
1252        if( creature_info->Rank == ELITE_WORLDBOSS )
1253                diff_coeff = CalcHPCoefficient( info, mode, true );
1254        else
1255        if( creature_info->Type != UNIT_TYPE_CRITTER )
1256                diff_coeff = CalcHPCoefficient( info, mode, false );
1257
1258        health = static_cast< uint32 >( health * diff_coeff );
1259
1260        SetHealth( health);
1261        SetMaxHealth( health);
1262        SetBaseHealth(health);
1263
1264        SetMaxPower(POWER_TYPE_MANA, proto->Mana);
1265        SetBaseMana(proto->Mana);
1266        SetPower( POWER_TYPE_MANA, proto->Mana );
1267
1268        // Whee, thank you blizz, I love patch 2.2! Later on, we can randomize male/female mobs! xD
1269        // Determine gender (for voices)
1270        //if(spawn->displayid != creature_info->Male_DisplayID)
1271        //      setGender(1);   // Female
1272
1273        // uint32 model = 0;
1274        // uint32 gender = creature_info->GenerateModelId(&model);
1275        // setGender(gender);
1276
1277        SetDisplayId(spawn->displayid);
1278        SetNativeDisplayId(spawn->displayid);
1279        SetMount(spawn->MountedDisplayID);
1280
1281        EventModelChange();
1282
1283    setLevel(proto->MinLevel + (RandomUInt(proto->MaxLevel - proto->MinLevel)));
1284       
1285        if( mode && info )
1286                modLevel(min(73 - getLevel(), info->lvl_mod_a));
1287
1288        for(uint32 i = 0; i < 7; ++i)
1289                SetResistance(i,proto->Resistances[i]);
1290
1291        SetBaseAttackTime(MELEE,proto->AttackTime);
1292
1293        float dmg_coeff = CalcDMGCoefficient( info, mode );
1294
1295        SetMinDamage((mode ? proto->MinDamage * dmg_coeff  : proto->MinDamage ) );
1296        SetMaxDamage((mode ? proto->MaxDamage * dmg_coeff  : proto->MaxDamage ) );
1297
1298        SetBaseAttackTime(RANGED,proto->RangedAttackTime);
1299        SetMinRangedDamage(proto->RangedMinDamage);
1300        SetMaxRangedDamage(proto->RangedMaxDamage);
1301
1302        SetEquippedItem(MELEE,spawn->Item1SlotDisplay);
1303        SetEquippedItem(OFFHAND,spawn->Item2SlotDisplay);
1304        SetEquippedItem(RANGED,spawn->Item3SlotDisplay);
1305
1306        SetFaction(spawn->factionid);
1307        SetUInt32Value(UNIT_FIELD_FLAGS, spawn->flags);
1308        SetEmoteState(spawn->emote_state);
1309        SetBoundingRadius(proto->BoundingRadius);
1310        SetCombatReach(proto->CombatReach);
1311        original_emotestate = spawn->emote_state;
1312        // set position
1313        m_position.ChangeCoords( spawn->x, spawn->y, spawn->z, spawn->o );
1314        m_spawnLocation.ChangeCoords(spawn->x, spawn->y, spawn->z, spawn->o);
1315        m_aiInterface->setMoveType(spawn->movetype);
1316        m_aiInterface->m_waypoints = objmgr.GetWayPointMap(spawn->id);
1317
1318        m_aiInterface->timed_emotes = objmgr.GetTimedEmoteList(spawn->id);
1319
1320        m_faction = dbcFactionTemplate.LookupEntryForced(spawn->factionid);
1321        if(m_faction)
1322        {
1323                m_factionDBC = dbcFaction.LookupEntry(m_faction->Faction);
1324                // not a neutral creature
1325                if(!(m_factionDBC->RepListId == -1 && m_faction->HostileMask == 0 && m_faction->FriendlyMask == 0))
1326                {
1327                        GetAIInterface()->m_canCallForHelp = true;
1328                }
1329        }
1330
1331        // set if creature can shoot or not.
1332        if( proto->CanRanged == 1 )
1333                GetAIInterface()->m_canRangedAttack = true;
1334        else
1335                m_aiInterface->m_canRangedAttack = false;
1336
1337//SETUP NPC FLAGS
1338        SetUInt32Value(UNIT_NPC_FLAGS,proto->NPCFLags);
1339
1340        if ( isVendor() )
1341                m_SellItems = objmgr.GetVendorList(GetEntry());
1342
1343        if ( isQuestGiver() )
1344                _LoadQuests();
1345
1346        if ( isTaxi() )
1347                m_TaxiNode = sTaxiMgr.GetNearestTaxiNode( m_position.x, m_position.y, m_position.z, GetMapId() );
1348
1349        if ( isTrainer() | isProf() )
1350                mTrainer = objmgr.GetTrainer(GetEntry());
1351
1352        if ( isAuctioner() )
1353                auctionHouse = sAuctionMgr.GetAuctionHouse(GetEntry());
1354
1355//NPC FLAGS
1356         m_aiInterface->m_waypoints=objmgr.GetWayPointMap(spawn->id);
1357
1358        //load resistances
1359        for(uint32 x= 0;x<7;x++)
1360                BaseResistance[x]=GetResistance(x);
1361        for(uint32 x= 0;x<5;x++)
1362                BaseStats[x]=GetStat(x);
1363
1364        BaseDamage[0]=GetMinDamage();
1365        BaseDamage[1]=GetMaxDamage();
1366        BaseOffhandDamage[0]=GetMinOffhandDamage();
1367        BaseOffhandDamage[1]=GetMaxOffhandDamage();
1368        BaseRangedDamage[0]=GetMinRangedDamage();
1369        BaseRangedDamage[1]=GetMaxRangedDamage();
1370        BaseAttackType=proto->AttackType;
1371
1372        SetCastSpeedMod(1.0f);   // better set this one
1373        SetUInt32Value(UNIT_FIELD_BYTES_0, spawn->bytes0);
1374        SetUInt32Value(UNIT_FIELD_BYTES_1, spawn->bytes1);
1375        SetUInt32Value(UNIT_FIELD_BYTES_2, spawn->bytes2);
1376
1377////////////AI
1378
1379        // kek
1380        for(list<AI_Spell*>::iterator itr = proto->spells.begin(); itr != proto->spells.end(); ++itr)
1381        {
1382                // Load all spells that are not bound to a specific difficulty, OR mathces this maps' difficulty
1383                if( (*itr)->instance_mode == mode || (*itr)->instance_mode == AISPELL_ANY_DIFFICULTY )
1384                        m_aiInterface->addSpellToList(*itr);
1385        }
1386
1387        // m_aiInterface->m_canCallForHelp = proto->m_canCallForHelp;
1388        // m_aiInterface->m_CallForHelpHealth = proto->m_callForHelpHealth;
1389        m_aiInterface->m_canFlee = proto->m_canFlee;
1390        m_aiInterface->m_FleeHealth = proto->m_fleeHealth;
1391        m_aiInterface->m_FleeDuration = proto->m_fleeDuration;
1392
1393        //these fields are always 0 in db
1394        GetAIInterface()->setMoveType(0);
1395        GetAIInterface()->setMoveRunFlag(0);
1396
1397    if(isattackable(spawn) && !(proto->isTrainingDummy) ){
1398          GetAIInterface()->SetAllowedToEnterCombat(true);
1399    }else{
1400        GetAIInterface()->SetAllowedToEnterCombat(false);
1401        GetAIInterface()->SetAIType( AITYPE_PASSIVE );
1402        Root();
1403    }
1404         
1405        // load formation data
1406        if( spawn->form != NULL )
1407        {
1408                m_aiInterface->m_formationLinkSqlId = spawn->form->fol;
1409                m_aiInterface->m_formationFollowDistance = spawn->form->dist;
1410                m_aiInterface->m_formationFollowAngle = spawn->form->ang;
1411        }
1412        else
1413        {
1414                m_aiInterface->m_formationLinkSqlId = 0;
1415                m_aiInterface->m_formationFollowDistance = 0;
1416                m_aiInterface->m_formationFollowAngle = 0;
1417        }
1418
1419//////////////AI
1420
1421        myFamily = dbcCreatureFamily.LookupEntry(creature_info->Family);
1422
1423
1424 //HACK!
1425        if(m_uint32Values[UNIT_FIELD_DISPLAYID] == 17743 ||
1426                m_uint32Values[UNIT_FIELD_DISPLAYID] == 20242 ||
1427                m_uint32Values[UNIT_FIELD_DISPLAYID] == 15435 ||
1428                (creature_info->Family == UNIT_TYPE_MISC))
1429        {
1430                m_useAI = false;
1431        }
1432
1433        if(spawn->CanFly == 1)
1434                GetAIInterface()->m_moveFly = true;
1435
1436        /* more hacks! */
1437        if(proto->Mana != 0)
1438                SetPowerType(POWER_TYPE_MANA);
1439        else
1440                SetPowerType(0);
1441
1442        has_combat_text = objmgr.HasMonsterSay(GetEntry(), MONSTER_SAY_EVENT_ENTER_COMBAT);
1443        has_waypoint_text = objmgr.HasMonsterSay(GetEntry(), MONSTER_SAY_EVENT_RANDOM_WAYPOINT);
1444
1445    if( proto->guardtype == GUARDTYPE_CITY )
1446        m_aiInterface->m_isGuard = true;
1447    else
1448        m_aiInterface->m_isGuard = false;
1449
1450    if( proto->guardtype == GUARDTYPE_NEUTRAL )
1451        m_aiInterface->m_isNeutralGuard = true;
1452    else
1453        m_aiInterface->m_isNeutralGuard = false;
1454
1455        m_aiInterface->getMoveFlags();
1456
1457        /* creature death state */
1458        if(proto->death_state == 1)
1459        {
1460                /*uint32 newhealth = m_uint32Values[UNIT_FIELD_HEALTH] / 100;
1461                if(!newhealth)
1462                        newhealth = 1;*/
1463                SetHealth( 1);
1464                m_limbostate = true;
1465                setDeathState( CORPSE );
1466                SetEmoteState(EMOTE_STATE_DEAD);
1467        }
1468        m_invisFlag = static_cast<uint8>( proto->invisibility_type );
1469        if( m_invisFlag > 0 )
1470                m_invisible = true;
1471        if( spawn->stand_state )
1472                SetStandState( (uint8)spawn->stand_state );
1473
1474        m_aiInterface->EventAiInterfaceParamsetFinish();
1475        this->m_position.x = spawn->x;
1476        this->m_position.y = spawn->y;
1477        this->m_position.z = spawn->z;
1478        this->m_position.o = spawn->o;
1479        this->m_mapId = spawn->id;
1480        return true;
1481}
1482
1483
1484void Creature::Load(CreatureProto * proto_, float x, float y, float z, float o)
1485{
1486        proto = proto_;
1487
1488        creature_info = CreatureNameStorage.LookupEntry(proto->Id);
1489        if(!creature_info)
1490                return;
1491
1492    if( proto_->isTrainingDummy == 0){
1493                GetAIInterface()->SetAllowedToEnterCombat( true );
1494    }else{
1495        GetAIInterface()->SetAllowedToEnterCombat( false );
1496        GetAIInterface()->SetAIType( AITYPE_PASSIVE );
1497        Root();
1498    }
1499
1500        m_walkSpeed = m_base_walkSpeed = proto->walk_speed; //set speeds
1501        m_runSpeed = m_base_runSpeed = proto->run_speed; //set speeds
1502
1503        //Set fields
1504        SetEntry( proto->Id);
1505        SetScale( proto->Scale);
1506
1507        uint32 health = proto->MinHealth + RandomUInt(proto->MaxHealth - proto->MinHealth);
1508
1509        SetHealth( health);
1510        SetMaxHealth( health);
1511        SetBaseHealth(health);
1512
1513        SetMaxPower(POWER_TYPE_MANA, proto->Mana);
1514        SetBaseMana(proto->Mana);
1515        SetPower( POWER_TYPE_MANA, proto->Mana );
1516
1517        uint32 model = 0;
1518        uint8 gender = creature_info->GenerateModelId(&model);
1519        setGender(gender);
1520
1521        SetDisplayId(model);
1522        SetNativeDisplayId(model);
1523        SetMount(0);
1524
1525        EventModelChange();
1526
1527        //setLevel((mode ? proto->Level + (info ? info->lvl_mod_a : 0) : proto->Level));
1528        setLevel(proto->MinLevel + (RandomUInt(proto->MaxLevel - proto->MinLevel)));
1529
1530        for(uint32 i = 0; i < 7; ++i)
1531                SetResistance(i,proto->Resistances[i]);
1532
1533        SetBaseAttackTime(MELEE,proto->AttackTime);
1534        SetMinDamage(proto->MinDamage);
1535        SetMaxDamage(proto->MaxDamage);
1536
1537// m_spawn is invalid here - don't use it!
1538// this is loading a CreatureProto, which doesn't have ItemSlotDisplays
1539//      SetEquippedItem(MELEE,m_spawn->Item1SlotDisplay);
1540//      SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID_1, m_spawn->Item2SlotDisplay);
1541//      SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID_2, m_spawn->Item3SlotDisplay);
1542
1543        SetFaction(proto->Faction);
1544        SetBoundingRadius(proto->BoundingRadius);
1545        SetCombatReach(proto->CombatReach);
1546        original_emotestate = 0;
1547        // set position
1548
1549        m_position.ChangeCoords( x, y, z, o );
1550        m_spawnLocation.ChangeCoords(x, y, z, o);
1551        m_faction = dbcFactionTemplate.LookupEntryForced(proto->Faction);
1552
1553        if(m_faction)
1554        {
1555                m_factionDBC = dbcFaction.LookupEntry(m_faction->Faction);
1556                // not a neutral creature
1557                if(!(m_factionDBC->RepListId == -1 && m_faction->HostileMask == 0 && m_faction->FriendlyMask == 0))
1558                {
1559                        GetAIInterface()->m_canCallForHelp = true;
1560                }
1561        }
1562
1563        // set if creature can shoot or not.
1564        if( proto->CanRanged == 1 )
1565                GetAIInterface()->m_canRangedAttack = true;
1566        else
1567                m_aiInterface->m_canRangedAttack = false;
1568
1569        //SETUP NPC FLAGS
1570        SetUInt32Value(UNIT_NPC_FLAGS,proto->NPCFLags);
1571
1572        if ( isVendor() )
1573                m_SellItems = objmgr.GetVendorList(GetEntry());
1574
1575        if ( isQuestGiver() )
1576                _LoadQuests();
1577
1578        if ( isTaxi() )
1579                m_TaxiNode = sTaxiMgr.GetNearestTaxiNode( m_position.x, m_position.y, m_position.z, GetMapId() );
1580
1581        if ( isTrainer() | isProf() )
1582                mTrainer = objmgr.GetTrainer(GetEntry());
1583
1584        if ( isAuctioner() )
1585                auctionHouse = sAuctionMgr.GetAuctionHouse(GetEntry());
1586
1587        //load resistances
1588        for(uint32 x= 0;x<7;x++)
1589                BaseResistance[x]=GetResistance(x);
1590        for(uint32 x= 0;x<5;x++)
1591                BaseStats[x]=GetStat(x);
1592
1593        BaseDamage[0]=GetMinDamage();
1594        BaseDamage[1]=GetMaxDamage();
1595        BaseOffhandDamage[0]=GetMinOffhandDamage();
1596        BaseOffhandDamage[1]=GetMaxOffhandDamage();
1597        BaseRangedDamage[0]=GetMinRangedDamage();
1598        BaseRangedDamage[1]=GetMaxRangedDamage();
1599        BaseAttackType=proto->AttackType;
1600
1601        SetCastSpeedMod(1.0f);   // better set this one
1602
1603        ////////////AI
1604
1605        // kek
1606        for(list<AI_Spell*>::iterator itr = proto->spells.begin(); itr != proto->spells.end(); ++itr)
1607        {
1608                // Load all spell that are not set for a specific difficulty
1609                if( (*itr)->instance_mode == AISPELL_ANY_DIFFICULTY )
1610                        m_aiInterface->addSpellToList(*itr);
1611        }
1612        m_aiInterface->m_canCallForHelp = proto->m_canCallForHelp;
1613        m_aiInterface->m_CallForHelpHealth = proto->m_callForHelpHealth;
1614        m_aiInterface->m_canFlee = proto->m_canFlee;
1615        m_aiInterface->m_FleeHealth = proto->m_fleeHealth;
1616        m_aiInterface->m_FleeDuration = proto->m_fleeDuration;
1617
1618        //these fields are always 0 in db
1619        GetAIInterface()->setMoveType(0);
1620        GetAIInterface()->setMoveRunFlag(0);
1621
1622        // load formation data
1623        m_aiInterface->m_formationLinkSqlId = 0;
1624        m_aiInterface->m_formationFollowDistance = 0;
1625        m_aiInterface->m_formationFollowAngle = 0;
1626
1627        //////////////AI
1628
1629        myFamily = dbcCreatureFamily.LookupEntry( creature_info->Family );
1630
1631
1632        //HACK!
1633        if( m_uint32Values[ UNIT_FIELD_DISPLAYID ] == 17743 ||
1634                m_uint32Values[ UNIT_FIELD_DISPLAYID ] == 20242 ||
1635                m_uint32Values[ UNIT_FIELD_DISPLAYID ] == 15435 ||
1636                creature_info->Type == UNIT_TYPE_MISC )
1637        {
1638                m_useAI = false;
1639        }
1640
1641        SetPowerType( POWER_TYPE_MANA );
1642
1643        has_combat_text = objmgr.HasMonsterSay(GetEntry(), MONSTER_SAY_EVENT_ENTER_COMBAT);
1644        has_waypoint_text = objmgr.HasMonsterSay(GetEntry(), MONSTER_SAY_EVENT_RANDOM_WAYPOINT);
1645       
1646    if( proto->guardtype == GUARDTYPE_CITY )
1647        m_aiInterface->m_isGuard = true;
1648    else
1649        m_aiInterface->m_isGuard = false;
1650
1651    if( proto->guardtype == GUARDTYPE_NEUTRAL )
1652        m_aiInterface->m_isNeutralGuard = true;
1653    else
1654        m_aiInterface->m_isNeutralGuard = false;
1655
1656        m_aiInterface->getMoveFlags();
1657
1658        /* creature death state */
1659        if(proto->death_state == 1)
1660        {
1661                /*uint32 newhealth = m_uint32Values[UNIT_FIELD_HEALTH] / 100;
1662                if(!newhealth)
1663                        newhealth = 1;*/
1664                SetHealth( 1);
1665                m_limbostate = true;
1666                setDeathState( CORPSE );
1667                SetEmoteState(EMOTE_STATE_DEAD);
1668        }
1669        m_invisFlag = static_cast<uint8>( proto->invisibility_type );
1670        if( m_invisFlag > 0 )
1671                m_invisible = true;
1672}
1673
1674void Creature::OnPushToWorld()
1675{
1676        if(proto)
1677        {
1678                set<uint32>::iterator itr = proto->start_auras.begin();
1679                SpellEntry * sp;
1680                for(; itr != proto->start_auras.end(); ++itr)
1681                {
1682                        sp = dbcSpell.LookupEntryForced((*itr));
1683                        if(sp == NULL) continue;
1684
1685                        CastSpell(this, sp, 0);
1686                }
1687                //generic ai stuff
1688                if ( this->GetProto()->AISpells[0] != 0 )
1689                        sEventMgr.AddEvent(this, &Creature::AISpellUpdate, EVENT_CREATURE_AISPELL, 500, 0, 0);
1690        }
1691        LoadScript();
1692        Unit::OnPushToWorld();
1693
1694        if(_myScriptClass)
1695                _myScriptClass->OnLoad();
1696
1697        if(m_spawn)
1698        {
1699                if(m_aiInterface->m_formationLinkSqlId)
1700                {
1701                        // add event
1702                        sEventMgr.AddEvent(this, &Creature::FormationLinkUp, m_aiInterface->m_formationLinkSqlId,
1703                                EVENT_CREATURE_FORMATION_LINKUP, 1000, 0,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
1704                        haslinkupevent = true;
1705                }
1706
1707                if(m_spawn->channel_target_creature)
1708                {
1709                        sEventMgr.AddEvent(this, &Creature::ChannelLinkUpCreature, m_spawn->channel_target_creature, EVENT_CREATURE_CHANNEL_LINKUP, 1000, 5, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);       // only 5 attempts
1710                }
1711
1712                if(m_spawn->channel_target_go)
1713                {
1714                        sEventMgr.AddEvent(this, &Creature::ChannelLinkUpGO, m_spawn->channel_target_go, EVENT_CREATURE_CHANNEL_LINKUP, 1000, 5, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);   // only 5 attempts
1715                }
1716        }
1717
1718        m_aiInterface->m_is_in_instance = (m_mapMgr->GetMapInfo()->type!=INSTANCE_NULL) ? true : false;
1719        if (this->HasItems())
1720        {
1721                for(std::vector<CreatureItem>::iterator itr = m_SellItems->begin(); itr != m_SellItems->end(); ++itr)
1722                {
1723                                if (itr->max_amount == 0)
1724                                        itr->available_amount= 0;
1725                                else if (itr->available_amount<itr->max_amount)
1726                                        sEventMgr.AddEvent(this, &Creature::UpdateItemAmount, itr->itemid, EVENT_ITEM_UPDATE, VENDOR_ITEMS_UPDATE_TIME, 1,0);
1727                }
1728
1729        }
1730        CALL_INSTANCE_SCRIPT_EVENT( m_mapMgr, OnCreaturePushToWorld )( this );
1731}
1732
1733void Creature::AISpellUpdate()
1734{
1735        //lower cooldowns
1736        for (int i= 0; i<4; i++)
1737        {
1738                if (AISpellsCooldown[i]>=500)
1739                        AISpellsCooldown[i]-=500;
1740                else
1741                        AISpellsCooldown[i]= 0;
1742        }
1743
1744        if (!IsInWorld() || !isAlive())
1745                return;
1746
1747        Spell* s=GetCurrentSpell();
1748        if (s != NULL) //check everythings going well on current spells
1749        {
1750
1751                SpellRange* range=dbcSpellRange.LookupEntryForced(s->GetProto()->rangeIndex);
1752
1753                if (s->GetUnitTarget() != NULL && range != NULL && (CalcDistance(s->GetUnitTarget()) > range->maxRange || CalcDistance(s->GetUnitTarget()) < range->minRange))
1754                        s->cancel();
1755
1756                if (m_silenced || IsStunned() || IsFeared())
1757                        s->cancel();
1758
1759                if (sWorld.Collision) {
1760                        if (s->GetUnitTarget() != NULL && !CollideInterface.CheckLOS(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), s->GetUnitTarget()->GetPositionX(), s->GetUnitTarget()->GetPositionY(), s->GetUnitTarget()->GetPositionZ()))
1761                                s->cancel();
1762                }
1763        }
1764        else //guess we can cast a spell now
1765        {
1766                if (!(this->GetProto()->AISpellsFlags & CREATURE_AI_FLAG_CASTOUTOFCOMBAT) && !CombatStatus.IsInCombat())
1767                        return;
1768
1769                bool random_chosen=false;
1770
1771                //calculate global cooldown
1772                int32 GCD=RandomUInt(2000)+5000;
1773
1774                if (this->GetProto()->AISpellsFlags & CREATURE_AI_FLAG_PLAYERGCD)
1775                        GCD=1500;
1776
1777                //do we have a spell to use?
1778                for (int i= 0; i<4; i++)
1779                {
1780                        if (this->GetProto()->AISpellsFlags & CREATURE_AI_FLAG_RANDOMCAST && !random_chosen)
1781                        {
1782                                //find the max spell
1783                                uint32 maxindex= 0;
1784                                for (int j= 0; j<4; j++)
1785                                {
1786                                        if (this->GetProto()->AISpells[j]== 0)
1787                                                break;
1788                                        else
1789                                                maxindex=j;
1790                                }
1791
1792                                //move index randomly
1793                                if (maxindex > 0)
1794                                        i=RandomUInt(maxindex);
1795
1796                                random_chosen=true;
1797                        }
1798
1799                        if (this->GetProto()->AISpells[i]== 0)
1800                                continue;
1801
1802                        if (AISpellsCooldown[i]== 0) //we can cast?
1803                        {
1804                                //get the spell
1805                                SpellEntry* newspell=dbcSpell.LookupEntry(this->GetProto()->AISpells[i]);
1806                                SpellCastTime* casttime=dbcSpellCastTime.LookupEntry(newspell->CastingTimeIndex);
1807                                Spell* spell = new Spell(this, newspell, false, 0);
1808                                SpellCastTargets t(0);
1809                                spell->GenerateTargets(&t);
1810
1811                                //printf("\nCOOLDOWN: %u, %u", newspell->RecoveryTime, newspell->CategoryRecoveryTime);
1812
1813                                //printf("\nTEST: %f %f %f "I64FMT" "I64FMT, t.m_destX, t.m_destY, t.m_destZ, t.m_itemTarget, t.m_unitTarget);
1814
1815                                //we have no targets?
1816                                if (t.m_destX == 0.0f && t.m_destY == 0.0f && t.m_destZ == 0.0f && t.m_itemTarget == 0 && t.m_unitTarget == 0)
1817                                {
1818                                        //printf("\nNo target, not casting!");
1819                                        delete spell;
1820                                        spell = NULL;
1821                                        continue;
1822                                }
1823
1824                                //hacky
1825                                spell->m_targets = t;
1826
1827                                if (spell->CanCast(false) != SPELL_CANCAST_OK || !spell->HasPower() || m_silenced || IsStunned() || IsFeared())
1828                                {
1829                                        delete spell;
1830                                        spell = NULL;
1831                                        continue;
1832                                }
1833
1834                                spell->prepare(&t);
1835
1836                                //stop movement for spells with a cast time
1837                                if (casttime->CastTime > 0)
1838                                        GetAIInterface()->StopMovement(0);
1839
1840                                if (newspell->CategoryRecoveryTime > newspell->RecoveryTime)
1841                                        AISpellsCooldown[i]=newspell->CategoryRecoveryTime;
1842                                else
1843                                        AISpellsCooldown[i]=newspell->RecoveryTime;
1844
1845
1846                                //weve cast, set GCD
1847                                for (int j= 0; j<4; j++)
1848                                        if (AISpellsCooldown[j] < GCD)
1849                                                AISpellsCooldown[j] = GCD;
1850                        }
1851                }
1852        }
1853}
1854
1855// this is used for guardians. They are non respawnable creatures linked to a player
1856void Creature::SummonExpire()
1857{
1858    DeleteMe();
1859}
1860
1861void Creature::Despawn(uint32 delay, uint32 respawntime)
1862{
1863        if(delay)
1864        {
1865                sEventMgr.AddEvent(this, &Creature::Despawn, (uint32)0, respawntime, EVENT_CREATURE_RESPAWN, delay, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
1866                return;
1867        }
1868
1869        if(!IsInWorld())
1870                return;
1871
1872        if(GetMapMgr() && GetMapMgr()->GetMapInfo() && GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID)
1873        {
1874                if(GetCreatureInfo() && GetCreatureInfo()->Rank == 3)
1875                {
1876                        GetMapMgr()->RemoveCombatInProgress(GetGUID());
1877                }
1878        }
1879
1880        if(respawntime && !m_noRespawn)
1881        {
1882                /* get the cell with our SPAWN location. if we've moved cell this might break :P */
1883                MapCell * pCell = m_mapMgr->GetCellByCoords(m_spawnLocation.x, m_spawnLocation.y);
1884                if(!pCell)
1885                        pCell = m_mapCell;
1886
1887                Arcemu::Util::ARCEMU_ASSERT(   pCell != NULL );
1888                pCell->_respawnObjects.insert((Object*)this);
1889                sEventMgr.RemoveEvents(this);
1890                sEventMgr.AddEvent(m_mapMgr, &MapMgr::EventRespawnCreature, this, pCell, EVENT_CREATURE_RESPAWN, respawntime, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
1891                Unit::RemoveFromWorld(false);
1892                m_position = m_spawnLocation;
1893                m_respawnCell=pCell;
1894        }
1895        else
1896        {
1897                Unit::RemoveFromWorld(true);
1898                SafeDelete();
1899        }
1900}
1901
1902void Creature::TriggerScriptEvent(string func)
1903{
1904        if( _myScriptClass )
1905                _myScriptClass->StringFunctionCall( func.c_str() );
1906}
1907
1908void Creature::DestroyCustomWaypointMap()
1909{
1910        if(m_custom_waypoint_map)
1911        {
1912                for(WayPointMap::iterator itr = m_custom_waypoint_map->begin(); itr != m_custom_waypoint_map->end(); ++itr)
1913                {
1914                        if( (*itr) )
1915                                delete (*itr);
1916                }
1917                //delete m_custom_waypoint_map;
1918                m_custom_waypoint_map->clear();
1919                m_custom_waypoint_map = 0;
1920                m_aiInterface->SetWaypointMap(0);
1921        }
1922}
1923
1924void Creature::RemoveLimboState(Unit * healer)
1925{
1926        if(!m_limbostate != true)
1927                return;
1928
1929        m_limbostate = false;
1930        SetEmoteState(m_spawn ? m_spawn->emote_state : 0);
1931        SetHealth( GetMaxHealth());
1932        bInvincible = false;
1933}
1934
1935// Generates 3 random waypoints around the NPC
1936void Creature::SetGuardWaypoints()
1937{
1938        if(!GetMapMgr()) return;
1939        if(!GetCreatureInfo()) return;
1940
1941        GetAIInterface()->setMoveType(1);
1942        for(int i = 1; i <= 4; i++)
1943        {
1944                float ang = rand()/100.0f;
1945                float ran = (rand()%(100))/10.0f;
1946                while(ran < 1)
1947                        ran = (rand()%(100))/10.0f;
1948
1949                WayPoint * wp = new WayPoint;
1950                wp->id = i;
1951                wp->flags = 0;
1952                wp->waittime = 800;  /* these guards are antsy :P */
1953                wp->x = GetSpawnX()+ran*sin(ang);
1954                wp->y = GetSpawnY()+ran*cos(ang);
1955
1956                if (sWorld.Collision) {
1957                        wp->z = CollideInterface.GetHeight(m_mapId, wp->x, wp->y, m_spawnLocation.z + 2.0f);
1958                        if( wp->z == NO_WMO_HEIGHT )
1959                                wp->z = m_mapMgr->GetLandHeight(wp->x, wp->y);
1960
1961                        if( fabs( wp->z - m_spawnLocation.z ) > 10.0f )
1962                                wp->z = m_spawnLocation.z;
1963                } else {
1964                        wp->z = GetMapMgr()->GetLandHeight(wp->x, wp->y);
1965                }
1966
1967                wp->o = 0;
1968                wp->backwardemoteid = 0;
1969                wp->backwardemoteoneshot = 0;
1970                wp->forwardemoteid = 0;
1971                wp->forwardemoteoneshot = 0;
1972                wp->backwardskinid = m_uint32Values[UNIT_FIELD_NATIVEDISPLAYID];
1973                wp->forwardskinid = m_uint32Values[UNIT_FIELD_NATIVEDISPLAYID];
1974                GetAIInterface()->addWayPoint(wp);
1975        }
1976}
1977
1978uint32 Creature::GetNpcTextId()
1979{
1980        return objmgr.GetGossipTextForNpc(this->GetEntry());
1981}
1982
1983float Creature::GetBaseParry()
1984{
1985        // TODO what are the parry rates for mobs?
1986        // FACT: bosses have varying parry rates (used to tune the difficulty of boss fights)
1987
1988        // for now return a base of 5%, later get from dbase?
1989        return 5.0f;
1990}
1991
1992Group *Creature::GetGroup()
1993{
1994        if ( IsPet() )
1995                static_cast<Pet *>(this)->GetGroup();
1996        else if( IsTotem() && totemOwner != NULL )
1997                return totemOwner->GetGroup();
1998        else if( GetCreatedByGUID() && GetMapMgr() )
1999        {
2000                Unit *tu = GetMapMgr()->GetUnit( GetCreatedByGUID() );
2001                if( tu )
2002                {
2003                        if( tu->IsPlayer() )
2004                                static_cast<Player *>(tu)->GetGroup();
2005                        else if( tu->IsCreature() )
2006                                static_cast<Creature *>(tu)->GetGroup();
2007                }
2008                else return NULL;
2009        }
2010        return NULL;
2011}
2012
2013bool Creature::HasLootForPlayer(Player * plr)
2014{
2015        if( loot.gold > 0 )
2016                return true;
2017
2018        for(vector<__LootItem>::iterator itr = loot.items.begin(); itr != loot.items.end(); ++itr)
2019        {
2020                ItemPrototype * proto = itr->item.itemproto;
2021                if( proto != NULL )
2022                {
2023                        if( proto->Bonding == ITEM_BIND_QUEST || proto->Bonding == ITEM_BIND_QUEST2 )
2024                        {
2025                                if( plr->HasQuestForItem( proto->ItemId ) )
2026                                        return true;
2027                        }
2028                        else if( itr->iItemsCount > 0 )
2029                                return true;
2030                }
2031        }
2032        return false;
2033}
2034
2035uint32 Creature::GetRequiredLootSkill()
2036{
2037        if(GetCreatureInfo()->Flags1 & CREATURE_FLAG1_HERBLOOT)
2038                return SKILL_HERBALISM;     // herbalism
2039        else if(GetCreatureInfo()->Flags1 & CREATURE_FLAG1_MININGLOOT)
2040                return SKILL_MINING;        // mining   
2041        else if(GetCreatureInfo()->Flags1 & CREATURE_FLAG1_ENGINEERLOOT)
2042                return SKILL_ENGINEERING;
2043        else
2044                return SKILL_SKINNING;      // skinning
2045};
2046
2047//! Is PVP flagged?
2048bool Creature::IsPvPFlagged()
2049{
2050        return HasByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP );
2051}
2052
2053void Creature::SetPvPFlag()
2054{
2055        SetByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP );
2056       
2057        // adjust our guardians too
2058        std::set< Creature* >::iterator itr = m_Guardians.begin();
2059        for( ; itr != m_Guardians.end(); ++itr )
2060                (*itr)->SetPvPFlag();
2061}
2062
2063void Creature::RemovePvPFlag()
2064{
2065        RemoveByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP );
2066       
2067        // adjust our guardians too
2068        std::set< Creature* >::iterator itr = m_Guardians.begin();
2069        for( ; itr != m_Guardians.end(); ++itr )
2070                (*itr)->RemovePvPFlag();
2071}
2072
2073bool Creature::IsFFAPvPFlagged()
2074{
2075        return HasByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP );
2076}
2077
2078void Creature::SetFFAPvPFlag()
2079{
2080        SetByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP );
2081
2082        // adjust our guardians too
2083        std::set< Creature* >::iterator itr = m_Guardians.begin();
2084        for( ; itr != m_Guardians.end(); ++itr )
2085                (*itr)->SetFFAPvPFlag();
2086}
2087
2088void Creature::RemoveFFAPvPFlag()
2089{
2090        RemoveByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP );
2091
2092        // adjust our guardians too
2093        std::set< Creature* >::iterator itr = m_Guardians.begin();
2094        for( ; itr != m_Guardians.end(); ++itr )
2095                (*itr)->RemoveFFAPvPFlag();
2096}
2097
2098bool Creature::IsSanctuaryFlagged()
2099{ 
2100        return HasByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_SANCTUARY); 
2101}
2102
2103void Creature::SetSanctuaryFlag()
2104{ 
2105        SetByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_SANCTUARY );
2106       
2107        // adjust our guardians too
2108        std::set< Creature* >::iterator itr = m_Guardians.begin();
2109        for( ; itr != m_Guardians.end(); ++itr )
2110                (*itr)->SetSanctuaryFlag();
2111}
2112
2113void Creature::RemoveSanctuaryFlag()
2114{ 
2115        RemoveByteFlag( UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_SANCTUARY );
2116
2117        // adjust our guardians too
2118        std::set< Creature* >::iterator itr = m_Guardians.begin();
2119        for( ; itr != m_Guardians.end(); ++itr )
2120                (*itr)->RemoveSanctuaryFlag();
2121}
Note: See TracBrowser for help on using the browser.