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:
Charles A Edwards 2016-09-15 14:56:42 +01:00 committed by Antz
parent c4c83f5b58
commit 600205641d
20 changed files with 634 additions and 507 deletions

View file

@ -52,10 +52,6 @@ Pet::Pet(PetType type) :
if (type == MINI_PET) // always 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()
@ -158,13 +154,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
uint32 pet_number = fields[0].GetUInt32();
if (current && owner->IsPetNeedBeTemporaryUnsummoned())
{
owner->SetTemporaryUnsummonedPetNumber(pet_number);
delete result;
return false;
}
Map* map = owner->GetMap();
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);
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);
SetPowerType(POWER_FOCUS);
break;
default:
sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
SetPowerType(POWER_FOCUS);
}
else if (getPetType() != SUMMON_PET)
sLog.outError("Pet have incorrect type (%u) for pet loading.", getPetType());
if (owner->IsPvP())
SetPvP(true);
@ -282,21 +266,16 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
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);
SetPower(powerType, savedpower > GetMaxPower(powerType) ? GetMaxPower(powerType) : savedpower);
}
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
SetPower(powerType, savedpower > GetMaxPower(powerType) ? GetMaxPower(powerType) : savedpower);
if (getPetType() == HUNTER_PET && savedhealth <= 0)
SetDeathState(JUST_DIED);
AIM_Initialize();
map->Add((Creature*)this);
AIM_Initialize();
// Spells should be loaded after pet is added to map, because in CheckCast is check on it
_LoadSpells();
@ -363,7 +342,13 @@ void Pet::SavePetToDB(PetSaveMode mode)
{
// reagents must be returned before save call
if (mode == PET_SAVE_REAGENTS)
mode = PET_SAVE_NOT_IN_SLOT;
{
// 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;
}
// not save pet as current if another pet temporary unsummoned
else if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() &&
pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber())
@ -430,7 +415,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
savePet.addUInt32(uint32(mode));
savePet.addString(m_name);
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);
std::ostringstream ss;
@ -441,7 +426,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
};
savePet.addString(ss);
savePet.addUInt64(uint64(time(NULL)));
savePet.addUInt64(uint64(time(nullptr)));
savePet.addUInt32(uint32(m_resetTalentsCost));
savePet.addUInt64(uint64(m_resetTalentsTime));
savePet.addUInt32(GetUInt32Value(UNIT_CREATED_BY_SPELL));
@ -774,18 +759,13 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
if (!Create(guid, pos, creature->GetCreatureInfo(), pet_number))
return false;
CreatureInfo const* cinfo = GetCreatureInfo();
if (!cinfo)
CreatureInfo const* cInfo = GetCreatureInfo();
if (!cInfo)
{
sLog.outError("CreateBaseAtCreature() failed, creatureInfo is missing!");
return false;
}
if (cinfo->CreatureType == CREATURE_TYPE_CRITTER)
{
setPetType(MINI_PET);
return true;
}
SetDisplayId(creature->GetDisplayId());
SetNativeDisplayId(creature->GetNativeDisplayId());
SetPowerType(POWER_FOCUS);
@ -794,118 +774,141 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel()));
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()]);
else
SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex()));
if (cinfo->CreatureType == CREATURE_TYPE_BEAST)
{
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
SetByteValue(UNIT_FIELD_BYTES_0, 3, POWER_FOCUS);
SetSheath(SHEATH_STATE_MELEE);
SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);
SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED));
}
SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR);
SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE);
SetByteValue(UNIT_FIELD_BYTES_0, 3, POWER_FOCUS);
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);
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_RENAME);
SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED));
return true;
}
bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
void Pet::InitStatsForLevel(uint32 petlevel)
{
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;
}
Unit* owner = GetOwner();
CreatureInfo const* cInfo = GetCreatureInfo();
MANGOS_ASSERT(cInfo);
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);
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};
if (getPetType() != HUNTER_PET)
if (getPetType() == HUNTER_PET)
{
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;
SetMeleeDamageSchool(SpellSchools(SPELL_SCHOOL_NORMAL));
SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME);
SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME);
SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
}
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())
{
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:
{
if (owner->GetTypeId() == TYPEID_PLAYER)
if (owner)
{
switch (owner->getClass())
{
case CLASS_WARLOCK:
{
// 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 val = (fire > shadow) ? fire : shadow;
uint32 val = (fire > shadow) ? fire : shadow;
SetBonusDamage(int32(val * 0.15f));
// bonusAP += val * 0.57;
@ -924,109 +927,172 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner)
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_PETNEXTLEVELEXP, 1000);
SetCreateMana(28 + 10 * petlevel);
SetCreateHealth(28 + 30 * petlevel);
// Info found in pet_levelstats
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]));
health = pInfo->health;
mana = pInfo->mana;
armor = pInfo->armor;
// Info found in ClassLevelStats
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(petlevel, cInfo->UnitClass, cInfo->Expansion))
{
minDmg = (cCLS->BaseDamage * cInfo->DamageVariance + (cCLS->BaseMeleeAttackPower / 14) * (cInfo->MeleeBaseAttackTime/1000)) * cInfo->DamageMultiplier;
// 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);
}
// FIXME: this is wrong formula, possible each guardian pet have own damage formula
// these formula may not be correct; however, it is designed to be close to what it should be
// this makes dps 0.5 of pets level
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
// damage range is then petlevel / 2
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
break;
}
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 levelup.", getPetType());
break;
sLog.outError("Pet have incorrect type (%u) for level handling.", getPetType());
}
for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(createResistance[i]));
// 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();
SetHealth(GetMaxHealth());
SetPower(GetPowerType(), GetMaxPower(GetPowerType()));
// A pet cannot not have health
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