Updated objects stuff

This commit is contained in:
tomrus88 2008-10-26 10:20:52 +03:00
parent 579fc917bb
commit 9c8864f134
12 changed files with 896 additions and 500 deletions

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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;
@ -190,7 +166,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
return false;
}
setPetType(PetType(fields[22].GetUInt8()));
setPetType(PetType(fields[20].GetUInt8()));
SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction());
SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id);
@ -202,20 +178,21 @@ 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)
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());
SetName(fields[9].GetString());
switch(getPetType())
{
case SUMMON_PET:
petlevel=owner->getLevel();
@ -225,38 +202,32 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
break;
case HUNTER_PET:
SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100);
SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[8].GetUInt32());
SetByteValue(UNIT_FIELD_BYTES_1, 1, fields[7].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_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());
SetPower(POWER_HAPPINESS, fields[13].GetUInt32());
setPowerType(POWER_FOCUS);
break;
default:
sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
}
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();
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());
@ -267,7 +238,7 @@ bool Pet::LoadPetFromDB( Unit* owner, uint32 petentry, uint32 petnumber, bool cu
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;
@ -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)
@ -906,8 +711,6 @@ void Pet::GivePetLevel(uint32 level)
return;
InitStatsForLevel(level);
SetTP(m_TrainingPoints + (GetLoyaltyLevel() - 1));
}
bool Pet::CreateBaseAtCreature(Creature* creature)
@ -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);
}
return true;
}
@ -1154,7 +953,8 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
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)
@ -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)
@ -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)
@ -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)
@ -1694,7 +1499,6 @@ bool Pet::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 pet_number)
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 );
if(getPetType() == MINI_PET) // always non-attackable
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);

View file

@ -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<uint32> 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
@ -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);
@ -193,8 +173,6 @@ class Pet : public Creature
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
void ToggleAutocast(uint32 spellid, bool apply);
bool HasTPForSpell(uint32 spellid);
int32 GetTPForSpell(uint32 spellid);
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;

View file

@ -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:
@ -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);
}

View file

@ -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))

View file

@ -173,7 +173,7 @@ void PlayerTaxi::AppendTaximaskTo( ByteBuffer& data, bool all )
if(all)
{
for (uint8 i=0; i<TaxiMaskSize; i++)
data << sTaxiNodesMask[i]; // all existed nodes
data << uint32(sTaxiNodesMask[i]); // all existed nodes
}
else
{
@ -527,6 +527,9 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
case POWER_RAGE:
unitfield = 0x00110000;
break;
case POWER_RUNIC_POWER:
unitfield = 0x0000EE00; //TODO: find correct unitfield here
break;
default:
sLog.outError("Invalid default powertype %u for player (class %u)",powertype,class_);
return false;
@ -577,7 +580,17 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
SetUInt32Value( PLAYER_FIELD_TODAY_CONTRIBUTION, 0 );
SetUInt32Value( PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0 );
for(uint32 i = 0; i < sGlyphSlotStore.GetNumRows(); ++i)
{
GlyphSlotEntry const * gs = sGlyphSlotStore.LookupEntry(i);
if(gs && gs->Order)
SetGlyphSlot(gs->Order - 1, gs->Id);
}
// set starting level
if(getClass() == CLASS_DEATH_KNIGHT)
SetUInt32Value(UNIT_FIELD_LEVEL, 55);
else
SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) );
// Played time
@ -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 + 0);
updateVisualBits.SetBit(UNIT_FIELD_CHARM + 1);
updateVisualBits.SetBit(UNIT_FIELD_SUMMON);
updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 0);
updateVisualBits.SetBit(UNIT_FIELD_SUMMON + 1);
updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY);
updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 0);
updateVisualBits.SetBit(UNIT_FIELD_CHARMEDBY + 1);
updateVisualBits.SetBit(UNIT_FIELD_TARGET);
updateVisualBits.SetBit(UNIT_FIELD_TARGET + 0);
updateVisualBits.SetBit(UNIT_FIELD_TARGET + 1);
updateVisualBits.SetBit(UNIT_FIELD_CHANNEL_OBJECT);
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,9 +3268,11 @@ 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 + 0);
updateVisualBits.SetBit(PLAYER_DUEL_ARBITER + 1);
updateVisualBits.SetBit(PLAYER_FLAGS);
updateVisualBits.SetBit(PLAYER_GUILDID);
@ -3267,25 +3288,25 @@ void Player::InitVisibleBits()
updateVisualBits.SetBit(i);
// Players visible items are not inventory stuff
//431) = 884 (0x374) = main weapon
for(uint16 i = 0; i < EQUIPMENT_SLOT_END; i++)
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;
@ -6382,12 +6402,36 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply)
for (int i = 0; i < 10; i++)
{
float val = float (proto->ItemStat[i].ItemStatValue);
uint32 statType = 0;
int32 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,17 +17735,42 @@ 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 )
{
@ -18166,3 +18500,56 @@ bool Player::isAllowUseBattleGroundObject()
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);
}

View file

@ -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<ItemSetEffect *> 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; }

View file

@ -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 );
}
@ -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);
}

View file

@ -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];