diff options
Diffstat (limited to 'src')
22 files changed, 482 insertions, 213 deletions
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index bcb1dd3fddc..60e9b734b13 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -540,7 +540,7 @@ bool AuthSession::HandleLogonProof() packet << uint8(3); packet << uint8(0); SendPacket(packet); - return false; + return true; } } diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp index 529e236d1ed..170954a86f4 100644 --- a/src/server/database/Updater/DBUpdater.cpp +++ b/src/server/database/Updater/DBUpdater.cpp @@ -311,7 +311,7 @@ bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool) } case LOCATION_DOWNLOAD: { - TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"http://www.trinitycore.org/f/files/category/1-database/\"" \ + TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"https://github.com/TrinityCore/TrinityCore/releases\"" \ " and place it in your server directory.", base.filename().generic_string().c_str()); break; } diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index afca851974a..6d058f405a8 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -72,9 +72,10 @@ class Minion : public TempSummon Unit* GetOwner() const { return m_owner; } float GetFollowAngle() const override { return m_followAngle; } void SetFollowAngle(float angle) { m_followAngle = angle; } - bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet - bool IsSpiritWolf() const {return GetEntry() == 29264;} // Spirit wolf from feral spirits + bool IsPetGhoul() const { return GetEntry() == 26125; } // Ghoul may be guardian or pet + bool IsSpiritWolf() const { return GetEntry() == 29264; } // Spirit wolf from feral spirits bool IsGuardianPet() const; + bool IsRisenAlly() const { return GetEntry() == 30230; } protected: Unit* const m_owner; float m_followAngle; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 9aabed67243..6f0b9f89e44 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1803,6 +1803,8 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true if (Unit* owner = GetOwner()) { trigger->setFaction(owner->getFaction()); + if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) + trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, owner->GetGUID()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 14b555adde9..4fdf25e41c3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1242,6 +1242,9 @@ void Player::Update(uint32 p_time) if (charmer->GetTypeId() == TYPEID_UNIT && charmer->IsAlive()) UpdateCharmedAI(); + if (GetAI() && IsAIEnabled) + GetAI()->UpdateAI(p_time); + // Update items that have just a limited lifetime if (now > m_Last_tick) UpdateItemDuration(uint32(now - m_Last_tick)); @@ -1476,8 +1479,8 @@ void Player::Update(uint32 p_time) _pendingBindTimer -= p_time; } - // not auto-free ghost from body in instances - if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) + // not auto-free ghost from body in instances or if its affected by risen ally + if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION) && !IsGhouled()) { if (p_time >= m_deathTimer) { @@ -2157,7 +2160,7 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) co return true; if (spellInfo->Effects[index].IsEffect(SPELL_EFFECT_ATTACK_ME)) return true; - + return Unit::IsImmunedToSpellEffect(spellInfo, index); } @@ -4731,6 +4734,32 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) } } +void Player::SendGhoulResurrectRequest(Player* target) +{ + target->m_ghoulResurrectPlayerGUID = GetGUID(); + + WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + 1 + 1); + data << uint64(GetGUID()); + data << uint32(0); + data << uint8(0); + data << uint8(0); + target->GetSession()->SendPacket(&data); +} + +void Player::GhoulResurrect() +{ + CastSpell(this, 46619 /*SPELL_DK_RAISE_ALLY*/, true, nullptr, nullptr, m_ghoulResurrectPlayerGUID); + + m_ghoulResurrectPlayerGUID = ObjectGuid::Empty; +} + +void Player::RemoveGhoul() +{ + if (IsGhouled()) + if (Creature* ghoul = ObjectAccessor::GetCreature(*this, m_ghoulResurrectGhoulGUID)) + ghoul->DespawnOrUnsummon(); // Raise Ally aura will handle unauras +} + void Player::KillPlayer() { if (IsFlying() && !GetTransport()) @@ -18594,31 +18623,6 @@ void Player::SendSavedInstances() } } -/// convert the player's binds to the group -void Player::ConvertInstancesToGroup(Player* player, Group* group, bool switchLeader) -{ - // copy all binds to the group, when changing leader it's assumed the character - // will not have any solo binds - - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) - { - if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first)) - group->BindToInstance(itr->second.save, itr->second.perm, false); - - // permanent binds are not removed - if (switchLeader && !itr->second.perm) - { - // increments itr in call - player->UnbindInstance(itr, Difficulty(i), false); - } - else - ++itr; - } - } -} - bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report) { if (!IsGameMaster() && ar) @@ -18707,7 +18711,7 @@ bool Player::CheckInstanceValidity(bool /*isLogin*/) // game masters' instances are always valid if (IsGameMaster()) return true; - + // non-instances are always valid Map* map = GetMap(); if (!map || !map->IsDungeon()) @@ -20181,6 +20185,12 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) void Player::StopCastingCharm() { + if (IsGhouled()) + { + RemoveGhoul(); + return; + } + Unit* charm = GetCharm(); if (!charm) return; @@ -21533,6 +21543,14 @@ void Player::setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, flo m_resurrectHealth = health; m_resurrectMana = mana; } + +void Player::clearResurrectRequestData() +{ + setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); + + m_ghoulResurrectPlayerGUID = ObjectGuid::Empty; + m_ghoulResurrectGhoulGUID = ObjectGuid::Empty; +} //slot to be excluded while counting bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) { @@ -22627,46 +22645,16 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) if (!found) return; - // prevent learn non first rank unknown profession and second specialization for same profession) uint32 learned_0 = spellInfo->Effects[0].TriggerSpell; - if (sSpellMgr->GetSpellRank(learned_0) > 1 && !HasSpell(learned_0)) + if (!HasSpell(learned_0)) { SpellInfo const* learnedInfo = sSpellMgr->GetSpellInfo(learned_0); if (!learnedInfo) return; - // not have first rank learned (unlearned prof?) - if (!HasSpell(learnedInfo->GetFirstRankSpell()->Id)) - return; - - SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(learned_0); - for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second; ++itr2) - { - uint32 profSpell = itr2->second; - - // specialization - if (learnedInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effects[1].Effect == 0 && profSpell) - { - // search other specialization for same prof - for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED || itr->first == learned_0) - continue; - - SpellInfo const* itrInfo = sSpellMgr->GetSpellInfo(itr->first); - if (!itrInfo) - return; - - // compare only specializations - if (itrInfo->Effects[0].Effect != SPELL_EFFECT_TRADE_SKILL || itrInfo->Effects[1].Effect != 0) - continue; - - // compare same chain spells - if (sSpellMgr->IsSpellRequiringSpell(itr->first, profSpell)) - return; - } - } - } + // profession specialization can be re-learned from npc + if (learnedInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effects[1].Effect == 0 && !learnedInfo->SpellLevel) + return; } CastSpell(this, spell_id, true); @@ -23465,6 +23453,8 @@ uint32 Player::GetBaseWeaponSkillValue(WeaponAttackType attType) const void Player::ResurrectUsingRequestData() { + RemoveGhoul(); + /// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); @@ -23909,6 +23899,31 @@ void Player::SetViewpoint(WorldObject* target, bool apply) //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0); //GetSession()->SendPacket(&data); } + + // HACK: Make sure update for PLAYER_FARSIGHT is received before SMSG_PET_SPELLS to properly hide "Release spirit" dialog + if (target->GetTypeId() == TYPEID_UNIT && static_cast<Unit*>(target)->HasUnitTypeMask(UNIT_MASK_MINION) && static_cast<Minion*>(target)->IsRisenAlly()) + { + if (apply) + { + UpdateDataMapType update_players; + BuildUpdate(update_players); + WorldPacket packet; + for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) + { + iter->second.BuildPacket(&packet); + iter->first->GetSession()->SendPacket(&packet); + packet.clear(); + } + } + else + { + m_deathTimer = 6 * MINUTE * IN_MILLISECONDS; + + // Reset "Release spirit" timer clientside + WorldPacket data(SMSG_FORCED_DEATH_UPDATE); + SendDirectMessage(&data); + } + } } WorldObject* Player::GetViewpoint() const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0072ec4125f..e7af827e9c7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1576,7 +1576,7 @@ class Player : public Unit, public GridObject<Player> void UpdatePotionCooldown(Spell* spell = NULL); void setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana); - void clearResurrectRequestData() { setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); } + void clearResurrectRequestData(); bool isResurrectRequestedBy(ObjectGuid guid) const { return !m_resurrectGUID.IsEmpty() && m_resurrectGUID == guid; } bool isResurrectRequested() const { return !m_resurrectGUID.IsEmpty(); } void ResurrectUsingRequestData(); @@ -1770,6 +1770,15 @@ class Player : public Unit, public GridObject<Player> void ResurrectPlayer(float restore_percent, bool applySickness = false); void BuildPlayerRepop(); void RepopAtGraveyard(); + void SendGhoulResurrectRequest(Player* target); + bool IsValidGhoulResurrectRequest(ObjectGuid guid) + { + return !m_ghoulResurrectPlayerGUID.IsEmpty() && m_ghoulResurrectPlayerGUID == guid; + } + void GhoulResurrect(); + void SetGhoulResurrectGhoulGUID(ObjectGuid guid) { m_ghoulResurrectGhoulGUID = guid; } + ObjectGuid GetGhoulResurrectGhoulGUID() { return m_ghoulResurrectGhoulGUID; } + void RemoveGhoul(); void DurabilityLossAll(double percent, bool inventory); void DurabilityLoss(Item* item, double percent); @@ -2116,7 +2125,6 @@ class Player : public Unit, public GridObject<Player> bool HasPendingBind() const { return _pendingBindId > 0; } void SendRaidInfo(); void SendSavedInstances(); - static void ConvertInstancesToGroup(Player* player, Group* group, bool switchLeader); bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false); bool CheckInstanceValidity(bool /*isLogin*/); bool CheckInstanceCount(uint32 instanceId) const; @@ -2404,6 +2412,9 @@ class Player : public Unit, public GridObject<Player> float m_resurrectX, m_resurrectY, m_resurrectZ; uint32 m_resurrectHealth, m_resurrectMana; + ObjectGuid m_ghoulResurrectPlayerGUID; + ObjectGuid m_ghoulResurrectGhoulGUID; + WorldSession* m_session; typedef std::list<Channel*> JoinedChannelsList; @@ -2503,7 +2514,7 @@ class Player : public Unit, public GridObject<Player> bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; } void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } void ScheduleDelayedOperation(uint32 operation) { if (operation < DELAYED_END) m_DelayedOperations |= operation; } - + bool IsInstanceLoginGameMasterException() const; MapReference m_mapRef; diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 775a3c96c46..a8e13a9f7db 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -499,7 +499,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness UpdateSpellDamageAndHealingBonus(); - if (pet && pet->IsPetGhoul()) // At melee attack power change for DK pet + if (pet && (pet->IsPetGhoul() || pet->IsRisenAlly())) // At melee attack power change for DK pet pet->UpdateAttackPowerAndDamage(); if (guardian && guardian->IsSpiritWolf()) // At melee attack power change for Shaman feral spirit @@ -1113,7 +1113,7 @@ bool Guardian::UpdateStats(Stats stat) Unit* owner = GetOwner(); // Handle Death Knight Glyphs and Talents float mod = 0.75f; - if (IsPetGhoul() && (stat == STAT_STAMINA || stat == STAT_STRENGTH)) + if ((IsPetGhoul() || IsRisenAlly()) && (stat == STAT_STAMINA || stat == STAT_STRENGTH)) { if (stat == STAT_STAMINA) mod = 0.3f; // Default Owner's Stamina scale @@ -1329,7 +1329,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f * mod; SetBonusDamage(int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f * mod)); } - else if (IsPetGhoul()) //ghouls benefit from deathknight's attack power (may be summon pet or not) + else if (IsPetGhoul() || IsRisenAlly()) //ghouls benefit from deathknight's attack power (may be summon pet or not) { bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.22f; SetBonusDamage(int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.1287f)); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index fcd2535dad9..261f4faf1a8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -9395,7 +9395,7 @@ void Unit::SetMinion(Minion *minion, bool apply) minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true); // Ghoul pets have energy instead of mana (is anywhere better place for this code?) - if (minion->IsPetGhoul()) + if (minion->IsPetGhoul() || minion->IsRisenAlly()) minion->setPowerType(POWER_ENERGY); // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again @@ -13625,6 +13625,9 @@ void Unit::RemoveFromWorld() RemoveAreaAurasDueToLeaveWorld(); + if (IsCharmed()) + RemoveCharmedBy(nullptr); + if (GetCharmerGUID()) { TC_LOG_FATAL("entities.unit", "Unit %u has charmer guid when removed from world", GetEntry()); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8fc93f24351..90d312f422a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1598,6 +1598,7 @@ class Unit : public WorldObject bool IsAlive() const { return (m_deathState == ALIVE); } bool isDying() const { return (m_deathState == JUST_DIED); } bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); } + bool IsGhouled() const { return HasAura(46619 /*SPELL_DK_RAISE_ALLY*/); } DeathState getDeathState() const { return m_deathState; } virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index d0e70eb3dbb..8ebc71b0146 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -148,10 +148,9 @@ bool Group::Create(Player* leader) CharacterDatabase.Execute(stmt); + Group::ConvertLeaderInstancesToGroup(leader, this, false); ASSERT(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong. - - Player::ConvertInstancesToGroup(leader, this, false); } else if (!AddMember(leader)) return false; @@ -375,9 +374,7 @@ bool Group::AddMember(Player* player) player->SetGroup(this, subGroup); // if the same group invites the player back, cancel the homebind timer - InstanceGroupBind* bind = GetBoundInstance(player); - if (bind && bind->save->GetInstanceId() == player->GetInstanceId()) - player->m_InstanceValid = true; + player->m_InstanceValid = player->CheckInstanceValidity(false); if (!isRaidGroup()) // reset targetIcons for non-raid-groups { @@ -654,7 +651,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid) } // Copy the permanent binds from the new leader to the group - Player::ConvertInstancesToGroup(newLeader, this, true); + Group::ConvertLeaderInstancesToGroup(newLeader, this, true); // Update the group leader PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEADER); @@ -680,6 +677,42 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid) BroadcastPacket(&data, true); } +/// convert the player's binds to the group +void Group::ConvertLeaderInstancesToGroup(Player* player, Group* group, bool switchLeader) +{ + // copy all binds to the group, when changing leader it's assumed the character + // will not have any solo binds + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + for (Player::BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) + { + if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first)) + group->BindToInstance(itr->second.save, itr->second.perm, false); + + // permanent binds are not removed + if (switchLeader && !itr->second.perm) + { + // increments itr in call + player->UnbindInstance(itr, Difficulty(i), false); + } + else + ++itr; + } + } + + /* if group leader is in a non-raid dungeon map and nobody is actually bound to this map then the group can "take over" the instance * + * (example: two-player group disbanded by disconnect where the player reconnects within 60 seconds and the group is reformed) */ + if (Map* playerMap = player->GetMap()) + if (!switchLeader && playerMap->IsNonRaidDungeon()) + if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(playerMap->GetInstanceId())) + if (save->GetGroupCount() == 0 && save->GetPlayerCount() == 0) + { + TC_LOG_DEBUG("maps", "Group::ConvertLeaderInstancesToGroup: Group for player %s is taking over unbound instance map %d with Id %d", player->GetName().c_str(), playerMap->GetId(), playerMap->GetInstanceId()); + // if nobody is saved to this, then the save wasn't permanent + group->BindToInstance(save, false, false); + } +} + void Group::Disband(bool hideDestroy /* = false */) { sScriptMgr->OnGroupDisband(this); diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 4d2ee57c9b2..42fd9b582e8 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -194,6 +194,7 @@ class Group bool AddMember(Player* player); bool RemoveMember(ObjectGuid guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = NULL); void ChangeLeader(ObjectGuid guid); + static void ConvertLeaderInstancesToGroup(Player* player, Group* group, bool switchLeader); void SetLootMethod(LootMethod method); void SetLooterGuid(ObjectGuid guid); void SetMasterLooterGuid(ObjectGuid guid); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index e4ee057d6ea..758d5af83f7 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -71,6 +71,7 @@ void WorldSession::HandleRepopRequestOpcode(WorldPacket& recvData) } //this is spirit release confirm? + GetPlayer()->RemoveGhoul(); GetPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); GetPlayer()->BuildPlayerRepop(); GetPlayer()->RepopAtGraveyard(); @@ -776,6 +777,12 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData) return; } + if (GetPlayer()->IsValidGhoulResurrectRequest(guid)) + { + GetPlayer()->GhoulResurrect(); + return; + } + if (!GetPlayer()->isResurrectRequestedBy(guid)) return; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 27fb55bb4da..a2cb84359f2 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3030,7 +3030,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) { if (group) { - // solo saves should be reset when entering a group + // solo saves should have been reset when the map was loaded InstanceGroupBind* groupBind = group->GetBoundInstance(this); if (playerBind && playerBind->save != mapSave) { diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 74d490bf941..47b9b376b1e 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -163,7 +163,11 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, u { groupBind = group->GetBoundInstance(this); if (groupBind) + { + // solo saves should be reset when entering a group's instance + player->UnbindInstance(GetId(), player->GetDifficulty(IsRaid())); pSave = groupBind->save; + } } } if (pSave) diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index fbe5febdbb1..3fa16cf4517 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1042,6 +1042,12 @@ std::vector<ChatCommand> ScriptMgr::GetChatCommands() table.insert(table.end(), cmds.begin(), cmds.end()); } + // Sort commands in alphabetical order + std::sort(table.begin(), table.end(), [](const ChatCommand& a, const ChatCommand&b) + { + return strcmp(a.Name, b.Name) < 0; + }); + return table; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0cfcf05c4b5..aed7c0db043 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4207,21 +4207,16 @@ void Spell::SendResurrectRequest(Player* target) { // get resurrector name for creature resurrections, otherwise packet will be not accepted // for player resurrections the name is looked up by guid - std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER - ? "" - : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex())); + std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER ? + "" : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex())); - WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+sentName.size()+1+1+1+4)); + WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + sentName.size() + 1 + 1 + 1); data << uint64(m_caster->GetGUID()); data << uint32(sentName.size() + 1); - data << sentName; - data << uint8(0); // null terminator - - data << uint8(m_caster->GetTypeId() == TYPEID_PLAYER ? 0 : 1); // "you'll be afflicted with resurrection sickness" + data << uint8(m_caster->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness" // override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute - if (m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER)) - data << uint32(0); + data << uint8(!m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER)); target->GetSession()->SendPacket(&data); } @@ -5512,7 +5507,7 @@ SpellCastResult Spell::CheckPetCast(Unit* target) // dead owner (pets still alive when owners ressed?) if (Unit* owner = m_caster->GetCharmerOrOwner()) - if (!owner->IsAlive()) + if (!owner->IsAlive() && !owner->IsGhouled()) return SPELL_FAILED_CASTER_DEAD; if (!target && m_targets.GetUnitTarget()) diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 9098bc13096..9b553ca4791 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -72,7 +72,7 @@ public: static bool HandleLearnCommand(ChatHandler* handler, char const* args) { - Player* targetPlayer = handler->getSelectedPlayer(); + Player* targetPlayer = handler->getSelectedPlayerOrSelf(); if (!targetPlayer) { diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp index 083662df7ba..fbcea958429 100644 --- a/src/server/scripts/Kalimdor/zone_moonglade.cpp +++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp @@ -25,7 +25,6 @@ EndScriptData */ /* ContentData npc_bunthen_plainswind -npc_great_bear_spirit npc_silva_filnaveth npc_clintar_spirit npc_clintar_dreamwalker diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 31dd7de96ca..fafe3113835 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -236,6 +236,7 @@ class boss_professor_putricide : public CreatureScript summons.DespawnAll(); SetPhase(PHASE_COMBAT_1); _experimentState = EXPERIMENT_STATE_OOZE; + me->SetReactState(REACT_DEFENSIVE); me->SetWalk(false); if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 7f5d2b95dc0..7ea87a3c0c4 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -560,6 +560,10 @@ public: me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } else PoisonTimer -= diff; } + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); } }; }; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 59caf4b7f7b..3cea620559a 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -22,6 +22,7 @@ */ #include "Player.h" +#include "UnitAI.h" #include "ScriptMgr.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -63,7 +64,10 @@ enum DeathKnightSpells SPELL_DK_UNHOLY_PRESENCE = 48265, SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772, SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, - SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284 + SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, + SPELL_DK_RAISE_ALLY_INITIAL = 61999, + SPELL_DK_RAISE_ALLY = 46619, + SPELL_DK_GHOUL_THRASH = 47480 }; enum DeathKnightSpellIcons @@ -1699,6 +1703,303 @@ public: } }; +enum RaiseAllyMisc +{ + TEXT_RISE_ALLY = 33055, + + SPELL_DK_RISEN_GHOUL_SELF_STUN = 47466, + SPELL_DK_RISEN_GHOUL_SPAWN__IN = 47448, + SPELL_DK_SUMMON_HEAL = 36492, + SPELL_DK_DEATH_KNIGHT_RUNE_WEAPON_SCALING_02 = 51906, + SPELL_DK_DEATH_KNIGHT_PET_SCALING_01 = 54566, + SPELL_DK_DEATH_KNIGHT_PET_SCALING_03 = 61697, + SPELL_DK_MIRROR_NAME = 62224, + SPELL_DK_MIRROR_NAME_TRIGGERED = 62214, + SPELL_DK_PET_SCALING___MASTER_SPELL_03___INTELLECT_SPIRIT_RESILIENCE = 67557, + SPELL_DK_PET_SCALING___MASTER_SPELL_06___SPELL_HIT_EXPERTISE_SPELL_PENETRATION = 67561, + + SPELL_GHOUL_FRENZY = 62218, + + NPC_RISEN_ALLY = 30230 +}; + +// 61999 - Raise Ally Initial +class spell_dk_raise_ally_initial : public SpellScriptLoader +{ +public: + spell_dk_raise_ally_initial() : SpellScriptLoader("spell_dk_raise_ally_initial") { } + + class spell_dk_raise_ally_initial_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_raise_ally_initial_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY_INITIAL)) + return false; + return true; + } + + SpellCastResult CheckCast() + { + // Raise Ally cannot be casted on alive players + Unit* target = GetExplTargetUnit(); + if (!target) + return SPELL_FAILED_NO_VALID_TARGETS; + if (target->IsAlive()) + return SPELL_FAILED_TARGET_NOT_DEAD; + if (Player* playerCaster = GetCaster()->ToPlayer()) + if (playerCaster->InArena()) + return SPELL_FAILED_NOT_IN_ARENA; + if (target->IsGhouled()) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + + return SPELL_CAST_OK; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Player* caster = GetCaster()->ToPlayer(); + Player* target = GetHitPlayer(); + if (caster && target) + caster->SendGhoulResurrectRequest(target); + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_dk_raise_ally_initial_SpellScript::CheckCast); + OnEffectHitTarget += SpellEffectFn(spell_dk_raise_ally_initial_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_raise_ally_initial_SpellScript(); + } +}; + +class player_ghoulAI : public PlayerAI +{ + public: + player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID) { } + + void UpdateAI(uint32 /*diff*/) override + { + if (Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID)) + { + if (!ghoul->IsAlive()) + me->RemoveAura(SPELL_DK_RAISE_ALLY); + } + else + me->RemoveAura(SPELL_DK_RAISE_ALLY); + } + + private: + ObjectGuid _ghoulGUID; +}; + +// 46619 - Raise Ally +class spell_dk_raise_ally : public SpellScriptLoader +{ +public: + spell_dk_raise_ally() : SpellScriptLoader("spell_dk_raise_ally") { } + + class spell_dk_raise_ally_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_raise_ally_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY)) + return false; + return true; + } + + void SendText() + { + Player* caster = GetCaster()->ToPlayer(); + Unit* original = GetOriginalCaster(); + if (caster && original) + original->Whisper(TEXT_RISE_ALLY, caster, true); + } + + void HandleSummon(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + Unit* caster = GetCaster(); + Unit* originalCaster = GetOriginalCaster(); + if (!originalCaster) + return; + + uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue); + + //! HACK - StatSystem needs further develop to enable update on Puppet stats + // Using same summon properties as Raise Dead 46585 (Guardian) - EffectMiscValueB = 829 + SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(829); + + uint32 duration = uint32(GetSpellInfo()->GetDuration()); + Position pos = caster->GetPosition(); + + TempSummon* summon = originalCaster->GetMap()->SummonCreature(entry, pos, properties, duration, originalCaster, GetSpellInfo()->Id); + if (!summon) + return; + + //! Leaving this here as it's necessary if statsystem problem is solved + /* + Default SUMMON_CATEGORY_PUPPET behaviour sets possesor as originalCaster, + in this case we need caster as possesor and originalCaster as owner + */ + //summon->RemoveCharmedBy(NULL); + + summon->SetCharmedBy(caster, CHARM_TYPE_POSSESS); + + summon->CastSpell(summon, SPELL_DK_RISEN_GHOUL_SELF_STUN, true); + summon->CastSpell(summon, SPELL_DK_RISEN_GHOUL_SPAWN__IN, true); + summon->CastSpell(summon, SPELL_DK_SUMMON_HEAL, true); + summon->CastSpell(caster, SPELL_DK_MIRROR_NAME, true); + caster->CastSpell(summon, SPELL_DK_MIRROR_NAME_TRIGGERED, true); + summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_RUNE_WEAPON_SCALING_02, true); + summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_PET_SCALING_01, true); + summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_PET_SCALING_03, true); + summon->CastSpell(summon, SPELL_DK_PET_SCALING___MASTER_SPELL_03___INTELLECT_SPIRIT_RESILIENCE, true); + summon->CastSpell(summon, SPELL_DK_PET_SCALING___MASTER_SPELL_06___SPELL_HIT_EXPERTISE_SPELL_PENETRATION, true); + + // SMSG_POWER_UPDATE is sent + summon->SetMaxPower(POWER_ENERGY, 100); + + if (Player* player = GetCaster()->ToPlayer()) + player->SetGhoulResurrectGhoulGUID(summon->GetGUID()); + } + + void Register() override + { + AfterHit += SpellHitFn(spell_dk_raise_ally_SpellScript::SendText); + OnEffectHit += SpellEffectFn(spell_dk_raise_ally_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_raise_ally_SpellScript(); + } + + class spell_dk_raise_ally_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_raise_ally_AuraScript); + + public: + spell_dk_raise_ally_AuraScript() + { + oldAI = nullptr; + oldAIState = false; + } + + private: + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Player* player = GetTarget()->ToPlayer(); + if (!player || player->GetGhoulResurrectGhoulGUID().IsEmpty()) + return; + + oldAI = player->GetAI(); + oldAIState = player->IsAIEnabled; + player->SetAI(new player_ghoulAI(player, player->GetGhoulResurrectGhoulGUID())); + player->IsAIEnabled = true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Player* player = GetTarget()->ToPlayer(); + if (!player) + return; + + player->IsAIEnabled = oldAIState; + UnitAI* thisAI = player->GetAI(); + player->SetAI(oldAI); + delete thisAI; + + // Dismiss ghoul if necessary + if (Creature* ghoul = ObjectAccessor::GetCreature(*player, player->GetGhoulResurrectGhoulGUID())) + { + ghoul->RemoveCharmedBy(nullptr); + ghoul->DespawnOrUnsummon(1000); + } + + player->SetGhoulResurrectGhoulGUID(ObjectGuid::Empty); + player->RemoveAura(SPELL_GHOUL_FRENZY); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_dk_raise_ally_AuraScript::OnApply, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_dk_raise_ally_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + + UnitAI* oldAI; + bool oldAIState; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_dk_raise_ally_AuraScript(); + } +}; + +// 47480 - Thrash +class spell_dk_ghoul_thrash : public SpellScriptLoader +{ +public: + spell_dk_ghoul_thrash() : SpellScriptLoader("spell_dk_ghoul_thrash") { } + + class spell_dk_ghoul_thrash_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_ghoul_thrash_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_THRASH)) + return false; + return true; + } + + void CalcDamage() + { + if (Aura* aur = GetCaster()->GetAura(SPELL_GHOUL_FRENZY)) + { + int32 damage = GetHitDamage(); + damage += int32(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK) * 0.05f * aur->GetStackAmount()); + aur->Remove(); + SetHitDamage(damage); + } + + /* + Also remove aura from charmer + SPELL_GHOUL_FRENZY (62218) - Targets (1, 27) (TARGET_UNIT_CASTER, TARGET_UNIT_MASTER) + */ + if (Unit* charmer = GetCaster()->GetCharmer()) + charmer->RemoveAura(SPELL_GHOUL_FRENZY); + } + + void Register() override + { + OnHit += SpellHitFn(spell_dk_ghoul_thrash_SpellScript::CalcDamage); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_ghoul_thrash_SpellScript(); + } +}; + void AddSC_deathknight_spell_scripts() { new spell_dk_anti_magic_shell_raid(); @@ -1729,4 +2030,7 @@ void AddSC_deathknight_spell_scripts() new spell_dk_vampiric_blood(); new spell_dk_will_of_the_necropolis(); new spell_dk_death_grip_initial(); + new spell_dk_raise_ally_initial(); + new spell_dk_raise_ally(); + new spell_dk_ghoul_thrash(); } diff --git a/src/server/scripts/World/npc_taxi.cpp b/src/server/scripts/World/npc_taxi.cpp index c982a07f5a4..a200ba545d8 100644 --- a/src/server/scripts/World/npc_taxi.cpp +++ b/src/server/scripts/World/npc_taxi.cpp @@ -33,20 +33,7 @@ EndScriptData #define GOSSIP_SUSURRUS "I am ready." #define GOSSIP_NETHER_DRAKE "I'm ready to fly! Take me up, dragon!" #define GOSSIP_BRAZEN "I am ready to go to Durnholde Keep." -#define GOSSIP_IRONWING "I'd like to take a flight around Stormwind Harbor." -#define GOSSIP_DABIREE1 "Fly me to Murketh and Shaadraz Gateways" -#define GOSSIP_DABIREE2 "Fly me to Shatter Point" -#define GOSSIP_WINDBELLOW1 "Fly me to The Abyssal Shelf" -#define GOSSIP_WINDBELLOW2 "Fly me to Honor Point" -#define GOSSIP_BRACK1 "Fly me to Murketh and Shaadraz Gateways" -#define GOSSIP_BRACK2 "Fly me to The Abyssal Shelf" -#define GOSSIP_BRACK3 "Fly me to Spinebreaker Post" -#define GOSSIP_IRENA "Fly me to Skettis please" -#define GOSSIP_CLOUDBREAKER1 "Speaking of action, I've been ordered to undertake an air strike." -#define GOSSIP_CLOUDBREAKER2 "I need to intercept the Dawnblade reinforcements." -#define GOSSIP_DRAGONHAWK "<Ride the dragonhawk to Sun's Reach>" #define GOSSIP_VERONIA "Fly me to Manaforge Coruu please" -#define GOSSIP_DEESAK "Fly me to Ogri'la please" #define GOSSIP_CRIMSONWING "<Ride the gryphons to Survey Alcaz Island>" class npc_taxi : public CreatureScript @@ -72,64 +59,11 @@ public: case 18725: // Old Hillsbrad Foothills - Brazen player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BRAZEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); break; - case 29154: // Stormwind City - Thargold Ironwing - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_IRONWING, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - break; - case 19409: // Hellfire Peninsula - Wing Commander Dabir'ee - //Mission: The Murketh and Shaadraz Gateways - if (player->GetQuestStatus(10146) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_DABIREE1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - - //Shatter Point - if (!player->GetQuestRewardStatus(10340)) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_DABIREE2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - break; - case 20235: // Hellfire Peninsula - Gryphoneer Windbellow - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (player->GetQuestStatus(10163) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10346) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_WINDBELLOW1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - - //Go to the Front - if (player->GetQuestStatus(10382) != QUEST_STATUS_NONE && !player->GetQuestRewardStatus(10382)) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_WINDBELLOW2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - break; - case 19401: // Hellfire Peninsula - Wing Commander Brack - //Mission: The Murketh and Shaadraz Gateways - if (player->GetQuestStatus(10129) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BRACK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - - //Mission: The Abyssal Shelf || Return to the Abyssal Shelf - if (player->GetQuestStatus(10162) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10347) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BRACK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - - //Spinebreaker Post - if (player->GetQuestStatus(10242) == QUEST_STATUS_COMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BRACK3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - break; - case 23413: // Blade's Edge Mountains - Skyguard Handler Irena - if (player->GetReputationRank(1031) >= REP_HONORED) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_IRENA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - break; - case 25059: // Isle of Quel'Danas - Ayren Cloudbreaker - if (player->GetQuestStatus(11532) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11533) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_CLOUDBREAKER1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - - if (player->GetQuestStatus(11542) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_CLOUDBREAKER2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - break; - case 25236: // Isle of Quel'Danas - Unrestrained Dragonhawk - if (player->GetQuestStatus(11542) == QUEST_STATUS_COMPLETE || player->GetQuestStatus(11543) == QUEST_STATUS_COMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_DRAGONHAWK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - break; case 20162: // Netherstorm - Veronia //Behind Enemy Lines if (player->GetQuestStatus(10652) != QUEST_STATUS_REWARDED) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_VERONIA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 15); break; - case 23415: // Terokkar Forest - Skyguard Handler Deesak - if (player->GetReputationRank(1031) >= REP_HONORED) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_DEESAK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 16); - break; case 23704: // Dustwallow Marsh - Cassa Crimsonwing if (player->GetQuestStatus(11142) == QUEST_STATUS_INCOMPLETE) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_CRIMSONWING, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+25); @@ -163,62 +97,10 @@ public: player->ActivateTaxiPathTo(534); //TaxiPath 534 } break; - case GOSSIP_ACTION_INFO_DEF + 3: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 53335, true); //TaxiPath 1041 (Stormwind Harbor) - break; - case GOSSIP_ACTION_INFO_DEF + 4: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 33768, true); //TaxiPath 585 (Gateways Murket and Shaadraz) - break; - case GOSSIP_ACTION_INFO_DEF + 5: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 35069, true); //TaxiPath 612 (Taxi - Hellfire Peninsula - Expedition Point to Shatter Point) - break; - case GOSSIP_ACTION_INFO_DEF + 6: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 33899, true); //TaxiPath 589 (Aerial Assault Flight (Alliance)) - break; - case GOSSIP_ACTION_INFO_DEF + 7: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 35065, true); //TaxiPath 607 (Taxi - Hellfire Peninsula - Shatter Point to Beach Head) - break; - case GOSSIP_ACTION_INFO_DEF + 8: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 33659, true); //TaxiPath 584 (Gateways Murket and Shaadraz) - break; - case GOSSIP_ACTION_INFO_DEF + 9: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 33825, true); //TaxiPath 587 (Aerial Assault Flight (Horde)) - break; - case GOSSIP_ACTION_INFO_DEF + 10: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 34578, true); //TaxiPath 604 (Taxi - Reaver's Fall to Spinebreaker Ridge) - break; - case GOSSIP_ACTION_INFO_DEF + 11: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 41278, true); //TaxiPath 706 - break; - case GOSSIP_ACTION_INFO_DEF + 12: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 45071, true); //TaxiPath 779 - break; - case GOSSIP_ACTION_INFO_DEF + 13: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 45113, true); //TaxiPath 784 - break; - case GOSSIP_ACTION_INFO_DEF + 14: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 45353, true); //TaxiPath 788 - break; case GOSSIP_ACTION_INFO_DEF + 15: player->CLOSE_GOSSIP_MENU(); player->CastSpell(player, 34905, true); //TaxiPath 606 break; - case GOSSIP_ACTION_INFO_DEF + 16: - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, 41279, true); //TaxiPath 705 (Taxi - Skettis to Skyguard Outpost) - break; case GOSSIP_ACTION_INFO_DEF + 25: player->CLOSE_GOSSIP_MENU(); player->CastSpell(player, 42295, true); |