[9033] Fixed percent mana regneration from spell 53228 and ranks buff.
[getmangos.git] / src / game / Creature.cpp
blob06949e94a07acb888435898798e303406f0f13b8
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Database/DatabaseEnv.h"
21 #include "WorldPacket.h"
22 #include "World.h"
23 #include "ObjectMgr.h"
24 #include "ObjectDefines.h"
25 #include "SpellMgr.h"
26 #include "Creature.h"
27 #include "QuestDef.h"
28 #include "GossipDef.h"
29 #include "Player.h"
30 #include "PoolManager.h"
31 #include "Opcodes.h"
32 #include "Log.h"
33 #include "LootMgr.h"
34 #include "MapManager.h"
35 #include "CreatureAI.h"
36 #include "CreatureAISelector.h"
37 #include "Formulas.h"
38 #include "WaypointMovementGenerator.h"
39 #include "InstanceData.h"
40 #include "BattleGroundMgr.h"
41 #include "Spell.h"
42 #include "Util.h"
43 #include "GridNotifiers.h"
44 #include "GridNotifiersImpl.h"
45 #include "CellImpl.h"
47 // apply implementation of the singletons
48 #include "Policies/SingletonImp.h"
50 TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
52 TrainerSpellMap::const_iterator itr = spellList.find(spell_id);
53 if (itr != spellList.end())
54 return &itr->second;
56 return NULL;
59 bool VendorItemData::RemoveItem( uint32 item_id )
61 for(VendorItemList::iterator i = m_items.begin(); i != m_items.end(); ++i )
63 if((*i)->item==item_id)
65 m_items.erase(i);
66 return true;
69 return false;
72 size_t VendorItemData::FindItemSlot(uint32 item_id) const
74 for(size_t i = 0; i < m_items.size(); ++i )
75 if(m_items[i]->item==item_id)
76 return i;
77 return m_items.size();
80 VendorItem const* VendorItemData::FindItem(uint32 item_id) const
82 for(VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i )
83 if((*i)->item==item_id)
84 return *i;
85 return NULL;
88 bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
90 if(Unit* victim = Unit::GetUnit(m_owner, m_victim))
92 while (!m_assistants.empty())
94 Creature* assistant = (Creature*)Unit::GetUnit(m_owner, *m_assistants.begin());
95 m_assistants.pop_front();
97 if (assistant && assistant->CanAssistTo(&m_owner, victim))
99 assistant->SetNoCallAssistance(true);
100 if(assistant->AI())
101 assistant->AI()->AttackStart(victim);
105 return true;
108 Creature::Creature() :
109 Unit(), i_AI(NULL),
110 lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
111 m_lootMoney(0), m_lootRecipient(0),
112 m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
113 m_isPet(false), m_isVehicle(false), m_isTotem(false),
114 m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0),
115 m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
116 m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
117 m_creatureInfo(NULL), m_isActiveObject(false), m_monsterMoveFlags(MONSTER_MOVE_WALK)
119 m_regenTimer = 200;
120 m_valuesCount = UNIT_END;
122 for(int i =0; i<4; ++i)
123 m_spells[i] = 0;
125 m_CreatureSpellCooldowns.clear();
126 m_CreatureCategoryCooldowns.clear();
127 m_GlobalCooldown = 0;
129 m_monsterMoveFlags = MONSTER_MOVE_WALK;
132 Creature::~Creature()
134 CleanupsBeforeDelete();
136 m_vendorItemCounts.clear();
138 delete i_AI;
139 i_AI = NULL;
142 void Creature::AddToWorld()
144 ///- Register the creature for guid lookup
145 if(!IsInWorld() && GetGUIDHigh()==HIGHGUID_UNIT)
146 GetMap()->GetObjectsStore().insert<Creature>(GetGUID(), (Creature*)this);
148 Unit::AddToWorld();
151 void Creature::RemoveFromWorld()
153 ///- Remove the creature from the accessor
154 if(IsInWorld() && GetGUIDHigh()==HIGHGUID_UNIT)
155 GetMap()->GetObjectsStore().erase<Creature>(GetGUID(), (Creature*)NULL);
157 Unit::RemoveFromWorld();
160 void Creature::RemoveCorpse()
162 if ((getDeathState() != CORPSE && !m_isDeadByDefault) || (getDeathState() != ALIVE && m_isDeadByDefault))
163 return;
165 m_deathTimer = 0;
166 setDeathState(DEAD);
167 UpdateObjectVisibility();
168 loot.clear();
169 uint32 respawnDelay = m_respawnDelay;
170 if (AI())
171 AI()->CorpseRemoved(respawnDelay);
173 m_respawnTime = time(NULL) + respawnDelay;
175 float x,y,z,o;
176 GetRespawnCoord(x, y, z, &o);
177 GetMap()->CreatureRelocation(this,x,y,z,o);
181 * change the entry of creature until respawn
183 bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data )
185 CreatureInfo const *normalInfo = ObjectMgr::GetCreatureTemplate(Entry);
186 if(!normalInfo)
188 sLog.outErrorDb("Creature::UpdateEntry creature entry %u does not exist.", Entry);
189 return false;
192 // get difficulty 1 mode entry
193 uint32 actualEntry = Entry;
194 CreatureInfo const *cinfo = normalInfo;
195 // TODO correctly implement spawnmodes for non-bg maps
196 for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1; ++diff)
198 if (normalInfo->DifficultyEntry[diff])
200 // we already have valid Map pointer for current creature!
201 if (GetMap()->GetSpawnMode() > diff)
203 cinfo = ObjectMgr::GetCreatureTemplate(normalInfo->DifficultyEntry[diff]);
204 if (!cinfo)
206 // maybe check such things already at startup
207 sLog.outErrorDb("Creature::UpdateEntry creature difficulty %u entry %u does not exist.", diff + 1, actualEntry);
208 return false;
214 SetEntry(Entry); // normal entry always
215 m_creatureInfo = cinfo; // map mode related always
217 // equal to player Race field, but creature does not have race
218 SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
220 // known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE
221 SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class));
223 uint32 display_id = sObjectMgr.ChooseDisplayId(team, GetCreatureInfo(), data);
224 if (!display_id) // Cancel load if no display id
226 sLog.outErrorDb("Creature (Entry: %u) has model %u not found in table `creature_model_info`, can't load. ", Entry, display_id);
227 return false;
230 CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelRandomGender(display_id);
231 if (!minfo) // Cancel load if no model defined
233 sLog.outErrorDb("Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ",Entry);
234 return false;
237 display_id = minfo->modelid; // it can be different (for another gender)
239 SetDisplayId(display_id);
240 SetNativeDisplayId(display_id);
241 SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
243 // Load creature equipment
244 if(!data || data->equipmentId == 0)
245 { // use default from the template
246 LoadEquipment(cinfo->equipmentId);
248 else if(data && data->equipmentId != -1)
249 { // override, -1 means no equipment
250 LoadEquipment(data->equipmentId);
253 SetName(normalInfo->Name); // at normal entry always
255 SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
256 SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach );
258 SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
260 SetSpeed(MOVE_WALK, cinfo->speed );
261 SetSpeed(MOVE_RUN, cinfo->speed );
262 SetSpeed(MOVE_SWIM, cinfo->speed );
264 SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale);
266 // checked at loading
267 m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
268 if(!m_respawnradius && m_defaultMovementType==RANDOM_MOTION_TYPE)
269 m_defaultMovementType = IDLE_MOTION_TYPE;
271 return true;
274 bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
276 if(!InitEntry(Entry,team,data))
277 return false;
279 m_regenHealth = GetCreatureInfo()->RegenHealth;
281 // creatures always have melee weapon ready if any
282 SetSheath(SHEATH_STATE_MELEE);
284 SelectLevel(GetCreatureInfo());
285 if (team == HORDE)
286 setFaction(GetCreatureInfo()->faction_H);
287 else
288 setFaction(GetCreatureInfo()->faction_A);
290 SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag);
292 SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime);
293 SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime);
294 SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime);
296 SetUInt32Value(UNIT_FIELD_FLAGS,GetCreatureInfo()->unit_flags);
297 SetUInt32Value(UNIT_DYNAMIC_FLAGS,GetCreatureInfo()->dynamicflags);
299 SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor));
300 SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1));
301 SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2));
302 SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3));
303 SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4));
304 SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5));
305 SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6));
307 SetCanModifyStats(true);
308 UpdateAllStats();
310 // checked and error show at loading templates
311 if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(GetCreatureInfo()->faction_A))
313 if (factionTemplate->factionFlags & FACTION_TEMPLATE_FLAG_PVP)
314 SetPvP(true);
315 else
316 SetPvP(false);
319 for(int i=0; i < CREATURE_MAX_SPELLS; ++i)
320 m_spells[i] = GetCreatureInfo()->spells[i];
322 return true;
325 void Creature::Update(uint32 diff)
327 if(m_GlobalCooldown <= diff)
328 m_GlobalCooldown = 0;
329 else
330 m_GlobalCooldown -= diff;
332 switch( m_deathState )
334 case JUST_ALIVED:
335 // Don't must be called, see Creature::setDeathState JUST_ALIVED -> ALIVE promoting.
336 sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_ALIVED (4)",GetGUIDLow(),GetEntry());
337 break;
338 case JUST_DIED:
339 // Don't must be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting.
340 sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_DEAD (1)",GetGUIDLow(),GetEntry());
341 break;
342 case DEAD:
344 if( m_respawnTime <= time(NULL) )
346 DEBUG_LOG("Respawning...");
347 m_respawnTime = 0;
348 lootForPickPocketed = false;
349 lootForBody = false;
351 if(m_originalEntry != GetEntry())
352 UpdateEntry(m_originalEntry);
354 CreatureInfo const *cinfo = GetCreatureInfo();
356 SelectLevel(cinfo);
357 SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
358 if (m_isDeadByDefault)
360 setDeathState(JUST_DIED);
361 SetHealth(0);
362 i_motionMaster.Clear();
363 clearUnitState(UNIT_STAT_ALL_STATE);
364 LoadCreaturesAddon(true);
366 else
367 setDeathState( JUST_ALIVED );
369 //Call AI respawn virtual function
370 i_AI->JustRespawned();
372 uint16 poolid = sPoolMgr.IsPartOfAPool(GetGUIDLow(), GetTypeId());
373 if (poolid)
374 sPoolMgr.UpdatePool(poolid, GetGUIDLow(), TYPEID_UNIT);
375 else
376 GetMap()->Add(this);
378 break;
380 case CORPSE:
382 if (m_isDeadByDefault)
383 break;
385 if( m_deathTimer <= diff )
387 RemoveCorpse();
388 DEBUG_LOG("Removing corpse... %u ", GetEntry());
390 else
392 m_deathTimer -= diff;
393 if (m_groupLootTimer && lootingGroupLeaderGUID)
395 if(diff <= m_groupLootTimer)
397 m_groupLootTimer -= diff;
399 else
401 Group* group = sObjectMgr.GetGroupByLeader(lootingGroupLeaderGUID);
402 if (group)
403 group->EndRoll();
404 m_groupLootTimer = 0;
405 lootingGroupLeaderGUID = 0;
410 break;
412 case ALIVE:
414 if (m_isDeadByDefault)
416 if( m_deathTimer <= diff )
418 RemoveCorpse();
419 DEBUG_LOG("Removing alive corpse... %u ", GetEntry());
421 else
423 m_deathTimer -= diff;
427 Unit::Update( diff );
429 // creature can be dead after Unit::Update call
430 // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
431 if(!isAlive())
432 break;
434 if(!IsInEvadeMode())
436 // do not allow the AI to be changed during update
437 m_AI_locked = true;
438 i_AI->UpdateAI(diff);
439 m_AI_locked = false;
442 // creature can be dead after UpdateAI call
443 // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
444 if(!isAlive())
445 break;
446 if(m_regenTimer > 0)
448 if(diff >= m_regenTimer)
449 m_regenTimer = 0;
450 else
451 m_regenTimer -= diff;
453 if (m_regenTimer != 0)
454 break;
456 if (!isInCombat() || IsPolymorphed())
457 RegenerateHealth();
459 RegenerateMana();
461 m_regenTimer = REGEN_TIME_FULL;
462 break;
464 case DEAD_FALLING:
466 if (!FallGround())
467 setDeathState(JUST_DIED);
469 default:
470 break;
474 void Creature::RegenerateMana()
476 uint32 curValue = GetPower(POWER_MANA);
477 uint32 maxValue = GetMaxPower(POWER_MANA);
479 if (curValue >= maxValue)
480 return;
482 uint32 addvalue = 0;
484 // Combat and any controlled creature
485 if (isInCombat() || GetCharmerOrOwnerGUID())
487 if(!IsUnderLastManaUseEffect())
489 float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA);
490 float Spirit = GetStat(STAT_SPIRIT);
492 addvalue = uint32((Spirit/5.0f + 17.0f) * ManaIncreaseRate);
495 else
496 addvalue = maxValue/3;
498 ModifyPower(POWER_MANA, addvalue);
501 void Creature::RegenerateHealth()
503 if (!isRegeneratingHealth())
504 return;
506 uint32 curValue = GetHealth();
507 uint32 maxValue = GetMaxHealth();
509 if (curValue >= maxValue)
510 return;
512 uint32 addvalue = 0;
514 // Not only pet, but any controlled creature
515 if(GetCharmerOrOwnerGUID())
517 float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH);
518 float Spirit = GetStat(STAT_SPIRIT);
520 if( GetPower(POWER_MANA) > 0 )
521 addvalue = uint32(Spirit * 0.25 * HealthIncreaseRate);
522 else
523 addvalue = uint32(Spirit * 0.80 * HealthIncreaseRate);
525 else
526 addvalue = maxValue/3;
528 ModifyHealth(addvalue);
531 void Creature::DoFleeToGetAssistance()
533 if (!getVictim())
534 return;
536 float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS);
537 if (radius >0)
539 Creature* pCreature = NULL;
541 CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
542 Cell cell(p);
543 cell.data.Part.reserved = ALL_DISTRICT;
544 cell.SetNoCreate();
545 MaNGOS::NearestAssistCreatureInCreatureRangeCheck u_check(this, getVictim(), radius);
546 MaNGOS::CreatureLastSearcher<MaNGOS::NearestAssistCreatureInCreatureRangeCheck> searcher(this, pCreature, u_check);
548 TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestAssistCreatureInCreatureRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
550 CellLock<GridReadGuard> cell_lock(cell, p);
551 cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, radius);
553 SetNoSearchAssistance(true);
554 if(!pCreature)
555 SetFeared(true, getVictim()->GetGUID(), 0 ,sWorld.getConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY));
556 else
557 GetMotionMaster()->MoveSeekAssistance(pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ());
561 bool Creature::AIM_Initialize()
563 // make sure nothing can change the AI during AI update
564 if(m_AI_locked)
566 sLog.outDebug("AIM_Initialize: failed to init, locked.");
567 return false;
570 CreatureAI * oldAI = i_AI;
571 i_motionMaster.Initialize();
572 i_AI = FactorySelector::selectAI(this);
573 if (oldAI)
574 delete oldAI;
575 return true;
578 bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, const CreatureData *data)
580 ASSERT(map);
581 SetMap(map);
582 SetPhaseMask(phaseMask,false);
584 //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
585 const bool bResult = CreateFromProto(guidlow, Entry, team, data);
587 if (bResult)
589 //Notify the map's instance data.
590 //Only works if you create the object in it, not if it is moves to that map.
591 //Normally non-players do not teleport to other maps.
592 if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
593 ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this);
595 switch (GetCreatureInfo()->rank)
597 case CREATURE_ELITE_RARE:
598 m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RARE);
599 break;
600 case CREATURE_ELITE_ELITE:
601 m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_ELITE);
602 break;
603 case CREATURE_ELITE_RAREELITE:
604 m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_RAREELITE);
605 break;
606 case CREATURE_ELITE_WORLDBOSS:
607 m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_WORLDBOSS);
608 break;
609 default:
610 m_corpseDelay = sWorld.getConfig(CONFIG_CORPSE_DECAY_NORMAL);
611 break;
613 LoadCreaturesAddon();
616 return bResult;
619 bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const
621 if(!isTrainer())
622 return false;
624 TrainerSpellData const* trainer_spells = GetTrainerSpells();
626 if(!trainer_spells || trainer_spells->spellList.empty())
628 sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.",
629 GetGUIDLow(),GetEntry());
630 return false;
633 switch(GetCreatureInfo()->trainer_type)
635 case TRAINER_TYPE_CLASS:
636 if(pPlayer->getClass()!=GetCreatureInfo()->trainer_class)
638 if(msg)
640 pPlayer->PlayerTalkClass->ClearMenus();
641 switch(GetCreatureInfo()->trainer_class)
643 case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu( 4913,GetGUID()); break;
644 case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090,GetGUID()); break;
645 case CLASS_MAGE: pPlayer->PlayerTalkClass->SendGossipMenu( 328,GetGUID()); break;
646 case CLASS_PALADIN:pPlayer->PlayerTalkClass->SendGossipMenu( 1635,GetGUID()); break;
647 case CLASS_PRIEST: pPlayer->PlayerTalkClass->SendGossipMenu( 4436,GetGUID()); break;
648 case CLASS_ROGUE: pPlayer->PlayerTalkClass->SendGossipMenu( 4797,GetGUID()); break;
649 case CLASS_SHAMAN: pPlayer->PlayerTalkClass->SendGossipMenu( 5003,GetGUID()); break;
650 case CLASS_WARLOCK:pPlayer->PlayerTalkClass->SendGossipMenu( 5836,GetGUID()); break;
651 case CLASS_WARRIOR:pPlayer->PlayerTalkClass->SendGossipMenu( 4985,GetGUID()); break;
654 return false;
656 break;
657 case TRAINER_TYPE_PETS:
658 if(pPlayer->getClass()!=CLASS_HUNTER)
660 pPlayer->PlayerTalkClass->ClearMenus();
661 pPlayer->PlayerTalkClass->SendGossipMenu(3620,GetGUID());
662 return false;
664 break;
665 case TRAINER_TYPE_MOUNTS:
666 if(GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race)
668 if(msg)
670 pPlayer->PlayerTalkClass->ClearMenus();
671 switch(GetCreatureInfo()->trainer_class)
673 case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865,GetGUID()); break;
674 case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881,GetGUID()); break;
675 case RACE_HUMAN: pPlayer->PlayerTalkClass->SendGossipMenu(5861,GetGUID()); break;
676 case RACE_NIGHTELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break;
677 case RACE_ORC: pPlayer->PlayerTalkClass->SendGossipMenu(5863,GetGUID()); break;
678 case RACE_TAUREN: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break;
679 case RACE_TROLL: pPlayer->PlayerTalkClass->SendGossipMenu(5816,GetGUID()); break;
680 case RACE_UNDEAD_PLAYER:pPlayer->PlayerTalkClass->SendGossipMenu( 624,GetGUID()); break;
681 case RACE_BLOODELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break;
682 case RACE_DRAENEI: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break;
685 return false;
687 break;
688 case TRAINER_TYPE_TRADESKILLS:
689 if(GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell))
691 if(msg)
693 pPlayer->PlayerTalkClass->ClearMenus();
694 pPlayer->PlayerTalkClass->SendGossipMenu(11031,GetGUID());
696 return false;
698 break;
699 default:
700 return false; // checked and error output at creature_template loading
702 return true;
705 bool Creature::isCanInteractWithBattleMaster(Player* pPlayer, bool msg) const
707 if(!isBattleMaster())
708 return false;
710 BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(GetEntry());
711 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
712 return false;
714 if(!msg)
715 return pPlayer->GetBGAccessByLevel(bgTypeId);
717 if(!pPlayer->GetBGAccessByLevel(bgTypeId))
719 pPlayer->PlayerTalkClass->ClearMenus();
720 switch(bgTypeId)
722 case BATTLEGROUND_AV: pPlayer->PlayerTalkClass->SendGossipMenu(7616,GetGUID()); break;
723 case BATTLEGROUND_WS: pPlayer->PlayerTalkClass->SendGossipMenu(7599,GetGUID()); break;
724 case BATTLEGROUND_AB: pPlayer->PlayerTalkClass->SendGossipMenu(7642,GetGUID()); break;
725 case BATTLEGROUND_EY:
726 case BATTLEGROUND_NA:
727 case BATTLEGROUND_BE:
728 case BATTLEGROUND_AA:
729 case BATTLEGROUND_RL:
730 case BATTLEGROUND_SA:
731 case BATTLEGROUND_DS:
732 case BATTLEGROUND_RV: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break;
733 default: break;
735 return false;
737 return true;
740 bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const
742 return pPlayer->getLevel() >= 10
743 && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS
744 && pPlayer->getClass() == GetCreatureInfo()->trainer_class;
747 void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, MonsterMovementFlags flags, uint8 type)
749 /* uint32 timeElap = getMSTime();
750 if ((timeElap - m_startMove) < m_moveTime)
752 oX = (dX - oX) * ( (timeElap - m_startMove) / m_moveTime );
753 oY = (dY - oY) * ( (timeElap - m_startMove) / m_moveTime );
755 else
757 oX = dX;
758 oY = dY;
761 dX = x;
762 dY = y;
763 m_orientation = atan2((oY - dY), (oX - dX));
765 m_startMove = getMSTime();
766 m_moveTime = time;*/
767 SendMonsterMove(x, y, z, type, flags, time);
770 Player *Creature::GetLootRecipient() const
772 if (!m_lootRecipient) return NULL;
773 else return ObjectAccessor::FindPlayer(m_lootRecipient);
776 void Creature::SetLootRecipient(Unit *unit)
778 // set the player whose group should receive the right
779 // to loot the creature after it dies
780 // should be set to NULL after the loot disappears
782 if (!unit)
784 m_lootRecipient = 0;
785 RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER);
786 return;
789 Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
790 if(!player) // normal creature, no player involved
791 return;
793 m_lootRecipient = player->GetGUID();
794 SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER);
797 void Creature::SaveToDB()
799 // this should only be used when the creature has already been loaded
800 // preferably after adding to map, because mapid may not be valid otherwise
801 CreatureData const *data = sObjectMgr.GetCreatureData(m_DBTableGuid);
802 if(!data)
804 sLog.outError("Creature::SaveToDB failed, cannot get creature data!");
805 return;
808 SaveToDB(GetMapId(), data->spawnMask,GetPhaseMask());
811 void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
813 // update in loaded data
814 if (!m_DBTableGuid)
815 m_DBTableGuid = GetGUIDLow();
816 CreatureData& data = sObjectMgr.NewOrExistCreatureData(m_DBTableGuid);
818 uint32 displayId = GetNativeDisplayId();
820 // check if it's a custom model and if not, use 0 for displayId
821 CreatureInfo const *cinfo = GetCreatureInfo();
822 if (cinfo)
824 if (displayId != cinfo->DisplayID_A[0] && displayId != cinfo->DisplayID_A[1] &&
825 displayId != cinfo->DisplayID_H[0] && displayId != cinfo->DisplayID_H[1])
827 if (cinfo->DisplayID_A[0])
828 if (CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelInfo(cinfo->DisplayID_A[0]))
829 if(displayId == minfo->modelid_other_gender)
830 displayId = 0;
832 if (displayId && cinfo->DisplayID_A[1])
833 if (CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelInfo(cinfo->DisplayID_A[1]))
834 if(displayId == minfo->modelid_other_gender)
835 displayId = 0;
837 if (displayId && cinfo->DisplayID_H[0])
838 if (CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelInfo(cinfo->DisplayID_H[0]))
839 if(displayId == minfo->modelid_other_gender)
840 displayId = 0;
842 if (displayId && cinfo->DisplayID_H[1])
843 if (CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelInfo(cinfo->DisplayID_H[1]))
844 if(displayId == minfo->modelid_other_gender)
845 displayId = 0;
847 else
848 displayId = 0;
851 // data->guid = guid don't must be update at save
852 data.id = GetEntry();
853 data.mapid = mapid;
854 data.phaseMask = phaseMask;
855 data.displayid = displayId;
856 data.equipmentId = GetEquipmentId();
857 data.posX = GetPositionX();
858 data.posY = GetPositionY();
859 data.posZ = GetPositionZ();
860 data.orientation = GetOrientation();
861 data.spawntimesecs = m_respawnDelay;
862 // prevent add data integrity problems
863 data.spawndist = GetDefaultMovementType()==IDLE_MOTION_TYPE ? 0 : m_respawnradius;
864 data.currentwaypoint = 0;
865 data.curhealth = GetHealth();
866 data.curmana = GetPower(POWER_MANA);
867 data.is_dead = m_isDeadByDefault;
868 // prevent add data integrity problems
869 data.movementType = !m_respawnradius && GetDefaultMovementType()==RANDOM_MOTION_TYPE
870 ? IDLE_MOTION_TYPE : GetDefaultMovementType();
871 data.spawnMask = spawnMask;
873 // updated in DB
874 WorldDatabase.BeginTransaction();
876 WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
878 std::ostringstream ss;
879 ss << "INSERT INTO creature VALUES ("
880 << m_DBTableGuid << ","
881 << GetEntry() << ","
882 << mapid <<","
883 << uint32(spawnMask) << "," // cast to prevent save as symbol
884 << uint16(GetPhaseMask()) << "," // prevent out of range error
885 << displayId <<","
886 << GetEquipmentId() <<","
887 << GetPositionX() << ","
888 << GetPositionY() << ","
889 << GetPositionZ() << ","
890 << GetOrientation() << ","
891 << m_respawnDelay << "," //respawn time
892 << (float) m_respawnradius << "," //spawn distance (float)
893 << (uint32) (0) << "," //currentwaypoint
894 << GetHealth() << "," //curhealth
895 << GetPower(POWER_MANA) << "," //curmana
896 << (m_isDeadByDefault ? 1 : 0) << "," //is_dead
897 << GetDefaultMovementType() << ")"; //default movement generator type
899 WorldDatabase.PExecuteLog( ss.str( ).c_str( ) );
901 WorldDatabase.CommitTransaction();
904 void Creature::SelectLevel(const CreatureInfo *cinfo)
906 uint32 rank = isPet()? 0 : cinfo->rank;
908 // level
909 uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel);
910 uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel);
911 uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
912 SetLevel(level);
914 float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel))/(maxlevel - minlevel);
916 // health
917 float healthmod = _GetHealthMod(rank);
919 uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth);
920 uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth);
921 uint32 health = uint32(healthmod * (minhealth + uint32(rellevel*(maxhealth - minhealth))));
923 SetCreateHealth(health);
924 SetMaxHealth(health);
925 SetHealth(health);
927 // mana
928 uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana);
929 uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana);
930 uint32 mana = minmana + uint32(rellevel*(maxmana - minmana));
932 SetCreateMana(mana);
933 SetMaxPower(POWER_MANA, mana); //MAX Mana
934 SetPower(POWER_MANA, mana);
936 // TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
938 SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, health);
939 SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, mana);
941 // damage
942 float damagemod = _GetDamageMod(rank);
944 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
945 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
947 SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod);
948 SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * damagemod);
950 SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
953 float Creature::_GetHealthMod(int32 Rank)
955 switch (Rank) // define rates for each elite rank
957 case CREATURE_ELITE_NORMAL:
958 return sWorld.getRate(RATE_CREATURE_NORMAL_HP);
959 case CREATURE_ELITE_ELITE:
960 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP);
961 case CREATURE_ELITE_RAREELITE:
962 return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_HP);
963 case CREATURE_ELITE_WORLDBOSS:
964 return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_HP);
965 case CREATURE_ELITE_RARE:
966 return sWorld.getRate(RATE_CREATURE_ELITE_RARE_HP);
967 default:
968 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_HP);
972 float Creature::_GetDamageMod(int32 Rank)
974 switch (Rank) // define rates for each elite rank
976 case CREATURE_ELITE_NORMAL:
977 return sWorld.getRate(RATE_CREATURE_NORMAL_DAMAGE);
978 case CREATURE_ELITE_ELITE:
979 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
980 case CREATURE_ELITE_RAREELITE:
981 return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_DAMAGE);
982 case CREATURE_ELITE_WORLDBOSS:
983 return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE);
984 case CREATURE_ELITE_RARE:
985 return sWorld.getRate(RATE_CREATURE_ELITE_RARE_DAMAGE);
986 default:
987 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
991 float Creature::GetSpellDamageMod(int32 Rank)
993 switch (Rank) // define rates for each elite rank
995 case CREATURE_ELITE_NORMAL:
996 return sWorld.getRate(RATE_CREATURE_NORMAL_SPELLDAMAGE);
997 case CREATURE_ELITE_ELITE:
998 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE);
999 case CREATURE_ELITE_RAREELITE:
1000 return sWorld.getRate(RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE);
1001 case CREATURE_ELITE_WORLDBOSS:
1002 return sWorld.getRate(RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE);
1003 case CREATURE_ELITE_RARE:
1004 return sWorld.getRate(RATE_CREATURE_ELITE_RARE_SPELLDAMAGE);
1005 default:
1006 return sWorld.getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE);
1010 bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const CreatureData *data)
1012 CreatureInfo const *cinfo = ObjectMgr::GetCreatureTemplate(Entry);
1013 if(!cinfo)
1015 sLog.outErrorDb("Creature entry %u does not exist.", Entry);
1016 return false;
1018 m_originalEntry = Entry;
1020 Object::_Create(guidlow, Entry, HIGHGUID_UNIT);
1022 if(!UpdateEntry(Entry, team, data))
1023 return false;
1025 return true;
1028 bool Creature::LoadFromDB(uint32 guid, Map *map)
1030 CreatureData const* data = sObjectMgr.GetCreatureData(guid);
1032 if(!data)
1034 sLog.outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid);
1035 return false;
1038 m_DBTableGuid = guid;
1039 if (map->GetInstanceId() == 0)
1041 // Creature can be loaded already in map if grid has been unloaded while creature walk to another grid
1042 // FIXME: until creature guids is global and for instances used dynamic generated guids
1043 // in instance possible load creature duplicates with same DB guid but different in game guids
1044 // This will be until implementing per-map creature guids
1045 if (map->GetCreature(MAKE_NEW_GUID(guid,data->id,HIGHGUID_UNIT)))
1046 return false;
1048 else
1049 guid = sObjectMgr.GenerateLowGuid(HIGHGUID_UNIT);
1051 uint16 team = 0;
1052 if(!Create(guid,map,data->phaseMask,data->id,team,data))
1053 return false;
1055 Relocate(data->posX,data->posY,data->posZ,data->orientation);
1057 if(!IsPositionValid())
1059 sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY());
1060 return false;
1063 m_respawnradius = data->spawndist;
1065 m_respawnDelay = data->spawntimesecs;
1066 m_isDeadByDefault = data->is_dead;
1067 m_deathState = m_isDeadByDefault ? DEAD : ALIVE;
1069 m_respawnTime = sObjectMgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId());
1070 if(m_respawnTime > time(NULL)) // not ready to respawn
1072 m_deathState = DEAD;
1073 if(canFly())
1075 float tz = GetMap()->GetHeight(data->posX,data->posY,data->posZ,false);
1076 if(data->posZ - tz > 0.1)
1077 Relocate(data->posX,data->posY,tz);
1080 else if(m_respawnTime) // respawn time set but expired
1082 m_respawnTime = 0;
1083 sObjectMgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0);
1086 uint32 curhealth = data->curhealth;
1087 if(curhealth)
1089 curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank));
1090 if(curhealth < 1)
1091 curhealth = 1;
1094 SetHealth(m_deathState == ALIVE ? curhealth : 0);
1095 SetPower(POWER_MANA,data->curmana);
1097 SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
1099 // checked at creature_template loading
1100 m_defaultMovementType = MovementGeneratorType(data->movementType);
1102 AIM_Initialize();
1103 return true;
1106 void Creature::LoadEquipment(uint32 equip_entry, bool force)
1108 if(equip_entry == 0)
1110 if (force)
1112 for (uint8 i = 0; i < 3; ++i)
1113 SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
1114 m_equipmentId = 0;
1116 return;
1119 EquipmentInfo const *einfo = sObjectMgr.GetEquipmentInfo(equip_entry);
1120 if (!einfo)
1121 return;
1123 m_equipmentId = equip_entry;
1124 for (uint8 i = 0; i < 3; ++i)
1125 SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->equipentry[i]);
1128 bool Creature::hasQuest(uint32 quest_id) const
1130 QuestRelations const& qr = sObjectMgr.mCreatureQuestRelations;
1131 for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr)
1133 if(itr->second==quest_id)
1134 return true;
1136 return false;
1139 bool Creature::hasInvolvedQuest(uint32 quest_id) const
1141 QuestRelations const& qr = sObjectMgr.mCreatureQuestInvolvedRelations;
1142 for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr)
1144 if(itr->second==quest_id)
1145 return true;
1147 return false;
1150 void Creature::DeleteFromDB()
1152 if (!m_DBTableGuid)
1154 sLog.outDebug("Trying to delete not saved creature!");
1155 return;
1158 sObjectMgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0);
1159 sObjectMgr.DeleteCreatureData(m_DBTableGuid);
1161 WorldDatabase.BeginTransaction();
1162 WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
1163 WorldDatabase.PExecuteLog("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid);
1164 WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id = '%u'", m_DBTableGuid);
1165 WorldDatabase.PExecuteLog("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid);
1166 WorldDatabase.PExecuteLog("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid);
1167 WorldDatabase.PExecuteLog("DELETE FROM creature_battleground WHERE guid = '%u'", m_DBTableGuid);
1168 WorldDatabase.CommitTransaction();
1171 float Creature::GetAttackDistance(Unit const* pl) const
1173 float aggroRate = sWorld.getRate(RATE_CREATURE_AGGRO);
1174 if(aggroRate==0)
1175 return 0.0f;
1177 uint32 playerlevel = pl->getLevelForTarget(this);
1178 uint32 creaturelevel = getLevelForTarget(pl);
1180 int32 leveldif = int32(playerlevel) - int32(creaturelevel);
1182 // "The maximum Aggro Radius has a cap of 25 levels under. Example: A level 30 char has the same Aggro Radius of a level 5 char on a level 60 mob."
1183 if ( leveldif < - 25)
1184 leveldif = -25;
1186 // "The aggro radius of a mob having the same level as the player is roughly 20 yards"
1187 float RetDistance = 20;
1189 // "Aggro Radius varies with level difference at a rate of roughly 1 yard/level"
1190 // radius grow if playlevel < creaturelevel
1191 RetDistance -= (float)leveldif;
1193 if(creaturelevel+5 <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
1195 // detect range auras
1196 RetDistance += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE);
1198 // detected range auras
1199 RetDistance += pl->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE);
1202 // "Minimum Aggro Radius for a mob seems to be combat range (5 yards)"
1203 if(RetDistance < 5)
1204 RetDistance = 5;
1206 return (RetDistance*aggroRate);
1209 void Creature::setDeathState(DeathState s)
1211 if ((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault))
1213 m_deathTimer = m_corpseDelay*IN_MILISECONDS;
1215 // always save boss respawn time at death to prevent crash cheating
1216 if (sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss())
1217 SaveRespawnTime();
1219 if (canFly() && FallGround())
1220 return;
1222 if (!IsStopped())
1223 StopMoving();
1225 Unit::setDeathState(s);
1227 if (s == JUST_DIED)
1229 SetTargetGUID(0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
1230 SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
1232 if (!isPet() && GetCreatureInfo()->SkinLootId)
1233 if (LootTemplates_Skinning.HaveLootFor(GetCreatureInfo()->SkinLootId))
1234 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
1236 if (canFly() && FallGround())
1237 return;
1239 SetNoSearchAssistance(false);
1240 Unit::setDeathState(CORPSE);
1242 if (s == JUST_ALIVED)
1244 SetHealth(GetMaxHealth());
1245 SetLootRecipient(NULL);
1246 CreatureInfo const *cinfo = GetCreatureInfo();
1247 SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
1248 RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
1249 AddMonsterMoveFlag(MONSTER_MOVE_WALK);
1250 SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
1251 Unit::setDeathState(ALIVE);
1252 clearUnitState(UNIT_STAT_ALL_STATE);
1253 i_motionMaster.Clear();
1254 SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
1255 LoadCreaturesAddon(true);
1259 bool Creature::FallGround()
1261 // Let's abort after we called this function one time
1262 if (getDeathState() == DEAD_FALLING)
1263 return false;
1265 // Let's do with no vmap because no way to get far distance with vmap high call
1266 float tz = GetMap()->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), false);
1268 // Abort too if the ground is very near
1269 if (fabs(GetPositionZ() - tz) < 0.1f)
1270 return false;
1272 Unit::setDeathState(DEAD_FALLING);
1273 GetMotionMaster()->MovePoint(0, GetPositionX(), GetPositionY(), tz);
1274 Relocate(GetPositionX(), GetPositionY(), tz);
1275 return true;
1278 void Creature::Respawn()
1280 RemoveCorpse();
1282 // forced recreate creature object at clients
1283 UnitVisibility currentVis = GetVisibility();
1284 SetVisibility(VISIBILITY_RESPAWN);
1285 UpdateObjectVisibility();
1286 SetVisibility(currentVis); // restore visibility state
1287 UpdateObjectVisibility();
1289 if(getDeathState()==DEAD)
1291 if (m_DBTableGuid)
1292 sObjectMgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0);
1293 m_respawnTime = time(NULL); // respawn at next tick
1297 void Creature::ForcedDespawn()
1299 setDeathState(JUST_DIED);
1300 RemoveCorpse();
1301 SetHealth(0); // just for nice GM-mode view
1304 bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo)
1306 if (!spellInfo)
1307 return false;
1309 if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))
1310 return true;
1312 return Unit::IsImmunedToSpell(spellInfo);
1315 bool Creature::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
1317 if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->EffectMechanic[index] - 1)))
1318 return true;
1320 // Taunt immunity special flag check
1321 if (GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NOT_TAUNTABLE)
1323 // Taunt aura apply check
1324 if (spellInfo->Effect[index] == SPELL_EFFECT_APPLY_AURA)
1326 if (spellInfo->EffectApplyAuraName[index] == SPELL_AURA_MOD_TAUNT)
1327 return true;
1329 // Spell effect taunt check
1330 else if (spellInfo->Effect[index] == SPELL_EFFECT_ATTACK_ME)
1331 return true;
1334 return Unit::IsImmunedToSpellEffect(spellInfo, index);
1337 SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim)
1339 if(!pVictim)
1340 return NULL;
1342 for(uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
1344 if(!m_spells[i])
1345 continue;
1346 SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] );
1347 if(!spellInfo)
1349 sLog.outError("WORLD: unknown spell id %i", m_spells[i]);
1350 continue;
1353 bool bcontinue = true;
1354 for(uint32 j=0;j<3;j++)
1356 if( (spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE ) ||
1357 (spellInfo->Effect[j] == SPELL_EFFECT_INSTAKILL) ||
1358 (spellInfo->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) ||
1359 (spellInfo->Effect[j] == SPELL_EFFECT_HEALTH_LEECH )
1362 bcontinue = false;
1363 break;
1366 if(bcontinue) continue;
1368 if(spellInfo->manaCost > GetPower(POWER_MANA))
1369 continue;
1370 SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
1371 float range = GetSpellMaxRange(srange);
1372 float minrange = GetSpellMinRange(srange);
1374 float dist = GetCombatDistance(pVictim);
1376 //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx )
1377 // continue;
1378 if( dist > range || dist < minrange )
1379 continue;
1380 if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
1381 continue;
1382 if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
1383 continue;
1384 return spellInfo;
1386 return NULL;
1389 SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim)
1391 if(!pVictim)
1392 return NULL;
1394 for(uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
1396 if(!m_spells[i])
1397 continue;
1398 SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] );
1399 if(!spellInfo)
1401 sLog.outError("WORLD: unknown spell id %i", m_spells[i]);
1402 continue;
1405 bool bcontinue = true;
1406 for(uint32 j=0;j<3;j++)
1408 if( (spellInfo->Effect[j] == SPELL_EFFECT_HEAL ) )
1410 bcontinue = false;
1411 break;
1414 if(bcontinue) continue;
1416 if(spellInfo->manaCost > GetPower(POWER_MANA))
1417 continue;
1418 SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
1419 float range = GetSpellMaxRange(srange);
1420 float minrange = GetSpellMinRange(srange);
1422 float dist = GetCombatDistance(pVictim);
1424 //if(!isInFront( pVictim, range ) && spellInfo->AttributesEx )
1425 // continue;
1426 if( dist > range || dist < minrange )
1427 continue;
1428 if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
1429 continue;
1430 if(spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
1431 continue;
1432 return spellInfo;
1434 return NULL;
1437 bool Creature::IsVisibleInGridForPlayer(Player* pl) const
1439 // gamemaster in GM mode see all, including ghosts
1440 if(pl->isGameMaster())
1441 return true;
1443 if (GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INVISIBLE)
1444 return false;
1446 // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0
1447 if(pl->isAlive() || pl->GetDeathTimer() > 0)
1449 return (isAlive() || m_deathTimer > 0 || (m_isDeadByDefault && m_deathState == CORPSE));
1452 // Dead player see live creatures near own corpse
1453 if(isAlive())
1455 Corpse *corpse = pl->GetCorpse();
1456 if(corpse)
1458 // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level
1459 if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))
1460 return true;
1464 // Dead player can see ghosts
1465 if (GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_GHOST_VISIBLE)
1466 return true;
1468 // and not see any other
1469 return false;
1472 void Creature::SendAIReaction(AiReaction reactionType)
1474 WorldPacket data(SMSG_AI_REACTION, 12);
1476 data << uint64(GetGUID());
1477 data << uint32(reactionType);
1479 ((WorldObject*)this)->SendMessageToSet(&data, true);
1481 sLog.outDebug("WORLD: Sent SMSG_AI_REACTION, type %u.", reactionType);
1484 void Creature::CallAssistance()
1486 if( !m_AlreadyCallAssistance && getVictim() && !isPet() && !isCharmed())
1488 SetNoCallAssistance(true);
1490 float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
1491 if(radius > 0)
1493 std::list<Creature*> assistList;
1496 CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
1497 Cell cell(p);
1498 cell.data.Part.reserved = ALL_DISTRICT;
1499 cell.SetNoCreate();
1501 MaNGOS::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius);
1502 MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck> searcher(this, assistList, u_check);
1504 TypeContainerVisitor<MaNGOS::CreatureListSearcher<MaNGOS::AnyAssistCreatureInRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
1506 CellLock<GridReadGuard> cell_lock(cell, p);
1507 cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, radius);
1510 if (!assistList.empty())
1512 AssistDelayEvent *e = new AssistDelayEvent(getVictim()->GetGUID(), *this);
1513 while (!assistList.empty())
1515 // Pushing guids because in delay can happen some creature gets despawned => invalid pointer
1516 e->AddAssistant((*assistList.begin())->GetGUID());
1517 assistList.pop_front();
1519 m_Events.AddEvent(e, m_Events.CalculateTime(sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)));
1525 void Creature::CallForHelp(float fRadius)
1527 if (fRadius <= 0.0f || !getVictim() || isPet() || isCharmed())
1528 return;
1530 CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
1531 Cell cell(p);
1532 cell.data.Part.reserved = ALL_DISTRICT;
1533 cell.SetNoCreate();
1535 MaNGOS::CallOfHelpCreatureInRangeDo u_do(this, getVictim(), fRadius);
1536 MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo> worker(this, u_do);
1538 TypeContainerVisitor<MaNGOS::CreatureWorker<MaNGOS::CallOfHelpCreatureInRangeDo>, GridTypeMapContainer > grid_creature_searcher(worker);
1540 CellLock<GridReadGuard> cell_lock(cell, p);
1541 cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap(), *this, fRadius);
1544 bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const
1546 // we don't need help from zombies :)
1547 if (!isAlive())
1548 return false;
1550 // we don't need help from non-combatant ;)
1551 if (isCivilian())
1552 return false;
1554 // skip fighting creature
1555 if (isInCombat())
1556 return false;
1558 // only free creature
1559 if (GetCharmerOrOwnerGUID())
1560 return false;
1562 // only from same creature faction
1563 if (checkfaction)
1565 if (getFaction() != u->getFaction())
1566 return false;
1568 else
1570 if (!IsFriendlyTo(u))
1571 return false;
1574 // skip non hostile to caster enemy creatures
1575 if (!IsHostileTo(enemy))
1576 return false;
1578 return true;
1581 void Creature::SaveRespawnTime()
1583 if(isPet() || !m_DBTableGuid)
1584 return;
1586 if(m_respawnTime > time(NULL)) // dead (no corpse)
1587 sObjectMgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
1588 else if(m_deathTimer > 0) // dead (corpse)
1589 sObjectMgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/IN_MILISECONDS);
1592 bool Creature::IsOutOfThreatArea(Unit* pVictim) const
1594 if(!pVictim)
1595 return true;
1597 if(!pVictim->IsInMap(this))
1598 return true;
1600 if(!pVictim->isTargetableForAttack())
1601 return true;
1603 if(!pVictim->isInAccessablePlaceFor(this))
1604 return true;
1606 if(sMapStore.LookupEntry(GetMapId())->IsDungeon())
1607 return false;
1609 float AttackDist = GetAttackDistance(pVictim);
1610 uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS);
1612 //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
1613 return !pVictim->IsWithinDist3d(CombatStartX,CombatStartY,CombatStartZ,
1614 ThreatRadius > AttackDist ? ThreatRadius : AttackDist);
1617 CreatureDataAddon const* Creature::GetCreatureAddon() const
1619 if (m_DBTableGuid)
1621 if(CreatureDataAddon const* addon = ObjectMgr::GetCreatureAddon(m_DBTableGuid))
1622 return addon;
1625 // dependent from difficulty mode entry
1626 return ObjectMgr::GetCreatureTemplateAddon(GetCreatureInfo()->Entry);
1629 //creature_addon table
1630 bool Creature::LoadCreaturesAddon(bool reload)
1632 CreatureDataAddon const *cainfo = GetCreatureAddon();
1633 if(!cainfo)
1634 return false;
1636 if (cainfo->mount != 0)
1637 Mount(cainfo->mount);
1639 if (cainfo->bytes1 != 0)
1641 // 0 StandState
1642 // 1 FreeTalentPoints Pet only, so always 0 for default creature
1643 // 2 StandFlags
1644 // 3 StandMiscFlags
1646 SetByteValue(UNIT_FIELD_BYTES_1, 0, uint8(cainfo->bytes1 & 0xFF));
1647 //SetByteValue(UNIT_FIELD_BYTES_1, 1, uint8((cainfo->bytes1 >> 8) & 0xFF));
1648 SetByteValue(UNIT_FIELD_BYTES_1, 1, 0);
1649 SetByteValue(UNIT_FIELD_BYTES_1, 2, uint8((cainfo->bytes1 >> 16) & 0xFF));
1650 SetByteValue(UNIT_FIELD_BYTES_1, 3, uint8((cainfo->bytes1 >> 24) & 0xFF));
1653 if (cainfo->bytes2 != 0)
1655 // 0 SheathState
1656 // 1 UnitPVPStateFlags Set at Creature::UpdateEntry (SetPvp())
1657 // 2 UnitRename Pet only, so always 0 for default creature
1658 // 3 ShapeshiftForm Must be determined/set by shapeshift spell/aura
1660 SetByteValue(UNIT_FIELD_BYTES_2, 0, uint8(cainfo->bytes2 & 0xFF));
1661 //SetByteValue(UNIT_FIELD_BYTES_2, 1, uint8((cainfo->bytes2 >> 8) & 0xFF));
1662 //SetByteValue(UNIT_FIELD_BYTES_2, 2, uint8((cainfo->bytes2 >> 16) & 0xFF));
1663 SetByteValue(UNIT_FIELD_BYTES_2, 2, 0);
1664 //SetByteValue(UNIT_FIELD_BYTES_2, 3, uint8((cainfo->bytes2 >> 24) & 0xFF));
1665 SetByteValue(UNIT_FIELD_BYTES_2, 3, 0);
1668 if (cainfo->emote != 0)
1669 SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote);
1671 if (cainfo->move_flags != 0)
1672 SetMonsterMoveFlags(MonsterMovementFlags(cainfo->move_flags));
1674 if(cainfo->auras)
1676 for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura)
1678 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura->spell_id);
1679 if (!AdditionalSpellInfo)
1681 sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has wrong spell %u defined in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id);
1682 continue;
1685 // skip already applied aura
1686 if(HasAura(cAura->spell_id,cAura->effect_idx))
1688 if(!reload)
1689 sLog.outErrorDb("Creature (GUIDLow: %u Entry: %u ) has duplicate aura (spell %u effect %u) in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id,cAura->effect_idx);
1691 continue;
1694 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, cAura->effect_idx, NULL, this, this, 0);
1695 AddAura(AdditionalAura);
1696 sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[0],GetGUIDLow(),GetEntry());
1699 return true;
1702 /// Send a message to LocalDefense channel for players opposition team in the zone
1703 void Creature::SendZoneUnderAttackMessage(Player* attacker)
1705 uint32 enemy_team = attacker->GetTeam();
1707 WorldPacket data(SMSG_ZONE_UNDER_ATTACK,4);
1708 data << (uint32)GetZoneId();
1709 sWorld.SendGlobalMessage(&data,NULL,(enemy_team==ALLIANCE ? HORDE : ALLIANCE));
1712 void Creature::SetInCombatWithZone()
1714 if (!CanHaveThreatList())
1716 sLog.outError("Creature entry %u call SetInCombatWithZone but creature cannot have threat list.", GetEntry());
1717 return;
1720 Map* pMap = GetMap();
1722 if (!pMap->IsDungeon())
1724 sLog.outError("Creature entry %u call SetInCombatWithZone for map (id: %u) that isn't an instance.", GetEntry(), pMap->GetId());
1725 return;
1728 Map::PlayerList const &PlList = pMap->GetPlayers();
1730 if (PlList.isEmpty())
1731 return;
1733 for(Map::PlayerList::const_iterator i = PlList.begin(); i != PlList.end(); ++i)
1735 if (Player* pPlayer = i->getSource())
1737 if (pPlayer->isGameMaster())
1738 continue;
1740 if (pPlayer->isAlive())
1742 pPlayer->SetInCombatWith(this);
1743 AddThreat(pPlayer);
1749 void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
1751 m_CreatureSpellCooldowns[spell_id] = end_time;
1754 void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
1756 m_CreatureCategoryCooldowns[category] = apply_time;
1759 void Creature::AddCreatureSpellCooldown(uint32 spellid)
1761 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
1762 if(!spellInfo)
1763 return;
1765 uint32 cooldown = GetSpellRecoveryTime(spellInfo);
1766 if(cooldown)
1767 _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILISECONDS);
1769 if(spellInfo->Category)
1770 _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL));
1772 m_GlobalCooldown = spellInfo->StartRecoveryTime;
1775 bool Creature::HasCategoryCooldown(uint32 spell_id) const
1777 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
1778 if(!spellInfo)
1779 return false;
1781 // check global cooldown if spell affected by it
1782 if (spellInfo->StartRecoveryCategory > 0 && m_GlobalCooldown > 0)
1783 return true;
1785 CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category);
1786 return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILISECONDS)) > time(NULL));
1789 bool Creature::HasSpellCooldown(uint32 spell_id) const
1791 CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id);
1792 return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id);
1795 bool Creature::IsInEvadeMode() const
1797 return !i_motionMaster.empty() && i_motionMaster.GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE;
1800 bool Creature::HasSpell(uint32 spellID) const
1802 uint8 i;
1803 for(i = 0; i < CREATURE_MAX_SPELLS; ++i)
1804 if(spellID == m_spells[i])
1805 break;
1806 return i < CREATURE_MAX_SPELLS; //broke before end of iteration of known spells
1809 time_t Creature::GetRespawnTimeEx() const
1811 time_t now = time(NULL);
1812 if(m_respawnTime > now) // dead (no corpse)
1813 return m_respawnTime;
1814 else if(m_deathTimer > 0) // dead (corpse)
1815 return now+m_respawnDelay+m_deathTimer/IN_MILISECONDS;
1816 else
1817 return now;
1820 void Creature::GetRespawnCoord( float &x, float &y, float &z, float* ori, float* dist ) const
1822 if (m_DBTableGuid)
1824 if (CreatureData const* data = sObjectMgr.GetCreatureData(GetDBTableGUIDLow()))
1826 x = data->posX;
1827 y = data->posY;
1828 z = data->posZ;
1829 if(ori)
1830 *ori = data->orientation;
1831 if(dist)
1832 *dist = data->spawndist;
1834 return;
1838 x = GetPositionX();
1839 y = GetPositionY();
1840 z = GetPositionZ();
1841 if(ori)
1842 *ori = GetOrientation();
1843 if(dist)
1844 *dist = 0;
1847 void Creature::AllLootRemovedFromCorpse()
1849 if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
1851 uint32 nDeathTimer;
1853 CreatureInfo const *cinfo = GetCreatureInfo();
1855 // corpse was not skinnable -> apply corpse looted timer
1856 if (!cinfo || !cinfo->SkinLootId)
1857 nDeathTimer = (uint32)((m_corpseDelay * IN_MILISECONDS) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED));
1858 // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
1859 else
1860 nDeathTimer = 0;
1862 // update death timer only if looted timer is shorter
1863 if (m_deathTimer > nDeathTimer)
1864 m_deathTimer = nDeathTimer;
1868 uint32 Creature::getLevelForTarget( Unit const* target ) const
1870 if(!isWorldBoss())
1871 return Unit::getLevelForTarget(target);
1873 uint32 level = target->getLevel()+sWorld.getConfig(CONFIG_WORLD_BOSS_LEVEL_DIFF);
1874 if(level < 1)
1875 return 1;
1876 if(level > 255)
1877 return 255;
1878 return level;
1881 std::string Creature::GetAIName() const
1883 return ObjectMgr::GetCreatureTemplate(GetEntry())->AIName;
1886 std::string Creature::GetScriptName() const
1888 return sObjectMgr.GetScriptName(GetScriptId());
1891 uint32 Creature::GetScriptId() const
1893 return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptID;
1896 VendorItemData const* Creature::GetVendorItems() const
1898 return sObjectMgr.GetNpcVendorItemList(GetEntry());
1901 uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
1903 if(!vItem->maxcount)
1904 return vItem->maxcount;
1906 VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
1907 for(; itr != m_vendorItemCounts.end(); ++itr)
1908 if(itr->itemId==vItem->item)
1909 break;
1911 if(itr == m_vendorItemCounts.end())
1912 return vItem->maxcount;
1914 VendorItemCount* vCount = &*itr;
1916 time_t ptime = time(NULL);
1918 if( vCount->lastIncrementTime + vItem->incrtime <= ptime )
1920 ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(vItem->item);
1922 uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
1923 if((vCount->count + diff * pProto->BuyCount) >= vItem->maxcount )
1925 m_vendorItemCounts.erase(itr);
1926 return vItem->maxcount;
1929 vCount->count += diff * pProto->BuyCount;
1930 vCount->lastIncrementTime = ptime;
1933 return vCount->count;
1936 uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count)
1938 if(!vItem->maxcount)
1939 return 0;
1941 VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
1942 for(; itr != m_vendorItemCounts.end(); ++itr)
1943 if(itr->itemId==vItem->item)
1944 break;
1946 if(itr == m_vendorItemCounts.end())
1948 uint32 new_count = vItem->maxcount > used_count ? vItem->maxcount-used_count : 0;
1949 m_vendorItemCounts.push_back(VendorItemCount(vItem->item,new_count));
1950 return new_count;
1953 VendorItemCount* vCount = &*itr;
1955 time_t ptime = time(NULL);
1957 if( vCount->lastIncrementTime + vItem->incrtime <= ptime )
1959 ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(vItem->item);
1961 uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
1962 if((vCount->count + diff * pProto->BuyCount) < vItem->maxcount )
1963 vCount->count += diff * pProto->BuyCount;
1964 else
1965 vCount->count = vItem->maxcount;
1968 vCount->count = vCount->count > used_count ? vCount->count-used_count : 0;
1969 vCount->lastIncrementTime = ptime;
1970 return vCount->count;
1973 TrainerSpellData const* Creature::GetTrainerSpells() const
1975 return sObjectMgr.GetNpcTrainerSpells(GetEntry());
1978 // overwrite WorldObject function for proper name localization
1979 const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const
1981 if (loc_idx >= 0)
1983 CreatureLocale const *cl = sObjectMgr.GetCreatureLocale(GetEntry());
1984 if (cl)
1986 if (cl->Name.size() > (size_t)loc_idx && !cl->Name[loc_idx].empty())
1987 return cl->Name[loc_idx].c_str();
1991 return GetName();
1994 void Creature::SetActiveObjectState( bool on )
1996 if(m_isActiveObject==on)
1997 return;
1999 bool world = IsInWorld();
2001 Map* map;
2002 if(world)
2004 map = GetMap();
2005 map->Remove(this,false);
2008 m_isActiveObject = on;
2010 if(world)
2011 map->Add(this);
2014 void Creature::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
2016 float x, y, z;
2017 if(GetMotionMaster()->GetDestination(x, y, z))
2018 SendMonsterMoveWithSpeed(x, y, z, 0, player);
2021 void Creature::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
2023 if (!transitTime)
2025 if(GetTypeId()==TYPEID_PLAYER)
2027 Traveller<Player> traveller(*(Player*)this);
2028 transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
2030 else
2032 Traveller<Creature> traveller(*(Creature*)this);
2033 transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
2036 //float orientation = (float)atan2((double)dy, (double)dx);
2037 SendMonsterMove(x, y, z, 0, GetMonsterMoveFlags(), transitTime, player);
2040 void Creature::SendAreaSpiritHealerQueryOpcode(Player *pl)
2042 uint32 next_resurrect = 0;
2043 if (Spell* pcurSpell = GetCurrentSpell(CURRENT_CHANNELED_SPELL))
2044 next_resurrect = pcurSpell->GetCastedTime();
2045 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 8 + 4);
2046 data << GetGUID() << next_resurrect;
2047 pl->SendDirectMessage(&data);