void PlayerbotWarlockAI::CheckDemon() { uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); Pet *pet = m_bot->GetPet(); //Assign demon of choice if (spec == WARLOCK_SPEC_AFFLICTION) m_demonOfChoice = DEMON_FELHUNTER; else if (spec == WARLOCK_SPEC_DEMONOLOGY) m_demonOfChoice = (DEMON_FELGUARD > 0 ? DEMON_FELGUARD : DEMON_SUCCUBUS); else if (spec == WARLOCK_SPEC_DESTRUCTION) m_demonOfChoice = DEMON_IMP; // Summon demon if (!pet || m_isTempImp || pet->GetEntry() != m_demonOfChoice) { uint32 summonSpellId; if (m_demonOfChoice != DEMON_IMP && shardCount > 0) { switch (m_demonOfChoice) { case DEMON_VOIDWALKER: summonSpellId = SUMMON_VOIDWALKER; break; case DEMON_FELGUARD: summonSpellId = SUMMON_FELGUARD; break; case DEMON_FELHUNTER: summonSpellId = SUMMON_FELHUNTER; break; case DEMON_SUCCUBUS: summonSpellId = SUMMON_SUCCUBUS; break; default: summonSpellId = 0; } if (m_ai->CastSpell(summonSpellId)) { //m_ai->TellMaster("Summoning favorite demon..."); m_isTempImp = false; return; } } else if (!pet && SUMMON_IMP && m_ai->CastSpell(SUMMON_IMP)) { if (m_demonOfChoice != DEMON_IMP) m_isTempImp = true; //m_ai->TellMaster("Summoning Imp..."); return; } } }
void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid) { if (!GetPlayer()) return; TC_LOG_DEBUG("network", "WORLD: Recv MSG_LIST_STABLED_PETS Send."); WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size data << uint64 (guid); Pet* pet = _player->GetPet(); size_t wpos = data.wpos(); data << uint8(0); // place holder for slot show number data << uint8(GetPlayer()->m_stableSlots); uint8 num = 0; // counter for place holder // not let move dead pet in slot if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET) { data << uint32(num); // 4.x unknown, some kind of order? data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); data << pet->GetName(); // petname data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) ++num; } if (result) { do { Field* fields = result->Fetch(); data << uint32(num); data << uint32(fields[1].GetUInt32()); // petnumber data << uint32(fields[2].GetUInt32()); // creature entry data << uint32(fields[3].GetUInt16()); // level data << fields[4].GetString(); // name data << uint8(2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) ++num; } while (result->NextRow()); } data.put<uint8>(wpos, num); // set real data to placeholder SendPacket(&data); SendStableResult(STABLE_ERR_NONE); }
void WorldSession::SendStablePetCallback(QueryResult result, uint64 guid) { if (!GetPlayer()) return; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv MSG_LIST_STABLED_PETS Send."); WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size data << uint64 (guid); Pet* pet = _player->GetPet(); size_t wpos = data.wpos(); data << uint8(0); // place holder for slot show number data << uint8(GetPlayer()->_petSlotUsed); uint8 num = 0; // counter for place holder // not let move dead pet in slot if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) { data << uint32(_player->_currentPetSlot); data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); data << pet->GetName(); // petname data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) ++num; } if (result) { do { Field *fields = result->Fetch(); data << uint32(fields[1].GetUInt32()); // slot data << uint32(fields[2].GetUInt32()); // petnumber data << uint32(fields[3].GetUInt32()); // creature entry data << uint32(fields[4].GetUInt16()); // level data << fields[5].GetString(); // name data << uint8(fields[1].GetUInt32() <= PET_SLOT_STABLE_FIRST ? 1 : 2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) ++num; } while (result->NextRow()); } data.put<uint8>(wpos, num); // set real data to placeholder SendPacket(&data); }
void WorldSession::SendStablePet(uint64 guid ) { sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size data << uint64 ( guid ); Pet *pet = _player->GetPet(); size_t wpos = data.wpos(); data << uint8(0); // place holder for slot show number data << uint8(GetPlayer()->m_stableSlots); uint8 num = 0; // counter for place holder // not let move dead pet in slot if(pet && pet->isAlive() && pet->getPetType()==HUNTER_PET) { data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); data << pet->GetName(); // petname data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) ++num; } // 0 1 2 3 4 QueryResult* result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot", _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); if(result) { do { Field *fields = result->Fetch(); data << uint32(fields[1].GetUInt32()); // petnumber data << uint32(fields[2].GetUInt32()); // creature entry data << uint32(fields[3].GetUInt32()); // level data << fields[4].GetString(); // name data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) ++num; }while( result->NextRow() ); delete result; } data.put<uint8>(wpos, num); // set real data to placeholder SendPacket(&data); }
void WorldSession::SendStablePetCallback(ObjectGuid guid, PreparedQueryResult result) { if (!GetPlayer()) return; WorldPackets::Pet::PetStableList packet; packet.StableMaster = guid; Pet* pet = _player->GetPet(); int32 petSlot = 0; // not let move dead pet in slot if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET) { WorldPackets::Pet::PetStableInfo stableEntry; stableEntry.PetSlot = petSlot; stableEntry.PetNumber = pet->GetCharmInfo()->GetPetNumber(); stableEntry.CreatureID = pet->GetEntry(); stableEntry.DisplayID = pet->GetDisplayId(); stableEntry.ExperienceLevel = pet->getLevel(); stableEntry.PetFlags = PET_STABLE_ACTIVE; stableEntry.PetName = pet->GetName(); ++petSlot; packet.Pets.push_back(stableEntry); } if (result) { do { Field* fields = result->Fetch(); WorldPackets::Pet::PetStableInfo stableEntry; stableEntry.PetSlot = petSlot; stableEntry.PetNumber = fields[1].GetUInt32(); // petnumber stableEntry.CreatureID = fields[2].GetUInt32(); // creature entry stableEntry.DisplayID = fields[5].GetUInt32(); // creature displayid stableEntry.ExperienceLevel = fields[3].GetUInt16(); // level stableEntry.PetFlags = PET_STABLE_INACTIVE; stableEntry.PetName = fields[4].GetString(); // Name ++petSlot; packet.Pets.push_back(stableEntry); } while (result->NextRow()); } SendPacket(packet.Write()); }
void WorldSession::SendStablePet(uint64 guid) { sLog->outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size data << uint64 (guid); Pet *pet = _player->GetPet(); data << uint8(0); // place holder for slot show number data << uint8(GetPlayer()->m_stableSlots); uint8 num = 0; // counter for place holder // not let move dead pet in slot if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) { data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); data << pet->GetName(); // petname data << uint32(pet->GetLoyaltyLevel()); // loyalty data << uint8(0x01); // client slot 1 == current pet (0) ++num; } // 0 1 2 3 4 5 6 QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, loyalty, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 3", _player->GetGUIDLow()); if (result) { do { Field *fields = result->Fetch(); data << uint32(fields[2].GetUInt32()); // petnumber data << uint32(fields[3].GetUInt32()); // creature entry data << uint32(fields[4].GetUInt32()); // level data << fields[6].GetString(); // name data << uint32(fields[5].GetUInt32()); // loyalty data << uint8(fields[1].GetUInt32()+1); // slot ++num; }while (result->NextRow()); } data.put<uint8>(8, num); // set real data to placeholder SendPacket(&data); }
void PlayerbotWarlockAI::DoNextCombatManeuver(Unit *pTarget) { PlayerbotAI* ai = GetAI(); if (!ai) return; switch (ai->GetScenarioType()) { case PlayerbotAI::SCENARIO_DUEL: { if (SHADOW_BOLT > 0) ai->CastSpell(SHADOW_BOLT); return; } default: break; } // ------- Non Duel combat ---------- //ai->SetMovementOrder( PlayerbotAI::MOVEMENT_FOLLOW, GetMaster() ); // dont want to melee mob ai->SetInFront(pTarget); Player *m_bot = GetPlayerBot(); Unit* pVictim = pTarget->getVictim(); Pet *pet = m_bot->GetPet(); // Empower demon if (pet && DEMONIC_EMPOWERMENT && !m_bot->HasSpellCooldown(DEMONIC_EMPOWERMENT)) ai->CastSpell(DEMONIC_EMPOWERMENT); // Use voidwalker sacrifice on low health if possible if (ai->GetHealthPercent() < 50) if (pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE)) ai->CastPetSpell(SACRIFICE); // Use healthstone if (ai->GetHealthPercent() < 30) { Item* healthStone = ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (healthStone) ai->UseItem(healthStone); } // Damage Spells switch (SpellSequence) { case SPELL_CURSES: if (CURSE_OF_AGONY && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(SHADOWFLAME) && LastSpellCurse < 1) { ai->CastSpell(CURSE_OF_AGONY, *pTarget); SpellSequence = SPELL_AFFLICTION; ++LastSpellCurse; break; } else if (CURSE_OF_THE_ELEMENTS && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && LastSpellCurse < 2) { ai->CastSpell(CURSE_OF_THE_ELEMENTS, *pTarget); SpellSequence = SPELL_AFFLICTION; ++LastSpellCurse; break; } else if (CURSE_OF_WEAKNESS && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 3) { ai->CastSpell(CURSE_OF_WEAKNESS, *pTarget); SpellSequence = SPELL_AFFLICTION; ++LastSpellCurse; break; } else if (CURSE_OF_TONGUES && !pTarget->HasAura(CURSE_OF_TONGUES) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 4) { ai->CastSpell(CURSE_OF_TONGUES, *pTarget); SpellSequence = SPELL_AFFLICTION; ++LastSpellCurse; break; } LastSpellCurse = 0; //SpellSequence = SPELL_AFFLICTION; //break; case SPELL_AFFLICTION: if (LIFE_TAP && LastSpellAffliction < 1 && ai->GetManaPercent() <= 50 && ai->GetHealthPercent() > 50) { ai->CastSpell(LIFE_TAP, *m_bot); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (CORRUPTION && !pTarget->HasAura(CORRUPTION) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(SEED_OF_CORRUPTION) && LastSpellAffliction < 2) { ai->CastSpell(CORRUPTION, *pTarget); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (DRAIN_SOUL && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.40 && !pTarget->HasAura(DRAIN_SOUL) && LastSpellAffliction < 3) { ai->CastSpell(DRAIN_SOUL, *pTarget); //ai->SetIgnoreUpdateTime(15); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (DRAIN_LIFE && LastSpellAffliction < 4 && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(SEED_OF_CORRUPTION) && !pTarget->HasAura(DRAIN_LIFE) && !pTarget->HasAura(DRAIN_MANA) && ai->GetHealthPercent() <= 70) { ai->CastSpell(DRAIN_LIFE, *pTarget); //ai->SetIgnoreUpdateTime(5); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (UNSTABLE_AFFLICTION && LastSpellAffliction < 5 && !pTarget->HasAura(UNSTABLE_AFFLICTION) && !pTarget->HasAura(SHADOWFLAME)) { ai->CastSpell(UNSTABLE_AFFLICTION, *pTarget); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (HAUNT && LastSpellAffliction < 6 && !pTarget->HasAura(HAUNT)) { ai->CastSpell(HAUNT, *pTarget); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (SEED_OF_CORRUPTION && !pTarget->HasAura(SEED_OF_CORRUPTION) && LastSpellAffliction < 7) { ai->CastSpell(SEED_OF_CORRUPTION, *pTarget); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (HOWL_OF_TERROR && !pTarget->HasAura(HOWL_OF_TERROR) && ai->GetAttackerCount() > 3 && LastSpellAffliction < 8) { ai->CastSpell(HOWL_OF_TERROR, *pTarget); ai->TellMaster("casting howl of terror!"); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if (FEAR && !pTarget->HasAura(FEAR) && pVictim == m_bot && ai->GetAttackerCount() >= 2 && LastSpellAffliction < 9) { ai->CastSpell(FEAR, *pTarget); //ai->TellMaster("casting fear!"); //ai->SetIgnoreUpdateTime(1.5); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } else if ((pet) && (DARK_PACT > 0 && ai->GetManaPercent() <= 50 && LastSpellAffliction < 10 && pet->GetPower(POWER_MANA) > 0)) { ai->CastSpell(DARK_PACT, *m_bot); SpellSequence = SPELL_DESTRUCTION; ++LastSpellAffliction; break; } LastSpellAffliction = 0; //SpellSequence = SPELL_DESTRUCTION; //break; case SPELL_DESTRUCTION: if (SHADOWFURY && LastSpellDestruction < 1 && !pTarget->HasAura(SHADOWFURY)) { ai->CastSpell(SHADOWFURY, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (SHADOW_BOLT && LastSpellDestruction < 2) { ai->CastSpell(SHADOW_BOLT, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (RAIN_OF_FIRE && LastSpellDestruction < 3 && ai->GetAttackerCount() >= 3) { ai->CastSpell(RAIN_OF_FIRE, *pTarget); //ai->TellMaster("casting rain of fire!"); //ai->SetIgnoreUpdateTime(8); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (SHADOWFLAME && !pTarget->HasAura(SHADOWFLAME) && LastSpellDestruction < 4) { ai->CastSpell(SHADOWFLAME, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (IMMOLATE && !pTarget->HasAura(IMMOLATE) && !pTarget->HasAura(SHADOWFLAME) && LastSpellDestruction < 5) { ai->CastSpell(IMMOLATE, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (CONFLAGRATE && LastSpellDestruction < 6) { ai->CastSpell(CONFLAGRATE, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (INCINERATE && LastSpellDestruction < 7) { ai->CastSpell(INCINERATE, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (SEARING_PAIN && LastSpellDestruction < 8) { ai->CastSpell(SEARING_PAIN, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (SOUL_FIRE && LastSpellDestruction < 9) { ai->CastSpell(SOUL_FIRE, *pTarget); //ai->SetIgnoreUpdateTime(6); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (CHAOS_BOLT && LastSpellDestruction < 10) { ai->CastSpell(CHAOS_BOLT, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (SHADOWBURN && LastSpellDestruction < 11 && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.20 && !pTarget->HasAura(SHADOWBURN)) { ai->CastSpell(SHADOWBURN, *pTarget); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else if (HELLFIRE && LastSpellDestruction < 12 && !m_bot->HasAura(HELLFIRE) && ai->GetAttackerCount() >= 5 && ai->GetHealthPercent() >= 50) { ai->CastSpell(HELLFIRE); ai->TellMaster("casting hellfire!"); //ai->SetIgnoreUpdateTime(15); SpellSequence = SPELL_CURSES; ++LastSpellDestruction; break; } else { LastSpellDestruction = 0; SpellSequence = SPELL_CURSES; } } } // end DoNextCombatManeuver
void PlayerbotWarlockAI::DoNonCombatActions() { SpellSequence = SPELL_CURSES; PlayerbotAI *ai = GetAI(); Player * m_bot = GetPlayerBot(); if (!ai || !m_bot) return; Pet *pet = m_bot->GetPet(); // Initialize pet spells if (pet && pet->GetEntry() != m_lastDemon) { switch (pet->GetEntry()) { case DEMON_IMP: { BLOOD_PACT = ai->initPetSpell(BLOOD_PACT_ICON); FIREBOLT = ai->initPetSpell(FIREBOLT_ICON); FIRE_SHIELD = ai->initPetSpell(FIRE_SHIELD_ICON); break; } case DEMON_VOIDWALKER: { CONSUME_SHADOWS = ai->initPetSpell(CONSUME_SHADOWS_ICON); SACRIFICE = ai->initPetSpell(SACRIFICE_ICON); SUFFERING = ai->initPetSpell(SUFFERING_ICON); TORMENT = ai->initPetSpell(TORMENT_ICON); break; } case DEMON_SUCCUBUS: { LASH_OF_PAIN = ai->initPetSpell(LASH_OF_PAIN_ICON); SEDUCTION = ai->initPetSpell(SEDUCTION_ICON); SOOTHING_KISS = ai->initPetSpell(SOOTHING_KISS_ICON); break; } case DEMON_FELHUNTER: { DEVOUR_MAGIC = ai->initPetSpell(DEVOUR_MAGIC_ICON); FEL_INTELLIGENCE = ai->initPetSpell(FEL_INTELLIGENCE_ICON); SHADOW_BITE = ai->initPetSpell(SHADOW_BITE_ICON); SPELL_LOCK = ai->initPetSpell(SPELL_LOCK_ICON); break; } case DEMON_FELGUARD: { ANGUISH = ai->initPetSpell(ANGUISH_ICON); CLEAVE = ai->initPetSpell(CLEAVE_ICON); INTERCEPT = ai->initPetSpell(INTERCEPT_ICON); break; } } m_lastDemon = pet->GetEntry(); if (!m_isTempImp) m_demonOfChoice = pet->GetEntry(); } // Destroy extra soul shards uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, NULL); uint8 freeSpace = ai->GetFreeBagSpace(); if (shardCount > MAX_SHARD_COUNT || (freeSpace == 0 && shardCount > 1)) m_bot->DestroyItemCount(SOUL_SHARD, shardCount > MAX_SHARD_COUNT ? shardCount - MAX_SHARD_COUNT : 1, true, false); // buff myself DEMON_SKIN, DEMON_ARMOR, FEL_ARMOR if (FEL_ARMOR) { if (ai->SelfBuff(FEL_ARMOR)) return; } else if (DEMON_ARMOR) { if (ai->SelfBuff(DEMON_ARMOR)) return; } else if (DEMON_SKIN) if (ai->SelfBuff(DEMON_SKIN)) return; // healthstone creation if (CREATE_HEALTHSTONE && shardCount > 0) { Item* const healthStone = ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (!healthStone && ai->CastSpell(CREATE_HEALTHSTONE)) return; } // soulstone creation and use if (CREATE_SOULSTONE) { Item* soulStone = ai->FindConsumable(SOULSTONE_DISPLAYID); if (!soulStone) { if (shardCount > 0 && !m_bot->HasSpellCooldown(CREATE_SOULSTONE) && ai->CastSpell(CREATE_SOULSTONE)) return; } else { uint32 soulStoneSpell = soulStone->GetProto()->Spells[0].SpellId; Player * master = GetMaster(); if (!master->HasAura(soulStoneSpell) && !m_bot->HasSpellCooldown(soulStoneSpell)) { ai->UseItem(soulStone, master); return; } } } // firestone creation and use Item* const weapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); if (weapon && weapon->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) == 0) { Item* const stone = ai->FindConsumable(FIRESTONE_DISPLAYID); if (!stone) { if (CREATE_FIRESTONE && shardCount > 0 && ai->CastSpell(CREATE_FIRESTONE)) return; } else { ai->UseItem(stone, EQUIPMENT_SLOT_MAINHAND); return; } } if (m_bot->getStandState() != UNIT_STAND_STATE_STAND) m_bot->SetStandState(UNIT_STAND_STATE_STAND); // mana check if (pet && DARK_PACT && pet->GetPower(POWER_MANA) > 0 && ai->GetManaPercent() <= 50) if (ai->CastSpell(DARK_PACT, *m_bot)) return; if (LIFE_TAP && ai->GetManaPercent() <= 50 && ai->GetHealthPercent() > 50) if (ai->CastSpell(LIFE_TAP, *m_bot)) return; if (ai->GetManaPercent() < 25) { Item* pItem = ai->FindDrink(); if (pItem) { ai->TellMaster("I could use a drink."); ai->UseItem(pItem); return; } } // hp check if (ai->GetHealthPercent() < 30) { Item* pItem = ai->FindFood(); if (pItem) { ai->TellMaster("I could use some food."); ai->UseItem(pItem); return; } } if (ai->GetHealthPercent() < 50 && !m_bot->HasAura(RECENTLY_BANDAGED)) { Item* fItem = ai->FindBandage(); if (fItem) { ai->TellMaster("I could use first aid."); ai->UseItem(fItem); return; } } //Heal Voidwalker if (pet && pet->GetEntry() == DEMON_VOIDWALKER && CONSUME_SHADOWS && pet->GetHealthPercent() < 75 && !pet->HasAura(CONSUME_SHADOWS)) ai->CastPetSpell(CONSUME_SHADOWS); // Summon demon if (!pet || m_isTempImp) { uint32 summonSpellId; if (m_demonOfChoice != DEMON_IMP && shardCount > 0) { switch (m_demonOfChoice) { case DEMON_VOIDWALKER: summonSpellId = SUMMON_VOIDWALKER; break; case DEMON_FELGUARD: summonSpellId = SUMMON_FELGUARD; break; case DEMON_FELHUNTER: summonSpellId = SUMMON_FELHUNTER; break; case DEMON_SUCCUBUS: summonSpellId = SUMMON_SUCCUBUS; break; default: summonSpellId = 0; } if (ai->CastSpell(summonSpellId)) { ai->TellMaster("Summoning favorite demon..."); m_isTempImp = false; return; } } else if (!pet && SUMMON_IMP && ai->CastSpell(SUMMON_IMP)) { if (m_demonOfChoice != DEMON_IMP) m_isTempImp = true; ai->TellMaster("Summoning Imp..."); return; } } // Soul link demon if (pet && SOUL_LINK && !m_bot->HasAura(SOUL_LINK_AURA) && ai->CastSpell(SOUL_LINK, *m_bot)) return; // Check demon buffs if (pet && pet->GetEntry() == DEMON_IMP && BLOOD_PACT && !m_bot->HasAura(BLOOD_PACT) && ai->CastPetSpell(BLOOD_PACT)) return; if (pet && pet->GetEntry() == DEMON_FELHUNTER && FEL_INTELLIGENCE && !m_bot->HasAura(FEL_INTELLIGENCE) && ai->CastPetSpell(FEL_INTELLIGENCE)) return; } // end DoNonCombatActions
void PlayerbotWarlockAI::DoNonCombatActions() { if (!m_ai) return; if (!m_bot) return; //uint32 spec = m_bot->GetSpec(); Pet *pet = m_bot->GetPet(); // Initialize pet spells if (pet && pet->GetEntry() != m_lastDemon) { switch (pet->GetEntry()) { case DEMON_IMP: BLOOD_PACT = m_ai->initPetSpell(BLOOD_PACT_ICON); FIREBOLT = m_ai->initPetSpell(FIREBOLT_ICON); FIRE_SHIELD = m_ai->initPetSpell(FIRE_SHIELD_ICON); break; case DEMON_VOIDWALKER: CONSUME_SHADOWS = m_ai->initPetSpell(CONSUME_SHADOWS_ICON); SACRIFICE = m_ai->initPetSpell(SACRIFICE_ICON); SUFFERING = m_ai->initPetSpell(SUFFERING_ICON); TORMENT = m_ai->initPetSpell(TORMENT_ICON); break; case DEMON_SUCCUBUS: LASH_OF_PAIN = m_ai->initPetSpell(LASH_OF_PAIN_ICON); SEDUCTION = m_ai->initPetSpell(SEDUCTION_ICON); SOOTHING_KISS = m_ai->initPetSpell(SOOTHING_KISS_ICON); break; case DEMON_FELHUNTER: DEVOUR_MAGIC = m_ai->initPetSpell(DEVOUR_MAGIC_ICON); SPELL_LOCK = m_ai->initPetSpell(SPELL_LOCK_ICON); break; } m_lastDemon = pet->GetEntry(); } // Destroy extra soul shards uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); uint8 freeSpace = m_ai->GetFreeBagSpace(); if (shardCount > MAX_SHARD_COUNT || (freeSpace == 0 && shardCount > 1)) m_bot->DestroyItemCount(SOUL_SHARD, shardCount > MAX_SHARD_COUNT ? shardCount - MAX_SHARD_COUNT : 1, true, false); // buff myself DEMON_SKIN, DEMON_ARMOR, FEL_ARMOR - Strongest one available is chosen if (DEMON_ARMOR) { if (m_ai->SelfBuff(DEMON_ARMOR)) return; } else if (DEMON_SKIN) if (m_ai->SelfBuff(DEMON_SKIN)) return; // healthstone creation if (CREATE_HEALTHSTONE && shardCount > 0) { Item* const healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (!healthStone && m_ai->CastSpell(CREATE_HEALTHSTONE)) return; } // soulstone creation and use if (CREATE_SOULSTONE) { Item* soulStone = m_ai->FindConsumable(SOULSTONE_DISPLAYID); if (!soulStone) { if (shardCount > 0 && m_bot->IsSpellReady(CREATE_SOULSTONE) && m_ai->CastSpell(CREATE_SOULSTONE)) return; } else { uint32 soulStoneSpell = soulStone->GetProto()->Spells[0].SpellId; Player* master = GetMaster(); if (!master->HasAura(soulStoneSpell) && m_bot->IsSpellReady(soulStoneSpell)) { // TODO: first choice: healer. Second choice: anyone else with revive spell. Third choice: self or master. m_ai->UseItem(soulStone, master); return; } } } // hp/mana check if (pet && DARK_PACT && (100 * pet->GetPower(POWER_MANA) / pet->GetMaxPower(POWER_MANA)) > 40 && m_ai->GetManaPercent() <= 60) if (m_ai->CastSpell(DARK_PACT, *m_bot)) return; if (LIFE_TAP && m_ai->GetManaPercent() <= 80 && m_ai->GetHealthPercent() > 50) if (m_ai->CastSpell(LIFE_TAP, *m_bot)) return; // Do not waste time/soul shards to create spellstone or firestone // if two-handed weapon (staff) or off-hand item are already equiped // Spellstone creation and use (Spellstone dominates firestone completely as I understand it) Item* const weapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); Item* const offweapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (weapon && !offweapon && weapon->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_STAFF && weapon->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) == 0) { Item* const stone = m_ai->FindConsumable(SPELLSTONE_DISPLAYID); Item* const stone2 = m_ai->FindConsumable(FIRESTONE_DISPLAYID); uint8 spellstone_count = m_bot->GetItemCount(SPELLSTONE, false, nullptr); if (spellstone_count == 0) spellstone_count = m_bot->GetItemCount(GREATER_SPELLSTONE, false, nullptr); if (spellstone_count == 0) spellstone_count = m_bot->GetItemCount(MAJOR_SPELLSTONE, false, nullptr); uint8 firestone_count = m_bot->GetItemCount(LESSER_FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(GREATER_FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(MAJOR_FIRESTONE, false, nullptr); if (spellstone_count == 0 && firestone_count == 0) { if (CREATE_SPELLSTONE && shardCount > 0 && m_ai->CastSpell(CREATE_SPELLSTONE)) return; else if (CREATE_SPELLSTONE == 0 && CREATE_FIRESTONE > 0 && shardCount > 0 && m_ai->CastSpell(CREATE_FIRESTONE)) return; } else if (stone) { m_ai->UseItem(stone, EQUIPMENT_SLOT_OFFHAND); return; } else { m_ai->UseItem(stone2, EQUIPMENT_SLOT_OFFHAND); return; } } if (EatDrinkBandage()) return; //Heal Voidwalker if (pet && pet->GetEntry() == DEMON_VOIDWALKER && CONSUME_SHADOWS && pet->GetHealthPercent() < 75 && !pet->HasAura(CONSUME_SHADOWS)) m_ai->CastPetSpell(CONSUME_SHADOWS); CheckDemon(); // Soul link demon if (pet && SOUL_LINK && !m_bot->HasAura(SOUL_LINK_AURA) && m_ai->CastSpell(SOUL_LINK, *m_bot)) return; // Check demon buffs if (pet && pet->GetEntry() == DEMON_IMP && BLOOD_PACT && !m_bot->HasAura(BLOOD_PACT) && m_ai->CastPetSpell(BLOOD_PACT)) return; } // end DoNonCombatActions
void PlayerbotWarlockAI::CheckDemon() { uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); Pet *pet = m_bot->GetPet(); uint32 demonOfChoice; // If pet other than imp is active: return if (pet && pet->GetEntry() != DEMON_IMP) return; // Assign demon of choice based on spec if (spec == WARLOCK_SPEC_AFFLICTION) demonOfChoice = DEMON_FELHUNTER; else if (spec == WARLOCK_SPEC_DEMONOLOGY) demonOfChoice = DEMON_SUCCUBUS; else // Destruction spec or no spec found demonOfChoice = DEMON_IMP; // Summon demon if (!pet || m_isTempImp) { uint32 summonSpellId; if (demonOfChoice != DEMON_IMP && shardCount > 0) { switch (demonOfChoice) { case DEMON_VOIDWALKER: summonSpellId = SUMMON_VOIDWALKER; break; case DEMON_FELHUNTER: summonSpellId = SUMMON_FELHUNTER; break; case DEMON_SUCCUBUS: summonSpellId = SUMMON_SUCCUBUS; break; default: summonSpellId = 0; } if (summonSpellId && m_ai->CastSpell(summonSpellId)) { //m_ai->TellMaster("Summoning favorite demon..."); m_isTempImp = false; return; } } if (!pet && SUMMON_IMP && m_ai->CastSpell(SUMMON_IMP)) { if (demonOfChoice != DEMON_IMP) m_isTempImp = true; else m_isTempImp = false; //m_ai->TellMaster("Summoning Imp..."); return; } } return; }
CombatManeuverReturns PlayerbotWarlockAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; //Unit* pVictim = pTarget->getVictim(); bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); Pet *pet = m_bot->GetPet(); uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); // Voidwalker is near death - sacrifice it for a shield if (pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE) && pet->GetHealthPercent() < 10) m_ai->CastPetSpell(SACRIFICE); // Use healthstone if (m_ai->GetHealthPercent() < 30) { Item* healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (healthStone) m_ai->UseItem(healthStone); } // Voidwalker sacrifice gives shield - but you lose the pet (and it's DPS/tank) - use only as last resort for your own health! if (m_ai->GetHealthPercent() < 20 && pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE)) m_ai->CastPetSpell(SACRIFICE); if (m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED && !meleeReach) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // switch to melee if in melee range AND can't shoot OR have no ranged (wand) equipped else if(m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE && meleeReach && (SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true))) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); //Used to determine if this bot is highest on threat Unit *newTarget = m_ai->FindAttacker((PlayerbotAI::ATTACKERINFOTYPE) (PlayerbotAI::AIT_VICTIMSELF | PlayerbotAI::AIT_HIGHESTTHREAT), m_bot); if (newTarget && !m_ai->IsNeutralized(newTarget)) // TODO: && party has a tank { // Have threat, can't quickly lower it. 3 options remain: Stop attacking, lowlevel damage (wand), keep on keeping on. if (newTarget->GetHealthPercent() > 25) { // If elite if (m_ai->IsElite(newTarget)) { // let warlock pet handle it to win some time Creature * pCreature = (Creature*) newTarget; if (pet) { switch (pet->GetEntry()) { // taunt the elite and tank it case DEMON_VOIDWALKER: if (TORMENT && m_ai->CastPetSpell(TORMENT, newTarget)) return RETURN_NO_ACTION_OK; // maybe give it some love? case DEMON_SUCCUBUS: if (pCreature && pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_HUMANOID) if (SEDUCTION && !newTarget->HasAura(SEDUCTION) && m_ai->CastPetSpell(SEDUCTION, newTarget)) return RETURN_NO_ACTION_OK; } } // if aggroed mob is a demon or an elemental: banish it if (pCreature && (pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON || pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_ELEMENTAL)) { if (BANISH && !newTarget->HasAura(BANISH) && CastSpell(BANISH, newTarget)) return RETURN_CONTINUE; } return RETURN_NO_ACTION_OK; // do nothing and pray tank gets aggro off you } // Not an elite. You could insert FEAR here but in any PvE situation that's 90-95% likely // to worsen the situation for the group. ... So please don't. return CastSpell(SHOOT, pTarget); } } // Create soul shard (only on non-worldboss) uint8 freeSpace = m_ai->GetFreeBagSpace(); uint8 HPThreshold = (m_ai->IsElite(pTarget) ? 10 : 25); if (!m_ai->IsElite(pTarget, true) && pTarget->GetHealthPercent() < HPThreshold && (shardCount < MAX_SHARD_COUNT && freeSpace > 0)) { if (SHADOWBURN && m_ai->In_Reach(pTarget, SHADOWBURN) && !pTarget->HasAura(SHADOWBURN) && m_bot->IsSpellReady(SHADOWBURN) && CastSpell(SHADOWBURN, pTarget)) return RETURN_CONTINUE; // Do not cast Drain Soul if Shadowburn is active on target if (DRAIN_SOUL && m_ai->In_Reach(pTarget, DRAIN_SOUL) && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(SHADOWBURN) && CastSpell(DRAIN_SOUL, pTarget)) { m_ai->SetIgnoreUpdateTime(15); return RETURN_CONTINUE; } } if (pet && DARK_PACT && (100 * pet->GetPower(POWER_MANA) / pet->GetMaxPower(POWER_MANA)) > 10 && m_ai->GetManaPercent() <= 20) if (m_ai->CastSpell(DARK_PACT, *m_bot)) return RETURN_CONTINUE; // Mana check and replenishment if (LIFE_TAP && m_ai->GetManaPercent() <= 20 && m_ai->GetHealthPercent() > 50) if (m_ai->CastSpell(LIFE_TAP, *m_bot)) return RETURN_CONTINUE; // HP, mana and aggro checks done // Curse the target if (CheckCurse(pTarget)) return RETURN_CONTINUE; // Damage Spells if (spec) { switch (spec) { case WARLOCK_SPEC_AFFLICTION: if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (SIPHON_LIFE > 0 && m_ai->In_Reach(pTarget,SIPHON_LIFE) && !pTarget->HasAura(SIPHON_LIFE) && CastSpell(SIPHON_LIFE, pTarget)) return RETURN_CONTINUE; break; case WARLOCK_SPEC_DEMONOLOGY: if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; break; case WARLOCK_SPEC_DESTRUCTION: if (SHADOWBURN && pTarget->GetHealthPercent() < (HPThreshold / 2.0) && m_ai->In_Reach(pTarget, SHADOWBURN) && !pTarget->HasAura(SHADOWBURN) && CastSpell(SHADOWBURN, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (CONFLAGRATE && m_ai->In_Reach(pTarget,CONFLAGRATE) && pTarget->HasAura(IMMOLATE) && m_bot->IsSpellReady(CONFLAGRATE) && CastSpell(CONFLAGRATE, pTarget)) return RETURN_CONTINUE; break; } // Shadow bolt is common to all specs if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_OK; //if (DRAIN_LIFE && LastSpellAffliction < 4 && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(DRAIN_LIFE) && !pTarget->HasAura(DRAIN_MANA) && m_ai->GetHealthPercent() <= 70) // m_ai->CastSpell(DRAIN_LIFE, *pTarget); // //m_ai->SetIgnoreUpdateTime(5); //else if (HOWL_OF_TERROR && !pTarget->HasAura(HOWL_OF_TERROR) && m_ai->GetAttackerCount() > 3 && LastSpellAffliction < 8) // m_ai->CastSpell(HOWL_OF_TERROR, *pTarget); // m_ai->TellMaster("casting howl of terror!"); //else if (FEAR && !pTarget->HasAura(FEAR) && pVictim == m_bot && m_ai->GetAttackerCount() >= 2 && LastSpellAffliction < 9) // m_ai->CastSpell(FEAR, *pTarget); // //m_ai->TellMaster("casting fear!"); // //m_ai->SetIgnoreUpdateTime(1.5); //else if (RAIN_OF_FIRE && LastSpellDestruction < 3 && m_ai->GetAttackerCount() >= 3) // m_ai->CastSpell(RAIN_OF_FIRE, *pTarget); // //m_ai->TellMaster("casting rain of fire!"); // //m_ai->SetIgnoreUpdateTime(8); //else if (SEARING_PAIN && LastSpellDestruction < 8) // m_ai->CastSpell(SEARING_PAIN, *pTarget); //else if (SOUL_FIRE && LastSpellDestruction < 9) // m_ai->CastSpell(SOUL_FIRE, *pTarget); // //m_ai->SetIgnoreUpdateTime(6); //else if (HELLFIRE && LastSpellDestruction < 12 && !m_bot->HasAura(HELLFIRE) && m_ai->GetAttackerCount() >= 5 && m_ai->GetHealthPercent() >= 50) // m_ai->CastSpell(HELLFIRE); // m_ai->TellMaster("casting hellfire!"); // //m_ai->SetIgnoreUpdateTime(15); } // No spec due to low level OR no spell found yet if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT)) return CastSpell(SHADOW_BOLT, pTarget); // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result, uint8 asynchLoadType) { if (!GetPlayer() || GetPlayer()->GetPet() || GetPlayer()->GetVehicle() || GetPlayer()->IsSpectator()) return PET_LOAD_ERROR; if (!result) return PET_LOAD_NO_RESULT; Field* fields = result->Fetch(); // Xinef: this can happen if fetch is called twice, impossibru. if (!fields) return PET_LOAD_ERROR; Player* owner = GetPlayer(); // update for case of current pet "slot = 0" uint32 petentry = fields[1].GetUInt32(); if (!petentry) return PET_LOAD_NO_RESULT; uint8 petSlot = fields[7].GetUInt8(); bool current = petSlot == PET_SAVE_AS_CURRENT; uint32 summon_spell_id = fields[15].GetUInt32(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); // CANT BE NULL bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0; uint32 pet_number = fields[0].GetUInt32(); uint32 savedhealth = fields[10].GetUInt32(); uint32 savedmana = fields[11].GetUInt32(); PetType pet_type = PetType(fields[16].GetUInt8()); // xinef: BG resurrect, overwrite saved value if (asynchLoadType == PET_LOAD_BG_RESURRECT) savedhealth = 1; if (pet_type == HUNTER_PET && savedhealth == 0 && asynchLoadType != PET_LOAD_SUMMON_DEAD_PET) { WorldPacket data(SMSG_CAST_FAILED, 1+4+1+4); data << uint8(0); data << uint32(883); data << uint8(SPELL_FAILED_TARGETS_DEAD); SendPacket(&data); owner->RemoveSpellCooldown(883, false); return PET_LOAD_ERROR; } // check temporary summoned pets like mage water elemental if (current && is_temporary_summoned) return PET_LOAD_ERROR; if (pet_type == HUNTER_PET) { CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petentry); if (!creatureInfo || !creatureInfo->IsTameable(owner->CanTameExoticPets())) return PET_LOAD_ERROR; } Map* map = owner->GetMap(); uint32 guid = sObjectMgr->GenerateLowGuid(HIGHGUID_PET); Pet* pet = new Pet(owner, pet_type); LoadPetFromDBQueryHolder* holder = new LoadPetFromDBQueryHolder(pet_number, current, uint32(time(NULL) - fields[14].GetUInt32()), fields[13].GetString(), savedhealth, savedmana); if (!pet->Create(guid, map, owner->GetPhaseMask(), petentry, pet_number) || !holder->Initialize()) { delete pet; delete holder; return PET_LOAD_ERROR; } float px, py, pz; owner->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle()); if (!pet->IsPositionValid()) { sLog->outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", pet->GetGUIDLow(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); delete pet; delete holder; return PET_LOAD_ERROR; } pet->SetLoading(true); pet->Relocate(px, py, pz, owner->GetOrientation()); pet->setPetType(pet_type); pet->setFaction(owner->getFaction()); pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); if (pet->IsCritter()) { map->AddToMap(pet->ToCreature(), true); pet->SetLoading(false); // xinef, mine delete holder; return PET_LOAD_OK; } pet->GetCharmInfo()->SetPetNumber(pet_number, pet->IsPermanentPetFor(owner)); pet->SetDisplayId(fields[3].GetUInt32()); pet->SetNativeDisplayId(fields[3].GetUInt32()); uint32 petlevel = fields[4].GetUInt8(); pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); pet->SetName(fields[8].GetString()); switch (pet->getPetType()) { case SUMMON_PET: petlevel = owner->getLevel(); if (pet->IsPetGhoul()) pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x400); // class = rogue else pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet dismiss, cancel) break; case HUNTER_PET: pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus pet->SetSheath(SHEATH_STATE_MELEE); pet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) pet->SetMaxPower(POWER_HAPPINESS, pet->GetCreatePowers(POWER_HAPPINESS)); pet->SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); pet->setPowerType(POWER_FOCUS); break; default: if (!pet->IsPetGhoul()) sLog->outError("Pet have incorrect type (%u) for pet loading.", pet->getPetType()); break; } pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped here pet->SetCreatorGUID(owner->GetGUID()); owner->SetMinion(pet, true); pet->InitStatsForLevel(petlevel); pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); pet->SynchronizeLevelWithOwner(); pet->SetReactState(ReactStates(fields[6].GetUInt8())); pet->SetCanModifyStats(true); // 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 (petSlot) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID); stmt->setUInt8(0, uint8(PET_SAVE_NOT_IN_SLOT)); stmt->setUInt32(1, owner->GetGUIDLow()); stmt->setUInt8(2, uint8(PET_SAVE_AS_CURRENT)); stmt->setUInt32(3, pet_number); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID); stmt->setUInt8(0, uint8(PET_SAVE_AS_CURRENT)); stmt->setUInt32(1, owner->GetGUIDLow()); stmt->setUInt32(2, pet_number); trans->Append(stmt); 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); } // do it as early as possible! pet->InitTalentForLevel(); // set original talents points before spell loading if (!is_temporary_summoned) pet->GetCharmInfo()->InitPetActionBar(); map->AddToMap(pet->ToCreature(), true); if (pet->getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA)); else { pet->SetHealth(savedhealth > pet->GetMaxHealth() ? pet->GetMaxHealth() : savedhealth); pet->SetPower(POWER_MANA, savedmana > pet->GetMaxPower(POWER_MANA) ? pet->GetMaxPower(POWER_MANA) : savedmana); } pet->SetAsynchLoadType(asynchLoadType); // xinef: clear any old result if (_loadPetFromDBSecondCallback.ready()) { SQLQueryHolder* param; _loadPetFromDBSecondCallback.get(param); delete param; } _loadPetFromDBSecondCallback.cancel(); _loadPetFromDBSecondCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); return PET_LOAD_OK; }
CombatManeuverReturns PlayerbotWarlockAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; //Unit* pVictim = pTarget->getVictim(); bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); Pet *pet = m_bot->GetPet(); uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); //If we have UA it will replace immolate in our rotation uint32 FIRE = (UNSTABLE_AFFLICTION > 0 ? UNSTABLE_AFFLICTION : IMMOLATE); // Voidwalker is near death - sacrifice it for a shield if (pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE) && pet->GetHealthPercent() < 10) m_ai->CastPetSpell(SACRIFICE); // Use healthstone if (m_ai->GetHealthPercent() < 30) { Item* healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (healthStone) m_ai->UseItem(healthStone); } // Voidwalker sacrifice gives shield - but you lose the pet (and it's DPS/tank) - use only as last resort for your own health! if (m_ai->GetHealthPercent() < 20 && pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE)) m_ai->CastPetSpell(SACRIFICE); if (m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED && !meleeReach) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // if in melee range OR can't shoot OR have no ranged (wand) equipped else if(m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE && (meleeReach || SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true))) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); //Used to determine if this bot is highest on threat Unit *newTarget = m_ai->FindAttacker((PlayerbotAI::ATTACKERINFOTYPE) (PlayerbotAI::AIT_VICTIMSELF | PlayerbotAI::AIT_HIGHESTTHREAT), m_bot); if (newTarget) // TODO: && party has a tank { if (SOULSHATTER > 0 && shardCount > 0 && !m_bot->HasSpellCooldown(SOULSHATTER)) if (CastSpell(SOULSHATTER, m_bot)) return RETURN_CONTINUE; // Have threat, can't quickly lower it. 3 options remain: Stop attacking, lowlevel damage (wand), keep on keeping on. if (newTarget->GetHealthPercent() > 25) { // If elite, do nothing and pray tank gets aggro off you // TODO: Is there an IsElite function? If so, find it and insert. //if (newTarget->IsElite()) // return; // Not an elite. You could insert FEAR here but in any PvE situation that's 90-95% likely // to worsen the situation for the group. ... So please don't. return CastSpell(SHOOT, pTarget); } } // Damage Spells switch (spec) { case WARLOCK_SPEC_AFFLICTION: if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (HAUNT && m_ai->In_Reach(pTarget,HAUNT) && !m_bot->HasSpellCooldown(HAUNT) && CastSpell(HAUNT, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; case WARLOCK_SPEC_DEMONOLOGY: if (pet && DEMONIC_EMPOWERMENT && !m_bot->HasSpellCooldown(DEMONIC_EMPOWERMENT) && CastSpell(DEMONIC_EMPOWERMENT)) return RETURN_CONTINUE; if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (INCINERATE && m_ai->In_Reach(pTarget,INCINERATE) && pTarget->HasAura(FIRE) && CastSpell(INCINERATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; case WARLOCK_SPEC_DESTRUCTION: if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (CONFLAGRATE && m_ai->In_Reach(pTarget,CONFLAGRATE) && pTarget->HasAura(FIRE) && !m_bot->HasSpellCooldown(CONFLAGRATE) && CastSpell(CONFLAGRATE, pTarget)) return RETURN_CONTINUE; if (CHAOS_BOLT && m_ai->In_Reach(pTarget,CHAOS_BOLT) && !m_bot->HasSpellCooldown(CHAOS_BOLT) && CastSpell(CHAOS_BOLT, pTarget)) return RETURN_CONTINUE; if (INCINERATE && m_ai->In_Reach(pTarget,INCINERATE) && pTarget->HasAura(FIRE) && CastSpell(INCINERATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; //if (LIFE_TAP && LastSpellAffliction < 1 && m_ai->GetManaPercent() <= 50 && m_ai->GetHealthPercent() > 50) // m_ai->CastSpell(LIFE_TAP, *m_bot); //else if (DRAIN_SOUL && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.40 && !pTarget->HasAura(DRAIN_SOUL) && LastSpellAffliction < 3) // m_ai->CastSpell(DRAIN_SOUL, *pTarget); // //m_ai->SetIgnoreUpdateTime(15); //else if (DRAIN_LIFE && LastSpellAffliction < 4 && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(SEED_OF_CORRUPTION) && !pTarget->HasAura(DRAIN_LIFE) && !pTarget->HasAura(DRAIN_MANA) && m_ai->GetHealthPercent() <= 70) // m_ai->CastSpell(DRAIN_LIFE, *pTarget); // //m_ai->SetIgnoreUpdateTime(5); //else if (SEED_OF_CORRUPTION && !pTarget->HasAura(SEED_OF_CORRUPTION) && LastSpellAffliction < 7) // m_ai->CastSpell(SEED_OF_CORRUPTION, *pTarget); //else if (HOWL_OF_TERROR && !pTarget->HasAura(HOWL_OF_TERROR) && m_ai->GetAttackerCount() > 3 && LastSpellAffliction < 8) // m_ai->CastSpell(HOWL_OF_TERROR, *pTarget); // m_ai->TellMaster("casting howl of terror!"); //else if (FEAR && !pTarget->HasAura(FEAR) && pVictim == m_bot && m_ai->GetAttackerCount() >= 2 && LastSpellAffliction < 9) // m_ai->CastSpell(FEAR, *pTarget); // //m_ai->TellMaster("casting fear!"); // //m_ai->SetIgnoreUpdateTime(1.5); //else if ((pet) && (DARK_PACT > 0 && m_ai->GetManaPercent() <= 50 && LastSpellAffliction < 10 && pet->GetPower(POWER_MANA) > 0)) // m_ai->CastSpell(DARK_PACT, *m_bot); //if (SHADOWFURY && LastSpellDestruction < 1 && !pTarget->HasAura(SHADOWFURY)) // m_ai->CastSpell(SHADOWFURY, *pTarget); //else if (RAIN_OF_FIRE && LastSpellDestruction < 3 && m_ai->GetAttackerCount() >= 3) // m_ai->CastSpell(RAIN_OF_FIRE, *pTarget); // //m_ai->TellMaster("casting rain of fire!"); // //m_ai->SetIgnoreUpdateTime(8); //else if (SHADOWFLAME && !pTarget->HasAura(SHADOWFLAME) && LastSpellDestruction < 4) // m_ai->CastSpell(SHADOWFLAME, *pTarget); //else if (SEARING_PAIN && LastSpellDestruction < 8) // m_ai->CastSpell(SEARING_PAIN, *pTarget); //else if (SOUL_FIRE && LastSpellDestruction < 9) // m_ai->CastSpell(SOUL_FIRE, *pTarget); // //m_ai->SetIgnoreUpdateTime(6); //else if (SHADOWBURN && LastSpellDestruction < 11 && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.20 && !pTarget->HasAura(SHADOWBURN)) // m_ai->CastSpell(SHADOWBURN, *pTarget); //else if (HELLFIRE && LastSpellDestruction < 12 && !m_bot->HasAura(HELLFIRE) && m_ai->GetAttackerCount() >= 5 && m_ai->GetHealthPercent() >= 50) // m_ai->CastSpell(HELLFIRE); // m_ai->TellMaster("casting hellfire!"); // //m_ai->SetIgnoreUpdateTime(15); //else if (CURSE_OF_THE_ELEMENTS && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && LastSpellCurse < 2) // m_ai->CastSpell(CURSE_OF_THE_ELEMENTS, *pTarget); //else if (CURSE_OF_WEAKNESS && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 3) // m_ai->CastSpell(CURSE_OF_WEAKNESS, *pTarget); //else if (CURSE_OF_TONGUES && !pTarget->HasAura(CURSE_OF_TONGUES) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 4) // m_ai->CastSpell(CURSE_OF_TONGUES, *pTarget); } // No spec due to low level OR no spell found yet if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT)) return CastSpell(SHADOW_BOLT, pTarget); return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
void WorldSession::HandleStableSwapPet( WorldPacket & recv_data ) { sLog.outDetail("WORLD: Recv CMSG_STABLE_SWAP_PET."); uint64 npcGUID; uint32 pet_number; recv_data >> npcGUID >> pet_number; if(!GetPlayer()->isAlive()) return; Creature *unit = ObjectAccessor::Instance().GetCreature(*_player, npcGUID); if (!unit) { sLog.outDebug( "WORLD: CMSG_STABLE_SWAP_PET - NO SUCH UNIT! (GUID: %u)", uint32(GUID_LOPART(npcGUID)) ); return; } if( unit->IsHostileTo(_player)) // do not talk with enemies return; WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size Pet* pet = _player->GetPet(); if(!pet) return; if(!pet->GetUInt32Value(UNIT_FIELD_PETNUMBER)) return; QueryResult *result; result = sDatabase.PQuery("SELECT `owner`,`slot`,`petnumber`,`entry`,`level`,`loyalty`,`trainpoint` FROM `character_stable` WHERE `owner` = '%u' AND `petnumber` = '%u'",_player->GetGUIDLow(),pet_number); if(!result) { delete result; return; } Field *fields = result->Fetch(); uint32 slot = fields[1].GetUInt32(); uint32 petentry = fields[3].GetUInt32(); delete result; // move alive pet to slot if(pet->isAlive()) { sDatabase.BeginTransaction(); sDatabase.PExecute("DELETE FROM `character_stable` WHERE `owner` = '%u' AND `slot` = '%u'", _player->GetGUIDLow(),slot); sDatabase.PExecute("INSERT INTO `character_stable` (`owner`,`slot`,`petnumber`,`entry`,`level`,`loyalty`,`trainpoint`) VALUES (%u,%u,%u,%u,%u,%u,%u)", _player->GetGUIDLow(),slot,pet->GetUInt32Value(UNIT_FIELD_PETNUMBER),pet->GetEntry(),pet->getLevel(),pet->getloyalty(),pet->getUsedTrainPoint()); sDatabase.CommitTransaction(); _player->RemovePet(pet,PET_SAVE_AS_STORED); } // delele dead pet and free slot else { sDatabase.PExecute("UPDATE `character_stable` SET `petnumber` = '0',`entry` = '0',`level` = '0',`loyalty` = '0',`trainpoint` = '0' WHERE `owner` = '%u' AND `slot` = '%u'",_player->GetGUIDLow(), slot); _player->RemovePet(pet,PET_SAVE_AS_DELETED); } // summon unstabled pet Pet *newpet = new Pet(_player->getClass()==CLASS_HUNTER?HUNTER_PET:SUMMON_PET); if(!newpet->LoadPetFromDB(_player,petentry)) { delete newpet; data << uint8(0x06); } else data << uint8(0x09); SendPacket(&data); }
void WorldSession::HandleStablePet( WorldPacket & recv_data ) { sLog.outDetail("WORLD: Recv CMSG_STABLE_PET not dispose."); uint64 npcGUID; recv_data >> npcGUID; if(!GetPlayer()->isAlive()) return; Creature *unit = ObjectAccessor::Instance().GetCreature(*_player, npcGUID); if (!unit) { sLog.outDebug( "WORLD: CMSG_STABLE_PET - NO SUCH UNIT! (GUID: %u)", uint32(GUID_LOPART(npcGUID)) ); return; } if( unit->IsHostileTo(_player)) // do not talk with enemies return; Pet *pet = _player->GetPet(); WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size // can't place in stable dead pet if(!pet||!pet->isAlive()) { data << uint8(0x06); SendPacket(&data); return; } if(!pet->GetUInt32Value(UNIT_FIELD_PETNUMBER)) return; QueryResult *result; bool flag = false; result = sDatabase.PQuery("SELECT `owner`,`slot`,`petnumber` FROM `character_stable` WHERE `owner` = '%u' ORDER BY `slot` ",_player->GetGUIDLow()); if(result) { do { Field *fields = result->Fetch(); uint32 slot = fields[1].GetUInt32(); if(fields[2].GetUInt32()) continue; else if(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER) == fields[2].GetUInt32()) break; else if( slot == 1 || slot == 2) { sDatabase.BeginTransaction(); sDatabase.PExecute("DELETE FROM `character_stable` WHERE `owner` = '%u' AND `slot` = '%u'", _player->GetGUIDLow(),slot); sDatabase.PExecute("INSERT INTO `character_stable` (`owner`,`slot`,`petnumber`,`entry`,`level`,`loyalty`,`trainpoint`) VALUES (%u,%u,%u,%u,%u,%u,%u)", _player->GetGUIDLow(),slot,pet->GetUInt32Value(UNIT_FIELD_PETNUMBER),pet->GetEntry(),pet->getLevel(),pet->getloyalty(),pet->getUsedTrainPoint()); sDatabase.CommitTransaction(); data << uint8(0x08); flag = true; _player->RemovePet(pet,PET_SAVE_AS_STORED); break; } }while( result->NextRow() ); } delete result; if(!flag) data << uint8(0x06); SendPacket(&data); }
void WorldSession::SendStablePet(uint64 guid ) { sLog.outDetail("WORLD: Recv MSG_LIST_STABLED_PETS Send."); WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size data << uint64 ( guid ); QueryResult *result,*result_1; uint8 max_slot = 0; uint8 num = 0; result_1 = sDatabase.PQuery("SELECT `slot`,`petnumber` FROM `character_stable` WHERE `owner` = '%u'",_player->GetGUIDLow()); if(result_1) { do { Field *fields = result_1->Fetch(); uint8 cur_slot = fields[0].GetUInt32(); if(max_slot < cur_slot) max_slot = cur_slot; if(fields[1].GetUInt32()) num++; }while( result_1->NextRow() ); } delete result_1; Pet *pet = _player->GetPet(); // count only alive pet if(pet && pet->isAlive()) num++; data << uint8(num) << uint8(max_slot); // not let move dead pet in slot if(pet && pet->isAlive()) { if(!pet->GetUInt32Value(UNIT_FIELD_PETNUMBER)) return; // petnumber data << uint32(pet->GetUInt32Value(UNIT_FIELD_PETNUMBER)); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); //data << cinfo->Name; // petname data << uint8(0x00); data << uint32(pet->getloyalty()); // loyalty data << uint8(0x01); // slot } result = sDatabase.PQuery("SELECT `owner`,`slot`,`petnumber`,`entry`,`level`,`loyalty`,`trainpoint` FROM `character_stable` WHERE `owner` = '%u'",_player->GetGUIDLow()); if(result) { do { Field *fields = result->Fetch(); uint32 petentry = fields[3].GetUInt32(); if(petentry) { CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(petentry); data << uint32(fields[2].GetUInt32()); // petnumber data << uint32(petentry); data << uint32(fields[4].GetUInt32()); data << cinfo->Name; data << uint32(fields[5].GetUInt32()); // loyalty data << uint8(fields[1].GetUInt32()+1); // slot } }while( result->NextRow() ); } delete result; SendPacket(&data); }