diff options
Diffstat (limited to 'src')
71 files changed, 903 insertions, 635 deletions
diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index a83bb9dad1c..a2024bff7cb 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -34,6 +34,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 2647368559c..114a48c60ca 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -488,9 +488,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_CAST: { - if (!me) - break; - ObjectList* targets = GetTargets(e, unit); if (!targets) break; @@ -502,31 +499,36 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell)) { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - me->InterruptNonMeleeSpells(false); - - if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + if (me) { - // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed - // unless target is outside spell range, out of mana, or LOS. + if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + me->InterruptNonMeleeSpells(false); - bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); - int32 mana = me->GetPower(POWER_MANA); + if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + { + // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed + // unless target is outside spell range, out of mana, or LOS. + + bool _allowMove = false; + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); + int32 mana = me->GetPower(POWER_MANA); - if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || - me->GetDistance(*itr) < spellInfo->GetMinRange(true) || - !me->IsWithinLOSInMap(*itr) || - mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) + if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || + me->GetDistance(*itr) < spellInfo->GetMinRange(true) || + !me->IsWithinLOSInMap(*itr) || + mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) _allowMove = true; - CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); - } + CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); + } - me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } + else if (go) + go->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell %u on target %u with castflags %u", - me->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); + TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: %s: %u casts spell %u on target %u with castflags %u", + GetLogNameForGuid(me ? me->GetGUID() : go->GetGUID()), me ? me->GetGUIDLow() : go->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); } else TC_LOG_DEBUG("scripts.ai", "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId())); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 9e9cc6c63ee..faa71fd2ffa 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -80,12 +80,11 @@ void BattlegroundIC::DoAction(uint32 action, uint64 var) if (!player) return; - player->SetTransport(player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde); + (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->AddPassenger(player); player->m_movementInfo.transport.pos.m_positionX = TransportMovementInfo.GetPositionX(); player->m_movementInfo.transport.pos.m_positionY = TransportMovementInfo.GetPositionY(); player->m_movementInfo.transport.pos.m_positionZ = TransportMovementInfo.GetPositionZ(); - player->m_movementInfo.transport.guid = (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->GetGUID(); if (player->TeleportTo(GetMapId(), TeleportToTransportPosition.GetPositionX(), TeleportToTransportPosition.GetPositionY(), diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index bf46c1fd7c6..26fd0814dcb 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -103,7 +103,9 @@ set(game_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index ec048e167ac..8e186e9d094 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -442,6 +442,7 @@ enum VehicleSeatFlagsB VEHICLE_SEAT_FLAG_B_EJECTABLE = 0x00000020, // ejectable VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 = 0x00000040, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 = 0x00000100, + VEHICLE_SEAT_FLAG_B_KEEP_PET = 0x00020000, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4 = 0x02000000, VEHICLE_SEAT_FLAG_B_CAN_SWITCH = 0x04000000, VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000 // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000 diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index aadf1529ffd..181e04e04fc 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -46,7 +46,7 @@ void LFGPlayerScript::OnLogout(Player* player) } } -void LFGPlayerScript::OnLogin(Player* player) +void LFGPlayerScript::OnLogin(Player* player, bool /*loginFirst*/) { if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER)) return; diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h index 87881ed7524..1ed37bd9d05 100644 --- a/src/server/game/DungeonFinding/LFGScripts.h +++ b/src/server/game/DungeonFinding/LFGScripts.h @@ -36,7 +36,7 @@ class LFGPlayerScript : public PlayerScript // Player Hooks void OnLogout(Player* player); - void OnLogin(Player* player); + void OnLogin(Player* player, bool loginFirst); void OnMapChanged(Player* player); }; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 90527912efd..c81ba409495 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -567,13 +567,13 @@ void Creature::Update(uint32 diff) if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed RegenerateHealth(); - if (getPowerType() == POWER_ENERGY) + if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER)) { - if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerDisplayId != POWER_PYRITE) + if (getPowerType() == POWER_ENERGY) Regenerate(POWER_ENERGY); + else + RegenerateMana(); } - else - RegenerateMana(); /*if (!bIsPolymorphed) // only increase the timer if not polymorphed m_regenTimer += CREATURE_REGEN_INTERVAL - diff; @@ -1173,14 +1173,22 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const* SetOriginalEntry(entry); - if (!vehId) - vehId = cinfo->VehicleId; - - Object::_Create(guidlow, entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); + Object::_Create(guidlow, entry, (vehId || cinfo->VehicleId) ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); if (!UpdateEntry(entry, data)) return false; + if (!vehId) + { + if (GetCreatureTemplate()->VehicleId) + { + vehId = GetCreatureTemplate()->VehicleId; + entry = GetCreatureTemplate()->Entry; + } + else + vehId = cinfo->VehicleId; + } + if (vehId) CreateVehicleKit(vehId, entry); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 69b15c2b56b..ae08a4251a5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1747,7 +1747,7 @@ void GameObject::Use(Unit* user) CastSpell(user, spellId); } -void GameObject::CastSpell(Unit* target, uint32 spellId) +void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true*/) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) @@ -1766,7 +1766,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) if (self) { if (target) - target->CastSpell(target, spellInfo, true); + target->CastSpell(target, spellInfo, triggered); return; } @@ -1780,14 +1780,14 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) trigger->setFaction(owner->getFaction()); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID()); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, owner->GetGUID()); } else { trigger->setFaction(14); // Set owner guid for target if no owner available - needed by trigger auras // - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell()) - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, target ? target->GetGUID() : 0); } } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 7aa3a01016b..8f70fc0e907 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -791,7 +791,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map GameObject* LookupFishingHoleAround(float range); - void CastSpell(Unit* target, uint32 spell); + void CastSpell(Unit* target, uint32 spell, bool triggered = true); void SendCustomAnim(uint32 anim); bool IsInRange(float x, float y, float z, float radius) const; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 768f5907c19..cc199969174 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1916,6 +1916,8 @@ bool Pet::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint3 if (!InitEntry(Entry)) return false; + // Force regen flag for player pets, just like we do for players themselves + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); SetSheath(SHEATH_STATE_MELEE); return true; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8ceb6c00808..9733c0f2b52 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6429,7 +6429,7 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) if (newVal < currVal) UpdateSkillEnchantments(id, currVal, newVal); // update step - SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_PAIR32(id, step)); + SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), MAKE_PAIR32(id, step)); // update value SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_SKILL_VALUE(newVal, maxVal)); if (itr->second.uState != SKILL_NEW) @@ -24976,7 +24976,7 @@ void Player::_LoadSkills(PreparedQueryResult result) base_skill = 1; // skill mast be known and then > 0 in any case if (GetPureSkillValue(SKILL_FIRST_AID) < base_skill) - SetSkill(SKILL_FIRST_AID, 0, base_skill, base_skill); + SetSkill(SKILL_FIRST_AID, 4 /*artisan*/, base_skill, 300); if (GetPureSkillValue(SKILL_AXES) < base_skill) SetSkill(SKILL_AXES, 0, base_skill, base_skill); if (GetPureSkillValue(SKILL_DEFENSE) < base_skill) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c0f179eb504..492197db64e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3352,7 +3352,7 @@ void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex) AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); ASSERT(aurApp); if (!aurApp->GetEffectMask()) - _ApplyAura(aurApp, 1<<effIndex); + _ApplyAura(aurApp, 1 << effIndex); else aurApp->_HandleEffect(effIndex, true); } @@ -3390,7 +3390,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) // apply effects of the aura for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (effMask & 1<<i && (!aurApp->GetRemoveMode())) + if (effMask & 1 << i && (!aurApp->GetRemoveMode())) aurApp->_HandleEffect(i, true); } } @@ -3503,6 +3503,19 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) if (spellProto->IsPassiveStackableWithRanks()) return; + if (!IsHighestExclusiveAura(aura)) + { + if (!aura->GetSpellInfo()->IsAffectingArea()) + { + Unit* caster = aura->GetCaster(); + if (caster && caster->GetTypeId() == TYPEID_PLAYER) + Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), 1, SPELL_FAILED_AURA_BOUNCED); + } + + RemoveAura(aura); + return; + } + bool remove = false; for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i) { @@ -3832,6 +3845,8 @@ void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, { Aura* aura = (*iter)->GetBase(); AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); + if (!aurApp) + continue; ++iter; if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID) @@ -6036,11 +6051,11 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 34299; if (triggeredByAura->GetCasterGUID() != GetGUID()) break; - int32 basepoints1 = triggerAmount * 2; + int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); // Improved Leader of the Pack // Check cooldown of heal spell cooldown if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) - CastCustomSpell(this, 60889, &basepoints1, 0, 0, true, 0, triggeredByAura); + CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); break; } // Healing Touch (Dreamwalker Raiment set) @@ -8645,25 +8660,30 @@ void Unit::setPowerType(Powers new_powertype) } } + float powerMultiplier = 1.0f; + if (!IsPet()) + if (Creature* creature = ToCreature()) + powerMultiplier = creature->GetCreatureTemplate()->ModMana; + switch (new_powertype) { default: case POWER_MANA: break; case POWER_RAGE: - SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE)); + SetMaxPower(POWER_RAGE, uint32(std::ceil(GetCreatePowers(POWER_RAGE) * powerMultiplier))); SetPower(POWER_RAGE, 0); break; case POWER_FOCUS: - SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); - SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); + SetMaxPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); + SetPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); break; case POWER_ENERGY: - SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY)); + SetMaxPower(POWER_ENERGY, uint32(std::ceil(GetCreatePowers(POWER_ENERGY) * powerMultiplier))); break; case POWER_HAPPINESS: - SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); - SetPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS)); + SetMaxPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); + SetPower(POWER_HAPPINESS, uint32(std::ceil(GetCreatePowers(POWER_HAPPINESS) * powerMultiplier))); break; } } @@ -10486,17 +10506,21 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto { if (!((*i)->IsAffectedOnSpell(spellProto))) continue; - int32 modChance = 0; + switch ((*i)->GetMiscValue()) { - // Shatter - case 911: modChance+= 16; - case 910: modChance+= 17; - case 849: modChance+= 17; - if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) - break; - crit_chance+=modChance; + case 911: // Shatter (Rank 1) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 17; break; + case 910: // Shatter (Rank 2) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 34; + break; + case 849: // Shatter (Rank 3) + if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + crit_chance += 50; + break; case 7917: // Glyph of Shadowburn if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) crit_chance+=(*i)->GetAmount(); @@ -10516,7 +10540,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto case SPELLFAMILY_MAGE: // Glyph of Fire Blast if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12) - if (victim->HasAuraWithMechanic((1<<MECHANIC_STUN) | (1<<MECHANIC_KNOCKOUT))) + if (victim->HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT))) if (AuraEffect const* aurEff = GetAuraEffect(56369, EFFECT_0)) crit_chance += aurEff->GetAmount(); break; @@ -10537,7 +10561,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto crit_chance += aurEff->GetAmount(); break; } - break; + break; case SPELLFAMILY_ROGUE: // Shiv-applied poisons can't crit if (FindCurrentSpellBySpellId(5938)) @@ -10559,7 +10583,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto return 100.0f; break; } - break; + break; case SPELLFAMILY_SHAMAN: // Lava Burst if (spellProto->SpellFamilyFlags[1] & 0x00001000) @@ -10569,7 +10593,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto return 100.0f; break; } - break; + break; } } break; @@ -10590,17 +10614,17 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto crit_chance += rendAndTear->GetAmount(); break; } - break; + break; case SPELLFAMILY_WARRIOR: - // Victory Rush - if (spellProto->SpellFamilyFlags[1] & 0x100) - { - // Glyph of Victory Rush - if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) - crit_chance += aurEff->GetAmount(); - break; - } - break; + // Victory Rush + if (spellProto->SpellFamilyFlags[1] & 0x100) + { + // Glyph of Victory Rush + if (AuraEffect const* aurEff = GetAuraEffect(58382, 0)) + crit_chance += aurEff->GetAmount(); + break; + } + break; } } /// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells @@ -17743,7 +17767,7 @@ void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns c } } -int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool sameMiscValue /*= false*/) const +int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const { int32 val = 0; SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id); @@ -17754,7 +17778,7 @@ int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEf AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType); for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr) { - if (aurEff != (*auraItr) && (!sameMiscValue || aurEff->GetMiscValue() == (*auraItr)->GetMiscValue()) && + if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) && sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second)) { // absolute value only @@ -17766,3 +17790,49 @@ int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEf } return val; } + +bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/) +{ + for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* aurEff = aura->GetEffect(i)) + { + AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName); + AuraEffectList const& auras = GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) + { + AuraEffect const* existingAurEff = (*itr); + ++itr; + + if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) + == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) + { + int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); + if (!diff) + diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); + + if (diff > 0) + { + Aura const* base = existingAurEff->GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) + { + if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) + { + bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + itr = auras.begin(); + } + } + } + else if (diff < 0) + return false; + } + } + } + } + + return true; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 103f6b596d9..535d75af204 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2155,7 +2155,8 @@ class Unit : public WorldObject time_t GetLastDamagedTime() const { return _lastDamagedTime; } void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; } - int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool sameMiscValue = false) const; + int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const; + bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false); protected: explicit Unit (bool isWorldObject); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 4c3724a8860..915e6016e22 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -77,8 +77,12 @@ Vehicle::~Vehicle() void Vehicle::Install() { if (_me->GetTypeId() == TYPEID_UNIT) + { if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId)) _me->setPowerType(Powers(powerDisplay->PowerType)); + else if (_me->getClass() == CLASS_ROGUE) + _me->setPowerType(POWER_ENERGY); + } _status = STATUS_INSTALLED; if (GetBase()->GetTypeId() == TYPEID_UNIT) @@ -775,6 +779,8 @@ bool VehicleJoinEvent::Execute(uint64, uint32) Passenger->InterruptNonMeleeSpells(false); Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED); + VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; + Player* player = Passenger->ToPlayer(); if (player) { @@ -785,14 +791,14 @@ bool VehicleJoinEvent::Execute(uint64, uint32) player->StopCastingCharm(); player->StopCastingBindSight(); player->SendOnCancelExpectedVehicleRideAura(); - player->UnsummonPetTemporaryIfAny(); + if (!(veSeat->m_flagsB & VEHICLE_SEAT_FLAG_B_KEEP_PET)) + player->UnsummonPetTemporaryIfAny(); } if (Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE) Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; Passenger->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); Passenger->m_movementInfo.transport.time = 0; Passenger->m_movementInfo.transport.seat = Seat->first; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 207f80eabe7..72ea1b16864 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2951,32 +2951,32 @@ void ObjectMgr::LoadVehicleTemplateAccessories() { Field* fields = result->Fetch(); - uint32 uiEntry = fields[0].GetUInt32(); - uint32 uiAccessory = fields[1].GetUInt32(); - int8 uiSeat = int8(fields[2].GetInt8()); - bool bMinion = fields[3].GetBool(); - uint8 uiSummonType = fields[4].GetUInt8(); - uint32 uiSummonTimer= fields[5].GetUInt32(); + uint32 entry = fields[0].GetUInt32(); + uint32 accessory = fields[1].GetUInt32(); + int8 seatId = fields[2].GetInt8(); + bool isMinion = fields[3].GetBool(); + uint8 summonType = fields[4].GetUInt8(); + uint32 summonTimer = fields[5].GetUInt32(); - if (!sObjectMgr->GetCreatureTemplate(uiEntry)) + if (!sObjectMgr->GetCreatureTemplate(entry)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", entry); continue; } - if (!sObjectMgr->GetCreatureTemplate(uiAccessory)) + if (!sObjectMgr->GetCreatureTemplate(accessory)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", uiAccessory); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", accessory); continue; } - if (_spellClickInfoStore.find(uiEntry) == _spellClickInfoStore.end()) + if (_spellClickInfoStore.find(entry) == _spellClickInfoStore.end()) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", entry); continue; } - _vehicleTemplateAccessoryStore[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer)); + _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer)); ++count; } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 113df993f81..45ecbf0c3df 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1572,7 +1572,7 @@ void Group::UpdatePlayerOutOfRange(Player* player) for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { member = itr->GetSource(); - if (member && !member->IsWithinDist(player, member->GetSightRange(), false)) + if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) member->GetSession()->SendPacket(&data); } } diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 0a797f0e008..dd654fb3ad0 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -260,26 +260,43 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) } else { + // client limits the amount of players to be invited to 100 + const uint32 MaxPlayerInvites = 100; + uint32 inviteCount; - recvData >> inviteCount; + uint64 invitee[MaxPlayerInvites]; + uint8 status[MaxPlayerInvites]; + uint8 rank[MaxPlayerInvites]; + + memset(invitee, 0, sizeof(invitee)); + memset(status, 0, sizeof(status)); + memset(rank, 0, sizeof(rank)); + + try + { + recvData >> inviteCount; + + for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) + { + recvData.readPackGUID(invitee[i]); + recvData >> status[i] >> rank[i]; + } + } + catch (ByteBufferException const&) + { + delete calendarEvent; + calendarEvent = NULL; + throw; + } SQLTransaction trans; if (inviteCount > 1) trans = CharacterDatabase.BeginTransaction(); - // client limits the amount of players to be invited to 100 - const uint32 MaxPlayerInvites = 100; - for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { - uint64 invitee = 0; - uint8 status = 0; - uint8 rank = 0; - recvData.readPackGUID(invitee); - recvData >> status >> rank; - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee[i], guid, 946684800, CalendarInviteStatus(status[i]), CalendarModerationRank(rank[i]), ""); sCalendarMgr->AddInvite(calendarEvent, invite, trans); } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ea5fc962bda..c2f93190a05 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1014,7 +1014,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) SendNotification(LANG_RESET_TALENTS); } - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) + bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST); + if (firstLogin) pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); // show time before shutdown if shutdown planned. @@ -1039,7 +1040,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) // Handle Login-Achievements (should be handled after loading) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); - sScriptMgr->OnPlayerLogin(pCurrChar); + sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); + delete holder; } diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 3ef99cc2fc1..60966ace011 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -1443,6 +1443,10 @@ void WorldSession::HandleItemRefund(WorldPacket &recvData) return; } + // Don't try to refund item currently being disenchanted + if (_player->GetLootGUID() == guid) + return; + GetPlayer()->RefundItem(item); } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index f92c6e08e31..61f0b9afce2 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -338,7 +338,8 @@ void WorldSession::DoLootRelease(uint64 lguid) } else { - if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db) + // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item + if (pItem->loot.isLooted() || !(proto->Flags & ITEM_PROTO_FLAG_OPENABLE)) player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } return; // item can be looted only single player diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 34871085157..3a680e30217 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1224,7 +1224,8 @@ enum TrinityStrings LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, - LANG_NPCINFO_INHABIT_TYPE = 11008 + LANG_NPCINFO_INHABIT_TYPE = 11008, + LANG_NPCINFO_FLAGS_EXTRA = 11009 // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 16dde61158b..9967b59ecec 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -397,7 +397,7 @@ enum SpellAttr3 SPELL_ATTR3_MAIN_HAND = 0x00000400, // 10 Main hand weapon required SPELL_ATTR3_BATTLEGROUND = 0x00000800, // 11 Can only be cast in battleground SPELL_ATTR3_ONLY_TARGET_GHOSTS = 0x00001000, // 12 - SPELL_ATTR3_UNK13 = 0x00002000, // 13 + SPELL_ATTR3_DONT_DISPLAY_CHANNEL_BAR = 0x00002000, // 13 Clientside attribute - will not display channeling bar SPELL_ATTR3_IS_HONORLESS_TARGET = 0x00004000, // 14 "Honorless Target" only this spells have this flag SPELL_ATTR3_UNK15 = 0x00008000, // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag SPELL_ATTR3_CANT_TRIGGER_PROC = 0x00010000, // 16 confirmed with many patchnotes @@ -544,7 +544,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK13 = 0x00002000, // 13 Not set in 3.2.2a. SPELL_ATTR7_UNK14 = 0x00004000, // 14 Only 52150 (Raise Dead - Pet) spell. SPELL_ATTR7_UNK15 = 0x00008000, // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? - SPELL_ATTR7_UNK16 = 0x00010000, // 16 Druid spells (29166, 54833, 64372, 68285). + SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER = 0x00010000, // 16 These spells can replenish a powertype, which is not the current powertype. SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell. SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects. SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones. diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index c181750a414..246d4682739 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -191,6 +191,10 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di } else { + // Set home position at place on waypoint movement. + if (!creature->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) || !creature->GetTransGUID()) + creature->SetHomePosition(creature->GetPosition()); + if (creature->IsStopped()) Stop(STOP_TIME_FOR_PLAYER); else if (creature->movespline->Finalized()) diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 1e5b31f448a..f1359b70aa6 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -471,7 +471,6 @@ void AddSC_boss_xt002(); void AddSC_boss_kologarn(); void AddSC_boss_assembly_of_iron(); void AddSC_boss_general_vezax(); -void AddSC_ulduar_teleporter(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); @@ -1315,7 +1314,6 @@ void AddNorthrendScripts() AddSC_boss_general_vezax(); AddSC_boss_assembly_of_iron(); AddSC_boss_kologarn(); - AddSC_ulduar_teleporter(); AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 505539eea20..83f401d4e79 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1243,9 +1243,9 @@ void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck) FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck); } -void ScriptMgr::OnPlayerLogin(Player* player) +void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin) { - FOREACH_SCRIPT(PlayerScript)->OnLogin(player); + FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin); } void ScriptMgr::OnPlayerLogout(Player* player) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index c016eb048df..e31a8ec1328 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -745,7 +745,7 @@ class PlayerScript : public UnitScript virtual void OnSpellCast(Player* /*player*/, Spell* /*spell*/, bool /*skipCheck*/) { } // Called when a player logs in. - virtual void OnLogin(Player* /*player*/) { } + virtual void OnLogin(Player* /*player*/, bool /*firstLogin*/) { } // Called when a player logs out. virtual void OnLogout(Player* /*player*/) { } @@ -1065,7 +1065,7 @@ class ScriptMgr void OnPlayerEmote(Player* player, uint32 emote); void OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, uint64 guid); void OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck); - void OnPlayerLogin(Player* player); + void OnPlayerLogin(Player* player, bool firstLogin); void OnPlayerLogout(Player* player); void OnPlayerCreate(Player* player); void OnPlayerDelete(uint64 guid, uint32 accountId); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 94f1a5b4ea9..152dc903825 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -3577,7 +3577,7 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo } Unit* target = aurApp->GetTarget(); - int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue()); if (abs(spellGroupVal) >= abs(GetAmount())) return; @@ -3704,14 +3704,30 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -1 || GetMiscValue() > 4) { TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); return; } + Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + + if (spellGroupVal) + { + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + { + if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply); + } + } + } + // save current health state float healthPct = target->GetHealthPct(); bool alive = target->IsAlive(); @@ -3720,6 +3736,17 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 { if (GetMiscValue() == i || GetMiscValue() == -1) { + int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); + if (abs(spellGroupVal2) >= abs(GetAmount())) + continue; + + if (spellGroupVal2) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply); + } + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); @@ -4573,28 +4600,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool // AT APPLY if (apply) { - // Overpower - if (caster && m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && - m_spellInfo->SpellFamilyFlags[0] & 0x4) - { - // In addition, if you strike a player.. - if (target->GetTypeId() != TYPEID_PLAYER) - return; - // ..while they are casting - if (target->IsNonMeleeSpellCast(false, false, true, false, true)) - if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0)) - switch (aurEff->GetId()) - { - // Unrelenting Assault, rank 1 - case 46859: - target->CastSpell(target, 64849, true, NULL, aurEff); - break; - // Unrelenting Assault, rank 2 - case 46860: - target->CastSpell(target, 64850, true, NULL, aurEff); - break; - } - } switch (GetId()) { case 1515: // Tame beast @@ -6295,6 +6300,9 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons { Powers powerType = Powers(GetMiscValue()); + if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + if (!target->IsAlive() || !target->GetMaxPower(powerType)) return; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 683059b8e99..3e4786df870 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -539,6 +539,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) || !CanBeAppliedOn(itr->first)) addUnit = false; + if (addUnit && !itr->first->IsHighestExclusiveAura(this, true)) + addUnit = false; + if (addUnit) { // persistent area aura does not hit flying targets @@ -894,6 +897,18 @@ void Aura::RefreshSpellMods() player->RestoreAllSpellMods(0, this); } +bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const +{ + uint32 count = 0; + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (HasEffect(i) && GetSpellInfo()->Effects[i].ApplyAuraName == auraType) + ++count; + } + + return count > 1; +} + bool Aura::IsArea() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -1699,7 +1714,7 @@ void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* cast break; } default: - break; + break; } } } @@ -1758,13 +1773,19 @@ bool Aura::CanStackWith(Aura const* existingAura) const return false; // check spell group stack rules - SpellGroupStackRule stackRule = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo); - if (stackRule) + switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo)) { - if (stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE) - return false; - if (sameCaster && stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER) + case SPELL_GROUP_STACK_RULE_EXCLUSIVE: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal return false; + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER: + if (sameCaster) + return false; + break; + case SPELL_GROUP_STACK_RULE_DEFAULT: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: + default: + break; } if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 669d2a529a1..8c426ea2175 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -149,6 +149,7 @@ class Aura uint8 GetCasterLevel() const { return m_casterLevel; } + bool HasMoreThanOneEffectForType(AuraType auraType) const; bool IsArea() const; bool IsPassive() const; bool IsDeathPersistent() const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c85fb0584cc..48c2a76578d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3231,7 +3231,7 @@ void Spell::handle_immediate() // Apply duration mod if (Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); - + // Apply haste mods m_caster->ModSpellCastTime(m_spellInfo, duration, this); @@ -3762,7 +3762,7 @@ void Spell::SendSpellStart() castFlags |= CAST_FLAG_POWER_LEFT_SELF; if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE) - castFlags |= CAST_FLAG_UNKNOWN_19; + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); if (m_CastItem) @@ -3818,21 +3818,22 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->RuneCostID - && m_spellInfo->PowerType == POWER_RUNE) + && m_spellInfo->PowerType == POWER_RUNE + && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) - { castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START - } if (m_targets.HasTraj()) castFlags |= CAST_FLAG_ADJUST_MISSILE; + if (!m_spellInfo->StartRecoveryTime) + castFlags |= CAST_FLAG_NO_GCD; + WorldPacket data(SMSG_SPELL_GO, 50); // guess size if (m_CastItem) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 341867ff787..584c20fdfb3 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -57,7 +57,7 @@ enum SpellCastFlags CAST_FLAG_UNKNOWN_16 = 0x00008000, CAST_FLAG_UNKNOWN_17 = 0x00010000, CAST_FLAG_ADJUST_MISSILE = 0x00020000, - CAST_FLAG_UNKNOWN_19 = 0x00040000, + CAST_FLAG_NO_GCD = 0x00040000, // no GCD for spell casts from charm/summon (vehicle spells is an example) CAST_FLAG_VISUAL_CHAIN = 0x00080000, CAST_FLAG_UNKNOWN_21 = 0x00100000, CAST_FLAG_RUNE_LIST = 0x00200000, diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 1b1730c9aaa..9cf0e1ae45c 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -836,10 +836,10 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) { // remove all harmful spells on you... SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo(); - if ((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells - || ((spell->GetDispelMask()) & dispelMask)) + if (((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spell->GetSchoolMask() != SPELL_SCHOOL_MASK_NORMAL) // only affect magic spells + || (spell->GetDispelMask() & dispelMask)) && // ignore positive and passive auras - && !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) + !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive()) { m_caster->RemoveAura(iter); } @@ -1751,6 +1751,12 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + + if (unitTarget->GetMaxPower(power) == 0) + return; + // Some level depends spells int level_multiplier = 0; int level_diff = 0; @@ -1796,9 +1802,6 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (damage < 0) return; - if (unitTarget->GetMaxPower(power) == 0) - return; - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); // Mad Alchemist's Potion @@ -1863,6 +1866,9 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + uint32 maxPower = unitTarget->GetMaxPower(power); if (maxPower == 0) return; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ba4c3deca85..4d97dc97e5b 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1207,10 +1207,8 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return true; - // these spells (Cyclone for example) can pierce all... - if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) - // ...but not these (Divine shield for example) - && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY))) + // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example) + if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH))) return true; return false; diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 9108618176f..757bd813613 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -349,14 +349,14 @@ typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_ enum SpellGroupStackRule { - SPELL_GROUP_STACK_RULE_DEFAULT = 0, - SPELL_GROUP_STACK_RULE_EXCLUSIVE = 1, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER = 2, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT = 3 + SPELL_GROUP_STACK_RULE_DEFAULT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST, + SPELL_GROUP_STACK_RULE_MAX }; -#define SPELL_GROUP_STACK_RULE_MAX 4 - typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap; struct SpellThreatEntry diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index c1a9435de52..938520209a0 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -47,7 +47,9 @@ message("") include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 28d49fe11aa..9cf8c041883 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -43,6 +43,7 @@ struct EnumName #define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) } #define NPCFLAG_COUNT 24 +#define FLAGS_EXTRA_COUNT 16 EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] = { @@ -144,6 +145,26 @@ EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] = CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31) }; +EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] = +{ + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS) +}; + class npc_commandscript : public CommandScript { public: @@ -730,6 +751,10 @@ public: handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); + handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra); + for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i) + if (cInfo->flags_extra & flagsExtra[i].Value) + handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value); for (uint8 i = 0; i < NPCFLAG_COUNT; i++) if (npcflags & npcFlagTexts[i].Value) diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp index 2a473754ce6..f9757997731 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp @@ -144,7 +144,7 @@ class npc_core_rager : public CreatureScript if (HealthAbovePct(50) || !instance) return; - if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) + if (Creature* pGolemagg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) { if (pGolemagg->IsAlive()) { diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp index 4aa59e72556..bf7b4355ea6 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp @@ -141,9 +141,9 @@ class instance_ahnkahet : public InstanceMapScript SwitchTrigger = data; break; case DATA_JEDOGA_RESET_INITIANDS: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* creature = instance->GetCreature(*itr)) + if (Creature* creature = instance->GetCreature(guid)) { creature->Respawn(); if (!creature->IsInEvadeMode()) @@ -164,9 +164,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_SPHERE_2: return SpheresState[type - DATA_SPHERE_1]; case DATA_ALL_INITIAND_DEAD: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (!cr || cr->IsAlive()) return 0; } @@ -214,11 +214,11 @@ class instance_ahnkahet : public InstanceMapScript { std::vector<uint64> vInitiands; vInitiands.clear(); - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (cr && cr->IsAlive()) - vInitiands.push_back(*itr); + vInitiands.push_back(guid); } if (vInitiands.empty()) return 0; @@ -245,9 +245,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_JEDOGA_SHADOWSEEKER: if (state == DONE) { - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* cr = instance->GetCreature(*itr)) + if (Creature* cr = instance->GetCreature(guid)) cr->DespawnOrUnsummon(); } } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index aff3c0a9528..8401ea4b9a5 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -20,7 +20,6 @@ set(scripts_STAT_SRCS Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp Northrend/Ulduar/HallsOfLightning/boss_loken.cpp Northrend/Ulduar/Ulduar/boss_general_vezax.cpp - Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp Northrend/Ulduar/Ulduar/boss_thorim.cpp Northrend/Ulduar/Ulduar/boss_ignis.cpp Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index f352b4faace..43c295d5f64 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -855,7 +855,6 @@ class npc_halion_controller : public CreatureScript { if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr))) { - RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION); halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true); if (itr == DATA_TWILIGHT_HALION) @@ -866,19 +865,6 @@ class npc_halion_controller : public CreatureScript } } - void RemoveCorporeality(Creature* who, bool isTwilight = false) - { - for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++) - { - uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell); - if (who->HasAura(spellID)) - { - who->RemoveAurasDueToSpell(spellID); - break; - } - } - } - uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const { CorporealityEntry entry = _corporealityReference[pctValue]; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index 63b1359a406..4e9462a447f 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -208,7 +208,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(summoners[i].data)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) { if (active) crystalChannelTarget->AI()->SetData(summoners[i].spell, summoners[i].timer); @@ -221,7 +221,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) SetCrystalStatus(crystal, active); } @@ -241,7 +241,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) if (crystal->GetGoState() == GO_STATE_ACTIVE) { SetCrystalStatus(crystal, false); @@ -258,7 +258,7 @@ public: events.ScheduleEvent(EVENT_SUMMON_MINIONS, 15000); } else if (uint64 guid = instance->GetData64(DATA_NOVOS_SUMMONER_4)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) crystalChannelTarget->AI()->SetData(SPELL_SUMMON_CRYSTAL_HANDLER, 15000); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 16d1531e890..e1658e564ec 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1227,9 +1227,9 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if (targets.empty()) return; - // select one random target, with preference of ranged targets + // select one random target, preferring ranged targets uint32 targetsAtRange = 0; - uint32 const minTargets = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 10 : 4); + uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4); targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); // get target count at range @@ -1237,18 +1237,12 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if ((*itr)->GetDistance(GetCaster()) < 12.0f) break; - // set the upper cap + // If not enough ranged targets are present just select anyone if (targetsAtRange < minTargets) - targetsAtRange = std::min<uint32>(targets.size() - 1, minTargets); - - if (!targetsAtRange) - { - targets.clear(); - return; - } + targetsAtRange = uint32(targets.size()); std::list<WorldObject*>::const_iterator itr = targets.begin(); - std::advance(itr, urand(0, targetsAtRange)); + std::advance(itr, urand(0, targetsAtRange - 1)); target = *itr; targets.clear(); targets.push_back(target); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 223f3731032..b72b953efb4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -559,6 +559,11 @@ class boss_the_lich_king : public CreatureScript Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); me->VisitNearbyGridObject(333.0f, worker); + // Restore Tirion's gossip only after The Lich King fully resets to prevent + // restarting the encounter while LK still runs back to spawn point + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + // Reset any light override me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); } @@ -1201,11 +1206,6 @@ class npc_tirion_fordring_tft : public CreatureScript void JustReachedHome() override { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - - if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) - return; - - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index d3b4a285af6..d4f00414b7d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -120,7 +120,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 02bafa8d10d..3d42827c0a8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -84,7 +84,6 @@ class boss_faerlina : public CreatureScript } void MoveInLineOfSight(Unit* who) override - { if (!_introDone && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index 3a0e3ce7c73..381be8d5cd1 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -70,7 +70,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (who->GetEntry() == NPC_ZOMBIE && me->IsWithinDistInMap(who, 7)) { diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 1331c25de17..e8ed181da5a 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -368,9 +368,9 @@ class instance_naxxramas : public InstanceMapScript if (i == section) continue; - for (std::set<uint64>::const_iterator itr = HeiganEruptionGUID[i].begin(); itr != HeiganEruptionGUID[i].end(); ++itr) + for (uint64 guid : HeiganEruptionGUID[i]) { - if (GameObject* heiganEruption = instance->GetGameObject(*itr)) + if (GameObject* heiganEruption = instance->GetGameObject(guid)) { heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress()); heiganEruption->CastSpell(NULL, SPELL_ERUPTION); diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index bf84a267a27..2b15ddf32c4 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -281,8 +281,8 @@ class instance_oculus : public InstanceMapScript void GreaterWhelps() { - for (std::list<uint64>::const_iterator itr = GreaterWhelpList.begin(); itr != GreaterWhelpList.end(); ++itr) - if (Creature* gwhelp = instance->GetCreature(*itr)) + for (uint64 guid : GreaterWhelpList) + if (Creature* gwhelp = instance->GetCreature(guid)) gwhelp->SetPhaseMask(1, true); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 24d145f097f..13ea815febc 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -164,11 +164,9 @@ public: for (uint8 i = 0; i < 2; ++i) { - if (Creature* pStormforgedLieutenant = (ObjectAccessor::GetCreature((*me), m_auiStormforgedLieutenantGUID[i]))) - { + if (Creature* pStormforgedLieutenant = ObjectAccessor::GetCreature(*me, m_auiStormforgedLieutenantGUID[i])) if (!pStormforgedLieutenant->IsAlive()) pStormforgedLieutenant->Respawn(); - } } if (m_uiStance != STANCE_DEFENSIVE) @@ -411,7 +409,7 @@ public: void EnterCombat(Unit* who) override { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive() && !pBjarngrim->GetVictim()) pBjarngrim->AI()->AttackStart(who); @@ -434,7 +432,7 @@ public: if (m_uiRenewSteel_Timer <= uiDiff) { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive()) DoCast(pBjarngrim, SPELL_RENEW_STEEL_N); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index aac315cda0d..83082b18d73 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -165,9 +165,9 @@ public: Position pos = me->GetPosition(); - for (std::list<uint64>::const_iterator itr = lSparkList.begin(); itr != lSparkList.end(); ++itr) + for (uint64 guid : lSparkList) { - if (Creature* pSpark = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* pSpark = ObjectAccessor::GetCreature(*me, guid)) { if (pSpark->IsAlive()) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index d0b8f75e711..b424ce01b06 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -162,13 +162,11 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) - { + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) if (temp->IsAlive()) temp->DespawnOrUnsummon(); - } } m_lGolemGUIDList.clear(); @@ -179,9 +177,9 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) { // Only shatter brittle golems if (temp->IsAlive() && temp->GetEntry() == NPC_BRITTLE_GOLEM) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index eec08c3c429..796299cc952 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -37,7 +37,7 @@ enum Spells enum Events { - EVENT_PARTING_SORROW = 1, + EVENT_PARTING_SORROW = 1, EVENT_STORM_OF_GRIEF, EVENT_SHOCK_OF_SORROW, EVENT_PILLAR_OF_WOE diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 67500382758..595dcecd554 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -334,7 +334,7 @@ class boss_algalon_the_observer : public CreatureScript { case ACTION_START_INTRO: { - me->SetFlag(UNIT_FIELD_FLAGS_2, 0x20); + me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_INSTANTLY_APPEAR_MODEL); me->SetDisableGravity(true); DoCast(me, SPELL_ARRIVAL, true); DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index d728bc2a898..6437a76ee95 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -18,9 +18,10 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "InstanceScript.h" -#include "ulduar.h" #include "Player.h" #include "WorldPacket.h" +#include "SpellScript.h" +#include "ulduar.h" static DoorData const doorData[] = { @@ -1094,7 +1095,43 @@ class instance_ulduar : public InstanceMapScript } }; +class spell_ulduar_teleporter : public SpellScriptLoader +{ + public: + spell_ulduar_teleporter() : SpellScriptLoader("spell_ulduar_teleporter") { } + + class spell_ulduar_teleporter_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_teleporter_SpellScript); + + SpellCastResult CheckRequirement() + { + if (GetExplTargetUnit()->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_DONT_REPORT; + + if (GetExplTargetUnit()->IsInCombat()) + { + Spell::SendCastResult(GetExplTargetUnit()->ToPlayer(), GetSpellInfo(), 0, SPELL_FAILED_AFFECTING_COMBAT); + return SPELL_FAILED_AFFECTING_COMBAT; + } + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_ulduar_teleporter_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ulduar_teleporter_SpellScript(); + } +}; + void AddSC_instance_ulduar() { new instance_ulduar(); + new spell_ulduar_teleporter(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp deleted file mode 100644 index 9fc0e4056fa..00000000000 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptMgr.h" -#include "ScriptedGossip.h" -#include "InstanceScript.h" -#include "Player.h" -#include "ulduar.h" - -/* -The teleporter appears to be active and stable. - -- Expedition Base Camp -- Formation Grounds -- Colossal Forge -- Scrapyard -- Antechamber of Ulduar -- Shattered Walkway -- Conservatory of Life -*/ - -enum UlduarTeleporter -{ - BASE_CAMP = 200, - GROUNDS = 201, - FORGE = 202, - SCRAPYARD = 203, - ANTECHAMBER = 204, - WALKWAY = 205, - CONSERVATORY = 206, -}; - -class ulduar_teleporter : public GameObjectScript -{ - public: - ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { } - - bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (sender != GOSSIP_SENDER_MAIN) - return false; - if (!player->getAttackers().empty()) - return false; - - switch (action) - { - case BASE_CAMP: - player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case GROUNDS: - player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case FORGE: - player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case SCRAPYARD: - player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case ANTECHAMBER: - player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case WALKWAY: - player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case CONSERVATORY: - player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - } - - return true; - } - - bool OnGossipHello(Player* player, GameObject* gameObject) override - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); - if (InstanceScript* instance = gameObject->GetInstanceScript()) - { - if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); - if (instance->GetBossState(BOSS_LEVIATHAN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); - if (instance->GetBossState(BOSS_XT002) == DONE) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); - } - if (instance->GetBossState(BOSS_KOLOGARN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); - if (instance->GetBossState(BOSS_AURIAYA) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); - } - - player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID()); - return true; - } -}; - -void AddSC_ulduar_teleporter() -{ - new ulduar_teleporter(); -} diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp index e4bd9c469fb..7d680ecd071 100644 --- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp +++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp @@ -76,20 +76,18 @@ public: GetCreatureListWithEntryInGrid(orbList, me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f); if (!orbList.empty()) { - for (std::list<Creature*>::const_iterator itr = orbList.begin(); itr != orbList.end(); ++itr) + for (Creature* orb : orbList) { - if (Creature* pOrb = *itr) + if (orb->GetPositionY() < 1000) { - if (pOrb->GetPositionY() < 1000) - { - targetGUID = pOrb->GetGUID(); - break; - } + targetGUID = orb->GetGUID(); + break; } } } } - }else + } + else { if (!targetGUID) if (Creature* pOrb = GetClosestCreatureWithEntry(me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f)) diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 21fc93578ae..1e8da70bbbf 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -73,7 +73,6 @@ public: void AttackStart(Unit* /*who*/) override { } void MoveInLineOfSight(Unit* who) override - { if (!who || !who->IsInWorld() || who->GetZoneId() != 4395) return; diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index bda6d953d9f..59c9b21a220 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -246,13 +246,10 @@ class npc_commander_eligor_dawnbringer : public CreatureScript { std::list<Creature*> creatureList; GetCreatureListWithEntryInGrid(creatureList, me, AudienceMobs[ii], 15.0f); - for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + for (Creature* creature : creatureList) { - if (Creature* creatureList = *itr) - { - audienceList[creaturecount] = creatureList->GetGUID(); - ++creaturecount; - } + audienceList[creaturecount] = creature->GetGUID(); + ++creaturecount; } } diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp index 0004df68016..f03caa37cb2 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp @@ -17,14 +17,14 @@ */ /* ScriptData -SDName: Boss_Bloodboil -SD%Complete: 80 -SDComment: Bloodboil not working correctly, missing enrage -SDCategory: Black Temple +Name: Boss_Bloodboil +Complete: 80 +Category: Black Temple EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "black_temple.h" enum Bloodboil @@ -54,9 +54,6 @@ enum Bloodboil SPELL_BERSERK = 45078 }; - -//This is used to sort the players by distance in preparation for the Bloodboil cast. - class boss_gurtogg_bloodboil : public CreatureScript { public: @@ -137,51 +134,6 @@ public: Talk(SAY_DEATH); } - // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not limited. - void CastBloodboil() - { - // Get the Threat List - std::list<HostileReference*> m_threatlist = me->getThreatManager().getThreatList(); - - if (m_threatlist.empty()) // He doesn't have anyone in his threatlist, useless to continue - return; - - std::list<Unit*> targets; - std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); - for (; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container - { - Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - //only on alive players - if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } - - //Sort the list of players - targets.sort(Trinity::ObjectDistanceOrderPred(me, false)); - //Resize so we only get top 5 - targets.resize(5); - - //Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp - /*SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_BLOODBOIL); - if (spellInfo) - { - for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - Unit* target = *itr; - if (!target) return; - for (uint32 i = 0; i<3; ++i) - { - uint8 eff = spellInfo->Effect[i]; - if (eff >= TOTAL_SPELL_EFFECTS) - continue; - - Aura* Aur = new Aura(spellInfo, i, target, target, target); - target->AddAura(Aur); - } - } - }*/ - } - void RevertThreatOnTarget(uint64 guid) { if (Unit* unit = ObjectAccessor::GetUnit(*me, guid)) @@ -247,8 +199,7 @@ public: { if (BloodboilCount < 5) // Only cast it five times. { - //CastBloodboil(); // Causes issues on windows, so is commented out. - DoCastVictim(SPELL_BLOODBOIL); + DoCastAOE(SPELL_BLOODBOIL); ++BloodboilCount; BloodboilTimer = 10000*BloodboilCount; } @@ -274,7 +225,7 @@ public: { if (Phase1) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { Phase1 = false; @@ -327,7 +278,41 @@ public: }; +// 42005 - Bloodboil +class spell_gurtogg_bloodboil_bloodboil : public SpellScriptLoader +{ + public: + spell_gurtogg_bloodboil_bloodboil() : SpellScriptLoader("spell_gurtogg_bloodboil_bloodboil") { } + + class spell_gurtogg_bloodboil_bloodboil_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gurtogg_bloodboil_bloodboil_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.size() <= 5) + return; + + // Sort the list of players + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); + // Resize so we only get top 5 + targets.resize(5); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gurtogg_bloodboil_bloodboil_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gurtogg_bloodboil_bloodboil_SpellScript(); + } +}; + void AddSC_boss_gurtogg_bloodboil() { new boss_gurtogg_bloodboil(); + new spell_gurtogg_bloodboil_bloodboil(); } diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 414a3bce14a..0c69a236ef8 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -112,7 +112,7 @@ set(scripts_STAT_SRCS Outland/BlackTemple/instance_black_temple.cpp Outland/BlackTemple/boss_reliquary_of_souls.cpp Outland/BlackTemple/boss_warlord_najentus.cpp - Outland/BlackTemple/boss_bloodboil.cpp + Outland/BlackTemple/boss_gurtogg_bloodboil.cpp Outland/BlackTemple/boss_illidan.cpp Outland/zone_shadowmoon_valley.cpp Outland/zone_blades_edge_mountains.cpp diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index fb438c38efb..4393f72eb1b 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -51,11 +51,7 @@ enum CoilfangGOs class AreaTrigger_at_coilfang_waterfall : public AreaTriggerScript { public: - - AreaTrigger_at_coilfang_waterfall() - : AreaTriggerScript("at_coilfang_waterfall") - { - } + AreaTrigger_at_coilfang_waterfall() : AreaTriggerScript("at_coilfang_waterfall") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -83,11 +79,7 @@ enum LegionTeleporter class AreaTrigger_at_legion_teleporter : public AreaTriggerScript { public: - - AreaTrigger_at_legion_teleporter() - : AreaTriggerScript("at_legion_teleporter") - { - } + AreaTrigger_at_legion_teleporter() : AreaTriggerScript("at_legion_teleporter") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -125,11 +117,7 @@ enum StormwrightShelf class AreaTrigger_at_stormwright_shelf : public AreaTriggerScript { public: - - AreaTrigger_at_stormwright_shelf() - : AreaTriggerScript("at_stormwright_shelf") - { - } + AreaTrigger_at_stormwright_shelf() : AreaTriggerScript("at_stormwright_shelf") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -153,11 +141,7 @@ enum ScentLarkorwi class AreaTrigger_at_scent_larkorwi : public AreaTriggerScript { public: - - AreaTrigger_at_scent_larkorwi() - : AreaTriggerScript("at_scent_larkorwi") - { - } + AreaTrigger_at_scent_larkorwi() : AreaTriggerScript("at_scent_larkorwi") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -184,11 +168,7 @@ enum AtLastRites class AreaTrigger_at_last_rites : public AreaTriggerScript { public: - - AreaTrigger_at_last_rites() - : AreaTriggerScript("at_last_rites") - { - } + AreaTrigger_at_last_rites() : AreaTriggerScript("at_last_rites") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override { @@ -246,7 +226,6 @@ enum Waygate class AreaTrigger_at_sholazar_waygate : public AreaTriggerScript { public: - AreaTrigger_at_sholazar_waygate() : AreaTriggerScript("at_sholazar_waygate") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index ca00b0fc352..4bb88a560bb 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -118,7 +118,8 @@ public: enum GildedBrazier { - NPC_STILLBLADE = 17716, + NPC_STILLBLADE = 17716, + QUEST_THE_FIRST_TRIAL = 9678 }; class go_gilded_brazier : public GameObjectScript @@ -130,7 +131,7 @@ public: { if (go->GetGoType() == GAMEOBJECT_TYPE_GOOBER) { - if (player->GetQuestStatus(9678) == QUEST_STATUS_INCOMPLETE) + if (player->GetQuestStatus(QUEST_THE_FIRST_TRIAL) == QUEST_STATUS_INCOMPLETE) { if (Creature* Stillblade = player->SummonCreature(NPC_STILLBLADE, 8106.11f, -7542.06f, 151.775f, 3.02598f, TEMPSUMMON_DEAD_DESPAWN, 60000)) Stillblade->AI()->AttackStart(player); diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index 21a81d37868..a156a41fcef 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -387,7 +387,7 @@ public: void AddSC_guards() { - new guard_generic; - new guard_shattrath_aldor; - new guard_shattrath_scryer; + new guard_generic(); + new guard_shattrath_aldor(); + new guard_shattrath_scryer(); } diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index 30666d5d2ea..2eb91b7b8fe 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -229,6 +229,6 @@ public: void AddSC_generic_creature() { //new generic_creature; - new trigger_periodic; + new trigger_periodic(); //new trigger_death; } diff --git a/src/server/scripts/World/npc_innkeeper.cpp b/src/server/scripts/World/npc_innkeeper.cpp index b647cccf8ea..be56e57cc9d 100644 --- a/src/server/scripts/World/npc_innkeeper.cpp +++ b/src/server/scripts/World/npc_innkeeper.cpp @@ -134,6 +134,6 @@ public: void AddSC_npc_innkeeper() { - new npc_innkeeper; + new npc_innkeeper(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index c32edff09bc..e67823a2939 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -185,7 +185,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!SpawnAssoc) return; @@ -1520,7 +1519,10 @@ class npc_brewfest_reveler : public CreatureScript enum TrainingDummy { NPC_ADVANCED_TARGET_DUMMY = 2674, - NPC_TARGET_DUMMY = 2673 + NPC_TARGET_DUMMY = 2673, + + EVENT_TD_CHECK_COMBAT = 1, + EVENT_TD_DESPAWN = 2 }; class npc_training_dummy : public CreatureScript @@ -1533,20 +1535,22 @@ public: npc_training_dummyAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); - entry = creature->GetEntry(); } - uint32 entry; - uint32 resetTimer; - uint32 despawnTimer; + EventMap _events; + std::unordered_map<uint64, time_t> _damageTimes; void Reset() override { me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave - resetTimer = 5000; - despawnTimer = 15000; + _events.Reset(); + _damageTimes.clear(); + if (me->GetEntry() != NPC_ADVANCED_TARGET_DUMMY && me->GetEntry() != NPC_TARGET_DUMMY) + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + else + _events.ScheduleEvent(EVENT_TD_DESPAWN, 15000); } void EnterEvadeMode() override @@ -1557,37 +1561,52 @@ public: Reset(); } - void DamageTaken(Unit* /*doneBy*/, uint32& damage) override + void DamageTaken(Unit* doneBy, uint32& damage) override { - resetTimer = 5000; + me->AddThreat(doneBy, float(damage)); // just to create threat reference + _damageTimes[doneBy->GetGUID()] = time(NULL); damage = 0; } void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!me->IsInCombat()) return; if (!me->HasUnitState(UNIT_STATE_STUNNED)) me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate - if (entry != NPC_ADVANCED_TARGET_DUMMY && entry != NPC_TARGET_DUMMY) + _events.Update(diff); + + if (uint32 eventId = _events.ExecuteEvent()) { - if (resetTimer <= diff) + switch (eventId) { - EnterEvadeMode(); - resetTimer = 5000; + case EVENT_TD_CHECK_COMBAT: + { + time_t now = time(NULL); + for (std::unordered_map<uint64, time_t>::iterator itr = _damageTimes.begin(); itr != _damageTimes.end();) + { + // If unit has not dealt damage to training dummy for 5 seconds, remove him from combat + if (itr->second < now - 5) + { + if (Unit* unit = ObjectAccessor::GetUnit(*me, itr->first)) + unit->getHostileRefManager().deleteReference(me); + + itr = _damageTimes.erase(itr); + } + else + ++itr; + } + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + break; + } + case EVENT_TD_DESPAWN: + me->DespawnOrUnsummon(1); + break; + default: + break; } - else - resetTimer -= diff; - return; - } - else - { - if (despawnTimer <= diff) - me->DespawnOrUnsummon(); - else - despawnTimer -= diff; } } diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 81825c9055b..d5ad7f15a04 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile; HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; +std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -767,18 +768,21 @@ ULONG /*SymbolSize*/, PVOID UserContext) { - char szBuffer[1024 * 64]; + char szBuffer[WER_LARGE_BUFFER_SIZE]; + memset(szBuffer, 0, sizeof(szBuffer)); __try { ClearSymbols(); if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, szBuffer, sizeof(szBuffer))) - _tprintf(_T("\t%s\r\n"), szBuffer); + _tprintf(_T("%s"), szBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { - _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name); + _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); + if (szBuffer[0] != '\0') + _tprintf(_T("%s"), szBuffer); } return TRUE; @@ -797,12 +801,6 @@ unsigned /*cbBuffer*/) { char * pszCurrBuffer = pszBuffer; - // Indicate if the variable is a local or parameter - if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) - pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter "); - else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) - pszCurrBuffer += sprintf(pszCurrBuffer, "Local "); - // If it's a function, don't do anything. if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK return false; @@ -824,19 +822,25 @@ unsigned /*cbBuffer*/) // return false; } else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER) - { return false; // Don't try to report register variable - } else { pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable } + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + + // Indicate if the variable is a local or parameter + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) + symbolDetails.top().Prefix = "Parameter "; + else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) + symbolDetails.top().Prefix = "Local "; + // Determine if the variable is a user defined type (UDT). IF so, bHandled // will return true. bool bHandled; pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex, - 0, pVariable, bHandled, pSym->Name, ""); + 0, pVariable, bHandled, pSym->Name, "", false, true); if (!bHandled) { @@ -844,15 +848,19 @@ unsigned /*cbBuffer*/) // variable. Based on the size, we're assuming it's a char, WORD, or // DWORD. BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; // Emit the variable name - pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name); + if (pSym->Name[0] != '\0') + symbolDetails.top().Name = pSym->Name; - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size, - (PVOID)pVariable); + char buffer[50]; + FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); return true; } @@ -868,13 +876,15 @@ DWORD dwTypeIndex, unsigned nestingLevel, DWORD_PTR offset, bool & bHandled, -char* Name, -char* suffix) +const char* Name, +char* suffix, +bool newSymbol, +bool logChildren) { bHandled = false; - if (!StoreSymbol(dwTypeIndex, offset)) - return pszCurrBuffer; + if (newSymbol) + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); DWORD typeTag; if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) @@ -890,19 +900,39 @@ char* suffix) if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0) { LocalFree(pwszTypeName); - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string"); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + symbolDetails.top().Type = "std::string"; + char buffer[50]; + FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; bHandled = true; return pszCurrBuffer; } - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); + char buffer[200]; + wcstombs(buffer, pwszTypeName, sizeof(buffer)); + buffer[199] = '\0'; + if (Name != NULL && Name[0] != '\0') + { + symbolDetails.top().Type = buffer; + symbolDetails.top().Name = Name; + } + else if (buffer[0] != '\0') + symbolDetails.top().Name = buffer; + LocalFree(pwszTypeName); } + else if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - if (strlen(suffix) > 0) - pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix); + if (!StoreSymbol(dwTypeIndex, offset)) + { + // Skip printing address and base class if it has been printed already + if (typeTag == SymTagBaseClass) + bHandled = true; + return pszCurrBuffer; + } DWORD innerTypeID; switch (typeTag) @@ -910,11 +940,9 @@ char* suffix) case SymTagPointerType: if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) { -#define MAX_NESTING_LEVEL 5 - if (nestingLevel >= MAX_NESTING_LEVEL) - break; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); BOOL isReference; SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); @@ -922,44 +950,56 @@ char* suffix) memset(addressStr, 0, sizeof(addressStr)); if (isReference) - addressStr[0] = '&'; + symbolDetails.top().Suffix += "&"; else - addressStr[0] = '*'; + symbolDetails.top().Suffix += "*"; - DWORD_PTR address = *(PDWORD_PTR)offset; - if (address == NULL) - { - pwszTypeName; - if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME, - &pwszTypeName)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); - LocalFree(pwszTypeName); - } + // Try to dereference the pointer in a try/except block since it might be invalid + DWORD_PTR address = DereferenceUnsafePointer(offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr); + char buffer[50]; + FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; - bHandled = true; - return pszCurrBuffer; - } - else - { - FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset); - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - address, bHandled, "", addressStr); + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + + // no need to log any children since the address is invalid anyway + if (address == NULL || address == DWORD_PTR(-1)) + logChildren = false; + + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + address, bHandled, Name, addressStr, false, logChildren); - if (!bHandled) + if (!bHandled) + { + BasicType basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + + if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + symbolDetails.top().Value = "<Unable to read memory>"; + else { - BasicType basicType = GetBasicType(dwTypeIndex, modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the size of the child member ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - bHandled = true; - return pszCurrBuffer; + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + bHandled = true; + return pszCurrBuffer; + } + else if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + { + symbolDetails.top().Value = "<Unable to read memory>"; + bHandled = true; + return pszCurrBuffer; } } break; @@ -970,13 +1010,80 @@ char* suffix) if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) break; - if (innerTypeTag == SymTagPointerType) + switch (innerTypeTag) { - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); + case SymTagUDT: + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagPointerType: + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagArrayType: + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + default: + break; + } + } + break; + case SymTagArrayType: + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) + { + symbolDetails.top().HasChildren = true; + + BasicType basicType = btNoType; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, Name, "", false, false); + + // Set Value back to an empty string since the Array object itself has no value, only its elements have + symbolDetails.top().Value = ""; + + DWORD elementsCount; + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) + symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]"; + else + symbolDetails.top().Suffix += "[<unknown count>]"; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, "", ""); + if (!bHandled) + { + basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + bHandled = true; + } + + // Get the size of the child member + ULONG64 length; + SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); + + char buffer[50]; + switch (basicType) + { + case btChar: + case btStdString: + FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + break; + default: + for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) + { + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + symbolDetails.top().Suffix += "[" + std::to_string(index) + "]"; + FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); + symbolDetails.top().Value = buffer; + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + } + break; } + + return pszCurrBuffer; } break; case SymTagBaseType: @@ -1013,26 +1120,37 @@ char* suffix) return pszCurrBuffer; } - // Append a line feed - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - // Iterate through each of the children for (unsigned i = 0; i < dwChildrenCount; i++) { DWORD symTag; SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); - if (symTag == SymTagFunction || symTag == SymTagTypedef) + if (symTag == SymTagFunction || + symTag == SymTagEnum || + symTag == SymTagTypedef || + symTag == SymTagVTable) continue; - // Add appropriate indentation level (since this routine is recursive) - for (unsigned j = 0; j <= nestingLevel+1; j++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + // Ignore static fields + DWORD dataKind; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind); + if (dataKind == DataIsStaticLocal || + dataKind == DataIsGlobal || + dataKind == DataIsStaticMember) + continue; + + + symbolDetails.top().HasChildren = true; + if (!logChildren) + { + bHandled = false; + return pszCurrBuffer; + } // Recurse for each of the child types bool bHandled2; BasicType basicType = GetBasicType(children.ChildId[i], modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the offset of the child member, relative to its parent DWORD dwMemberOffset; @@ -1044,11 +1162,14 @@ char* suffix) pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, children.ChildId[i], nestingLevel+1, - dwFinalOffset, bHandled2, ""/*Name */, ""); + dwFinalOffset, bHandled2, ""/*Name */, "", true, true); // If the child wasn't a UDT, format it appropriately if (!bHandled2) { + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + // Get the real "TypeId" of the child. We need this for the // SymGetTypeInfo(TI_GET_TYPEID) call below. DWORD typeId; @@ -1059,75 +1180,75 @@ char* suffix) ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, - length, (PVOID)dwFinalOffset); - - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); } bHandled = true; return pszCurrBuffer; } -char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, +void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, -PVOID pAddress) +PVOID pAddress, +size_t bufferSize) { __try { switch (basicType) { case btChar: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress); + { + if (strlen((char*)pAddress) > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress); break; + } case btStdString: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str()); + { + std::string* value = static_cast<std::string*>(pAddress); + if (value->length() > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str()); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str()); break; + } default: // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) if (length == 1) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress); else if (length == 2) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress); else if (length == 4) { if (basicType == btFloat) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress); - } - else if (basicType == btChar) - { - if (!IsBadStringPtr(*(PSTR*)pAddress, 32)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"", - *(PSTR*)pAddress); - } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", - *(PDWORD)pAddress); - } + pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress); else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress); } else if (length == 8) { if (basicType == btFloat) { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf", + pszCurrBuffer += sprintf(pszCurrBuffer, "%lf", *(double *)pAddress); } else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", *(DWORD64*)pAddress); } else { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress); #endif } break; @@ -1136,13 +1257,11 @@ PVOID pAddress) __except (EXCEPTION_EXECUTE_HANDLER) { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress); #endif } - - return pszCurrBuffer; } BasicType @@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) return btNoType; } +DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) +{ + __try + { + return *(PDWORD_PTR)address; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return DWORD_PTR(-1); + } +} + //============================================================================ // Helper function that writes to the report file, and allows the user to use // printf style formating //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[1024 * 64]; + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; DWORD cbWritten; va_list argptr; @@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset) void WheatyExceptionReport::ClearSymbols() { symbols.clear(); + while (!symbolDetails.empty()) + symbolDetails.pop(); +} + +char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer) +{ + // Log current symbol and then add another to the stack to keep the hierarchy format + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.emplace(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer) +{ + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.pop(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer) +{ + if (symbolDetails.empty()) + return pszCurrBuffer; + + // Don't log anything if has been logged already or if it's empty + if (symbolDetails.top().Logged || symbolDetails.top().empty()) + return pszCurrBuffer; + + // Add appropriate indentation level (since this routine is recursive) + for (size_t i = 0; i < symbolDetails.size(); i++) + pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + + pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str()); + + return pszCurrBuffer; } #endif // _WIN32 diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index e1cc3050929..9137b91aac9 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -5,12 +5,13 @@ #include <dbghelp.h> #include <set> -#if _MSC_VER < 1400 -# define countof(array) (sizeof(array) / sizeof(array[0])) -#else -# include <stdlib.h> -# define countof _countof -#endif // _MSC_VER < 1400 +#include <stdlib.h> +#include <stack> +#define countof _countof + +#define WER_MAX_ARRAY_ELEMENTS_COUNT 10 +#define WER_MAX_NESTING_LEVEL 5 +#define WER_LARGE_BUFFER_SIZE 1024 * 128 enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK { @@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON btStdString = 101 }; +enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK +{ + DataIsUnknown, + DataIsLocal, + DataIsStaticLocal, + DataIsParam, + DataIsObjectPtr, + DataIsFileStatic, + DataIsGlobal, + DataIsMember, + DataIsStaticMember, + DataIsConstant +}; + const char* const rgBaseType[] = { - " <user defined> ", // btNoType = 0, - " void ", // btVoid = 1, - " char* ", // btChar = 2, - " wchar_t* ", // btWChar = 3, - " signed char ", - " unsigned char ", - " int ", // btInt = 6, - " unsigned int ", // btUInt = 7, - " float ", // btFloat = 8, - " <BCD> ", // btBCD = 9, - " bool ", // btBool = 10, - " short ", - " unsigned short ", - " long ", // btLong = 13, - " unsigned long ", // btULong = 14, - " __int8 ", - " __int16 ", - " __int32 ", - " __int64 ", - " __int128 ", - " unsigned __int8 ", - " unsigned __int16 ", - " unsigned __int32 ", - " unsigned __int64 ", - " unsigned __int128 ", - " <currency> ", // btCurrency = 25, - " <date> ", // btDate = 26, - " VARIANT ", // btVariant = 27, - " <complex> ", // btComplex = 28, - " <bit> ", // btBit = 29, - " BSTR ", // btBSTR = 30, - " HRESULT " // btHresult = 31 + "<user defined>", // btNoType = 0, + "void", // btVoid = 1, + "char",//char* // btChar = 2, + "wchar_t*", // btWChar = 3, + "signed char", + "unsigned char", + "int", // btInt = 6, + "unsigned int", // btUInt = 7, + "float", // btFloat = 8, + "<BCD>", // btBCD = 9, + "bool", // btBool = 10, + "short", + "unsigned short", + "long", // btLong = 13, + "unsigned long", // btULong = 14, + "int8", + "int16", + "int32", + "int64", + "int128", + "uint8", + "uint16", + "uint32", + "uint64", + "uint128", + "<currency>", // btCurrency = 25, + "<date>", // btDate = 26, + "VARIANT", // btVariant = 27, + "<complex>", // btComplex = 28, + "<bit>", // btBit = 29, + "BSTR", // btBSTR = 30, + "HRESULT" // btHresult = 31 }; struct SymbolPair @@ -92,6 +107,39 @@ struct SymbolPair }; typedef std::set<SymbolPair> SymbolPairs; +struct SymbolDetail +{ + SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {} + + std::string ToString() + { + Logged = true; + std::string formatted = Prefix + Type + Suffix; + if (!Name.empty()) + { + if (!formatted.empty()) + formatted += " "; + formatted += Name; + } + if (!Value.empty()) + formatted += " = " + Value; + return formatted; + } + + bool empty() const + { + return Value.empty() && !HasChildren; + } + + std::string Prefix; + std::string Type; + std::string Suffix; + std::string Name; + std::string Value; + bool Logged; + bool HasChildren; +}; + class WheatyExceptionReport { public: @@ -122,11 +170,12 @@ class WheatyExceptionReport static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); - static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*); + static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool); - static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress); + static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize); static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); + static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); @@ -141,6 +190,12 @@ class WheatyExceptionReport static HANDLE m_hDumpFile; static HANDLE m_hProcess; static SymbolPairs symbols; + static std::stack<SymbolDetail> symbolDetails; + + static char* PushSymbolDetail(char* pszCurrBuffer); + static char* PopSymbolDetail(char* pszCurrBuffer); + static char* PrintSymbolDetail(char* pszCurrBuffer); + }; extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index d1d2ef11848..78a29dbedf6 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -45,6 +45,7 @@ include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/dep/gsoap ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index 591e0cc8e98..c0268680657 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -18,7 +18,9 @@ set(mmap_gen_Includes ${CMAKE_SOURCE_DIR}/dep/bzip2 ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/game/Conditions ${CMAKE_SOURCE_DIR}/src/server/collision |
