1. /*
  2. * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
  3. * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "Common.h"
  19. #include "DatabaseEnv.h"
  20. #include "WorldPacket.h"
  21. #include "World.h"
  22. #include "ObjectMgr.h"
  23. #include "SpellMgr.h"
  24. #include "Creature.h"
  25. #include "QuestDef.h"
  26. #include "GossipDef.h"
  27. #include "Player.h"
  28. #include "PoolMgr.h"
  29. #include "Opcodes.h"
  30. #include "Log.h"
  31. #include "LootMgr.h"
  32. #include "MapManager.h"
  33. #include "CreatureAI.h"
  34. #include "CreatureAISelector.h"
  35. #include "Formulas.h"
  36. #include "WaypointMovementGenerator.h"
  37. #include "InstanceScript.h"
  38. #include "BattlegroundMgr.h"
  39. #include "Util.h"
  40. #include "GridNotifiers.h"
  41. #include "GridNotifiersImpl.h"
  42. #include "CellImpl.h"
  43. #include "OutdoorPvPMgr.h"
  44. #include "GameEventMgr.h"
  45. #include "CreatureGroups.h"
  46. #include "Vehicle.h"
  47. #include "SpellAuraEffects.h"
  48. #include "Group.h"
  49. // apply implementation of the singletons
  50. TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
  51. {
  52. TrainerSpellMap::const_iterator itr = spellList.find(spell_id);
  53. if (itr != spellList.end())
  54. return &itr->second;
  55. return NULL;
  56. }
  57. bool VendorItemData::RemoveItem(uint32 item_id)
  58. {
  59. bool found = false;
  60. for (VendorItemList::iterator i = m_items.begin(); i != m_items.end();)
  61. {
  62. if ((*i)->item == item_id)
  63. {
  64. i = m_items.erase(i++);
  65. found = true;
  66. }
  67. else
  68. ++i;
  69. }
  70. return found;
  71. }
  72. VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost) const
  73. {
  74. for (VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i)
  75. if((*i)->item == item_id && (*i)->ExtendedCost == extendedCost)
  76. return *i;
  77. return NULL;
  78. }
  79. uint32 CreatureInfo::GetRandomValidModelId() const
  80. {
  81. uint8 c = 0;
  82. uint32 modelIDs[4];
  83. if (Modelid1) modelIDs[c++] = Modelid1;
  84. if (Modelid2) modelIDs[c++] = Modelid2;
  85. if (Modelid3) modelIDs[c++] = Modelid3;
  86. if (Modelid4) modelIDs[c++] = Modelid4;
  87. return ((c>0) ? modelIDs[urand(0,c-1)] : 0);
  88. }
  89. uint32 CreatureInfo::GetFirstValidModelId() const
  90. {
  91. if (Modelid1) return Modelid1;
  92. if (Modelid2) return Modelid2;
  93. if (Modelid3) return Modelid3;
  94. if (Modelid4) return Modelid4;
  95. return 0;
  96. }
  97. bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
  98. {
  99. if (Unit* victim = Unit::GetUnit(m_owner, m_victim))
  100. {
  101. while (!m_assistants.empty())
  102. {
  103. Creature* assistant = Unit::GetCreature(m_owner, *m_assistants.begin());
  104. m_assistants.pop_front();
  105. if (assistant && assistant->CanAssistTo(&m_owner, victim))
  106. {
  107. assistant->SetNoCallAssistance(true);
  108. assistant->CombatStart(victim);
  109. if (assistant->IsAIEnabled)
  110. assistant->AI()->AttackStart(victim);
  111. }
  112. }
  113. }
  114. return true;
  115. }
  116. CreatureBaseStats const* CreatureBaseStats::GetBaseStats(uint8 level, uint8 unitClass)
  117. {
  118. return sObjectMgr->GetCreatureBaseStats(level, unitClass);
  119. }
  120. bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
  121. {
  122. m_owner.ForcedDespawn();
  123. return true;
  124. }
  125. Creature::Creature(): Unit(),
  126. lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
  127. m_PlayerDamageReq(0), m_lootMoney(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
  128. m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
  129. m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
  130. m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
  131. m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_creatureInfo(NULL), m_creatureData(NULL),
  132. m_formation(NULL)
  133. {
  134. m_regenTimer = CREATURE_REGEN_INTERVAL;
  135. m_valuesCount = UNIT_END;
  136. for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
  137. m_spells[i] = 0;
  138. m_CreatureSpellCooldowns.clear();
  139. m_CreatureCategoryCooldowns.clear();
  140. DisableReputationGain = false;
  141. m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
  142. m_CombatDistance = 0;//MELEE_RANGE;
  143. ResetLootMode(); // restore default loot mode
  144. TriggerJustRespawned = false;
  145. }
  146. Creature::~Creature()
  147. {
  148. m_vendorItemCounts.clear();
  149. delete i_AI;
  150. i_AI = NULL;
  151. //if (m_uint32Values)
  152. // sLog->outError("Deconstruct Creature Entry = %u", GetEntry());
  153. }
  154. void Creature::AddToWorld()
  155. {
  156. ///- Register the creature for guid lookup
  157. if (!IsInWorld())
  158. {
  159. if (m_zoneScript)
  160. m_zoneScript->OnCreatureCreate(this);
  161. sObjectAccessor->AddObject(this);
  162. Unit::AddToWorld();
  163. SearchFormation();
  164. AIM_Initialize();
  165. if (IsVehicle())
  166. GetVehicleKit()->Install();
  167. }
  168. }
  169. void Creature::RemoveFromWorld()
  170. {
  171. if (IsInWorld())
  172. {
  173. if (m_zoneScript)
  174. m_zoneScript->OnCreatureRemove(this);
  175. if (m_formation)
  176. sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
  177. Unit::RemoveFromWorld();
  178. sObjectAccessor->RemoveObject(this);
  179. }
  180. }
  181. void Creature::DisappearAndDie()
  182. {
  183. DestroyForNearbyPlayers();
  184. //SetVisibility(VISIBILITY_OFF);
  185. //ObjectAccessor::UpdateObjectVisibility(this);
  186. if (isAlive())
  187. setDeathState(JUST_DIED);
  188. RemoveCorpse(false);
  189. }
  190. void Creature::SearchFormation()
  191. {
  192. if (isSummon())
  193. return;
  194. uint32 lowguid = GetDBTableGUIDLow();
  195. if (!lowguid)
  196. return;
  197. CreatureGroupInfoType::iterator frmdata = CreatureGroupMap.find(lowguid);
  198. if (frmdata != CreatureGroupMap.end())
  199. sFormationMgr->AddCreatureToGroup(frmdata->second->leaderGUID, this);
  200. }
  201. void Creature::RemoveCorpse(bool setSpawnTime)
  202. {
  203. if ((getDeathState() != CORPSE && !m_isDeadByDefault) || (getDeathState() != ALIVE && m_isDeadByDefault))
  204. return;
  205. m_corpseRemoveTime = time(NULL);
  206. setDeathState(DEAD);
  207. UpdateObjectVisibility();
  208. loot.clear();
  209. uint32 respawnDelay = m_respawnDelay;
  210. if (IsAIEnabled)
  211. AI()->CorpseRemoved(respawnDelay);
  212. // Should get removed later, just keep "compatibility" with scripts
  213. if(setSpawnTime)
  214. m_respawnTime = time(NULL) + respawnDelay;
  215. float x,y,z,o;
  216. GetRespawnCoord(x, y, z, &o);
  217. SetHomePosition(x,y,z,o);
  218. GetMap()->CreatureRelocation(this,x,y,z,o);
  219. }
  220. /**
  221. * change the entry of creature until respawn
  222. */
  223. bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData *data)
  224. {
  225. CreatureInfo const *normalInfo = ObjectMgr::GetCreatureTemplate(Entry);
  226. if (!normalInfo)
  227. {
  228. sLog->outErrorDb("Creature::InitEntry creature entry %u does not exist.", Entry);
  229. return false;
  230. }
  231. // get difficulty 1 mode entry
  232. CreatureInfo const *cinfo = normalInfo;
  233. for (uint8 diff = uint8(GetMap()->GetSpawnMode()); diff > 0;)
  234. {
  235. // we already have valid Map pointer for current creature!
  236. if (normalInfo->DifficultyEntry[diff - 1])
  237. {
  238. cinfo = ObjectMgr::GetCreatureTemplate(normalInfo->DifficultyEntry[diff - 1]);
  239. if (cinfo)
  240. break; // template found
  241. // check and reported at startup, so just ignore (restore normalInfo)
  242. cinfo = normalInfo;
  243. }
  244. // for instances heroic to normal, other cases attempt to retrieve previous difficulty
  245. if (diff >= RAID_DIFFICULTY_10MAN_HEROIC && GetMap()->IsRaid())
  246. diff -= 2; // to normal raid difficulty cases
  247. else
  248. --diff;
  249. }
  250. SetEntry(Entry); // normal entry always
  251. m_creatureInfo = cinfo; // map mode related always
  252. // equal to player Race field, but creature does not have race
  253. SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
  254. // known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE
  255. SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class));
  256. // Cancel load if no model defined
  257. if (!(cinfo->GetFirstValidModelId()))
  258. {
  259. sLog->outErrorDb("Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ",Entry);
  260. return false;
  261. }
  262. uint32 display_id = sObjectMgr->ChooseDisplayId(0, GetCreatureInfo(), data);
  263. CreatureModelInfo const *minfo = sObjectMgr->GetCreatureModelRandomGender(display_id);
  264. if (!minfo) // Cancel load if no model defined
  265. {
  266. sLog->outErrorDb("Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ",Entry);
  267. return false;
  268. }
  269. display_id = minfo->modelid; // it can be different (for another gender)
  270. SetDisplayId(display_id);
  271. SetNativeDisplayId(display_id);
  272. SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
  273. // Load creature equipment
  274. if (!data || data->equipmentId == 0) // use default from the template
  275. LoadEquipment(cinfo->equipmentId);
  276. else if (data && data->equipmentId != -1) // override, -1 means no equipment
  277. LoadEquipment(data->equipmentId);
  278. SetName(normalInfo->Name); // at normal entry always
  279. SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
  280. SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach);
  281. SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
  282. SetSpeed(MOVE_WALK, cinfo->speed_walk);
  283. SetSpeed(MOVE_RUN, cinfo->speed_run);
  284. SetSpeed(MOVE_SWIM, 1.0f); // using 1.0 rate
  285. SetSpeed(MOVE_FLIGHT, 1.0f); // using 1.0 rate
  286. SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale);
  287. // checked at loading
  288. m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
  289. if (!m_respawnradius && m_defaultMovementType == RANDOM_MOTION_TYPE)
  290. m_defaultMovementType = IDLE_MOTION_TYPE;
  291. for (uint8 i=0; i < CREATURE_MAX_SPELLS; ++i)
  292. m_spells[i] = GetCreatureInfo()->spells[i];
  293. return true;
  294. }
  295. bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data)
  296. {
  297. if (!InitEntry(Entry,team,data))
  298. return false;
  299. CreatureInfo const* cInfo = GetCreatureInfo();
  300. m_regenHealth = cInfo->RegenHealth;
  301. // creatures always have melee weapon ready if any
  302. SetSheath(SHEATH_STATE_MELEE);
  303. SelectLevel(GetCreatureInfo());
  304. if (team == HORDE)
  305. setFaction(cInfo->faction_H);
  306. else
  307. setFaction(cInfo->faction_A);
  308. uint32 npcflag, unit_flags, dynamicflags;
  309. ObjectMgr::ChooseCreatureFlags(cInfo, npcflag, unit_flags, dynamicflags, data);
  310. if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT)
  311. SetUInt32Value(UNIT_NPC_FLAGS, npcflag | sGameEventMgr->GetNPCFlag(this));
  312. else
  313. SetUInt32Value(UNIT_NPC_FLAGS, npcflag);
  314. SetAttackTime(BASE_ATTACK, cInfo->baseattacktime);
  315. SetAttackTime(OFF_ATTACK, cInfo->baseattacktime);
  316. SetAttackTime(RANGED_ATTACK,cInfo->rangeattacktime);
  317. SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags);
  318. SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicflags);
  319. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
  320. SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
  321. CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class);
  322. float armor = (float)stats->GenerateArmor(cInfo); // TODO: Why is this treated as uint32 when it's a float?
  323. SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
  324. SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance1));
  325. SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance2));
  326. SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance3));
  327. SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance4));
  328. SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance5));
  329. SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance6));
  330. SetCanModifyStats(true);
  331. UpdateAllStats();
  332. // checked and error show at loading templates
  333. if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A))
  334. {
  335. if (factionTemplate->factionFlags & FACTION_TEMPLATE_FLAG_PVP)
  336. SetPvP(true);
  337. else
  338. SetPvP(false);
  339. }
  340. // trigger creature is always not selectable and can not be attacked
  341. if (isTrigger())
  342. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
  343. InitializeReactState();
  344. if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_TAUNT)
  345. {
  346. ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
  347. ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
  348. }
  349. // TODO: In fact monster move flags should be set - not movement flags.
  350. if (cInfo->InhabitType & INHABIT_AIR)
  351. AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING);
  352. if (cInfo->InhabitType & INHABIT_WATER)
  353. AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
  354. return true;
  355. }
  356. void Creature::Update(uint32 diff)
  357. {
  358. if (IsAIEnabled && TriggerJustRespawned)
  359. {
  360. TriggerJustRespawned = false;
  361. AI()->JustRespawned();
  362. if (m_vehicleKit)
  363. m_vehicleKit->Reset();
  364. }
  365. switch(m_deathState)
  366. {
  367. case JUST_ALIVED:
  368. // Don't must be called, see Creature::setDeathState JUST_ALIVED -> ALIVE promoting.
  369. sLog->outError("Creature (GUID: %u Entry: %u) in wrong state: JUST_ALIVED (4)",GetGUIDLow(),GetEntry());
  370. break;
  371. case JUST_DIED:
  372. // Don't must be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting.
  373. sLog->outError("Creature (GUID: %u Entry: %u) in wrong state: JUST_DEAD (1)",GetGUIDLow(),GetEntry());
  374. break;
  375. case DEAD:
  376. {
  377. time_t now = time(NULL);
  378. if (m_respawnTime <= now)
  379. {
  380. bool allowed = IsAIEnabled ? AI()->CanRespawn() : true; // First check if there are any scripts that object to us respawning
  381. if (!allowed) // Will be rechecked on next Update call
  382. break;
  383. uint64 dbtableHighGuid = MAKE_NEW_GUID(m_DBTableGuid, GetEntry(), HIGHGUID_UNIT);
  384. time_t linkedRespawntime = sObjectMgr->GetLinkedRespawnTime(dbtableHighGuid, GetMap()->GetInstanceId());
  385. if (!linkedRespawntime) // Can respawn
  386. Respawn();
  387. else // the master is dead
  388. {
  389. uint64 targetGuid = sObjectMgr->GetLinkedRespawnGuid(GetGUID());
  390. if (targetGuid == GetGUID()) // if linking self, never respawn (check delayed to next day)
  391. SetRespawnTime(DAY);
  392. else
  393. m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime)+urand(5,MINUTE); // else copy time from master and add a little
  394. SaveRespawnTime(); // also save to DB immediately
  395. }
  396. }
  397. break;
  398. }
  399. case CORPSE:
  400. {
  401. if (m_isDeadByDefault)
  402. break;
  403. if (m_groupLootTimer && lootingGroupLowGUID)
  404. {
  405. // for delayed spells
  406. m_Events.Update(diff);
  407. if (m_groupLootTimer <= diff)
  408. {
  409. Group* group = sObjectMgr->GetGroupByGUID(lootingGroupLowGUID);
  410. if (group)
  411. group->EndRoll(&loot);
  412. m_groupLootTimer = 0;
  413. lootingGroupLowGUID = 0;
  414. }
  415. else m_groupLootTimer -= diff;
  416. }
  417. else if (m_corpseRemoveTime <= time(NULL))
  418. {
  419. RemoveCorpse(false);
  420. sLog->outStaticDebug("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY));
  421. }
  422. else
  423. {
  424. // for delayed spells
  425. m_Events.Update(diff);
  426. }
  427. break;
  428. }
  429. case ALIVE:
  430. {
  431. if (m_isDeadByDefault)
  432. {
  433. if (m_corpseRemoveTime <= time(NULL))
  434. {
  435. RemoveCorpse(false);
  436. sLog->outStaticDebug("Removing alive corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY));
  437. }
  438. }
  439. Unit::Update(diff);
  440. // creature can be dead after Unit::Update call
  441. // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
  442. if (!isAlive())
  443. break;
  444. // if creature is charmed, switch to charmed AI
  445. if (NeedChangeAI)
  446. {
  447. UpdateCharmAI();
  448. NeedChangeAI = false;
  449. IsAIEnabled = true;
  450. }
  451. if (!IsInEvadeMode() && IsAIEnabled)
  452. {
  453. // do not allow the AI to be changed during update
  454. m_AI_locked = true;
  455. i_AI->UpdateAI(diff);
  456. m_AI_locked = false;
  457. }
  458. // creature can be dead after UpdateAI call
  459. // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
  460. if (!isAlive())
  461. break;
  462. if (m_regenTimer > 0)
  463. {
  464. if (diff >= m_regenTimer)
  465. m_regenTimer = 0;
  466. else
  467. m_regenTimer -= diff;
  468. }
  469. if (m_regenTimer != 0)
  470. break;
  471. bool bInCombat = isInCombat() && (!getVictim() || // if isInCombat() is true and this has no victim
  472. !getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() || // or the victim/owner/charmer is not a player
  473. !getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->isGameMaster()); // or the victim/owner/charmer is not a GameMaster
  474. /*if (m_regenTimer <= diff)
  475. {*/
  476. if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed
  477. RegenerateHealth();
  478. if (getPowerType() == POWER_ENERGY)
  479. {
  480. if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerType != POWER_PYRITE)
  481. Regenerate(POWER_ENERGY);
  482. }
  483. else
  484. RegenerateMana();
  485. /*if (!bIsPolymorphed) // only increase the timer if not polymorphed
  486. m_regenTimer += CREATURE_REGEN_INTERVAL - diff;
  487. }
  488. else
  489. if (!bIsPolymorphed) // if polymorphed, skip the timer
  490. m_regenTimer -= diff;*/
  491. m_regenTimer = CREATURE_REGEN_INTERVAL;
  492. break;
  493. }
  494. case DEAD_FALLING:
  495. GetMotionMaster()->UpdateMotion(diff);
  496. break;
  497. default:
  498. break;
  499. }
  500. sScriptMgr->OnCreatureUpdate(this, diff);
  501. }
  502. void Creature::RegenerateMana()
  503. {
  504. uint32 curValue = GetPower(POWER_MANA);
  505. uint32 maxValue = GetMaxPower(POWER_MANA);
  506. if (curValue >= maxValue)
  507. return;
  508. uint32 addvalue = 0;
  509. // Combat and any controlled creature
  510. if (isInCombat() || GetCharmerOrOwnerGUID())
  511. {
  512. if (!IsUnderLastManaUseEffect())
  513. {
  514. float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA);
  515. float Spirit = GetStat(STAT_SPIRIT);
  516. addvalue = uint32((Spirit / 5.0f + 17.0f) * ManaIncreaseRate);
  517. }
  518. }
  519. else
  520. addvalue = maxValue / 3;
  521. // Apply modifiers (if any).
  522. AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
  523. for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
  524. if ((*i)->GetMiscValue() == POWER_MANA)
  525. AddPctN(addvalue, (*i)->GetAmount());
  526. addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
  527. ModifyPower(POWER_MANA, addvalue);
  528. }
  529. void Creature::RegenerateHealth()
  530. {
  531. if (!isRegeneratingHealth())
  532. return;
  533. uint32 curValue = GetHealth();
  534. uint32 maxValue = GetMaxHealth();
  535. if (curValue >= maxValue)
  536. return;
  537. uint32 addvalue = 0;
  538. // Not only pet, but any controlled creature
  539. if (GetCharmerOrOwnerGUID())
  540. {
  541. float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH);
  542. float Spirit = GetStat(STAT_SPIRIT);
  543. if (GetPower(POWER_MANA) > 0)
  544. addvalue = uint32(Spirit * 0.25 * HealthIncreaseRate);
  545. else
  546. addvalue = uint32(Spirit * 0.80 * HealthIncreaseRate);
  547. }
  548. else
  549. addvalue = maxValue/3;
  550. // Apply modifiers (if any).
  551. AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
  552. for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
  553. AddPctN(addvalue, (*i)->GetAmount());
  554. addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
  555. ModifyHealth(addvalue);
  556. }
  557. void Creature::DoFleeToGetAssistance()
  558. {
  559. if (!getVictim())
  560. return;
  561. if (HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
  562. return;
  563. float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS);
  564. if (radius >0)
  565. {
  566. Creature* pCreature = NULL;
  567. CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
  568. Cell cell(p);
  569. cell.data.Part.reserved = ALL_DISTRICT;
  570. cell.SetNoCreate();
  571. Trinity::NearestAssistCreatureInCreatureRangeCheck u_check(this, getVictim(), radius);
  572. Trinity::CreatureLastSearcher<Trinity::NearestAssistCreatureInCreatureRangeCheck> searcher(this, pCreature, u_check);
  573. TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestAssistCreatureInCreatureRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
  574. cell.Visit(p, grid_creature_searcher, *GetMap(), *this, radius);
  575. SetNoSearchAssistance(true);
  576. UpdateSpeed(MOVE_RUN, false);
  577. if (!pCreature)
  578. //SetFeared(true, getVictim()->GetGUID(), 0 ,sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY));
  579. //TODO: use 31365
  580. SetControlled(true, UNIT_STAT_FLEEING);
  581. else
  582. GetMotionMaster()->MoveSeekAssistance(pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ());
  583. }
  584. }
  585. bool Creature::AIM_Initialize(CreatureAI* ai)
  586. {
  587. // make sure nothing can change the AI during AI update
  588. if (m_AI_locked)
  589. {
  590. sLog->outDebug(LOG_FILTER_TSCR, "AIM_Initialize: failed to init, locked.");
  591. return false;
  592. }
  593. UnitAI *oldAI = i_AI;
  594. Motion_Initialize();
  595. i_AI = ai ? ai : FactorySelector::selectAI(this);
  596. delete oldAI;
  597. IsAIEnabled = true;
  598. i_AI->InitializeAI();
  599. // Initialize vehicle
  600. if (GetVehicleKit())
  601. GetVehicleKit()->Reset();
  602. return true;
  603. }
  604. void Creature::Motion_Initialize()
  605. {
  606. if (!m_formation)
  607. i_motionMaster.Initialize();
  608. else if (m_formation->getLeader() == this)
  609. {
  610. m_formation->FormationReset(false);
  611. i_motionMaster.Initialize();
  612. }
  613. else if (m_formation->isFormed())
  614. i_motionMaster.MoveIdle(MOTION_SLOT_IDLE); //wait the order of leader
  615. else
  616. i_motionMaster.Initialize();
  617. }
  618. bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData *data)
  619. {
  620. ASSERT(map);
  621. SetMap(map);
  622. SetPhaseMask(phaseMask,false);
  623. CreatureInfo const *cinfo = ObjectMgr::GetCreatureTemplate(Entry);
  624. if (!cinfo)
  625. {
  626. sLog->outErrorDb("Creature::Create(): creature template (guidlow: %u, entry: %u) does not exist.", guidlow, Entry);
  627. return false;
  628. }
  629. Relocate(x, y, z, ang);
  630. if (!IsPositionValid())
  631. {
  632. sLog->outError("Creature::Create(): given coordinates for creature (guidlow %d, entry %d) are not valid (X: %f, Y: %f, Z: %f, O: %f)", guidlow, Entry, x, y, z, ang);
  633. return false;
  634. }
  635. //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
  636. if (!CreateFromProto(guidlow, Entry, vehId, team, data))
  637. return false;
  638. switch (GetCreatureInfo()->rank)
  639. {
  640. case CREATURE_ELITE_RARE:
  641. m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_RARE);
  642. break;
  643. case CREATURE_ELITE_ELITE:
  644. m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_ELITE);
  645. break;
  646. case CREATURE_ELITE_RAREELITE:
  647. m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_RAREELITE);
  648. break;
  649. case CREATURE_ELITE_WORLDBOSS:
  650. m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_WORLDBOSS);
  651. break;
  652. default:
  653. m_corpseDelay = sWorld->getIntConfig(CONFIG_CORPSE_DECAY_NORMAL);
  654. break;
  655. }
  656. LoadCreaturesAddon();
  657. CreatureModelInfo const *minfo = sObjectMgr->GetCreatureModelRandomGender(GetNativeDisplayId());
  658. if (minfo && !isTotem()) // Cancel load if no model defined or if totem
  659. {
  660. uint32 display_id = minfo->modelid; // it can be different (for another gender)
  661. SetDisplayId(display_id);
  662. SetNativeDisplayId(display_id);
  663. SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
  664. }
  665. if (GetCreatureInfo()->InhabitType & INHABIT_AIR)
  666. {
  667. if (GetDefaultMovementType() == IDLE_MOTION_TYPE)
  668. AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
  669. else
  670. SetFlying(true);
  671. }
  672. if (GetCreatureInfo()->InhabitType & INHABIT_WATER)
  673. AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
  674. LastUsedScriptID = GetCreatureInfo()->ScriptID;
  675. // TODO: Replace with spell, handle from DB
  676. if (isSpiritHealer())
  677. {
  678. m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
  679. m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
  680. }
  681. else if (isSpiritGuide())
  682. {
  683. m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST | GHOST_VISIBILITY_ALIVE);
  684. m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST | GHOST_VISIBILITY_ALIVE);
  685. }
  686. if (Entry == VISUAL_WAYPOINT)
  687. SetVisible(false);
  688. return true;
  689. }
  690. bool Creature::isCanTrainingOf(Player* pPlayer, bool msg) const
  691. {
  692. if (!isTrainer())
  693. return false;
  694. TrainerSpellData const* trainer_spells = GetTrainerSpells();
  695. if ((!trainer_spells || trainer_spells->spellList.empty()) && GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS)
  696. {
  697. sLog->outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.",
  698. GetGUIDLow(),GetEntry());
  699. return false;
  700. }
  701. switch(GetCreatureInfo()->trainer_type)
  702. {
  703. case TRAINER_TYPE_CLASS:
  704. if (pPlayer->getClass() != GetCreatureInfo()->trainer_class)
  705. {
  706. if (msg)
  707. {
  708. pPlayer->PlayerTalkClass->ClearMenus();
  709. switch(GetCreatureInfo()->trainer_class)
  710. {
  711. case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913,GetGUID()); break;
  712. case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090,GetGUID()); break;
  713. case CLASS_MAGE: pPlayer->PlayerTalkClass->SendGossipMenu(328,GetGUID()); break;
  714. case CLASS_PALADIN:pPlayer->PlayerTalkClass->SendGossipMenu(1635,GetGUID()); break;
  715. case CLASS_PRIEST: pPlayer->PlayerTalkClass->SendGossipMenu(4436,GetGUID()); break;
  716. case CLASS_ROGUE: pPlayer->PlayerTalkClass->SendGossipMenu(4797,GetGUID()); break;
  717. case CLASS_SHAMAN: pPlayer->PlayerTalkClass->SendGossipMenu(5003,GetGUID()); break;
  718. case CLASS_WARLOCK:pPlayer->PlayerTalkClass->SendGossipMenu(5836,GetGUID()); break;
  719. case CLASS_WARRIOR:pPlayer->PlayerTalkClass->SendGossipMenu(4985,GetGUID()); break;
  720. }
  721. }
  722. return false;
  723. }
  724. break;
  725. case TRAINER_TYPE_PETS:
  726. if (pPlayer->getClass() != CLASS_HUNTER)
  727. {
  728. pPlayer->PlayerTalkClass->ClearMenus();
  729. pPlayer->PlayerTalkClass->SendGossipMenu(3620,GetGUID());
  730. return false;
  731. }
  732. break;
  733. case TRAINER_TYPE_MOUNTS:
  734. if (GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race)
  735. {
  736. if (msg)
  737. {
  738. pPlayer->PlayerTalkClass->ClearMenus();
  739. switch(GetCreatureInfo()->trainer_class)
  740. {
  741. case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865,GetGUID()); break;
  742. case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881,GetGUID()); break;
  743. case RACE_HUMAN: pPlayer->PlayerTalkClass->SendGossipMenu(5861,GetGUID()); break;
  744. case RACE_NIGHTELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break;
  745. case RACE_ORC: pPlayer->PlayerTalkClass->SendGossipMenu(5863,GetGUID()); break;
  746. case RACE_TAUREN: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break;
  747. case RACE_TROLL: pPlayer->PlayerTalkClass->SendGossipMenu(5816,GetGUID()); break;
  748. case RACE_UNDEAD_PLAYER:pPlayer->PlayerTalkClass->SendGossipMenu(624,GetGUID()); break;
  749. case RACE_BLOODELF: pPlayer->PlayerTalkClass->SendGossipMenu(5862,GetGUID()); break;
  750. case RACE_DRAENEI: pPlayer->PlayerTalkClass->SendGossipMenu(5864,GetGUID()); break;
  751. }
  752. }
  753. return false;
  754. }
  755. break;
  756. case TRAINER_TYPE_TRADESKILLS:
  757. if (GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell))
  758. {
  759. if (msg)
  760. {
  761. pPlayer->PlayerTalkClass->ClearMenus();
  762. pPlayer->PlayerTalkClass->SendGossipMenu(11031,GetGUID());
  763. }
  764. return false;
  765. }
  766. break;
  767. default:
  768. return false; // checked and error output at creature_template loading
  769. }
  770. return true;
  771. }
  772. bool Creature::isCanInteractWithBattleMaster(Player* pPlayer, bool msg) const
  773. {
  774. if (!isBattleMaster())
  775. return false;
  776. BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(GetEntry());
  777. if (!msg)
  778. return pPlayer->GetBGAccessByLevel(bgTypeId);
  779. if (!pPlayer->GetBGAccessByLevel(bgTypeId))
  780. {
  781. pPlayer->PlayerTalkClass->ClearMenus();
  782. switch(bgTypeId)
  783. {
  784. case BATTLEGROUND_AV: pPlayer->PlayerTalkClass->SendGossipMenu(7616,GetGUID()); break;
  785. case BATTLEGROUND_WS: pPlayer->PlayerTalkClass->SendGossipMenu(7599,GetGUID()); break;
  786. case BATTLEGROUND_AB: pPlayer->PlayerTalkClass->SendGossipMenu(7642,GetGUID()); break;
  787. case BATTLEGROUND_EY:
  788. case BATTLEGROUND_NA:
  789. case BATTLEGROUND_BE:
  790. case BATTLEGROUND_AA:
  791. case BATTLEGROUND_RL:
  792. case BATTLEGROUND_SA:
  793. case BATTLEGROUND_DS:
  794. case BATTLEGROUND_RV: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break;
  795. default: break;
  796. }
  797. return false;
  798. }
  799. return true;
  800. }
  801. bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const
  802. {
  803. return pPlayer->getLevel() >= 10
  804. && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS
  805. && pPlayer->getClass() == GetCreatureInfo()->trainer_class;
  806. }
  807. void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 /*MovementFlags*/, uint8 /*type*/)
  808. {
  809. /* uint32 timeElap = getMSTime();
  810. if ((timeElap - m_startMove) < m_moveTime)
  811. {
  812. oX = (dX - oX) * ((timeElap - m_startMove) / m_moveTime);
  813. oY = (dY - oY) * ((timeElap - m_startMove) / m_moveTime);
  814. }
  815. else
  816. {
  817. oX = dX;
  818. oY = dY;
  819. }
  820. dX = x;
  821. dY = y;
  822. m_orientation = atan2((oY - dY), (oX - dX));
  823. m_startMove = getMSTime();
  824. m_moveTime = time;*/
  825. SendMonsterMove(x, y, z, time);
  826. }
  827. Player *Creature::GetLootRecipient() const
  828. {
  829. if (!m_lootRecipient)
  830. return NULL;
  831. return ObjectAccessor::FindPlayer(m_lootRecipient);
  832. }
  833. Group *Creature::GetLootRecipientGroup() const
  834. {
  835. if (!m_lootRecipientGroup)
  836. return NULL;
  837. return sObjectMgr->GetGroupByGUID(m_lootRecipientGroup);
  838. }
  839. void Creature::SetLootRecipient(Unit *unit)
  840. {
  841. // set the player whose group should receive the right
  842. // to loot the creature after it dies
  843. // should be set to NULL after the loot disappears
  844. if (!unit)
  845. {
  846. m_lootRecipient = 0;
  847. m_lootRecipientGroup = 0;
  848. RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE|UNIT_DYNFLAG_TAPPED);
  849. return;
  850. }
  851. if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle())
  852. return;
  853. Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
  854. if (!player) // normal creature, no player involved
  855. return;
  856. m_lootRecipient = player->GetGUID();
  857. if (Group *group = player->GetGroup())
  858. m_lootRecipientGroup = group->GetLowGUID();
  859. SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED);
  860. }
  861. // return true if this creature is tapped by the player or by a member of his group.
  862. bool Creature::isTappedBy(Player *player) const
  863. {
  864. if (player->GetGUID() == m_lootRecipient)
  865. return true;
  866. Group* playerGroup = player->GetGroup();
  867. if (!playerGroup || playerGroup != GetLootRecipientGroup()) // if we dont have a group we arent the recipient
  868. return false; // if creature doesnt have group bound it means it was solo killed by someone else
  869. return true;
  870. }
  871. void Creature::SaveToDB()
  872. {
  873. // this should only be used when the creature has already been loaded
  874. // preferably after adding to map, because mapid may not be valid otherwise
  875. CreatureData const *data = sObjectMgr->GetCreatureData(m_DBTableGuid);
  876. if (!data)
  877. {
  878. sLog->outError("Creature::SaveToDB failed, cannot get creature data!");
  879. return;
  880. }
  881. SaveToDB(GetMapId(), data->spawnMask, GetPhaseMask());
  882. }
  883. void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
  884. {
  885. // update in loaded data
  886. if (!m_DBTableGuid)
  887. m_DBTableGuid = GetGUIDLow();
  888. CreatureData& data = sObjectMgr->NewOrExistCreatureData(m_DBTableGuid);
  889. uint32 displayId = GetNativeDisplayId();
  890. uint32 npcflag = GetUInt32Value(UNIT_NPC_FLAGS);
  891. uint32 unit_flags = GetUInt32Value(UNIT_FIELD_FLAGS);
  892. uint32 dynamicflags = GetUInt32Value(UNIT_DYNAMIC_FLAGS);
  893. // check if it's a custom model and if not, use 0 for displayId
  894. CreatureInfo const *cinfo = GetCreatureInfo();
  895. if (cinfo)
  896. {
  897. if (displayId == cinfo->Modelid1 || displayId == cinfo->Modelid2 ||
  898. displayId == cinfo->Modelid3 || displayId == cinfo->Modelid4)
  899. displayId = 0;
  900. if (npcflag == cinfo->npcflag)
  901. npcflag = 0;
  902. if (unit_flags == cinfo->unit_flags)
  903. unit_flags = 0;
  904. if (dynamicflags == cinfo->dynamicflags)
  905. dynamicflags = 0;
  906. }
  907. // data->guid = guid don't must be update at save
  908. data.id = GetEntry();
  909. data.mapid = mapid;
  910. data.phaseMask = phaseMask;
  911. data.displayid = displayId;
  912. data.equipmentId = GetEquipmentId();
  913. data.posX = GetPositionX();
  914. data.posY = GetPositionY();
  915. data.posZ = GetPositionZ();
  916. data.orientation = GetOrientation();
  917. data.spawntimesecs = m_respawnDelay;
  918. // prevent add data integrity problems
  919. data.spawndist = GetDefaultMovementType() == IDLE_MOTION_TYPE ? 0 : m_respawnradius;
  920. data.currentwaypoint = 0;
  921. data.curhealth = GetHealth();
  922. data.curmana = GetPower(POWER_MANA);
  923. data.is_dead = m_isDeadByDefault;
  924. // prevent add data integrity problems
  925. data.movementType = !m_respawnradius && GetDefaultMovementType() == RANDOM_MOTION_TYPE
  926. ? IDLE_MOTION_TYPE : GetDefaultMovementType();
  927. data.spawnMask = spawnMask;
  928. data.npcflag = npcflag;
  929. data.unit_flags = unit_flags;
  930. data.dynamicflags = dynamicflags;
  931. // updated in DB
  932. SQLTransaction trans = WorldDatabase.BeginTransaction();
  933. trans->PAppend("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
  934. std::ostringstream ss;
  935. ss << "INSERT INTO creature VALUES ("
  936. << m_DBTableGuid << ","
  937. << GetEntry() << ","
  938. << mapid <<","
  939. << uint32(spawnMask) << "," // cast to prevent save as symbol
  940. << uint16(GetPhaseMask()) << "," // prevent out of range error
  941. << displayId <<","
  942. << GetEquipmentId() <<","
  943. << GetPositionX() << ","
  944. << GetPositionY() << ","
  945. << GetPositionZ() << ","
  946. << GetOrientation() << ","
  947. << m_respawnDelay << "," //respawn time
  948. << (float) m_respawnradius << "," //spawn distance (float)
  949. << (uint32) (0) << "," //currentwaypoint
  950. << GetHealth() << "," //curhealth
  951. << GetPower(POWER_MANA) << "," //curmana
  952. << (m_isDeadByDefault ? 1 : 0) << "," //is_dead
  953. << GetDefaultMovementType() << "," //default movement generator type
  954. << npcflag << ","
  955. << unit_flags << ","
  956. << dynamicflags << ")";
  957. trans->Append(ss.str().c_str());
  958. WorldDatabase.CommitTransaction(trans);
  959. }
  960. void Creature::SelectLevel(const CreatureInfo *cinfo)
  961. {
  962. uint32 rank = isPet()? 0 : cinfo->rank;
  963. // level
  964. uint8 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel);
  965. uint8 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel);
  966. uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
  967. SetLevel(level);
  968. CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cinfo->unit_class);
  969. // health
  970. float healthmod = _GetHealthMod(rank);
  971. uint32 basehp = stats->GenerateHealth(cinfo);
  972. uint32 health = uint32(basehp * healthmod);
  973. SetCreateHealth(health);
  974. SetMaxHealth(health);
  975. SetHealth(health);
  976. ResetPlayerDamageReq();
  977. // mana
  978. uint32 mana = stats->GenerateMana(cinfo);
  979. SetCreateMana(mana);
  980. SetMaxPower(POWER_MANA, mana); //MAX Mana
  981. SetPower(POWER_MANA, mana);
  982. // TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
  983. SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
  984. SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
  985. //damage
  986. float damagemod = 1.0f;//_GetDamageMod(rank);
  987. SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
  988. SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
  989. SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod);
  990. SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * damagemod);
  991. SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
  992. }
  993. float Creature::_GetHealthMod(int32 Rank)
  994. {
  995. switch (Rank) // define rates for each elite rank
  996. {
  997. case CREATURE_ELITE_NORMAL:
  998. return sWorld->getRate(RATE_CREATURE_NORMAL_HP);
  999. case CREATURE_ELITE_ELITE:
  1000. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_HP);
  1001. case CREATURE_ELITE_RAREELITE:
  1002. return sWorld->getRate(RATE_CREATURE_ELITE_RAREELITE_HP);
  1003. case CREATURE_ELITE_WORLDBOSS:
  1004. return sWorld->getRate(RATE_CREATURE_ELITE_WORLDBOSS_HP);
  1005. case CREATURE_ELITE_RARE:
  1006. return sWorld->getRate(RATE_CREATURE_ELITE_RARE_HP);
  1007. default:
  1008. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_HP);
  1009. }
  1010. }
  1011. float Creature::_GetDamageMod(int32 Rank)
  1012. {
  1013. switch (Rank) // define rates for each elite rank
  1014. {
  1015. case CREATURE_ELITE_NORMAL:
  1016. return sWorld->getRate(RATE_CREATURE_NORMAL_DAMAGE);
  1017. case CREATURE_ELITE_ELITE:
  1018. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
  1019. case CREATURE_ELITE_RAREELITE:
  1020. return sWorld->getRate(RATE_CREATURE_ELITE_RAREELITE_DAMAGE);
  1021. case CREATURE_ELITE_WORLDBOSS:
  1022. return sWorld->getRate(RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE);
  1023. case CREATURE_ELITE_RARE:
  1024. return sWorld->getRate(RATE_CREATURE_ELITE_RARE_DAMAGE);
  1025. default:
  1026. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
  1027. }
  1028. }
  1029. float Creature::GetSpellDamageMod(int32 Rank)
  1030. {
  1031. switch (Rank) // define rates for each elite rank
  1032. {
  1033. case CREATURE_ELITE_NORMAL:
  1034. return sWorld->getRate(RATE_CREATURE_NORMAL_SPELLDAMAGE);
  1035. case CREATURE_ELITE_ELITE:
  1036. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE);
  1037. case CREATURE_ELITE_RAREELITE:
  1038. return sWorld->getRate(RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE);
  1039. case CREATURE_ELITE_WORLDBOSS:
  1040. return sWorld->getRate(RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE);
  1041. case CREATURE_ELITE_RARE:
  1042. return sWorld->getRate(RATE_CREATURE_ELITE_RARE_SPELLDAMAGE);
  1043. default:
  1044. return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE);
  1045. }
  1046. }
  1047. bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData *data)
  1048. {
  1049. SetZoneScript();
  1050. if (m_zoneScript && data)
  1051. {
  1052. Entry = m_zoneScript->GetCreatureEntry(guidlow, data);
  1053. if (!Entry)
  1054. return false;
  1055. }
  1056. CreatureInfo const *cinfo = ObjectMgr::GetCreatureTemplate(Entry);
  1057. if (!cinfo)
  1058. {
  1059. sLog->outErrorDb("Creature::CreateFromProto(): creature template (guidlow: %u, entry: %u) does not exist.", guidlow, Entry);
  1060. return false;
  1061. }
  1062. SetOriginalEntry(Entry);
  1063. if (!vehId)
  1064. vehId = cinfo->VehicleId;
  1065. if (vehId && !CreateVehicleKit(vehId, Entry))
  1066. vehId = 0;
  1067. Object::_Create(guidlow, Entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT);
  1068. if (!UpdateEntry(Entry, team, data))
  1069. return false;
  1070. return true;
  1071. }
  1072. bool Creature::LoadFromDB(uint32 guid, Map *map)
  1073. {
  1074. CreatureData const* data = sObjectMgr->GetCreatureData(guid);
  1075. if (!data)
  1076. {
  1077. sLog->outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid);
  1078. return false;
  1079. }
  1080. m_DBTableGuid = guid;
  1081. if (map->GetInstanceId() == 0)
  1082. {
  1083. if (map->GetCreature(MAKE_NEW_GUID(guid,data->id,HIGHGUID_UNIT)))
  1084. return false;
  1085. }
  1086. else
  1087. guid = sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT);
  1088. uint16 team = 0;
  1089. if (!Create(guid,map,data->phaseMask,data->id,0,team,data->posX,data->posY,data->posZ,data->orientation,data))
  1090. return false;
  1091. //We should set first home position, because then AI calls home movement
  1092. SetHomePosition(data->posX,data->posY,data->posZ,data->orientation);
  1093. m_respawnradius = data->spawndist;
  1094. m_respawnDelay = data->spawntimesecs;
  1095. m_isDeadByDefault = data->is_dead;
  1096. m_deathState = m_isDeadByDefault ? DEAD : ALIVE;
  1097. m_respawnTime = sObjectMgr->GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId());
  1098. if (m_respawnTime) // respawn on Update
  1099. {
  1100. m_deathState = DEAD;
  1101. if (canFly())
  1102. {
  1103. float tz = map->GetHeight(data->posX,data->posY,data->posZ,false);
  1104. if (data->posZ - tz > 0.1)
  1105. Relocate(data->posX,data->posY,tz);
  1106. }
  1107. }
  1108. uint32 curhealth;
  1109. if (!m_regenHealth)
  1110. {
  1111. curhealth = data->curhealth;
  1112. if (curhealth)
  1113. {
  1114. curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank));
  1115. if (curhealth < 1)
  1116. curhealth = 1;
  1117. }
  1118. SetPower(POWER_MANA,data->curmana);
  1119. }
  1120. else
  1121. {
  1122. curhealth = GetMaxHealth();
  1123. SetPower(POWER_MANA,GetMaxPower(POWER_MANA));
  1124. }
  1125. SetHealth(m_deathState == ALIVE ? curhealth : 0);
  1126. // checked at creature_template loading
  1127. m_defaultMovementType = MovementGeneratorType(data->movementType);
  1128. m_creatureData = data;
  1129. return true;
  1130. }
  1131. void Creature::LoadEquipment(uint32 equip_entry, bool force)
  1132. {
  1133. if (equip_entry == 0)
  1134. {
  1135. if (force)
  1136. {
  1137. for (uint8 i = 0; i < 3; ++i)
  1138. SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
  1139. m_equipmentId = 0;
  1140. }
  1141. return;
  1142. }
  1143. EquipmentInfo const *einfo = sObjectMgr->GetEquipmentInfo(equip_entry);
  1144. if (!einfo)
  1145. return;
  1146. m_equipmentId = equip_entry;
  1147. for (uint8 i = 0; i < 3; ++i)
  1148. SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->equipentry[i]);
  1149. }
  1150. bool Creature::hasQuest(uint32 quest_id) const
  1151. {
  1152. QuestRelationBounds qr = sObjectMgr->GetCreatureQuestRelationBounds(GetEntry());
  1153. for (QuestRelations::const_iterator itr = qr.first; itr != qr.second; ++itr)
  1154. {
  1155. if (itr->second == quest_id)
  1156. return true;
  1157. }
  1158. return false;
  1159. }
  1160. bool Creature::hasInvolvedQuest(uint32 quest_id) const
  1161. {
  1162. QuestRelationBounds qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(GetEntry());
  1163. for (QuestRelations::const_iterator itr = qir.first; itr != qir.second; ++itr)
  1164. {
  1165. if (itr->second == quest_id)
  1166. return true;
  1167. }
  1168. return false;
  1169. }
  1170. void Creature::DeleteFromDB()
  1171. {
  1172. if (!m_DBTableGuid)
  1173. {
  1174. sLog->outError("Trying to delete not saved creature! LowGUID: %u, Entry: %u", GetGUIDLow(), GetEntry());
  1175. return;
  1176. }
  1177. sObjectMgr->RemoveCreatureRespawnTime(m_DBTableGuid, GetInstanceId());
  1178. sObjectMgr->DeleteCreatureData(m_DBTableGuid);
  1179. SQLTransaction trans = WorldDatabase.BeginTransaction();
  1180. trans->PAppend("DELETE FROM creature WHERE guid = '%u'", m_DBTableGuid);
  1181. trans->PAppend("DELETE FROM creature_addon WHERE guid = '%u'", m_DBTableGuid);
  1182. trans->PAppend("DELETE FROM game_event_creature WHERE guid = '%u'", m_DBTableGuid);
  1183. trans->PAppend("DELETE FROM game_event_model_equip WHERE guid = '%u'", m_DBTableGuid);
  1184. WorldDatabase.CommitTransaction(trans);
  1185. }
  1186. bool Creature::isVisibleForInState(WorldObject const* seer) const
  1187. {
  1188. if (!Unit::isVisibleForInState(seer))
  1189. return false;
  1190. if (isAlive() || (m_isDeadByDefault && m_deathState == CORPSE) || m_corpseRemoveTime > time(NULL))
  1191. return true;
  1192. return false;
  1193. }
  1194. bool Creature::canSeeAlways(WorldObject const* obj) const
  1195. {
  1196. if (Unit::canSeeAlways(obj))
  1197. return true;
  1198. if (IsAIEnabled && AI()->CanSeeAlways(obj))
  1199. return true;
  1200. return false;
  1201. }
  1202. bool Creature::canStartAttack(Unit const* who, bool force) const
  1203. {
  1204. if (isCivilian())
  1205. return false;
  1206. if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE))
  1207. return false;
  1208. if (!canFly() && (GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE + m_CombatDistance))
  1209. //|| who->IsControlledByPlayer() && who->IsFlying()))
  1210. // we cannot check flying for other creatures, too much map/vmap calculation
  1211. // TODO: should switch to range attack
  1212. return false;
  1213. if (!force)
  1214. {
  1215. if (!_IsTargetAcceptable(who))
  1216. return false;
  1217. if (who->isInCombat())
  1218. if (Unit *victim = who->getAttackerForHelper())
  1219. if (IsWithinDistInMap(victim, sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)))
  1220. force = true;
  1221. if (!force && (IsNeutralToAll() || !IsWithinDistInMap(who, GetAttackDistance(who) + m_CombatDistance)))
  1222. return false;
  1223. }
  1224. if (!canCreatureAttack(who, force))
  1225. return false;
  1226. return IsWithinLOSInMap(who);
  1227. }
  1228. float Creature::GetAttackDistance(Unit const* pl) const
  1229. {
  1230. float aggroRate = sWorld->getRate(RATE_CREATURE_AGGRO);
  1231. if (aggroRate == 0)
  1232. return 0.0f;
  1233. uint32 playerlevel = pl->getLevelForTarget(this);
  1234. uint32 creaturelevel = getLevelForTarget(pl);
  1235. int32 leveldif = int32(playerlevel) - int32(creaturelevel);
  1236. // "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."
  1237. if (leveldif < - 25)
  1238. leveldif = -25;
  1239. // "The aggro radius of a mob having the same level as the player is roughly 20 yards"
  1240. float RetDistance = 20;
  1241. // "Aggro Radius varies with level difference at a rate of roughly 1 yard/level"
  1242. // radius grow if playlevel < creaturelevel
  1243. RetDistance -= (float)leveldif;
  1244. if (creaturelevel+5 <= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
  1245. {
  1246. // detect range auras
  1247. RetDistance += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE);
  1248. // detected range auras
  1249. RetDistance += pl->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE);
  1250. }
  1251. // "Minimum Aggro Radius for a mob seems to be combat range (5 yards)"
  1252. if (RetDistance < 5)
  1253. RetDistance = 5;
  1254. return (RetDistance*aggroRate);
  1255. }
  1256. void Creature::setDeathState(DeathState s)
  1257. {
  1258. if ((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault))
  1259. {
  1260. m_corpseRemoveTime = time(NULL) + m_corpseDelay;
  1261. m_respawnTime = time(NULL) + m_respawnDelay + m_corpseDelay;
  1262. // always save boss respawn time at death to prevent crash cheating
  1263. if (sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY) || isWorldBoss())
  1264. SaveRespawnTime();
  1265. }
  1266. Unit::setDeathState(s);
  1267. if (s == JUST_DIED)
  1268. {
  1269. SetUInt64Value(UNIT_FIELD_TARGET,0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
  1270. SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
  1271. setActive(false);
  1272. if (!isPet() && GetCreatureInfo()->SkinLootId)
  1273. if (LootTemplates_Skinning.HaveLootFor(GetCreatureInfo()->SkinLootId))
  1274. if (hasLootRecipient())
  1275. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
  1276. if (HasSearchedAssistance())
  1277. {
  1278. SetNoSearchAssistance(false);
  1279. UpdateSpeed(MOVE_RUN, false);
  1280. }
  1281. //Dismiss group if is leader
  1282. if (m_formation && m_formation->getLeader() == this)
  1283. m_formation->FormationReset(true);
  1284. if (ZoneScript* zoneScript = GetZoneScript())
  1285. zoneScript->OnCreatureDeath(this);
  1286. if ((canFly() || IsFlying()) && FallGround())
  1287. return;
  1288. Unit::setDeathState(CORPSE);
  1289. }
  1290. else if (s == JUST_ALIVED)
  1291. {
  1292. //if (isPet())
  1293. // setActive(true);
  1294. SetFullHealth();
  1295. SetLootRecipient(NULL);
  1296. ResetPlayerDamageReq();
  1297. CreatureInfo const *cinfo = GetCreatureInfo();
  1298. AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
  1299. if (GetCreatureInfo()->InhabitType & INHABIT_AIR)
  1300. AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING);
  1301. if (GetCreatureInfo()->InhabitType & INHABIT_WATER)
  1302. AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
  1303. SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
  1304. ClearUnitState(uint32(UNIT_STAT_ALL_STATE));
  1305. SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
  1306. LoadCreaturesAddon(true);
  1307. Motion_Initialize();
  1308. if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask)
  1309. SetPhaseMask(GetCreatureData()->phaseMask, false);
  1310. Unit::setDeathState(ALIVE);
  1311. }
  1312. }
  1313. bool Creature::FallGround()
  1314. {
  1315. // Let's abort after we called this function one time
  1316. if (getDeathState() == DEAD_FALLING)
  1317. return false;
  1318. float x, y, z;
  1319. GetPosition(x, y, z);
  1320. // use larger distance for vmap height search than in most other cases
  1321. float ground_Z = GetMap()->GetHeight(x, y, z, true, MAX_FALL_DISTANCE);
  1322. if (fabs(ground_Z - z) < 0.1f)
  1323. return false;
  1324. GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND);
  1325. Unit::setDeathState(DEAD_FALLING);
  1326. return true;
  1327. }
  1328. void Creature::Respawn(bool force)
  1329. {
  1330. DestroyForNearbyPlayers();
  1331. if (force)
  1332. {
  1333. if (isAlive())
  1334. setDeathState(JUST_DIED);
  1335. else if (getDeathState() != CORPSE)
  1336. setDeathState(CORPSE);
  1337. }
  1338. RemoveCorpse(false);
  1339. if (getDeathState() == DEAD)
  1340. {
  1341. if (m_DBTableGuid)
  1342. sObjectMgr->RemoveCreatureRespawnTime(m_DBTableGuid, GetInstanceId());
  1343. sLog->outStaticDebug("Respawning...");
  1344. m_respawnTime = 0;
  1345. lootForPickPocketed = false;
  1346. lootForBody = false;
  1347. if (m_originalEntry != GetEntry())
  1348. UpdateEntry(m_originalEntry);
  1349. CreatureInfo const *cinfo = GetCreatureInfo();
  1350. SelectLevel(cinfo);
  1351. if (m_isDeadByDefault)
  1352. {
  1353. setDeathState(JUST_DIED);
  1354. i_motionMaster.Clear();
  1355. ClearUnitState(uint32(UNIT_STAT_ALL_STATE));
  1356. LoadCreaturesAddon(true);
  1357. }
  1358. else
  1359. setDeathState(JUST_ALIVED);
  1360. CreatureModelInfo const *minfo = sObjectMgr->GetCreatureModelRandomGender(GetNativeDisplayId());
  1361. if (minfo) // Cancel load if no model defined
  1362. {
  1363. uint32 display_id = minfo->modelid; // it can be different (for another gender)
  1364. SetDisplayId(display_id);
  1365. SetNativeDisplayId(display_id);
  1366. SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
  1367. }
  1368. GetMotionMaster()->InitDefault();
  1369. //Call AI respawn virtual function
  1370. if (IsAIEnabled)
  1371. TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
  1372. uint32 poolid = GetDBTableGUIDLow() ? sPoolMgr->IsPartOfAPool<Creature>(GetDBTableGUIDLow()) : 0;
  1373. if (poolid)
  1374. sPoolMgr->UpdatePool<Creature>(poolid, GetDBTableGUIDLow());
  1375. //Re-initialize reactstate that could be altered by movementgenerators
  1376. InitializeReactState();
  1377. }
  1378. UpdateObjectVisibility();
  1379. }
  1380. void Creature::ForcedDespawn(uint32 timeMSToDespawn)
  1381. {
  1382. if (timeMSToDespawn)
  1383. {
  1384. ForcedDespawnDelayEvent *pEvent = new ForcedDespawnDelayEvent(*this);
  1385. m_Events.AddEvent(pEvent, m_Events.CalculateTime(timeMSToDespawn));
  1386. return;
  1387. }
  1388. if (isAlive())
  1389. setDeathState(JUST_DIED);
  1390. RemoveCorpse(false);
  1391. }
  1392. void Creature::DespawnOrUnsummon(uint32 msTimeToDespawn /*= 0*/)
  1393. {
  1394. if (TempSummon* summon = this->ToTempSummon())
  1395. summon->UnSummon(msTimeToDespawn);
  1396. else
  1397. ForcedDespawn(msTimeToDespawn);
  1398. }
  1399. bool Creature::IsImmunedToSpell(SpellEntry const* spellInfo)
  1400. {
  1401. if (!spellInfo)
  1402. return false;
  1403. if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))
  1404. return true;
  1405. return Unit::IsImmunedToSpell(spellInfo);
  1406. }
  1407. bool Creature::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
  1408. {
  1409. if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->EffectMechanic[index] - 1)))
  1410. return true;
  1411. if (GetCreatureInfo()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effect[index] == SPELL_EFFECT_HEAL)
  1412. return true;
  1413. return Unit::IsImmunedToSpellEffect(spellInfo, index);
  1414. }
  1415. SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim)
  1416. {
  1417. if (!pVictim)
  1418. return NULL;
  1419. for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
  1420. {
  1421. if (!m_spells[i])
  1422. continue;
  1423. SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i]);
  1424. if (!spellInfo)
  1425. {
  1426. sLog->outError("WORLD: unknown spell id %i", m_spells[i]);
  1427. continue;
  1428. }
  1429. bool bcontinue = true;
  1430. for (uint32 j = 0; j < MAX_SPELL_EFFECTS; j++)
  1431. {
  1432. if ((spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE) ||
  1433. (spellInfo->Effect[j] == SPELL_EFFECT_INSTAKILL) ||
  1434. (spellInfo->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) ||
  1435. (spellInfo->Effect[j] == SPELL_EFFECT_HEALTH_LEECH)
  1436. )
  1437. {
  1438. bcontinue = false;
  1439. break;
  1440. }
  1441. }
  1442. if (bcontinue) continue;
  1443. if (spellInfo->manaCost > GetPower(POWER_MANA))
  1444. continue;
  1445. SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
  1446. float range = GetSpellMaxRangeForHostile(srange);
  1447. float minrange = GetSpellMinRangeForHostile(srange);
  1448. float dist = GetDistance(pVictim);
  1449. //if (!isInFront(pVictim, range) && spellInfo->AttributesEx)
  1450. // continue;
  1451. if (dist > range || dist < minrange)
  1452. continue;
  1453. if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
  1454. continue;
  1455. if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
  1456. continue;
  1457. return spellInfo;
  1458. }
  1459. return NULL;
  1460. }
  1461. SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim)
  1462. {
  1463. if (!pVictim)
  1464. return NULL;
  1465. for (uint32 i=0; i < CREATURE_MAX_SPELLS; ++i)
  1466. {
  1467. if (!m_spells[i])
  1468. continue;
  1469. SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i]);
  1470. if (!spellInfo)
  1471. {
  1472. sLog->outError("WORLD: unknown spell id %i", m_spells[i]);
  1473. continue;
  1474. }
  1475. bool bcontinue = true;
  1476. for (uint32 j = 0; j < MAX_SPELL_EFFECTS; j++)
  1477. {
  1478. if ((spellInfo->Effect[j] == SPELL_EFFECT_HEAL))
  1479. {
  1480. bcontinue = false;
  1481. break;
  1482. }
  1483. }
  1484. if (bcontinue) continue;
  1485. if (spellInfo->manaCost > GetPower(POWER_MANA))
  1486. continue;
  1487. SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
  1488. float range = GetSpellMaxRangeForFriend(srange);
  1489. float minrange = GetSpellMinRangeForFriend(srange);
  1490. float dist = GetDistance(pVictim);
  1491. //if (!isInFront(pVictim, range) && spellInfo->AttributesEx)
  1492. // continue;
  1493. if (dist > range || dist < minrange)
  1494. continue;
  1495. if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
  1496. continue;
  1497. if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
  1498. continue;
  1499. return spellInfo;
  1500. }
  1501. return NULL;
  1502. }
  1503. // select nearest hostile unit within the given distance (regardless of threat list).
  1504. Unit* Creature::SelectNearestTarget(float dist) const
  1505. {
  1506. CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
  1507. Cell cell(p);
  1508. cell.data.Part.reserved = ALL_DISTRICT;
  1509. cell.SetNoCreate();
  1510. Unit *target = NULL;
  1511. {
  1512. if (dist == 0.0f)
  1513. dist = MAX_VISIBILITY_DISTANCE;
  1514. Trinity::NearestHostileUnitCheck u_check(this, dist);
  1515. Trinity::UnitLastSearcher<Trinity::NearestHostileUnitCheck> searcher(this, target, u_check);
  1516. TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
  1517. TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
  1518. cell.Visit(p, world_unit_searcher, *GetMap(), *this, dist);
  1519. cell.Visit(p, grid_unit_searcher, *GetMap(), *this, dist);
  1520. }
  1521. return target;
  1522. }
  1523. // select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list.
  1524. Unit* Creature::SelectNearestTargetInAttackDistance(float dist) const
  1525. {
  1526. CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
  1527. Cell cell(p);
  1528. cell.data.Part.reserved = ALL_DISTRICT;
  1529. cell.SetNoCreate();
  1530. Unit *target = NULL;
  1531. if (dist > ATTACK_DISTANCE)
  1532. sLog->outError("Creature (GUID: %u Entry: %u) SelectNearestTargetInAttackDistance called with dist > ATTACK_DISTANCE. Extra distance ignored.",GetGUIDLow(),GetEntry());
  1533. {
  1534. Trinity::NearestHostileUnitInAttackDistanceCheck u_check(this, dist);
  1535. Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck> searcher(this, target, u_check);
  1536. TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
  1537. TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
  1538. cell.Visit(p, world_unit_searcher, *GetMap(), *this, ATTACK_DISTANCE);
  1539. cell.Visit(p, grid_unit_searcher, *GetMap(), *this, ATTACK_DISTANCE);
  1540. }
  1541. return target;
  1542. }
  1543. void Creature::SendAIReaction(AiReaction reactionType)
  1544. {
  1545. WorldPacket data(SMSG_AI_REACTION, 12);
  1546. data << uint64(GetGUID());
  1547. data << uint32(reactionType);
  1548. ((WorldObject*)this)->SendMessageToSet(&data, true);
  1549. sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_AI_REACTION, type %u.", reactionType);
  1550. }
  1551. void Creature::CallAssistance()
  1552. {
  1553. if (!m_AlreadyCallAssistance && getVictim() && !isPet() && !isCharmed())
  1554. {
  1555. SetNoCallAssistance(true);
  1556. float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
  1557. if (radius > 0)
  1558. {
  1559. std::list<Creature*> assistList;
  1560. {
  1561. CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
  1562. Cell cell(p);
  1563. cell.data.Part.reserved = ALL_DISTRICT;
  1564. cell.SetNoCreate();
  1565. Trinity::AnyAssistCreatureInRangeCheck u_check(this, getVictim(), radius);
  1566. Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck> searcher(this, assistList, u_check);
  1567. TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
  1568. cell.Visit(p, grid_creature_searcher, *GetMap(), *this, radius);
  1569. }
  1570. if (!assistList.empty())
  1571. {
  1572. AssistDelayEvent *e = new AssistDelayEvent(getVictim()->GetGUID(), *this);
  1573. while (!assistList.empty())
  1574. {
  1575. // Pushing guids because in delay can happen some creature gets despawned => invalid pointer
  1576. e->AddAssistant((*assistList.begin())->GetGUID());
  1577. assistList.pop_front();
  1578. }
  1579. m_Events.AddEvent(e, m_Events.CalculateTime(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)));
  1580. }
  1581. }
  1582. }
  1583. }
  1584. void Creature::CallForHelp(float fRadius)
  1585. {
  1586. if (fRadius <= 0.0f || !getVictim() || isPet() || isCharmed())
  1587. return;
  1588. CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
  1589. Cell cell(p);
  1590. cell.data.Part.reserved = ALL_DISTRICT;
  1591. cell.SetNoCreate();
  1592. Trinity::CallOfHelpCreatureInRangeDo u_do(this, getVictim(), fRadius);
  1593. Trinity::CreatureWorker<Trinity::CallOfHelpCreatureInRangeDo> worker(this, u_do);
  1594. TypeContainerVisitor<Trinity::CreatureWorker<Trinity::CallOfHelpCreatureInRangeDo>, GridTypeMapContainer > grid_creature_searcher(worker);
  1595. cell.Visit(p, grid_creature_searcher, *GetMap(), *this, fRadius);
  1596. }
  1597. bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction /*= true*/) const
  1598. {
  1599. // is it true?
  1600. if (!HasReactState(REACT_AGGRESSIVE))
  1601. return false;
  1602. // we don't need help from zombies :)
  1603. if (!isAlive())
  1604. return false;
  1605. // we don't need help from non-combatant ;)
  1606. if (isCivilian())
  1607. return false;
  1608. if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PASSIVE))
  1609. return false;
  1610. // skip fighting creature
  1611. if (isInCombat())
  1612. return false;
  1613. // only free creature
  1614. if (GetCharmerOrOwnerGUID())
  1615. return false;
  1616. // only from same creature faction
  1617. if (checkfaction)
  1618. {
  1619. if (getFaction() != u->getFaction())
  1620. return false;
  1621. }
  1622. else
  1623. {
  1624. if (!IsFriendlyTo(u))
  1625. return false;
  1626. }
  1627. // skip non hostile to caster enemy creatures
  1628. if (!IsHostileTo(enemy))
  1629. return false;
  1630. return true;
  1631. }
  1632. // use this function to avoid having hostile creatures attack
  1633. // friendlies and other mobs they shouldn't attack
  1634. bool Creature::_IsTargetAcceptable(const Unit *target) const
  1635. {
  1636. ASSERT(target);
  1637. // if the target cannot be attacked, the target is not acceptable
  1638. if (IsFriendlyTo(target)
  1639. || !target->isAttackableByAOE()
  1640. || (m_vehicle && (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))))
  1641. return false;
  1642. if (target->HasUnitState(UNIT_STAT_DIED))
  1643. {
  1644. // guards can detect fake death
  1645. if (isGuard() && target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH))
  1646. return true;
  1647. else
  1648. return false;
  1649. }
  1650. const Unit *myVictim = getAttackerForHelper();
  1651. const Unit *targetVictim = target->getAttackerForHelper();
  1652. // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
  1653. if (myVictim == target || targetVictim == this || IsHostileTo(target))
  1654. return true;
  1655. // if the target's victim is friendly, and the target is neutral, the target is acceptable
  1656. if (targetVictim && IsFriendlyTo(targetVictim))
  1657. return true;
  1658. // if the target's victim is not friendly, or the target is friendly, the target is not acceptable
  1659. return false;
  1660. }
  1661. void Creature::SaveRespawnTime()
  1662. {
  1663. if (isSummon() || !m_DBTableGuid || (m_creatureData && !m_creatureData->dbData))
  1664. return;
  1665. sObjectMgr->SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
  1666. }
  1667. // this should not be called by petAI or
  1668. bool Creature::canCreatureAttack(Unit const *pVictim, bool force) const
  1669. {
  1670. if (!pVictim->IsInMap(this))
  1671. return false;
  1672. if (!canAttack(pVictim, force))
  1673. return false;
  1674. if (!pVictim->isInAccessiblePlaceFor(this))
  1675. return false;
  1676. if (IsAIEnabled && !AI()->CanAIAttack(pVictim))
  1677. return false;
  1678. if (sMapStore.LookupEntry(GetMapId())->IsDungeon())
  1679. return true;
  1680. //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
  1681. float dist = std::max(GetAttackDistance(pVictim), sWorld->getFloatConfig(CONFIG_THREAT_RADIUS)) + m_CombatDistance;
  1682. if (Unit *unit = GetCharmerOrOwner())
  1683. return pVictim->IsWithinDist(unit, dist);
  1684. else
  1685. return pVictim->IsInDist(&m_homePosition, dist);
  1686. }
  1687. CreatureDataAddon const* Creature::GetCreatureAddon() const
  1688. {
  1689. if (m_DBTableGuid)
  1690. {
  1691. if (CreatureDataAddon const* addon = ObjectMgr::GetCreatureAddon(m_DBTableGuid))
  1692. return addon;
  1693. }
  1694. // dependent from difficulty mode entry
  1695. return ObjectMgr::GetCreatureTemplateAddon(GetCreatureInfo()->Entry);
  1696. }
  1697. //creature_addon table
  1698. bool Creature::LoadCreaturesAddon(bool reload)
  1699. {
  1700. CreatureDataAddon const *cainfo = GetCreatureAddon();
  1701. if (!cainfo)
  1702. return false;
  1703. if (cainfo->mount != 0)
  1704. Mount(cainfo->mount);
  1705. if (cainfo->bytes1 != 0)
  1706. {
  1707. // 0 StandState
  1708. // 1 FreeTalentPoints Pet only, so always 0 for default creature
  1709. // 2 StandFlags
  1710. // 3 StandMiscFlags
  1711. SetByteValue(UNIT_FIELD_BYTES_1, 0, uint8(cainfo->bytes1 & 0xFF));
  1712. //SetByteValue(UNIT_FIELD_BYTES_1, 1, uint8((cainfo->bytes1 >> 8) & 0xFF));
  1713. SetByteValue(UNIT_FIELD_BYTES_1, 1, 0);
  1714. SetByteValue(UNIT_FIELD_BYTES_1, 2, uint8((cainfo->bytes1 >> 16) & 0xFF));
  1715. SetByteValue(UNIT_FIELD_BYTES_1, 3, uint8((cainfo->bytes1 >> 24) & 0xFF));
  1716. }
  1717. if (cainfo->bytes2 != 0)
  1718. {
  1719. // 0 SheathState
  1720. // 1 Bytes2Flags
  1721. // 2 UnitRename Pet only, so always 0 for default creature
  1722. // 3 ShapeshiftForm Must be determined/set by shapeshift spell/aura
  1723. SetByteValue(UNIT_FIELD_BYTES_2, 0, uint8(cainfo->bytes2 & 0xFF));
  1724. //SetByteValue(UNIT_FIELD_BYTES_2, 1, uint8((cainfo->bytes2 >> 8) & 0xFF));
  1725. //SetByteValue(UNIT_FIELD_BYTES_2, 2, uint8((cainfo->bytes2 >> 16) & 0xFF));
  1726. SetByteValue(UNIT_FIELD_BYTES_2, 2, 0);
  1727. //SetByteValue(UNIT_FIELD_BYTES_2, 3, uint8((cainfo->bytes2 >> 24) & 0xFF));
  1728. SetByteValue(UNIT_FIELD_BYTES_2, 3, 0);
  1729. }
  1730. if (cainfo->emote != 0)
  1731. SetUInt32Value(UNIT_NPC_EMOTESTATE, cainfo->emote);
  1732. //Load Path
  1733. if (cainfo->path_id != 0)
  1734. m_path_id = cainfo->path_id;
  1735. if (cainfo->auras)
  1736. {
  1737. for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura)
  1738. {
  1739. SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura->spell_id);
  1740. if (!AdditionalSpellInfo)
  1741. {
  1742. sLog->outErrorDb("Creature (GUID: %u Entry: %u) has wrong spell %u defined in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id);
  1743. continue;
  1744. }
  1745. // skip already applied aura
  1746. if (HasAura(cAura->spell_id))
  1747. {
  1748. if (!reload)
  1749. sLog->outErrorDb("Creature (GUID: %u Entry: %u) has duplicate aura (spell %u) in `auras` field.",GetGUIDLow(),GetEntry(),cAura->spell_id);
  1750. continue;
  1751. }
  1752. AddAura(AdditionalSpellInfo, cAura->effectMask, this);
  1753. sLog->outDebug(LOG_FILTER_UNITS, "Spell: %u with AuraEffectMask %u added to creature (GUID: %u Entry: %u)", cAura->spell_id, cAura->effectMask,GetGUIDLow(),GetEntry());
  1754. }
  1755. }
  1756. return true;
  1757. }
  1758. /// Send a message to LocalDefense channel for players opposition team in the zone
  1759. void Creature::SendZoneUnderAttackMessage(Player* attacker)
  1760. {
  1761. uint32 enemy_team = attacker->GetTeam();
  1762. WorldPacket data(SMSG_ZONE_UNDER_ATTACK,4);
  1763. data << (uint32)GetAreaId();
  1764. sWorld->SendGlobalMessage(&data,NULL,(enemy_team == ALLIANCE ? HORDE : ALLIANCE));
  1765. }
  1766. void Creature::SetInCombatWithZone()
  1767. {
  1768. if (!CanHaveThreatList())
  1769. {
  1770. sLog->outError("Creature entry %u call SetInCombatWithZone but creature cannot have threat list.", GetEntry());
  1771. return;
  1772. }
  1773. Map* pMap = GetMap();
  1774. if (!pMap->IsDungeon())
  1775. {
  1776. sLog->outError("Creature entry %u call SetInCombatWithZone for map (id: %u) that isn't an instance.", GetEntry(), pMap->GetId());
  1777. return;
  1778. }
  1779. Map::PlayerList const &PlList = pMap->GetPlayers();
  1780. if (PlList.isEmpty())
  1781. return;
  1782. for (Map::PlayerList::const_iterator i = PlList.begin(); i != PlList.end(); ++i)
  1783. {
  1784. if (Player* pPlayer = i->getSource())
  1785. {
  1786. if (pPlayer->isGameMaster())
  1787. continue;
  1788. if (pPlayer->isAlive())
  1789. {
  1790. this->SetInCombatWith(pPlayer);
  1791. pPlayer->SetInCombatWith(this);
  1792. AddThreat(pPlayer, 0.0f);
  1793. }
  1794. }
  1795. }
  1796. }
  1797. void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
  1798. {
  1799. m_CreatureSpellCooldowns[spell_id] = end_time;
  1800. }
  1801. void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
  1802. {
  1803. m_CreatureCategoryCooldowns[category] = apply_time;
  1804. }
  1805. void Creature::AddCreatureSpellCooldown(uint32 spellid)
  1806. {
  1807. SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
  1808. if (!spellInfo)
  1809. return;
  1810. uint32 cooldown = GetSpellRecoveryTime(spellInfo);
  1811. if (Player *modOwner = GetSpellModOwner())
  1812. modOwner->ApplySpellMod(spellid, SPELLMOD_COOLDOWN, cooldown);
  1813. if (cooldown)
  1814. _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILLISECONDS);
  1815. if (spellInfo->Category)
  1816. _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL));
  1817. }
  1818. bool Creature::HasCategoryCooldown(uint32 spell_id) const
  1819. {
  1820. SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
  1821. if (!spellInfo)
  1822. return false;
  1823. CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category);
  1824. return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL));
  1825. }
  1826. bool Creature::HasSpellCooldown(uint32 spell_id) const
  1827. {
  1828. CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id);
  1829. return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id);
  1830. }
  1831. bool Creature::HasSpell(uint32 spellID) const
  1832. {
  1833. uint8 i;
  1834. for (i = 0; i < CREATURE_MAX_SPELLS; ++i)
  1835. if (spellID == m_spells[i])
  1836. break;
  1837. return i < CREATURE_MAX_SPELLS; //broke before end of iteration of known spells
  1838. }
  1839. time_t Creature::GetRespawnTimeEx() const
  1840. {
  1841. time_t now = time(NULL);
  1842. if (m_respawnTime > now)
  1843. return m_respawnTime;
  1844. else
  1845. return now;
  1846. }
  1847. void Creature::GetRespawnCoord(float &x, float &y, float &z, float* ori, float* dist) const
  1848. {
  1849. if (m_DBTableGuid)
  1850. {
  1851. if (CreatureData const* data = sObjectMgr->GetCreatureData(GetDBTableGUIDLow()))
  1852. {
  1853. x = data->posX;
  1854. y = data->posY;
  1855. z = data->posZ;
  1856. if (ori)
  1857. *ori = data->orientation;
  1858. if (dist)
  1859. *dist = data->spawndist;
  1860. return;
  1861. }
  1862. }
  1863. x = GetPositionX();
  1864. y = GetPositionY();
  1865. z = GetPositionZ();
  1866. if (ori)
  1867. *ori = GetOrientation();
  1868. if (dist)
  1869. *dist = 0;
  1870. }
  1871. void Creature::AllLootRemovedFromCorpse()
  1872. {
  1873. if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
  1874. {
  1875. time_t now = time(NULL);
  1876. if(m_corpseRemoveTime <= now)
  1877. return;
  1878. float decayRate;
  1879. CreatureInfo const *cinfo = GetCreatureInfo();
  1880. decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
  1881. uint32 diff = uint32((m_corpseRemoveTime - now) * decayRate);
  1882. m_respawnTime -= diff;
  1883. // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
  1884. if (cinfo && cinfo->SkinLootId)
  1885. m_corpseRemoveTime = time(NULL);
  1886. else
  1887. m_corpseRemoveTime -= diff;
  1888. }
  1889. }
  1890. uint8 Creature::getLevelForTarget(WorldObject const* target) const
  1891. {
  1892. if (!isWorldBoss() || !target->ToUnit())
  1893. return Unit::getLevelForTarget(target);
  1894. uint16 level = target->ToUnit()->getLevel() + sWorld->getIntConfig(CONFIG_WORLD_BOSS_LEVEL_DIFF);
  1895. if (level < 1)
  1896. return 1;
  1897. if (level > 255)
  1898. return 255;
  1899. return uint8(level);
  1900. }
  1901. std::string Creature::GetAIName() const
  1902. {
  1903. return ObjectMgr::GetCreatureTemplate(GetEntry())->AIName;
  1904. }
  1905. std::string Creature::GetScriptName() const
  1906. {
  1907. return sObjectMgr->GetScriptName(GetScriptId());
  1908. }
  1909. uint32 Creature::GetScriptId() const
  1910. {
  1911. return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptID;
  1912. }
  1913. VendorItemData const* Creature::GetVendorItems() const
  1914. {
  1915. return sObjectMgr->GetNpcVendorItemList(GetEntry());
  1916. }
  1917. uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
  1918. {
  1919. if (!vItem->maxcount)
  1920. return vItem->maxcount;
  1921. VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
  1922. for (; itr != m_vendorItemCounts.end(); ++itr)
  1923. if (itr->itemId == vItem->item)
  1924. break;
  1925. if (itr == m_vendorItemCounts.end())
  1926. return vItem->maxcount;
  1927. VendorItemCount* vCount = &*itr;
  1928. time_t ptime = time(NULL);
  1929. if (time_t(vCount->lastIncrementTime + vItem->incrtime) <= ptime)
  1930. {
  1931. ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(vItem->item);
  1932. uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
  1933. if ((vCount->count + diff * pProto->BuyCount) >= vItem->maxcount)
  1934. {
  1935. m_vendorItemCounts.erase(itr);
  1936. return vItem->maxcount;
  1937. }
  1938. vCount->count += diff * pProto->BuyCount;
  1939. vCount->lastIncrementTime = ptime;
  1940. }
  1941. return vCount->count;
  1942. }
  1943. uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count)
  1944. {
  1945. if (!vItem->maxcount)
  1946. return 0;
  1947. VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
  1948. for (; itr != m_vendorItemCounts.end(); ++itr)
  1949. if (itr->itemId == vItem->item)
  1950. break;
  1951. if (itr == m_vendorItemCounts.end())
  1952. {
  1953. uint32 new_count = vItem->maxcount > used_count ? vItem->maxcount-used_count : 0;
  1954. m_vendorItemCounts.push_back(VendorItemCount(vItem->item,new_count));
  1955. return new_count;
  1956. }
  1957. VendorItemCount* vCount = &*itr;
  1958. time_t ptime = time(NULL);
  1959. if (time_t(vCount->lastIncrementTime + vItem->incrtime) <= ptime)
  1960. {
  1961. ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(vItem->item);
  1962. uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
  1963. if ((vCount->count + diff * pProto->BuyCount) < vItem->maxcount)
  1964. vCount->count += diff * pProto->BuyCount;
  1965. else
  1966. vCount->count = vItem->maxcount;
  1967. }
  1968. vCount->count = vCount->count > used_count ? vCount->count-used_count : 0;
  1969. vCount->lastIncrementTime = ptime;
  1970. return vCount->count;
  1971. }
  1972. TrainerSpellData const* Creature::GetTrainerSpells() const
  1973. {
  1974. return sObjectMgr->GetNpcTrainerSpells(GetEntry());
  1975. }
  1976. // overwrite WorldObject function for proper name localization
  1977. const char* Creature::GetNameForLocaleIdx(LocaleConstant loc_idx) const
  1978. {
  1979. if (loc_idx != DEFAULT_LOCALE)
  1980. {
  1981. uint8 uloc_idx = uint8(loc_idx);
  1982. CreatureLocale const *cl = sObjectMgr->GetCreatureLocale(GetEntry());
  1983. if (cl)
  1984. {
  1985. if (cl->Name.size() > uloc_idx && !cl->Name[uloc_idx].empty())
  1986. return cl->Name[uloc_idx].c_str();
  1987. }
  1988. }
  1989. return GetName();
  1990. }
  1991. void Creature::FarTeleportTo(Map* map, float X, float Y, float Z, float O)
  1992. {
  1993. InterruptNonMeleeSpells(true);
  1994. CombatStop();
  1995. ClearComboPointHolders();
  1996. DeleteThreatList();
  1997. GetMotionMaster()->Clear(false);
  1998. DestroyForNearbyPlayers();
  1999. RemoveFromWorld();
  2000. ResetMap();
  2001. SetMap(map);
  2002. AddToWorld();
  2003. SetPosition(X, Y, Z, O, true);
  2004. }
  2005. bool Creature::IsDungeonBoss() const
  2006. {
  2007. CreatureInfo const *cinfo = ObjectMgr::GetCreatureTemplate(GetEntry());
  2008. return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS);
  2009. }