*More work on summon system.
--HG-- branch : trunk
This commit is contained in:
@@ -136,10 +136,10 @@ Unit(),
|
||||
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
|
||||
m_lootMoney(0), m_lootRecipient(0),
|
||||
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
|
||||
m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isVehicle(false), m_isTotem(false),
|
||||
m_gossipOptionLoaded(false), m_emoteState(0),
|
||||
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
|
||||
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
|
||||
m_creatureInfo(NULL), m_reactState(REACT_AGGRESSIVE), m_formationID(0), m_isSummon(false)
|
||||
m_creatureInfo(NULL), m_reactState(REACT_AGGRESSIVE), m_formationID(0), m_summonMask(SUMMON_MASK_NONE)
|
||||
{
|
||||
m_regenTimer = 200;
|
||||
m_valuesCount = UNIT_END;
|
||||
@@ -597,9 +597,10 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(i_AI) delete i_AI;
|
||||
UnitAI *oldAI = i_AI;
|
||||
i_motionMaster.Initialize();
|
||||
i_AI = ai ? ai : FactorySelector::selectAI(this);
|
||||
if(oldAI) delete oldAI;
|
||||
IsAIEnabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
+16
-8
@@ -136,6 +136,16 @@ enum CreatureFlagsExtra
|
||||
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00010000, // cannot be taunted
|
||||
};
|
||||
|
||||
enum SummonMask
|
||||
{
|
||||
SUMMON_MASK_NONE = 0x00000000,
|
||||
SUMMON_MASK_SUMMON = 0x00000001,
|
||||
SUMMON_MASK_GUARDIAN = 0x00000002,
|
||||
SUMMON_MASK_TOTEM = 0x00000004,
|
||||
SUMMON_MASK_PET = 0x00000008,
|
||||
SUMMON_MASK_VEHICLE = 0x00000010,
|
||||
};
|
||||
|
||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
|
||||
#if defined( __GNUC__ )
|
||||
#pragma pack(1)
|
||||
@@ -436,11 +446,12 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
|
||||
uint32 GetEquipmentId() const { return m_equipmentId; }
|
||||
|
||||
bool isSummon() const { return m_isSummon; }
|
||||
bool isPet() const { return m_isPet; }
|
||||
bool isVehicle() const { return m_isVehicle; }
|
||||
uint32 GetSummonMask() const { return m_summonMask; }
|
||||
bool isSummon() const { return m_summonMask & SUMMON_MASK_SUMMON; }
|
||||
bool isPet() const { return m_summonMask & SUMMON_MASK_PET; }
|
||||
bool isVehicle() const { return m_summonMask & SUMMON_MASK_VEHICLE; }
|
||||
bool isTotem() const { return m_summonMask & SUMMON_MASK_TOTEM; }
|
||||
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
|
||||
bool isTotem() const { return m_isTotem; }
|
||||
bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
|
||||
bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
|
||||
@@ -669,10 +680,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
GossipOptionList m_goptions;
|
||||
|
||||
uint8 m_emoteState;
|
||||
bool m_isSummon;
|
||||
bool m_isPet; // set only in Pet::Pet
|
||||
bool m_isVehicle; // set only in Vehicle::Vehicle
|
||||
bool m_isTotem; // set only in Totem::Totem
|
||||
uint32 m_summonMask;
|
||||
ReactStates m_reactState; // for AI, not charmInfo
|
||||
void RegenerateMana();
|
||||
void RegenerateHealth();
|
||||
|
||||
@@ -64,10 +64,17 @@ namespace FactorySelector
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
else if(creature->isTotem())
|
||||
ai_factory = ai_registry.GetRegistryItem("TotemAI");
|
||||
else if(creature->isSummon() && ((TempSummon*)creature)->m_properties && ((TempSummon*)creature)->m_properties->Type == SUMMON_TYPE_MINIPET)
|
||||
ai_factory = ai_registry.GetRegistryItem("CritterAI");
|
||||
else if(creature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
|
||||
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
|
||||
else if(creature->isSummon() && ((TempSummon*)creature)->m_Properties)
|
||||
{
|
||||
if(((TempSummon*)creature)->m_Properties->Category == SUMMON_CATEGORY_GUARDIAN
|
||||
|| ((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_GUARDIAN
|
||||
|| ((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_MINION)
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
else if(((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_MINIPET)
|
||||
ai_factory = ai_registry.GetRegistryItem("CritterAI");
|
||||
}
|
||||
else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER)
|
||||
ai_factory = ai_registry.GetRegistryItem("CritterAI");
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class InstanceData;
|
||||
class Group;
|
||||
class InstanceSave;
|
||||
class WorldObject;
|
||||
class TempSummon;
|
||||
|
||||
namespace ZThread
|
||||
{
|
||||
@@ -414,6 +415,8 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
|
||||
template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier);
|
||||
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier);
|
||||
template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier);
|
||||
|
||||
TempSummon *SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties = NULL, uint32 duration = 0, Unit *summoner = NULL);
|
||||
private:
|
||||
void LoadVMap(int pX, int pY);
|
||||
void LoadMap(uint32 mapid, uint32 instanceid, int x,int y);
|
||||
|
||||
+73
-20
@@ -44,6 +44,7 @@
|
||||
#include "GridNotifiersImpl.h"
|
||||
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
|
||||
uint32 GuidHigh2TypeId(uint32 guid_hi)
|
||||
{
|
||||
@@ -1578,34 +1579,88 @@ void WorldObject::AddObjectToRemoveList()
|
||||
map->AddObjectToRemoveList(this);
|
||||
}
|
||||
|
||||
TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
|
||||
TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties, uint32 duration, Unit *summoner)
|
||||
{
|
||||
TempSummon* pCreature = new TempSummon(GetGUID());
|
||||
|
||||
uint32 team = 0;
|
||||
if (GetTypeId()==TYPEID_PLAYER)
|
||||
team = ((Player*)this)->GetTeam();
|
||||
|
||||
if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), GetPhaseMask(), id, team))
|
||||
uint32 mask = SUMMON_MASK_SUMMON;
|
||||
if(properties)
|
||||
{
|
||||
delete pCreature;
|
||||
if(properties->Category == SUMMON_CATEGORY_GUARDIAN
|
||||
|| properties->Type == SUMMON_TYPE_GUARDIAN
|
||||
|| properties->Type == SUMMON_TYPE_MINION)
|
||||
mask = SUMMON_MASK_GUARDIAN;
|
||||
else if(properties->Type == SUMMON_TYPE_TOTEM)
|
||||
mask = SUMMON_MASK_TOTEM;
|
||||
else if(properties->Category == SUMMON_CATEGORY_VEHICLE
|
||||
|| properties->Type == SUMMON_TYPE_VEHICLE)
|
||||
mask = SUMMON_MASK_VEHICLE;
|
||||
}
|
||||
|
||||
TempSummon *summon = NULL;
|
||||
bool ok = true;
|
||||
uint32 phase = PHASEMASK_NORMAL, team = 0;
|
||||
if(summoner)
|
||||
{
|
||||
phase = summoner->GetPhaseMask();
|
||||
if(summoner->GetTypeId() == TYPEID_PLAYER)
|
||||
team = ((Player*)summoner)->GetTeam();
|
||||
}
|
||||
|
||||
switch(mask)
|
||||
{
|
||||
case SUMMON_MASK_SUMMON:
|
||||
summon = new TempSummon(properties, summoner);
|
||||
ok = summon->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), this, phase, entry, team);
|
||||
break;
|
||||
case SUMMON_MASK_GUARDIAN:
|
||||
summon = new Guardian(properties, summoner);
|
||||
team = objmgr.GeneratePetNumber();
|
||||
ok = summon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), this, phase, entry, team);
|
||||
// this enables pet details window (Shift+P)
|
||||
summon->GetCharmInfo()->SetPetNumber(team, false);
|
||||
break;
|
||||
case SUMMON_MASK_TOTEM:
|
||||
summon = new Totem(properties, summoner);
|
||||
ok = summon->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), this, phase, entry, team);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
if(!ok)
|
||||
{
|
||||
delete summon;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
summon->Relocate(x, y, z, angle);
|
||||
if(!summon->IsPositionValid())
|
||||
{
|
||||
sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",summon->GetGUIDLow(),summon->GetEntry(),summon->GetPositionX(),summon->GetPositionY());
|
||||
delete summon;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
summon->InitSummon(duration);
|
||||
|
||||
Add((Creature*)summon);
|
||||
|
||||
return summon;
|
||||
}
|
||||
|
||||
TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z, float ang, TempSummonType spwtype, uint32 duration)
|
||||
{
|
||||
if(!IsInWorld())
|
||||
return NULL;
|
||||
|
||||
if (x == 0.0f && y == 0.0f && z == 0.0f)
|
||||
GetClosePoint(x, y, z, pCreature->GetObjectSize());
|
||||
GetClosePoint(x, y, z, GetObjectSize());
|
||||
|
||||
pCreature->Relocate(x, y, z, ang);
|
||||
|
||||
if(!pCreature->IsPositionValid())
|
||||
{
|
||||
sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
|
||||
delete pCreature;
|
||||
TempSummon *pCreature = GetMap()->SummonCreature(entry, x, y, z, ang, NULL, duration, GetTypeId() == TYPEID_UNIT ? (Unit*)this : NULL);
|
||||
if(!pCreature)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pCreature->SetHomePosition(x, y, z, ang);
|
||||
pCreature->Summon(spwtype, despwtime);
|
||||
pCreature->InitSummon(duration);
|
||||
pCreature->SetTempSummonType(spwtype);
|
||||
|
||||
if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->IsAIEnabled)
|
||||
((Creature*)this)->AI()->JustSummoned(pCreature);
|
||||
@@ -1617,7 +1672,6 @@ TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, fl
|
||||
pCreature->CastSpell(pCreature, pCreature->m_spells[0], false, 0, 0, GetGUID());
|
||||
}
|
||||
|
||||
//return the creature therewith the summoner has access to it
|
||||
return pCreature;
|
||||
}
|
||||
|
||||
@@ -1727,7 +1781,6 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
|
||||
|
||||
switch(petType)
|
||||
{
|
||||
case GUARDIAN_PET:
|
||||
case POSSESSED_PET:
|
||||
pet->SetUInt32Value(UNIT_FIELD_FLAGS,0);
|
||||
AddGuardian(pet);
|
||||
|
||||
+2
-41
@@ -44,19 +44,15 @@ Creature(), m_petType(type), m_removed(false), m_happinessTimer(7500), m_duratio
|
||||
m_resetTalentsCost(0), m_resetTalentsTime(0), m_usedTalentCount(0), m_auraRaidUpdateMask(0), m_loading(false),
|
||||
m_declinedname(NULL)
|
||||
{
|
||||
m_isPet = true;
|
||||
m_summonMask |= SUMMON_MASK_PET;
|
||||
m_name = "Pet";
|
||||
m_regenTimer = 4000;
|
||||
|
||||
// pets always have a charminfo, even if they are not actually charmed
|
||||
CharmInfo* charmInfo = InitCharmInfo();
|
||||
InitCharmInfo();
|
||||
|
||||
if(type == POSSESSED_PET) // always passive
|
||||
SetReactState(REACT_PASSIVE);
|
||||
else if(type == GUARDIAN_PET) // always aggressive
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
//m_isActive = true;
|
||||
}
|
||||
|
||||
Pet::~Pet()
|
||||
@@ -930,41 +926,6 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUARDIAN_PET:
|
||||
SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
|
||||
SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
|
||||
|
||||
switch(GetEntry())
|
||||
{
|
||||
case 1964: //force of nature
|
||||
SetCreateHealth(30 + 30*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 2.5f - (petlevel / 2)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 2.5f + (petlevel / 2)));
|
||||
break;
|
||||
case 15352: //earth elemental 36213
|
||||
SetCreateHealth(100 + 120*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
break;
|
||||
case 15438: //fire elemental
|
||||
SetCreateHealth(40*petlevel);
|
||||
SetCreateMana(28 + 10*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 4 - petlevel));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel));
|
||||
break;
|
||||
default:
|
||||
SetCreateMana(28 + 10*petlevel);
|
||||
SetCreateHealth(28 + 30*petlevel);
|
||||
|
||||
// FIXME: this is wrong formula, possible each guardian pet have own damage formula
|
||||
//these formula may not be correct; however, it is designed to be close to what it should be
|
||||
//this makes dps 0.5 of pets level
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
//damage range is then petlevel / 2
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Pet have incorrect type (%u) for levelup.", getPetType());
|
||||
break;
|
||||
|
||||
+2
-3
@@ -29,9 +29,8 @@ enum PetType
|
||||
{
|
||||
SUMMON_PET = 0,
|
||||
HUNTER_PET = 1,
|
||||
GUARDIAN_PET = 2,
|
||||
POSSESSED_PET = 3,
|
||||
MAX_PET_TYPE = 4
|
||||
POSSESSED_PET = 2,
|
||||
MAX_PET_TYPE = 4,
|
||||
};
|
||||
|
||||
extern char const* petTypeSuffix[MAX_PET_TYPE];
|
||||
|
||||
@@ -157,7 +157,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
|
||||
p->setDeathState(CORPSE);
|
||||
}
|
||||
else // charmed or possessed
|
||||
_player->Uncharm();
|
||||
_player->StopCastingCharm();
|
||||
break;
|
||||
default:
|
||||
sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
|
||||
@@ -493,7 +493,7 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
|
||||
_player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
|
||||
}
|
||||
else if(pet->GetGUID() == _player->GetCharmGUID())
|
||||
_player->Uncharm();
|
||||
_player->StopCastingCharm();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-55
@@ -1424,9 +1424,6 @@ void Player::setDeathState(DeathState s)
|
||||
//FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD)
|
||||
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
|
||||
|
||||
// remove uncontrolled pets
|
||||
RemoveGuardians();
|
||||
|
||||
// save value before aura remove in Unit::setDeathState
|
||||
ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL);
|
||||
|
||||
@@ -1886,7 +1883,6 @@ void Player::RemoveFromWorld()
|
||||
///- Release charmed creatures, unsummon totems and remove pets/guardians
|
||||
StopCastingCharm();
|
||||
StopCastingBindSight();
|
||||
RemoveGuardians();
|
||||
}
|
||||
|
||||
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
|
||||
@@ -17051,11 +17047,8 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
// only if current pet in slot
|
||||
switch(pet->getPetType())
|
||||
{
|
||||
case GUARDIAN_PET:
|
||||
m_guardianPets.erase(pet->GetGUID());
|
||||
break;
|
||||
case POSSESSED_PET:
|
||||
m_guardianPets.erase(pet->GetGUID());
|
||||
m_Guardians.erase(pet->GetGUID());
|
||||
pet->RemoveCharmedOrPossessedBy(NULL);
|
||||
break;
|
||||
default:
|
||||
@@ -17098,30 +17091,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveGuardians()
|
||||
{
|
||||
while(!m_guardianPets.empty())
|
||||
{
|
||||
uint64 guid = *m_guardianPets.begin();
|
||||
if(Pet* pet = ObjectAccessor::GetPet(guid))
|
||||
pet->Remove(PET_SAVE_AS_DELETED);
|
||||
|
||||
m_guardianPets.erase(guid);
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::HasGuardianWithEntry(uint32 entry)
|
||||
{
|
||||
// pet guid middle part is entry (and creature also)
|
||||
// and in guardian list must be guardians with same entry _always_
|
||||
for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
|
||||
if(GUID_ENPART(*itr)==entry)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Player::Uncharm()
|
||||
void Player::StopCastingCharm()
|
||||
{
|
||||
Unit* charm = GetCharm();
|
||||
if(!charm)
|
||||
@@ -17295,13 +17265,14 @@ void Player::PetSpellInitialize()
|
||||
data << uint32(itr->second); // category cooldown
|
||||
}
|
||||
|
||||
data.hexlike();
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::PossessSpellInitialize()
|
||||
{
|
||||
Unit* charm = GetCharm();
|
||||
|
||||
if(!charm)
|
||||
return;
|
||||
|
||||
@@ -17313,24 +17284,23 @@ void Player::PossessSpellInitialize()
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 addlist = 0;
|
||||
WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds
|
||||
WorldPacket data(SMSG_PET_SPELLS, 20+40+1+1);
|
||||
|
||||
//16
|
||||
//basic info 20
|
||||
data << uint64(charm->GetGUID());
|
||||
data << uint32(0x00000000);
|
||||
data << uint32(0);
|
||||
data << uint8(0) << uint8(0) << uint16(0);
|
||||
data << uint32(0); //family
|
||||
data << uint32(0); //0
|
||||
data << uint8(0) << uint8(0) << uint16(0); //reactstate, commandstate, 0
|
||||
|
||||
for(uint32 i = 0; i < 10; i++) //40
|
||||
{
|
||||
//action bar 40
|
||||
for(uint32 i = 0; i < 10; i++)
|
||||
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
|
||||
}
|
||||
|
||||
data << uint8(addlist); //1
|
||||
//addlist 1
|
||||
data << uint8(0);
|
||||
|
||||
uint8 count = 0;
|
||||
data << uint8(count); // cooldowns count
|
||||
//cooldown 1
|
||||
data << uint8(0);
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
@@ -17377,7 +17347,8 @@ void Player::VehicleSpellInitialize()
|
||||
void Player::CharmSpellInitialize()
|
||||
{
|
||||
Unit* charm = GetCharm();
|
||||
|
||||
if(!charm && GetPetGUID())
|
||||
charm = GetUnit(*this, GetPetGUID());
|
||||
if(!charm)
|
||||
return;
|
||||
|
||||
@@ -17389,14 +17360,12 @@ void Player::CharmSpellInitialize()
|
||||
}
|
||||
|
||||
uint8 addlist = 0;
|
||||
|
||||
if(charm->GetTypeId() != TYPEID_PLAYER)
|
||||
{
|
||||
CreatureInfo const *cinfo = ((Creature*)charm)->GetCreatureInfo();
|
||||
|
||||
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
|
||||
//if(cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK)
|
||||
{
|
||||
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
for(uint32 i = 0; i < 4; ++i)
|
||||
{
|
||||
if(charmInfo->GetCharmSpell(i)->spellId)
|
||||
++addlist;
|
||||
@@ -17404,10 +17373,11 @@ void Player::CharmSpellInitialize()
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_PET_SPELLS, 16+40+1+4*addlist+25);// first line + actionbar + spellcount + spells + last adds
|
||||
WorldPacket data(SMSG_PET_SPELLS, 20+40+1+4*addlist+1);// first line + actionbar + spellcount + spells + last adds
|
||||
|
||||
//basic info 20
|
||||
data << uint64(charm->GetGUID());
|
||||
data << uint32(0x00000000);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
if(charm->GetTypeId() != TYPEID_PLAYER)
|
||||
data << uint8(((Creature*)charm)->GetReactState()) << uint8(charmInfo->GetCommandState());
|
||||
@@ -17415,16 +17385,17 @@ void Player::CharmSpellInitialize()
|
||||
data << uint8(0) << uint8(0);
|
||||
data << uint16(0);
|
||||
|
||||
for(uint32 i = 0; i < 10; i++) //40
|
||||
//action bar 40
|
||||
for(uint32 i = 0; i < 10; ++i) //40
|
||||
{
|
||||
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
|
||||
}
|
||||
|
||||
//add list
|
||||
data << uint8(addlist); //1
|
||||
|
||||
if(addlist)
|
||||
{
|
||||
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
for(uint32 i = 0; i < 4; ++i)
|
||||
{
|
||||
CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i);
|
||||
if(cspell->spellId)
|
||||
@@ -17435,9 +17406,12 @@ void Player::CharmSpellInitialize()
|
||||
}
|
||||
}
|
||||
|
||||
//cooldown
|
||||
uint8 count = 0;
|
||||
data << uint8(count); // cooldowns count
|
||||
|
||||
data.hexlike();
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
|
||||
+1
-10
@@ -298,8 +298,6 @@ typedef std::map<RepListID,FactionState> FactionStateList;
|
||||
|
||||
typedef std::map<uint32,ReputationRank> ForcedReactions;
|
||||
|
||||
typedef std::set<uint64> GuardianPetList;
|
||||
|
||||
struct EnchantDuration
|
||||
{
|
||||
EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) {};
|
||||
@@ -1052,11 +1050,6 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
|
||||
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
|
||||
void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false);
|
||||
void RemoveGuardians();
|
||||
bool HasGuardianWithEntry(uint32 entry);
|
||||
void AddGuardian(Pet* pet) { m_guardianPets.insert(pet->GetGUID()); }
|
||||
GuardianPetList const& GetGuardians() const { return m_guardianPets; }
|
||||
void Uncharm();
|
||||
uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn
|
||||
|
||||
void Say(const std::string& text, const uint32 language);
|
||||
@@ -2058,7 +2051,7 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
void SetSeer(WorldObject *target) { m_seer = target; }
|
||||
void CreateViewpoint(WorldObject *target);
|
||||
WorldObject* GetViewpoint() const;
|
||||
void StopCastingCharm() { Uncharm(); }
|
||||
void StopCastingCharm();
|
||||
void StopCastingBindSight();
|
||||
|
||||
// Transports
|
||||
@@ -2420,8 +2413,6 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
uint32 m_temporaryUnsummonedPetNumber;
|
||||
uint32 m_oldpetspell;
|
||||
|
||||
GuardianPetList m_guardianPets;
|
||||
|
||||
// Player summoning
|
||||
time_t m_summon_expire;
|
||||
uint32 m_summon_mapid;
|
||||
|
||||
@@ -2386,18 +2386,24 @@ enum SummonCategory
|
||||
|
||||
enum SummonType
|
||||
{
|
||||
SUMMON_TYPE_NONE = 0,
|
||||
SUMMON_TYPE_WILD1 = 1,
|
||||
SUMMON_TYPE_GUARDIAN = 2,
|
||||
SUMMON_TYPE_MINION = 3,
|
||||
SUMMON_TYPE_TOTEM = 4,
|
||||
SUMMON_TYPE_MINIPET = 5,
|
||||
SUMMON_TYPE_GUARDIAN2 = 6,
|
||||
SUMMON_TYPE_WILD2 = 7,
|
||||
SUMMON_TYPE_WILD3 = 8,
|
||||
SUMMON_TYPE_WILD4 = 9,
|
||||
SUMMON_TYPE_VEHICLE = 10,
|
||||
SUMMON_TYPE_OBJECT = 11,
|
||||
|
||||
SUMMON_TYPE_CRITTER = 41,
|
||||
SUMMON_TYPE_GUARDIAN = 61,
|
||||
SUMMON_TYPE_TOTEM_SLOT1 = 63,
|
||||
//SUMMON_TYPE_GUARDIAN = 61,
|
||||
SUMMON_TYPE_WILD = 64,
|
||||
SUMMON_TYPE_DEMON = 66,
|
||||
SUMMON_TYPE_SUMMON = 67,
|
||||
SUMMON_TYPE_TOTEM_SLOT2 = 81,
|
||||
SUMMON_TYPE_TOTEM_SLOT3 = 82,
|
||||
SUMMON_TYPE_TOTEM_SLOT4 = 83,
|
||||
SUMMON_TYPE_TOTEM = 121,
|
||||
SUMMON_TYPE_UNKNOWN3 = 181,
|
||||
SUMMON_TYPE_UNKNOWN4 = 187,
|
||||
SUMMON_TYPE_UNKNOWN1 = 247,
|
||||
|
||||
+4
-4
@@ -276,10 +276,7 @@ class Spell
|
||||
void EffectDualWield(uint32 i);
|
||||
void EffectPickPocket(uint32 i);
|
||||
void EffectAddFarsight(uint32 i);
|
||||
void EffectSummonPossessed(uint32 i);
|
||||
void EffectSummonVehicle(uint32 i);
|
||||
void EffectSummonWild(uint32 i);
|
||||
void EffectSummonGuardian(uint32 i);
|
||||
void EffectHealMechanical(uint32 i);
|
||||
void EffectJump(uint32 i);
|
||||
void EffectTeleUnitsFaceCaster(uint32 i);
|
||||
@@ -307,7 +304,6 @@ class Spell
|
||||
void EffectSummonPlayer(uint32 i);
|
||||
void EffectActivateObject(uint32 i);
|
||||
void EffectApplyGlyph(uint32 i);
|
||||
void EffectSummonTotem(uint32 i);
|
||||
void EffectEnchantHeldItem(uint32 i);
|
||||
void EffectSummonObject(uint32 i);
|
||||
void EffectResurrect(uint32 i);
|
||||
@@ -600,6 +596,10 @@ class Spell
|
||||
void SpellDamageHeal(uint32 i);
|
||||
|
||||
void GetSummonPosition(float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0);
|
||||
void SummonTotem (uint32 entry, SummonPropertiesEntry const *properties);
|
||||
void SummonGuardian (uint32 entry, SummonPropertiesEntry const *properties);
|
||||
void SummonPossessed(uint32 entry, SummonPropertiesEntry const *properties);
|
||||
void SummonVehicle (uint32 entry, SummonPropertiesEntry const *properties);
|
||||
|
||||
SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
|
||||
// -------------------------------------------
|
||||
|
||||
@@ -5440,6 +5440,7 @@ void Aura::CleanupTriggeredSpells()
|
||||
if(m_spellProto->EffectApplyAuraName[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL &&
|
||||
GetSpellDuration(m_spellProto) == m_spellProto->EffectAmplitude[GetEffIndex()])
|
||||
return;
|
||||
|
||||
m_target->RemoveAurasDueToSpell(tSpellId);
|
||||
}
|
||||
|
||||
|
||||
+152
-219
@@ -3313,15 +3313,12 @@ void Spell::EffectApplyAreaAura(uint32 i)
|
||||
|
||||
void Spell::EffectSummonType(uint32 i)
|
||||
{
|
||||
uint32 entry = m_spellInfo->EffectMiscValue[i];
|
||||
if(!entry)
|
||||
return;
|
||||
|
||||
switch(m_spellInfo->EffectMiscValueB[i])
|
||||
{
|
||||
case SUMMON_TYPE_GUARDIAN:
|
||||
EffectSummonGuardian(i);
|
||||
break;
|
||||
case SUMMON_TYPE_FORCE_OF_NATURE:
|
||||
case SUMMON_TYPE_FERAL_SPIRIT:
|
||||
EffectSummonGuardian(i);
|
||||
break;
|
||||
case SUMMON_TYPE_WILD:
|
||||
case SUMMON_TYPE_FROZEN_EARTH:
|
||||
case SUMMON_TYPE_LIGHTWELL:
|
||||
@@ -3333,39 +3330,45 @@ void Spell::EffectSummonType(uint32 i)
|
||||
case SUMMON_TYPE_SUMMON:
|
||||
EffectSummon(i);
|
||||
break;
|
||||
case SUMMON_TYPE_TOTEM_SLOT1:
|
||||
case SUMMON_TYPE_TOTEM_SLOT2:
|
||||
case SUMMON_TYPE_TOTEM_SLOT3:
|
||||
case SUMMON_TYPE_TOTEM_SLOT4:
|
||||
case SUMMON_TYPE_TOTEM:
|
||||
EffectSummonTotem(i);
|
||||
break;
|
||||
case SUMMON_TYPE_UNKNOWN1:
|
||||
case SUMMON_TYPE_UNKNOWN3:
|
||||
case SUMMON_TYPE_UNKNOWN4:
|
||||
case SUMMON_TYPE_UNKNOWN5:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]);
|
||||
if(!SummonProperties)
|
||||
SummonPropertiesEntry const *properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]);
|
||||
if(!properties)
|
||||
{
|
||||
sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
|
||||
return;
|
||||
}
|
||||
switch(SummonProperties->Category)
|
||||
switch(properties->Category)
|
||||
{
|
||||
default:
|
||||
if(SummonProperties->Type == SUMMON_TYPE_MINIPET)
|
||||
EffectSummonCritter(i);
|
||||
else
|
||||
EffectSummonWild(i);
|
||||
switch(properties->Type)
|
||||
{
|
||||
case SUMMON_TYPE_GUARDIAN:
|
||||
case SUMMON_TYPE_MINION:
|
||||
SummonGuardian(entry, properties);
|
||||
break;
|
||||
case SUMMON_TYPE_VEHICLE:
|
||||
SummonVehicle(entry, properties);
|
||||
break;
|
||||
case SUMMON_TYPE_TOTEM:
|
||||
SummonTotem(entry, properties);
|
||||
break;
|
||||
case SUMMON_TYPE_MINIPET:
|
||||
EffectSummonCritter(i);
|
||||
break;
|
||||
default:
|
||||
EffectSummonWild(i);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SUMMON_CATEGORY_GUARDIAN:
|
||||
SummonGuardian(entry, properties);
|
||||
break;
|
||||
case SUMMON_CATEGORY_POSSESSED:
|
||||
EffectSummonPossessed(i);
|
||||
SummonPossessed(entry, properties);
|
||||
break;
|
||||
case SUMMON_CATEGORY_VEHICLE:
|
||||
EffectSummonVehicle(i);
|
||||
SummonVehicle(entry, properties);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -3701,101 +3704,6 @@ void Spell::EffectSummonWild(uint32 i)
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectSummonGuardian(uint32 i)
|
||||
{
|
||||
uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
|
||||
if(!pet_entry)
|
||||
return;
|
||||
|
||||
// Jewelery statue case (totem like)
|
||||
if(m_spellInfo->SpellIconID==2056)
|
||||
{
|
||||
EffectSummonTotem(i);
|
||||
return;
|
||||
}
|
||||
|
||||
Player *caster = NULL;
|
||||
if(m_originalCaster)
|
||||
{
|
||||
if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
|
||||
caster = (Player*)m_originalCaster;
|
||||
else if(((Creature*)m_originalCaster)->isTotem())
|
||||
caster = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
}
|
||||
|
||||
if(!caster)
|
||||
{
|
||||
EffectSummonWild(i);
|
||||
return;
|
||||
}
|
||||
|
||||
// set timer for unsummon
|
||||
int32 duration = GetSpellDuration(m_spellInfo);
|
||||
|
||||
// Search old Guardian only for players (if casted spell not have duration or cooldown)
|
||||
// FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
|
||||
// so this code hack in fact
|
||||
if(duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0)
|
||||
if(caster->HasGuardianWithEntry(pet_entry))
|
||||
return; // find old guardian, ignore summon
|
||||
|
||||
// in another case summon new
|
||||
uint32 level = caster->getLevel();
|
||||
|
||||
// level of pet summoned using engineering item based at engineering skill level
|
||||
if(m_CastItem)
|
||||
{
|
||||
ItemPrototype const *proto = m_CastItem->GetProto();
|
||||
if(proto && proto->RequiredSkill == SKILL_ENGINERING)
|
||||
{
|
||||
uint16 skill202 = caster->GetSkillValue(SKILL_ENGINERING);
|
||||
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 = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
|
||||
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
|
||||
m_caster->GetClosePoint(px,py,pz,m_caster->GetObjectSize());
|
||||
|
||||
Pet *spawnCreature = caster->SummonPet(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(), GUARDIAN_PET, duration);
|
||||
if(!spawnCreature)
|
||||
return;
|
||||
|
||||
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
|
||||
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectTeleUnitsFaceCaster(uint32 i)
|
||||
{
|
||||
if(!unitTarget)
|
||||
@@ -5525,90 +5433,6 @@ void Spell::EffectApplyGlyph(uint32 i)
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectSummonTotem(uint32 i)
|
||||
{
|
||||
uint8 slot = 0;
|
||||
switch(m_spellInfo->EffectMiscValueB[i])
|
||||
{
|
||||
case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
|
||||
case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
|
||||
case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
|
||||
case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
|
||||
// Battle standard case
|
||||
case SUMMON_TYPE_TOTEM: slot = 254; break;
|
||||
// jewelery statue case, like totem without slot
|
||||
case SUMMON_TYPE_GUARDIAN: slot = 255; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
if(slot < MAX_TOTEM)
|
||||
{
|
||||
uint64 guid = m_caster->m_TotemSlot[slot];
|
||||
if(guid != 0)
|
||||
{
|
||||
Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
|
||||
if(OldTotem && OldTotem->isTotem())
|
||||
((Totem*)OldTotem)->UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 team = 0;
|
||||
if (m_caster->GetTypeId()==TYPEID_PLAYER)
|
||||
team = ((Player*)m_caster)->GetTeam();
|
||||
|
||||
Totem* pTotem = new Totem;
|
||||
|
||||
if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
|
||||
m_spellInfo->EffectMiscValue[i], team ))
|
||||
{
|
||||
delete pTotem;
|
||||
return;
|
||||
}
|
||||
|
||||
float x,y,z;
|
||||
GetSummonPosition(x, y, z);
|
||||
|
||||
// totem must be at same Z in case swimming caster and etc.
|
||||
if( fabs( z - m_caster->GetPositionZ() ) > 5 )
|
||||
z = m_caster->GetPositionZ();
|
||||
|
||||
pTotem->Relocate(x, y, z, m_caster->GetOrientation());
|
||||
|
||||
if(slot < MAX_TOTEM)
|
||||
m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
|
||||
|
||||
pTotem->SetOwner(m_caster->GetGUID());
|
||||
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
|
||||
|
||||
int32 duration=GetSpellDuration(m_spellInfo);
|
||||
if(Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
|
||||
pTotem->SetDuration(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);
|
||||
|
||||
pTotem->Summon(m_caster);
|
||||
|
||||
if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
|
||||
data << uint8(slot);
|
||||
data << uint64(pTotem->GetGUID());
|
||||
data << uint32(duration);
|
||||
data << uint32(m_spellInfo->Id);
|
||||
((Player*)m_caster)->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectEnchantHeldItem(uint32 i)
|
||||
{
|
||||
// this is only item spell effect applied to main-hand weapon of target player (players in area)
|
||||
@@ -6031,8 +5855,7 @@ void Spell::EffectSummonCritter(uint32 i)
|
||||
GetSummonPosition(x, y, z);
|
||||
|
||||
int32 duration = GetSpellDuration(m_spellInfo);
|
||||
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
TempSummon *critter = m_caster->SummonCreature(pet_entry, x, y, z, m_caster->GetOrientation(), summonType, duration);
|
||||
TempSummon *critter = m_caster->GetMap()->SummonCreature(pet_entry, x, y, z, m_caster->GetOrientation(), sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]), duration, m_caster);
|
||||
if(!critter)
|
||||
return;
|
||||
|
||||
@@ -6052,8 +5875,6 @@ void Spell::EffectSummonCritter(uint32 i)
|
||||
std::string name = player->GetName();
|
||||
name.append(petTypeSuffix[3]);
|
||||
critter->SetName( name );
|
||||
|
||||
critter->SetSummonProperties(sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i]));
|
||||
}
|
||||
|
||||
void Spell::EffectKnockBack(uint32 i)
|
||||
@@ -6681,12 +6502,128 @@ void Spell::EffectRedirectThreat(uint32 /*i*/)
|
||||
m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
|
||||
}
|
||||
|
||||
void Spell::EffectSummonPossessed(uint32 i)
|
||||
void Spell::SummonTotem(uint32 entry, SummonPropertiesEntry const *properties)
|
||||
{
|
||||
uint32 entry = m_spellInfo->EffectMiscValue[i];
|
||||
if(!entry)
|
||||
int8 slot = (int8)properties->Slot - 1;
|
||||
|
||||
if(slot >= 0 && slot < MAX_TOTEM)
|
||||
{
|
||||
uint64 guid = m_caster->m_TotemSlot[slot];
|
||||
if(guid != 0)
|
||||
{
|
||||
Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
|
||||
if(OldTotem && OldTotem->isTotem())
|
||||
((Totem*)OldTotem)->UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 team = 0;
|
||||
if (m_caster->GetTypeId()==TYPEID_PLAYER)
|
||||
team = ((Player*)m_caster)->GetTeam();
|
||||
|
||||
Totem* pTotem = new Totem(properties, m_caster);
|
||||
|
||||
if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
|
||||
entry, team ))
|
||||
{
|
||||
delete pTotem;
|
||||
return;
|
||||
}
|
||||
|
||||
float x,y,z;
|
||||
GetSummonPosition(x, y, z);
|
||||
|
||||
// totem must be at same Z in case swimming caster and etc.
|
||||
if( fabs( z - m_caster->GetPositionZ() ) > 5 )
|
||||
z = m_caster->GetPositionZ();
|
||||
|
||||
pTotem->Relocate(x, y, z, m_caster->GetOrientation());
|
||||
|
||||
if(slot < MAX_TOTEM)
|
||||
m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
|
||||
|
||||
pTotem->SetOwner(m_caster->GetGUID());
|
||||
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
|
||||
|
||||
int32 duration=GetSpellDuration(m_spellInfo);
|
||||
if(Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
|
||||
pTotem->SetDuration(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);
|
||||
|
||||
pTotem->Summon(m_caster);
|
||||
|
||||
if(slot >= 0 && slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
|
||||
data << uint8(slot);
|
||||
data << uint64(pTotem->GetGUID());
|
||||
data << uint32(duration);
|
||||
data << uint32(m_spellInfo->Id);
|
||||
((Player*)m_caster)->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties)
|
||||
{
|
||||
Unit *caster = m_originalCaster;
|
||||
if(caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())
|
||||
caster = caster->GetOwner();
|
||||
if(!caster)
|
||||
return;
|
||||
|
||||
// in another case summon new
|
||||
uint32 level = caster->getLevel();
|
||||
|
||||
// level of pet summoned using engineering item based at engineering skill level
|
||||
if(m_CastItem && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
ItemPrototype const *proto = m_CastItem->GetProto();
|
||||
if(proto && proto->RequiredSkill == SKILL_ENGINERING)
|
||||
{
|
||||
uint16 skill202 = ((Player*)caster)->GetSkillValue(SKILL_ENGINERING);
|
||||
if(skill202)
|
||||
{
|
||||
level = skill202/5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
||||
float radius = 5.0f;
|
||||
int32 amount = damage > 0 ? damage : 1;
|
||||
int32 duration = GetSpellDuration(m_spellInfo);
|
||||
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
Map *map = caster->GetMap();
|
||||
|
||||
for(int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
float px, py, pz;
|
||||
GetSummonPosition(px, py, pz, radius, count);
|
||||
|
||||
TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster);
|
||||
if(!summon)
|
||||
return;
|
||||
|
||||
if(summon->GetSummonMask() | SUMMON_MASK_GUARDIAN)
|
||||
((Guardian*)summon)->InitStatsForLevel(level);
|
||||
|
||||
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::SummonPossessed(uint32 entry, SummonPropertiesEntry const *properties)
|
||||
{
|
||||
if(m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
@@ -6705,12 +6642,8 @@ void Spell::EffectSummonPossessed(uint32 i)
|
||||
pet->SetCharmedOrPossessedBy(m_caster, true);
|
||||
}
|
||||
|
||||
void Spell::EffectSummonVehicle(uint32 i)
|
||||
void Spell::SummonVehicle(uint32 entry, SummonPropertiesEntry const *properties)
|
||||
{
|
||||
uint32 entry = m_spellInfo->EffectMiscValue[i];
|
||||
if(!entry)
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
|
||||
Vehicle *vehicle = m_caster->SummonVehicle(entry, x, y, z, m_caster->GetOrientation());
|
||||
|
||||
+128
-40
@@ -22,12 +22,13 @@
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
|
||||
TempSummon::TempSummon( uint64 summoner ) :
|
||||
Creature(), m_type(TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN), m_timer(0), m_lifetime(0), m_summoner(summoner)
|
||||
, m_properties(NULL)
|
||||
TempSummon::TempSummon(SummonPropertiesEntry const *properties, Unit *owner) :
|
||||
Creature(), m_type(TEMPSUMMON_MANUAL_DESPAWN), m_timer(0), m_lifetime(0)
|
||||
, m_Properties(properties), m_summonerGUID(owner->GetGUID())
|
||||
{
|
||||
m_isSummon = true;
|
||||
m_summonMask |= SUMMON_MASK_SUMMON;
|
||||
}
|
||||
|
||||
void TempSummon::Update( uint32 diff )
|
||||
@@ -159,50 +160,23 @@ void TempSummon::Update( uint32 diff )
|
||||
Creature::Update( diff );
|
||||
}
|
||||
|
||||
void TempSummon::Summon(TempSummonType type, uint32 lifetime)
|
||||
void TempSummon::InitSummon(uint32 duration)
|
||||
{
|
||||
m_type = type;
|
||||
m_timer = lifetime;
|
||||
m_lifetime = lifetime;
|
||||
m_timer = duration;
|
||||
m_lifetime = duration;
|
||||
|
||||
GetMap()->Add((Creature*)this);
|
||||
if(m_type == TEMPSUMMON_MANUAL_DESPAWN)
|
||||
m_type = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
|
||||
AIM_Initialize();
|
||||
}
|
||||
|
||||
void TempSummon::UnSummon()
|
||||
{
|
||||
CleanupsBeforeDelete();
|
||||
AddObjectToRemoveList();
|
||||
|
||||
Unit* owner = GetSummoner();
|
||||
if(owner)
|
||||
{
|
||||
if(owner->GetTypeId() == TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled)
|
||||
((Creature*)owner)->AI()->SummonedCreatureDespawn(this);
|
||||
|
||||
if(!m_properties)
|
||||
return;
|
||||
|
||||
if(uint32 slot = m_properties->Slot)
|
||||
{
|
||||
--slot;
|
||||
owner->m_TotemSlot[slot] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TempSummon::SetSummonProperties(SummonPropertiesEntry const *properties)
|
||||
{
|
||||
if(!properties)
|
||||
if(!m_Properties)
|
||||
return;
|
||||
|
||||
m_properties = properties;
|
||||
|
||||
if(uint32 slot = m_properties->Slot)
|
||||
Unit* owner = GetSummoner();
|
||||
if(uint32 slot = m_Properties->Slot)
|
||||
{
|
||||
--slot;
|
||||
Unit* owner = GetSummoner();
|
||||
if(owner)
|
||||
{
|
||||
if(owner->m_TotemSlot[slot] && owner->m_TotemSlot[slot] != GetGUID())
|
||||
@@ -214,11 +188,125 @@ void TempSummon::SetSummonProperties(SummonPropertiesEntry const *properties)
|
||||
owner->m_TotemSlot[slot] = GetGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AIM_Initialize();
|
||||
void TempSummon::SetTempSummonType(TempSummonType type)
|
||||
{
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
void TempSummon::UnSummon()
|
||||
{
|
||||
Unit* owner = GetSummoner();
|
||||
if(owner)
|
||||
{
|
||||
if(owner->GetTypeId() == TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled)
|
||||
((Creature*)owner)->AI()->SummonedCreatureDespawn(this);
|
||||
|
||||
if(m_Properties)
|
||||
{
|
||||
if(uint32 slot = m_Properties->Slot)
|
||||
{
|
||||
--slot;
|
||||
if(owner->m_TotemSlot[slot] = GetGUID())
|
||||
owner->m_TotemSlot[slot] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CleanupsBeforeDelete();
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
void TempSummon::SaveToDB()
|
||||
{
|
||||
}
|
||||
|
||||
Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : TempSummon(properties, owner)
|
||||
, m_owner(owner)
|
||||
{
|
||||
m_summonMask |= SUMMON_MASK_GUARDIAN;
|
||||
InitCharmInfo();
|
||||
}
|
||||
|
||||
bool Guardian::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number)
|
||||
{
|
||||
SetMapId(map->GetId());
|
||||
SetInstanceId(map->GetInstanceId());
|
||||
SetPhaseMask(phaseMask,false);
|
||||
|
||||
Object::_Create(guidlow, pet_number, HIGHGUID_PET);
|
||||
|
||||
m_DBTableGuid = guidlow;
|
||||
m_originalEntry = Entry;
|
||||
|
||||
if(!InitEntry(Entry))
|
||||
return false;
|
||||
|
||||
SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Guardian::InitSummon(uint32 duration)
|
||||
{
|
||||
TempSummon::InitSummon(duration);
|
||||
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
|
||||
|
||||
SetOwnerGUID(m_owner->GetGUID());
|
||||
SetCreatorGUID(m_owner->GetGUID());
|
||||
SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_owner->getFaction());
|
||||
m_owner->AddGuardian(this);
|
||||
SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
|
||||
|
||||
if(m_owner->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
m_owner->SetUInt64Value(UNIT_FIELD_SUMMON, GetGUID());
|
||||
m_charmInfo->InitCharmCreateSpells();
|
||||
//charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
|
||||
((Player*)m_owner)->CharmSpellInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
void Guardian::InitStatsForLevel(uint32 petlevel)
|
||||
{
|
||||
SetLevel(petlevel);
|
||||
switch(GetEntry())
|
||||
{
|
||||
case 1964: //force of nature
|
||||
SetCreateHealth(30 + 30*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 2.5f - (petlevel / 2)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 2.5f + (petlevel / 2)));
|
||||
break;
|
||||
case 15352: //earth elemental 36213
|
||||
SetCreateHealth(100 + 120*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
break;
|
||||
case 15438: //fire elemental
|
||||
SetCreateHealth(40*petlevel);
|
||||
SetCreateMana(28 + 10*petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 4 - petlevel));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel));
|
||||
break;
|
||||
default:
|
||||
SetCreateMana(28 + 10*petlevel);
|
||||
SetCreateHealth(28 + 30*petlevel);
|
||||
// FIXME: this is wrong formula, possible each guardian pet have own damage formula
|
||||
//these formula may not be correct; however, it is designed to be close to what it should be
|
||||
//this makes dps 0.5 of pets level
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
|
||||
//damage range is then petlevel / 2
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Guardian::UnSummon()
|
||||
{
|
||||
m_owner->m_Guardians.erase(GetGUID());
|
||||
TempSummon::UnSummon();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,21 +27,34 @@
|
||||
class TempSummon : public Creature
|
||||
{
|
||||
public:
|
||||
explicit TempSummon(uint64 summoner = 0);
|
||||
explicit TempSummon(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
virtual ~TempSummon(){};
|
||||
void Update(uint32 time);
|
||||
void Summon(TempSummonType type, uint32 lifetime);
|
||||
virtual void InitSummon(uint32 lifetime);
|
||||
virtual void UnSummon();
|
||||
void SetTempSummonType(TempSummonType type);
|
||||
void SaveToDB();
|
||||
Unit* GetSummoner() const { return m_summoner ? ObjectAccessor::GetUnit(*this, m_summoner) : NULL; }
|
||||
Unit* GetSummoner() const { return m_summonerGUID ? ObjectAccessor::GetUnit(*this, m_summonerGUID) : NULL; }
|
||||
|
||||
void SetSummonProperties(SummonPropertiesEntry const *properties);
|
||||
SummonPropertiesEntry const *m_properties;
|
||||
SummonPropertiesEntry const *m_Properties;
|
||||
private:
|
||||
TempSummonType m_type;
|
||||
uint32 m_timer;
|
||||
uint32 m_lifetime;
|
||||
uint64 m_summoner;
|
||||
uint64 m_summonerGUID;
|
||||
};
|
||||
|
||||
class Guardian : public TempSummon
|
||||
{
|
||||
public:
|
||||
Guardian(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
bool Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number);
|
||||
void InitSummon(uint32 duration);
|
||||
void UnSummon();
|
||||
void InitStatsForLevel(uint32 level);
|
||||
protected:
|
||||
Unit *m_owner;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
Totem::Totem() : TempSummon(0)
|
||||
Totem::Totem(SummonPropertiesEntry const *properties, Unit *owner) : TempSummon(properties, owner)
|
||||
{
|
||||
m_isTotem = true;
|
||||
m_summonMask |= SUMMON_MASK_TOTEM;
|
||||
m_duration = 0;
|
||||
m_type = TOTEM_PASSIVE;
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ enum TotemType
|
||||
class Totem : public TempSummon
|
||||
{
|
||||
public:
|
||||
explicit Totem();
|
||||
explicit Totem(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
virtual ~Totem(){};
|
||||
void Update( uint32 time );
|
||||
void Summon(Unit* owner);
|
||||
|
||||
+27
-11
@@ -106,7 +106,7 @@ Unit::Unit()
|
||||
|
||||
m_addDmgOnce = 0;
|
||||
|
||||
for(int i = 0; i < MAX_TOTEM; ++i)
|
||||
for(int i = 0; i < MAX_SUMMON_SLOT; ++i)
|
||||
m_TotemSlot[i] = 0;
|
||||
|
||||
m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
|
||||
@@ -8139,13 +8139,9 @@ void Unit::CombatStopWithPets(bool cast)
|
||||
pet->CombatStop(cast);
|
||||
if(Unit* charm = GetCharm())
|
||||
charm->CombatStop(cast);
|
||||
if(GetTypeId()==TYPEID_PLAYER)
|
||||
{
|
||||
GuardianPetList const& guardians = ((Player*)this)->GetGuardians();
|
||||
for(GuardianPetList::const_iterator itr = guardians.begin(); itr != guardians.end(); ++itr)
|
||||
if(Unit* guardian = Unit::GetUnit(*this,*itr))
|
||||
guardian->CombatStop(cast);
|
||||
}
|
||||
for(GuardianList::const_iterator itr = m_Guardians.begin(); itr != m_Guardians.end(); ++itr)
|
||||
if(Unit* guardian = Unit::GetUnit(*this,*itr))
|
||||
guardian->CombatStop(cast);
|
||||
}
|
||||
|
||||
bool Unit::isAttackingPlayer() const
|
||||
@@ -8362,7 +8358,7 @@ void Unit::RemoveCharmAuras()
|
||||
|
||||
void Unit::UnsummonAllTotems()
|
||||
{
|
||||
for (int8 i = 0; i < MAX_TOTEM; ++i)
|
||||
for (int8 i = 0; i < MAX_SUMMON_SLOT; ++i)
|
||||
{
|
||||
if(!m_TotemSlot[i])
|
||||
continue;
|
||||
@@ -10447,8 +10443,9 @@ void Unit::setDeathState(DeathState s)
|
||||
|
||||
if (s == JUST_DIED)
|
||||
{
|
||||
RemoveAllAurasOnDeath();
|
||||
UnsummonAllTotems();
|
||||
RemoveGuardians();
|
||||
RemoveAllAurasOnDeath();
|
||||
//This is needed to clear visible auras after unit dies
|
||||
UpdateAuras();
|
||||
|
||||
@@ -11404,6 +11401,7 @@ void Unit::RemoveFromWorld()
|
||||
if(IsInWorld())
|
||||
{
|
||||
UnsummonAllTotems();
|
||||
RemoveGuardians();
|
||||
RemoveCharmAuras();
|
||||
RemoveBindSightAuras();
|
||||
RemoveNotOwnSingleTargetAuras();
|
||||
@@ -11563,7 +11561,7 @@ void CharmInfo::InitCharmCreateSpells()
|
||||
|
||||
InitPetActionBar();
|
||||
|
||||
for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
|
||||
for(uint32 x = 0; x < 4; ++x)
|
||||
{
|
||||
uint32 spellId = ((Creature*)m_unit)->m_spells[x];
|
||||
m_charmspells[x].spellId = spellId;
|
||||
@@ -13351,6 +13349,7 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
|
||||
|
||||
if(GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet())
|
||||
{
|
||||
//TODO: this will cause crash when a guardian is charmed
|
||||
DeleteCharmInfo();
|
||||
}
|
||||
|
||||
@@ -13363,6 +13362,23 @@ void Unit::RemoveCharmedOrPossessedBy(Unit *charmer)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveGuardians()
|
||||
{
|
||||
while(!m_Guardians.empty())
|
||||
{
|
||||
uint64 guid = *m_Guardians.begin();
|
||||
if(Unit* guardian = ObjectAccessor::GetUnit(*this, guid))
|
||||
{
|
||||
if(guardian->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if(((Creature*)guardian)->isSummon())
|
||||
((TempSummon*)guardian)->UnSummon();
|
||||
}
|
||||
}
|
||||
m_Guardians.erase(guid);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RestoreFaction()
|
||||
{
|
||||
if(GetTypeId() == TYPEID_PLAYER)
|
||||
|
||||
@@ -838,6 +838,8 @@ struct AuraSlotEntry
|
||||
|
||||
struct SpellProcEventEntry; // used only privately
|
||||
|
||||
typedef std::set<uint64> GuardianList;
|
||||
|
||||
class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
{
|
||||
public:
|
||||
@@ -1304,6 +1306,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
uint32 m_detectInvisibilityMask;
|
||||
uint32 m_invisibilityMask;
|
||||
|
||||
GuardianList m_Guardians;
|
||||
void RemoveGuardians();
|
||||
void AddGuardian(Unit* pet) { m_Guardians.insert(pet->GetGUID()); }
|
||||
|
||||
uint32 m_ShapeShiftFormSpellId;
|
||||
ShapeshiftForm m_form;
|
||||
bool IsInFeralForm() const { return m_form == FORM_CAT || m_form == FORM_BEAR || m_form == FORM_DIREBEAR; }
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
Vehicle::Vehicle() : Creature(), m_vehicleId(0)
|
||||
{
|
||||
m_isVehicle = true;
|
||||
m_summonMask |= SUMMON_MASK_VEHICLE;
|
||||
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_VEHICLE);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user