mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
[12041] Refactor Npc Summoning code
* Do positions handling in one place for all npc summon spell types * Handle a bunch of shared post-summoning processing also in a shared place * Ensure that summon positions have proper z, thx to Reamer for this part
This commit is contained in:
parent
6b50ce1f1a
commit
dc60abae90
3 changed files with 391 additions and 394 deletions
|
|
@ -231,8 +231,8 @@ class Spell
|
|||
friend struct MaNGOS::SpellNotifierPlayer;
|
||||
friend struct MaNGOS::SpellNotifierCreatureAndPlayer;
|
||||
friend void Unit::SetCurrentCastedSpell( Spell * pSpell );
|
||||
public:
|
||||
|
||||
public:
|
||||
void EffectEmpty(SpellEffectIndex eff_idx);
|
||||
void EffectNULL(SpellEffectIndex eff_idx);
|
||||
void EffectUnused(SpellEffectIndex eff_idx);
|
||||
|
|
@ -393,11 +393,6 @@ class Spell
|
|||
void setState(uint32 state) { m_spellState = state; }
|
||||
|
||||
void DoCreateItem(SpellEffectIndex eff_idx, uint32 itemtype);
|
||||
void DoSummonPet(SpellEffectIndex eff_idx);
|
||||
void DoSummonWild(SpellEffectIndex eff_idx, uint32 forceFaction = 0);
|
||||
void DoSummonGuardian(SpellEffectIndex eff_idx, uint32 forceFaction = 0);
|
||||
void DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc = 0);
|
||||
void DoSummonCritter(SpellEffectIndex eff_idx, uint32 forceFaction = 0);
|
||||
|
||||
void WriteSpellGoTargets(WorldPacket* data);
|
||||
void WriteAmmoToPacket(WorldPacket* data);
|
||||
|
|
@ -648,6 +643,27 @@ class Spell
|
|||
// we can't store original aura link to prevent access to deleted auras
|
||||
// and in same time need aura data and after aura deleting.
|
||||
SpellEntry const* m_triggeredByAuraSpell;
|
||||
|
||||
private:
|
||||
// NPC Summonings
|
||||
struct CreaturePosition
|
||||
{
|
||||
CreaturePosition() :
|
||||
x(0.0f), y(0.0f), z(0.0f),
|
||||
creature(NULL)
|
||||
{}
|
||||
|
||||
float x, y, z;
|
||||
Creature* creature;
|
||||
};
|
||||
typedef std::vector<CreaturePosition> CreatureSummonPositions;
|
||||
|
||||
// return true IFF further processing required
|
||||
bool DoSummonPet(SpellEffectIndex eff_idx);
|
||||
bool DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc = 0);
|
||||
bool DoSummonWild(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 level);
|
||||
bool DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 level);
|
||||
bool DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 level);
|
||||
};
|
||||
|
||||
enum ReplenishType
|
||||
|
|
|
|||
|
|
@ -4754,6 +4754,65 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
return;
|
||||
}
|
||||
|
||||
// Pet's are atm handled differently
|
||||
if (summon_prop->Group == SUMMON_PROP_GROUP_PETS && prop_id != 1562)
|
||||
{
|
||||
DoSummonPet(eff_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Expected Amount: TODO - there are quite some exceptions (like totems, engineering dragonlings..)
|
||||
uint32 amount = damage > 0 ? damage : 1;
|
||||
|
||||
// Expected Level (Totem, Pet and Critter may not use this)
|
||||
uint32 level = m_caster->getLevel();
|
||||
// level of creature summoned using engineering item based at engineering skill level
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem)
|
||||
{
|
||||
ItemPrototype const* proto = m_CastItem->GetProto();
|
||||
if (proto && proto->RequiredSkill == SKILL_ENGINEERING)
|
||||
if (uint16 engineeringSkill = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINEERING))
|
||||
level = engineeringSkill / 5;
|
||||
}
|
||||
|
||||
CreatureSummonPositions summonPositions;
|
||||
summonPositions.resize(amount, CreaturePosition());
|
||||
|
||||
// Set middle position
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
{
|
||||
summonPositions[0].x = m_targets.m_destX;
|
||||
summonPositions[0].y = m_targets.m_destY;
|
||||
summonPositions[0].z = m_targets.m_destZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caster->GetPosition(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z);
|
||||
|
||||
// TODO - Is this really an error?
|
||||
sLog.outDebug("Spell Effect EFFECT_SUMMON (%u) - summon without destination (spell id %u, effIndex %u)", m_spellInfo->Effect[eff_idx], m_spellInfo->Id, eff_idx);
|
||||
}
|
||||
|
||||
// Set summon positions
|
||||
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
|
||||
CreatureSummonPositions::iterator itr = summonPositions.begin();
|
||||
for (++itr; itr != summonPositions.end(); ++itr) // In case of multiple summons around position for not-fist positions
|
||||
{
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION || radius > 1.0f)
|
||||
{
|
||||
m_caster->GetRandomPoint(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, radius, itr->x, itr->y, itr->z);
|
||||
if (m_caster->GetMap()->GetObjectHitPos(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, itr->x, itr->y, itr->z, itr->x, itr->y, itr->z, 0.5f))
|
||||
m_caster->UpdateAllowedPositionZ(itr->x, itr->y, itr->z);
|
||||
}
|
||||
else // Get a point near the caster
|
||||
{
|
||||
m_caster->GetClosePoint(itr->x, itr->y, itr->z, 0.0f, radius, frand(0.0f, 2*M_PI_F));
|
||||
if (m_caster->GetMap()->GetObjectHitPos(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, itr->x, itr->y, itr->z, itr->x, itr->y, itr->z, 0.5f))
|
||||
m_caster->UpdateAllowedPositionZ(itr->x, itr->y, itr->z);
|
||||
}
|
||||
}
|
||||
|
||||
bool summonResult = false;
|
||||
switch(summon_prop->Group)
|
||||
{
|
||||
// faction handled later on, or loaded from template
|
||||
|
|
@ -4768,15 +4827,15 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
//121: 23035, battlestands
|
||||
//647: 52893, Anti-Magic Zone (npc used)
|
||||
if (prop_id == 121 || prop_id == 647)
|
||||
DoSummonTotem(eff_idx);
|
||||
summonResult = DoSummonTotem(eff_idx);
|
||||
else
|
||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
}
|
||||
case UNITNAME_SUMMON_TITLE_PET:
|
||||
case UNITNAME_SUMMON_TITLE_MINION:
|
||||
case UNITNAME_SUMMON_TITLE_RUNEBLADE:
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
case UNITNAME_SUMMON_TITLE_GUARDIAN:
|
||||
{
|
||||
|
|
@ -4784,7 +4843,7 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
{
|
||||
// * Stone Statue, etc -- fits much better totem AI
|
||||
if (m_spellInfo->SpellIconID == 2056)
|
||||
DoSummonTotem(eff_idx);
|
||||
summonResult = DoSummonTotem(eff_idx);
|
||||
else
|
||||
{
|
||||
// possible sort totems/guardians only by summon creature type
|
||||
|
|
@ -4795,37 +4854,37 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
|
||||
// FIXME: not all totems and similar cases seelcted by this check...
|
||||
if (cInfo->type == CREATURE_TYPE_TOTEM)
|
||||
DoSummonTotem(eff_idx);
|
||||
summonResult = DoSummonTotem(eff_idx);
|
||||
else
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
}
|
||||
}
|
||||
else
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
}
|
||||
case UNITNAME_SUMMON_TITLE_CONSTRUCT:
|
||||
{
|
||||
if (prop_id == 2913) // Scrapbot
|
||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||
else
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
}
|
||||
case UNITNAME_SUMMON_TITLE_TOTEM:
|
||||
DoSummonTotem(eff_idx, summon_prop->Slot);
|
||||
summonResult = DoSummonTotem(eff_idx, summon_prop->Slot);
|
||||
break;
|
||||
case UNITNAME_SUMMON_TITLE_COMPANION:
|
||||
// slot 6 set for critters that can help to player in fighting
|
||||
if (summon_prop->Slot == 6)
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
else
|
||||
DoSummonCritter(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonCritter(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
case UNITNAME_SUMMON_TITLE_OPPONENT:
|
||||
case UNITNAME_SUMMON_TITLE_LIGHTWELL:
|
||||
case UNITNAME_SUMMON_TITLE_BUTLER:
|
||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
case UNITNAME_SUMMON_TITLE_VEHICLE:
|
||||
case UNITNAME_SUMMON_TITLE_MOUNT:
|
||||
|
|
@ -4844,16 +4903,14 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
// 1562 - force of nature - sid 33831
|
||||
// 1161 - feral spirit - sid 51533
|
||||
if (prop_id == 1562) // 3 uncontrolable instead of one controllable :/
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
else
|
||||
DoSummonPet(eff_idx);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
}
|
||||
case SUMMON_PROP_GROUP_CONTROLLABLE:
|
||||
{
|
||||
// no type here
|
||||
// maybe wrong - but thats the handler currently used for those
|
||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
||||
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||
break;
|
||||
}
|
||||
case SUMMON_PROP_GROUP_VEHICLE:
|
||||
|
|
@ -4867,28 +4924,304 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
|||
sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!summonResult)
|
||||
return; // No further handling required
|
||||
|
||||
for (CreatureSummonPositions::iterator itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
|
||||
{
|
||||
MANGOS_ASSERT(itr->creature || itr != summonPositions.begin());
|
||||
if (!itr->creature)
|
||||
{
|
||||
sLog.outError("EffectSummonType: Expected to have %u NPCs summoned, but some failed (Spell id %u)", amount, m_spellInfo->Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
||||
if (summon_prop->FactionId)
|
||||
itr->creature->setFaction(summon_prop->FactionId);
|
||||
|
||||
if (!itr->creature->IsTemporarySummon())
|
||||
{
|
||||
itr->creature->AIM_Initialize();
|
||||
|
||||
m_caster->GetMap()->Add(itr->creature);
|
||||
|
||||
// Notify Summoner
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
|
||||
((Creature*)m_caster)->AI()->JustSummoned(itr->creature);
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(itr->creature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Spell::DoSummonWild(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 level)
|
||||
{
|
||||
MANGOS_ASSERT(!list.empty() && prop);
|
||||
|
||||
uint32 creature_entry = m_spellInfo->EffectMiscValue[effIdx];
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(creature_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonWild: creature entry %u not found for spell %u.", creature_entry, m_spellInfo->Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
TempSummonType summonType = (m_duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
|
||||
|
||||
for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
|
||||
if (Creature* summon = m_caster->SummonCreature(creature_entry, itr->x, itr->y, itr->z, m_caster->GetOrientation(), summonType, m_duration))
|
||||
{
|
||||
itr->creature = summon;
|
||||
|
||||
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
// UNIT_FIELD_CREATEDBY are not set for these kind of spells.
|
||||
// Does exceptions exist? If so, what are they?
|
||||
// summon->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
|
||||
// Notify original caster if not done already
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(summon);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 /*level*/)
|
||||
{
|
||||
MANGOS_ASSERT(!list.empty() && prop);
|
||||
|
||||
// ATM only first position is supported for summoning
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[effIdx];
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonCritter: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
Pet* old_critter = m_caster->GetMiniPet();
|
||||
|
||||
// for same pet just despawn (player unsummon command)
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && old_critter && old_critter->GetEntry() == pet_entry)
|
||||
{
|
||||
m_caster->RemoveMiniPet();
|
||||
return false;
|
||||
}
|
||||
|
||||
// despawn old pet before summon new
|
||||
if (old_critter)
|
||||
m_caster->RemoveMiniPet();
|
||||
|
||||
// for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
|
||||
CreatureCreatePos pos(m_caster->GetMap(), list[0].x, list[0].y, list[0].z, m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
|
||||
// summon new pet
|
||||
Pet* critter = new Pet(MINI_PET);
|
||||
|
||||
uint32 pet_number = sObjectMgr.GeneratePetNumber();
|
||||
if (!critter->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
|
||||
{
|
||||
sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
|
||||
delete critter;
|
||||
return false;
|
||||
}
|
||||
|
||||
// itr!
|
||||
list[0].creature = critter;
|
||||
|
||||
critter->SetSummonPoint(pos);
|
||||
|
||||
//critter->SetName(""); // generated by client
|
||||
critter->SetOwnerGuid(m_caster->GetObjectGuid());
|
||||
critter->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
|
||||
critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
|
||||
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
|
||||
//critter->InitLevelupSpellsForLevel(); // none?
|
||||
critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
|
||||
critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag);
|
||||
// some mini-pets have quests
|
||||
// set timer for unsummon
|
||||
if (m_duration > 0)
|
||||
critter->SetDuration(m_duration);
|
||||
|
||||
m_caster->SetMiniPet(critter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectIndex effIdx, uint32 level)
|
||||
{
|
||||
MANGOS_ASSERT(!list.empty() && prop);
|
||||
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[effIdx];
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonGuardian: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
PetType petType = prop->Title == UNITNAME_SUMMON_TITLE_COMPANION ? PROTECTOR_PET : GUARDIAN_PET;
|
||||
|
||||
// second direct cast unsummon guardian(s) (guardians without like functionality have cooldown > spawn time)
|
||||
if (!m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
bool found = false;
|
||||
// including protector
|
||||
while (Pet* old_summon = m_caster->FindGuardianWithEntry(pet_entry))
|
||||
{
|
||||
old_summon->Unsummon(PET_SAVE_AS_DELETED, m_caster);
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found)
|
||||
return false;
|
||||
}
|
||||
|
||||
// protectors allowed only in single amount
|
||||
if (petType == PROTECTOR_PET)
|
||||
if (Pet* old_protector = m_caster->GetProtectorPet())
|
||||
old_protector->Unsummon(PET_SAVE_AS_DELETED, m_caster);
|
||||
|
||||
// in another case summon new
|
||||
for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
|
||||
{
|
||||
Pet* spawnCreature = new Pet(petType);
|
||||
|
||||
CreatureCreatePos pos(m_caster->GetMap(), itr->x, itr->y, itr->z, -m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
|
||||
uint32 pet_number = sObjectMgr.GeneratePetNumber();
|
||||
if (!spawnCreature->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
|
||||
{
|
||||
sLog.outError("Spell::DoSummonGuardian: can't create creature entry %u for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
delete spawnCreature;
|
||||
return false;
|
||||
}
|
||||
|
||||
itr->creature = spawnCreature;
|
||||
|
||||
spawnCreature->SetSummonPoint(pos);
|
||||
|
||||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
|
||||
//spawnCreature->SetName(""); // generated by client
|
||||
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->setPowerType(POWER_MANA);
|
||||
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag);
|
||||
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
|
||||
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
spawnCreature->InitStatsForLevel(level, m_caster);
|
||||
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
m_caster->AddGuardian(spawnCreature);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc)
|
||||
{
|
||||
// DBC store slots starting from 1, with no slot 0 value)
|
||||
int slot = slot_dbc ? slot_dbc - 1 : TOTEM_SLOT_NONE;
|
||||
|
||||
// unsummon old totem
|
||||
if (slot < MAX_TOTEM_SLOT)
|
||||
if (Totem *OldTotem = m_caster->GetTotem(TotemSlot(slot)))
|
||||
OldTotem->UnSummon();
|
||||
|
||||
// FIXME: Setup near to finish point because GetObjectBoundingRadius set in Create but some Create calls can be dependent from proper position
|
||||
// if totem have creature_template_addon.auras with persistent point for example or script call
|
||||
float angle = slot < MAX_TOTEM_SLOT ? M_PI_F/MAX_TOTEM_SLOT - (slot*2*M_PI_F/MAX_TOTEM_SLOT) : 0;
|
||||
|
||||
CreatureCreatePos pos(m_caster, m_caster->GetOrientation(), 2.0f, angle);
|
||||
|
||||
CreatureInfo const* cinfo = sCreatureStorage.LookupEntry<CreatureInfo>(m_spellInfo->EffectMiscValue[eff_idx]);
|
||||
if (!cinfo)
|
||||
{
|
||||
sLog.outErrorDb("Creature entry %u does not exist but used in spell %u totem summon.", m_spellInfo->Id, m_spellInfo->EffectMiscValue[eff_idx]);
|
||||
return false;
|
||||
}
|
||||
|
||||
Totem* pTotem = new Totem;
|
||||
|
||||
if (!pTotem->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_UNIT), pos, cinfo, m_caster))
|
||||
{
|
||||
delete pTotem;
|
||||
return false;
|
||||
}
|
||||
|
||||
pTotem->SetSummonPoint(pos);
|
||||
|
||||
if (slot < MAX_TOTEM_SLOT)
|
||||
m_caster->_AddTotem(TotemSlot(slot),pTotem);
|
||||
|
||||
//pTotem->SetName(""); // generated by client
|
||||
pTotem->SetOwner(m_caster);
|
||||
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initialized
|
||||
|
||||
pTotem->SetDuration(m_duration);
|
||||
|
||||
if (damage) // if not spell info, DB values used
|
||||
{
|
||||
pTotem->SetMaxHealth(damage);
|
||||
pTotem->SetHealth(damage);
|
||||
}
|
||||
|
||||
pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
pTotem->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
|
||||
if (m_caster->IsPvP())
|
||||
pTotem->SetPvP(true);
|
||||
|
||||
if (m_caster->IsFFAPvP())
|
||||
pTotem->SetFFAPvP(true);
|
||||
|
||||
// sending SMSG_TOTEM_CREATED before add to map (done in Summon)
|
||||
if (slot < MAX_TOTEM_SLOT && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_TOTEM_CREATED, 1 + 8 + 4 + 4);
|
||||
data << uint8(slot);
|
||||
data << pTotem->GetObjectGuid();
|
||||
data << uint32(m_duration);
|
||||
data << uint32(m_spellInfo->Id);
|
||||
((Player*)m_caster)->SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
pTotem->Summon(m_caster);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
||||
{
|
||||
if (m_caster->GetPetGuid())
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (!unitTarget)
|
||||
return;
|
||||
return false;
|
||||
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
||||
if (!pet_entry)
|
||||
return;
|
||||
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonPet: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 level = m_caster->getLevel();
|
||||
uint32 level = m_caster->getLevel(); // TODO Engineering Pets have also caster-level? (if they exist)
|
||||
Pet* spawnCreature = new Pet(SUMMON_PET);
|
||||
|
||||
if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
|
||||
|
|
@ -4901,7 +5234,7 @@ void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
|||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Summon in dest location
|
||||
|
|
@ -4916,7 +5249,7 @@ void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
|||
{
|
||||
sLog.outErrorDb("Spell::EffectSummon: can't create creature with entry %u for spell %u", cInfo->Entry, m_spellInfo->Id);
|
||||
delete spawnCreature;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
spawnCreature->SetSummonPoint(pos);
|
||||
|
|
@ -4962,6 +5295,8 @@ void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
|||
((Creature*)m_caster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Spell::EffectLearnSpell(SpellEffectIndex eff_idx)
|
||||
|
|
@ -5198,215 +5533,6 @@ void Spell::EffectAddFarsight(SpellEffectIndex eff_idx)
|
|||
((Player*)m_caster)->GetCamera().SetView(dynObj);
|
||||
}
|
||||
|
||||
void Spell::DoSummonWild(SpellEffectIndex eff_idx, uint32 forceFaction)
|
||||
{
|
||||
uint32 creature_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
||||
if (!creature_entry)
|
||||
return;
|
||||
|
||||
uint32 level = m_caster->getLevel();
|
||||
|
||||
// level of creature summoned using engineering item based at engineering skill level
|
||||
if (m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
|
||||
{
|
||||
ItemPrototype const *proto = m_CastItem->GetProto();
|
||||
if (proto && proto->RequiredSkill == SKILL_ENGINEERING)
|
||||
{
|
||||
uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINEERING);
|
||||
if (skill202)
|
||||
level = skill202/5;
|
||||
}
|
||||
}
|
||||
|
||||
// select center of summon position
|
||||
float center_x = m_targets.m_destX;
|
||||
float center_y = m_targets.m_destY;
|
||||
float center_z = m_targets.m_destZ;
|
||||
|
||||
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
|
||||
TempSummonType summonType = (m_duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
|
||||
|
||||
int32 amount = damage > 0 ? damage : 1;
|
||||
|
||||
for(int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
float px, py, pz;
|
||||
// If dest location if present
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
{
|
||||
// Summon 1 unit in dest location
|
||||
if (count == 0)
|
||||
{
|
||||
px = m_targets.m_destX;
|
||||
py = m_targets.m_destY;
|
||||
pz = m_targets.m_destZ;
|
||||
}
|
||||
// Summon in random point all other units if location present
|
||||
else
|
||||
m_caster->GetRandomPoint(center_x, center_y, center_z, radius, px, py, pz);
|
||||
}
|
||||
// Summon if dest location not present near caster
|
||||
else
|
||||
{
|
||||
if (radius > 0.0f)
|
||||
{
|
||||
// not using bounding radius of caster here
|
||||
m_caster->GetClosePoint(px, py, pz, 0.0f, radius);
|
||||
}
|
||||
else
|
||||
{
|
||||
// EffectRadiusIndex 0 or 36
|
||||
px = m_caster->GetPositionX();
|
||||
py = m_caster->GetPositionY();
|
||||
pz = m_caster->GetPositionZ();
|
||||
}
|
||||
}
|
||||
|
||||
if (Creature* summon = m_caster->SummonCreature(creature_entry, px, py, pz, m_caster->GetOrientation(), summonType, m_duration))
|
||||
{
|
||||
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
// UNIT_FIELD_CREATEDBY are not set for these kind of spells.
|
||||
// Does exceptions exist? If so, what are they?
|
||||
// summon->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
|
||||
if(forceFaction)
|
||||
summon->setFaction(forceFaction);
|
||||
|
||||
// Notify original caster if not done already
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(summon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::DoSummonGuardian(SpellEffectIndex eff_idx, uint32 forceFaction)
|
||||
{
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
||||
if (!pet_entry)
|
||||
return;
|
||||
|
||||
SummonPropertiesEntry const* propEntry = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[eff_idx]);
|
||||
if (!propEntry)
|
||||
return;
|
||||
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonGuardian: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
return;
|
||||
}
|
||||
|
||||
PetType petType = propEntry->Title == UNITNAME_SUMMON_TITLE_COMPANION ? PROTECTOR_PET : GUARDIAN_PET;
|
||||
|
||||
// second direct cast unsummon guardian(s) (guardians without like functionality have cooldown > spawn time)
|
||||
if (!m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
bool found = false;
|
||||
// including protector
|
||||
while (Pet* old_summon = m_caster->FindGuardianWithEntry(pet_entry))
|
||||
{
|
||||
old_summon->Unsummon(PET_SAVE_AS_DELETED, m_caster);
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found)
|
||||
return;
|
||||
}
|
||||
|
||||
// protectors allowed only in single amount
|
||||
if (petType == PROTECTOR_PET)
|
||||
if (Pet* old_protector = m_caster->GetProtectorPet())
|
||||
old_protector->Unsummon(PET_SAVE_AS_DELETED, m_caster);
|
||||
|
||||
// in another case summon new
|
||||
uint32 level = m_caster->getLevel();
|
||||
|
||||
// level of pet summoned using engineering item based at engineering skill level
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem)
|
||||
{
|
||||
ItemPrototype const *proto = m_CastItem->GetProto();
|
||||
if (proto && proto->RequiredSkill == SKILL_ENGINEERING)
|
||||
{
|
||||
uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINEERING);
|
||||
if (skill202)
|
||||
{
|
||||
level = skill202 / 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// select center of summon position
|
||||
float center_x = m_targets.m_destX;
|
||||
float center_y = m_targets.m_destY;
|
||||
float center_z = m_targets.m_destZ;
|
||||
|
||||
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
|
||||
|
||||
int32 amount = damage > 0 ? damage : 1;
|
||||
|
||||
for (int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
Pet* spawnCreature = new Pet(petType);
|
||||
|
||||
// If dest location if present
|
||||
// Summon 1 unit in dest location
|
||||
CreatureCreatePos pos(m_caster->GetMap(), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
{
|
||||
// Summon in random point all other units if location present
|
||||
if (count > 0)
|
||||
{
|
||||
float x, y, z;
|
||||
m_caster->GetRandomPoint(center_x, center_y, center_z, radius, x, y, z);
|
||||
pos = CreatureCreatePos(m_caster->GetMap(), x, y, z, m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
}
|
||||
}
|
||||
// Summon if dest location not present near caster
|
||||
else
|
||||
pos = CreatureCreatePos(m_caster, m_caster->GetOrientation());
|
||||
|
||||
Map *map = m_caster->GetMap();
|
||||
uint32 pet_number = sObjectMgr.GeneratePetNumber();
|
||||
if (!spawnCreature->Create(map->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
|
||||
{
|
||||
sLog.outError("Spell::DoSummonGuardian: can't create creature entry %u for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
delete spawnCreature;
|
||||
return;
|
||||
}
|
||||
|
||||
spawnCreature->SetSummonPoint(pos);
|
||||
|
||||
if (m_duration > 0)
|
||||
spawnCreature->SetDuration(m_duration);
|
||||
|
||||
//spawnCreature->SetName(""); // generated by client
|
||||
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->setPowerType(POWER_MANA);
|
||||
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag);
|
||||
spawnCreature->setFaction(forceFaction ? forceFaction : m_caster->getFaction());
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
|
||||
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
spawnCreature->InitStatsForLevel(level, m_caster);
|
||||
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
spawnCreature->AIM_Initialize();
|
||||
|
||||
m_caster->AddGuardian(spawnCreature);
|
||||
|
||||
map->Add((Creature*)spawnCreature);
|
||||
|
||||
// Notify Summoner
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
|
||||
((Creature*)m_caster)->AI()->JustSummoned(spawnCreature);
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(spawnCreature);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectTeleUnitsFaceCaster(SpellEffectIndex eff_idx)
|
||||
{
|
||||
if (!unitTarget)
|
||||
|
|
@ -8528,79 +8654,6 @@ void Spell::EffectApplyGlyph(SpellEffectIndex eff_idx)
|
|||
}
|
||||
}
|
||||
|
||||
void Spell::DoSummonTotem(SpellEffectIndex eff_idx, uint8 slot_dbc)
|
||||
{
|
||||
// DBC store slots starting from 1, with no slot 0 value)
|
||||
int slot = slot_dbc ? slot_dbc - 1 : TOTEM_SLOT_NONE;
|
||||
|
||||
// unsummon old totem
|
||||
if (slot < MAX_TOTEM_SLOT)
|
||||
if (Totem *OldTotem = m_caster->GetTotem(TotemSlot(slot)))
|
||||
OldTotem->UnSummon();
|
||||
|
||||
// FIXME: Setup near to finish point because GetObjectBoundingRadius set in Create but some Create calls can be dependent from proper position
|
||||
// if totem have creature_template_addon.auras with persistent point for example or script call
|
||||
float angle = slot < MAX_TOTEM_SLOT ? M_PI_F/MAX_TOTEM_SLOT - (slot*2*M_PI_F/MAX_TOTEM_SLOT) : 0;
|
||||
|
||||
CreatureCreatePos pos(m_caster, m_caster->GetOrientation(), 2.0f, angle);
|
||||
|
||||
CreatureInfo const *cinfo = ObjectMgr::GetCreatureTemplate(m_spellInfo->EffectMiscValue[eff_idx]);
|
||||
if (!cinfo)
|
||||
{
|
||||
sLog.outErrorDb("Creature entry %u does not exist but used in spell %u totem summon.", m_spellInfo->Id, m_spellInfo->EffectMiscValue[eff_idx]);
|
||||
return;
|
||||
}
|
||||
|
||||
Totem* pTotem = new Totem;
|
||||
|
||||
if (!pTotem->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_UNIT), pos, cinfo, m_caster))
|
||||
{
|
||||
delete pTotem;
|
||||
return;
|
||||
}
|
||||
|
||||
pTotem->SetSummonPoint(pos);
|
||||
|
||||
if (slot < MAX_TOTEM_SLOT)
|
||||
m_caster->_AddTotem(TotemSlot(slot),pTotem);
|
||||
|
||||
//pTotem->SetName(""); // generated by client
|
||||
pTotem->SetOwner(m_caster);
|
||||
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initialized
|
||||
|
||||
pTotem->SetDuration(m_duration);
|
||||
|
||||
if (damage) // if not spell info, DB values used
|
||||
{
|
||||
pTotem->SetMaxHealth(damage);
|
||||
pTotem->SetHealth(damage);
|
||||
}
|
||||
|
||||
pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
pTotem->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
|
||||
|
||||
if (m_caster->IsPvP())
|
||||
pTotem->SetPvP(true);
|
||||
|
||||
if (m_caster->IsFFAPvP())
|
||||
pTotem->SetFFAPvP(true);
|
||||
|
||||
// sending SMSG_TOTEM_CREATED before add to map (done in Summon)
|
||||
if (slot < MAX_TOTEM_SLOT && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_TOTEM_CREATED, 1 + 8 + 4 + 4);
|
||||
data << uint8(slot);
|
||||
data << pTotem->GetObjectGuid();
|
||||
data << uint32(m_duration);
|
||||
data << uint32(m_spellInfo->Id);
|
||||
((Player*)m_caster)->SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
pTotem->Summon(m_caster);
|
||||
}
|
||||
|
||||
void Spell::EffectEnchantHeldItem(SpellEffectIndex eff_idx)
|
||||
{
|
||||
// this is only item spell effect applied to main-hand weapon of target player (players in area)
|
||||
|
|
@ -9031,78 +9084,6 @@ void Spell::EffectCharge2(SpellEffectIndex /*eff_idx*/)
|
|||
m_caster->Attack(unitTarget, true);
|
||||
}
|
||||
|
||||
void Spell::DoSummonCritter(SpellEffectIndex eff_idx, uint32 forceFaction)
|
||||
{
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
||||
if(!pet_entry)
|
||||
return;
|
||||
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||
if (!cInfo)
|
||||
{
|
||||
sLog.outErrorDb("Spell::DoSummonCritter: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
||||
return;
|
||||
}
|
||||
|
||||
Pet* old_critter = m_caster->GetMiniPet();
|
||||
|
||||
// for same pet just despawn (player unsummon command)
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && old_critter && old_critter->GetEntry() == pet_entry)
|
||||
{
|
||||
m_caster->RemoveMiniPet();
|
||||
return;
|
||||
}
|
||||
|
||||
// despawn old pet before summon new
|
||||
if (old_critter)
|
||||
m_caster->RemoveMiniPet();
|
||||
|
||||
CreatureCreatePos pos(m_caster->GetMap(), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, m_caster->GetOrientation(), m_caster->GetPhaseMask());
|
||||
if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
|
||||
pos = CreatureCreatePos(m_caster, m_caster->GetOrientation());
|
||||
|
||||
// summon new pet
|
||||
Pet* critter = new Pet(MINI_PET);
|
||||
|
||||
Map *map = m_caster->GetMap();
|
||||
uint32 pet_number = sObjectMgr.GeneratePetNumber();
|
||||
if (!critter->Create(map->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
|
||||
{
|
||||
sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
|
||||
delete critter;
|
||||
return;
|
||||
}
|
||||
|
||||
critter->SetSummonPoint(pos);
|
||||
|
||||
//critter->SetName(""); // generated by client
|
||||
critter->SetOwnerGuid(m_caster->GetObjectGuid());
|
||||
critter->SetCreatorGuid(m_caster->GetObjectGuid());
|
||||
|
||||
critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
critter->setFaction(forceFaction ? forceFaction : m_caster->getFaction());
|
||||
critter->AIM_Initialize();
|
||||
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
|
||||
//critter->InitLevelupSpellsForLevel(); // none?
|
||||
critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
|
||||
critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag);
|
||||
// some mini-pets have quests
|
||||
|
||||
// set timer for unsummon
|
||||
if(m_duration > 0)
|
||||
critter->SetDuration(m_duration);
|
||||
|
||||
m_caster->SetMiniPet(critter);
|
||||
|
||||
map->Add((Creature*)critter);
|
||||
|
||||
// Notify Summoner
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
|
||||
((Creature*)m_caster)->AI()->JustSummoned(critter);
|
||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||
((Creature*)m_originalCaster)->AI()->JustSummoned(critter);
|
||||
}
|
||||
|
||||
void Spell::EffectKnockBack(SpellEffectIndex eff_idx)
|
||||
{
|
||||
if (!unitTarget)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "12040"
|
||||
#define REVISION_NR "12041"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue