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::SpellNotifierPlayer;
|
||||||
friend struct MaNGOS::SpellNotifierCreatureAndPlayer;
|
friend struct MaNGOS::SpellNotifierCreatureAndPlayer;
|
||||||
friend void Unit::SetCurrentCastedSpell( Spell * pSpell );
|
friend void Unit::SetCurrentCastedSpell( Spell * pSpell );
|
||||||
public:
|
|
||||||
|
|
||||||
|
public:
|
||||||
void EffectEmpty(SpellEffectIndex eff_idx);
|
void EffectEmpty(SpellEffectIndex eff_idx);
|
||||||
void EffectNULL(SpellEffectIndex eff_idx);
|
void EffectNULL(SpellEffectIndex eff_idx);
|
||||||
void EffectUnused(SpellEffectIndex eff_idx);
|
void EffectUnused(SpellEffectIndex eff_idx);
|
||||||
|
|
@ -393,11 +393,6 @@ class Spell
|
||||||
void setState(uint32 state) { m_spellState = state; }
|
void setState(uint32 state) { m_spellState = state; }
|
||||||
|
|
||||||
void DoCreateItem(SpellEffectIndex eff_idx, uint32 itemtype);
|
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 WriteSpellGoTargets(WorldPacket* data);
|
||||||
void WriteAmmoToPacket(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
|
// we can't store original aura link to prevent access to deleted auras
|
||||||
// and in same time need aura data and after aura deleting.
|
// and in same time need aura data and after aura deleting.
|
||||||
SpellEntry const* m_triggeredByAuraSpell;
|
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
|
enum ReplenishType
|
||||||
|
|
|
||||||
|
|
@ -4747,13 +4747,72 @@ void Spell::EffectApplyAreaAura(SpellEffectIndex eff_idx)
|
||||||
void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
uint32 prop_id = m_spellInfo->EffectMiscValueB[eff_idx];
|
uint32 prop_id = m_spellInfo->EffectMiscValueB[eff_idx];
|
||||||
SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
|
SummonPropertiesEntry const* summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
|
||||||
if(!summon_prop)
|
if (!summon_prop)
|
||||||
{
|
{
|
||||||
sLog.outError("EffectSummonType: Unhandled summon type %u", prop_id);
|
sLog.outError("EffectSummonType: Unhandled summon type %u", prop_id);
|
||||||
return;
|
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)
|
switch(summon_prop->Group)
|
||||||
{
|
{
|
||||||
// faction handled later on, or loaded from template
|
// faction handled later on, or loaded from template
|
||||||
|
|
@ -4768,15 +4827,15 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
||||||
//121: 23035, battlestands
|
//121: 23035, battlestands
|
||||||
//647: 52893, Anti-Magic Zone (npc used)
|
//647: 52893, Anti-Magic Zone (npc used)
|
||||||
if (prop_id == 121 || prop_id == 647)
|
if (prop_id == 121 || prop_id == 647)
|
||||||
DoSummonTotem(eff_idx);
|
summonResult = DoSummonTotem(eff_idx);
|
||||||
else
|
else
|
||||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNITNAME_SUMMON_TITLE_PET:
|
case UNITNAME_SUMMON_TITLE_PET:
|
||||||
case UNITNAME_SUMMON_TITLE_MINION:
|
case UNITNAME_SUMMON_TITLE_MINION:
|
||||||
case UNITNAME_SUMMON_TITLE_RUNEBLADE:
|
case UNITNAME_SUMMON_TITLE_RUNEBLADE:
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
case UNITNAME_SUMMON_TITLE_GUARDIAN:
|
case UNITNAME_SUMMON_TITLE_GUARDIAN:
|
||||||
{
|
{
|
||||||
|
|
@ -4784,7 +4843,7 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
// * Stone Statue, etc -- fits much better totem AI
|
// * Stone Statue, etc -- fits much better totem AI
|
||||||
if (m_spellInfo->SpellIconID == 2056)
|
if (m_spellInfo->SpellIconID == 2056)
|
||||||
DoSummonTotem(eff_idx);
|
summonResult = DoSummonTotem(eff_idx);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// possible sort totems/guardians only by summon creature type
|
// 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...
|
// FIXME: not all totems and similar cases seelcted by this check...
|
||||||
if (cInfo->type == CREATURE_TYPE_TOTEM)
|
if (cInfo->type == CREATURE_TYPE_TOTEM)
|
||||||
DoSummonTotem(eff_idx);
|
summonResult = DoSummonTotem(eff_idx);
|
||||||
else
|
else
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNITNAME_SUMMON_TITLE_CONSTRUCT:
|
case UNITNAME_SUMMON_TITLE_CONSTRUCT:
|
||||||
{
|
{
|
||||||
if (prop_id == 2913) // Scrapbot
|
if (prop_id == 2913) // Scrapbot
|
||||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||||
else
|
else
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNITNAME_SUMMON_TITLE_TOTEM:
|
case UNITNAME_SUMMON_TITLE_TOTEM:
|
||||||
DoSummonTotem(eff_idx, summon_prop->Slot);
|
summonResult = DoSummonTotem(eff_idx, summon_prop->Slot);
|
||||||
break;
|
break;
|
||||||
case UNITNAME_SUMMON_TITLE_COMPANION:
|
case UNITNAME_SUMMON_TITLE_COMPANION:
|
||||||
// slot 6 set for critters that can help to player in fighting
|
// slot 6 set for critters that can help to player in fighting
|
||||||
if (summon_prop->Slot == 6)
|
if (summon_prop->Slot == 6)
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
else
|
else
|
||||||
DoSummonCritter(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonCritter(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
case UNITNAME_SUMMON_TITLE_OPPONENT:
|
case UNITNAME_SUMMON_TITLE_OPPONENT:
|
||||||
case UNITNAME_SUMMON_TITLE_LIGHTWELL:
|
case UNITNAME_SUMMON_TITLE_LIGHTWELL:
|
||||||
case UNITNAME_SUMMON_TITLE_BUTLER:
|
case UNITNAME_SUMMON_TITLE_BUTLER:
|
||||||
DoSummonWild(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonWild(summonPositions, summon_prop, eff_idx, level);
|
||||||
break;
|
break;
|
||||||
case UNITNAME_SUMMON_TITLE_VEHICLE:
|
case UNITNAME_SUMMON_TITLE_VEHICLE:
|
||||||
case UNITNAME_SUMMON_TITLE_MOUNT:
|
case UNITNAME_SUMMON_TITLE_MOUNT:
|
||||||
|
|
@ -4841,19 +4900,17 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
||||||
case SUMMON_PROP_GROUP_PETS:
|
case SUMMON_PROP_GROUP_PETS:
|
||||||
{
|
{
|
||||||
// FIXME : multiple summons - not yet supported as pet
|
// FIXME : multiple summons - not yet supported as pet
|
||||||
//1562 - force of nature - sid 33831
|
// 1562 - force of nature - sid 33831
|
||||||
//1161 - feral spirit - sid 51533
|
// 1161 - feral spirit - sid 51533
|
||||||
if(prop_id == 1562) // 3 uncontrolable instead of one controllable :/
|
if (prop_id == 1562) // 3 uncontrolable instead of one controllable :/
|
||||||
DoSummonGuardian(eff_idx, summon_prop->FactionId);
|
summonResult = DoSummonGuardian(summonPositions, summon_prop, eff_idx, level);
|
||||||
else
|
|
||||||
DoSummonPet(eff_idx);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUMMON_PROP_GROUP_CONTROLLABLE:
|
case SUMMON_PROP_GROUP_CONTROLLABLE:
|
||||||
{
|
{
|
||||||
// no type here
|
// no type here
|
||||||
// maybe wrong - but thats the handler currently used for those
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
case SUMMON_PROP_GROUP_VEHICLE:
|
case SUMMON_PROP_GROUP_VEHICLE:
|
||||||
|
|
@ -4867,31 +4924,307 @@ void Spell::EffectSummonType(SpellEffectIndex eff_idx)
|
||||||
sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
|
sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
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())
|
if (m_caster->GetPetGuid())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if (!unitTarget)
|
if (!unitTarget)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
uint32 pet_entry = m_spellInfo->EffectMiscValue[eff_idx];
|
||||||
if (!pet_entry)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(pet_entry);
|
||||||
if (!cInfo)
|
if (!cInfo)
|
||||||
{
|
{
|
||||||
sLog.outErrorDb("Spell::DoSummonPet: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
|
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);
|
Pet* spawnCreature = new Pet(SUMMON_PET);
|
||||||
|
|
||||||
if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
|
if (m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
|
||||||
{
|
{
|
||||||
// Summon in dest location
|
// Summon in dest location
|
||||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||||
|
|
@ -4901,7 +5234,7 @@ void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
||||||
if (m_duration > 0)
|
if (m_duration > 0)
|
||||||
spawnCreature->SetDuration(m_duration);
|
spawnCreature->SetDuration(m_duration);
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summon in dest location
|
// 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);
|
sLog.outErrorDb("Spell::EffectSummon: can't create creature with entry %u for spell %u", cInfo->Entry, m_spellInfo->Id);
|
||||||
delete spawnCreature;
|
delete spawnCreature;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnCreature->SetSummonPoint(pos);
|
spawnCreature->SetSummonPoint(pos);
|
||||||
|
|
@ -4962,6 +5295,8 @@ void Spell::DoSummonPet(SpellEffectIndex eff_idx)
|
||||||
((Creature*)m_caster)->AI()->JustSummoned((Creature*)spawnCreature);
|
((Creature*)m_caster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||||
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
|
||||||
((Creature*)m_originalCaster)->AI()->JustSummoned((Creature*)spawnCreature);
|
((Creature*)m_originalCaster)->AI()->JustSummoned((Creature*)spawnCreature);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::EffectLearnSpell(SpellEffectIndex eff_idx)
|
void Spell::EffectLearnSpell(SpellEffectIndex eff_idx)
|
||||||
|
|
@ -5198,215 +5533,6 @@ void Spell::EffectAddFarsight(SpellEffectIndex eff_idx)
|
||||||
((Player*)m_caster)->GetCamera().SetView(dynObj);
|
((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)
|
void Spell::EffectTeleUnitsFaceCaster(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
if (!unitTarget)
|
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)
|
void Spell::EffectEnchantHeldItem(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
// this is only item spell effect applied to main-hand weapon of target player (players in area)
|
// 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);
|
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)
|
void Spell::EffectKnockBack(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
if (!unitTarget)
|
if (!unitTarget)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "12040"
|
#define REVISION_NR "12041"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue