Lots of cmangos commirs applied

This commit is contained in:
Charles A Edwards 2016-09-12 17:52:23 +01:00 committed by Antz
parent 8431568536
commit 18dd18780d
44 changed files with 677 additions and 323 deletions

View file

@ -130,7 +130,6 @@ class BattleGroundQueue
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
bool KickGroup(uint32 size);
uint32 GetPlayerCount() const {return PlayerCount;}
public:
GroupsQueueType SelectedGroups;
private:
uint32 PlayerCount;

View file

@ -235,8 +235,6 @@ bool ChatHandler::HandleTriggerCommand(char* args)
float dist2 = MAP_SIZE * MAP_SIZE;
Player* pl = m_session->GetPlayer();
// Search triggers
for (uint32 id = 0; id < sAreaTriggerStore.GetNumRows(); ++id)
{

View file

@ -734,17 +734,17 @@ dtStatus PathFinder::findSmoothPath(const float* startPos, const float* endPos,
npolys -= npos;
// Handle the connection.
float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
dtResult = m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos);
float newStartPos[VERTEX_SIZE], newEndPos[VERTEX_SIZE];
dtResult = m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, newStartPos, newEndPos);
if (dtStatusSucceed(dtResult))
{
if (nsmoothPath < maxSmoothPathSize)
{
dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], startPos);
dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], newStartPos);
++nsmoothPath;
}
// Move position at the other side of the off-mesh link.
dtVcopy(iterPos, endPos);
dtVcopy(iterPos, newEndPos);
m_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]);
iterPos[1] += 0.5f;

View file

@ -419,6 +419,7 @@ void FlightPathMovementGenerator::Reset(Player& player)
player.getHostileRefManager().setOnlineOfflineState(false);
player.addUnitState(UNIT_STAT_TAXI_FLIGHT);
player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
player.SetClientControl(&player, 0);
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();

View file

@ -411,7 +411,14 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*=
// creatures always have melee weapon ready if any
SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f);
if (preserveHPAndPower)
{
uint32 healthPercent = GetHealthPercent();
SelectLevel();
SetHealthPercent(healthPercent);
}
else
SelectLevel();
if (team == HORDE)
setFaction(GetCreatureInfo()->FactionHorde);
@ -830,6 +837,9 @@ bool Creature::AIM_Initialize()
i_motionMaster.Initialize();
i_AI = FactorySelector::selectAI(this);
delete oldAI;
// Handle Spawned Events, also calls Reset()
i_AI->JustRespawned();
return true;
}
@ -1241,6 +1251,126 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
WorldDatabase.CommitTransaction();
}
void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
{
CreatureInfo const* cinfo = GetCreatureInfo();
if (!cinfo)
return;
uint32 rank = IsPet() ? 0 : cinfo->Rank; // TODO :: IsPet probably not needed here
// level
uint32 level = forcedLevel;
uint32 const minlevel = cinfo->MinLevel;
uint32 const maxlevel = cinfo->MaxLevel;
if (level == USE_DEFAULT_DATABASE_LEVEL)
level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level);
//////////////////////////////////////////////////////////////////////////
// Calculate level dependent stats
//////////////////////////////////////////////////////////////////////////
uint32 health;
uint32 mana;
if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(level, cinfo->UnitClass, cinfo->Expansion))
{
// Use Creature Stats to calculate stat values
// health
health = cCLS->BaseHealth * cinfo->HealthMultiplier;
// mana
mana = cCLS->BaseMana * cinfo->PowerMultiplier;
}
else
{
if (forcedLevel == USE_DEFAULT_DATABASE_LEVEL || (forcedLevel >= minlevel && forcedLevel <= maxlevel))
{
// Use old style to calculate stat values
float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel);
// health
uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth);
health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth)));
// mana
uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana);
uint32 maxmana = std::max(cinfo->MaxLevelMana, cinfo->MinLevelMana);
mana = minmana + uint32(rellevel * (maxmana - minmana));
}
else
{
sLog.outError("Creature::SelectLevel> Error trying to set level(%u) for creature %s without enough data to do it!", level, GetGuidStr().c_str());
// probably wrong
health = (cinfo->MaxLevelHealth / cinfo->MaxLevel) * level;
mana = (cinfo->MaxLevelMana / cinfo->MaxLevel) * level;
}
}
health *= _GetHealthMod(rank); // Apply custom config settting
if (health < 1)
health = 1;
//////////////////////////////////////////////////////////////////////////
// Set values
//////////////////////////////////////////////////////////////////////////
// health
SetCreateHealth(health);
SetMaxHealth(health);
SetHealth(health);
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health));
// all power types
for (int i = POWER_MANA; i <= POWER_RUNIC_POWER; ++i)
{
uint32 maxValue = 0;
switch (i)
{
case POWER_MANA: maxValue = mana; break;
case POWER_RAGE: maxValue = 0; break;
case POWER_FOCUS: maxValue = POWER_FOCUS_DEFAULT; break;
case POWER_ENERGY: maxValue = POWER_ENERGY_DEFAULT * cinfo->PowerMultiplier; break;
case POWER_RUNE: maxValue = 0; break;
case POWER_RUNIC_POWER: maxValue = 0; break;
}
uint32 value = maxValue;
// For non regenerating powers set 0
if ((i == POWER_ENERGY || i == POWER_MANA) && !IsRegeneratingPower())
value = 0;
// Mana requires an extra field to be set
if (i == POWER_MANA)
SetCreateMana(value);
SetMaxPower(Powers(i), maxValue);
SetPower(Powers(i), value);
SetModifierValue(UnitMods(UNIT_MOD_POWER_START + i), BASE_VALUE, float(value));
}
// damage
float damagemod = _GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->MaxRangedDmg * damagemod);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->MeleeAttackPower * damagemod);
}
void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 100.0f*/)
{

View file

@ -78,7 +78,7 @@ enum CreatureFlagsExtra
#define MAX_KILL_CREDIT 2
#define MAX_CREATURE_MODEL 4
#define USE_DEFAULT_DATABASE_LEVEL 0 // just used to show we don't want to force the new creature level and use the level stored in db
// from `creature_template` table
struct CreatureInfo
@ -522,6 +522,7 @@ class Creature : public Unit
bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL);
bool LoadCreatureAddon(bool reload);
void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f);
void SelectLevel(uint32 forcedLevel = USE_DEFAULT_DATABASE_LEVEL);
void LoadEquipment(uint32 equip_entry, bool force = false);
bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid

View file

@ -59,9 +59,12 @@ namespace FactorySelector
// select by NPC flags _first_ - otherwise EventAI might be choosen for pets/totems
// excplicit check for isControlled() and owner type to allow guardian, mini-pets and pets controlled by NPCs to be scripted by EventAI
Unit* owner = NULL;
if ((creature->IsPet() && ((Pet*)creature)->isControlled() &&
((owner = creature->GetOwner()) && owner->GetTypeId() == TYPEID_PLAYER)) || creature->IsCharmed())
ai_factory = ai_registry.GetRegistryItem("PetAI");
if (creature->IsPet() && ((Pet*)creature)->isControlled())
{
Unit* controler = creature->GetOwner() ? creature->GetOwner() : creature->GetCharmer();
if (controler && controler->GetTypeId() == TYPEID_PLAYER && controler->IsAlive())
ai_factory = ai_registry.GetRegistryItem("PetAI");
}
else if (creature->IsTotem())
ai_factory = ai_registry.GetRegistryItem("TotemAI");

View file

@ -156,9 +156,6 @@ CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c),
}
else
sLog.outErrorEventAI("EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature->GetEntry());
// Handle Spawned Events, also calls Reset()
JustRespawned();
}
#define LOG_PROCESS_EVENT \

View file

@ -214,6 +214,7 @@ bool DynamicObject::isVisibleForInState(Player const* u, WorldObject const* view
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
bool DynamicObject::IsHostileTo(Unit const* unit) const
{
if (Unit* owner = GetCaster())

View file

@ -764,6 +764,76 @@ void GameObject::SaveRespawnTime()
{ GetMap()->GetPersistentState()->SaveGORespawnTime(GetGUIDLow(), m_respawnTime); }
}
bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
{
// Not in world
if (!IsInWorld() || !u->IsInWorld())
return false;
// invisible at client always
if (!GetGOInfo()->displayId)
return false;
// Transport always visible at this step implementation
if (IsTransport() && IsInMap(u))
return true;
// quick check visibility false cases for non-GM-mode
if (!u->isGameMaster())
{
// despawned and then not visible for non-GM in GM-mode
if (!isSpawned())
return false;
// special invisibility cases
if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && GetGOInfo()->trap.stealthed)
{
bool trapNotVisible = false;
// handle summoned traps, usually by players
if (Unit* owner = GetOwner())
{
if (owner->GetTypeId() == TYPEID_PLAYER)
{
Player* ownerPlayer = (Player*)owner;
if ((GetMap()->IsBattleGroundOrArena() && ownerPlayer->GetBGTeam() != u->GetBGTeam()) ||
(ownerPlayer->IsInDuelWith(u)) ||
(ownerPlayer->GetTeam() != u->GetTeam()))
trapNotVisible = true;
}
else
{
if (u->IsFriendlyTo(owner))
return true;
}
}
// handle environment traps (spawned by DB)
else
{
if (this->IsFriendlyTo(u))
return true;
else
trapNotVisible = true;
}
// only rogue have skill for traps detection
if (Aura* aura = ((Player*)u)->GetAura(2836, EFFECT_INDEX_0))
{
if (roll_chance_i(aura->GetModifier()->m_amount) && u->isInFront(this, 15.0f))
return true;
}
if (trapNotVisible)
return false;
}
}
// check distance
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() +
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
/*
bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const
{
// Not in world
@ -784,6 +854,7 @@ bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoi
// despawned and then not visible for non-GM in GM-mode
if (!isSpawned())
{ return false; }
*/
// special invisibility cases
/* TODO: implement trap stealth, take look at spell 2836
@ -792,12 +863,14 @@ bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoi
if(check stuff here)
return false;
}*/
/*
}
// check distance
return IsWithinDistInMap(viewPoint, GetMap()->GetVisibilityDistance() +
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
*/
void GameObject::Respawn()
{
@ -1669,7 +1742,7 @@ void GameObject::Use(Unit* user)
SpellCastTargets targets;
targets.setUnitTarget(user);
spell->prepare(&targets);
spell->SpellStart(&targets);
}
// overwrite WorldObject function for proper name localization

View file

@ -259,16 +259,19 @@ bool LootStoreItem::Roll(bool rate) const
if (mincountOrRef < 0) // reference case
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED) : 1.0f));
if (type == LOOT_ITEM_TYPE_ITEM)
if (type == LOOTITEM_TYPE_CURRENCY)
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY) : 1.0f));
else
{
if (needs_quest)
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_ITEM_QUEST) : 1.0f));
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemid);
float qualityModifier = pProto && rate ? sWorld.getConfig(qualityToRate[pProto->Quality]) : 1.0f;
return roll_chance_f(chance * qualityModifier);
}
else if (type == LOOT_ITEM_TYPE_CURRENCY)
return roll_chance_f(chance * (rate ? sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_CURRENCY) : 1.0f));
return false;
}

View file

@ -53,8 +53,10 @@ enum PermissionTypes
enum LootItemType
{
LOOT_ITEM_TYPE_ITEM = 0,
LOOT_ITEM_TYPE_CURRENCY = 1,
LOOT_ITEM_TYPE_ITEM = 0,
LOOT_ITEM_TYPE_CURRENCY = 1,
LOOTITEM_TYPE_CONDITIONNAL = 3,
LOOTITEM_TYPE_CURRENCY = 4,
};
enum LootType

View file

@ -133,63 +133,37 @@ void Object::SendForcedObjectUpdate()
void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
{
if (!target)
{ return; }
return;
uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
uint16 updateFlags = m_updateFlag;
/** lower flag1 **/
if (target == this) // building packet for yourself
{ updateFlags |= UPDATEFLAG_SELF; }
updateFlags |= UPDATEFLAG_SELF;
switch (GetObjectGuid().GetHigh())
if (m_itsNewObject)
{
case HIGHGUID_PLAYER:
case HIGHGUID_PET:
case HIGHGUID_CORPSE:
case HIGHGUID_DYNAMICOBJECT:
updatetype = UPDATETYPE_CREATE_OBJECT2;
break;
case HIGHGUID_UNIT:
switch (GetObjectGuid().GetHigh())
{
Creature* creature = (Creature*)this;
if (creature->IsTemporarySummon() && ((TemporarySummon*)this)->GetSummonerGuid().IsPlayer())
case HighGuid::HIGHGUID_DYNAMICOBJECT:
case HighGuid::HIGHGUID_CORPSE:
case HighGuid::HIGHGUID_PLAYER:
case HighGuid::HIGHGUID_UNIT:
case HighGuid::HIGHGUID_VEHICLE:
case HighGuid::HIGHGUID_GAMEOBJECT:
updatetype = UPDATETYPE_CREATE_OBJECT2;
break;
}
case HIGHGUID_GAMEOBJECT:
{
if (((GameObject*)this)->GetOwnerGuid().IsPlayer())
updatetype = UPDATETYPE_CREATE_OBJECT2;
break;
break;
default:
break;
}
}
if (updateFlags & UPDATEFLAG_HAS_POSITION)
{
// UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
if (isType(TYPEMASK_GAMEOBJECT))
{
switch (((GameObject*)this)->GetGoType())
{
case GAMEOBJECT_TYPE_TRAP:
case GAMEOBJECT_TYPE_DUEL_ARBITER:
case GAMEOBJECT_CreatureTypeFlagsTAND:
case GAMEOBJECT_TYPE_FLAGDROP:
updatetype = UPDATETYPE_CREATE_OBJECT2;
break;
case GAMEOBJECT_TYPE_TRANSPORT:
updateFlags |= UPDATEFLAG_TRANSPORT;
break;
default:
break;
}
}
if (isType(TYPEMASK_UNIT))
{
if (((Unit*)this)->getVictim())
updateFlags |= UPDATEFLAG_HAS_ATTACKING_TARGET;
}
if (isType(TYPEMASK_UNIT))
{
if (((Unit*)this)->getVictim())
updateFlags |= UPDATEFLAG_HAS_ATTACKING_TARGET;
}
// DEBUG_LOG("BuildCreateUpdate: update-type: %u, object-type: %u got updateFlags: %X", updatetype, m_objectTypeId, updateFlags);

View file

@ -400,6 +400,7 @@ class Object
virtual bool HasQuest(uint32 /* quest_id */) const { return false; }
virtual bool HasInvolvedQuest(uint32 /* quest_id */) const { return false; }
void SetItsNewObject(bool enable) { m_itsNewObject = enable; }
protected:
Object();
@ -435,6 +436,7 @@ class Object
private:
bool m_inWorld;
bool m_itsNewObject;
PackedGuid m_PackGUID;
@ -567,7 +569,7 @@ class WorldObject : public Object
float GetDistanceZ(const WorldObject* obj) const;
bool IsInMap(const WorldObject* obj) const
{
return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
return obj && IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj);
}
bool IsWithinDist3d(float x, float y, float z, float dist2compare) const;
bool IsWithinDist2d(float x, float y, float dist2compare) const;

View file

@ -8227,9 +8227,9 @@ bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject co
case CONDITION_TEAM:
{
if (conditionSourceType == CONDITION_FROM_REFERING_LOOT && sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{ return true; }
return true;
else
{ return uint32(player->GetTeam()) == m_value1; }
return uint32(player->GetTeam()) == m_value1;
}
case CONDITION_SKILL:
return player->HasSkill(m_value1) && player->GetBaseSkillValue(m_value1) >= m_value2;

View file

@ -197,6 +197,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
SetName(fields[8].GetString());
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
switch (getPetType())
{
case SUMMON_PET:

View file

@ -129,7 +129,7 @@ typedef std::vector<uint32> AutoSpellList;
#define ACTIVE_SPELLS_MAX 4
#define PET_FOLLOW_DIST 1.0f
#define PET_FOLLOW_ANGLE (M_PI_F/2.0f)
#define PET_FOLLOW_ANGLE (M_PI_F / 4.00f) * 3.50f
class Player;

View file

@ -48,28 +48,24 @@ PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK), inComb
UpdateAllies();
}
void PetAI::MoveInLineOfSight(Unit* u)
void PetAI::MoveInLineOfSight(Unit* pWho)
{
if (m_creature->getVictim())
return;
if (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
return;
if (!m_creature->GetCharmInfo() || !m_creature->GetCharmInfo()->HasReactState(REACT_AGGRESSIVE))
return;
if (u->IsTargetableForAttack() && m_creature->IsHostileTo(u) &&
u->isInAccessablePlaceFor(m_creature))
if (m_creature->CanInitiateAttack() && pWho->IsTargetableForAttack() &&
m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature))
{
float attackRadius = m_creature->GetAttackDistance(u);
if (m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE)
if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
return;
if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho))
{
if (m_creature->IsWithinLOSInMap(u))
{
AttackStart(u);
u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
}
pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(pWho);
}
}
}
@ -298,7 +294,7 @@ void PetAI::UpdateAI(const uint32 diff)
m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id);
spell->prepare(&targets);
spell->SpellStart(&targets);
}
// deleted cached Spell objects

View file

@ -3629,17 +3629,18 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
if (prev_itr != m_spells.end())
{
if (prev_itr->second.dependent != cur_dependent)
PlayerSpell& spell = prev_itr->second;
if (spell.dependent != cur_dependent)
{
prev_itr->second.dependent = cur_dependent;
if (prev_itr->second.state != PLAYERSPELL_NEW)
prev_itr->second.state = PLAYERSPELL_CHANGED;
spell.dependent = cur_dependent;
if (spell.state != PLAYERSPELL_NEW)
spell.state = PLAYERSPELL_CHANGED;
}
// now re-learn if need re-activate
if (cur_active && !prev_itr->second.active && learn_low_rank)
if (cur_active && !spell.active && learn_low_rank)
{
if (addSpell(prev_id, true, false, prev_itr->second.dependent, prev_itr->second.disabled))
if (addSpell(prev_id, true, false, spell.dependent, spell.disabled))
{
// downgrade spell ranks in spellbook and action bar
WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
@ -6306,7 +6307,12 @@ void Player::CheckAreaExploreAndOutdoor()
SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
if (!spellInfo || !IsNeedCastSpellAtOutdoor(spellInfo) || HasAura(itr->first))
continue;
CastSpell(this, itr->first, true, NULL);
SpellShapeshiftEntry const* shapeShift = spellInfo->GetSpellShapeshift();
if (!shapeShift || (shapeShift->Stances || shapeShift->StancesNot) && !IsNeedCastSpellAtFormApply(spellInfo, GetShapeshiftForm()))
continue;
CastSpell(this, itr->first, true, nullptr);
}
}
else if (sWorld.getConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK) && !isGameMaster())
@ -6980,13 +6986,13 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
if (zone->flags & AREA_FLAG_SANCTUARY) // in sanctuary
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
if (sWorld.IsFFAPvPRealm())
SetFFAPvP(false);
}
else
{
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE);
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY);
}
if (zone->flags & AREA_FLAG_CAPITAL) // in capital city
@ -7812,7 +7818,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
spell->m_currentBasePoints[EFFECT_INDEX_0] = learning_spell_id;
spell->prepare(&targets);
spell->SpellStart(&targets);
return;
}
@ -7843,7 +7849,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
spell->m_glyphIndex = glyphIndex; // glyph index
spell->prepare(&targets);
spell->SpellStart(&targets);
++count;
}
@ -7875,7 +7881,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
spell->m_glyphIndex = glyphIndex; // glyph index
spell->prepare(&targets);
spell->SpellStart(&targets);
++count;
}
@ -18354,6 +18360,10 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName());
rPlayer->GetSession()->SendPacket(&data);
// do not send confirmations, afk, dnd or system notifications for addon messages
if (language == LANG_ADDON)
return;
data.clear();
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid());
GetSession()->SendPacket(&data);
@ -18365,10 +18375,13 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv
}
// announce afk or dnd message
if (rPlayer->isAFK())
ChatHandler(this).PSendSysMessage(LANG_PLAYER_AFK, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
else if (rPlayer->isDND())
ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str());
if (rPlayer->isAFK() || rPlayer->isDND())
{
const ChatMsg msgtype = rPlayer->isAFK() ? CHAT_MSG_AFK : CHAT_MSG_DND;
data.clear();
ChatHandler::BuildChatPacket(data, msgtype, rPlayer->autoReplyMsg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, rPlayer->GetObjectGuid());
GetSession()->SendPacket(&data);
}
}
void Player::PetSpellInitialize()
@ -20780,8 +20793,8 @@ bool Player::IsSpellFitByClassAndRace(uint32 spell_id, uint32* pReqlevel /*= NUL
if (abilityEntry->classmask && (abilityEntry->classmask & classmask) == 0)
continue;
SkillRaceClassInfoMapBounds bounds = sSpellMgr.GetSkillRaceClassInfoMapBounds(abilityEntry->skillId);
for (SkillRaceClassInfoMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
SkillRaceClassInfoMapBounds raceBounds = sSpellMgr.GetSkillRaceClassInfoMapBounds(abilityEntry->skillId);
for (SkillRaceClassInfoMap::const_iterator itr = raceBounds.first; itr != raceBounds.second; ++itr)
{
SkillRaceClassInfoEntry const* skillRCEntry = itr->second;
if ((skillRCEntry->raceMask & racemask) && (skillRCEntry->classMask & classmask))

View file

@ -452,7 +452,7 @@ enum PlayerFlags
PLAYER_FLAGS_GM = 0x00000008,
PLAYER_FLAGS_GHOST = 0x00000010,
PLAYER_FLAGS_RESTING = 0x00000020,
PLAYER_FLAGS_UNK7 = 0x00000040, // admin?
PLAYER_FLAGS_SANCTUARY = 0x00000040,
PLAYER_FLAGS_UNK8 = 0x00000080, // pre-3.0.3 PLAYER_FLAGS_FFA_PVP flag for FFA PVP state
PLAYER_FLAGS_CONTESTED_PVP = 0x00000100, // Player has been involved in a PvP combat and will be attacked by contested guards
PLAYER_FLAGS_IN_PVP = 0x00000200,
@ -2574,6 +2574,10 @@ class Player : public Unit
void SetTitle(CharTitlesEntry const* title, bool lost = false);
bool canSeeSpellClickOn(Creature const* creature) const;
// function used for raise ally spell
bool IsGhouled() const { return m_isGhouled; }
void SetGhouled(bool enable) { m_isGhouled = enable; }
protected:
uint32 m_contestedPvPTimer;
@ -2899,6 +2903,8 @@ class Player : public Unit
uint32 m_timeSyncServer;
uint32 m_cachedGS;
bool m_isGhouled;
};
void AddItemsSetItem(Player* player, Item* item);

View file

@ -809,7 +809,9 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
switch (spellproto->Id)
{
case 13139: // net-o-matic special effect
case 23182: // Mark of Frost
case 23445: // evil twin
case 25040: // Mark of Nature
case 35679: // Protectorate Demolitionist
case 37695: // Stanky
case 38637: // Nether Exhaustion (red)
@ -931,6 +933,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
{
case 36897: // Transporter Malfunction (race mutation to horde)
case 36899: // Transporter Malfunction (race mutation to alliance)
case 37097: // Crate Disguise
return false;
}
break;
@ -940,6 +943,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
{
case 802: // Mutate Bug, wrongly negative by target modes
case 38449: // Blessing of the Tides
case 50312: // Unholy Frenzy
return true;
case 36900: // Soul Split: Evil!
case 36901: // Soul Split: Good
@ -1058,16 +1062,6 @@ bool IsSingleTargetSpell(SpellEntry const* spellInfo)
{
// all other single target spells have if it has AttributesEx5
if (spellInfo->HasAttribute(SPELL_ATTR_EX5_SINGLE_TARGET_SPELL))
return true;
// TODO - need found Judgements rule
switch (GetSpellSpecific(spellInfo->Id))
{
case SPELL_JUDGEMENT:
return true;
default:
break;
}
// single target triggered spell.
// Not real client side single target spell, but it' not triggered until prev. aura expired.
@ -1086,12 +1080,10 @@ bool IsSingleTargetSpells(SpellEntry const* spellInfo1, SpellEntry const* spellI
spellInfo1->SpellIconID == spellInfo2->SpellIconID )
return true;
// TODO - need found Judgements rule
SpellSpecific spec1 = GetSpellSpecific(spellInfo1->Id);
// spell with single target specific types
switch (spec1)
{
case SPELL_JUDGEMENT:
case SPELL_MAGE_POLYMORPH:
if (GetSpellSpecific(spellInfo2->Id) == spec1)
return true;

View file

@ -669,9 +669,13 @@ void Unit::Update(uint32 update_diff, uint32 p_time)
// update abilities available only for fraction of time
UpdateReactives(update_diff);
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f);
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f);
if (IsAlive())
{
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth() * 0.35f);
ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth() * 0.75f);
}
UpdateSplineMovement(p_time);
i_motionMaster.UpdateMotion(p_time);
}
@ -734,7 +738,7 @@ bool Unit::UpdateMeleeAttackingState()
player->SwingErrorMsg(swingError);
}
return swingError == 0;
return swingError;
}
bool Unit::haveOffhandWeapon() const
@ -1089,6 +1093,8 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
player_tap->SendDirectMessage(&data);
}
else if (GetTypeId() == TYPEID_UNIT && this != pVictim)
ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
// Reward player, his pets, and group/raid members
if (player_tap != pVictim)
@ -1538,7 +1544,7 @@ void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered,
targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ());
spell->m_CastItem = castItem;
spell->prepare(&targets, triggeredByAura);
spell->SpellStart(&targets, triggeredByAura);
}
void Unit::CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, Aura* triggeredByAura, ObjectGuid originalCaster, SpellEntry const* triggeredBy)
@ -1600,7 +1606,7 @@ void Unit::CastCustomSpell(Unit* Victim, SpellEntry const* spellInfo, int32 cons
if (WorldObject* caster = spell->GetCastingObject())
{ targets.setSource(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); }
spell->prepare(&targets, triggeredByAura);
spell->SpellStart(&targets, triggeredByAura);
}
// used for scripting
@ -1657,7 +1663,7 @@ void Unit::CastSpell(float x, float y, float z, SpellEntry const* spellInfo, boo
{ targets.setDestination(x, y, z); }
spell->m_CastItem = castItem;
spell->prepare(&targets, triggeredByAura);
spell->SpellStart(&targets, triggeredByAura);
}
// Obsolete func need remove, here only for comotability vs another patches
@ -1897,6 +1903,11 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, Weapo
damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
// Crit bonus calc
damageInfo->damage += damageInfo->damage;
// Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first
const int32 bonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL);
damageInfo->damage += int32((damageInfo->damage) * float(bonus / 100.0f));
int32 mod = 0;
// Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
if (damageInfo->attackType == RANGED_ATTACK)
@ -1904,8 +1915,6 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, Weapo
else
mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, SPELL_SCHOOL_MASK_NORMAL);
if (mod != 0)
damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod) / 100.0f));
@ -2917,6 +2926,8 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
return;
}
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK);
// attack can be redirected to another target
pVictim = SelectMagnetTarget(pVictim);
@ -2934,6 +2945,22 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext
else
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
if (Unit* owner = GetOwner())
if (owner->GetTypeId() == TYPEID_UNIT)
{
owner->SetInCombatWith(pVictim);
owner->AddThreat(pVictim);
pVictim->SetInCombatWith(owner);
}
for (GuidSet::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
if (Unit* pet = (Unit*)GetMap()->GetPet(*itr))
{
pet->SetInCombatWith(pVictim);
pet->AddThreat(pVictim);
pVictim->SetInCombatWith(pet);
}
// if damage pVictim call AI reaction
pVictim->AttackedBy(this);
@ -3101,25 +3128,19 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT
}
// mobs can score crushing blows if they're 4 or more levels above victim
if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 &&
// can be from by creature (if can) or from controlled player that considered as creature
((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() &&
!(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) ||
GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid()))
// having defense above your maximum (from items, talents etc.) has no effect
// mob's level * 5 - player's current defense skill - add 2% chance per lacking skill point, min. is 20%
if ((getLevel() - 4) >= pVictim->getLevel() && !IsNonMeleeSpellCasted(false) /* It should have been !spellCasted but wrath doesn't have that? */
&& roll < (tmp = (((attackerMaxSkillValueForLevel - tmp) * 200) - 2000)))
{
// when their weapon skill is 15 or more above victim's defense skill
tmp = victimMaxSkillValueForLevel;
// tmp = mob's level * 5 - player's current defense skill
tmp = attackerMaxSkillValueForLevel - tmp;
if (tmp >= 15)
uint32 typeId = GetTypeId();
/* It should have been !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH) but wrath doesn't have that? */
if ((typeId == TYPEID_UNIT && !(GetOwnerGuid() && GetOwner()->GetTypeId() == TYPEID_PLAYER)
&& !(static_cast<Creature const*>(this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH))
|| (typeId == TYPEID_PLAYER && GetCharmerGuid() && GetCharmer()->GetTypeId() == TYPEID_UNIT))
{
// add 2% chance per lacking skill point, min. is 15%
tmp = tmp * 200 - 1500;
if (roll < (sum += tmp))
{
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum - tmp, sum);
return MELEE_HIT_CRUSHING;
}
DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "RollMeleeOutcomeAgainst: CRUSHING %d)", tmp);
return MELEE_HIT_CRUSHING;
}
}
@ -3848,7 +3869,7 @@ void Unit::_UpdateAutoRepeatSpell()
// we want to shoot
Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true);
spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
spell->SpellStart(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
// all went good, reset attack
resetAttackTimer(RANGED_ATTACK);
@ -4557,31 +4578,9 @@ bool Unit::RemoveNoStackAurasDueToAuraHolder(SpellAuraHolder* holder)
continue;
}
if (i_spellId == spellId) continue;
bool is_triggered_by_spell = false;
// prevent triggering aura of removing aura that triggered it
for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* iSpellEffect = i_spellProto->GetSpellEffect(SpellEffectIndex(j));
if(!iSpellEffect)
continue;
if (iSpellEffect->EffectTriggerSpell == spellId)
is_triggered_by_spell = true;
}
// prevent triggered aura of removing aura that triggering it (triggered effect early some aura of parent spell
for(int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* spellEffect = i_spellProto->GetSpellEffect(SpellEffectIndex(j));
if(!spellEffect)
continue;
if (spellEffect->EffectTriggerSpell == i_spellId)
is_triggered_by_spell = true;
}
if (is_triggered_by_spell)
if (((*i).second->GetTriggeredBy() && (*i).second->GetTriggeredBy()->Id == spellId)
|| (holder->GetTriggeredBy() && holder->GetTriggeredBy()->Id == i_spellId))
continue;
SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
@ -4982,6 +4981,46 @@ void Unit::RemoveAurasWithAttribute(uint32 flags)
}
}
void Unit::RemoveAurasOnCast(SpellEntry const* castedSpellEntry)
{
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
{
SpellAuraHolder* holder = iter->second;
SpellEntry const* spellEntry = holder->GetSpellProto();
bool removeThisHolder = false;
if (spellEntry->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_UNK2)
{
if (castedSpellEntry->HasAttribute(SPELL_ATTR_EX_NOT_BREAK_STEALTH))
{
bool foundStealth = false;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura* aura = holder->m_auras[i])
{
if (aura->GetModifier()->m_auraname == SPELL_AURA_MOD_STEALTH)
{
foundStealth = true;
break;
}
}
}
removeThisHolder = !foundStealth;
}
else
removeThisHolder = true;
}
if (removeThisHolder)
{
RemoveSpellAuraHolder(iter->second);
iter = m_spellAuraHolders.begin();
}
else
++iter;
}
}
void Unit::RemoveNotOwnTrackedTargetAuras(uint32 newPhase)
{
// tracked aura targets from other casters are removed if the phase does no more fit
@ -5882,7 +5921,7 @@ bool Unit::IsHostileTo(Unit const* unit) const
return false;
// Sanctuary
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
return false;
// PvP FFA state
@ -5994,7 +6033,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
return true;
// Sanctuary
if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE))
if (pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY))
return true;
// PvP FFA state
@ -6115,10 +6154,13 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
if (m_attacking == victim)
{
// switch to melee attack from ranged/magic
if (meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING))
if (meleeAttack)
{
addUnitState(UNIT_STAT_MELEE_ATTACKING);
SendMeleeAttackStart(victim);
if (!hasUnitState(UNIT_STAT_MELEE_ATTACKING))
{
addUnitState(UNIT_STAT_MELEE_ATTACKING);
SendMeleeAttackStart(victim);
}
return true;
}
return false;
@ -7237,6 +7279,14 @@ bool Unit::IsSpellCrit(Unit* pVictim, SpellEntry const* spellProto, SpellSchoolM
if (spellProto->HasAttribute(SPELL_ATTR_EX2_CANT_CRIT))
return false;
// Creatures do not crit with their spells or abilities, unless it is owned by a player (pet, totem, etc)
if (GetTypeId() != TYPEID_PLAYER)
{
Unit* owner = GetOwner();
if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
return false;
}
float crit_chance = 0.0f;
switch(spellProto->GetDmgClass())
{
@ -7420,6 +7470,10 @@ uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damag
break;
}
// Apply SPELL_AURA_MOD_CRIT_DAMAGE_BONUS modifier first
const int32 pctBonus = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto));
crit_bonus += int32((damage + crit_bonus) * float(pctBonus / 100.0f));
// adds additional damage to crit_bonus (from talents)
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
@ -7438,8 +7492,6 @@ uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damag
else
critPctDamageMod += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE, GetSpellSchoolMask(spellProto));
critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto));
if (critPctDamageMod != 0)
crit_bonus = int32(crit_bonus * float((100.0f + critPctDamageMod) / 100.0f));
@ -7535,9 +7587,9 @@ uint32 Unit::SpellHealingBonusDone(Unit* pVictim, SpellEntry const* spellProto,
int ownHotCount = 0; // counted HoT types amount, not stacks
Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID &&
(*i)->GetCasterGuid() == GetObjectGuid())
for (Unit::AuraList::const_iterator itr = RejorRegr.begin(); itr != RejorRegr.end(); ++itr)
if ((*itr)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DRUID &&
(*itr)->GetCasterGuid() == GetObjectGuid())
++ownHotCount;
if (ownHotCount)
@ -8274,13 +8326,11 @@ void Unit::Mount(uint32 mount, uint32 spellId)
// Normal case (Unsummon only permanent pet)
else if (Pet* pet = GetPet())
{
if (pet->IsPermanentPetFor((Player*)this) && !((Player*)this)->InArena() &&
sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT))
{
if (pet->isControlled() && (!(pet->isTemporarySummoned() || ((Player*)this)->InArena())
|| sWorld.getConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT)))
((Player*)this)->UnsummonPetTemporaryIfAny();
}
else
pet->ApplyModeFlags(PET_MODE_DISABLE_ACTIONS, true);
pet->SetModeFlags(PET_MODE_DISABLE_ACTIONS);
}
}

View file

@ -79,9 +79,9 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water
AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water
AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing
AURA_INTERRUPT_FLAG_UNK10 = 0x00000400, // 10
AURA_INTERRUPT_FLAG_UNK11 = 0x00000800, // 11
AURA_INTERRUPT_FLAG_UNK12 = 0x00001000, // 12 removed by attack?
AURA_INTERRUPT_FLAG_TALK = 0x00000400, // 10 talk to npc / loot? action on creature
AURA_INTERRUPT_FLAG_USE = 0x00000800, // 11 mine/use/open action on gameobject
AURA_INTERRUPT_FLAG_MELEE_ATTACK = 0x00001000, // 12 removed by attack
AURA_INTERRUPT_FLAG_UNK13 = 0x00002000, // 13
AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14
AURA_INTERRUPT_FLAG_UNK15 = 0x00008000, // 15 removed by casting a spell?
@ -3140,6 +3140,9 @@ class Unit : public WorldObject
* \todo Are linked and flying auras really not removed on evade?
*/
void RemoveAllAurasOnEvade();
// remove specific aura on cast
void RemoveAurasOnCast(SpellEntry const* castedSpellEntry);
// removing specific aura FROM stack by diff reasons and selections
void RemoveAuraHolderFromStack(uint32 spellId, uint32 stackAmount = 1, ObjectGuid casterGuid = ObjectGuid(), AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);

View file

@ -321,6 +321,9 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle)
UnBoardPassenger(passenger); // Use TransportBase to remove the passenger from storage list
// Remove passenger modifications
RemoveSeatMods(passenger, seatEntry->m_flags);
if (!changeVehicle) // Send expected unboarding packages
{
// Update movementInfo
@ -354,9 +357,6 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle)
}
}
// Remove passenger modifications
RemoveSeatMods(passenger, seatEntry->m_flags);
// Some creature vehicles get despawned after passenger unboarding
if (m_owner->GetTypeId() == TYPEID_UNIT)
{

View file

@ -136,8 +136,8 @@ void OutdoorPvPMgr::HandlePlayerEnterZone(Player* player, uint32 zoneId)
{
if (OutdoorPvP* script = GetScript(zoneId))
script->HandlePlayerEnterZone(player, true);
else if (OutdoorPvP* script = GetScriptOfAffectedZone(zoneId))
script->HandlePlayerEnterZone(player, false);
else if (OutdoorPvP* affectedScript = GetScriptOfAffectedZone(zoneId))
affectedScript->HandlePlayerEnterZone(player, false);
}
/**
@ -151,8 +151,8 @@ void OutdoorPvPMgr::HandlePlayerLeaveZone(Player* player, uint32 zoneId)
// teleport: called once from Player::CleanupsBeforeDelete, once from Player::UpdateZone
if (OutdoorPvP* script = GetScript(zoneId))
script->HandlePlayerLeaveZone(player, true);
else if (OutdoorPvP* script = GetScriptOfAffectedZone(zoneId))
script->HandlePlayerLeaveZone(player, false);
else if (OutdoorPvP* affectedScript = GetScriptOfAffectedZone(zoneId))
affectedScript->HandlePlayerLeaveZone(player, false);
}
void OutdoorPvPMgr::Update(uint32 diff)

View file

@ -107,6 +107,9 @@ void HostileReference::fireStatusChanged(ThreatRefStatusChangeEvent& pThreatRefS
void HostileReference::addThreat(float pMod)
{
if (pMod + iThreat < 0)
pMod = -iThreat;
iThreat += pMod;
// the threat is changed. Source and target unit have to be availabe
// if the link was cut before relink it again
@ -495,12 +498,16 @@ Unit* ThreatManager::getHostileTarget()
float ThreatManager::getThreat(Unit* pVictim, bool pAlsoSearchOfflineList)
{
if (!pVictim)
return 0.0f;
float threat = 0.0f;
HostileReference* ref = iThreatContainer.getReferenceByTarget(pVictim);
if (!ref && pAlsoSearchOfflineList)
ref = iThreatOfflineContainer.getReferenceByTarget(pVictim);
if (ref)
if (HostileReference* ref = iThreatContainer.getReferenceByTarget(pVictim))
threat = ref->getThreat();
else if (pAlsoSearchOfflineList)
threat = iThreatOfflineContainer.getReferenceByTarget(pVictim)->getThreat();
return threat;
}

View file

@ -531,7 +531,7 @@ enum SpellCastTargetFlags
TARGET_FLAG_OBJECT = 0x00000800, // pguid, 2 spells
TARGET_FLAG_TRADE_ITEM = 0x00001000, // pguid, 0 spells
TARGET_FLAG_STRING = 0x00002000, // string, 0 spells
TARGET_FLAG_UNK1 = 0x00004000, // 199 spells, opening object/lock
TARGET_FLAG_GAMEOBJECT_ITEM = 0x00004000, // 199 spells, opening object/lock
TARGET_FLAG_CORPSE = 0x00008000, // pguid, resurrection spells
TARGET_FLAG_UNK2 = 0x00010000, // pguid, not used in any spells as of 3.0.3 (can be set dynamically)
TARGET_FLAG_GLYPH = 0x00020000, // used in glyph spells

View file

@ -279,7 +279,7 @@ enum SpellAttributes
SPELL_ATTR_TRADESPELL = 0x00000020,// 5 trade spells, will be added by client to a sublist of profession spell
SPELL_ATTR_PASSIVE = 0x00000040,// 6 Passive spell
SPELL_ATTR_UNK7 = 0x00000080,// 7 can't be linked in chat?
SPELL_ATTR_UNK8 = 0x00000100,// 8 hide created item in tooltip (for effect=24)
SPELL_ATTR_UNK8 = 0x00000100,// 8
SPELL_ATTR_UNK9 = 0x00000200,// 9
SPELL_ATTR_ON_NEXT_SWING_2 = 0x00000400,// 10 on next swing 2
SPELL_ATTR_UNK11 = 0x00000800,// 11
@ -422,7 +422,7 @@ enum SpellAttributesEx4
SPELL_ATTR_EX4_UNK4 = 0x00000010,// 4 This will no longer cause guards to attack on use??
SPELL_ATTR_EX4_UNK5 = 0x00000020,// 5
SPELL_ATTR_EX4_NOT_STEALABLE = 0x00000040,// 6 although such auras might be dispellable, they cannot be stolen
SPELL_ATTR_EX4_UNK7 = 0x00000080,// 7
SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING = 0x00000080,// 7 In theory, can use this spell while another is channeled/cast/autocast
SPELL_ATTR_EX4_STACK_DOT_MODIFIER = 0x00000100,// 8 no effect on non DoTs?
SPELL_ATTR_EX4_UNK9 = 0x00000200,// 9
SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST = 0x00000400,// 10 Rogue Shiv have this flag
@ -495,7 +495,7 @@ enum SpellAttributesEx6
SPELL_ATTR_EX6_UNK5 = 0x00000020,// 5
SPELL_ATTR_EX6_UNK6 = 0x00000040,// 6
SPELL_ATTR_EX6_UNK7 = 0x00000080,// 7
SPELL_ATTR_EX6_UNK8 = 0x00000100,// 8
SPELL_ATTR_EX6_IGNORE_CC_TARGETS = 0x00000100,// 8 ignores target with cc effects
SPELL_ATTR_EX6_UNK9 = 0x00000200,// 9
SPELL_ATTR_EX6_UNK10 = 0x00000400,// 10
SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE = 0x00000800,// 11 not usable in raid instance

View file

@ -1016,8 +1016,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
{
uint32 counter = 0;
for (QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr != GetPlayer()->getQuestStatusMap().end(); ++itr)
if (itr->second.m_rewarded)
for (QuestStatusMap::const_iterator questItr = GetPlayer()->getQuestStatusMap().begin(); questItr != GetPlayer()->getQuestStatusMap().end(); ++questItr)
if (questItr->second.m_rewarded)
++counter;
change = counter;
progressType = PROGRESS_HIGHEST;
@ -1030,10 +1030,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
continue;
uint32 counter = 0;
for (QuestStatusMap::const_iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr != GetPlayer()->getQuestStatusMap().end(); ++itr)
for (QuestStatusMap::const_iterator questItr = GetPlayer()->getQuestStatusMap().begin(); questItr != GetPlayer()->getQuestStatusMap().end(); ++questItr)
{
Quest const* quest = sObjectMgr.GetQuestTemplate(itr->first);
if (itr->second.m_rewarded && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
Quest const* quest = sObjectMgr.GetQuestTemplate(questItr->first);
if (questItr->second.m_rewarded && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->complete_quests_in_zone.zoneID)
++counter;
}
change = counter;

View file

@ -682,7 +682,7 @@ class ChatHandler
std::string ExtractPlayerNameFromLink(char** text);
bool ExtractPlayerTarget(char** args, Player** player, ObjectGuid* player_guid = NULL, std::string* player_name = NULL);
// select by arg (name/link) or in-game selection online/offline player
std::string petLink(std::string const& name) const { return m_session ? "|cffffffff|Hpet:" + name + "|h[" + name + "]|h|r" : name; }
std::string playerLink(std::string const& name) const { return m_session ? "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r" : name; }
std::string GetNameLink(Player* chr) const;

View file

@ -362,7 +362,9 @@ Map::Add(T* obj)
DEBUG_LOG("%s enters grid[%u,%u]", obj->GetGuidStr().c_str(), cell.GridX(), cell.GridY());
obj->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY()));
obj->SetItsNewObject(true);
UpdateObjectVisibility(obj, cell, p);
obj->SetItsNewObject(false);
}
void Map::MessageBroadcast(Player const* player, WorldPacket* msg, bool to_self)

View file

@ -263,7 +263,7 @@ void WorldSession::HandlePetAction(WorldPacket& recv_data)
}
}
spell->prepare(&(spell->m_targets));
spell->SpellStart(&(spell->m_targets));
}
else
{
@ -704,7 +704,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
pet->SendPetAIReaction();
}
spell->prepare(&(spell->m_targets), triggeredByAura);
spell->SpellStart(&(spell->m_targets), triggeredByAura);
}
else
{

View file

@ -243,8 +243,8 @@ void SpellCastTargets::read(ByteBuffer& data, Unit* caster)
// TARGET_FLAG_UNK2 is used for non-combat pets, maybe other?
if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNK2))
data >> m_unitTargetGUID.ReadAsPacked();
if (m_targetMask & (TARGET_FLAG_OBJECT))
if (m_targetMask & (TARGET_FLAG_OBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
data >> m_GOTargetGUID.ReadAsPacked();
if ((m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM)) && caster->GetTypeId() == TYPEID_PLAYER)
@ -416,7 +416,7 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
m_currentBasePoints[i] = m_spellInfo->CalculateSimpleValue(SpellEffectIndex(i));
m_spellState = SPELL_STATE_PREPARING;
m_spellState = SPELL_STATE_CREATED;
m_castPositionX = m_castPositionY = m_castPositionZ = 0;
m_TriggerSpells.clear();
@ -1854,6 +1854,13 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
++next;
continue;
}
if (!prev->IsWithinLOSInMap(*next)
|| (m_spellInfo->HasAttribute(SPELL_ATTR_EX6_IGNORE_CC_TARGETS) && !(*next)->CanFreeMove()))
{
++next;
continue;
}
prev = *next;
targetUnitMap.push_back(prev);
tempTargetUnitMap.erase(next);
@ -2986,8 +2993,13 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
}
// remove caster from the list if required by attribute
if (targetMode != TARGET_SELF && targetMode != TARGET_SELF2 && m_spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_TARGET_SELF))
targetUnitMap.remove(m_caster);
if (m_spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_TARGET_SELF))
{
const SpellEffectEntry* spellEffect = m_spellInfo->GetSpellEffect(effIndex);
if (targetMode != TARGET_SELF && targetMode != TARGET_SELF2 && (spellEffect && spellEffect->Effect != SPELL_EFFECT_SUMMON))
targetUnitMap.remove(m_caster);
}
if (unMaxTargets && targetUnitMap.size() > unMaxTargets)
{
@ -3064,34 +3076,11 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
}
}
void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
SpellCastResult Spell::PreCastCheck(Aura* triggeredByAura /*= nullptr*/)
{
m_targets = *targets;
m_spellState = SPELL_STATE_PREPARING;
m_castPositionX = m_caster->GetPositionX();
m_castPositionY = m_caster->GetPositionY();
m_castPositionZ = m_caster->GetPositionZ();
m_castOrientation = m_caster->GetOrientation();
if (triggeredByAura)
m_triggeredByAuraSpell = triggeredByAura->GetSpellProto();
// create and add update event for this spell
SpellEvent* Event = new SpellEvent(this);
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
// Prevent casting at cast another spell (ServerSide check)
if (m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count)
{
SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
finish(false);
return;
}
// Fill cost data
m_powerCost = CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem);
if (m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count && !m_spellInfo->HasAttribute(SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING))
return SPELL_FAILED_SPELL_IN_PROGRESS;
SpellCastResult result = CheckCast(true);
if (result != SPELL_CAST_OK && !IsAutoRepeat()) // always cast autorepeat dummy for triggering
@ -3101,10 +3090,49 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
SendChannelUpdate(0);
triggeredByAura->GetHolder()->SetAuraDuration(0);
}
return result;
}
return SPELL_CAST_OK;
}
void Spell::SpellStart(SpellCastTargets const* targets, Aura* triggeredByAura)
{
m_spellState = SPELL_STATE_STARTING;
m_targets = *targets;
if (m_CastItem)
m_CastItemGuid = m_CastItem->GetObjectGuid();
m_castPositionX = m_caster->GetPositionX();
m_castPositionY = m_caster->GetPositionY();
m_castPositionZ = m_caster->GetPositionZ();
m_castOrientation = m_caster->GetOrientation();
if (triggeredByAura)
m_triggeredByAuraSpell = triggeredByAura->GetSpellProto();
// create and add update event for this spell
SpellEvent* Event = new SpellEvent(this);
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
// Fill cost data
m_powerCost = m_IsTriggeredSpell ? 0 : CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem);
SpellCastResult result = PreCastCheck();
if (result != SPELL_CAST_OK)
{
SendCastResult(result);
finish(false);
return;
}
else
Prepare();
}
void Spell::Prepare()
{
m_spellState = SPELL_STATE_PREPARING;
// Prepare data for triggers
prepareDataForTriggerSystem();
@ -3116,13 +3144,8 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
// set timer base at cast time
ReSetTimer();
// stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
if (!m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo))
{
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
m_caster->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
}
if (!m_IsTriggeredSpell)
m_caster->RemoveAurasOnCast(m_spellInfo);
// add non-triggered (with cast time and without)
if (!m_IsTriggeredSpell)
@ -3134,6 +3157,10 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
SendSpellStart();
TriggerGlobalCooldown();
// Execute instant spells immediate
if (m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsChanneledSpell(m_spellInfo))
cast();
}
// execute triggered without cast time explicitly in call point
else if (m_timer == 0)
@ -5087,7 +5114,7 @@ void Spell::CastTriggerSpells()
for (SpellInfoList::const_iterator si = m_TriggerSpells.begin(); si != m_TriggerSpells.end(); ++si)
{
Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID);
spell->prepare(&m_targets); // use original spell original targets
spell->SpellStart(&m_targets); // use original spell original targets
}
}
@ -6072,23 +6099,43 @@ SpellCastResult Spell::CheckCast(bool strict)
}
case SPELL_EFFECT_SUMMON_PET:
{
if (m_caster->GetPetGuid()) // let warlock do a replacement summon
if (m_caster->GetCharmGuid())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
uint32 plClass = m_caster->getClass();
if (plClass == CLASS_HUNTER)
{
Pet* pet = ((Player*)m_caster)->GetPet();
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARLOCK)
if (Creature* pet = m_caster->GetPet())
{
if (strict) // Summoning Disorientation, trigger pet stun (cast by pet so it doesn't attack player)
pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetObjectGuid());
if (!pet->IsAlive() || pet->IsDead()) // this one will not play along; tried and retried countless times....
return SPELL_FAILED_TARGETS_DEAD;
else
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
}
else
{
Pet* dbPet = new Pet;
if (dbPet->LoadPetFromDB((Player*)m_caster, 0))
return SPELL_CAST_OK; // still returns an error to the player, so this error must come from somewhere else...
else
{
delete dbPet;
return SPELL_FAILED_NO_PET;
}
}
}
else if (m_caster->GetPetGuid())
{
if (plClass == CLASS_WARLOCK) // let warlock do a replacement summon
{
if (strict) // Summoning Disorientation, trigger pet stun (cast by pet so it doesn't attack player)
if (Pet* pet = ((Player*)m_caster)->GetPet())
pet->CastSpell(pet, 32752, true, nullptr, nullptr, pet->GetObjectGuid());
}
else
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
}
if (m_caster->GetCharmGuid())
return SPELL_FAILED_ALREADY_HAVE_CHARM;
break;
}
case SPELL_EFFECT_SUMMON_PLAYER:
@ -6438,16 +6485,21 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
if (!m_caster->IsAlive())
return SPELL_FAILED_CASTER_DEAD;
if (m_caster->IsNonMeleeSpellCasted(false)) // prevent spellcast interruption by another spellcast
if (m_caster->IsNonMeleeSpellCasted(false) && !m_spellInfo->HasAttribute(SPELL_ATTR_EX4_CAN_CAST_WHILE_CASTING)) // prevent spellcast interruption by another spellcast
return SPELL_FAILED_SPELL_IN_PROGRESS;
if (m_caster->IsInCombat() && IsNonCombatSpell(m_spellInfo))
return SPELL_FAILED_AFFECTING_COMBAT;
if (m_caster->GetTypeId() == TYPEID_UNIT && (((Creature*)m_caster)->IsPet() || m_caster->IsCharmed()))
{
// dead owner (pets still alive when owners ressed?)
if (m_caster->GetCharmerOrOwner() && !m_caster->GetCharmerOrOwner()->IsAlive())
return SPELL_FAILED_CASTER_DEAD;
// dead owner (currently only ghouled players can have alive pet casting)
Unit* charmer = m_caster->GetCharmerOrOwner();
if (charmer)
{
Player* pCharmer = charmer->GetTypeId() == TYPEID_PLAYER ? static_cast<Player*>(charmer) : nullptr;
if (!charmer->IsAlive() && (!pCharmer || !pCharmer->IsGhouled()))
return SPELL_FAILED_CASTER_DEAD;
}
if (!target && m_targets.getUnitTarget())
target = m_targets.getUnitTarget();

View file

@ -390,7 +390,7 @@ class Spell
Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid originalCasterGUID = ObjectGuid(), SpellEntry const* triggeredBy = NULL);
~Spell();
void prepare(SpellCastTargets const* targets, Aura* triggeredByAura = NULL);
void SpellStart(SpellCastTargets const* targets, Aura* triggeredByAura = nullptr);
void cancel();
@ -537,6 +537,9 @@ class Spell
bool IgnoreItemRequirements() const; // some item use spells have unexpected reagent data
void UpdateOriginalCasterPointer();
SpellCastResult PreCastCheck(Aura* triggeredByAura = nullptr);
void Prepare();
Unit* m_caster;
ObjectGuid m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection

View file

@ -611,9 +611,9 @@ Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* curr
return new Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
}
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem)
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem /*= nullptr*/, SpellEntry const* triggeredBy /*= nullptr*/)
{
return new SpellAuraHolder(spellproto, target, caster, castItem);
return new SpellAuraHolder(spellproto, target, caster, castItem, triggeredBy);
}
void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
@ -4670,15 +4670,15 @@ void Aura::HandleAuraModStun(bool apply, bool Real)
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
target->CastStop(target->GetObjectGuid() == GetCasterGuid() ? GetId() : 0);
// Creature specific
if (target->GetTypeId() != TYPEID_PLAYER)
{ target->StopMoving(); }
else
Unit* charmer = target->GetCharmer();
if (target->GetTypeId() == TYPEID_PLAYER || (charmer && charmer->GetTypeId() == TYPEID_PLAYER))
{
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
target->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client
target->SetRoot(true);
}
else
target->StopMoving();
// Summon the Naj'entus Spine GameObject on target if spell is Impaling Spine
if (GetId() == 39837)
@ -7592,9 +7592,12 @@ void Aura::PeriodicTick()
if (Spell* spell = pCaster->GetCurrentSpell(CurrentSpellTypes(i)))
if (spell->m_spellInfo->Id == GetId())
{ spell->cancel(); }
if (Player* modOwner = pCaster->GetSpellModOwner())
{ modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier); }
{
modOwner->ApplySpellMod(GetId(), SPELLMOD_ALL_EFFECTS, new_damage);
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier);
}
int32 heal = pCaster->SpellHealingBonusTaken(pCaster, spellProto, int32(new_damage * multiplier), DOT, GetStackAmount());
@ -7602,6 +7605,9 @@ void Aura::PeriodicTick()
pCaster->CalculateHealAbsorb(heal, &absorbHeal);
int32 gain = pCaster->DealHeal(pCaster, heal - absorbHeal, spellProto, false, absorbHeal);
// Health Leech effects do not generate healing aggro
if (m_modifier.m_auraname == SPELL_AURA_PERIODIC_LEECH)
break;
pCaster->getHostileRefManager().threatAssist(pCaster, gain * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
break;
}
@ -7802,9 +7808,9 @@ void Aura::PeriodicTick()
pdamage = target->GetMaxPower(POWER_MANA) * 5 / 100;
drain_amount = target->GetPower(POWER_MANA) > pdamage ? pdamage : target->GetPower(POWER_MANA);
target->ModifyPower(POWER_MANA, -drain_amount);
SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, 0.0f);
target->SendPeriodicAuraLog(&pInfo);
SpellPeriodicAuraLogInfo info(this, drain_amount, 0, 0, 0, 0.0f);
target->SendPeriodicAuraLog(&info);
}
// no break here
}
@ -9119,8 +9125,8 @@ bool Aura::HasMechanic(uint32 mechanic) const
return m_spellEffect->EffectMechanic == mechanic;
}
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem) :
m_spellProto(spellproto),
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem, SpellEntry const* triggeredBy) :
m_spellProto(spellproto), m_triggeredBy(triggeredBy),
m_target(target), m_castItemGuid(castItem ? castItem->GetObjectGuid() : ObjectGuid()),
m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1),
m_procCharges(0), m_stackAmount(1),

View file

@ -83,7 +83,7 @@ struct ReapplyAffectedPassiveAurasHelper;
class SpellAuraHolder
{
public:
SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem);
SpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem, SpellEntry const* triggeredBy);
Aura* m_auras[MAX_EFFECT_INDEX];
void AddAura(Aura* aura, SpellEffectIndex index);
@ -104,6 +104,7 @@ class SpellAuraHolder
bool ModStackAmount(int32 num); // return true if last charge dropped
Aura* GetAuraByEffectIndex(SpellEffectIndex index) const { return m_auras[index]; }
SpellEntry const* GetTriggeredBy() const { return m_triggeredBy; }
uint32 GetId() const { return m_spellProto->Id; }
SpellEntry const* GetSpellProto() const { return m_spellProto; }
@ -206,6 +207,7 @@ class SpellAuraHolder
ObjectGuid m_casterGuid;
ObjectGuid m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
time_t m_applyTime;
SpellEntry const* m_triggeredBy; // Spell responsible for this holder
uint8 m_auraSlot; // Aura slot on unit (for show in client)
uint8 m_auraFlags; // Aura info flag (for send data to client)
@ -578,5 +580,5 @@ class SingleEnemyTargetAura : public Aura
};
Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = NULL, Item* castItem = NULL);
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem = NULL);
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit* target, WorldObject* caster, Item* castItem = nullptr, SpellEntry const* triggeredBy = nullptr);
#endif

View file

@ -306,8 +306,8 @@ void Spell::EffectInstaKill(SpellEffectEntry const* /*effect*/)
data << unitTarget->GetObjectGuid(); // Victim GUID
data << uint32(m_spellInfo->Id);
m_caster->SendMessageToSet(&data, true);
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, m_spellInfo, false);
}
void Spell::EffectEnvironmentalDMG(SpellEffectEntry const* effect)
@ -1384,6 +1384,13 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
return;
}
case 32027: // Expedition Flare
{
// 32029 = Expedition Preserver | 32030 = Expedition Scout
m_caster->CastSpell(m_caster, (urand(0, 1) ? 32029 : 32030), true);
return;
}
case 32146: // Liquid Fire
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
@ -1609,7 +1616,7 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(m_caster, 42486, true);
// There is no known spell to kill the target
unitTarget->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
return;
}
case 42489: // Cast Ooze Zap When Energized
@ -5372,6 +5379,10 @@ void Spell::EffectApplyAreaAura(SpellEffectEntry const* effect)
void Spell::EffectSummonType(SpellEffectEntry const* effect)
{
// if this spell already have an aura applied cancel the summon
if (m_caster->HasAura(m_spellInfo->Id))
return;
uint32 prop_id = effect->EffectMiscValueB;
SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
if(!summon_prop)
@ -5563,8 +5574,8 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect)
if (!summonResult)
return; // No further handling required
for (CreatureSummonPositions::iterator itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
for (itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
{
MANGOS_ASSERT(itr->creature || itr != summonPositions.begin());
if (!itr->creature)
@ -5930,21 +5941,27 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
return false;
}
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();
if (m_caster->GetTypeId() == TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
// set timer for unsummon
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
// Summon in dest location
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
spawnCreature->Relocate(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation());
if (spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
{
// Summon in dest location
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
spawnCreature->Relocate(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation());
// set timer for unsummon
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
return true;
}
return false;
spawnCreature->setPetType(SUMMON_PET);
}
else
spawnCreature->setPetType(GUARDIAN_PET);
// Summon 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());
@ -5961,35 +5978,27 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
return false;
}
uint32 level = std::max(m_caster->getLevel() + effect->EffectMultipleValue, 1.0f);
spawnCreature->SetRespawnCoord(pos);
// set timer for unsummon
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
spawnCreature->SetPowerType(POWER_MANA);
spawnCreature->setFaction(m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
spawnCreature->InitStatsForLevel(level, m_caster);
spawnCreature->InitStatsForLevel(level);
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
spawnCreature->AIM_Initialize();
spawnCreature->InitPetCreateSpells();
spawnCreature->InitLevelupSpellsForLevel();
spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
// spawnCreature->SetName(""); // generated by client
map->Add((Creature*)spawnCreature);
spawnCreature->AIM_Initialize();
m_caster->SetPet(spawnCreature);
@ -5999,13 +6008,25 @@ bool Spell::DoSummonPet(SpellEffectEntry const* effect)
spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
((Player*)m_caster)->PetSpellInitialize();
}
else
{
// Notify Summoner
if (m_originalCaster && (m_originalCaster != m_caster)
&& (m_originalCaster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_originalCaster)->AI())
{
((Creature*)m_originalCaster)->AI()->JustSummoned(spawnCreature);
if (m_originalCaster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)spawnCreature)->AI()->AttackStart(m_originalCaster->getAttackerForHelper());
}
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_caster)->AI())
{
((Creature*)m_caster)->AI()->JustSummoned(spawnCreature);
if (m_caster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)spawnCreature)->AI()->AttackStart(m_caster->getAttackerForHelper());
}
}
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
((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;
return true;
}
bool Spell::DoSummonVehicle(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const * effect, uint32 /*level*/)
@ -6496,7 +6517,7 @@ void Spell::EffectEnchantItemTmp(SpellEffectEntry const* effect)
Spell* spell = new Spell(m_caster, spellInfo, true);
SpellCastTargets targets;
targets.setItemTarget(itemTarget);
spell->prepare(&targets);
spell->SpellStart(&targets);
return;
}
@ -11232,6 +11253,18 @@ void Spell::EffectTransmitted(SpellEffectEntry const* effect)
{
uint32 name_id = effect->EffectMiscValue;
switch (m_spellInfo->Id)
{
case 29886: // Create Soulwell
if (m_caster->HasAura(18692))
name_id = 183510;
else if (m_caster->HasAura(18693))
name_id = 183511;
break;
default:
break;
}
GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(name_id);
if (!goinfo)

View file

@ -433,7 +433,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
Spell* spell = new Spell(mover, spellInfo, triggeredByAura ? true : false, mover->GetObjectGuid(), triggeredByAura ? triggeredByAura->GetSpellProto() : NULL);
spell->m_cast_count = cast_count; // set count of casts
spell->m_glyphIndex = glyphIndex;
spell->prepare(&targets, triggeredByAura);
spell->SpellStart(&targets, triggeredByAura);
}
void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)

View file

@ -521,10 +521,10 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& recvPacket)
trader->ModifyMoney(my_trade->GetMoney());
if (my_spell)
my_spell->prepare(&my_targets);
my_spell->SpellStart(&my_targets);
if (his_spell)
his_spell->prepare(&his_targets);
his_spell->SpellStart(&his_targets);
// cleanup
clearAcceptTradeMode(my_trade, his_trade);

View file

@ -358,7 +358,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
newY = keyFrames[i].node->y + (keyFrames[i + 1].node->y - keyFrames[i].node->y) * d / keyFrames[i + 1].distFromPrev;
newZ = keyFrames[i].node->z + (keyFrames[i + 1].node->z - keyFrames[i].node->z) * d / keyFrames[i + 1].distFromPrev;
bool teleport = false;
teleport = false;
if (keyFrames[i].node->mapid != cM)
{
teleport = true;
@ -366,7 +366,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
}
// sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
WayPoint pos(keyFrames[i].node->mapid, newX, newY, newZ, teleport);
pos = WayPoint(keyFrames[i].node->mapid, newX, newY, newZ, teleport);
if (teleport)
m_WayPoints[t] = pos;
}
@ -412,7 +412,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32>& mapids)
cM = keyFrames[i + 1].node->mapid;
}
WayPoint pos(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
pos = WayPoint(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
keyFrames[i + 1].node->arrivalEventID, keyFrames[i + 1].node->departureEventID);
// sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);

View file

@ -3109,10 +3109,10 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
}
case 69023: // Mirrored Soul
{
int32 basepoints = (int32)(damage * 0.45f);
int32 basepoints2 = (int32)(damage * 0.45f);
if (Unit* caster = triggeredByAura->GetCaster())
// Actually this spell should be sent with SMSG_SPELL_START
CastCustomSpell(caster, 69034, &basepoints, nullptr, nullptr, true, nullptr, triggeredByAura, GetObjectGuid());
CastCustomSpell(caster, 69034, &basepoints2, nullptr, nullptr, true, nullptr, triggeredByAura, GetObjectGuid());
return SPELL_AURA_PROC_OK;
}
@ -3212,8 +3212,8 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_WARLOCK && (*i)->GetSpellProto()->SpellIconID == 113)
{
// basepoints of trigger spell stored in dummyeffect of spellProto
int32 basepoints = GetMaxPower(POWER_MANA) * (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2) / 100;
CastCustomSpell(this, 18371, &basepoints, nullptr, nullptr, true, castItem, triggeredByAura);
int32 basepoints2 = GetMaxPower(POWER_MANA) * (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2) / 100;
CastCustomSpell(this, 18371, &basepoints2, nullptr, nullptr, true, castItem, triggeredByAura);
break;
}
}

View file

@ -252,8 +252,6 @@ World::AddSession_(WorldSession* s)
// prevent decrease sessions count if session queued
if (RemoveQueuedSession(old->second))
{ decrease_session = false; }
// not remove replaced session form queue if listed
delete old->second;
}
}
@ -468,6 +466,7 @@ void World::LoadConfigSettings(bool reload)
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY, "Rate.Drop.Item.Legendary", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "Rate.Drop.Item.Artifact", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_QUEST, "Rate.Drop.Item.Quest", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY, "Rate.Drop.Currency", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT, "Rate.Drop.Currency.Amount", 1.0f);

View file

@ -263,6 +263,7 @@ enum eConfigFloatValues
CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY,
CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT,
CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED,
CONFIG_FLOAT_RATE_DROP_ITEM_QUEST,
CONFIG_FLOAT_RATE_DROP_MONEY,
CONFIG_FLOAT_RATE_DROP_CURRENCY,
CONFIG_FLOAT_RATE_DROP_CURRENCY_AMOUNT,

View file

@ -1272,6 +1272,7 @@ Visibility.AIRelocationNotifyDelay = 1000
# Rate.Drop.Item.Legendary
# Rate.Drop.Item.Artifact
# Rate.Drop.Item.Referenced
# Rate.Drop.Item.Quest
# Rate.Drop.Money
# Rate.Drop.Currency
# Drop rates (items by quality, money and currency drop chance)
@ -1423,6 +1424,7 @@ Rate.Drop.Item.Epic = 1
Rate.Drop.Item.Legendary = 1
Rate.Drop.Item.Artifact = 1
Rate.Drop.Item.Referenced = 1
Rate.Drop.Item.Quest = 1
Rate.Drop.Money = 1
Rate.Drop.Currency = 1
Rate.Drop.Currency.Amount = 1