uint32 PetAI::GetSpellType(PetAutoSpellType type) { if (type >= PET_SPELL_MAX || m_spellType[type].empty()) return 0; std::vector<uint32> tmpSet; for (Unit::SpellIdSet::const_iterator itr = m_spellType[type].begin(); itr != m_spellType[type].end(); ++itr) { uint32 _spellID = *itr; if (!_spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(_spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; if (m_creature->HasSpellCooldown(spellInfo)) continue; if (IsInCombat() && IsNonCombatSpell(spellInfo)) continue; if (!IsInCombat() && IsPositiveSpell(spellInfo) && !IsNonCombatSpell(spellInfo)) { int32 duration = GetSpellDuration(spellInfo); // if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) // continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } tmpSet.push_back(_spellID); } if (tmpSet.empty()) return 0; else return tmpSet[urand(0, tmpSet.size() - 1)]; }
void AIUpdate() { if (!IsInCombat()) CastSpellOnTarget(_unit, Target_Self, dbcSpell.LookupEntry(SPELL_SHADOW_CHANNELING), false); if (timmer == 6 && IsInCombat()) { SpawnCreature(CN_VOLATILE_FELFIRE_FIEND, _unit->GetPositionX()+1, _unit->GetPositionY()+1, _unit->GetPositionZ(), 0, true); timmer = 0; } if(GetHealthPercent()<=25 && infusion == false) { ApplyAura(SPELL_SHADOW_INFUSION); infusion = true; } timmer++; ParentClass::AIUpdate(); }
void PetAI::_stopAttack() { inCombat = false; if (IsInCombat()) { m_creature->CastStop(); m_creature->AttackStop(); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveTargetedHome(); } }
void PetAI::_stopAttack() { if (!IsInCombat()) return; inCombat = false; m_creature->CastStop(); m_creature->AttackStop(); m_creature->GetMotionMaster()->Clear(); // move idle if (!m_savedTargetGuid) m_creature->GetMotionMaster()->MoveTargetedHome(); }
void TempSummon::Update(uint32 diff) { Creature::Update(diff); if (m_deathState == DEAD) { UnSummon(); return; } switch (m_type) { case TEMPSUMMON_MANUAL_DESPAWN: break; case TEMPSUMMON_TIMED_DESPAWN: { if (m_timer <= diff) { UnSummon(); return; } m_timer -= diff; break; } case TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT: { if (!IsInCombat()) { if (m_timer <= diff) { UnSummon(); return; } m_timer -= diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSUMMON_CORPSE_TIMED_DESPAWN: { if (m_deathState == CORPSE) { if (m_timer <= diff) { UnSummon(); return; } m_timer -= diff; } break; } case TEMPSUMMON_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (m_deathState == CORPSE || m_deathState == DEAD) { UnSummon(); return; } break; } case TEMPSUMMON_DEAD_DESPAWN: { if (m_deathState == DEAD) { UnSummon(); return; } break; } case TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (m_deathState == CORPSE || m_deathState == DEAD) { UnSummon(); return; } if (!IsInCombat()) { if (m_timer <= diff) { UnSummon(); return; } else m_timer -= diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSUMMON_TIMED_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (m_deathState == DEAD) { UnSummon(); return; } if (!IsInCombat() && IsAlive()) { if (m_timer <= diff) { UnSummon(); return; } else m_timer -= diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } default: UnSummon(); TC_LOG_ERROR("entities.unit", "Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type); break; } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); m_updateAlliesTimer.Update(diff); if (m_updateAlliesTimer.Passed()) { UpdateAllies(); m_updateAlliesTimer.Reset(); } if (!inCombat && !m_savedTargetGuid.IsEmpty()) { if (Unit* saved_target = m_creature->GetMap()->GetUnit(m_savedTargetGuid)) { if (!saved_target->isAlive()) m_savedTargetGuid.Clear(); else if (!saved_target->IsCrowdControlled()) AttackStart(saved_target); } else m_savedTargetGuid.Clear(); } if (inCombat && (!m_creature->getVictim() || !m_creature->getVictim()->isAlive() || (m_creature->IsPet() && m_creature->GetCharmInfo()->HasState(CHARM_STATE_ACTION, ACTIONS_DISABLE)))) _stopAttack(); if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) { UpdateAIType(); return; } // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim()); if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (!m_creature->getVictim()->isAlive()) // Stop attack if target dead { m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } else if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && IsInCombat() && m_creature->getVictim() && m_creature->getVictim()->IsCrowdControlled()) // Stop attack if target under CC effect { m_savedTargetGuid = m_creature->getVictim()->GetObjectGuid(); m_creature->InterruptSpell(CURRENT_GENERIC_SPELL, true); if (!m_creature->IsNonMeleeSpellCasted(false, false, true)) _stopAttack(); return; } else if (m_creature->IsStopped() || meleeReach) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (DoMeleeAttackIfReady()) { if (!m_creature->getVictim()) return; //if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } if (!m_creature->IsNonMeleeSpellCasted(true)) { m_attackDistanceRecheckTimer.Update(diff); if (m_attackDistanceRecheckTimer.Passed()) { m_attackDistanceRecheckTimer.Reset(); if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType == PET_AI_RANGED) { float dist = m_creature->GetDistance(m_creature->getVictim()); if ((m_creature->CanReachWithMeleeAttack(m_creature->getVictim()) && m_creature->IsWithinDist(m_creature->GetOwner(), m_creature->GetMap()->GetVisibilityDistance() / 2.0f)) || dist > (m_attackDistance + 2.0f)) { MoveToVictim(m_creature->getVictim()); return; } } if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI)) { // AOE check } } } } else if (Unit* target = GetPrimaryTarget()) { AttackStart(target); } else if (owner && owner->IsInCombat()) { switch (m_creature->GetCharmState(CHARM_STATE_REACT)) { case REACT_DEFENSIVE: { if (!m_creature->getVictim() || !m_creature->getVictim()->isAlive() || (m_primaryTargetGuid.IsEmpty() && owner->getVictim() != m_creature->getVictim() && owner->getVictim()->isAlive())) AttackStart(owner->getAttackerForHelper()); break; } case REACT_AGGRESSIVE: { if (!m_creature->getVictim() || !m_creature->getVictim()->isAlive()) AttackStart(owner->getAttackerForHelper()); break; } case REACT_PASSIVE: default: break; } } UpdateAIType(); if (m_creature->IsNonMeleeSpellCasted(true)) return; // Autocast (casted only in combat or persistent spells in any state) if (!sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType != PET_AI_PASSIVE) { typedef std::vector<std::pair<ObjectGuid, uint32> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; if (m_creature->HasSpellCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { // allow only spell without spell cost or with spell cost but not duration limit int32 duration = GetSpellDuration(spellInfo); if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } } else { // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } Unit* autoCastTarget = NULL; if (inCombat && m_creature->getVictim() && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { SpellCastResult result = CanAutoCast(m_creature->getVictim(), spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) autoCastTarget = m_creature->getVictim(); } if (!autoCastTarget) { for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* target = m_creature->GetMap()->GetUnit(*tar); // Only buff targets that are in combat, unless the spell can only be cast while out of combat if (!target) continue; SpellCastResult result = CanAutoCast(target, spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) { autoCastTarget = target; break; } } } if (autoCastTarget) targetSpellStore.push_back(TargetSpellList::value_type(autoCastTarget->GetObjectGuid(), spellInfo->Id)); } // found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); if (Unit* target = m_creature->GetMap()->GetUnit(targetSpellStore[index].first)) m_creature->DoPetCastSpell(target, targetSpellStore[index].second); } } else { AutoSpellList currentSpells; switch (m_AIType) { case PET_AI_PASSIVE: { currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_SLACKER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_DEFENCE)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_HEALER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); if (m_creature->GetHealth() < m_creature->GetMaxHealth() || (owner && (owner->GetHealth() < owner->GetMaxHealth()))) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_RANGED: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_MELEE: case PET_AI_RANGED_NOAMMO: { if (!IsInCombat()) break; if (Unit* victim = m_creature->getVictim()) { if (!victim->getVictim() || (victim->getVictim()->GetObjectGuid() != m_creature->GetObjectGuid())) { currentSpells.push_back(GetSpellType(PET_SPELL_ATTACKSTART)); currentSpells.push_back(GetSpellType(PET_SPELL_THREAT)); } } if (m_creature->IsCrowdControlled() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); } /* no break here!*/ default: { if (!IsInCombat()) break; currentSpells.push_back(GetSpellType(PET_SPELL_MELEE)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } } if (!IsInCombat()) { currentSpells.push_back(GetSpellType(PET_SPELL_NONCOMBAT)); if (m_creature->GetHealthPercent() < 95.0f) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); } else currentSpells.push_back(GetSpellType(PET_SPELL_SPECIAL)); for (AutoSpellList::const_iterator itr = currentSpells.begin(); itr != currentSpells.end(); ++itr) { uint32 spellID = *itr; if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; Unit* pTarget = m_creature->IsPet() ? ((Pet*)m_creature)->SelectPreferredTargetForSpell(spellInfo) : ((Creature*)m_creature)->SelectPreferredTargetForSpell(spellInfo); bool b_castOk = false; if (pTarget) { SpellCastResult result = CanAutoCast(pTarget, spellInfo); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update %s, AI %u try cast %u Target %s", m_creature->GetGuidStr().c_str(), m_AIType, spellID, pTarget ? pTarget->GetGuidStr().c_str() : "<none>"); switch (result) { case SPELL_FAILED_UNIT_NOT_INFRONT: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) { b_castOk = true; m_creature->SetInFront(pTarget); if (pTarget->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)pTarget); } break; } case SPELL_CAST_OK: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) b_castOk = true; break; } default: { Player* owner = (Player*)m_creature->GetOwner(); if (owner) Spell::SendCastResult(owner,spellInfo,0,result, true); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update cast %s, AI %u Target %s spell %u result %u", m_creature->GetGuidStr().c_str(), m_AIType, pTarget ? pTarget->GetGuidStr().c_str() : "<none>", spellID, result); break; } } } else continue; if (b_castOk) { m_creature->AddSpellAndCategoryCooldowns(spellInfo); if (m_creature->IsPet()) { if(((Pet*)m_creature)->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) m_creature->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else m_creature->SendPetAIReaction(); } break; } } } }
void NPCComponent::ExecuteAI(Instance *level, int deltaMillis) { if (!this->IsAlive()) { return; } if (this->IsInCombat()) { GameObject *target = this->GetTarget(); const glm::vec3 &myPosition = this->GetOwner()->GetPosition(); const glm::vec3 &targetPosition = target->GetPosition(); glm::vec3 direction = glm::normalize(targetPosition - myPosition); double distance = glm::distance(myPosition, targetPosition); auto model = this->GetOwner()->FindComponent<ModelComponent>(); if ((distance > 10 && mMoving) || (distance > 15 && !mMoving)) { float movementSpeed = (this->GetStats().GetStat(CharacterStatMovementSpeed) / 100.0f) * kBaseNpcRunSpeed; this->GetOwner()->MoveBy(direction * movementSpeed); mMoving = true; if (model) { model->SetAnimation("run"); } } else { mMoving = false; if (model) { model->SetAnimation("idle"); } } double angle = glm::degrees(atan2(direction.z, direction.x)) + 90; this->GetOwner()->RotateTo(glm::vec3(0, -angle, 0)); } else { std::vector<GameObject *> objects; level->FindObjectsWithinRadius(mAgroShape, objects); if (objects.size() > 0) { for (GameObject *object : objects) { if (object == this->GetOwner()) { continue; } auto character = object->FindComponent<CharacterComponent>(); if (character) { if (character->GetData()->GetHostility() == this->GetData()->GetHostility() && false) { // If these 2 objects are on the same side, and one is in combat, enter combat if (character->IsInCombat()) { this->SetInCombat(true, object); } } else { // If these 2 objects aren't on the same side, and we are hostile, enter combat if (this->GetData()->GetHostility() == HostilityHostile) { this->SetInCombat(true, object); } } } } } } }
void TemporarySummon::Update(uint32 update_diff, uint32 diff) { switch (m_type) { case TEMPSUMMON_MANUAL_DESPAWN: break; case TEMPSUMMON_TIMED_DESPAWN: { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSUMMON_TIMED_OOC_DESPAWN: { if (!IsInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSUMMON_CORPSE_TIMED_DESPAWN: { if (IsCorpse()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSUMMON_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } break; } case TEMPSUMMON_DEAD_DESPAWN: { if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } if (!IsInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } else m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (!IsInCombat() && IsAlive()) { if (m_timer <= update_diff) { UnSummon(); return; } else m_timer -= update_diff; } else if (m_timer != m_lifetime) m_timer = m_lifetime; break; } case TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSUMMON_TIMED_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } default: UnSummon(); sLog.outError("Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type); break; } switch (m_deathState) { case ALIVE: if (m_linkedToOwnerAura & TEMPSUMMON_LINKED_AURA_OWNER_CHECK) { // we have to check if owner still have the required aura Unit* owner = GetCharmerOrOwner(); uint32 const& spellId = GetUInt32Value(UNIT_CREATED_BY_SPELL); if (!owner || !spellId || !owner->HasAura(spellId)) UnSummon(); } break; case DEAD: case CORPSE: if (m_linkedToOwnerAura & TEMPSUMMON_LINKED_AURA_REMOVE_OWNER) { RemoveAuraFromOwner(); m_linkedToOwnerAura = 0; // we dont need to recheck } default: break; } Creature::Update(update_diff, diff); }
void AIUpdate() { if ( _unit->CalcDistance(BoomTarget) < 5 && IsInCombat()) _unit->CastSpell(_unit, dbcSpell.LookupEntry(SPELL_FELFIRE_FISSION), true); ParentClass::AIUpdate(); }
void TemporarySummon::Update(uint32 update_diff, uint32 diff) { switch (m_type) { case TEMPSUMMON_MANUAL_DESPAWN: break; case TEMPSUMMON_TIMED_DESPAWN: { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSUMMON_TIMED_OOC_DESPAWN: { if (!IsInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } else if (m_timer != m_lifetime) { m_timer = m_lifetime; } break; } case TEMPSUMMON_CORPSE_TIMED_DESPAWN: { if (IsCorpse()) { if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; } if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSUMMON_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } break; } case TEMPSUMMON_DEAD_DESPAWN: { if (IsDespawned()) { UnSummon(); return; } break; } case TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } if (!IsInCombat()) { if (m_timer <= update_diff) { UnSummon(); return; } else { m_timer -= update_diff; } } else if (m_timer != m_lifetime) { m_timer = m_lifetime; } break; } case TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (!IsInCombat() && IsAlive()) { if (m_timer <= update_diff) { UnSummon(); return; } else { m_timer -= update_diff; } } else if (m_timer != m_lifetime) { m_timer = m_lifetime; } break; } case TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDead()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } case TEMPSUMMON_TIMED_OR_DEAD_DESPAWN: { // if m_deathState is DEAD, CORPSE was skipped if (IsDespawned()) { UnSummon(); return; } if (m_timer <= update_diff) { UnSummon(); return; } m_timer -= update_diff; break; } default: UnSummon(); sLog.outError("Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type); break; } Creature::Update(update_diff, diff); }