Core/Creatures: moved pre/post summon actions into SummonInfo API and disabled most old TemporarySummon functionalities

This commit is contained in:
Ovahlord committed 2025-08-22 20:26:10 +02:00
1 parent 0841615951
commit 98d4a57db1
13 files changed
+272 -339

No files matched your search

+11 -39
View File
@@ -336,9 +336,20 @@ void Creature::RemoveFromWorld()
{
// If the creature about to despawn, unregister it for the summoner
if (SummonInfo* summonInfo = GetSummonInfo())
{
if (Unit* summoner = summonInfo->GetUnitSummoner())
{
summoner->UnregisterSummon(summonInfo);
if (summonInfo->GetControl() == SummonPropertiesControl::Pet)
{
summoner->SetPetGUID(ObjectGuid::Empty);
//if (Player* playerSummoner = summoner->ToPlayer())
// playerSummoner->SendRemoveControlBar();
}
}
}
if (GetZoneScript())
GetZoneScript()->OnCreatureRemove(this);
@@ -2814,45 +2825,6 @@ bool Creature::IsSummon() const
return _summonInfo != nullptr;
}
void Creature::HandlePreSummonActions()
{
SummonInfo* summonInfo = ASSERT_NOTNULL(GetSummonInfo());
if (Unit* summoner = summonInfo->GetUnitSummoner())
{
SummonPropertiesSlot slot = summonInfo->GetSummonSlot();
// Controlled summons always set their creator guid, which is being used to display summoner names in their title
if (summonInfo->IsControlledBySummoner())
SetCreatorGUID(summoner->GetGUID());
// Totem slot summons always send the TotemCreated packet. Some non-Shaman classes use this
// to display summon icons that can be canceled (Consecration, DK ghouls, Wild Mushrooms)
switch (slot)
{
case SummonPropertiesSlot::Totem1:
case SummonPropertiesSlot::Totem2:
case SummonPropertiesSlot::Totem3:
case SummonPropertiesSlot::Totem4:
{
if (Player* playerSummoner = Object::ToPlayer(summoner))
{
WorldPackets::Totem::TotemCreated totemCreated;
totemCreated.Totem = GetGUID();
totemCreated.SpellID = GetUInt32Value(UNIT_CREATED_BY_SPELL);
totemCreated.Duration = summonInfo->GetRemainingDuration().value_or(0ms).count();
totemCreated.Slot = AsUnderlyingType(summonInfo->GetSummonSlot()) - 1;
playerSummoner->SendDirectMessage(totemCreated.Write());
}
break;
}
default:
break;
}
}
}
void Creature::AllLootRemovedFromCorpse()
{
if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
@@ -430,9 +430,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool IsSummon() const override;
// Handles all summon based actions which happen before the creature is being added to the world
void HandlePreSummonActions();
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0);
bool InitEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -17,12 +17,15 @@
#include "SummonInfo.h"
#include "CharmInfo.h"
#include "Creature.h"
#include "DBCStores.h"
#include "DBCEnums.h"
#include "DBCStores.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "SummonInfoArgs.h"
#include "TotemPackets.h"
SummonInfo::SummonInfo(Creature* summonedCreature, SummonInfoArgs const& args) :
_summonedCreature(ASSERT_NOTNULL(summonedCreature)), _summonerGUID(args.Summoner ? args.Summoner->GetGUID() : ObjectGuid::Empty),
@@ -64,6 +67,13 @@ void SummonInfo::InitializeSummonProperties(uint32 summonPropertiesId, Unit cons
// Controlled summons inherit their summoner's faction if not overridden by DBC data
if (!_factionId.has_value())
_factionId = summoner->GetFaction();
// The summon is going to be treated as a pet. Prepare spell list.
if (_control == SummonPropertiesControl::Pet)
{
if (CharmInfo* charmInfo = _summonedCreature->InitCharmInfo())
charmInfo->InitCharmCreateSpells();
}
}
}
}
@@ -103,6 +113,86 @@ Optional<uint8> SummonInfo::GetCreatureLevel() const
return _creatureLevel;
}
void SummonInfo::HandlePreSummonActions()
{
if (Unit* summoner = GetUnitSummoner())
{
SummonPropertiesSlot slot = GetSummonSlot();
// Controlled summons always set their creator guid, which is being used to display summoner names in their title
if (IsControlledBySummoner())
_summonedCreature->SetCreatorGUID(summoner->GetGUID());
// Pets are set to Assist by default (this does not apply for class pets which save their states)
if (_control == SummonPropertiesControl::Pet)
_summonedCreature->SetReactState(REACT_ASSIST);
// Totem slot summons always send the TotemCreated packet. Some non-Shaman classes use this
// to display summon icons that can be canceled (Consecration, DK ghouls, Wild Mushrooms)
switch (slot)
{
case SummonPropertiesSlot::Totem1:
case SummonPropertiesSlot::Totem2:
case SummonPropertiesSlot::Totem3:
case SummonPropertiesSlot::Totem4:
{
if (Player* playerSummoner = Object::ToPlayer(summoner))
{
WorldPackets::Totem::TotemCreated totemCreated;
totemCreated.Totem = _summonedCreature->GetGUID();
totemCreated.SpellID = _summonedCreature->GetUInt32Value(UNIT_CREATED_BY_SPELL);
totemCreated.Duration = _remainingDuration.value_or(0ms).count();
totemCreated.Slot = AsUnderlyingType(_summonSlot) - 1;
playerSummoner->SendDirectMessage(totemCreated.Write());
}
break;
}
default:
break;
}
}
}
void SummonInfo::HandlePostSummonActions()
{
// Register Pet and enable its control
if (_control == SummonPropertiesControl::Pet)
{
if (Unit* summoner = GetUnitSummoner())
{
_summonedCreature->SetOwnerGUID(summoner->GetGUID());
// Only set the Summon GUID when it's empty (prevent multiple applications on multi-summons like Feral Spirit)
if (summoner->GetMinionGUID() != _summonedCreature->GetGUID())
{
summoner->SetMinionGUID(_summonedCreature->GetGUID());
if (Player* playerSummoner = summoner->ToPlayer())
{
_summonedCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
playerSummoner->SendPetSpells(this);
}
}
}
}
}
void SummonInfo::HandlePreUnsummonActions()
{
Unit* summoner = GetUnitSummoner();
if (!summoner)
return;
// Clear the current pet action bar and reset the Summon GUID
if (_control == SummonPropertiesControl::Pet && summoner->GetMinionGUID() == _summonedCreature->GetGUID())
{
summoner->SetMinionGUID(ObjectGuid::Empty);
if (Player* player = summoner->ToPlayer())
player->SendRemoveControlBar();
}
}
void SummonInfo::UpdateRemainingDuration(Milliseconds deltaTime)
{
if (!_remainingDuration.has_value() || _remainingDuration <= 0ms)
@@ -112,9 +202,9 @@ void SummonInfo::UpdateRemainingDuration(Milliseconds deltaTime)
if (_remainingDuration <= 0ms)
{
if (DespawnsWhenExpired())
GetSummonedCreature()->DespawnOrUnsummon();
_summonedCreature->DespawnOrUnsummon();
else
GetSummonedCreature()->KillSelf();
_summonedCreature->KillSelf();
}
}
@@ -179,3 +269,8 @@ SummonPropertiesSlot SummonInfo::GetSummonSlot() const
{
return _summonSlot;
}
SummonPropertiesControl SummonInfo::GetControl() const
{
return _control;
}
@@ -59,6 +59,13 @@ public:
// Returns the level of the creature that will override the default level calculation. Nullopt when the creature uses its default values.
Optional<uint8> GetCreatureLevel() const;
// Handles all summon actions which must be performed before the summoned creature is being added to the world
void HandlePreSummonActions();
// Handles all summon actions which must be performed after the summoned creature has been added to the world
void HandlePostSummonActions();
// Handles all summon actions which much be performend before the summoned creature is being removed from the world
void HandlePreUnsummonActions();
// Updates the remaining duration of a summon and triggers the expiration
void UpdateRemainingDuration(Milliseconds deltaTime);
@@ -82,6 +89,8 @@ public:
bool IsControlledBySummoner() const;
// Returns the summon slot that the summon is going to be stored in
SummonPropertiesSlot GetSummonSlot() const;
// Returns the summon control type which determines how the summon can be controlled by the summoner
SummonPropertiesControl GetControl() const;
private:
Creature* _summonedCreature;
@@ -50,6 +50,7 @@ void TempSummon::Update(uint32 diff)
{
Creature::Update(diff);
/*
if (m_deathState == DEAD)
{
UnSummon();
@@ -147,10 +148,12 @@ void TempSummon::Update(uint32 diff)
TC_LOG_ERROR("entities.unit", "Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type);
break;
}
*/
}
void TempSummon::InitStats(uint32 duration)
{
/*
ASSERT(!IsPet());
m_timer = duration;
@@ -186,10 +189,12 @@ void TempSummon::InitStats(uint32 duration)
}
}
}
*/
}
void TempSummon::InitSummon()
{
/*
if (Unit* owner = GetSummoner())
{
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled())
@@ -197,6 +202,7 @@ void TempSummon::InitSummon()
if (IsAIEnabled())
AI()->IsSummonedBy(owner);
}
*/
}
void TempSummon::UpdateObjectVisibilityOnCreate()
@@ -206,8 +212,10 @@ void TempSummon::UpdateObjectVisibilityOnCreate()
void TempSummon::SetTempSummonType(TempSummonType type)
{
/*
m_type = type;
GetSummonInfo()->SetDespawnWhenExpired(true); // To maintain legacy behavior in which all summons just despawn when expired
*/
}
void TempSummon::UnSummon(uint32 msTime)
@@ -220,6 +228,7 @@ void TempSummon::UnSummon(uint32 msTime)
return;
}
/*
//ASSERT(!IsPet());
if (IsPet())
{
@@ -234,6 +243,7 @@ void TempSummon::UnSummon(uint32 msTime)
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->IsAIEnabled())
owner->ToCreature()->AI()->SummonedCreatureDespawn(this);
}
*/
AddObjectToRemoveList();
}
@@ -264,6 +274,7 @@ Minion::Minion(SummonPropertiesEntry const* properties, Unit* owner, bool isWorl
void Minion::InitStats(uint32 duration)
{
/*
TempSummon::InitStats(duration);
SetReactState(REACT_PASSIVE);
@@ -286,6 +297,7 @@ void Minion::InitStats(uint32 duration)
SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureTemplate()->npcflag);
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
}
*/
}
void Minion::RemoveFromWorld()
@@ -293,6 +305,7 @@ void Minion::RemoveFromWorld()
if (!IsInWorld())
return;
/*
Unit* owner = GetOwner();
if ((IsMinion() || IsControlableGuardian()) && !IsTotem() && !IsVehicle())
@@ -309,6 +322,7 @@ void Minion::RemoveFromWorld()
if (totemOwner->m_Controlled.find(this) != totemOwner->m_Controlled.end())
totemOwner->m_Controlled.erase(this);
}
*/
TempSummon::RemoveFromWorld();
}
@@ -338,15 +352,19 @@ Guardian::Guardian(SummonPropertiesEntry const* properties, Unit* owner, bool is
{
memset(m_statFromOwner, 0, sizeof(float)*MAX_STATS);
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
/*
if (properties && SummonTitle(properties->Title) == SummonTitle::Pet)
{
m_unitTypeMask |= UNIT_MASK_CONTROLABLE_GUARDIAN;
InitCharmInfo();
}
*/
}
void Guardian::InitStats(uint32 duration)
{
/*
Minion::InitStats(duration);
InitStatsForLevel(getLevel());
@@ -355,18 +373,21 @@ void Guardian::InitStats(uint32 duration)
m_charmInfo->InitCharmCreateSpells();
SetReactState(REACT_AGGRESSIVE);
*/
}
void Guardian::InitSummon()
{
TempSummon::InitSummon();
/*
if (GetOwner()->GetTypeId() == TYPEID_PLAYER
&& GetOwner()->GetMinionGUID() == GetGUID()
&& !GetOwner()->GetCharmedGUID())
{
GetOwner()->ToPlayer()->CharmSpellInitialize();
}
*/
}
Puppet::Puppet(SummonPropertiesEntry const* properties, Unit* owner)
@@ -379,19 +400,26 @@ Puppet::Puppet(SummonPropertiesEntry const* properties, Unit* owner)
void Puppet::InitStats(uint32 duration)
{
Minion::InitStats(duration);
/*
SetReactState(REACT_PASSIVE);
*/
}
void Puppet::InitSummon()
{
/*
Minion::InitSummon();
if (!SetCharmedBy(GetOwner(), CHARM_TYPE_POSSESS))
ABORT();
*/
}
void Puppet::Update(uint32 time)
{
Minion::Update(time);
/*
//check if caster is channelling?
if (IsInWorld())
{
@@ -401,6 +429,7 @@ void Puppet::Update(uint32 time)
/// @todo why long distance .die does not remove it
}
}
*/
}
void Puppet::RemoveFromWorld()
@@ -408,6 +437,8 @@ void Puppet::RemoveFromWorld()
if (!IsInWorld())
return;
/*
RemoveCharmedBy(nullptr);
*/
Minion::RemoveFromWorld();
}
@@ -119,15 +119,6 @@ class TC_GAME_API Guardian : public Minion
bool InitStatsForLevel(uint8 level);
void InitSummon() override;
bool UpdateStats(Stats stat) override;
bool UpdateAllStats() override;
void UpdateResistances(uint32 school) override;
void UpdateArmor() override;
void UpdateMaxHealth() override;
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void UpdateDamagePhysical(WeaponAttackType attType) override;
int32 GetBonusDamage() const { return m_bonusSpellDamage; }
float GetBonusStatFromOwner(Stats stat) const { return m_statFromOwner[stat]; }
void SetBonusDamage(int32 damage);
+5 -69
View File
@@ -2008,74 +2008,7 @@ void WorldObject::AddObjectToRemoveList()
TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonCreatureExtraArgs const& summonArgs /*= { }*/)
{
uint32 mask = UNIT_MASK_SUMMON;
if (summonArgs.SummonProperties)
{
switch (summonArgs.SummonProperties->Control)
{
case SUMMON_CATEGORY_PET:
mask = UNIT_MASK_GUARDIAN;
break;
case SUMMON_CATEGORY_PUPPET:
mask = UNIT_MASK_PUPPET;
break;
case SUMMON_CATEGORY_VEHICLE:
mask = UNIT_MASK_MINION;
break;
case SUMMON_CATEGORY_WILD:
case SUMMON_CATEGORY_ALLY:
case SUMMON_CATEGORY_UNK:
{
switch (SummonTitle(summonArgs.SummonProperties->Title))
{
case SummonTitle::Minion:
case SummonTitle::Guardian:
case SummonTitle::Runeblade:
mask = UNIT_MASK_GUARDIAN;
break;
case SummonTitle::Totem:
case SummonTitle::Lightwell:
mask = UNIT_MASK_TOTEM;
break;
case SummonTitle::Vehicle:
case SummonTitle::Mount:
mask = UNIT_MASK_SUMMON;
break;
case SummonTitle::Companion:
mask = UNIT_MASK_MINION;
break;
default:
if (summonArgs.SummonProperties->Flags & 512) // Mirror Image, Summon Gargoyle
mask = UNIT_MASK_GUARDIAN;
break;
}
break;
}
default:
return nullptr;
}
}
TempSummon* summon = nullptr;
switch (mask)
{
case UNIT_MASK_SUMMON:
summon = new TempSummon(summonArgs.SummonProperties, summonArgs.Summoner, false);
break;
case UNIT_MASK_GUARDIAN:
summon = new Guardian(summonArgs.SummonProperties, summonArgs.Summoner, false);
break;
case UNIT_MASK_PUPPET:
summon = new Puppet(summonArgs.SummonProperties, summonArgs.Summoner);
break;
case UNIT_MASK_TOTEM:
summon = new Totem(summonArgs.SummonProperties, summonArgs.Summoner);
break;
case UNIT_MASK_MINION:
summon = new Minion(summonArgs.SummonProperties, summonArgs.Summoner, false);
break;
}
TempSummon* summon = new TempSummon(summonArgs.SummonProperties, summonArgs.Summoner, false);
// Store special settings which have been extracted from spell effects/scripts
SummonInfoArgs args;
@@ -2118,8 +2051,10 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonCreatur
transport->AddPassenger(summon);
}
SummonInfo* summonInfo = ASSERT_NOTNULL(summon->GetSummonInfo());
summon->SetHomePosition(pos);
summon->HandlePreSummonActions();
summonInfo->HandlePreSummonActions();
summon->InitStats(summonArgs.SummonDuration);
summon->SetPrivateObjectOwner(summonArgs.PrivateObjectOwner);
@@ -2134,6 +2069,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonCreatur
}
summon->InitSummon();
summonInfo->HandlePostSummonActions();
// call MoveInLineOfSight for nearby creatures
Trinity::AIRelocationNotifier notifier(*summon);
+55 -8
View File
@@ -16,6 +16,11 @@
*/
#include "Player.h"
#include <G3D/g3dmath.h>
#include <boost/dynamic_bitset.hpp>
#include "AccountMgr.h"
#include "AchievementMgr.h"
#include "Archaeology.h"
@@ -36,13 +41,13 @@
#include "CharmInfo.h"
#include "Chat.h"
#include "CinematicMgr.h"
#include "CombatPackets.h"
#include "CombatLogPackets.h"
#include "CombatPackets.h"
#include "Common.h"
#include "ConditionMgr.h"
#include "CreatureAI.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "DatabaseEnv.h"
#include "DisableMgr.h"
#include "Formulas.h"
#include "GameClient.h"
@@ -57,13 +62,13 @@
#include "GroupMgr.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "InstancePackets.h"
#include "InstanceSaveMgr.h"
#include "InstanceScript.h"
#include "InstancePackets.h"
#include "ItemPackets.h"
#include "KillRewarder.h"
#include "Language.h"
#include "LFGMgr.h"
#include "Language.h"
#include "Log.h"
#include "LootItemStorage.h"
#include "LootMgr.h"
@@ -72,9 +77,9 @@
#include "MapManager.h"
#include "MiscPackets.h"
#include "MotionMaster.h"
#include "MovementStructures.h"
#include "MovementPackets.h"
#include "MovementPacketSender.h"
#include "MovementPackets.h"
#include "MovementStructures.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@@ -102,6 +107,7 @@
#include "SpellMgr.h"
#include "SpellPackets.h"
#include "StringConvert.h"
#include "SummonInfo.h"
#include "TerrainMgr.h"
#include "TicketMgr.h"
#include "TradeData.h"
@@ -119,8 +125,6 @@
#include "WorldSession.h"
#include "WorldStateMgr.h"
#include "WorldStatePackets.h"
#include <boost/dynamic_bitset.hpp>
#include <G3D/g3dmath.h>
// corpse reclaim times
static constexpr uint32 DEATH_EXPIRE_STEP = 5 * MINUTE;
@@ -20756,6 +20760,49 @@ void Player::VehicleSpellInitialize()
SendDirectMessage(&data);
}
void Player::SendPetSpells(SummonInfo* summonInfo)
{
if (!summonInfo)
return;
Creature* summon = summonInfo->GetSummonedCreature();
CharmInfo* charmInfo = summon->GetCharmInfo();
if (!charmInfo)
return;
uint8 maxCharmInfoSpells = 0;
for (uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
if (charmInfo->GetCharmSpell(i)->GetAction())
++maxCharmInfoSpells;
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * MAX_UNIT_ACTION_BAR_INDEX + 1 + 4 * maxCharmInfoSpells + 1);
data << summon->GetGUID();
data << uint16(summon->GetCreatureTemplate()->family);
data << uint32(summonInfo->GetRemainingDuration().value_or(0ms).count());
data << uint8(summon->GetReactState());
data << uint8(charmInfo->GetCommandState());
data << uint16(0);
// action bar loop
charmInfo->BuildActionBar(&data);
data << uint8(maxCharmInfoSpells);
if (maxCharmInfoSpells)
{
for (uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
{
CharmSpellInfo* cspell = charmInfo->GetCharmSpell(i);
if (cspell->GetAction())
data << uint32(cspell->packedData);
}
}
data << uint8(0); // cooldowns count
SendDirectMessage(&data);
}
void Player::CharmSpellInitialize()
{
Unit* charm = GetFirstControlled();
+1
View File
@@ -1532,6 +1532,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void CharmSpellInitialize();
void PossessSpellInitialize();
void VehicleSpellInitialize();
void SendPetSpells(SummonInfo* summonInfo);
void SendRemoveControlBar() const;
bool HasSpell(uint32 spell) const override;
bool HasActiveSpell(uint32 spell) const; // show in spellbook
@@ -1096,214 +1096,6 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
######## ########
#######################################*/
bool Guardian::UpdateStats(Stats stat)
{
if (stat >= MAX_STATS)
return false;
// value = ((base_value * base_pct) + total_value) * total_pct
float value = GetTotalStatValue(stat);
//ApplyStatBuffMod(stat, m_statFromOwner[stat], false);
float ownersBonus = 0.0f;
SetStat(stat, int32(value));
m_statFromOwner[stat] = ownersBonus;
UpdateStatBuffMod(stat);
switch (stat)
{
case STAT_STRENGTH:
UpdateAttackPowerAndDamage();
break;
case STAT_AGILITY:
UpdateArmor();
break;
case STAT_STAMINA:
UpdateMaxHealth();
break;
case STAT_INTELLECT:
UpdateMaxPower(POWER_MANA);
break;
case STAT_SPIRIT:
break;
default:
break;
}
return true;
}
bool Guardian::UpdateAllStats()
{
UpdateMaxHealth();
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
UpdateStats(Stats(i));
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
UpdateMaxPower(Powers(i));
UpdateAllResistances();
return true;
}
void Guardian::UpdateResistances(uint32 school)
{
if (school > SPELL_SCHOOL_NORMAL)
{
float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school));
SetResistance(SpellSchools(school), int32(value));
}
else
UpdateArmor();
}
void Guardian::UpdateArmor()
{
float value = 0.0f;
UnitMods unitMod = UNIT_MOD_ARMOR;
value = GetFlatModifierValue(unitMod, BASE_VALUE);
value *= GetPctModifierValue(unitMod, BASE_PCT);
//value += GetStat(STAT_AGILITY) * 2.0f; (deprecated since 4.x)
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetArmor(int32(value));
}
void Guardian::UpdateMaxHealth()
{
UnitMods unitMod = UNIT_MOD_HEALTH;
float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA);
float multiplicator = 10.0f;
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
void Guardian::UpdateMaxPower(Powers power)
{
if (GetPowerIndex(power) == MAX_POWERS)
return;
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + AsUnderlyingType(power));
float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f;
float multiplicator = 15.0f;
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowerValue(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, int32(value));
}
void Guardian::UpdateAttackPowerAndDamage(bool ranged)
{
if (ranged)
return;
float ap_per_strength = 2.0f;
float val = GetStat(STAT_STRENGTH) - 20.0f;
val *= ap_per_strength;
UnitMods unitMod = UNIT_MOD_ATTACK_POWER;
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val);
// in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
// UNIT_FIELD_(RANGED)_ATTACK_POWER field
SetInt32Value(UNIT_FIELD_ATTACK_POWER, int32(base_attPower));
// UNIT_FIELD_(RANGED)_ATTACK_POWER_MOD_POS field
SetInt32Value(UNIT_FIELD_ATTACK_POWER_MOD_POS, int32(attPowerMod > 0.f ? attPowerMod : 0.f));
// UNIT_FIELD_(RANGED)_ATTACK_POWER_MOD_NEG field
SetInt32Value(UNIT_FIELD_ATTACK_POWER_MOD_NEG, int32(attPowerMod < 0.f ? -attPowerMod : 0.f));
// UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier);
// automatically update weapon damage after attack power modification
UpdateDamagePhysical(BASE_ATTACK);
// update pet spell power
int32 spellDamage = 0;
for (auto itr : GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE))
spellDamage += itr->GetAmount();
SetBonusDamage(spellDamage);
}
void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
{
if (attType > BASE_ATTACK)
return;
float bonusDamage = 0.0f;
if (m_owner->GetTypeId() == TYPEID_PLAYER)
{
//force of nature
if (GetEntry() == ENTRY_TREANT)
{
int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + AsUnderlyingType(SPELL_SCHOOL_NATURE))) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + AsUnderlyingType(SPELL_SCHOOL_NATURE));
if (spellDmg > 0)
bonusDamage = spellDmg * 0.09f;
}
//greater fire elemental
else if (GetEntry() == ENTRY_FIRE_ELEMENTAL)
{
int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + AsUnderlyingType(SPELL_SCHOOL_FIRE))) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + AsUnderlyingType(SPELL_SCHOOL_FIRE));
if (spellDmg > 0)
bonusDamage = spellDmg * 0.4f;
}
}
UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
float att_speed = float(GetBaseAttackTime(BASE_ATTACK))/1000.0f;
float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed + bonusDamage;
float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT);
float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
/// @todo: remove this
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_MOD_ATTACKSPEED);
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
switch ((*itr)->GetSpellInfo()->Id)
{
case 61682:
case 61683:
AddPct(mindamage, -(*itr)->GetAmount());
AddPct(maxdamage, -(*itr)->GetAmount());
break;
default:
break;
}
}
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
}
void Guardian::SetBonusDamage(int32 damage)
{
//m_bonusSpellDamage = damage;
+3
View File
@@ -8863,6 +8863,9 @@ void Unit::UnregisterSummon(SummonInfo* summon)
if (!summon)
return;
// Perform cleanup actions if needed
summon->HandlePreUnsummonActions();
SummonPropertiesSlot slot = summon->GetSummonSlot();
if (slot == SummonPropertiesSlot::None)
{
@@ -16,7 +16,9 @@
*/
#include "PetPackets.h"
#include "PetDefines.h"
#include "Spell.h"
WorldPacket const* WorldPackets::Pet::PetDismissSound::Write()
{
@@ -80,3 +82,32 @@ WorldPacket const* WorldPackets::Pet::PetAdded::Write()
return &_worldPacket;
}
WorldPacket const* WorldPackets::Pet::PetSpells::Write()
{
_worldPacket << PetGUID;
if (PetGUID.IsEmpty())
return &_worldPacket;
_worldPacket << uint16(_CreatureFamily);
_worldPacket << uint32(TimeLimit);
_worldPacket << uint8(ReactState);
_worldPacket << uint8(CommandState);
_worldPacket << uint16(Flag);
_worldPacket.append(ActionButtons.data(), ActionButtons.size());
_worldPacket << uint8(Actions.size());
_worldPacket.append(Actions.data(), Actions.size());
_worldPacket << uint8(Cooldowns.size());
for (PetSpellCooldown const& cooldown : Cooldowns)
{
_worldPacket << int32(cooldown.SpellID);
_worldPacket << uint16(cooldown.Category);
_worldPacket << int32(cooldown.Duration);
_worldPacket << int32(cooldown.CategoryDuration);
}
return &_worldPacket;
}
@@ -94,6 +94,34 @@ namespace WorldPackets
uint32 PetNumber = 0;
uint8 Flags = 0;
};
struct PetSpellCooldown
{
int32 SpellID = 0;
int32 Duration = 0;
int32 CategoryDuration = 0;
uint16 Category = 0;
};
class PetSpells final : public ServerPacket
{
public:
PetSpells() : ServerPacket(SMSG_PET_SPELLS, 100) { }
WorldPacket const* Write() override;
ObjectGuid PetGUID;
uint16 _CreatureFamily = 0; ///< @see enum CreatureFamily
uint32 TimeLimit = 0;
uint8 ReactState = 0;
uint8 CommandState = 0;
uint16 Flag = 0;
std::array<int, 10> ActionButtons = { };
std::vector<uint32> Actions;
std::vector<PetSpellCooldown> Cooldowns;
};
}
}