void Creature::OnRemoveCorpse() { // time to respawn! if (IsInWorld() && (int32)m_mapMgr->GetInstanceID() == m_instanceId) { sLog.outDetail("Removing corpse of "I64FMT"...", GetGUID()); if((GetMapMgr()->GetMapInfo() && GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID && this->proto && this->proto->boss) || m_noRespawn) { RemoveFromWorld(false, true); } else { if(proto && proto->RespawnTime) RemoveFromWorld(true, false); else RemoveFromWorld(false, true); } setDeathState(DEAD); m_position = m_spawnLocation; } else { // if we got here it's pretty bad } }
void Creature::AIM_Update(const uint32 &diff) { switch( m_deathState ) { case JUST_DIED: { SetUInt32Value(UNIT_NPC_FLAGS, 0); m_deathState = CORPSE; i_AI->UpdateAI(diff); break; } case DEAD: { if( m_respawnTimer <= diff ) { DEBUG_LOG("Respawning..."); SetUInt32Value(UNIT_FIELD_HEALTH, GetUInt32Value(UNIT_FIELD_MAXHEALTH)); m_deathState = ALIVE; ClearState(ALL_STATE); i_motionMaster.Clear(); MapManager::Instance().GetMap(GetMapId())->Add(this); } else m_respawnTimer -= diff; break; } case CORPSE: { if( m_deathTimer <= diff ) { DEBUG_LOG("Removing corpse..."); ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(this); setDeathState(DEAD); m_respawnTimer = m_respawnDelay; GetRespawnCoord(m_positionX, m_positionY, m_positionZ); } else m_deathTimer -= diff; break; } case ALIVE: { Unit::Update( diff ); i_AI->UpdateAI(diff); i_motionMaster.UpdateMotion(diff); break; } default: break; } }
void Totem::UnSummon(uint32 msTime) { if (msTime) { m_Events.AddEvent(new ForcedUnsummonDelayEvent(*this), m_Events.CalculateTime(msTime)); return; } CombatStop(); RemoveAurasDueToSpell(GetSpell(), GetGUID()); // clear owner's totem slot for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) { if (GetOwner()->m_SummonSlot[i] == GetGUID()) { GetOwner()->m_SummonSlot[i].Clear(); break; } } GetOwner()->RemoveAurasDueToSpell(GetSpell(), GetGUID()); // Remove Sentry Totem Aura if (GetEntry() == SENTRY_TOTEM_ENTRY) GetOwner()->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID); //remove aura all party members too if (Player* owner = GetOwner()->ToPlayer()) { owner->SendAutoRepeatCancel(this); if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL))) GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false); if (Group* group = owner->GetGroup()) { for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* target = itr->GetSource(); if (target && group->SameSubGroup(owner, target)) target->RemoveAurasDueToSpell(GetSpell(), GetGUID()); } } } // any totem unsummon look like as totem kill, req. for proper animation if (IsAlive()) setDeathState(DEAD); AddObjectToRemoveList(); }
void Totem::UnSummon() { SendObjectDeSpawnAnim(GetGUID()); CombatStop(); RemoveAurasDueToSpell(GetSpell()); // clear owner's totem slot for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) { if (m_owner->m_SummonSlot[i] == GetGUID()) { m_owner->m_SummonSlot[i] = 0; break; } } m_owner->RemoveAurasDueToSpell(GetSpell()); //remove aura all party members too Group* pGroup = NULL; if (m_owner->GetTypeId() == TYPEID_PLAYER) { // Not only the player can summon the totem (scripted AI) pGroup = m_owner->ToPlayer()->GetGroup(); if (pGroup) { for (GroupReference* itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* Target = itr->GetSource(); if (Target && pGroup->SameSubGroup(m_owner->ToPlayer(), Target)) Target->RemoveAurasDueToSpell(GetSpell()); } } } // any totem unsummon look like as totem kill, req. for proper animation if (IsAlive()) setDeathState(DEAD); AddObjectToRemoveList(); }
void Creature::OnRespawn(MapMgr * m) { sLog.outDetail("Respawning "I64FMT"...", GetGUID()); SetUInt32Value(UNIT_FIELD_HEALTH, GetUInt32Value(UNIT_FIELD_MAXHEALTH)); SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); // not tagging shiat if(proto && m_spawn) { SetUInt32Value(UNIT_NPC_FLAGS, proto->NPCFLags); SetUInt32Value(UNIT_NPC_EMOTESTATE, m_spawn->emote_state); } RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); Skinned = false; Tagged = false; TaggerGuid = 0; m_lootMethod = -1; /* creature death state */ if(proto && proto->death_state == 1) { uint32 newhealth = m_uint32Values[UNIT_FIELD_HEALTH] / 100; if(!newhealth) newhealth = 1; SetUInt32Value(UNIT_FIELD_HEALTH, 1); m_limbostate = true; bInvincible = true; SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DEAD); } //empty loot loot.items.clear(); setDeathState(ALIVE); GetAIInterface()->StopMovement(0); // after respawn monster can move m_PickPocketed = false; PushToWorld(m); }
bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool current) { m_loading = true; uint32 ownerid = owner->GetGUIDLow(); QueryResult result; if (petnumber) // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND id = '%u'", ownerid, petnumber); else if (current) // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND slot = '%u'", ownerid, PET_SAVE_AS_CURRENT); else if (petentry) // known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets) // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid, petentry, PET_SAVE_AS_CURRENT, PET_SAVE_LAST_STABLE_SLOT); else // any current or other non-stabled pet (for hunter "call pet") // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid, PET_SAVE_AS_CURRENT, PET_SAVE_LAST_STABLE_SLOT); if (!result) { m_loading = false; return false; } Field* fields = result->Fetch(); // update for case of current pet "slot = 0" petentry = fields[1].GetUInt32(); if (!petentry) return false; uint32 summon_spell_id = fields[15].GetUInt32(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0; // check temporary summoned pets like mage water elemental if (current && is_temporary_summoned) return false; PetType pet_type = PetType(fields[16].GetUInt8()); if (pet_type == HUNTER_PET) { CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petentry); if (!creatureInfo || !creatureInfo->isTameable(owner->CanTameExoticPets())) return false; } uint32 pet_number = fields[0].GetUInt32(); if (current && owner->IsPetNeedBeTemporaryUnsummoned()) { owner->SetTemporaryUnsummonedPetNumber(pet_number); return false; } Map* map = owner->GetMap(); uint32 guid = sObjectMgr->GenerateLowGuid(HIGHGUID_PET); if (!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number)) return false; float px, py, pz; owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle()); Relocate(px, py, pz, owner->GetOrientation()); if (!IsPositionValid()) { sLog->outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", GetGUIDLow(), GetEntry(), GetPositionX(), GetPositionY()); return false; } setPetType(pet_type); setFaction(owner->getFaction()); SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); CreatureTemplate const* cinfo = GetCreatureInfo(); if (cinfo->type == CREATURE_TYPE_CRITTER) { map->AddToMap(this->ToCreature()); return true; } m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner)); SetDisplayId(fields[3].GetUInt32()); SetNativeDisplayId(fields[3].GetUInt32()); uint32 petlevel = fields[4].GetUInt16(); SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); SetName(fields[8].GetString()); switch (getPetType()) { case SUMMON_PET: petlevel = owner->getLevel(); SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet dismiss, cancel) break; case HUNTER_PET: SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus SetSheath(SHEATH_STATE_MELEE); SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); setPowerType(POWER_FOCUS); break; default: if (!IsPetGhoul()) sLog->outError("Pet have incorrect type (%u) for pet loading.", getPetType()); break; } SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped here SetCreatorGUID(owner->GetGUID()); InitStatsForLevel(petlevel); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); SynchronizeLevelWithOwner(); SetReactState(ReactStates(fields[6].GetUInt8())); SetCanModifyStats(true); if (getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); else { uint32 savedhealth = fields[10].GetUInt32(); uint32 savedmana = fields[11].GetUInt32(); if (!savedhealth && getPetType() == HUNTER_PET) setDeathState(JUST_DIED); else { SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth); SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana); } } // set current pet as current // 0=current // 1..MAX_PET_STABLES in stable slot // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning)) if (fields[7].GetUInt8()) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u' AND id <> '%u'", PET_SAVE_NOT_IN_SLOT, ownerid, PET_SAVE_AS_CURRENT, m_charmInfo->GetPetNumber()); trans->PAppend("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND id = '%u'", PET_SAVE_AS_CURRENT, ownerid, m_charmInfo->GetPetNumber()); CharacterDatabase.CommitTransaction(trans); } // Send fake summon spell cast - this is needed for correct cooldown application for spells // Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside // TODO: pets should be summoned from real cast instead of just faking it? if (summon_spell_id) { WorldPacket data(SMSG_SPELL_GO, (8+8+4+4+2)); data.append(owner->GetPackGUID()); data.append(owner->GetPackGUID()); data << uint8(0); data << uint32(summon_spell_id); data << uint32(256); // CAST_FLAG_UNKNOWN3 data << uint32(0); owner->SendMessageToSet(&data, true); } owner->SetMinion(this, true); map->AddToMap(this->ToCreature()); InitTalentForLevel(); // set original talents points before spell loading uint32 timediff = uint32(time(NULL) - fields[14].GetUInt32()); _LoadAuras(timediff); // load action bar, if data broken will fill later by default spells. if (!is_temporary_summoned) { m_charmInfo->LoadPetActionBar(fields[13].GetString()); _LoadSpells(); InitTalentForLevel(); // re-init to check talent count _LoadSpellCooldowns(); LearnPetPassives(); InitLevelupSpellsForLevel(); CastPetAuras(current); } CleanupActionBar(); // remove unknown spells from action bar after load sLog->outDebug(LOG_FILTER_PETS, "New Pet has guid %u", GetGUIDLow()); owner->PetSpellInitialize(); if (owner->GetGroup()) owner->SetGroupUpdateFlag(GROUP_UPDATE_PET); owner->SendTalentsInfoData(true); if (getPetType() == HUNTER_PET) { result = CharacterDatabase.PQuery("SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", owner->GetGUIDLow(), GetCharmInfo()->GetPetNumber()); if (result) { delete m_declinedname; m_declinedname = new DeclinedName; Field* fields2 = result->Fetch(); for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) { m_declinedname->name[i] = fields2[i].GetString(); } } } //set last used pet number (for use in BG's) if (owner->GetTypeId() == TYPEID_PLAYER && isControlled() && !isTemporarySummoned() && (getPetType() == SUMMON_PET || getPetType() == HUNTER_PET)) owner->ToPlayer()->SetLastPetNumber(pet_number); m_loading = false; return true; }
void Creature::Update(uint32 diff) { switch( m_deathState ) { case JUST_DIED: // Dont must be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting. sLog.outError("Creature (GUIDLow: %u Entry: %u ) in wrong state: JUST_DEAD (1)",GetGUIDLow(),GetEntry()); break; case DEAD: { if( m_respawnTime <= time(NULL) ) { DEBUG_LOG("Respawning..."); m_respawnTime = 0; CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(this->GetEntry()); SelectLevel(cinfo); SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); SetHealth(GetMaxHealth()); setDeathState( ALIVE ); clearUnitState(UNIT_STAT_ALL_STATE); i_motionMaster.Clear(); MapManager::Instance().GetMap(GetMapId(), this)->Add(this); } break; } case CORPSE: { if( m_deathTimer <= diff ) { m_deathTimer = 0; DEBUG_LOG("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(this); lootForPickPocketed = false; lootForBody = false; loot.clear(); setDeathState(DEAD); m_respawnTime = time(NULL) + m_respawnDelay; float x,y,z; GetRespawnCoord(x, y, z); MapManager::Instance().GetMap(GetMapId(), this)->CreatureRelocation(this,x,y,z,GetOrientation()); } else { m_deathTimer -= diff; if (m_groupLootTimer && lootingGroupLeaderGUID) { if(diff <= m_groupLootTimer) { m_groupLootTimer -= diff; } else { Group* group = objmgr.GetGroupByLeader(lootingGroupLeaderGUID); if (group) group->EndRoll(); m_groupLootTimer = 0; lootingGroupLeaderGUID = 0; } } } break; } case ALIVE: { Unit::Update( diff ); i_motionMaster.UpdateMotion(diff); i_AI->UpdateAI(diff); if(m_regenTimer > 0) { if(diff >= m_regenTimer) m_regenTimer = 0; else m_regenTimer -= diff; } if (m_regenTimer != 0) break; if (!isInCombat()) { RegenerateHealth(); RegenerateMana(); } m_regenTimer = 2000; break; } default: break; } }
void Creature::OnRespawn(MapMgr * m) { if(m_noRespawn) return; InstanceBossInfoMap *bossInfoMap = objmgr.m_InstanceBossInfoMap[m->GetMapId()]; if(bossInfoMap != NULL) { bool skip = false; Instance *pInstance = m->pInstance; for(std::set<uint32>::iterator killedNpc = pInstance->m_killedNpcs.begin(); killedNpc != pInstance->m_killedNpcs.end(); ++killedNpc) { // Is killed boss? if((*killedNpc) == this->creature_info->Id) { skip = true; break; } // Is add from killed boss? InstanceBossInfoMap::const_iterator bossInfo = bossInfoMap->find((*killedNpc)); if(bossInfo != bossInfoMap->end() && bossInfo->second->trash.find(this->spawnid) != bossInfo->second->trash.end()) { skip = true; break; } } if(skip) { this->m_noRespawn = true; this->DeleteMe(); return; } } sLog.outDetail("Respawning "I64FMT"...", GetGUID()); SetUInt32Value(UNIT_FIELD_HEALTH, GetUInt32Value(UNIT_FIELD_MAXHEALTH)); SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); // not tagging shiat if(proto && m_spawn) { SetUInt32Value(UNIT_NPC_FLAGS, proto->NPCFLags); SetUInt32Value(UNIT_NPC_EMOTESTATE, m_spawn->emote_state); } RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); Skinned = false; Tagged = false; TaggerGuid = 0; m_lootMethod = -1; /* creature death state */ if(proto && proto->death_state == 1) { uint32 newhealth = m_uint32Values[UNIT_FIELD_HEALTH] / 100; if(!newhealth) newhealth = 1; SetUInt32Value(UNIT_FIELD_HEALTH, 1); m_limbostate = true; bInvincible = true; SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DEAD); SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, 35); } //empty loot loot.items.clear(); setDeathState(ALIVE); GetAIInterface()->StopMovement(0); // after respawn monster can move GetAIInterface()->m_canMove = true; m_PickPocketed = false; PushToWorld(m); }