[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:
Schmoozerd 2012-07-15 02:01:42 +02:00
parent 6b50ce1f1a
commit dc60abae90
3 changed files with 391 additions and 394 deletions

View file

@ -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

View file

@ -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)

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "12040"
#define REVISION_NR "12041"
#endif // __REVISION_NR_H__