diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 34f7b1ee9..e39c319de 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -645,8 +645,11 @@ bool Creature::isCanIneractWithBattleMaster(Player* pPlayer, bool msg) const case BATTLEGROUND_NA: case BATTLEGROUND_BE: case BATTLEGROUND_AA: - case BATTLEGROUND_RL: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break; - break; + case BATTLEGROUND_RL: + case BATTLEGROUND_SA: + case BATTLEGROUND_DS: + case BATTLEGROUND_RV: pPlayer->PlayerTalkClass->SendGossipMenu(10024,GetGUID()); break; + default: break; } return false; } @@ -1353,11 +1356,7 @@ void Creature::LoadEquipment(uint32 equip_entry, bool force) if (force) { for (uint8 i = 0; i < 3; i++) - { - SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, 0); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), 0); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, 0); - } + SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0); m_equipmentId = 0; } return; @@ -1369,11 +1368,7 @@ void Creature::LoadEquipment(uint32 equip_entry, bool force) m_equipmentId = equip_entry; for (uint8 i = 0; i < 3; i++) - { - SetUInt32Value( UNIT_VIRTUAL_ITEM_SLOT_DISPLAY + i, einfo->equipmodel[i]); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2), einfo->equipinfo[i]); - SetUInt32Value( UNIT_VIRTUAL_ITEM_INFO + (i * 2) + 1, einfo->equipslot[i]); - } + SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->equipentry[i]); } bool Creature::hasQuest(uint32 quest_id) const diff --git a/src/game/Creature.h b/src/game/Creature.h index 5d0ff9cf7..05a65be6b 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -210,9 +210,7 @@ struct CreatureLocale struct EquipmentInfo { uint32 entry; - uint32 equipmodel[3]; - uint32 equipinfo[3]; - uint32 equipslot[3]; + uint32 equipentry[3]; }; // from `creature` table diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index dc2aee43d..b9fb5033a 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -123,10 +123,10 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float SetFloatValue(GAMEOBJECT_POS_Z, z); SetFloatValue(GAMEOBJECT_FACING, ang); //this is not facing angle - SetFloatValue (GAMEOBJECT_ROTATION, rotation0); - SetFloatValue (GAMEOBJECT_ROTATION+1, rotation1); - SetFloatValue (GAMEOBJECT_ROTATION+2, rotation2); - SetFloatValue (GAMEOBJECT_ROTATION+3, rotation3); + SetFloatValue(GAMEOBJECT_PARENTROTATION, rotation0); + SetFloatValue(GAMEOBJECT_PARENTROTATION+1, rotation1); + SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2); + SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3); SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); @@ -510,10 +510,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask) data.posY = GetFloatValue(GAMEOBJECT_POS_Y); data.posZ = GetFloatValue(GAMEOBJECT_POS_Z); data.orientation = GetFloatValue(GAMEOBJECT_FACING); - data.rotation0 = GetFloatValue(GAMEOBJECT_ROTATION+0); - data.rotation1 = GetFloatValue(GAMEOBJECT_ROTATION+1); - data.rotation2 = GetFloatValue(GAMEOBJECT_ROTATION+2); - data.rotation3 = GetFloatValue(GAMEOBJECT_ROTATION+3); + data.rotation0 = GetFloatValue(GAMEOBJECT_PARENTROTATION+0); + data.rotation1 = GetFloatValue(GAMEOBJECT_PARENTROTATION+1); + data.rotation2 = GetFloatValue(GAMEOBJECT_PARENTROTATION+2); + data.rotation3 = GetFloatValue(GAMEOBJECT_PARENTROTATION+3); data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime; data.animprogress = GetGoAnimProgress(); data.go_state = GetGoState(); @@ -530,10 +530,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask) << GetFloatValue(GAMEOBJECT_POS_Y) << ", " << GetFloatValue(GAMEOBJECT_POS_Z) << ", " << GetFloatValue(GAMEOBJECT_FACING) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+1) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+2) << ", " - << GetFloatValue(GAMEOBJECT_ROTATION+3) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+1) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+2) << ", " + << GetFloatValue(GAMEOBJECT_PARENTROTATION+3) << ", " << m_respawnDelayTime << ", " << (uint32)GetGoAnimProgress() << ", " << (uint32)GetGoState() << ")"; @@ -1222,6 +1222,26 @@ void GameObject::Use(Unit* user) } break; } + case GAMEOBJECT_TYPE_BARBER_CHAIR: //32 + { + GameObjectInfo const* info = GetGOInfo(); + if(!info) + return; + + if(user->GetTypeId()!=TYPEID_PLAYER) + return; + + Player* player = (Player*)user; + + // fallback, will always work + player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET); + + WorldPacket data(SMSG_ENABLE_BARBER_SHOP, 0); + player->GetSession()->SendPacket(&data); + + player->SetStandState(PLAYER_STATE_SIT_LOW_CHAIR+info->barberChair.chairheight); + return; + } default: sLog.outDebug("Unknown Object Type %u", GetGoType()); break; diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 1fab1492a..3f05bff67 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -334,12 +334,12 @@ struct GameObjectInfo uint32 mapID; //0 uint32 difficulty; //1 } dungeonDifficulty; - //32 GAMEOBJECT_TYPE_DO_NOT_USE_YET + //32 GAMEOBJECT_TYPE_BARBER_CHAIR struct { - uint32 mapID; //0 - uint32 difficulty; //1 - } doNotUseYet; + uint32 chairheight; //0 + uint32 heightOffset; //1 + } barberChair; //33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING struct { @@ -348,6 +348,13 @@ struct GameObjectInfo uint32 state1Name; //2 uint32 state2Name; //3 } destructibleBuilding; + //34 GAMEOBJECT_TYPE_TRAPDOOR + struct + { + uint32 whenToPause; // 0 + uint32 startOpen; // 1 + uint32 autoClose; // 2 + } trapDoor; // not use for specific field access (only for output with loop by all filed), also this determinate max union size struct // GAMEOBJECT_TYPE_SPELLCASTER @@ -497,14 +504,14 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject void SetSpellId(uint32 id) { m_spellId = id;} uint32 GetSpellId() const { return m_spellId;} void getFishLoot(Loot *loot); - GameobjectTypes GetGoType() const { return GameobjectTypes(GetUInt32Value(GAMEOBJECT_TYPE_ID)); } - void SetGoType(GameobjectTypes type) { SetUInt32Value(GAMEOBJECT_TYPE_ID, type); } - uint32 GetGoState() const { return GetUInt32Value(GAMEOBJECT_STATE); } - void SetGoState(uint32 state) { SetUInt32Value(GAMEOBJECT_STATE, state); } - uint32 GetGoArtKit() const { return GetUInt32Value(GAMEOBJECT_ARTKIT); } - void SetGoArtKit(uint32 artkit) { SetUInt32Value(GAMEOBJECT_ARTKIT, artkit); } - uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); } - void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); } + GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); } + void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); } + uint8 GetGoState() const { return GetByteValue(GAMEOBJECT_BYTES_1, 0); } + void SetGoState(uint8 state) { SetByteValue(GAMEOBJECT_BYTES_1, 0, state); } + uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); } + void SetGoArtKit(uint8 artkit) { SetByteValue(GAMEOBJECT_BYTES_1, 2, artkit); } + uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); } + void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); } void Use(Unit* user); diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 9f9f12d6d..ad8d2e093 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -39,27 +39,6 @@ char const* petTypeSuffix[MAX_PET_TYPE] = "'s Companion" // MINI_PET }; -//numbers represent minutes * 100 while happy (you get 100 loyalty points per min while happy) -uint32 const LevelUpLoyalty[6] = -{ - 5500, - 11500, - 17000, - 23500, - 31000, - 39500, -}; - -uint32 const LevelStartLoyalty[6] = -{ - 2000, - 4500, - 7000, - 10000, - 13500, - 17500, -}; - Pet::Pet(PetType type) : Creature() { m_isPet = true; @@ -69,12 +48,9 @@ Pet::Pet(PetType type) : Creature() m_removed = false; m_regenTimer = 4000; m_happinessTimer = 7500; - m_loyaltyTimer = 12000; m_duration = 0; m_bonusdamage = 0; - m_loyaltyPoints = 0; - m_TrainingPoints = 0; m_resetTalentsCost = 0; m_resetTalentsTime = 0; @@ -130,19 +106,19 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu QueryResult *result; if(petnumber) - // known petnumber entry 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND id = '%u'",ownerid, petnumber); + // known petnumber entry 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, 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 17 18 19 20 21 22 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND slot = '0'",ownerid ); + // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND slot = '0'",ownerid ); 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 17 18 19 20 21 22 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '0' OR slot = '3') ",ownerid, petentry ); + // 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '0' OR slot = '3') ",ownerid, petentry ); 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 17 18 19 20 21 22 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3') ",ownerid); + // 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3') ",ownerid); if(!result) return false; @@ -157,7 +133,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu return false; } - uint32 summon_spell_id = fields[21].GetUInt32(); + uint32 summon_spell_id = fields[19].GetUInt32(); SpellEntry const* spellInfo = sSpellStore.LookupEntry(summon_spell_id); bool is_temporary_summoned = spellInfo && GetSpellDuration(spellInfo) > 0; @@ -170,7 +146,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu } Map *map = owner->GetMap(); - uint32 guid=objmgr.GenerateLowGuid(HIGHGUID_PET); + uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_PET); uint32 pet_number = fields[0].GetUInt32(); if(!Create(guid, map, petentry, pet_number)) { @@ -179,7 +155,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu } float px, py, pz; - owner->GetClosePoint(px, py, pz,GetObjectSize(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); + owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); Relocate(px, py, pz, owner->GetOrientation()); @@ -190,8 +166,8 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu return false; } - setPetType(PetType(fields[22].GetUInt8())); - SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction()); + setPetType(PetType(fields[20].GetUInt8())); + SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction()); SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); CreatureInfo const *cinfo = GetCreatureInfo(); @@ -202,72 +178,67 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu delete result; return true; } - if(getPetType()==HUNTER_PET || getPetType()==SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK) + + if(getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK) m_charmInfo->SetPetNumber(pet_number, true); else m_charmInfo->SetPetNumber(pet_number, false); + SetUInt64Value(UNIT_FIELD_SUMMONEDBY, owner->GetGUID()); SetDisplayId(fields[3].GetUInt32()); SetNativeDisplayId(fields[3].GetUInt32()); - uint32 petlevel=fields[4].GetUInt32(); - SetUInt32Value(UNIT_NPC_FLAGS , 0); - SetName(fields[11].GetString()); + uint32 petlevel = fields[4].GetUInt32(); + SetUInt32Value(UNIT_NPC_FLAGS, 0); + SetName(fields[9].GetString()); switch(getPetType()) { - case SUMMON_PET: petlevel=owner->getLevel(); - SetUInt32Value(UNIT_FIELD_BYTES_0,2048); + SetUInt32Value(UNIT_FIELD_BYTES_0, 2048); 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); - SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[8].GetUInt32()); - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); - SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 ); - - if(fields[12].GetBool()) - SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED); - else - SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED); + SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[7].GetUInt32()); + SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); + SetByteValue(UNIT_FIELD_BYTES_2, 2, fields[10].GetBool() ? UNIT_RENAME_NOT_ALLOWED : UNIT_RENAME_ALLOWED); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) - SetTP(fields[9].GetInt32()); - SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); - SetPower( POWER_HAPPINESS,fields[15].GetUInt32()); + SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); + SetPower(POWER_HAPPINESS, fields[13].GetUInt32()); setPowerType(POWER_FOCUS); break; default: - sLog.outError("Pet have incorrect type (%u) for pet loading.",getPetType()); + sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType()); } - InitStatsForLevel( petlevel); + + InitStatsForLevel(petlevel); SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL)); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); SetUInt64Value(UNIT_FIELD_CREATEDBY, owner->GetGUID()); - m_charmInfo->SetReactState( ReactStates( fields[6].GetUInt8() )); - m_loyaltyPoints = fields[7].GetInt32(); + m_charmInfo->SetReactState(ReactStates(fields[6].GetUInt8())); - uint32 savedhealth = fields[13].GetUInt32(); - uint32 savedmana = fields[14].GetUInt32(); + uint32 savedhealth = fields[11].GetUInt32(); + uint32 savedmana = fields[12].GetUInt32(); // set current pet as current - if(fields[10].GetUInt32() != 0) + if(fields[8].GetUInt32() != 0) { CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE character_pet SET slot = '3' WHERE owner = '%u' AND slot = '0' AND id <> '%u'",ownerid, m_charmInfo->GetPetNumber()); - CharacterDatabase.PExecute("UPDATE character_pet SET slot = '0' WHERE owner = '%u' AND id = '%u'",ownerid, m_charmInfo->GetPetNumber()); + CharacterDatabase.PExecute("UPDATE character_pet SET slot = '3' WHERE owner = '%u' AND slot = '0' AND id <> '%u'", ownerid, m_charmInfo->GetPetNumber()); + CharacterDatabase.PExecute("UPDATE character_pet SET slot = '0' WHERE owner = '%u' AND id = '%u'", ownerid, m_charmInfo->GetPetNumber()); CharacterDatabase.CommitTransaction(); } if(!is_temporary_summoned) { // permanent controlled pets store state in DB - Tokens tokens = StrSplit(fields[16].GetString(), " "); + Tokens tokens = StrSplit(fields[14].GetString(), " "); if(tokens.size() != 20) { @@ -285,7 +256,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu } //init teach spells - tokens = StrSplit(fields[17].GetString(), " "); + tokens = StrSplit(fields[15].GetString(), " "); for (iter = tokens.begin(), index = 0; index < 4; ++iter, ++index) { uint32 tmp = atol((*iter).c_str()); @@ -300,7 +271,10 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu } // since last save (in seconds) - uint32 timediff = (time(NULL) - fields[18].GetUInt32()); + uint32 timediff = (time(NULL) - fields[16].GetUInt32()); + + m_resetTalentsCost = fields[17].GetUInt32(); + m_resetTalentsTime = fields[18].GetUInt64(); delete result; @@ -350,7 +324,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu if(owner->GetTypeId() == TYPEID_PLAYER && 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()); + 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) { @@ -408,10 +382,6 @@ void Pet::SavePetToDB(PetSaveMode mode) case PET_SAVE_IN_STABLE_SLOT_2: case PET_SAVE_NOT_IN_SLOT: { - uint32 loyalty =1; - if(getPetType()!=HUNTER_PET) - loyalty = GetLoyaltyLevel(); - uint32 owner = GUID_LOPART(GetOwnerGUID()); std::string name = m_name; CharacterDatabase.escape_string(name); @@ -428,7 +398,7 @@ void Pet::SavePetToDB(PetSaveMode mode) CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3')", owner ); // save pet std::ostringstream ss; - ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata,TeachSpelldata,savetime,resettalents_cost,resettalents_time,CreatedBySpell,PetType) " + ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " << "VALUES (" << m_charmInfo->GetPetNumber() << ", " << GetEntry() << ", " @@ -437,9 +407,7 @@ void Pet::SavePetToDB(PetSaveMode mode) << getLevel() << ", " << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", " << uint32(m_charmInfo->GetReactState()) << ", " - << m_loyaltyPoints << ", " - << GetLoyaltyLevel() << ", " - << m_TrainingPoints << ", " + << uint32(GetFreeTalentPoints()) << ", " << uint32(mode) << ", '" << name.c_str() << "', " << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", " @@ -590,14 +558,6 @@ void Pet::Update(uint32 diff) else m_happinessTimer -= diff; - if(m_loyaltyTimer <= diff) - { - TickLoyaltyChange(); - m_loyaltyTimer = 12000; - } - else - m_loyaltyTimer -= diff; - break; } default: @@ -629,83 +589,12 @@ void Pet::LooseHappiness() uint32 curValue = GetPower(POWER_HAPPINESS); if (curValue <= 0) return; - int32 addvalue = (140 >> GetLoyaltyLevel()) * 125; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs) + int32 addvalue = 670; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs) if(isInCombat()) //we know in combat happiness fades faster, multiplier guess addvalue = int32(addvalue * 1.5); ModifyPower(POWER_HAPPINESS, -addvalue); } -void Pet::ModifyLoyalty(int32 addvalue) -{ - uint32 loyaltylevel = GetLoyaltyLevel(); - - if(addvalue > 0) //only gain influenced, not loss - addvalue = int32((float)addvalue * sWorld.getRate(RATE_LOYALTY)); - - if(loyaltylevel >= BEST_FRIEND && (addvalue + m_loyaltyPoints) > int32(GetMaxLoyaltyPoints(loyaltylevel))) - return; - - m_loyaltyPoints += addvalue; - - if(m_loyaltyPoints < 0) - { - if(loyaltylevel > REBELLIOUS) - { - //level down - --loyaltylevel; - SetLoyaltyLevel(LoyaltyLevel(loyaltylevel)); - m_loyaltyPoints = GetStartLoyaltyPoints(loyaltylevel); - SetTP(m_TrainingPoints - int32(getLevel())); - } - else - { - m_loyaltyPoints = 0; - Unit* owner = GetOwner(); - if(owner && owner->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_PET_BROKEN, 0); - ((Player*)owner)->GetSession()->SendPacket(&data); - - //run away - ((Player*)owner)->RemovePet(this,PET_SAVE_AS_DELETED); - } - } - } - //level up - else if(m_loyaltyPoints > int32(GetMaxLoyaltyPoints(loyaltylevel))) - { - ++loyaltylevel; - SetLoyaltyLevel(LoyaltyLevel(loyaltylevel)); - m_loyaltyPoints = GetStartLoyaltyPoints(loyaltylevel); - SetTP(m_TrainingPoints + getLevel()); - } -} - -void Pet::TickLoyaltyChange() -{ - int32 addvalue; - - switch(GetHappinessState()) - { - case HAPPY: addvalue = 20; break; - case CONTENT: addvalue = 10; break; - case UNHAPPY: addvalue = -20; break; - default: - return; - } - ModifyLoyalty(addvalue); -} - -void Pet::KillLoyaltyBonus(uint32 level) -{ - if(level > 100) - return; - - //at lower levels gain is faster | the lower loyalty the more loyalty is gained - uint32 bonus = uint32(((100 - level) / 10) + (6 - GetLoyaltyLevel())); - ModifyLoyalty(bonus); -} - HappinessState Pet::GetHappinessState() { if(GetPower(POWER_HAPPINESS) < HAPPINESS_LEVEL_SIZE) @@ -716,11 +605,6 @@ HappinessState Pet::GetHappinessState() return CONTENT; } -void Pet::SetLoyaltyLevel(LoyaltyLevel level) -{ - SetByteValue(UNIT_FIELD_BYTES_1, 1, level); -} - bool Pet::CanTakeMoreActiveSpells(uint32 spellid) { uint8 activecount = 1; @@ -757,82 +641,6 @@ bool Pet::CanTakeMoreActiveSpells(uint32 spellid) return true; } -bool Pet::HasTPForSpell(uint32 spellid) -{ - int32 neededtrainp = GetTPForSpell(spellid); - if((m_TrainingPoints - neededtrainp < 0 || neededtrainp < 0) && neededtrainp != 0) - return false; - return true; -} - -int32 Pet::GetTPForSpell(uint32 spellid) -{ - uint32 basetrainp = 0; - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellid); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellid); - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - if(!_spell_idx->second->reqtrainpoints) - return 0; - - basetrainp = _spell_idx->second->reqtrainpoints; - break; - } - - uint32 spenttrainp = 0; - uint32 chainstart = spellmgr.GetFirstSpellInChain(spellid); - - for (PetSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if(itr->second->state == PETSPELL_REMOVED) - continue; - - if(spellmgr.GetFirstSpellInChain(itr->first) == chainstart) - { - SkillLineAbilityMap::const_iterator _lower = spellmgr.GetBeginSkillLineAbilityMap(itr->first); - SkillLineAbilityMap::const_iterator _upper = spellmgr.GetEndSkillLineAbilityMap(itr->first); - - for(SkillLineAbilityMap::const_iterator _spell_idx2 = _lower; _spell_idx2 != _upper; ++_spell_idx2) - { - if(_spell_idx2->second->reqtrainpoints > spenttrainp) - { - spenttrainp = _spell_idx2->second->reqtrainpoints; - break; - } - } - } - } - - return int32(basetrainp) - int32(spenttrainp); -} - -uint32 Pet::GetMaxLoyaltyPoints(uint32 level) -{ - return LevelUpLoyalty[level - 1]; -} - -uint32 Pet::GetStartLoyaltyPoints(uint32 level) -{ - return LevelStartLoyalty[level - 1]; -} - -void Pet::SetTP(int32 TP) -{ - m_TrainingPoints = TP; - SetUInt32Value(UNIT_TRAINING_POINTS, (uint32)GetDispTP()); -} - -int32 Pet::GetDispTP() -{ - if(getPetType()!= HUNTER_PET) - return(0); - if(m_TrainingPoints < 0) - return -m_TrainingPoints; - else - return -(m_TrainingPoints + 1); -} - void Pet::Remove(PetSaveMode mode, bool returnreagent) { Unit* owner = GetOwner(); @@ -895,9 +703,6 @@ void Pet::GivePetXP(uint32 xp) } SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, newXP); - - if(getPetType() == HUNTER_PET) - KillLoyaltyBonus(level); } void Pet::GivePetLevel(uint32 level) @@ -905,9 +710,7 @@ void Pet::GivePetLevel(uint32 level) if(!level) return; - InitStatsForLevel( level); - - SetTP(m_TrainingPoints + (GetLoyaltyLevel() - 1)); + InitStatsForLevel(level); } bool Pet::CreateBaseAtCreature(Creature* creature) @@ -949,14 +752,14 @@ bool Pet::CreateBaseAtCreature(Creature* creature) } SetDisplayId(creature->GetDisplayId()); SetNativeDisplayId(creature->GetNativeDisplayId()); - SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS)); - SetPower( POWER_HAPPINESS,166500); + SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); + SetPower(POWER_HAPPINESS, 166500); setPowerType(POWER_FOCUS); - SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0); - SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); + SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); + SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, uint32((MaNGOS::XP::xp_to_level(creature->getLevel()))/4)); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - SetUInt32Value(UNIT_NPC_FLAGS , 0); + SetUInt32Value(UNIT_NPC_FLAGS, 0); CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(creature->GetCreatureInfo()->family); if( char* familyname = cFamily->Name[sWorld.GetDefaultDbcLocale()] ) @@ -964,16 +767,12 @@ bool Pet::CreateBaseAtCreature(Creature* creature) else SetName(creature->GetName()); - m_loyaltyPoints = 1000; if(cinfo->type == CREATURE_TYPE_BEAST) { SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); - SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 ); SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED); - - SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED) ); - SetLoyaltyLevel(REBELLIOUS); + SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED)); } return true; } @@ -992,7 +791,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel) uint32 creature_ID = (getPetType() == HUNTER_PET) ? 1 : cinfo->Entry; - SetLevel( petlevel); + SetLevel(petlevel); SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); @@ -1081,7 +880,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel) for(int stat = 0; stat < MAX_STATS; ++stat) { - SetCreateStat(Stats(stat),float(pInfo->stats[stat])); + SetCreateStat(Stats(stat), float(pInfo->stats[stat])); } } else // not exist in DB, use some default fake data @@ -1092,11 +891,11 @@ bool Pet::InitStatsForLevel(uint32 petlevel) SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); SetCreateMana( uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); - SetCreateStat(STAT_STRENGTH,22); - SetCreateStat(STAT_AGILITY,22); - SetCreateStat(STAT_STAMINA,25); - SetCreateStat(STAT_INTELLECT,28); - SetCreateStat(STAT_SPIRIT,27); + SetCreateStat(STAT_STRENGTH, 22); + SetCreateStat(STAT_AGILITY, 22); + SetCreateStat(STAT_STAMINA, 25); + SetCreateStat(STAT_INTELLECT, 28); + SetCreateStat(STAT_SPIRIT, 27); } break; } @@ -1131,34 +930,35 @@ bool Pet::InitStatsForLevel(uint32 petlevel) // remove elite bonuses included in DB values SetCreateHealth( uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->rank)) * petlevel) ); - SetCreateStat(STAT_STRENGTH,22); - SetCreateStat(STAT_AGILITY,22); - SetCreateStat(STAT_STAMINA,25); - SetCreateStat(STAT_INTELLECT,28); - SetCreateStat(STAT_SPIRIT,27); + SetCreateStat(STAT_STRENGTH, 22); + SetCreateStat(STAT_AGILITY, 22); + SetCreateStat(STAT_STAMINA, 25); + SetCreateStat(STAT_INTELLECT, 28); + SetCreateStat(STAT_SPIRIT, 27); } break; } case GUARDIAN_PET: - SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0); - SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000); + SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); + SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000); - SetCreateMana( 28 + 10*petlevel ); - SetCreateHealth( 28 + 30*petlevel ); + SetCreateMana(28 + 10*petlevel); + SetCreateHealth(28 + 30*petlevel); // FIXME: this is wrong formula, possible each guardian pet have own damage formula //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 - SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)) ); + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4))); //damage range is then petlevel / 2 - SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)) ); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); break; default: - sLog.outError("Pet have incorrect type (%u) for levelup.",getPetType()); break; + sLog.outError("Pet have incorrect type (%u) for levelup.", getPetType()); + break; } for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]) ); + SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i])); UpdateAllStats(); @@ -1189,7 +989,7 @@ bool Pet::HaveInDiet(ItemPrototype const* item) const uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) { // -5 or greater food level - if(getLevel() <= itemlevel +5) //possible to feed level 60 pet with level 55 level food for full effect + if(getLevel() <= itemlevel + 5) //possible to feed level 60 pet with level 55 level food for full effect return 35000; // -10..-6 else if(getLevel() <= itemlevel + 10) //pure guess, but sounds good @@ -1239,7 +1039,7 @@ void Pet::_LoadSpellCooldowns() _AddCreatureSpellCooldown(spell_id,db_time); - sLog.outDebug("Pet (Number: %u) spell %u cooldown loaded (%u secs).",m_charmInfo->GetPetNumber(),spell_id,uint32(db_time-curTime)); + sLog.outDebug("Pet (Number: %u) spell %u cooldown loaded (%u secs).", m_charmInfo->GetPetNumber(), spell_id, uint32(db_time-curTime)); } while( result->NextRow() ); @@ -1313,10 +1113,6 @@ void Pet::_LoadAuras(uint32 timediff) for (int i = 0; i < TOTAL_AURAS; i++) m_modAuras[i].clear(); - // all aura related fields - for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i) - SetUInt32Value(i, 0); - QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); if(result) @@ -1382,7 +1178,7 @@ void Pet::_LoadAuras(uint32 timediff) void Pet::_SaveAuras() { - CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'",m_charmInfo->GetPetNumber()); + CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'", m_charmInfo->GetPetNumber()); AuraMap const& auras = GetAuras(); for(AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) @@ -1483,7 +1279,7 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s } } - uint16 tmpslot=slot_id; + uint16 tmpslot = slot_id; if (tmpslot == 0xffff) { @@ -1500,6 +1296,16 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s newspell->slotId = tmpslot; m_spells[spell_id] = newspell; + if(GetOwner()->GetTypeId() == TYPEID_PLAYER) + { + if(!IsPassiveSpell(spell_id)) + { + WorldPacket data(SMSG_PET_LEARNED_SPELL, 2); + data << uint16(spell_id); + ((Player*)GetOwner())->GetSession()->SendPacket(&data); + } + } + if (IsPassiveSpell(spell_id)) CastSpell(this, spell_id, true); else if(state == PETSPELL_NEW) @@ -1518,7 +1324,7 @@ bool Pet::learnSpell(uint16 spell_id) return false; Unit* owner = GetOwner(); - if(owner->GetTypeId()==TYPEID_PLAYER) + if(owner->GetTypeId() == TYPEID_PLAYER) ((Player*)owner)->PetSpellInitialize(); return true; } @@ -1541,6 +1347,16 @@ void Pet::removeSpell(uint16 spell_id) itr->second->state = PETSPELL_REMOVED; RemoveAurasDueToSpell(spell_id); + + if(GetOwner()->GetTypeId() == TYPEID_PLAYER) + { + if(!IsPassiveSpell(spell_id)) + { + WorldPacket data(SMSG_PET_UNLEARNED_SPELL, 2); + data << uint16(spell_id); + ((Player*)GetOwner())->GetSession()->SendPacket(&data); + } + } } bool Pet::_removeSpell(uint16 spell_id) @@ -1560,7 +1376,7 @@ void Pet::InitPetCreateSpells() m_charmInfo->InitPetActionBar(); m_spells.clear(); - int32 usedtrainpoints = 0, petspellid; + int32 petspellid; PetCreateSpellEntry const* CreateSpells = objmgr.GetPetCreateSpellEntry(GetEntry()); if(CreateSpells) { @@ -1589,23 +1405,12 @@ void Pet::InitPetCreateSpells() petspellid = learn_spellproto->Id; addSpell(petspellid); - - SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(learn_spellproto->EffectTriggerSpell[0]); - SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(learn_spellproto->EffectTriggerSpell[0]); - - for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx) - { - usedtrainpoints += _spell_idx->second->reqtrainpoints; - break; - } } } LearnPetPassives(); CastPetAuras(false); - - SetTP(-usedtrainpoints); } void Pet::CheckLearning(uint32 spellid) @@ -1693,8 +1498,7 @@ bool Pet::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number) if(!InitEntry(Entry)) return false; - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); - SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5 ); + SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); if(getPetType() == MINI_PET) // always non-attackable SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -1735,7 +1539,7 @@ void Pet::CastPetAuras(bool current) if(getPetType() != HUNTER_PET && (getPetType() != SUMMON_PET || owner->getClass() != CLASS_WARLOCK)) return; - for(PetAuraSet::iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end(); ) + for(PetAuraSet::iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();) { PetAura const* pa = *itr; ++itr; @@ -1756,7 +1560,7 @@ void Pet::CastPetAura(PetAura const* aura) if(auraId == 35696) // Demonic Knowledge { int32 basePoints = int32(aura->GetDamage() * (GetStat(STAT_STAMINA) + GetStat(STAT_INTELLECT)) / 100); - CastCustomSpell(this,auraId,&basePoints, NULL, NULL, true ); + CastCustomSpell(this, auraId, &basePoints, NULL, NULL, true); } else CastSpell(this, auraId, true); diff --git a/src/game/Pet.h b/src/game/Pet.h index f7a372adf..ab349fc72 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -50,16 +50,6 @@ enum HappinessState HAPPY = 3 }; -enum LoyaltyLevel -{ - REBELLIOUS = 1, - UNRULY = 2, - SUBMISSIVE = 3, - DEPENDABLE = 4, - FAITHFUL = 5, - BEST_FRIEND = 6 -}; - enum PetSpellState { PETSPELL_UNCHANGED = 0, @@ -119,9 +109,6 @@ typedef std::vector AutoSpellList; #define HAPPINESS_LEVEL_SIZE 333000 -extern const uint32 LevelUpLoyalty[6]; -extern const uint32 LevelStartLoyalty[6]; - #define ACTIVE_SPELLS_MAX 4 #define OWNER_MAX_DISTANCE 100 @@ -144,7 +131,7 @@ class Pet : public Creature bool isTemporarySummoned() const { return m_duration > 0; } bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number); - bool CreateBaseAtCreature( Creature* creature ); + bool CreateBaseAtCreature(Creature* creature); bool LoadPetFromDB( Unit* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false ); void SavePetToDB(PetSaveMode mode); void Remove(PetSaveMode mode, bool returnreagent = false); @@ -164,14 +151,7 @@ class Pet : public Creature void RegenerateFocus(); void LooseHappiness(); - void TickLoyaltyChange(); - void ModifyLoyalty(int32 addvalue); HappinessState GetHappinessState(); - uint32 GetMaxLoyaltyPoints(uint32 level); - uint32 GetStartLoyaltyPoints(uint32 level); - void KillLoyaltyBonus(uint32 level); - uint32 GetLoyaltyLevel() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); } - void SetLoyaltyLevel(LoyaltyLevel level); void GivePetXP(uint32 xp); void GivePetLevel(uint32 level); bool InitStatsForLevel(uint32 level); @@ -191,10 +171,8 @@ class Pet : public Creature void UpdateAttackPowerAndDamage(bool ranged = false); void UpdateDamagePhysical(WeaponAttackType attType); - bool CanTakeMoreActiveSpells(uint32 SpellIconID); - void ToggleAutocast(uint32 spellid, bool apply); - bool HasTPForSpell(uint32 spellid); - int32 GetTPForSpell(uint32 spellid); + bool CanTakeMoreActiveSpells(uint32 SpellIconID); + void ToggleAutocast(uint32 spellid, bool apply); bool HasSpell(uint32 spell) const; void AddTeachSpell(uint32 learned_id, uint32 source_id) { m_teachspells[learned_id] = source_id; } @@ -222,11 +200,10 @@ class Pet : public Creature void InitPetCreateSpells(); void CheckLearning(uint32 spellid); uint32 resetTalentsCost() const; + uint8 GetMaxTalentPointsForLevel(uint32 level) { return (level >= 20) ? ((level - 16) / 4) : 0; } + uint8 GetFreeTalentPoints() { return GetByteValue(UNIT_FIELD_BYTES_1, 1); } + void SetFreeTalentPoints(uint8 points) { SetByteValue(UNIT_FIELD_BYTES_1, 1, points); } - void SetTP(int32 TP); - int32 GetDispTP(); - - int32 m_TrainingPoints; uint32 m_resetTalentsCost; time_t m_resetTalentsTime; @@ -240,10 +217,8 @@ class Pet : public Creature protected: uint32 m_regenTimer; uint32 m_happinessTimer; - uint32 m_loyaltyTimer; PetType m_petType; int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets) - int32 m_loyaltyPoints; int32 m_bonusdamage; uint64 m_auraUpdateMask; diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 197c6b2ef..a1d5d896b 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -34,7 +34,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) { - CHECK_PACKET_SIZE(recv_data,8+2+2+8); + CHECK_PACKET_SIZE(recv_data, 8+2+2+8); uint64 guid1; uint16 spellid; @@ -46,8 +46,8 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) recv_data >> guid2; //tag guid // used also for charmed creature - Unit* pet= ObjectAccessor::GetUnit(*_player,guid1); - sLog.outDetail( "HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) ); + Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); + sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) ); if(!pet) { sLog.outError( "Pet %u not exist.\n", uint32(GUID_LOPART(guid1)) ); @@ -56,7 +56,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) { - sLog.outError( "HandlePetAction.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid1)),GetPlayer()->GetName() ); + sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.\n", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() ); return; } @@ -234,7 +234,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS)) { WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint32(spellid) << uint8(2) << uint8(result); + data << uint8(0) << uint32(spellid) << uint8(result); switch (result) { case SPELL_FAILED_REQUIRES_SPELL_FOCUS: @@ -304,7 +304,7 @@ void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber) void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) { - CHECK_PACKET_SIZE(recv_data,8+4+2+2); + CHECK_PACKET_SIZE(recv_data, 8+4+2+2); sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION\n" ); @@ -519,8 +519,6 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket) pet->removeSpell(spell_id); } - pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1)); - for(uint8 i = 0; i < 10; i++) { if(charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) @@ -590,11 +588,15 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) { sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); - CHECK_PACKET_SIZE(recvPacket,8+4); + CHECK_PACKET_SIZE(recvPacket,8+1+4+1); uint64 guid; uint32 spellid; + uint8 cast_count; + uint8 unk_flags; // flags (if 0x02 - some additional data are received) - recvPacket >> guid >> spellid; + recvPacket >> guid >> cast_count >> spellid >> unk_flags; + + sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags); if(!_player->GetPet() && !_player->GetCharm()) return; @@ -628,6 +630,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) pet->clearUnitState(UNIT_STAT_FOLLOW); Spell *spell = new Spell(pet, spellInfo, false); + spell->m_cast_count = cast_count; // probably pending spell cast spell->m_targets = targets; int16 result = spell->PetCanCast(NULL); @@ -674,3 +677,129 @@ void WorldSession::SendPetNameInvalid(uint32 error, std::string name, DeclinedNa data << uint8(0); SendPacket(&data); } + +void WorldSession::HandlePetLearnTalent( WorldPacket & recv_data ) +{ + sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT"); + recv_data.hexlike(); + + CHECK_PACKET_SIZE(recv_data, 8+4+4); + + uint64 guid; + uint32 talent_id, requested_rank; + recv_data >> guid >> talent_id >> requested_rank; + + Pet *pet = _player->GetPet(); + + if(!pet) + return; + + if(guid != pet->GetGUID()) + return; + + uint32 CurTalentPoints = pet->GetFreeTalentPoints(); + + if(CurTalentPoints == 0) + return; + + if (requested_rank > 4) + return; + + TalentEntry const *talentInfo = sTalentStore.LookupEntry(talent_id); + + if(!talentInfo) + return; + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); + + if(!talentTabInfo) + return; + + CreatureInfo const *ci = pet->GetCreatureInfo(); + + if(!ci) + return; + + CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + + if(!pet_family) + return; + + // prevent learn talent for different family (cheating) + if(!((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask)) + return; + + // prevent skip talent ranks (cheating) + if(requested_rank > 0 && !pet->HasSpell(talentInfo->RankID[requested_rank-1])) + return; + + // Check if it requires another talent + if (talentInfo->DependsOn > 0) + { + if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn)) + { + bool hasEnoughRank = false; + for (int i = talentInfo->DependsOnRank; i <= 4; i++) + { + if (depTalentInfo->RankID[i] != 0) + if (pet->HasSpell(depTalentInfo->RankID[i])) + hasEnoughRank = true; + } + if (!hasEnoughRank) + return; + } + } + + // Find out how many points we have in this field + uint32 spentPoints = 0; + + uint32 tTab = talentInfo->TalentTab; + if (talentInfo->Row > 0) + { + unsigned int numRows = sTalentStore.GetNumRows(); + for (unsigned int i = 0; i < numRows; i++) // Loop through all talents. + { + // Someday, someone needs to revamp + const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i); + if (tmpTalent) // the way talents are tracked + { + if (tmpTalent->TalentTab == tTab) + { + for (int j = 0; j <= 4; j++) + { + if (tmpTalent->RankID[j] != 0) + { + if (pet->HasSpell(tmpTalent->RankID[j])) + { + spentPoints += j + 1; + } + } + } + } + } + } + } + + // not have required min points spent in talent tree + if(spentPoints < (talentInfo->Row * 3)) + return; + + // spell not set in talent.dbc + uint32 spellid = talentInfo->RankID[requested_rank]; + if( spellid == 0 ) + { + sLog.outError("Talent.dbc have for talent: %u Rank: %u spell id = 0", talent_id, requested_rank); + return; + } + + // already known + if(pet->HasSpell(spellid)) + return; + + // learn! (other talent ranks will unlearned at learning) + pet->learnSpell(spellid); + sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid); + + // update free talent points + pet->SetFreeTalentPoints(CurTalentPoints - 1); +} diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp index d53e7ab24..186d179f8 100644 --- a/src/game/PetitionsHandler.cpp +++ b/src/game/PetitionsHandler.cpp @@ -209,9 +209,9 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) if(!charter) return; - charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow()); - // ITEM_FIELD_ENCHANTMENT is guild/arenateam id - // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item) + charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); + // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id + // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); @@ -574,7 +574,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) // update signs count on charter, required testing... //Item *item = _player->GetItemByGuid(petitionguid)); //if(item) - // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs); + // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); // update for owner if online if(Player *owner = objmgr.GetPlayer(ownerguid)) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index ab3e98e59..72da1740f 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -173,7 +173,7 @@ void PlayerTaxi::AppendTaximaskTo( ByteBuffer& data, bool all ) if(all) { for (uint8 i=0; iOrder) + SetGlyphSlot(gs->Order - 1, gs->Id); + } + // set starting level - SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) ); + if(getClass() == CLASS_DEATH_KNIGHT) + SetUInt32Value(UNIT_FIELD_LEVEL, 55); + else + SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) ); // Played time m_Last_tick = time(NULL); @@ -588,6 +601,7 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_, // base stats and related field values InitStatsForLevel(); InitTaxiNodesForLevel(); + InitGlyphsForLevel(); InitTalentForLevel(); InitPrimaryProffesions(); // to max set before any spell added @@ -1302,7 +1316,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) char_flags |= CHARACTER_FLAG_DECLINED; *p_data << (uint32)char_flags; // character flags - + *p_data << (uint32)0; // new wotlk *p_data << (uint8)1; // unknown // Pets info @@ -1750,6 +1764,8 @@ void Player::RegenerateAll() Regenerate( POWER_MANA ); + Regenerate( POWER_RUNIC_POWER ); + m_regenTimer = regenDelay; } @@ -1769,11 +1785,11 @@ void Player::Regenerate(Powers power) if (recentCast) { // Mangos Updates Mana in intervals of 2s, which is correct - addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT) * ManaIncreaseRate * 2.00f; + addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 2.00f; } else { - addvalue = GetFloatValue(PLAYER_FIELD_MOD_MANA_REGEN) * ManaIncreaseRate * 2.00f; + addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * 2.00f; } } break; case POWER_RAGE: // Regenerate rage @@ -1784,6 +1800,9 @@ void Player::Regenerate(Powers power) case POWER_ENERGY: // Regenerate energy (rogue) addvalue = 20; break; + case POWER_RUNIC_POWER: + addvalue = 100; // TODO: find correct regen rate + break; case POWER_FOCUS: case POWER_HAPPINESS: break; @@ -2082,6 +2101,8 @@ void Player::GiveLevel(uint32 level) data << uint32(0); data << uint32(0); data << uint32(0); + data << uint32(0); + data << uint32(0); // end for for(int i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4) data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i))); @@ -2105,6 +2126,7 @@ void Player::GiveLevel(uint32 level) InitTalentForLevel(); InitTaxiNodesForLevel(); + InitGlyphsForLevel(); UpdateAllStats(); @@ -2297,6 +2319,7 @@ void Player::InitStatsForLevel(bool reapplyMods) SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE)); SetPower(POWER_FOCUS, 0); SetPower(POWER_HAPPINESS, 0); + SetPower(POWER_RUNIC_POWER, 0); } void Player::SendInitialSpells() @@ -3193,50 +3216,46 @@ void Player::InitVisibleBits() { updateVisualBits.SetCount(PLAYER_END); - // TODO: really implement OWNER_ONLY and GROUP_ONLY. Flags can be found in UpdateFields.h - updateVisualBits.SetBit(OBJECT_FIELD_GUID); updateVisualBits.SetBit(OBJECT_FIELD_TYPE); + updateVisualBits.SetBit(OBJECT_FIELD_ENTRY); updateVisualBits.SetBit(OBJECT_FIELD_SCALE_X); - - updateVisualBits.SetBit(UNIT_FIELD_CHARM); - updateVisualBits.SetBit(UNIT_FIELD_CHARM+1); - - updateVisualBits.SetBit(UNIT_FIELD_SUMMON); - updateVisualBits.SetBit(UNIT_FIELD_SUMMON+1); - - updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY); - updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY+1); - - updateVisualBits.SetBit(UNIT_FIELD_TARGET); - updateVisualBits.SetBit(UNIT_FIELD_TARGET+1); - - updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT); - updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT+1); - + updateVisualBits.SetBit(UNIT_FIELD_CHARM + 0); + updateVisualBits.SetBit(UNIT_FIELD_CHARM + 1); + updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 0); + updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 1); + updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 0); + updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 1); + updateVisualBits.SetBit(UNIT_FIELD_TARGET + 0); + updateVisualBits.SetBit(UNIT_FIELD_TARGET + 1); + updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT + 0); + updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT + 1); + updateVisualBits.SetBit(UNIT_FIELD_BYTES_0); updateVisualBits.SetBit(UNIT_FIELD_HEALTH); updateVisualBits.SetBit(UNIT_FIELD_POWER1); updateVisualBits.SetBit(UNIT_FIELD_POWER2); updateVisualBits.SetBit(UNIT_FIELD_POWER3); updateVisualBits.SetBit(UNIT_FIELD_POWER4); updateVisualBits.SetBit(UNIT_FIELD_POWER5); - + updateVisualBits.SetBit(UNIT_FIELD_POWER6); + updateVisualBits.SetBit(UNIT_FIELD_POWER7); updateVisualBits.SetBit(UNIT_FIELD_MAXHEALTH); updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER1); updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER2); updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER3); updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER4); updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER5); - + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER6); + updateVisualBits.SetBit(UNIT_FIELD_MAXPOWER7); updateVisualBits.SetBit(UNIT_FIELD_LEVEL); updateVisualBits.SetBit(UNIT_FIELD_FACTIONTEMPLATE); - updateVisualBits.SetBit(UNIT_FIELD_BYTES_0); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 0); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 1); + updateVisualBits.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 2); updateVisualBits.SetBit(UNIT_FIELD_FLAGS); updateVisualBits.SetBit(UNIT_FIELD_FLAGS_2); - for(uint16 i = UNIT_FIELD_AURA; i < UNIT_FIELD_AURASTATE; ++i) - updateVisualBits.SetBit(i); updateVisualBits.SetBit(UNIT_FIELD_AURASTATE); - updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME); + updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 0); updateVisualBits.SetBit(UNIT_FIELD_BASEATTACKTIME + 1); updateVisualBits.SetBit(UNIT_FIELD_BOUNDINGRADIUS); updateVisualBits.SetBit(UNIT_FIELD_COMBATREACH); @@ -3249,10 +3268,12 @@ void Player::InitVisibleBits() updateVisualBits.SetBit(UNIT_DYNAMIC_FLAGS); updateVisualBits.SetBit(UNIT_CHANNEL_SPELL); updateVisualBits.SetBit(UNIT_MOD_CAST_SPEED); + updateVisualBits.SetBit(UNIT_FIELD_BASE_MANA); updateVisualBits.SetBit(UNIT_FIELD_BYTES_2); + updateVisualBits.SetBit(UNIT_FIELD_HOVERHEIGHT); - updateVisualBits.SetBit(PLAYER_DUEL_ARBITER); - updateVisualBits.SetBit(PLAYER_DUEL_ARBITER+1); + updateVisualBits.SetBit(PLAYER_DUEL_ARBITER + 0); + updateVisualBits.SetBit(PLAYER_DUEL_ARBITER + 1); updateVisualBits.SetBit(PLAYER_FLAGS); updateVisualBits.SetBit(PLAYER_GUILDID); updateVisualBits.SetBit(PLAYER_GUILDRANK); @@ -3263,29 +3284,29 @@ void Player::InitVisibleBits() updateVisualBits.SetBit(PLAYER_GUILD_TIMESTAMP); // PLAYER_QUEST_LOG_x also visible bit on official (but only on party/raid)... - for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i+=4) + for(uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i += 4) updateVisualBits.SetBit(i); - //Players visible items are not inventory stuff - //431) = 884 (0x374) = main weapon - for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++) + // Players visible items are not inventory stuff + for(uint16 i = 0; i < EQUIPMENT_SLOT_END; ++i) { - // item creator - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 0); - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + (i*MAX_VISIBLE_ITEM_OFFSET) + 1); + uint32 offset = i * MAX_VISIBLE_ITEM_OFFSET; - uint16 visual_base = PLAYER_VISIBLE_ITEM_1_0 + (i*MAX_VISIBLE_ITEM_OFFSET); + // item creator + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + 0 + offset); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_CREATOR + 1 + offset); // item entry - updateVisualBits.SetBit(visual_base + 0); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_0 + 0 + offset); - // item enchantment IDs - for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) - updateVisualBits.SetBit(visual_base + 1 + j); + // item enchantments + for(uint8 j = 0; j < MAX_ENCHANTMENT_SLOT; ++j) + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_0 + 1 + j + offset); // random properties - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 0 + (i*MAX_VISIBLE_ITEM_OFFSET)); - updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + 1 + (i*MAX_VISIBLE_ITEM_OFFSET)); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PROPERTIES + offset); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_SEED + offset); + updateVisualBits.SetBit(PLAYER_VISIBLE_ITEM_1_PAD + offset); } updateVisualBits.SetBit(PLAYER_CHOSEN_TITLE); @@ -3303,7 +3324,6 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) if(target == this) { - for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { if(m_items[i] == NULL) @@ -3311,7 +3331,7 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) m_items[i]->BuildCreateUpdateBlockForPlayer( data, target ); } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { if(m_items[i] == NULL) continue; @@ -3337,7 +3357,6 @@ void Player::DestroyForPlayer( Player *target ) const if(target == this) { - for(int i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { if(m_items[i] == NULL) @@ -3345,7 +3364,7 @@ void Player::DestroyForPlayer( Player *target ) const m_items[i]->DestroyForPlayer( target ); } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { if(m_items[i] == NULL) continue; @@ -3697,7 +3716,7 @@ void Player::ResurrectPlayer(float restore_percent, bool updateToWorld, bool app if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i)) { Aur->SetAuraDuration(delta*1000); - Aur->UpdateAuraDuration(); + Aur->SendAuraUpdate(false); } } } @@ -5320,6 +5339,7 @@ void Player::SendFactionState(FactionState const* faction) const { WorldPacket data(SMSG_SET_FACTION_STANDING, (16)); // last check 2.4.0 data << (float) 0; // unk 2.4.0 + data << (uint8) 0; // wotlk 8634 data << (uint32) 1; // count // for data << (uint32) faction->ReputationListID; @@ -6375,19 +6395,43 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) sLog.outDebug("_ApplyItemMods complete."); } -void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply) +void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply) { if(slot >= INVENTORY_SLOT_BAG_END || !proto) return; for (int i = 0; i < 10; i++) { - float val = float (proto->ItemStat[i].ItemStatValue); + uint32 statType = 0; + int32 val = 0; - if(val==0) + if(proto->ScalingStatDistribution) + { + if(ScalingStatDistributionEntry const *ssd = sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution)) + { + statType = ssd->StatMod[i]; + + if(uint32 modifier = ssd->Modifier[i]) + { + uint32 level = ((getLevel() > ssd->MaxLevel) ? ssd->MaxLevel : getLevel()); + if(ScalingStatValuesEntry const *ssv = sScalingStatValuesStore.LookupEntry(level)) + { + int multiplier = ssv->Multiplier[proto->GetScalingStatValuesColumn()]; + val = (multiplier * modifier) / 10000; + } + } + } + } + else + { + statType = proto->ItemStat[i].ItemStatType; + val = float(proto->ItemStat[i].ItemStatValue); + } + + if(val == 0) continue; - switch (proto->ItemStat[i].ItemStatType) + switch (statType) { case ITEM_MOD_MANA: HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply); @@ -6397,23 +6441,23 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply) break; case ITEM_MOD_AGILITY: // modify agility HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, val, apply); + ApplyStatBuffMod(STAT_AGILITY, float(val), apply); break; case ITEM_MOD_STRENGTH: //modify strength HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, val, apply); + ApplyStatBuffMod(STAT_STRENGTH, float(val), apply); break; case ITEM_MOD_INTELLECT: //modify intellect HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, val, apply); + ApplyStatBuffMod(STAT_INTELLECT, float(val), apply); break; case ITEM_MOD_SPIRIT: //modify spirit HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_SPIRIT, val, apply); + ApplyStatBuffMod(STAT_SPIRIT, float(val), apply); break; case ITEM_MOD_STAMINA: //modify stamina HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, val, apply); + ApplyStatBuffMod(STAT_STAMINA, float(val), apply); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); @@ -6505,6 +6549,9 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply) case ITEM_MOD_EXPERTISE_RATING: ApplyRatingMod(CR_EXPERTISE, int32(val), apply); break; + case ITEM_MOD_ARMOR_PENETRATION_RATING: + ApplyRatingMod(CR_ARMOR_PENETRATION, int32(val), apply); + break; } } @@ -8000,7 +8047,7 @@ uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const return EQUIP_ERR_OK; } } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem->GetEntry() == item ) @@ -8047,7 +8094,7 @@ uint32 Player::GetItemCount( uint32 item, bool inBankAlso, Item* skipItem ) cons if( pItem && pItem != skipItem && pItem->GetEntry() == item ) count += pItem->GetCount(); } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem != skipItem && pItem->GetEntry() == item ) @@ -8107,7 +8154,7 @@ Item* Player::GetItemByGuid( uint64 guid ) const if( pItem && pItem->GetGUID() == guid ) return pItem; } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem->GetGUID() == guid ) @@ -8161,7 +8208,7 @@ Item* Player::GetItemByPos( uint16 pos ) const Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const { - if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || slot >= KEYRING_SLOT_START && slot < QUESTBAG_SLOT_END ) ) return m_items[slot]; else if(bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END || bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) @@ -8239,7 +8286,7 @@ bool Player::IsInventoryPos( uint8 bag, uint8 slot ) return true; if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END ) return true; - if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END ) ) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < QUESTBAG_SLOT_END ) ) return true; return false; } @@ -8288,7 +8335,7 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const return true; } } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem->GetEntry() == item ) @@ -8416,7 +8463,7 @@ bool Player::HasItemTotemCategory( uint32 TotemCategory ) const if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) return true; } - for(uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + for(uint8 i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; ++i) { pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && IsTotemCategoryCompatiableWith(pItem->GetProto()->TotemCategory,TotemCategory )) @@ -8463,6 +8510,18 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + // vanitypet case + if(slot >= VANITYPET_SLOT_START && slot < VANITYPET_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS)) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + // currencytoken case + if(slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + // guestbag case + if(slot >= QUESTBAG_SLOT_START && slot < QUESTBAG_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_QUEST_ITEMS)) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + // prevent cheating if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; @@ -8697,7 +8756,7 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 } } - // not specific slot or have spece for partly store only in specific slot + // not specific slot or have space for partly store only in specific slot // in specific bag if( bag != NULL_BAG ) @@ -8707,7 +8766,7 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 { if( bag == INVENTORY_SLOT_BAG_0 ) // inventory { - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,true,pItem,bag,slot); if(res!=EQUIP_ERR_OK) { if(no_space_count) @@ -8745,7 +8804,7 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 } else // equipped bag { - // we need check 2 time (specilized/non_specialized), use NULL_BAG to prevent skipping bag + // we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); if(res!=EQUIP_ERR_OK) res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); @@ -8794,6 +8853,66 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } + else if(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) + { + res = _CanStoreItem_InInventorySlots(VANITYPET_SLOT_START,VANITYPET_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + { + res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else if(pProto->BagFamily & BAG_FAMILY_MASK_QUEST_ITEMS) + { + res = _CanStoreItem_InInventorySlots(QUESTBAG_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); if(res!=EQUIP_ERR_OK) @@ -8843,7 +8962,7 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 // search stack for merge to if( pProto->Stackable > 1 ) { - res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_END,dest,pProto,count,true,pItem,bag,slot); + res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,true,pItem,bag,slot); if(res!=EQUIP_ERR_OK) { if(no_space_count) @@ -8941,6 +9060,66 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } + else if(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) + { + res = _CanStoreItem_InInventorySlots(VANITYPET_SLOT_START,VANITYPET_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + { + res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } + else if(pProto->BagFamily & BAG_FAMILY_MASK_QUEST_ITEMS) + { + res = _CanStoreItem_InInventorySlots(QUESTBAG_SLOT_START,QUESTBAG_SLOT_END,dest,pProto,count,false,pItem,bag,slot); + if(res!=EQUIP_ERR_OK) + { + if(no_space_count) + *no_space_count = count + no_similar_count; + return res; + } + + if(count==0) + { + if(no_similar_count==0) + return EQUIP_ERR_OK; + + if(no_space_count) + *no_space_count = count + no_similar_count; + return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; + } + } for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { @@ -9011,10 +9190,16 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const int inv_slot_items[INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START]; int inv_bags[INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE]; int inv_keys[KEYRING_SLOT_END-KEYRING_SLOT_START]; + int inv_pets[VANITYPET_SLOT_END-VANITYPET_SLOT_START]; + int inv_tokens[CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START]; + int inv_quests[QUESTBAG_SLOT_END-QUESTBAG_SLOT_START]; memset(inv_slot_items,0,sizeof(int)*(INVENTORY_SLOT_ITEM_END-INVENTORY_SLOT_ITEM_START)); memset(inv_bags,0,sizeof(int)*(INVENTORY_SLOT_BAG_END-INVENTORY_SLOT_BAG_START)*MAX_BAG_SIZE); memset(inv_keys,0,sizeof(int)*(KEYRING_SLOT_END-KEYRING_SLOT_START)); + memset(inv_pets,0,sizeof(int)*(VANITYPET_SLOT_END-VANITYPET_SLOT_START)); + memset(inv_tokens,0,sizeof(int)*(CURRENCYTOKEN_SLOT_END-CURRENCYTOKEN_SLOT_START)); + memset(inv_quests,0,sizeof(int)*(QUESTBAG_SLOT_END-QUESTBAG_SLOT_START)); for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) { @@ -9036,6 +9221,36 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const } } + for(int i = VANITYPET_SLOT_START; i < VANITYPET_SLOT_END; i++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + + if (pItem2 && !pItem2->IsInTrade()) + { + inv_pets[i-VANITYPET_SLOT_START] = pItem2->GetCount(); + } + } + + for(int i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + + if (pItem2 && !pItem2->IsInTrade()) + { + inv_tokens[i-CURRENCYTOKEN_SLOT_START] = pItem2->GetCount(); + } + } + + for(int i = QUESTBAG_SLOT_START; i < QUESTBAG_SLOT_END; i++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + + if (pItem2 && !pItem2->IsInTrade()) + { + inv_quests[i-QUESTBAG_SLOT_START] = pItem2->GetCount(); + } + } + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { Bag *pBag; @@ -9104,6 +9319,42 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const } if (b_found) continue; + for(int t = VANITYPET_SLOT_START; t < VANITYPET_SLOT_END; t++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_pets[t-VANITYPET_SLOT_START] + pItem->GetCount() <= pProto->Stackable ) + { + inv_pets[t-VANITYPET_SLOT_START] += pItem->GetCount(); + b_found = true; + break; + } + } + if (b_found) continue; + + for(int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; t++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->Stackable ) + { + inv_tokens[t-CURRENCYTOKEN_SLOT_START] += pItem->GetCount(); + b_found = true; + break; + } + } + if (b_found) continue; + + for(int t = QUESTBAG_SLOT_START; t < QUESTBAG_SLOT_END; t++) + { + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_quests[t-QUESTBAG_SLOT_START] + pItem->GetCount() <= pProto->Stackable ) + { + inv_quests[t-QUESTBAG_SLOT_START] += pItem->GetCount(); + b_found = true; + break; + } + } + if (b_found) continue; + for(int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; t++) { pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); @@ -9160,6 +9411,51 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const if (b_found) continue; + if(pProto->BagFamily & BAG_FAMILY_MASK_VANITY_PETS) + { + for(uint32 t = VANITYPET_SLOT_START; t < VANITYPET_SLOT_END; ++t) + { + if( inv_pets[t-VANITYPET_SLOT_START] == 0 ) + { + inv_pets[t-VANITYPET_SLOT_START] = 1; + b_found = true; + break; + } + } + } + + if (b_found) continue; + + if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + { + for(uint32 t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t) + { + if( inv_tokens[t-CURRENCYTOKEN_SLOT_START] == 0 ) + { + inv_tokens[t-CURRENCYTOKEN_SLOT_START] = 1; + b_found = true; + break; + } + } + } + + if (b_found) continue; + + if(pProto->BagFamily & BAG_FAMILY_MASK_QUEST_ITEMS) + { + for(uint32 t = QUESTBAG_SLOT_START; t < QUESTBAG_SLOT_END; ++t) + { + if( inv_quests[t-QUESTBAG_SLOT_START] == 0 ) + { + inv_quests[t-QUESTBAG_SLOT_START] = 1; + b_found = true; + break; + } + } + } + + if (b_found) continue; + for(int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; t++) { pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t ); @@ -10205,7 +10501,6 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update ) if( bag == INVENTORY_SLOT_BAG_0 ) { - SetUInt64Value((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (slot*2)), 0); // equipment and equipped bags can have applied bonuses @@ -10281,7 +10576,7 @@ void Player::DestroyItemCount( uint32 item, uint32 count, bool update, bool uneq } } } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem->GetEntry() == item ) @@ -10391,7 +10686,7 @@ void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone ) if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) DestroyItem( INVENTORY_SLOT_BAG_0, i, update); } - for(int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++) + for(int i = KEYRING_SLOT_START; i < QUESTBAG_SLOT_END; i++) { Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); if( pItem && pItem->IsLimitedToAnotherMapOrZone(GetMapId(),new_zone) ) @@ -10429,7 +10724,7 @@ void Player::DestroyZoneLimitedItem( bool update, uint32 new_zone ) void Player::DestroyConjuredItems( bool update ) { // used when entering arena - // distroys all conjured items + // destroys all conjured items sLog.outDebug( "STORAGE: DestroyConjuredItems" ); // in inventory @@ -11400,6 +11695,10 @@ void Player::ApplyEnchantment(Item *item,EnchantmentSlot slot,bool apply, bool a ((Player*)this)->ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply); sLog.outDebug("+ %u EXPERTISE", enchant_amount); break; + case ITEM_MOD_ARMOR_PENETRATION_RATING: + ((Player*)this)->ApplyRatingMod(CR_ARMOR_PENETRATION, enchant_amount, apply); + sLog.outDebug("+ %u ARMOR PENETRATION", enchant_amount); + break; default: break; } @@ -13071,6 +13370,7 @@ void Player::SendQuestComplete( uint32 quest_id ) void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGiver ) { + // TODO: something really wrong here (there is only 5 x uint32 in client) uint32 questid = pQuest->GetQuestId(); sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid ); WorldPacket data( SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4+4+pQuest->GetRewItemsCount()*8) ); @@ -13087,7 +13387,8 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive data << uint32(0); data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY))); } - data << uint32(0); // new 2.3.0, HonorPoints? + data << uint32(0); // new 2.3.0, HonorPoints, HONORAWARD + data << uint32(0); // added in WotLK, LEVEL_UP_CHAR_POINTS data << uint32( pQuest->GetRewItemsCount() ); // max is 5 for (uint32 i = 0; i < pQuest->GetRewItemsCount(); ++i) @@ -13107,8 +13408,9 @@ void Player::SendQuestFailed( uint32 quest_id ) { if( quest_id ) { - WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4 ); + WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4+4 ); data << quest_id; + data << uint32(0); // added in WotLK? GetSession()->SendPacket( &data ); sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); } @@ -13557,10 +13859,10 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) uint32 extraflags = fields[25].GetUInt32(); m_stableSlots = fields[26].GetUInt32(); - if(m_stableSlots > 2) + if(m_stableSlots > 4) { - sLog.outError("Player can have not more 2 stable slots, but have in DB %u",uint32(m_stableSlots)); - m_stableSlots = 2; + sLog.outError("Player can have not more 4 stable slots, but have in DB %u",uint32(m_stableSlots)); + m_stableSlots = 4; } m_atLoginFlags = fields[27].GetUInt32(); @@ -13629,6 +13931,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // reset stats before loading any modifiers InitStatsForLevel(); InitTaxiNodesForLevel(); + InitGlyphsForLevel(); // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() @@ -13838,10 +14141,6 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) for (int i = 0; i < TOTAL_AURAS; i++) m_modAuras[i].clear(); - // all aura related fields - for(int i = UNIT_FIELD_AURA; i <= UNIT_FIELD_AURASTATE; ++i) - SetUInt32Value(i, 0); - //QueryResult *result = CharacterDatabase.PQuery("SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'",GetGUIDLow()); if(result) @@ -13886,7 +14185,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) remaincharges = spellproto->procCharges; } else - remaincharges = -1; + remaincharges = 0; //do not load single target auras (unless they were cast by the player) if (caster_guid != GetGUID() && IsSingleTargetSpell(spellproto)) @@ -15345,7 +15644,8 @@ void Player::SendAttackSwingBadFacingAttack() void Player::SendAutoRepeatCancel() { - WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, 0); + WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, GetPackGUID().size()); + data.append(GetPackGUID()); // may be it's target guid GetSession()->SendPacket( &data ); } @@ -15570,6 +15870,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) { WorldPacket data(SMSG_PET_SPELLS, 8); data << uint64(0); + data << uint32(0); GetSession()->SendPacket(&data); if(GetGroup()) @@ -15726,7 +16027,10 @@ void Player::PetSpellInitialize() CharmInfo *charmInfo = pet->GetCharmInfo(); //16 - data << (uint64)pet->GetGUID() << uint32(0x00000000) << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); + data << uint64(pet->GetGUID()); + data << uint32(pet->GetCreatureInfo()->family); // creature family (required for pet talents) + data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); + data << uint32(0); for(uint32 i = 0; i < 10; i++) //40 { @@ -15782,7 +16086,10 @@ void Player::PossessSpellInitialize() WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds //16 - data << (uint64)charm->GetGUID() << uint32(0x00000000) << uint8(0) << uint8(0) << uint16(0); + data << uint64(charm->GetGUID()); + data << uint32(0x00000000); + data << uint8(0) << uint8(0) << uint16(0); + data << uint32(0); for(uint32 i = 0; i < 10; i++) //40 { @@ -15840,6 +16147,7 @@ void Player::CharmSpellInitialize() data << uint8(0) << uint8(0); data << uint16(0); + data << uint32(0); for(uint32 i = 0; i < 10; i++) //40 { @@ -16104,7 +16412,7 @@ void Player::HandleStealthedUnitsDetection() // target aura duration for caster show only if target exist at caster client // send data at target visibility change (adding to client) if((*i)!=this && (*i)->isType(TYPEMASK_UNIT)) - SendAuraDurationsForTarget(*i); + SendAurasForTarget(*i); i = stealthedUnits.erase(i); continue; @@ -16981,7 +17289,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) // target aura duration for caster show only if target exist at caster client // send data at target visibility change (adding to client) if(target!=this && target->isType(TYPEMASK_UNIT)) - SendAuraDurationsForTarget((Unit*)target); + SendAurasForTarget((Unit*)target); if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive()) ((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this); @@ -17120,7 +17428,7 @@ void Player::SetGroup(Group *group, int8 subgroup) void Player::SendInitialPacketsBeforeAddToMap() { - WorldPacket data(SMSG_SET_REST_START, 4); + WorldPacket data(SMSG_SET_REST_START_OBSOLETE, 4); data << uint32(0); // unknown, may be rest state time or expirience GetSession()->SendPacket(&data); @@ -17195,6 +17503,7 @@ void Player::SendInitialPacketsAfterAddToMap() SendMessageToSet(&data,true); } + SendAurasForTarget(this); SendEnchantmentDurations(); // must be after add to map SendItemDurations(); // must be after add to map } @@ -17426,16 +17735,41 @@ void Player::learnSkillRewardedSpells() } } -void Player::SendAuraDurationsForTarget(Unit* target) +void Player::SendAurasForTarget(Unit *target) { + WorldPacket data(SMSG_AURA_UPDATE_ALL); + data.append(target->GetPackGUID()); + for(Unit::AuraMap::const_iterator itr = target->GetAuras().begin(); itr != target->GetAuras().end(); ++itr) { Aura* aura = itr->second; if(aura->GetAuraSlot() >= MAX_AURAS || aura->IsPassive() || aura->GetCasterGUID()!=GetGUID()) continue; - aura->SendAuraDurationForCaster(this); + data << uint8(aura->GetAuraSlot()); + data << uint32(aura->GetId()); + + if(aura->GetId()) + { + uint8 auraFlags = aura->GetAuraFlags(); + data << uint8(auraFlags); // flags + data << uint8(aura->GetAuraLevel()); // level + data << uint8(aura->m_procCharges); // charges + + /*if(!(auraFlags & AFLAG_NOT_GUID)) + { + data << uint8(0) // packed GUID of someone (caster?) + }*/ + + if(auraFlags & AFLAG_DURATION) // include aura duration + { + data << uint32(aura->GetAuraMaxDuration()); + data << uint32(aura->GetAuraDuration()); + } + } } + + GetSession()->SendPacket(&data); } void Player::SetDailyQuestStatus( uint32 quest_id ) @@ -18115,7 +18449,7 @@ Player* Player::GetNextRandomRaidMember(float radius) void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { float water_z = m->GetWaterLevel(x,y); - float height_z = m->GetHeight(x,y,z, false); // use .map base surface height + float height_z = m->GetHeight(x,y,z, false); // use .map base surface height uint8 flag1 = m->GetTerrainType(x,y); //!Underwater check, not in water if underground or above water level @@ -18158,11 +18492,64 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const bool Player::isAllowUseBattleGroundObject() { - return ( //InBattleGround() && // in battleground - not need, check in other cases - !IsMounted() && // not mounted - !HasStealthAura() && // not stealthed - !HasInvisibilityAura() && // not invisible - !HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup - isAlive() // live player + return ( //InBattleGround() && // in battleground - not need, check in other cases + !IsMounted() && // not mounted + !HasStealthAura() && // not stealthed + !HasInvisibilityAura() && // not invisible + !HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup + isAlive() // live player ); } + +uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair) +{ + uint32 level = getLevel(); + + if(level > sGtBarberShopCostBaseStore.GetNumRows()) + level = GT_MAX_LEVEL; // max level in this dbc + + uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2); + uint8 haircolor = GetByteValue(PLAYER_BYTES, 3); + uint8 facialhair = GetByteValue(PLAYER_BYTES_2, 0); + + if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair)) + return 0; + + GtBarberShopCostBaseEntry const *bsc = sGtBarberShopCostBaseStore.LookupEntry(level - 1); + + if(!bsc) // shouldn't happen + return 0xFFFFFFFF; + + float cost = 0; + + if(hairstyle != newhairstyle) + cost += bsc->cost; // full price + + if((haircolor != newhaircolor) && (hairstyle == newhairstyle)) + cost += bsc->cost * 0.5f; // +1/2 of price + + if(facialhair != newfacialhair) + cost += bsc->cost * 0.75f; // +3/4 of price + + return uint32(cost); +} + +void Player::InitGlyphsForLevel() +{ + uint32 level = getLevel(); + uint32 value = 0; + + // 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level + if(level >= 15) + value |= (0x01 | 0x02); + if(level >= 30) + value |= 0x04; + if(level >= 50) + value |= 0x08; + if(level >= 70) + value |= 0x10; + if(level >= 80) + value |= 0x20; + + SetUInt32Value(PLAYER_GLYPHS_ENABLED, value); +} diff --git a/src/game/Player.h b/src/game/Player.h index aaaaac60f..f1d9d0cec 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -540,7 +540,7 @@ enum PlayerSlots // first slot for item stored (in any way in player m_items data) PLAYER_SLOT_START = 0, // last+1 slot for item stored (in any way in player m_items data) - PLAYER_SLOT_END = 118, + PLAYER_SLOT_END = 200, PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) }; @@ -668,6 +668,24 @@ enum KeyRingSlots KEYRING_SLOT_END = 118 }; +enum VanityPetSlots +{ + VANITYPET_SLOT_START = 118, + VANITYPET_SLOT_END = 136 +}; + +enum CurrencyTokenSlots +{ + CURRENCYTOKEN_SLOT_START = 136, + CURRENCYTOKEN_SLOT_END = 168 +}; + +enum QuestBagSlots +{ + QUESTBAG_SLOT_START = 168, + QUESTBAG_SLOT_END = 200 +}; + struct ItemPosCount { ItemPosCount(uint16 _pos, uint8 _count) : pos(_pos), count(_count) {} @@ -714,14 +732,15 @@ struct MovementInfo { // common //uint32 flags; - uint8 unk1; + uint16 unk1; uint32 time; float x, y, z, o; // transport uint64 t_guid; float t_x, t_y, t_z, t_o; uint32 t_time; - // swimming and unk + uint8 t_unk; + // swimming and unknown float s_pitch; // last fall time uint32 fallTime; @@ -943,6 +962,8 @@ class MANGOS_DLL_SPEC Player : public Unit std::string afkMsg; std::string dndMsg; + uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair); + PlayerSocial *GetSocial() { return m_social; } PlayerTaxi m_taxi; @@ -1410,6 +1431,12 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 resetTalentsCost() const; void InitTalentForLevel(); + void InitGlyphsForLevel(); + void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); } + uint32 GetGlyphSlot(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); } + void SetGlyph(uint8 slot, uint32 glyph) { SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); } + uint32 GetGlyph(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot); } + uint32 GetFreePrimaryProffesionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } void SetFreePrimaryProffesions(uint16 profs) { SetUInt32Value(PLAYER_CHARACTER_POINTS2,profs); } void InitPrimaryProffesions(); @@ -1782,7 +1809,7 @@ class MANGOS_DLL_SPEC Player : public Unit void SendUpdateWorldState(uint32 Field, uint32 Value); void SendDirectMessage(WorldPacket *data); - void SendAuraDurationsForTarget(Unit* target); + void SendAurasForTarget(Unit *target); PlayerMenu* PlayerTalkClass; std::vector ItemSetEff; @@ -1930,6 +1957,7 @@ class MANGOS_DLL_SPEC Player : public Unit float GetTransOffsetZ() const { return m_movementInfo.t_z; } float GetTransOffsetO() const { return m_movementInfo.t_o; } uint32 GetTransTime() const { return m_movementInfo.t_time; } + uint8 GetTransUnk() const { return m_movementInfo.t_unk; } uint32 GetSaveTimer() const { return m_nextSave; } void SetSaveTimer(uint32 timer) { m_nextSave = timer; } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 339a59079..08175df9a 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -183,6 +183,8 @@ Unit::Unit() m_ShapeShiftFormSpellId = 0; m_canModifyStats = false; + for (int i = 0; i < MAX_AURAS; ++i) + m_visibleAuras[i] = 0; for (int i = 0; i < MAX_SPELL_IMMUNITY; i++) m_spellImmune[i].clear(); for (int i = 0; i < UNIT_MOD_END; i++) @@ -2124,7 +2126,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama ((*itr).second->GetCasterGUID() == GetGUID() && (!spellCasted || spellCasted->Id == 35395)) ) { (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->UpdateAuraDuration(); + (*itr).second->SendAuraUpdate(false); } } } @@ -4170,7 +4172,7 @@ void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime) iter->second->SetAuraDuration(0); else iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime); - iter->second->UpdateAuraDuration(); + iter->second->SendAuraUpdate(false); sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration()); } } @@ -4344,6 +4346,7 @@ void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, data.append(GetPackGUID()); data << uint32(SpellID); data << uint32(Damage-AbsorbedDamage-Resist-Blocked); + data << uint32(0); // wotlk data << uint8(damageSchoolMask); // spell school data << uint32(AbsorbedDamage); // AbsorbedDamage data << uint32(Resist); // resist @@ -4377,28 +4380,63 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, data << (uint32)HitInfo; data.append(GetPackGUID()); data.append(target->GetPackGUID()); - data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); + data << uint32(Damage-AbsorbDamage-Resist-BlockedAmount); + data << uint32(0); // WotLK data << (uint8)SwingType; // count? // for(i = 0; i < SwingType; ++i) data << (uint32)damageSchoolMask; data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); - // still need to double check damage data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); - data << (uint32)AbsorbDamage; - data << (uint32)Resist; // end loop - data << (uint32)TargetState; + if(HitInfo & (HITINFO_RESIST | HITINFO_ABSORB)) + { + // for(i = 0; i < SwingType; ++i) + data << (uint32)Resist; + // end loop + } - if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens - data << (uint32)0; - else - data << (uint32)-1; + if(HitInfo & (HITINFO_CRITICALHIT | HITINFO_UNK2)) + { + // for(i = 0; i < SwingType; ++i) + data << uint32(0); // what is it? + // end loop + } + data << (uint8)TargetState; data << (uint32)0; - data << (uint32)BlockedAmount; + data << (uint32)0; + + if(HitInfo & HITINFO_UNK3) + { + data << uint32(0); + } + + /*if(unknown & HitInfo) + { + data << uint32(0); + }*/ + + /*if(HitInfo & HITINFO_UNK1) + { + data << uint32(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + for(uint8 i = 0; i < 5; ++i) + { + data << float(0); + data << float(0); + } + data << uint32(0); + }*/ SendMessageToSet( &data, true ); } @@ -7089,7 +7127,7 @@ Unit* Unit::GetCharm() const void Unit::SetPet(Pet* pet) { - SetUInt64Value(UNIT_FIELD_SUMMON,pet ? pet->GetGUID() : 0); + SetUInt64Value(UNIT_FIELD_SUMMON, pet ? pet->GetGUID() : 0); // FIXME: hack, speed must be set only at follow if(pet) @@ -8896,7 +8934,7 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) data.append(GetPackGUID()); data << uint32(0); //movement flags - data << uint8(0); //unk + data << uint16(0); //unk data << uint32(getMSTime()); data << float(GetPositionX()); data << float(GetPositionY()); @@ -9648,6 +9686,12 @@ void Unit::SetPower(Powers power, uint32 val) SetStatInt32Value(UNIT_FIELD_POWER1 + power, val); + WorldPacket data(SMSG_POWER_UPDATE); + data.append(GetPackGUID()); + data << uint8(power); + data << uint32(val); + SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER ? true : false); + // group update if(GetTypeId() == TYPEID_PLAYER) { @@ -9761,6 +9805,7 @@ uint32 Unit::GetCreatePowers( Powers power ) const case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100); case POWER_ENERGY: return 100; case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000); + case POWER_RUNIC_POWER: return 1000; } return 0; @@ -10272,8 +10317,11 @@ void Unit::SendPetCastFail(uint32 spellid, uint8 msg) return; WorldPacket data(SMSG_PET_CAST_FAILED, (4+1)); + data << uint8(0); // cast count? data << uint32(spellid); data << uint8(msg); + // uint32 for some reason + // uint32 for some reason ((Player*)owner)->GetSession()->SendPacket(&data); } diff --git a/src/game/Unit.h b/src/game/Unit.h index 6eb643843..f886000b2 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -413,10 +413,11 @@ enum CombatRating CR_WEAPON_SKILL_MAINHAND = 20, CR_WEAPON_SKILL_OFFHAND = 21, CR_WEAPON_SKILL_RANGED = 22, - CR_EXPERTISE = 23 + CR_EXPERTISE = 23, + CR_ARMOR_PENETRATION = 24 }; -#define MAX_COMBAT_RATING 24 +#define MAX_COMBAT_RATING 25 enum DamageEffectType { @@ -1125,6 +1126,9 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void removeHatedBy(HostilReference* /*pHostilReference*/ ) { /* nothing to do yet */ } HostilRefManager& getHostilRefManager() { return m_HostilRefManager; } + uint32 GetVisibleAura(uint32 slot) { return m_visibleAuras[slot]; } + void SetVisibleAura(uint32 slot, uint32 spellid) { m_visibleAuras[slot] = spellid; } + Aura* GetAura(uint32 spellId, uint32 effindex); AuraMap & GetAuras() { return m_Auras; } AuraMap const& GetAuras() const { return m_Auras; } @@ -1297,6 +1301,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject float m_weaponDamage[MAX_ATTACK][2]; bool m_canModifyStats; //std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem + uint32 m_visibleAuras[MAX_AURAS]; float m_speed_rate[MAX_MOVE_TYPE];