mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
Cmangos Cata commits applied
I thankee, cmangos :-) Commits: 13271d6 Commit Ported Core Pet DB cleanup and simplification 60d6e29 Commit Imported Core Utilize flags in PetAI (And uniform extra flags with the other cores) 06d30ce Commit Ported Core Make pet assist owner on summon if not a passive 2821da8 Commit Ported Core Fix Guardian reactions 4f88a9e Commit Ported Core Pet AI Fixup 67e0558 Commit Imported Core Fix pet unsummon on mount f50041f Commit Imported Core Fix player rooted after possesing an unit. df59a93 Commit Imported Core Syncing up pet work 056f4f5 Commit Imported Core Fix a couple of invalid name for spell attributes 6a58f1f Commit Imported Core only save correct auras on pet::SavePetToDB 34ab59b Commit Imported Core Hunter summon pet (call pet) checkcast fixup dfbb69c Commit Imported Core Handle owner entering combat properly 4b10eb4 Commit Imported Core Pet Aggro 1bdb7e3 Commit Ported Core Clean up pet stay functionality 1bdb7e3 Commit Ported Core Clean up pet stay functionality 9b7b50e Commit Imported Core UNIT_BYTE2_FLAG work 0777235 Commit Imported Core Implement displaying group leader indicators on players 5efab47 Commit Imported Core Health funnel fixes 60e6a84 Commit Ported Core Fix SMSG_QUESTGIVER_STATUS_MULTIPLE and GetDialogStatus 60e6a84 Commit Ported Core Fix SMSG_QUESTGIVER_STATUS_MULTIPLE and GetDialogStatus f8d3cbd Commit Imported Core Fix talent spell cannot stack 32ba32e Commit Imported Core Fix channeled spell distance check interval 47ec2fa Commit Imported Core Adding state to aura holder Now proc cannot remove an aura not finalized 34588dc Commit Ported Core Unbreak creature pets bd079a1 Commit Imported Core The (not so)Great Pet Rework
This commit is contained in:
parent
c4c83f5b58
commit
600205641d
20 changed files with 634 additions and 507 deletions
|
|
@ -52,10 +52,6 @@ Pet::Pet(PetType type) :
|
||||||
|
|
||||||
if (type == MINI_PET) // always passive
|
if (type == MINI_PET) // always passive
|
||||||
charmInfo->SetReactState(REACT_PASSIVE);
|
charmInfo->SetReactState(REACT_PASSIVE);
|
||||||
else if (type == PROTECTOR_PET) // always defensive
|
|
||||||
charmInfo->SetReactState(REACT_DEFENSIVE);
|
|
||||||
else if (type == GUARDIAN_PET) // always aggressive
|
|
||||||
charmInfo->SetReactState(REACT_AGGRESSIVE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pet::~Pet()
|
Pet::~Pet()
|
||||||
|
|
@ -158,13 +154,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||||
|
|
||||||
uint32 pet_number = fields[0].GetUInt32();
|
uint32 pet_number = fields[0].GetUInt32();
|
||||||
|
|
||||||
if (current && owner->IsPetNeedBeTemporaryUnsummoned())
|
|
||||||
{
|
|
||||||
owner->SetTemporaryUnsummonedPetNumber(pet_number);
|
|
||||||
delete result;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map* map = owner->GetMap();
|
Map* map = owner->GetMap();
|
||||||
|
|
||||||
CreatureCreatePos pos(owner, owner->GetOrientation(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
CreatureCreatePos pos(owner, owner->GetOrientation(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||||
|
|
@ -202,18 +191,13 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||||
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
|
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
|
||||||
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||||
|
|
||||||
switch (getPetType())
|
if (getPetType() == HUNTER_PET)
|
||||||
{
|
{
|
||||||
case SUMMON_PET:
|
|
||||||
petlevel = owner->getLevel();
|
|
||||||
break;
|
|
||||||
case HUNTER_PET:
|
|
||||||
SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
|
SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
|
||||||
SetPowerType(POWER_FOCUS);
|
SetPowerType(POWER_FOCUS);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
|
|
||||||
}
|
}
|
||||||
|
else if (getPetType() != SUMMON_PET)
|
||||||
|
sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
|
||||||
|
|
||||||
if (owner->IsPvP())
|
if (owner->IsPvP())
|
||||||
SetPvP(true);
|
SetPvP(true);
|
||||||
|
|
@ -282,21 +266,16 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||||
CastOwnerTalentAuras();
|
CastOwnerTalentAuras();
|
||||||
}
|
}
|
||||||
|
|
||||||
Powers powerType = GetPowerType();
|
Powers powerType = GetPowerType();;
|
||||||
|
|
||||||
if (getPetType() == SUMMON_PET && !current) // all (?) summon pets come with full health when called, but not when they are current
|
|
||||||
{
|
|
||||||
SetHealth(GetMaxHealth());
|
|
||||||
SetPower(powerType, GetMaxPower(powerType));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
||||||
SetPower(powerType, savedpower > GetMaxPower(powerType) ? GetMaxPower(powerType) : savedpower);
|
SetPower(powerType, savedpower > GetMaxPower(powerType) ? GetMaxPower(powerType) : savedpower);
|
||||||
}
|
|
||||||
|
|
||||||
AIM_Initialize();
|
if (getPetType() == HUNTER_PET && savedhealth <= 0)
|
||||||
|
SetDeathState(JUST_DIED);
|
||||||
|
|
||||||
map->Add((Creature*)this);
|
map->Add((Creature*)this);
|
||||||
|
AIM_Initialize();
|
||||||
|
|
||||||
// Spells should be loaded after pet is added to map, because in CheckCast is check on it
|
// Spells should be loaded after pet is added to map, because in CheckCast is check on it
|
||||||
_LoadSpells();
|
_LoadSpells();
|
||||||
|
|
@ -363,7 +342,13 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||||
{
|
{
|
||||||
// reagents must be returned before save call
|
// reagents must be returned before save call
|
||||||
if (mode == PET_SAVE_REAGENTS)
|
if (mode == PET_SAVE_REAGENTS)
|
||||||
|
{
|
||||||
|
// Hunter Pets always save as current if dismissed or unsummoned due to range/etc.
|
||||||
|
if (getPetType() == HUNTER_PET)
|
||||||
|
mode = PET_SAVE_AS_CURRENT;
|
||||||
|
else
|
||||||
mode = PET_SAVE_NOT_IN_SLOT;
|
mode = PET_SAVE_NOT_IN_SLOT;
|
||||||
|
}
|
||||||
// not save pet as current if another pet temporary unsummoned
|
// not save pet as current if another pet temporary unsummoned
|
||||||
else if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() &&
|
else if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() &&
|
||||||
pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber())
|
pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber())
|
||||||
|
|
@ -430,7 +415,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||||
savePet.addUInt32(uint32(mode));
|
savePet.addUInt32(uint32(mode));
|
||||||
savePet.addString(m_name);
|
savePet.addString(m_name);
|
||||||
savePet.addUInt32(uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1));
|
savePet.addUInt32(uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1));
|
||||||
savePet.addUInt32((curhealth < 1 ? 1 : curhealth));
|
savePet.addUInt32(curhealth);
|
||||||
savePet.addUInt32(curpower);
|
savePet.addUInt32(curpower);
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
@ -441,7 +426,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||||
};
|
};
|
||||||
savePet.addString(ss);
|
savePet.addString(ss);
|
||||||
|
|
||||||
savePet.addUInt64(uint64(time(NULL)));
|
savePet.addUInt64(uint64(time(nullptr)));
|
||||||
savePet.addUInt32(uint32(m_resetTalentsCost));
|
savePet.addUInt32(uint32(m_resetTalentsCost));
|
||||||
savePet.addUInt64(uint64(m_resetTalentsTime));
|
savePet.addUInt64(uint64(m_resetTalentsTime));
|
||||||
savePet.addUInt32(GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
savePet.addUInt32(GetUInt32Value(UNIT_CREATED_BY_SPELL));
|
||||||
|
|
@ -774,18 +759,13 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
|
||||||
if (!Create(guid, pos, creature->GetCreatureInfo(), pet_number))
|
if (!Create(guid, pos, creature->GetCreatureInfo(), pet_number))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CreatureInfo const* cinfo = GetCreatureInfo();
|
CreatureInfo const* cInfo = GetCreatureInfo();
|
||||||
if (!cinfo)
|
if (!cInfo)
|
||||||
{
|
{
|
||||||
sLog.outError("CreateBaseAtCreature() failed, creatureInfo is missing!");
|
sLog.outError("CreateBaseAtCreature() failed, creatureInfo is missing!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
|
|
||||||
{
|
|
||||||
setPetType(MINI_PET);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
SetDisplayId(creature->GetDisplayId());
|
SetDisplayId(creature->GetDisplayId());
|
||||||
SetNativeDisplayId(creature->GetNativeDisplayId());
|
SetNativeDisplayId(creature->GetNativeDisplayId());
|
||||||
SetPowerType(POWER_FOCUS);
|
SetPowerType(POWER_FOCUS);
|
||||||
|
|
@ -794,114 +774,137 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
|
||||||
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
|
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
|
||||||
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||||
|
|
||||||
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family))
|
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family))
|
||||||
SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]);
|
SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]);
|
||||||
else
|
else
|
||||||
SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex()));
|
SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex()));
|
||||||
|
|
||||||
if (cinfo->CreatureType == CREATURE_TYPE_BEAST)
|
|
||||||
{
|
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
|
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
|
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 3, POWER_FOCUS);
|
SetByteValue(UNIT_FIELD_BYTES_0, 3, POWER_FOCUS);
|
||||||
SetSheath(SHEATH_STATE_MELEE);
|
SetSheath(SHEATH_STATE_MELEE);
|
||||||
|
|
||||||
|
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
|
||||||
SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
|
SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
|
||||||
|
|
||||||
|
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_RENAME);
|
||||||
|
|
||||||
SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED));
|
SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
|
void Pet::InitStatsForLevel(uint32 petlevel)
|
||||||
{
|
{
|
||||||
CreatureInfo const* cinfo = GetCreatureInfo();
|
Unit* owner = GetOwner();
|
||||||
MANGOS_ASSERT(cinfo);
|
CreatureInfo const* cInfo = GetCreatureInfo();
|
||||||
|
MANGOS_ASSERT(cInfo);
|
||||||
if (!owner)
|
|
||||||
{
|
|
||||||
owner = GetOwner();
|
|
||||||
if (!owner)
|
|
||||||
{
|
|
||||||
sLog.outError("attempt to summon pet (Entry %u) without owner! Attempt terminated.", cinfo->Entry);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 creature_ID = (getPetType() == HUNTER_PET) ? 1 : cinfo->Entry;
|
|
||||||
|
|
||||||
switch (getPetType())
|
|
||||||
{
|
|
||||||
case SUMMON_PET:
|
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_MAGE);
|
|
||||||
|
|
||||||
// this enables popup window (pet dismiss, cancel)
|
|
||||||
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
|
||||||
break;
|
|
||||||
case HUNTER_PET:
|
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
|
|
||||||
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
|
|
||||||
SetSheath(SHEATH_STATE_MELEE);
|
|
||||||
|
|
||||||
// this enables popup window (pet abandon, cancel)
|
|
||||||
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
|
||||||
break;
|
|
||||||
case GUARDIAN_PET:
|
|
||||||
case MINI_PET:
|
|
||||||
case PROTECTOR_PET:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetLevel(petlevel);
|
SetLevel(petlevel);
|
||||||
|
|
||||||
SetMeleeDamageSchool(SpellSchools(cinfo->DamageSchool));
|
|
||||||
|
|
||||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
|
|
||||||
|
|
||||||
SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME);
|
|
||||||
SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME);
|
|
||||||
SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
|
|
||||||
|
|
||||||
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
|
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
|
||||||
|
|
||||||
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family);
|
|
||||||
if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET)
|
|
||||||
{
|
|
||||||
float Scale;
|
|
||||||
if (getLevel() >= cFamily->maxScaleLevel)
|
|
||||||
Scale = cFamily->maxScale;
|
|
||||||
else if (getLevel() <= cFamily->minScaleLevel)
|
|
||||||
Scale = cFamily->minScale;
|
|
||||||
else
|
|
||||||
Scale = cFamily->minScale + float(getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale);
|
|
||||||
|
|
||||||
SetObjectScale(Scale);
|
|
||||||
UpdateModelData();
|
|
||||||
}
|
|
||||||
m_bonusdamage = 0;
|
|
||||||
|
|
||||||
int32 createResistance[MAX_SPELL_SCHOOL] = {0, 0, 0, 0, 0, 0, 0};
|
int32 createResistance[MAX_SPELL_SCHOOL] = {0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
if (getPetType() != HUNTER_PET)
|
if (getPetType() == HUNTER_PET)
|
||||||
{
|
{
|
||||||
createResistance[SPELL_SCHOOL_HOLY] = cinfo->ResistanceHoly;
|
SetMeleeDamageSchool(SpellSchools(SPELL_SCHOOL_NORMAL));
|
||||||
createResistance[SPELL_SCHOOL_FIRE] = cinfo->ResistanceFire;
|
SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME);
|
||||||
createResistance[SPELL_SCHOOL_NATURE] = cinfo->ResistanceNature;
|
SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME);
|
||||||
createResistance[SPELL_SCHOOL_FROST] = cinfo->ResistanceFrost;
|
SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
|
||||||
createResistance[SPELL_SCHOOL_SHADOW] = cinfo->ResistanceShadow;
|
|
||||||
createResistance[SPELL_SCHOOL_ARCANE] = cinfo->ResistanceArcane;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetMeleeDamageSchool(SpellSchools(cInfo->DamageSchool));
|
||||||
|
SetAttackTime(BASE_ATTACK, cInfo->MeleeBaseAttackTime);
|
||||||
|
SetAttackTime(OFF_ATTACK, cInfo->MeleeBaseAttackTime);
|
||||||
|
SetAttackTime(RANGED_ATTACK, cInfo->RangedBaseAttackTime);
|
||||||
|
|
||||||
|
createResistance[SPELL_SCHOOL_HOLY] = cInfo->ResistanceHoly;
|
||||||
|
createResistance[SPELL_SCHOOL_FIRE] = cInfo->ResistanceFire;
|
||||||
|
createResistance[SPELL_SCHOOL_NATURE] = cInfo->ResistanceNature;
|
||||||
|
createResistance[SPELL_SCHOOL_FROST] = cInfo->ResistanceFrost;
|
||||||
|
createResistance[SPELL_SCHOOL_SHADOW] = cInfo->ResistanceShadow;
|
||||||
|
createResistance[SPELL_SCHOOL_ARCANE] = cInfo->ResistanceArcane;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
||||||
|
SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]));
|
||||||
|
|
||||||
|
float health, mana, armor, minDmg;
|
||||||
|
|
||||||
switch (getPetType())
|
switch (getPetType())
|
||||||
{
|
{
|
||||||
|
case HUNTER_PET:
|
||||||
|
{
|
||||||
|
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family);
|
||||||
|
|
||||||
|
if (cFamily && cFamily->minScale > 0.0f)
|
||||||
|
{
|
||||||
|
float scale;
|
||||||
|
if (getLevel() >= cFamily->maxScaleLevel)
|
||||||
|
scale = cFamily->maxScale;
|
||||||
|
else if (getLevel() <= cFamily->minScaleLevel)
|
||||||
|
scale = cFamily->minScale;
|
||||||
|
else
|
||||||
|
scale = cFamily->minScale + float(getLevel() - cFamily->minScaleLevel) / cFamily->maxScaleLevel * (cFamily->maxScale - cFamily->minScale);
|
||||||
|
|
||||||
|
SetObjectScale(scale);
|
||||||
|
UpdateModelData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max level
|
||||||
|
if (petlevel < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL))
|
||||||
|
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(petlevel));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||||
|
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info found in pet_levelstats
|
||||||
|
if (PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(1, petlevel))
|
||||||
|
{
|
||||||
|
for (int i = STAT_STRENGTH; i < MAX_STATS;++i)
|
||||||
|
SetCreateStat(Stats(i), float(pInfo->stats[i]));
|
||||||
|
|
||||||
|
health = pInfo->health;
|
||||||
|
mana = 0;
|
||||||
|
armor = pInfo->armor;
|
||||||
|
|
||||||
|
// First we divide attack time by standard attack time, and then multipy by level and damage mod.
|
||||||
|
uint32 mDmg = (GetAttackTime(BASE_ATTACK) * petlevel) / 2000;
|
||||||
|
|
||||||
|
// Set damage
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(mDmg - mDmg / 4));
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((mDmg - mDmg / 4) * 1.5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("HUNTER PET levelstats missing in DB! 'Weakifying' pet");
|
||||||
|
|
||||||
|
for (int i = STAT_STRENGTH; i < MAX_STATS;++i)
|
||||||
|
SetCreateStat(Stats(i), 1.0f);
|
||||||
|
|
||||||
|
health = 1;
|
||||||
|
mana = 0;
|
||||||
|
armor = 0;
|
||||||
|
|
||||||
|
// Set damage
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 1);
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SUMMON_PET:
|
case SUMMON_PET:
|
||||||
{
|
{
|
||||||
if (owner->GetTypeId() == TYPEID_PLAYER)
|
if (owner)
|
||||||
{
|
{
|
||||||
switch (owner->getClass())
|
switch (owner->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
{
|
{
|
||||||
|
|
||||||
// the damage bonus used for pets is either fire or shadow damage, whatever is higher
|
// the damage bonus used for pets is either fire or shadow damage, whatever is higher
|
||||||
uint32 fire = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE);
|
uint32 fire = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE);
|
||||||
uint32 shadow = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW);
|
uint32 shadow = owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW);
|
||||||
|
|
@ -924,109 +927,172 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
sLog.outError("Pet::InitStatsForLevel> No owner for creature pet %s !", GetGuidStr().c_str());
|
||||||
|
|
||||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
|
||||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
|
||||||
|
|
||||||
// SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower));
|
|
||||||
|
|
||||||
PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(creature_ID, petlevel);
|
|
||||||
if (pInfo) // exist in DB
|
|
||||||
{
|
|
||||||
SetCreateHealth(pInfo->health);
|
|
||||||
SetCreateMana(pInfo->mana);
|
|
||||||
|
|
||||||
if (pInfo->armor > 0)
|
|
||||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
|
||||||
|
|
||||||
for (int stat = 0; stat < MAX_STATS; ++stat)
|
|
||||||
{
|
|
||||||
SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // not exist in DB, use some default fake data
|
|
||||||
{
|
|
||||||
sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB", cinfo->Entry);
|
|
||||||
|
|
||||||
// remove elite bonuses included in DB values
|
|
||||||
SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel));
|
|
||||||
SetCreateMana(uint32(((float(cinfo->MaxLevelMana) / 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);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HUNTER_PET:
|
|
||||||
{
|
|
||||||
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(petlevel));
|
|
||||||
// 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)));
|
|
||||||
// damage range is then petlevel / 2
|
|
||||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
|
||||||
// damage is increased afterwards as strength and pet scaling modify attack power
|
|
||||||
|
|
||||||
// stored standard pet stats are entry 1 in pet_levelinfo
|
|
||||||
PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(creature_ID, petlevel);
|
|
||||||
if (pInfo) // exist in DB
|
|
||||||
{
|
|
||||||
SetCreateHealth(pInfo->health);
|
|
||||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
|
||||||
// SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower));
|
|
||||||
|
|
||||||
for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
|
||||||
{
|
|
||||||
SetCreateStat(Stats(i), float(pInfo->stats[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // not exist in DB, use some default fake data
|
|
||||||
{
|
|
||||||
sLog.outErrorDb("Hunter pet levelstats missing in DB");
|
|
||||||
|
|
||||||
// remove elite bonuses included in DB values
|
|
||||||
SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / 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);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GUARDIAN_PET:
|
|
||||||
case PROTECTOR_PET:
|
|
||||||
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||||
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||||
|
|
||||||
SetCreateMana(28 + 10 * petlevel);
|
// Info found in pet_levelstats
|
||||||
SetCreateHealth(28 + 30 * petlevel);
|
if (PetLevelInfo const* pInfo = sObjectMgr.GetPetLevelInfo(cInfo->Entry, petlevel))
|
||||||
|
{
|
||||||
|
for (int i = STAT_STRENGTH; i < MAX_STATS;++i)
|
||||||
|
SetCreateStat(Stats(i), float(pInfo->stats[i]));
|
||||||
|
|
||||||
// FIXME: this is wrong formula, possible each guardian pet have own damage formula
|
health = pInfo->health;
|
||||||
// these formula may not be correct; however, it is designed to be close to what it should be
|
mana = pInfo->mana;
|
||||||
// this makes dps 0.5 of pets level
|
armor = pInfo->armor;
|
||||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
|
||||||
// damage range is then petlevel / 2
|
// Info found in ClassLevelStats
|
||||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(petlevel, cInfo->UnitClass, cInfo->Expansion))
|
||||||
break;
|
{
|
||||||
default:
|
minDmg = (cCLS->BaseDamage * cInfo->DamageVariance + (cCLS->BaseMeleeAttackPower / 14) * (cInfo->MeleeBaseAttackTime/1000)) * cInfo->DamageMultiplier;
|
||||||
sLog.outError("Pet have incorrect type (%u) for levelup.", getPetType());
|
|
||||||
break;
|
// Apply custom damage setting (from config)
|
||||||
|
minDmg *= _GetDamageMod(cInfo->Rank);
|
||||||
|
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(minDmg));
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(minDmg * 1.5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("SUMMON_PET creature_template not finished (expansion field = -1) on creature %s! (entry: %u)", GetGuidStr().c_str(), cInfo->Entry);
|
||||||
|
|
||||||
|
float dMinLevel = cInfo->MinMeleeDmg / cInfo->MinLevel;
|
||||||
|
float dMaxLevel = cInfo->MaxMeleeDmg / cInfo->MaxLevel;
|
||||||
|
float mDmg = (dMaxLevel - ((dMaxLevel - dMinLevel) / 2)) * petlevel;
|
||||||
|
|
||||||
|
// Set damage
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(mDmg - mDmg / 4));
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((mDmg - mDmg / 4) * 1.5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("SUMMON_PET levelstats missing in DB! 'Weakifying' pet and giving it mana to make it obvious");
|
||||||
|
|
||||||
|
for (int i = STAT_STRENGTH; i < MAX_STATS;++i)
|
||||||
|
SetCreateStat(Stats(i), 1.0f);
|
||||||
|
|
||||||
|
health = 1;
|
||||||
|
mana = 1;
|
||||||
|
armor = 1;
|
||||||
|
|
||||||
|
// Set damage
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 1);
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
break;
|
||||||
SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]));
|
}
|
||||||
|
case PROTECTOR_PET:
|
||||||
|
case GUARDIAN_PET:
|
||||||
|
{
|
||||||
|
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(petlevel, cInfo->UnitClass, cInfo->Expansion))
|
||||||
|
{
|
||||||
|
health = cCLS->BaseHealth;
|
||||||
|
mana = cCLS->BaseMana;
|
||||||
|
armor = cCLS->BaseArmor;
|
||||||
|
|
||||||
|
// Melee
|
||||||
|
minDmg = (cCLS->BaseDamage * cInfo->DamageVariance + (cCLS->BaseMeleeAttackPower / 14) * (cInfo->MeleeBaseAttackTime/1000)) * cInfo->DamageMultiplier;
|
||||||
|
|
||||||
|
// Get custom setting
|
||||||
|
minDmg *= _GetDamageMod(cInfo->Rank);
|
||||||
|
|
||||||
|
// If the damage value is not passed on as float it will result in damage = 1; but only for guardian type pets, though...
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(minDmg));
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(minDmg * 1.5));
|
||||||
|
|
||||||
|
// Ranged
|
||||||
|
minDmg = (cCLS->BaseDamage * cInfo->DamageVariance + (cCLS->BaseRangedAttackPower / 14) * (cInfo->RangedBaseAttackTime/1000)) * cInfo->DamageMultiplier;
|
||||||
|
|
||||||
|
// Get custom setting
|
||||||
|
minDmg *= _GetDamageMod(cInfo->Rank);
|
||||||
|
|
||||||
|
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, float(minDmg));
|
||||||
|
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, float(minDmg * 1.5));
|
||||||
|
}
|
||||||
|
else // TODO: Remove fallback to creature_template data when DB is ready
|
||||||
|
{
|
||||||
|
if (petlevel >= cInfo->MaxLevel)
|
||||||
|
{
|
||||||
|
health = cInfo->MaxLevelHealth;
|
||||||
|
mana = cInfo->MaxLevelMana;
|
||||||
|
}
|
||||||
|
else if (petlevel <= cInfo->MinLevel)
|
||||||
|
{
|
||||||
|
health = cInfo->MinLevelHealth;
|
||||||
|
mana = cInfo->MinLevelMana;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float hMinLevel = cInfo->MinLevelHealth / cInfo->MinLevel;
|
||||||
|
float hMaxLevel = cInfo->MaxLevelHealth / cInfo->MaxLevel;
|
||||||
|
float mMinLevel = cInfo->MinLevelMana / cInfo->MinLevel;
|
||||||
|
float mMaxLevel = cInfo->MaxLevelMana / cInfo->MaxLevel;
|
||||||
|
|
||||||
|
health = (hMaxLevel - ((hMaxLevel - hMinLevel) / 2)) * petlevel;
|
||||||
|
mana = (mMaxLevel - ((mMaxLevel - mMinLevel) / 2)) * petlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
sLog.outErrorDb("Pet::InitStatsForLevel> Error trying to set stats for creature %s (entry: %u) using ClassLevelStats; not enough data to do it!", GetGuidStr().c_str(), cInfo->Entry);
|
||||||
|
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(cInfo->MinMeleeDmg));
|
||||||
|
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(cInfo->MaxMeleeDmg));
|
||||||
|
|
||||||
|
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, float(cInfo->MinRangedDmg));
|
||||||
|
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, float(cInfo->MaxRangedDmg));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
sLog.outError("Pet have incorrect type (%u) for level handling.", getPetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hunter's pets' should NOT use creature's original modifiers/multipliers
|
||||||
|
if (getPetType() != HUNTER_PET)
|
||||||
|
{
|
||||||
|
health *= cInfo->HealthMultiplier;
|
||||||
|
|
||||||
|
if (mana > 0)
|
||||||
|
mana *= cInfo->PowerMultiplier;
|
||||||
|
|
||||||
|
armor *= cInfo->ArmorMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply custom health setting (from config)
|
||||||
|
health *= _GetHealthMod(cInfo->Rank);
|
||||||
|
|
||||||
|
// Need to update stats before setting health and power or it will bug out in-game displaying it as the mob missing about 2/3
|
||||||
UpdateAllStats();
|
UpdateAllStats();
|
||||||
|
|
||||||
SetHealth(GetMaxHealth());
|
// A pet cannot not have health
|
||||||
SetPower(GetPowerType(), GetMaxPower(GetPowerType()));
|
if (health < 1)
|
||||||
|
health = 1;
|
||||||
|
|
||||||
return true;
|
// Set health
|
||||||
|
SetCreateHealth(health);
|
||||||
|
SetMaxHealth(health);
|
||||||
|
SetHealth(health);
|
||||||
|
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, health);
|
||||||
|
|
||||||
|
// Set mana
|
||||||
|
SetCreateMana(mana);
|
||||||
|
SetMaxPower(POWER_MANA, mana);
|
||||||
|
SetPower(POWER_MANA, mana);
|
||||||
|
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, mana);
|
||||||
|
|
||||||
|
// Remove rage bar from pets (By setting rage = 0, and ensuring it stays that way by setting max rage = 0 as well)
|
||||||
|
SetMaxPower(POWER_RAGE, 0);
|
||||||
|
SetPower(POWER_RAGE, 0);
|
||||||
|
SetModifierValue(UNIT_MOD_RAGE, BASE_VALUE, 0);
|
||||||
|
|
||||||
|
// Set armor
|
||||||
|
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pet::HaveInDiet(ItemPrototype const* item) const
|
bool Pet::HaveInDiet(ItemPrototype const* item) const
|
||||||
|
|
|
||||||
|
|
@ -184,10 +184,11 @@ class Pet : public Creature
|
||||||
void GivePetXP(uint32 xp);
|
void GivePetXP(uint32 xp);
|
||||||
void GivePetLevel(uint32 level);
|
void GivePetLevel(uint32 level);
|
||||||
void SynchronizeLevelWithOwner();
|
void SynchronizeLevelWithOwner();
|
||||||
bool InitStatsForLevel(uint32 level, Unit* owner = NULL);
|
void InitStatsForLevel(uint32 level);
|
||||||
bool HaveInDiet(ItemPrototype const* item) const;
|
bool HaveInDiet(ItemPrototype const* item) const;
|
||||||
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel);
|
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel);
|
||||||
void SetDuration(int32 dur) { m_duration = dur; }
|
void SetDuration(int32 dur) { m_duration = dur; }
|
||||||
|
int32 GetDuration() { return m_duration; }
|
||||||
|
|
||||||
int32 GetBonusDamage() { return m_bonusdamage; }
|
int32 GetBonusDamage() { return m_bonusdamage; }
|
||||||
void SetBonusDamage(int32 damage) { m_bonusdamage = damage; }
|
void SetBonusDamage(int32 damage) { m_bonusdamage = damage; }
|
||||||
|
|
@ -202,10 +203,6 @@ class Pet : public Creature
|
||||||
void UpdateDamagePhysical(WeaponAttackType attType) override;
|
void UpdateDamagePhysical(WeaponAttackType attType) override;
|
||||||
uint32 GetCurrentEquipmentId() const { return m_equipmentId; }
|
uint32 GetCurrentEquipmentId() const { return m_equipmentId; }
|
||||||
|
|
||||||
static float _GetHealthMod(int32 Rank); ///< Get custom factor to scale health (default 1, CONFIG_FLOAT_RATE_CREATURE_*_HP)
|
|
||||||
static float _GetDamageMod(int32 Rank); ///< Get custom factor to scale damage (default 1, CONFIG_FLOAT_RATE_*_DAMAGE)
|
|
||||||
static float _GetSpellDamageMod(int32 Rank); ///< Get custom factor to scale spell damage (default 1, CONFIG_FLOAT_RATE_*_SPELLDAMAGE)
|
|
||||||
|
|
||||||
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
|
bool CanTakeMoreActiveSpells(uint32 SpellIconID);
|
||||||
void ToggleAutocast(uint32 spellid, bool apply);
|
void ToggleAutocast(uint32 spellid, bool apply);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,22 +50,24 @@ PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK), inComb
|
||||||
|
|
||||||
void PetAI::MoveInLineOfSight(Unit* pWho)
|
void PetAI::MoveInLineOfSight(Unit* pWho)
|
||||||
{
|
{
|
||||||
if (m_creature->getVictim())
|
if (Unit* victim = m_creature->getVictim())
|
||||||
|
if (victim->IsAlive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE))
|
if (CharmInfo* charmInfo = m_creature->GetCharmInfo())
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() &&
|
|
||||||
m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature))
|
|
||||||
{
|
{
|
||||||
if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
|
if (charmInfo->HasReactState(REACT_AGGRESSIVE)
|
||||||
return;
|
&& !(m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
|
||||||
|
&& pWho && pWho->IsTargetableForAttack() && pWho->isInAccessablePlaceFor(m_creature)
|
||||||
if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho))
|
&& (m_creature->IsHostileTo(pWho) || pWho->IsHostileTo(m_creature->GetCharmerOrOwner()))
|
||||||
|
&& m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho))
|
||||||
|
&& m_creature->GetDistanceZ(pWho) <= CREATURE_Z_ATTACK_RANGE
|
||||||
|
&& m_creature->IsWithinLOSInMap(pWho))
|
||||||
{
|
{
|
||||||
pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
|
||||||
AttackStart(pWho);
|
AttackStart(pWho);
|
||||||
|
|
||||||
|
if (Unit* owner = m_creature->GetOwner())
|
||||||
|
owner->SetInCombatState(true, pWho);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +83,9 @@ void PetAI::AttackStart(Unit* u)
|
||||||
// thus with the following clear the original TMG gets invalidated and crash, doh
|
// thus with the following clear the original TMG gets invalidated and crash, doh
|
||||||
// hope it doesn't start to leak memory without this :-/
|
// hope it doesn't start to leak memory without this :-/
|
||||||
// i_pet->Clear();
|
// i_pet->Clear();
|
||||||
|
if (!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
|
||||||
HandleMovementOnAttackStart(u);
|
HandleMovementOnAttackStart(u);
|
||||||
|
|
||||||
inCombat = true;
|
inCombat = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2687,6 +2687,9 @@ void Player::GiveLevel(uint32 level)
|
||||||
MailDraft(mailReward->mailTemplateId).SendMailTo(this, MailSender(MAIL_CREATURE, mailReward->senderEntry));
|
MailDraft(mailReward->mailTemplateId).SendMailTo(this, MailSender(MAIL_CREATURE, mailReward->senderEntry));
|
||||||
|
|
||||||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
|
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
|
||||||
|
|
||||||
|
// resend quests status directly
|
||||||
|
SendQuestGiverStatusMultiple();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::UpdateFreeTalentPoints(bool resetIfNeed)
|
void Player::UpdateFreeTalentPoints(bool resetIfNeed)
|
||||||
|
|
@ -2877,7 +2880,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
|
||||||
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST);
|
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST);
|
||||||
|
|
||||||
RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes
|
RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes
|
||||||
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP | UNIT_BYTE2_FLAG_SUPPORTABLE);
|
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||||
|
|
||||||
// restore if need some important flags
|
// restore if need some important flags
|
||||||
SetUInt32Value(PLAYER_FIELD_BYTES2, 0); // flags empty by default
|
SetUInt32Value(PLAYER_FIELD_BYTES2, 0); // flags empty by default
|
||||||
|
|
@ -13897,6 +13900,9 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver,
|
||||||
saBounds = sSpellMgr.GetSpellAreaForAreaMapBounds(0);
|
saBounds = sSpellMgr.GetSpellAreaForAreaMapBounds(0);
|
||||||
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
||||||
itr->second->ApplyOrRemoveSpellIfCan(this, zone, area, false);
|
itr->second->ApplyOrRemoveSpellIfCan(this, zone, area, false);
|
||||||
|
|
||||||
|
// resend quests status directly
|
||||||
|
SendQuestGiverStatusMultiple();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::IncompleteQuest(uint32 quest_id)
|
void Player::IncompleteQuest(uint32 quest_id)
|
||||||
|
|
@ -15199,6 +15205,60 @@ void Player::SendQuestUpdateAddCreatureOrGo(Quest const* pQuest, ObjectGuid guid
|
||||||
SetQuestSlotCounter(log_slot, creatureOrGO_idx, count);
|
SetQuestSlotCounter(log_slot, creatureOrGO_idx, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::SendQuestGiverStatusMultiple()
|
||||||
|
{
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
|
||||||
|
data << uint32(count); // placeholder
|
||||||
|
|
||||||
|
for (GuidSet::const_iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (itr->IsAnyTypeCreature())
|
||||||
|
{
|
||||||
|
// need also pet quests case support
|
||||||
|
Creature* questgiver = GetMap()->GetAnyTypeCreature(*itr);
|
||||||
|
|
||||||
|
if (!questgiver || questgiver->IsHostileTo(this))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8 dialogStatus = sScriptMgr.GetDialogStatus(this, questgiver);
|
||||||
|
|
||||||
|
if (dialogStatus == DIALOG_STATUS_REWARD_REP)
|
||||||
|
dialogStatus = GetSession()->getDialogStatus(this, questgiver, DIALOG_STATUS_NONE);
|
||||||
|
|
||||||
|
data << questgiver->GetObjectGuid();
|
||||||
|
data << uint8(dialogStatus);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else if (itr->IsGameObject())
|
||||||
|
{
|
||||||
|
GameObject* questgiver = GetMap()->GetGameObject(*itr);
|
||||||
|
|
||||||
|
if (!questgiver)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8 dialogStatus = sScriptMgr.GetDialogStatus(this, questgiver);
|
||||||
|
|
||||||
|
if (dialogStatus == DIALOG_STATUS_REWARD_REP)
|
||||||
|
dialogStatus = GetSession()->getDialogStatus(this, questgiver, DIALOG_STATUS_NONE);
|
||||||
|
|
||||||
|
data << questgiver->GetObjectGuid();
|
||||||
|
data << uint8(dialogStatus);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.put<uint32>(0, count); // write real count
|
||||||
|
GetSession()->SendPacket(&data);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
/*** LOAD SYSTEM ***/
|
/*** LOAD SYSTEM ***/
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
|
|
@ -16840,6 +16900,7 @@ void Player::_LoadTalents(QueryResult* result)
|
||||||
while (result->NextRow());
|
while (result->NextRow());
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
UpdateGroupLeaderFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::_LoadGroup(QueryResult* result)
|
void Player::_LoadGroup(QueryResult* result)
|
||||||
|
|
@ -21497,6 +21558,18 @@ PartyResult Player::CanUninviteFromGroup() const
|
||||||
return ERR_PARTY_RESULT_OK;
|
return ERR_PARTY_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::UpdateGroupLeaderFlag(const bool remove /*= false*/)
|
||||||
|
{
|
||||||
|
const Group* group = GetGroup();
|
||||||
|
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER))
|
||||||
|
{
|
||||||
|
if (remove || !group || group->GetLeaderGuid() != GetObjectGuid())
|
||||||
|
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER);
|
||||||
|
}
|
||||||
|
else if (!remove && group && group->GetLeaderGuid() == GetObjectGuid())
|
||||||
|
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER);
|
||||||
|
}
|
||||||
|
|
||||||
void Player::SetBattleGroundRaid(Group* group, int8 subgroup)
|
void Player::SetBattleGroundRaid(Group* group, int8 subgroup)
|
||||||
{
|
{
|
||||||
// we must move references from m_group to m_originalGroup
|
// we must move references from m_group to m_originalGroup
|
||||||
|
|
|
||||||
|
|
@ -1558,6 +1558,7 @@ class Player : public Unit
|
||||||
void SendQuestConfirmAccept(const Quest* pQuest, Player* pReceiver);
|
void SendQuestConfirmAccept(const Quest* pQuest, Player* pReceiver);
|
||||||
void SendPushToPartyResponse(Player* pPlayer, uint32 msg);
|
void SendPushToPartyResponse(Player* pPlayer, uint32 msg);
|
||||||
void SendQuestUpdateAddCreatureOrGo(Quest const* pQuest, ObjectGuid guid, uint32 creatureOrGO_idx, uint32 count);
|
void SendQuestUpdateAddCreatureOrGo(Quest const* pQuest, ObjectGuid guid, uint32 creatureOrGO_idx, uint32 count);
|
||||||
|
void SendQuestGiverStatusMultiple();
|
||||||
|
|
||||||
ObjectGuid GetDividerGuid() const { return m_dividerGuid; }
|
ObjectGuid GetDividerGuid() const { return m_dividerGuid; }
|
||||||
void SetDividerGuid(ObjectGuid guid) { m_dividerGuid = guid; }
|
void SetDividerGuid(ObjectGuid guid) { m_dividerGuid = guid; }
|
||||||
|
|
@ -2531,6 +2532,7 @@ class Player : public Unit
|
||||||
uint32 GetNextResetTalentsCost() const;
|
uint32 GetNextResetTalentsCost() const;
|
||||||
Player* GetNextRandomRaidMember(float radius);
|
Player* GetNextRandomRaidMember(float radius);
|
||||||
PartyResult CanUninviteFromGroup() const;
|
PartyResult CanUninviteFromGroup() const;
|
||||||
|
void UpdateGroupLeaderFlag(const bool remove = false);
|
||||||
// BattleGround Group System
|
// BattleGround Group System
|
||||||
void SetBattleGroundRaid(Group* group, int8 subgroup = -1);
|
void SetBattleGroundRaid(Group* group, int8 subgroup = -1);
|
||||||
void RemoveFromBattleGroundRaid();
|
void RemoveFromBattleGroundRaid();
|
||||||
|
|
|
||||||
|
|
@ -855,7 +855,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
||||||
case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
|
case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
|
||||||
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
|
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
|
||||||
if (spellEffect->CalculateSimpleValue() > 0)
|
if (spellEffect->CalculateSimpleValue() > 0)
|
||||||
return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE or unclear target modes
|
return true; // some expected positive spells have SPELL_ATTR_NEGATIVE or unclear target modes
|
||||||
break;
|
break;
|
||||||
case SPELL_AURA_ADD_TARGET_TRIGGER:
|
case SPELL_AURA_ADD_TARGET_TRIGGER:
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -924,7 +924,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
||||||
spellproto->GetSpellFamilyName() == SPELLFAMILY_GENERIC)
|
spellproto->GetSpellFamilyName() == SPELLFAMILY_GENERIC)
|
||||||
return false;
|
return false;
|
||||||
// but not this if this first effect (don't found better check)
|
// but not this if this first effect (don't found better check)
|
||||||
if (spellproto->HasAttribute(SPELL_ATTR_UNK26) && effIndex == EFFECT_INDEX_0)
|
if (spellproto->HasAttribute(SPELL_ATTR_NEGATIVE) && effIndex == EFFECT_INDEX_0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case SPELL_AURA_TRANSFORM:
|
case SPELL_AURA_TRANSFORM:
|
||||||
|
|
@ -1032,7 +1032,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// AttributesEx check
|
// AttributesEx check
|
||||||
if (spellproto->HasAttribute(SPELL_ATTR_EX_NEGATIVE))
|
if (spellproto->HasAttribute(SPELL_ATTR_NEGATIVE))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// ok, positive
|
// ok, positive
|
||||||
|
|
@ -2728,6 +2728,17 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SpellMgr::IsSpellCanAffectSpell(SpellEntry const* spellInfo_1, SpellEntry const* spellInfo_2) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
|
||||||
|
{
|
||||||
|
ClassFamilyMask mask = spellInfo_1->GetEffectSpellClassMask(SpellEffectIndex(i));
|
||||||
|
if (spellInfo_2->IsFitToFamilyMask(mask))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId)
|
bool SpellMgr::IsProfessionOrRidingSpell(uint32 spellId)
|
||||||
{
|
{
|
||||||
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
|
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
|
||||||
|
|
|
||||||
|
|
@ -1155,6 +1155,9 @@ class SpellMgr
|
||||||
return !canStackSpellRanksInSpellBook(spellInfo) && GetSpellRank(spellInfo->Id) != 0;
|
return !canStackSpellRanksInSpellBook(spellInfo) && GetSpellRank(spellInfo->Id) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if spell1 can affect spell2
|
||||||
|
bool IsSpellCanAffectSpell(SpellEntry const* spellInfo_1, SpellEntry const* spellInfo_2) const;
|
||||||
|
|
||||||
SpellEntry const* SelectAuraRankForLevel(SpellEntry const* spellInfo, uint32 Level) const;
|
SpellEntry const* SelectAuraRankForLevel(SpellEntry const* spellInfo, uint32 Level) const;
|
||||||
|
|
||||||
// Spell learning
|
// Spell learning
|
||||||
|
|
|
||||||
|
|
@ -2898,12 +2898,7 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
|
||||||
if (IsNonMeleeSpellCasted(false))
|
if (IsNonMeleeSpellCasted(false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 hitInfo;
|
if (attType == RANGED_ATTACK)
|
||||||
if (attType == BASE_ATTACK)
|
|
||||||
hitInfo = HITINFO_NORMALSWING2;
|
|
||||||
else if (attType == OFF_ATTACK)
|
|
||||||
hitInfo = HITINFO_LEFTSWING;
|
|
||||||
else
|
|
||||||
return; // ignore ranged case
|
return; // ignore ranged case
|
||||||
|
|
||||||
uint32 extraAttacks = m_extraAttacks;
|
uint32 extraAttacks = m_extraAttacks;
|
||||||
|
|
@ -4637,7 +4632,13 @@ bool Unit::RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder* holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
// non single (per caster) per target spell specific (possible single spell per target at caster)
|
// non single (per caster) per target spell specific (possible single spell per target at caster)
|
||||||
if (!is_spellSpecPerTargetPerCaster && !is_spellSpecPerTarget && sSpellMgr.IsNoStackSpellDueToSpell(spellId, i_spellId))
|
if (!is_spellSpecPerTargetPerCaster && !is_spellSpecPerTarget)
|
||||||
|
{
|
||||||
|
SpellEntry const* triggeredBy = holder->GetTriggeredBy();
|
||||||
|
if (triggeredBy && sSpellMgr.IsSpellCanAffectSpell(triggeredBy, i_spellProto)) // check if this spell can be triggered by any talent aura
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sSpellMgr.IsNoStackSpellDueToSpell(spellProto->Id, i_spellProto->Id))
|
||||||
{
|
{
|
||||||
// Its a parent aura (create this aura in ApplyModifier)
|
// Its a parent aura (create this aura in ApplyModifier)
|
||||||
if ((*i).second->IsInUse())
|
if ((*i).second->IsInUse())
|
||||||
|
|
@ -4651,7 +4652,7 @@ bool Unit::RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder* holder)
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
next = m_spellAuraHolders.begin();
|
next = m_spellAuraHolders.begin();
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -10945,7 +10946,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag,
|
||||||
for (SpellAuraHolderMap::const_iterator itr = GetSpellAuraHolderMap().begin(); itr != GetSpellAuraHolderMap().end(); ++itr)
|
for (SpellAuraHolderMap::const_iterator itr = GetSpellAuraHolderMap().begin(); itr != GetSpellAuraHolderMap().end(); ++itr)
|
||||||
{
|
{
|
||||||
// skip deleted auras (possible at recursive triggered call
|
// skip deleted auras (possible at recursive triggered call
|
||||||
if (itr->second->IsDeleted())
|
if (itr->second->GetState() != SPELLAURAHOLDER_STATE_READY || itr->second->IsDeleted())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SpellProcEventEntry const* spellProcEvent = NULL;
|
SpellProcEventEntry const* spellProcEvent = NULL;
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ enum SpellAttributes
|
||||||
SPELL_ATTR_UNK23 = 0x00800000,// 23 castable while dead?
|
SPELL_ATTR_UNK23 = 0x00800000,// 23 castable while dead?
|
||||||
SPELL_ATTR_CASTABLE_WHILE_MOUNTED = 0x01000000,// 24 castable while mounted
|
SPELL_ATTR_CASTABLE_WHILE_MOUNTED = 0x01000000,// 24 castable while mounted
|
||||||
SPELL_ATTR_DISABLED_WHILE_ACTIVE = 0x02000000,// 25 Activate and start cooldown after aura fade or remove summoned creature or go
|
SPELL_ATTR_DISABLED_WHILE_ACTIVE = 0x02000000,// 25 Activate and start cooldown after aura fade or remove summoned creature or go
|
||||||
SPELL_ATTR_UNK26 = 0x04000000,// 26
|
SPELL_ATTR_NEGATIVE = 0x04000000,// 26 Almost all negative spell have it
|
||||||
SPELL_ATTR_CASTABLE_WHILE_SITTING = 0x08000000,// 27 castable while sitting
|
SPELL_ATTR_CASTABLE_WHILE_SITTING = 0x08000000,// 27 castable while sitting
|
||||||
SPELL_ATTR_CANT_USED_IN_COMBAT = 0x10000000,// 28 Cannot be used in combat
|
SPELL_ATTR_CANT_USED_IN_COMBAT = 0x10000000,// 28 Cannot be used in combat
|
||||||
SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY = 0x20000000,// 29 unaffected by invulnerability (hmm possible not...)
|
SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY = 0x20000000,// 29 unaffected by invulnerability (hmm possible not...)
|
||||||
|
|
@ -314,7 +314,7 @@ enum SpellAttributesEx
|
||||||
SPELL_ATTR_EX_UNK4 = 0x00000010,// 4
|
SPELL_ATTR_EX_UNK4 = 0x00000010,// 4
|
||||||
SPELL_ATTR_EX_NOT_BREAK_STEALTH = 0x00000020,// 5 Not break stealth
|
SPELL_ATTR_EX_NOT_BREAK_STEALTH = 0x00000020,// 5 Not break stealth
|
||||||
SPELL_ATTR_EX_CHANNELED_2 = 0x00000040,// 6 channeled 2
|
SPELL_ATTR_EX_CHANNELED_2 = 0x00000040,// 6 channeled 2
|
||||||
SPELL_ATTR_EX_NEGATIVE = 0x00000080,// 7
|
SPELL_ATTR_EX_UNK7 = 0x00000080,// 7
|
||||||
SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET = 0x00000100,// 8 Spell req target not to be in combat state
|
SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET = 0x00000100,// 8 Spell req target not to be in combat state
|
||||||
SPELL_ATTR_EX_UNK9 = 0x00000200,// 9
|
SPELL_ATTR_EX_UNK9 = 0x00000200,// 9
|
||||||
SPELL_ATTR_EX_NO_THREAT = 0x00000400,// 10 no generates threat on cast 100%
|
SPELL_ATTR_EX_NO_THREAT = 0x00000400,// 10 no generates threat on cast 100%
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,8 @@ bool Group::Create(ObjectGuid guid, const char* name)
|
||||||
|
|
||||||
m_lootMethod = GROUP_LOOT;
|
m_lootMethod = GROUP_LOOT;
|
||||||
m_lootThreshold = ITEM_QUALITY_UNCOMMON;
|
m_lootThreshold = ITEM_QUALITY_UNCOMMON;
|
||||||
m_looterGuid = guid;
|
m_masterLooterGuid = guid;
|
||||||
|
m_currentLooterGuid = guid; // used for round robin looter
|
||||||
|
|
||||||
m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL;
|
m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL;
|
||||||
m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
|
m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
|
||||||
|
|
@ -155,7 +156,7 @@ bool Group::Create(ObjectGuid guid, const char* name)
|
||||||
CharacterDatabase.PExecute("INSERT INTO groups (groupId,leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,groupType,difficulty,raiddifficulty) "
|
CharacterDatabase.PExecute("INSERT INTO groups (groupId,leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,groupType,difficulty,raiddifficulty) "
|
||||||
"VALUES ('%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')",
|
"VALUES ('%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')",
|
||||||
m_Id, m_leaderGuid.GetCounter(), m_mainTankGuid.GetCounter(), m_mainAssistantGuid.GetCounter(), uint32(m_lootMethod),
|
m_Id, m_leaderGuid.GetCounter(), m_mainTankGuid.GetCounter(), m_mainAssistantGuid.GetCounter(), uint32(m_lootMethod),
|
||||||
m_looterGuid.GetCounter(), uint32(m_lootThreshold),
|
m_masterLooterGuid.GetCounter(), uint32(m_lootThreshold),
|
||||||
m_targetIcons[0].GetRawValue(), m_targetIcons[1].GetRawValue(),
|
m_targetIcons[0].GetRawValue(), m_targetIcons[1].GetRawValue(),
|
||||||
m_targetIcons[2].GetRawValue(), m_targetIcons[3].GetRawValue(),
|
m_targetIcons[2].GetRawValue(), m_targetIcons[3].GetRawValue(),
|
||||||
m_targetIcons[4].GetRawValue(), m_targetIcons[5].GetRawValue(),
|
m_targetIcons[4].GetRawValue(), m_targetIcons[5].GetRawValue(),
|
||||||
|
|
@ -169,6 +170,8 @@ bool Group::Create(ObjectGuid guid, const char* name)
|
||||||
if (!isBGGroup())
|
if (!isBGGroup())
|
||||||
CharacterDatabase.CommitTransaction();
|
CharacterDatabase.CommitTransaction();
|
||||||
|
|
||||||
|
_updateLeaderFlag();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,8 +272,10 @@ bool Group::AddLeaderInvite(Player* player)
|
||||||
if (!AddInvite(player))
|
if (!AddInvite(player))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
_updateLeaderFlag(true);
|
||||||
m_leaderGuid = player->GetObjectGuid();
|
m_leaderGuid = player->GetObjectGuid();
|
||||||
m_leaderName = player->GetName();
|
m_leaderName = player->GetName();
|
||||||
|
_updateLeaderFlag();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,6 +489,7 @@ void Group::Disband(bool hideDestroy)
|
||||||
ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL);
|
ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateLeaderFlag(true);
|
||||||
m_leaderGuid.Clear();
|
m_leaderGuid.Clear();
|
||||||
m_leaderName.clear();
|
m_leaderName.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -1367,6 +1373,12 @@ void Group::_removeRolls(ObjectGuid guid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::_updateLeaderFlag(const bool remove /*= false*/)
|
||||||
|
{
|
||||||
|
if (Player* player = sObjectMgr.GetPlayer(m_leaderGuid))
|
||||||
|
player->UpdateGroupLeaderFlag(remove);
|
||||||
|
}
|
||||||
|
|
||||||
bool Group::_setMembersGroup(ObjectGuid guid, uint8 group)
|
bool Group::_setMembersGroup(ObjectGuid guid, uint8 group)
|
||||||
{
|
{
|
||||||
member_witerator slot = _getMemberWSlot(guid);
|
member_witerator slot = _getMemberWSlot(guid);
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,8 @@ class Group
|
||||||
|
|
||||||
void _removeRolls(ObjectGuid guid);
|
void _removeRolls(ObjectGuid guid);
|
||||||
|
|
||||||
|
void _updateLeaderFlag(const bool remove = false);
|
||||||
|
|
||||||
bool _setMembersGroup(ObjectGuid guid, uint8 group);
|
bool _setMembersGroup(ObjectGuid guid, uint8 group);
|
||||||
bool _setAssistantFlag(ObjectGuid guid, const bool& state);
|
bool _setAssistantFlag(ObjectGuid guid, const bool& state);
|
||||||
bool _setMainTank(ObjectGuid guid);
|
bool _setMainTank(ObjectGuid guid);
|
||||||
|
|
@ -489,6 +491,8 @@ class Group
|
||||||
LootMethod m_lootMethod;
|
LootMethod m_lootMethod;
|
||||||
ItemQualities m_lootThreshold;
|
ItemQualities m_lootThreshold;
|
||||||
ObjectGuid m_looterGuid;
|
ObjectGuid m_looterGuid;
|
||||||
|
ObjectGuid m_masterLooterGuid;
|
||||||
|
ObjectGuid m_currentLooterGuid;
|
||||||
Rolls RollId;
|
Rolls RollId;
|
||||||
BoundInstancesMap m_boundInstances[MAX_DIFFICULTY];
|
BoundInstancesMap m_boundInstances[MAX_DIFFICULTY];
|
||||||
uint8* m_subGroupsCounts;
|
uint8* m_subGroupsCounts;
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,9 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetPlayer()->GetObjectGuid() != pet->GetCharmerOrOwnerGuid())
|
if (_player->GetObjectGuid() != pet->GetCharmerOrOwnerGuid())
|
||||||
{
|
{
|
||||||
sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str());
|
sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), _player->GetGuidStr().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,45 +118,35 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
}
|
}
|
||||||
case COMMAND_ATTACK: // spellid=1792 // ATTACK
|
case COMMAND_ATTACK: // spellid=1792 // ATTACK
|
||||||
{
|
{
|
||||||
Unit* TargetUnit = _player->GetMap()->GetUnit(targetGuid);
|
((Pet*)pet)->SetIsRetreating();
|
||||||
if (!TargetUnit)
|
((Pet*)pet)->SetSpellOpener();
|
||||||
return;
|
|
||||||
|
|
||||||
// not let attack friendly units.
|
Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr;
|
||||||
if (GetPlayer()->IsFriendlyTo(TargetUnit))
|
|
||||||
return;
|
if (targetUnit && targetUnit != pet && targetUnit->IsTargetableForAttack() && targetUnit->isInAccessablePlaceFor((Creature*)pet))
|
||||||
// Not let attack through obstructions
|
{
|
||||||
if (!pet->IsWithinLOSInMap(TargetUnit))
|
_player->SetInCombatState(true, targetUnit);
|
||||||
return;
|
|
||||||
|
|
||||||
// This is true if pet has no target or has target but targets differs.
|
// This is true if pet has no target or has target but targets differs.
|
||||||
if (pet->getVictim() != TargetUnit)
|
if (pet->getVictim() != targetUnit)
|
||||||
{
|
{
|
||||||
if (pet->getVictim())
|
|
||||||
pet->AttackStop();
|
pet->AttackStop();
|
||||||
|
|
||||||
if (pet->hasUnitState(UNIT_STAT_CONTROLLED))
|
|
||||||
{
|
|
||||||
pet->Attack(TargetUnit, true);
|
|
||||||
pet->SendPetAIReaction();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pet->GetMotionMaster()->Clear();
|
pet->GetMotionMaster()->Clear();
|
||||||
|
|
||||||
if (((Creature*)pet)->AI())
|
if (((Creature*)pet)->AI())
|
||||||
((Creature*)pet)->AI()->AttackStart(TargetUnit);
|
|
||||||
|
|
||||||
// 10% chance to play special pet attack talk, else growl
|
|
||||||
if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && roll_chance_i(10))
|
|
||||||
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// 90% chance for pet and 100% chance for charmed creature
|
((Creature*)pet)->AI()->AttackStart(targetUnit);
|
||||||
|
// 10% chance to play special warlock pet attack talk, else growl
|
||||||
|
if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && roll_chance_i(10))
|
||||||
|
pet->SendPetTalk((uint32)PET_TALK_ATTACK);
|
||||||
|
|
||||||
pet->SendPetAIReaction();
|
pet->SendPetAIReaction();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
pet->Attack(targetUnit, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
|
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
|
||||||
|
|
@ -208,9 +198,10 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
case ACT_PASSIVE: // 0x01
|
case ACT_PASSIVE: // 0x01
|
||||||
case ACT_ENABLED: // 0xC1 spell
|
case ACT_ENABLED: // 0xC1 spell
|
||||||
{
|
{
|
||||||
Unit* unit_target = NULL;
|
((Pet*)pet)->SetIsRetreating();
|
||||||
if (targetGuid)
|
((Pet*)pet)->SetSpellOpener();
|
||||||
unit_target = _player->GetMap()->GetUnit(targetGuid);
|
|
||||||
|
Unit* unit_target = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr;
|
||||||
|
|
||||||
// do not cast unknown spells
|
// do not cast unknown spells
|
||||||
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
|
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
|
||||||
|
|
@ -228,7 +219,10 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i));
|
SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i));
|
||||||
if (!spellEffect)
|
if (!spellEffect)
|
||||||
continue;
|
continue;
|
||||||
if (spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA || spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
|
|
||||||
|
if (spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA
|
||||||
|
|| spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_INSTANT
|
||||||
|
|| spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,6 +230,8 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
|
||||||
if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
|
if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_player->SetInCombatState(true, unit_target);
|
||||||
|
|
||||||
pet->clearUnitState(UNIT_STAT_MOVING);
|
pet->clearUnitState(UNIT_STAT_MOVING);
|
||||||
|
|
||||||
Spell* spell = new Spell(pet, spellInfo, false);
|
Spell* spell = new Spell(pet, spellInfo, false);
|
||||||
|
|
|
||||||
|
|
@ -550,14 +550,10 @@ uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32
|
||||||
|
|
||||||
QuestStatus status = pPlayer->GetQuestStatus(quest_id);
|
QuestStatus status = pPlayer->GetQuestStatus(quest_id);
|
||||||
|
|
||||||
if ((status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) ||
|
if (status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id))
|
||||||
(pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)))
|
dialogStatusNew = pQuest->IsRepeatable() ? DIALOG_STATUS_REWARD_REP : DIALOG_STATUS_REWARD;
|
||||||
{
|
else if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false))
|
||||||
if (pQuest->IsAutoComplete() && pQuest->IsRepeatable())
|
dialogStatusNew = pQuest->IsRepeatable() ? DIALOG_STATUS_AVAILABLE_REP : DIALOG_STATUS_AVAILABLE;
|
||||||
dialogStatusNew = DIALOG_STATUS_REWARD_REP;
|
|
||||||
else
|
|
||||||
dialogStatusNew = DIALOG_STATUS_REWARD;
|
|
||||||
}
|
|
||||||
else if (status == QUEST_STATUS_INCOMPLETE)
|
else if (status == QUEST_STATUS_INCOMPLETE)
|
||||||
dialogStatusNew = DIALOG_STATUS_INCOMPLETE;
|
dialogStatusNew = DIALOG_STATUS_INCOMPLETE;
|
||||||
|
|
||||||
|
|
@ -614,58 +610,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket
|
||||||
{
|
{
|
||||||
DEBUG_LOG("WORLD: Received opcode CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY");
|
DEBUG_LOG("WORLD: Received opcode CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY");
|
||||||
|
|
||||||
uint32 count = 0;
|
_player->SendQuestGiverStatusMultiple();
|
||||||
|
|
||||||
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
|
|
||||||
data << uint32(count); // placeholder
|
|
||||||
|
|
||||||
for (GuidSet::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
|
|
||||||
{
|
|
||||||
uint32 dialogStatus = DIALOG_STATUS_NONE;
|
|
||||||
|
|
||||||
if (itr->IsAnyTypeCreature())
|
|
||||||
{
|
|
||||||
// need also pet quests case support
|
|
||||||
Creature* questgiver = GetPlayer()->GetMap()->GetAnyTypeCreature(*itr);
|
|
||||||
|
|
||||||
if (!questgiver || questgiver->IsHostileTo(_player))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dialogStatus = sScriptMgr.GetDialogStatus(_player, questgiver);
|
|
||||||
|
|
||||||
if (dialogStatus > DIALOG_STATUS_REWARD_REP)
|
|
||||||
dialogStatus = getDialogStatus(_player, questgiver, DIALOG_STATUS_NONE);
|
|
||||||
|
|
||||||
data << questgiver->GetObjectGuid();
|
|
||||||
data << uint32(dialogStatus);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
else if (itr->IsGameObject())
|
|
||||||
{
|
|
||||||
GameObject* questgiver = GetPlayer()->GetMap()->GetGameObject(*itr);
|
|
||||||
|
|
||||||
if (!questgiver)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dialogStatus = sScriptMgr.GetDialogStatus(_player, questgiver);
|
|
||||||
|
|
||||||
if (dialogStatus > DIALOG_STATUS_REWARD_REP)
|
|
||||||
dialogStatus = getDialogStatus(_player, questgiver, DIALOG_STATUS_NONE);
|
|
||||||
|
|
||||||
data << questgiver->GetObjectGuid();
|
|
||||||
data << uint32(dialogStatus);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.put<uint32>(0, count); // write real count
|
|
||||||
SendPacket(&data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldSession::CanInteractWithQuestGiver(ObjectGuid guid, char const* descr)
|
bool WorldSession::CanInteractWithQuestGiver(ObjectGuid guid, char const* descr)
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,7 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or
|
||||||
m_cast_count = 0;
|
m_cast_count = 0;
|
||||||
m_glyphIndex = 0;
|
m_glyphIndex = 0;
|
||||||
m_triggeredByAuraSpell = NULL;
|
m_triggeredByAuraSpell = NULL;
|
||||||
|
m_spellAuraHolder = NULL;
|
||||||
|
|
||||||
// Auto Shot & Shoot (wand)
|
// Auto Shot & Shoot (wand)
|
||||||
m_autoRepeat = IsAutoRepeatRangedSpell(m_spellInfo);
|
m_autoRepeat = IsAutoRepeatRangedSpell(m_spellInfo);
|
||||||
|
|
@ -463,7 +464,7 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or
|
||||||
if(!IsPositiveTarget(spellEffect->EffectImplicitTargetA, spellEffect->EffectImplicitTargetB))
|
if(!IsPositiveTarget(spellEffect->EffectImplicitTargetA, spellEffect->EffectImplicitTargetB))
|
||||||
m_canReflect = true;
|
m_canReflect = true;
|
||||||
else
|
else
|
||||||
m_canReflect = m_spellInfo->HasAttribute(SPELL_ATTR_EX_NEGATIVE);
|
m_canReflect = m_spellInfo->HasAttribute(SPELL_ATTR_EX_UNK7);
|
||||||
|
|
||||||
if (m_canReflect)
|
if (m_canReflect)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1285,6 +1286,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||||
((Creature*)m_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
|
((Creature*)m_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
|
||||||
if (real_caster && real_caster != m_caster && real_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)real_caster)->AI())
|
if (real_caster && real_caster != m_caster && real_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)real_caster)->AI())
|
||||||
((Creature*)real_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
|
((Creature*)real_caster)->AI()->SpellHitTarget(unit, m_spellInfo);
|
||||||
|
|
||||||
|
if (m_spellAuraHolder)
|
||||||
|
m_spellAuraHolder->SetState(SPELLAURAHOLDER_STATE_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
|
void Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
|
||||||
|
|
@ -1403,7 +1407,7 @@ void Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask)
|
||||||
|
|
||||||
if (IsSpellAppliesAura(m_spellInfo, effectMask))
|
if (IsSpellAppliesAura(m_spellInfo, effectMask))
|
||||||
{
|
{
|
||||||
m_spellAuraHolder = CreateSpellAuraHolder(m_spellInfo, unit, realCaster, m_CastItem);
|
m_spellAuraHolder = CreateSpellAuraHolder(m_spellInfo, unit, realCaster, m_CastItem, m_triggeredBySpellInfo);
|
||||||
m_spellAuraHolder->setDiminishGroup(m_diminishGroup);
|
m_spellAuraHolder->setDiminishGroup(m_diminishGroup);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,7 @@ Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* curr
|
||||||
return new Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
|
return new Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem /*= nullptr*/, SpellEntry const* triggeredBy /*= nullptr*/)
|
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem /*= NULL*/, SpellEntry const* triggeredBy /*= NULL*/)
|
||||||
{
|
{
|
||||||
return new SpellAuraHolder(spellproto, target, caster, castItem, triggeredBy);
|
return new SpellAuraHolder(spellproto, target, caster, castItem, triggeredBy);
|
||||||
}
|
}
|
||||||
|
|
@ -7526,32 +7526,32 @@ void Aura::PeriodicTick()
|
||||||
case SPELL_AURA_PERIODIC_HEAL:
|
case SPELL_AURA_PERIODIC_HEAL:
|
||||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||||
{
|
{
|
||||||
// don't heal target if not alive, mostly death persistent effects from items
|
|
||||||
if (!target->IsAlive())
|
|
||||||
{ return; }
|
|
||||||
|
|
||||||
Unit* pCaster = GetCaster();
|
Unit* pCaster = GetCaster();
|
||||||
if (!pCaster)
|
if (!pCaster)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't heal target if it is already at max health
|
bool canApplyHealthPart = true;
|
||||||
if (target->GetHealth() == target->GetMaxHealth())
|
|
||||||
return;
|
// don't heal target if max health or if not alive, mostly death persistent effects from items
|
||||||
|
if (!target->IsAlive() || (target->GetHealth() == target->GetMaxHealth()))
|
||||||
|
canApplyHealthPart = false;
|
||||||
|
|
||||||
// heal for caster damage (must be alive)
|
// heal for caster damage (must be alive)
|
||||||
if (target != pCaster && spellProto->SpellVisual[0] == 163 && !pCaster->IsAlive())
|
if (target != pCaster && spellProto->SpellVisual[0] == 163 && !pCaster->IsAlive())
|
||||||
{ return; }
|
canApplyHealthPart = false;
|
||||||
|
|
||||||
|
if (canApplyHealthPart)
|
||||||
|
{
|
||||||
// ignore non positive values (can be result apply spellmods to aura damage
|
// ignore non positive values (can be result apply spellmods to aura damage
|
||||||
uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
|
uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
|
||||||
|
|
||||||
uint32 pdamage;
|
uint32 pdamage;
|
||||||
|
|
||||||
if (m_modifier.m_auraname == SPELL_AURA_OBS_MOD_HEALTH)
|
if (m_modifier.m_auraname == SPELL_AURA_OBS_MOD_HEALTH)
|
||||||
{ pdamage = uint32(target->GetMaxHealth() * amount / 100); }
|
pdamage = uint32(target->GetMaxHealth() * amount / 100);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
{ pdamage = amount; }
|
pdamage = amount;
|
||||||
|
|
||||||
// Wild Growth (1/7 - 6 + 2*ramainTicks) %
|
// Wild Growth (1/7 - 6 + 2*ramainTicks) %
|
||||||
if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellIconID == 2864)
|
if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellIconID == 2864)
|
||||||
|
|
@ -7598,35 +7598,30 @@ void Aura::PeriodicTick()
|
||||||
|
|
||||||
target->getHostileRefManager().threatAssist(pCaster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
|
target->getHostileRefManager().threatAssist(pCaster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
|
||||||
|
|
||||||
// heal for caster damage
|
// apply damage part to caster if needed (ex. health funnel)
|
||||||
if (target != pCaster && spellProto->SpellVisual[0] == 163)
|
if (target != pCaster && spellProto->SpellVisual[0] == 163)
|
||||||
{
|
{
|
||||||
uint32 dmg = spellProto->GetManaPerSecond();
|
uint32 damage = spellProto->GetManaPerSecond();
|
||||||
if (pCaster->GetHealth() <= dmg && pCaster->GetTypeId() == TYPEID_PLAYER)
|
uint32 absorb = 0;
|
||||||
|
|
||||||
|
pCaster->DealDamageMods(pCaster, damage, &absorb);
|
||||||
|
if (pCaster->GetHealth() > damage)
|
||||||
{
|
{
|
||||||
|
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(spellProto), absorb, 0, false, 0, false);
|
||||||
|
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||||
|
pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cannot apply damage part so we have to cancel responsible aura
|
||||||
pCaster->RemoveAurasDueToSpell(GetId());
|
pCaster->RemoveAurasDueToSpell(GetId());
|
||||||
|
|
||||||
// finish current generic/channeling spells, don't affect autorepeat
|
// finish current generic/channeling spells, don't affect autorepeat
|
||||||
pCaster->FinishSpell(CURRENT_GENERIC_SPELL);
|
pCaster->FinishSpell(CURRENT_GENERIC_SPELL);
|
||||||
pCaster->FinishSpell(CURRENT_CHANNELED_SPELL);
|
pCaster->FinishSpell(CURRENT_CHANNELED_SPELL);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 damage = gain;
|
|
||||||
uint32 absorb = 0;
|
|
||||||
pCaster->DealDamageMods(pCaster, damage, &absorb);
|
|
||||||
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(spellProto), absorb, 0, false, 0, false);
|
|
||||||
|
|
||||||
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL);
|
|
||||||
pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HEAL;
|
|
||||||
// uint32 procVictim = 0;// ROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_TAKEN_HEAL;
|
|
||||||
// ignore item heals
|
|
||||||
// if(procSpell && !haveCastItem)
|
|
||||||
// pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPELL_AURA_PERIODIC_MANA_LEECH:
|
case SPELL_AURA_PERIODIC_MANA_LEECH:
|
||||||
|
|
@ -10322,11 +10317,15 @@ SpellAuraHolder::~SpellAuraHolder()
|
||||||
|
|
||||||
void SpellAuraHolder::Update(uint32 diff)
|
void SpellAuraHolder::Update(uint32 diff)
|
||||||
{
|
{
|
||||||
|
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
|
||||||
|
if (Aura* aura = m_auras[i])
|
||||||
|
aura->UpdateAura(diff);
|
||||||
|
|
||||||
if (m_duration > 0)
|
if (m_duration > 0)
|
||||||
{
|
{
|
||||||
m_duration -= diff;
|
m_duration -= diff;
|
||||||
if (m_duration < 0)
|
if (m_duration < 0)
|
||||||
{ m_duration = 0; }
|
m_duration = 0;
|
||||||
|
|
||||||
m_timeCla -= diff;
|
m_timeCla -= diff;
|
||||||
|
|
||||||
|
|
@ -10348,12 +10347,6 @@ void SpellAuraHolder::Update(uint32 diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
|
|
||||||
if (Aura* aura = m_auras[i])
|
|
||||||
{ aura->UpdateAura(diff); }
|
|
||||||
|
|
||||||
// Channeled aura required check distance from caster
|
// Channeled aura required check distance from caster
|
||||||
if (IsChanneledSpell(m_spellProto) && GetCasterGuid() != m_target->GetObjectGuid())
|
if (IsChanneledSpell(m_spellProto) && GetCasterGuid() != m_target->GetObjectGuid())
|
||||||
|
|
@ -10372,7 +10365,7 @@ void SpellAuraHolder::Update(uint32 diff)
|
||||||
float max_range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
|
float max_range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
|
||||||
|
|
||||||
if (Player* modOwner = caster->GetSpellModOwner())
|
if (Player* modOwner = caster->GetSpellModOwner())
|
||||||
{ modOwner->ApplySpellMod(GetId(), SPELLMOD_RANGE, max_range, NULL); }
|
modOwner->ApplySpellMod(GetId(), SPELLMOD_RANGE, max_range);
|
||||||
|
|
||||||
if (!caster->IsWithinDistInMap(m_target, max_range))
|
if (!caster->IsWithinDistInMap(m_target, max_range))
|
||||||
{
|
{
|
||||||
|
|
@ -10382,6 +10375,8 @@ void SpellAuraHolder::Update(uint32 diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SpellAuraHolder::RefreshHolder()
|
void SpellAuraHolder::RefreshHolder()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,13 @@ class Aura;
|
||||||
// internal helper
|
// internal helper
|
||||||
struct ReapplyAffectedPassiveAurasHelper;
|
struct ReapplyAffectedPassiveAurasHelper;
|
||||||
|
|
||||||
|
enum SpellAuraHolderState
|
||||||
|
{
|
||||||
|
SPELLAURAHOLDER_STATE_CREATED = 0, // just created, initialization steps
|
||||||
|
SPELLAURAHOLDER_STATE_READY = 1, // all initialization steps are done
|
||||||
|
SPELLAURAHOLDER_STATE_REMOVING = 2 // removing steps
|
||||||
|
};
|
||||||
|
|
||||||
class SpellAuraHolder
|
class SpellAuraHolder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -108,6 +115,8 @@ class SpellAuraHolder
|
||||||
|
|
||||||
uint32 GetId() const { return m_spellProto->Id; }
|
uint32 GetId() const { return m_spellProto->Id; }
|
||||||
SpellEntry const* GetSpellProto() const { return m_spellProto; }
|
SpellEntry const* GetSpellProto() const { return m_spellProto; }
|
||||||
|
SpellAuraHolderState GetState() const { return m_spellAuraHolderState; }
|
||||||
|
void SetState(SpellAuraHolderState state) { m_spellAuraHolderState = state; }
|
||||||
|
|
||||||
ObjectGuid const& GetCasterGuid() const { return m_casterGuid; }
|
ObjectGuid const& GetCasterGuid() const { return m_casterGuid; }
|
||||||
void SetCasterGuid(ObjectGuid guid) { m_casterGuid = guid; }
|
void SetCasterGuid(ObjectGuid guid) { m_casterGuid = guid; }
|
||||||
|
|
@ -208,6 +217,8 @@ class SpellAuraHolder
|
||||||
ObjectGuid m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
|
ObjectGuid m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
|
||||||
time_t m_applyTime;
|
time_t m_applyTime;
|
||||||
SpellEntry const* m_triggeredBy; // Spell responsible for this holder
|
SpellEntry const* m_triggeredBy; // Spell responsible for this holder
|
||||||
|
SpellAuraHolderState m_spellAuraHolderState; // State used to be sure init part is finished (ex there is still some aura to add or effect to process)
|
||||||
|
|
||||||
|
|
||||||
uint8 m_auraSlot; // Aura slot on unit (for show in client)
|
uint8 m_auraSlot; // Aura slot on unit (for show in client)
|
||||||
uint8 m_auraFlags; // Aura info flag (for send data to client)
|
uint8 m_auraFlags; // Aura info flag (for send data to client)
|
||||||
|
|
|
||||||
|
|
@ -6085,7 +6085,7 @@ void Spell::EffectDispel(SpellEffectEntry const* effect)
|
||||||
if (!holder->IsPositive())
|
if (!holder->IsPositive())
|
||||||
positive = false;
|
positive = false;
|
||||||
else
|
else
|
||||||
positive = !holder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX_NEGATIVE);
|
positive = !holder->GetSpellProto()->HasAttribute(SPELL_ATTR_NEGATIVE);
|
||||||
|
|
||||||
// do not remove positive auras if friendly target
|
// do not remove positive auras if friendly target
|
||||||
// negative auras if non-friendly target
|
// negative auras if non-friendly target
|
||||||
|
|
@ -6583,41 +6583,44 @@ void Spell::EffectTameCreature(SpellEffectEntry const* /*effect*/)
|
||||||
if (plr->IsFFAPvP())
|
if (plr->IsFFAPvP())
|
||||||
pet->SetFFAPvP(true);
|
pet->SetFFAPvP(true);
|
||||||
|
|
||||||
// level of hunter pet can't be less owner level at 5 levels
|
|
||||||
uint32 level = creatureTarget->getLevel() + 5 < plr->getLevel() ? (plr->getLevel() - 5) : creatureTarget->getLevel();
|
|
||||||
|
|
||||||
if (!pet->InitStatsForLevel(level))
|
|
||||||
{
|
|
||||||
sLog.outError("Pet::InitStatsForLevel() failed for creature (Entry: %u)!", creatureTarget->GetEntry());
|
|
||||||
delete pet;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pet->GetCharmInfo()->SetPetNumber(sObjectMgr.GeneratePetNumber(), true);
|
pet->GetCharmInfo()->SetPetNumber(sObjectMgr.GeneratePetNumber(), true);
|
||||||
// this enables pet details window (Shift+P)
|
|
||||||
pet->AIM_Initialize();
|
pet->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
|
||||||
pet->InitPetCreateSpells();
|
|
||||||
|
// level of hunter pet can't be less owner level at 5 levels
|
||||||
|
uint32 cLevel = creatureTarget->getLevel();
|
||||||
|
uint32 plLevel = plr->getLevel();
|
||||||
|
uint32 level = (cLevel + 5) < plLevel ? (plLevel - 5) : cLevel;
|
||||||
|
pet->InitStatsForLevel(level);
|
||||||
pet->InitLevelupSpellsForLevel();
|
pet->InitLevelupSpellsForLevel();
|
||||||
pet->InitTalentForLevel();
|
pet->InitTalentForLevel();
|
||||||
pet->SetHealth(pet->GetMaxHealth());
|
|
||||||
|
|
||||||
// "kill" original creature
|
pet->SetHealthPercent(creatureTarget->GetHealthPercent());
|
||||||
|
|
||||||
|
pet->GetCharmInfo()->SetPetNumber(sObjectMgr.GeneratePetNumber(), true);
|
||||||
|
|
||||||
|
// destroy creature object
|
||||||
creatureTarget->ForcedDespawn();
|
creatureTarget->ForcedDespawn();
|
||||||
|
|
||||||
// prepare visual effect for levelup
|
// prepare visual effect for levelup
|
||||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
|
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
|
||||||
|
|
||||||
// add to world
|
// add pet object to the world
|
||||||
pet->GetMap()->Add((Creature*)pet);
|
pet->GetMap()->Add((Creature*)pet);
|
||||||
|
pet->AIM_Initialize();
|
||||||
|
|
||||||
// visual effect for levelup
|
// visual effect for levelup
|
||||||
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
|
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
|
||||||
|
|
||||||
|
// this enables pet details window (Shift+P)
|
||||||
|
pet->InitPetCreateSpells();
|
||||||
|
|
||||||
// caster have pet now
|
// caster have pet now
|
||||||
plr->SetPet(pet);
|
plr->SetPet(pet);
|
||||||
|
|
||||||
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
|
||||||
plr->PetSpellInitialize();
|
plr->PetSpellInitialize();
|
||||||
|
|
||||||
|
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::EffectSummonPet(SpellEffectEntry const* effect)
|
void Spell::EffectSummonPet(SpellEffectEntry const* effect)
|
||||||
|
|
@ -11090,8 +11093,13 @@ void Spell::EffectSummonDeadPet(SpellEffectEntry const* /*effect*/)
|
||||||
return;
|
return;
|
||||||
if (pet->IsAlive())
|
if (pet->IsAlive())
|
||||||
return;
|
return;
|
||||||
if (damage < 0)
|
|
||||||
return;
|
if (_player->GetDistance(pet) >= 2.0f)
|
||||||
|
{
|
||||||
|
float px, py, pz;
|
||||||
|
m_caster->GetClosePoint(px, py, pz, pet->GetObjectBoundingRadius());
|
||||||
|
((Unit*)pet)->NearTeleportTo(px, py, pz, -m_caster->GetOrientation());
|
||||||
|
}
|
||||||
|
|
||||||
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
|
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
|
||||||
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||||
|
|
@ -11872,7 +11880,7 @@ void Spell::EffectGravityPull(SpellEffectEntry const* effect)
|
||||||
|
|
||||||
void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
|
void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
|
||||||
{
|
{
|
||||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->getClass() != CLASS_HUNTER)
|
if (!unitTarget || unitTarget->getClass() != CLASS_HUNTER)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 creatureEntry = effect->EffectMiscValue;
|
uint32 creatureEntry = effect->EffectMiscValue;
|
||||||
|
|
@ -11884,7 +11892,7 @@ void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pet* newTamedPet = new Pet;
|
Pet* newTamedPet = new Pet(HUNTER_PET);
|
||||||
CreatureCreatePos pos(unitTarget, unitTarget->GetOrientation());
|
CreatureCreatePos pos(unitTarget, unitTarget->GetOrientation());
|
||||||
|
|
||||||
Map* map = unitTarget->GetMap();
|
Map* map = unitTarget->GetMap();
|
||||||
|
|
@ -11896,15 +11904,12 @@ void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
|
||||||
}
|
}
|
||||||
|
|
||||||
newTamedPet->SetRespawnCoord(pos);
|
newTamedPet->SetRespawnCoord(pos);
|
||||||
newTamedPet->setPetType(HUNTER_PET);
|
|
||||||
|
|
||||||
newTamedPet->SetOwnerGuid(unitTarget->GetObjectGuid());
|
newTamedPet->SetOwnerGuid(unitTarget->GetObjectGuid());
|
||||||
newTamedPet->SetCreatorGuid(unitTarget->GetObjectGuid());
|
newTamedPet->SetCreatorGuid(unitTarget->GetObjectGuid());
|
||||||
newTamedPet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
newTamedPet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||||
newTamedPet->setFaction(unitTarget->getFaction());
|
newTamedPet->setFaction(unitTarget->getFaction());
|
||||||
newTamedPet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL)));
|
newTamedPet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr)));
|
||||||
newTamedPet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
|
||||||
newTamedPet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
|
||||||
newTamedPet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
newTamedPet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||||
|
|
||||||
newTamedPet->GetCharmInfo()->SetPetNumber(petNumber, true);
|
newTamedPet->GetCharmInfo()->SetPetNumber(petNumber, true);
|
||||||
|
|
@ -11915,17 +11920,15 @@ void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
|
||||||
if (unitTarget->IsFFAPvP())
|
if (unitTarget->IsFFAPvP())
|
||||||
newTamedPet->SetFFAPvP(true);
|
newTamedPet->SetFFAPvP(true);
|
||||||
|
|
||||||
newTamedPet->InitStatsForLevel(unitTarget->getLevel(), unitTarget);
|
newTamedPet->InitStatsForLevel(unitTarget->getLevel());
|
||||||
newTamedPet->InitPetCreateSpells();
|
newTamedPet->InitPetCreateSpells();
|
||||||
newTamedPet->InitLevelupSpellsForLevel();
|
newTamedPet->InitLevelupSpellsForLevel();
|
||||||
newTamedPet->InitTalentForLevel();
|
newTamedPet->InitTalentForLevel();
|
||||||
|
|
||||||
newTamedPet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
newTamedPet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
|
||||||
newTamedPet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_ABANDONED);
|
newTamedPet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_ABANDONED);
|
||||||
|
|
||||||
newTamedPet->AIM_Initialize();
|
newTamedPet->AIM_Initialize();
|
||||||
newTamedPet->SetHealth(newTamedPet->GetMaxHealth());
|
|
||||||
newTamedPet->SetPower(POWER_MANA, newTamedPet->GetMaxPower(POWER_MANA));
|
|
||||||
|
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
unitTarget->GetClosePoint(x, y, z, newTamedPet->GetObjectBoundingRadius());
|
unitTarget->GetClosePoint(x, y, z, newTamedPet->GetObjectBoundingRadius());
|
||||||
|
|
|
||||||
|
|
@ -4263,7 +4263,7 @@ SpellAuraProcResult Unit::HandleRemoveByDamageChanceProc(Unit* /*pVictim*/, uint
|
||||||
|
|
||||||
SpellAuraProcResult Unit::HandleInvisibilityAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
|
SpellAuraProcResult Unit::HandleInvisibilityAuraProc(Unit* pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
|
||||||
{
|
{
|
||||||
if (triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_PASSIVE) || triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_EX_NEGATIVE))
|
if (triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_PASSIVE) || triggeredByAura->GetSpellProto()->HasAttribute(SPELL_ATTR_NEGATIVE))
|
||||||
return SPELL_AURA_PROC_FAILED;
|
return SPELL_AURA_PROC_FAILED;
|
||||||
|
|
||||||
RemoveAurasDueToSpell(triggeredByAura->GetId());
|
RemoveAurasDueToSpell(triggeredByAura->GetId());
|
||||||
|
|
|
||||||
|
|
@ -805,7 +805,7 @@ void World::LoadConfigSettings(bool reload)
|
||||||
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL, "TimerBar.Fire.GMLevel", SEC_CONSOLE);
|
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL, "TimerBar.Fire.GMLevel", SEC_CONSOLE);
|
||||||
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX, "TimerBar.Fire.Max", 1);
|
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX, "TimerBar.Fire.Max", 1);
|
||||||
|
|
||||||
setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", true);
|
setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", false);
|
||||||
|
|
||||||
// Warden
|
// Warden
|
||||||
/* badly broken on m3 :( - this causes all these defaults to be set to 0
|
/* badly broken on m3 :( - this causes all these defaults to be set to 0
|
||||||
|
|
|
||||||
|
|
@ -755,8 +755,8 @@ SD2ErrorLogFile = "scriptdev2-errors.log"
|
||||||
#
|
#
|
||||||
# PetUnsummonAtMount
|
# PetUnsummonAtMount
|
||||||
# Permanent pet will unsummoned at player mount
|
# Permanent pet will unsummoned at player mount
|
||||||
# 0 - unsummon only for flying mounts
|
# Default: 0 - unsummon only when appropriate (don't unsummon temp summons on ground mounting)
|
||||||
# Default: 1 - unsummon for any mount
|
# 1 - always unsummon controlled pets on mounting
|
||||||
#
|
#
|
||||||
# ClientCacheVersion
|
# ClientCacheVersion
|
||||||
# Client cache version for client cache data reset. Use any different from DB value and not recently used for triggering reset.
|
# Client cache version for client cache data reset. Use any different from DB value and not recently used for triggering reset.
|
||||||
|
|
@ -858,7 +858,7 @@ MassMailer.SendPerTick = 10
|
||||||
SkillChance.Prospecting = 0
|
SkillChance.Prospecting = 0
|
||||||
SkillChance.Milling = 0
|
SkillChance.Milling = 0
|
||||||
OffhandCheckAtTalentsReset = 0
|
OffhandCheckAtTalentsReset = 0
|
||||||
PetUnsummonAtMount = 1
|
PetUnsummonAtMount = 0
|
||||||
ClientCacheVersion = 0
|
ClientCacheVersion = 0
|
||||||
Event.Announce = 0
|
Event.Announce = 0
|
||||||
BeepAtStart = 1
|
BeepAtStart = 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue