diff --git a/src/game/BattleGround/BattleGroundMgr.h b/src/game/BattleGround/BattleGroundMgr.h index 420080807..40c991142 100644 --- a/src/game/BattleGround/BattleGroundMgr.h +++ b/src/game/BattleGround/BattleGroundMgr.h @@ -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; diff --git a/src/game/ChatCommands/Level2.cpp b/src/game/ChatCommands/Level2.cpp index 797d70960..e7582d7ec 100644 --- a/src/game/ChatCommands/Level2.cpp +++ b/src/game/ChatCommands/Level2.cpp @@ -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) { diff --git a/src/game/MotionGenerators/PathFinder.cpp b/src/game/MotionGenerators/PathFinder.cpp index 0a45ec253..81ba746bd 100644 --- a/src/game/MotionGenerators/PathFinder.cpp +++ b/src/game/MotionGenerators/PathFinder.cpp @@ -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; diff --git a/src/game/MotionGenerators/WaypointMovementGenerator.cpp b/src/game/MotionGenerators/WaypointMovementGenerator.cpp index 20939384a..89007b683 100644 --- a/src/game/MotionGenerators/WaypointMovementGenerator.cpp +++ b/src/game/MotionGenerators/WaypointMovementGenerator.cpp @@ -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(); diff --git a/src/game/Object/Creature.cpp b/src/game/Object/Creature.cpp index eb24a81dc..3031a56ba 100644 --- a/src/game/Object/Creature.cpp +++ b/src/game/Object/Creature.cpp @@ -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*/) { diff --git a/src/game/Object/Creature.h b/src/game/Object/Creature.h index 507d86fd2..bfc881125 100644 --- a/src/game/Object/Creature.h +++ b/src/game/Object/Creature.h @@ -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 diff --git a/src/game/Object/CreatureAISelector.cpp b/src/game/Object/CreatureAISelector.cpp index aba560856..4edb13e47 100644 --- a/src/game/Object/CreatureAISelector.cpp +++ b/src/game/Object/CreatureAISelector.cpp @@ -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"); diff --git a/src/game/Object/CreatureEventAI.cpp b/src/game/Object/CreatureEventAI.cpp index 60d6a700a..41cd2a99d 100644 --- a/src/game/Object/CreatureEventAI.cpp +++ b/src/game/Object/CreatureEventAI.cpp @@ -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 \ diff --git a/src/game/Object/DynamicObject.cpp b/src/game/Object/DynamicObject.cpp index 9657b557c..851fab270 100644 --- a/src/game/Object/DynamicObject.cpp +++ b/src/game/Object/DynamicObject.cpp @@ -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()) diff --git a/src/game/Object/GameObject.cpp b/src/game/Object/GameObject.cpp index c212bb9a7..caf5cdaeb 100644 --- a/src/game/Object/GameObject.cpp +++ b/src/game/Object/GameObject.cpp @@ -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 diff --git a/src/game/Object/LootMgr.cpp b/src/game/Object/LootMgr.cpp index 16e9dad7b..6602eb2b1 100644 --- a/src/game/Object/LootMgr.cpp +++ b/src/game/Object/LootMgr.cpp @@ -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; } diff --git a/src/game/Object/LootMgr.h b/src/game/Object/LootMgr.h index a11af2b4e..fd4225b3d 100644 --- a/src/game/Object/LootMgr.h +++ b/src/game/Object/LootMgr.h @@ -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 diff --git a/src/game/Object/Object.cpp b/src/game/Object/Object.cpp index 65057b0fb..124bca80c 100644 --- a/src/game/Object/Object.cpp +++ b/src/game/Object/Object.cpp @@ -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); diff --git a/src/game/Object/Object.h b/src/game/Object/Object.h index 752a642cf..6ad7321e8 100644 --- a/src/game/Object/Object.h +++ b/src/game/Object/Object.h @@ -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; diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index 5569ac5a7..8d909995a 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -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; diff --git a/src/game/Object/Pet.cpp b/src/game/Object/Pet.cpp index 5e15fd4fc..a01326da3 100644 --- a/src/game/Object/Pet.cpp +++ b/src/game/Object/Pet.cpp @@ -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: diff --git a/src/game/Object/Pet.h b/src/game/Object/Pet.h index 7265b1f66..451fe7c30 100644 --- a/src/game/Object/Pet.h +++ b/src/game/Object/Pet.h @@ -129,7 +129,7 @@ typedef std::vector 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; diff --git a/src/game/Object/PetAI.cpp b/src/game/Object/PetAI.cpp index 3e92e29d1..934c19da0 100644 --- a/src/game/Object/PetAI.cpp +++ b/src/game/Object/PetAI.cpp @@ -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 diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index b99443afc..8f4bf0b3d 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -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)) diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index 5c74a974a..9f59dee96 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -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); diff --git a/src/game/Object/SpellMgr.cpp b/src/game/Object/SpellMgr.cpp index 96c93636c..eef79caaa 100644 --- a/src/game/Object/SpellMgr.cpp +++ b/src/game/Object/SpellMgr.cpp @@ -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; diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index 7e356320a..6fefd8a91 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -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(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); } } diff --git a/src/game/Object/Unit.h b/src/game/Object/Unit.h index 96a0b9de9..9ac6ce4f5 100644 --- a/src/game/Object/Unit.h +++ b/src/game/Object/Unit.h @@ -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); diff --git a/src/game/Object/Vehicle.cpp b/src/game/Object/Vehicle.cpp index 3954cb381..8d4ed12fe 100644 --- a/src/game/Object/Vehicle.cpp +++ b/src/game/Object/Vehicle.cpp @@ -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) { diff --git a/src/game/OutdoorPvP/OutdoorPvPMgr.cpp b/src/game/OutdoorPvP/OutdoorPvPMgr.cpp index 13adf6a99..af9f987b1 100644 --- a/src/game/OutdoorPvP/OutdoorPvPMgr.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPMgr.cpp @@ -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) diff --git a/src/game/References/ThreatManager.cpp b/src/game/References/ThreatManager.cpp index 61bf55ca1..7e67809d7 100644 --- a/src/game/References/ThreatManager.cpp +++ b/src/game/References/ThreatManager.cpp @@ -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; } diff --git a/src/game/Server/DBCEnums.h b/src/game/Server/DBCEnums.h index 9cdf69669..21e77ecbc 100644 --- a/src/game/Server/DBCEnums.h +++ b/src/game/Server/DBCEnums.h @@ -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 diff --git a/src/game/Server/SharedDefines.h b/src/game/Server/SharedDefines.h index 73a5eec30..525fcb1cc 100644 --- a/src/game/Server/SharedDefines.h +++ b/src/game/Server/SharedDefines.h @@ -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 diff --git a/src/game/WorldHandlers/AchievementMgr.cpp b/src/game/WorldHandlers/AchievementMgr.cpp index 3c536c4d6..76bb4c005 100644 --- a/src/game/WorldHandlers/AchievementMgr.cpp +++ b/src/game/WorldHandlers/AchievementMgr.cpp @@ -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; diff --git a/src/game/WorldHandlers/Chat.h b/src/game/WorldHandlers/Chat.h index 3aaea18a7..9d42d041a 100644 --- a/src/game/WorldHandlers/Chat.h +++ b/src/game/WorldHandlers/Chat.h @@ -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; diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index 6e5782f0b..e97f4099e 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -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) diff --git a/src/game/WorldHandlers/PetHandler.cpp b/src/game/WorldHandlers/PetHandler.cpp index 583655540..8dcda78e9 100644 --- a/src/game/WorldHandlers/PetHandler.cpp +++ b/src/game/WorldHandlers/PetHandler.cpp @@ -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 { diff --git a/src/game/WorldHandlers/Spell.cpp b/src/game/WorldHandlers/Spell.cpp index 82bf4e8ab..12cff13a6 100644 --- a/src/game/WorldHandlers/Spell.cpp +++ b/src/game/WorldHandlers/Spell.cpp @@ -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(charmer) : nullptr; + if (!charmer->IsAlive() && (!pCharmer || !pCharmer->IsGhouled())) + return SPELL_FAILED_CASTER_DEAD; + } if (!target && m_targets.getUnitTarget()) target = m_targets.getUnitTarget(); diff --git a/src/game/WorldHandlers/Spell.h b/src/game/WorldHandlers/Spell.h index 0dc599471..60287a5dd 100644 --- a/src/game/WorldHandlers/Spell.h +++ b/src/game/WorldHandlers/Spell.h @@ -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 diff --git a/src/game/WorldHandlers/SpellAuras.cpp b/src/game/WorldHandlers/SpellAuras.cpp index 25e5e8ad8..3c008176f 100644 --- a/src/game/WorldHandlers/SpellAuras.cpp +++ b/src/game/WorldHandlers/SpellAuras.cpp @@ -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), diff --git a/src/game/WorldHandlers/SpellAuras.h b/src/game/WorldHandlers/SpellAuras.h index 86c835747..2ec8e95a5 100644 --- a/src/game/WorldHandlers/SpellAuras.h +++ b/src/game/WorldHandlers/SpellAuras.h @@ -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 diff --git a/src/game/WorldHandlers/SpellEffects.cpp b/src/game/WorldHandlers/SpellEffects.cpp index f1cf081e4..1c2d7325c 100644 --- a/src/game/WorldHandlers/SpellEffects.cpp +++ b/src/game/WorldHandlers/SpellEffects.cpp @@ -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) diff --git a/src/game/WorldHandlers/SpellHandler.cpp b/src/game/WorldHandlers/SpellHandler.cpp index 90f8ccea2..beadd40f9 100644 --- a/src/game/WorldHandlers/SpellHandler.cpp +++ b/src/game/WorldHandlers/SpellHandler.cpp @@ -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) diff --git a/src/game/WorldHandlers/TradeHandler.cpp b/src/game/WorldHandlers/TradeHandler.cpp index 77e7852a4..ee36d857f 100644 --- a/src/game/WorldHandlers/TradeHandler.cpp +++ b/src/game/WorldHandlers/TradeHandler.cpp @@ -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); diff --git a/src/game/WorldHandlers/Transports.cpp b/src/game/WorldHandlers/Transports.cpp index fd089ee23..02da0f3d3 100644 --- a/src/game/WorldHandlers/Transports.cpp +++ b/src/game/WorldHandlers/Transports.cpp @@ -358,7 +358,7 @@ bool Transport::GenerateWaypoints(uint32 pathid, std::set& 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& 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& 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); diff --git a/src/game/WorldHandlers/UnitAuraProcHandler.cpp b/src/game/WorldHandlers/UnitAuraProcHandler.cpp index fd04fc594..fabf1042b 100644 --- a/src/game/WorldHandlers/UnitAuraProcHandler.cpp +++ b/src/game/WorldHandlers/UnitAuraProcHandler.cpp @@ -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; } } diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 5b7a5b6fc..320d58933 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -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); diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index 879151466..5f85f4363 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -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, diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 955478b60..6177001cb 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -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