diff --git a/sql/updates/ek/mangos_pet_levelspells.sql b/sql/updates/ek/mangos_pet_levelspells.sql new file mode 100644 index 0000000..3d69228 --- /dev/null +++ b/sql/updates/ek/mangos_pet_levelspells.sql @@ -0,0 +1,112 @@ +DROP TABLE IF EXISTS `pet_levelspells`; +CREATE TABLE `pet_levelspells` ( + `entry` int(11) unsigned NOT NULL default '0', + `spell` int(11) unsigned NOT NULL default '0', + PRIMARY KEY (`entry`,`spell`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System'; + +INSERT INTO `pet_levelspells` VALUES ('15', '19244'); +INSERT INTO `pet_levelspells` VALUES ('15', '19505'); +INSERT INTO `pet_levelspells` VALUES ('15', '19647'); +INSERT INTO `pet_levelspells` VALUES ('15', '19731'); +INSERT INTO `pet_levelspells` VALUES ('15', '19734'); +INSERT INTO `pet_levelspells` VALUES ('15', '19736'); +INSERT INTO `pet_levelspells` VALUES ('15', '27276'); +INSERT INTO `pet_levelspells` VALUES ('15', '27277'); +INSERT INTO `pet_levelspells` VALUES ('15', '48011'); +INSERT INTO `pet_levelspells` VALUES ('15', '54049'); +INSERT INTO `pet_levelspells` VALUES ('15', '54050'); +INSERT INTO `pet_levelspells` VALUES ('15', '54051'); +INSERT INTO `pet_levelspells` VALUES ('15', '54052'); +INSERT INTO `pet_levelspells` VALUES ('15', '54053'); +INSERT INTO `pet_levelspells` VALUES ('15', '54424'); +INSERT INTO `pet_levelspells` VALUES ('15', '57564'); +INSERT INTO `pet_levelspells` VALUES ('15', '57565'); +INSERT INTO `pet_levelspells` VALUES ('15', '57566'); +INSERT INTO `pet_levelspells` VALUES ('15', '57567'); +INSERT INTO `pet_levelspells` VALUES ('16', '3716'); +INSERT INTO `pet_levelspells` VALUES ('16', '7809'); +INSERT INTO `pet_levelspells` VALUES ('16', '7810'); +INSERT INTO `pet_levelspells` VALUES ('16', '7811'); +INSERT INTO `pet_levelspells` VALUES ('16', '7812'); +INSERT INTO `pet_levelspells` VALUES ('16', '11774'); +INSERT INTO `pet_levelspells` VALUES ('16', '11775'); +INSERT INTO `pet_levelspells` VALUES ('16', '17735'); +INSERT INTO `pet_levelspells` VALUES ('16', '17750'); +INSERT INTO `pet_levelspells` VALUES ('16', '17751'); +INSERT INTO `pet_levelspells` VALUES ('16', '17752'); +INSERT INTO `pet_levelspells` VALUES ('16', '17767'); +INSERT INTO `pet_levelspells` VALUES ('16', '17850'); +INSERT INTO `pet_levelspells` VALUES ('16', '17851'); +INSERT INTO `pet_levelspells` VALUES ('16', '17852'); +INSERT INTO `pet_levelspells` VALUES ('16', '17853'); +INSERT INTO `pet_levelspells` VALUES ('16', '17854'); +INSERT INTO `pet_levelspells` VALUES ('16', '19438'); +INSERT INTO `pet_levelspells` VALUES ('16', '19440'); +INSERT INTO `pet_levelspells` VALUES ('16', '19441'); +INSERT INTO `pet_levelspells` VALUES ('16', '19442'); +INSERT INTO `pet_levelspells` VALUES ('16', '19443'); +INSERT INTO `pet_levelspells` VALUES ('16', '27270'); +INSERT INTO `pet_levelspells` VALUES ('16', '27271'); +INSERT INTO `pet_levelspells` VALUES ('16', '27272'); +INSERT INTO `pet_levelspells` VALUES ('16', '27273'); +INSERT INTO `pet_levelspells` VALUES ('16', '33701'); +INSERT INTO `pet_levelspells` VALUES ('16', '47984'); +INSERT INTO `pet_levelspells` VALUES ('16', '47985'); +INSERT INTO `pet_levelspells` VALUES ('16', '47986'); +INSERT INTO `pet_levelspells` VALUES ('16', '47987'); +INSERT INTO `pet_levelspells` VALUES ('16', '47988'); +INSERT INTO `pet_levelspells` VALUES ('16', '47989'); +INSERT INTO `pet_levelspells` VALUES ('16', '47990'); +INSERT INTO `pet_levelspells` VALUES ('17', '6358'); +INSERT INTO `pet_levelspells` VALUES ('17', '6360'); +INSERT INTO `pet_levelspells` VALUES ('17', '7813'); +INSERT INTO `pet_levelspells` VALUES ('17', '7814'); +INSERT INTO `pet_levelspells` VALUES ('17', '7815'); +INSERT INTO `pet_levelspells` VALUES ('17', '7816'); +INSERT INTO `pet_levelspells` VALUES ('17', '7870'); +INSERT INTO `pet_levelspells` VALUES ('17', '11778'); +INSERT INTO `pet_levelspells` VALUES ('17', '11779'); +INSERT INTO `pet_levelspells` VALUES ('17', '11780'); +INSERT INTO `pet_levelspells` VALUES ('17', '11784'); +INSERT INTO `pet_levelspells` VALUES ('17', '11785'); +INSERT INTO `pet_levelspells` VALUES ('17', '27274'); +INSERT INTO `pet_levelspells` VALUES ('17', '27275'); +INSERT INTO `pet_levelspells` VALUES ('17', '47991'); +INSERT INTO `pet_levelspells` VALUES ('17', '47992'); +INSERT INTO `pet_levelspells` VALUES ('23', '2947'); +INSERT INTO `pet_levelspells` VALUES ('23', '3110'); +INSERT INTO `pet_levelspells` VALUES ('23', '4511'); +INSERT INTO `pet_levelspells` VALUES ('23', '6307'); +INSERT INTO `pet_levelspells` VALUES ('23', '7799'); +INSERT INTO `pet_levelspells` VALUES ('23', '7800'); +INSERT INTO `pet_levelspells` VALUES ('23', '7801'); +INSERT INTO `pet_levelspells` VALUES ('23', '7802'); +INSERT INTO `pet_levelspells` VALUES ('23', '7804'); +INSERT INTO `pet_levelspells` VALUES ('23', '7805'); +INSERT INTO `pet_levelspells` VALUES ('23', '8316'); +INSERT INTO `pet_levelspells` VALUES ('23', '8317'); +INSERT INTO `pet_levelspells` VALUES ('23', '11762'); +INSERT INTO `pet_levelspells` VALUES ('23', '11763'); +INSERT INTO `pet_levelspells` VALUES ('23', '11766'); +INSERT INTO `pet_levelspells` VALUES ('23', '11767'); +INSERT INTO `pet_levelspells` VALUES ('23', '11770'); +INSERT INTO `pet_levelspells` VALUES ('23', '11771'); +INSERT INTO `pet_levelspells` VALUES ('23', '27267'); +INSERT INTO `pet_levelspells` VALUES ('23', '27268'); +INSERT INTO `pet_levelspells` VALUES ('23', '27269'); +INSERT INTO `pet_levelspells` VALUES ('23', '47964'); +INSERT INTO `pet_levelspells` VALUES ('23', '47982'); +INSERT INTO `pet_levelspells` VALUES ('23', '47983'); +INSERT INTO `pet_levelspells` VALUES ('29', '30151'); +INSERT INTO `pet_levelspells` VALUES ('29', '30194'); +INSERT INTO `pet_levelspells` VALUES ('29', '30198'); +INSERT INTO `pet_levelspells` VALUES ('29', '30213'); +INSERT INTO `pet_levelspells` VALUES ('29', '30219'); +INSERT INTO `pet_levelspells` VALUES ('29', '30223'); +INSERT INTO `pet_levelspells` VALUES ('29', '33698'); +INSERT INTO `pet_levelspells` VALUES ('29', '33699'); +INSERT INTO `pet_levelspells` VALUES ('29', '33700'); +INSERT INTO `pet_levelspells` VALUES ('29', '47993'); +INSERT INTO `pet_levelspells` VALUES ('29', '47994'); +INSERT INTO `pet_levelspells` VALUES ('29', '47996'); \ No newline at end of file diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 3442611..f475cb9 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -177,6 +177,25 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetUInt32Value(UNIT_NPC_FLAGS, 0); SetName(fields[9].GetString()); + bool petlevelchange = false; + switch(owner->getClass()) + { + case CLASS_WARLOCK: + { + // if player level up without pet, when player summon a pet, pet auto level up. (only warlock) + _LoadSpells(); + _LoadSpellCooldowns(); + + if(owner->getLevel() > petlevel) + { + petlevelchange = true; + } + break; + } + default: + break; + } + switch(getPetType()) { case SUMMON_PET: @@ -202,6 +221,18 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType()); } + switch(owner->getClass()) + { + case CLASS_WARLOCK: + { + _LoadSpells(); + _LoadSpellCooldowns(); + break; + } + default: + break; + } + InitStatsForLevel(petlevel); SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL)); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); @@ -295,8 +326,25 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool map->Add((Creature*)this); // Spells should be loaded after pet is added to map, because in CheckCast is check on it - _LoadSpells(); - _LoadSpellCooldowns(); + switch(owner->getClass()) + { + case CLASS_WARLOCK: + { + //if player level up to high level without pet, when player summon a pet, pet auto level up. (only warlock) + if(petlevelchange == true) + { + InitPetCreateSpells(); + InitStatsForLevel(petlevel); + } + break; + } + default: + { + _LoadSpells(); + _LoadSpellCooldowns(); + break; + } + } owner->SetPet(this); // in DB stored only full controlled creature sLog.outDebug("New Pet has guid %u", GetGUIDLow()); @@ -745,7 +793,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) setPowerType(POWER_FOCUS); SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); - SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(creature->getLevel())/4); + SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(creature->getLevel())/10); SetUInt32Value(UNIT_NPC_FLAGS, 0); if(CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) @@ -831,6 +879,9 @@ bool Pet::InitStatsForLevel(uint32 petlevel) uint32 fire = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE); uint32 shadow = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW); uint32 val = (fire > shadow) ? fire : shadow; + + // WARLOCK + learnLevelupSpellsWarlock(); SetBonusDamage(int32 (val * 0.15f)); //bonusAP += val * 0.57; @@ -887,7 +938,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel) } case HUNTER_PET: { - SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(petlevel)/4); + SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(petlevel)/10); learnLevelupSpells(); //these formula may not be correct; however, it is designed to be close to what it should be //this makes dps 0.5 of pets level @@ -1051,7 +1102,7 @@ void Pet::_SaveSpellCooldowns() m_CreatureSpellCooldowns.erase(itr++); else { - CharacterDatabase.PExecute("INSERT INTO pet_spell_cooldown (guid,spell,time) VALUES ('%u', '%u', '" I64FMTD "')", m_charmInfo->GetPetNumber(), itr->first, uint64(itr->second)); + CharacterDatabase.PExecute("INSERT IGNORE INTO pet_spell_cooldown (guid,spell,time) VALUES ('%u', '%u', '" I64FMTD "')", m_charmInfo->GetPetNumber(), itr->first, uint64(itr->second)); ++itr; } } @@ -1083,9 +1134,8 @@ void Pet::_SaveSpells() if (itr->second->type == PETSPELL_FAMILY) continue; // prevent saving family passives to DB if (itr->second->state == PETSPELL_REMOVED || itr->second->state == PETSPELL_CHANGED) CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first); - if (itr->second->state == PETSPELL_NEW || itr->second->state == PETSPELL_CHANGED) - CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second->active); - + if (itr->second->state == PETSPELL_NEW || itr->second->state == PETSPELL_CHANGED) + CharacterDatabase.PExecute("INSERT IGNORE INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second->active); if (itr->second->state == PETSPELL_REMOVED) _removeSpell(itr->first); else @@ -1370,6 +1420,113 @@ void Pet::learnLevelupSpells() } } +void Pet::learnLevelupSpellsWarlock() +{ + PetLevelupSpellSet const *levelupSpells = spellmgr.GetPetLevelupSpellList(GetCreatureInfo()->family); + if(!levelupSpells) + return; + + uint32 level = getLevel(); + uint32 levelspelladd = 0; + uint32 levelspelldel = 0; + + for(PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr) + { + if((itr->first & 0xffff) <= level) + { + if (existAddSpell(itr->second) == true) + { + // add spell + if(existLowRankOfSpell(itr->second) == false) + { + levelspelladd++; + } + } + } + else + { + if(existDeleteSpell(itr->second) == true) + { + // delete spell + levelspelldel++; + } + } + } + if(levelspelladd == 0 && levelspelldel == 0) + { + return; + } + for(PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr) + { + if((itr->first & 0xffff) <= level) + { + if(existLowRankOfSpell(itr->second) == false) + { + learnSpell(itr->second); + } + } + else + { + unlearnSpell(itr->second); + } + } +} + +bool Pet::existLowRankOfSpell(uint32 spell_id) +{ + uint32 levelspelllow = 0; + for (PetSpellMap::const_iterator sitr = m_spells.begin(), next = m_spells.begin(); sitr != m_spells.end(); sitr = next) { + ++next; + if(sitr->first == spell_id) { + levelspelllow = 1; + break; + } + else if(spellmgr.IsHighRankOfSpell(sitr->first,spell_id)) + { + levelspelllow = 1; + break; + } + } + if(levelspelllow) + { + return(true); + } + return(false); +} + +bool Pet::existAddSpell(uint32 spell_id) +{ + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if (!spellInfo) + { + sLog.outError("Pet::existAddSpell: Non-existed in SpellStore spell #%u request.",spell_id); + return false; + } + PetSpellMap::iterator itr = m_spells.find(spell_id); + if (itr != m_spells.end()) + { + if (itr->second->state == PETSPELL_REMOVED) + { + } + else + return false; + } + return true; +} + +bool Pet::existDeleteSpell(uint32 spell_id) +{ + PetSpellMap::iterator itr = m_spells.find(spell_id); + if (itr == m_spells.end()) + return false; + + if(itr->second->state == PETSPELL_REMOVED) + return false; + + return true; +} + + bool Pet::unlearnSpell(uint32 spell_id) { if(removeSpell(spell_id)) diff --git a/src/game/Pet.h b/src/game/Pet.h index 7f43b06..133f233 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -192,6 +192,10 @@ class Pet : public Creature bool learnSpell(uint32 spell_id); void learnSpellHighRank(uint32 spellid); void learnLevelupSpells(); + void learnLevelupSpellsWarlock(); + bool existLowRankOfSpell(uint32 spell_id); + bool existAddSpell(uint32 spell_id); + bool existDeleteSpell(uint32 spell_id); bool unlearnSpell(uint32 spell_id); bool removeSpell(uint32 spell_id); bool _removeSpell(uint32 spell_id); diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 7ef35a5..b1796fb 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -2114,6 +2114,44 @@ void SpellMgr::LoadPetLevelupSpellMap() SpellEntry const *spell; uint32 count = 0; + #define MAX_PET_SPELL_COUNT 1024 + uint32 pet_spell_db_no = 0; + uint32 pet_spell_is; + uint32 pet_spell_count; + uint32 pet_spell_data[MAX_PET_SPELL_COUNT][2]; + QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell FROM pet_levelspells"); + if(!result) + { + sLog.outErrorDb(">> Loaded 0 pet dblevel spells. DB table `pet_levelspells` is empty."); + pet_spell_db_no = 1; + } + else + { + pet_spell_count = 0; + do + { + Field *fields = result->Fetch(); + + pet_spell_data[pet_spell_count][0] = fields[0].GetUInt32(); + pet_spell_data[pet_spell_count][1] = fields[1].GetUInt32(); + + pet_spell_count++; + + if(pet_spell_count >= MAX_PET_SPELL_COUNT) + { + // Overflow Detect + sLog.outErrorDb(">> Loaded %u over pet dblevel spells. DB table `pet_levelspells`.",pet_spell_count); + break; + } + } + while ( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u spell pet dblevel spells", pet_spell_count ); + } + for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i) { creatureFamily = sCreatureFamilyStore.LookupEntry(i); @@ -2121,8 +2159,33 @@ void SpellMgr::LoadPetLevelupSpellMap() if(!creatureFamily) // not exist continue; - if(creatureFamily->petTalentType < 0) // not hunter pet family - continue; + if(pet_spell_db_no == 0) + { + //WARLOCK + switch(creatureFamily->ID) + { + case CREATURE_FAMILY_IMP: + case CREATURE_FAMILY_VOIDWALKER: + case CREATURE_FAMILY_SUCCUBUS: + case CREATURE_FAMILY_FELHUNTER: + case CREATURE_FAMILY_FELGUARD: + pet_spell_is = 1; + break; + default: + pet_spell_is = 0; + break; + } + } + else + { + pet_spell_is = 0; + } + + if(pet_spell_is == 0) + { + if(creatureFamily->petTalentType < 0) // not hunter pet family + continue; + } for(uint32 j = 0; j < sSpellStore.GetNumRows(); ++j) { @@ -2131,6 +2194,21 @@ void SpellMgr::LoadPetLevelupSpellMap() // not exist if(!spell) continue; + + //WARLOCK + if(pet_spell_is) + { + for(uint32 k = 0; k < pet_spell_count; k++) + { + if(creatureFamily->ID == pet_spell_data[k][0] && spell->Id == pet_spell_data[k][1]) + { + mPetLevelupSpellMap[creatureFamily->ID][spell->spellLevel + (k*0x10000)] = spell->Id; + count++; + break; + } + } + continue; + } // not hunter spell if(spell->SpellFamilyName != SPELLFAMILY_HUNTER)