diff options
Diffstat (limited to 'src')
32 files changed, 602 insertions, 750 deletions
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp index 0043482c77f..20d0364ab79 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp @@ -170,7 +170,7 @@ void AuctionBotBuyer::PrepareListOfEntry(BuyerConfiguration& config) TC_LOG_DEBUG("ahbot", "AHBot: CheckedEntry size = %u", (uint32)config.CheckedEntry.size()); } -bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, double maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio) +bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, uint32 maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio) { double ratio = 0; uint32 chance = 0; @@ -184,7 +184,7 @@ bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, if (buyoutPrice > 0 && maxBuyablePrice > 0) { - ratio = buyoutPrice / maxBuyablePrice; + ratio = double(buyoutPrice) / double(maxBuyablePrice); if (ratio < 10) chance = maxChance - (ratio * maxChance / 10); else @@ -201,7 +201,7 @@ bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, if (buyoutPrice > 0 && maxBuyablePrice > 0) { - ratio = buyoutPrice / maxBuyablePrice; + ratio = double(buyoutPrice) / double(maxBuyablePrice); if (ratio < 10) chance = (maxChance / 5) - (ratio * maxChance / 50); else @@ -215,7 +215,7 @@ bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, { if (buyoutPrice > 0 && maxBuyablePrice > 0) { - ratio = buyoutPrice / maxBuyablePrice; + ratio = double(buyoutPrice) / double(maxBuyablePrice); if (ratio < 10) chance = (maxChance / 5) - (ratio* maxChance / 50); else @@ -348,12 +348,13 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) uint32 basePrice = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_BUYER) ? prototype->BuyPrice : prototype->SellPrice; basePrice *= item->GetCount(); - double maxBuyablePrice = (basePrice * config.BuyerPriceRatio) / 100; + uint32 maxBuyablePrice = (basePrice * config.BuyerPriceRatio) / 100; BuyerItemInfoMap::iterator sameItemItr = config.SameItemInfo.find(item->GetEntry()); uint32 buyoutPrice = auction->buyout / item->GetCount(); uint32 bidPrice; uint32 bidPriceByItem; + uint32 minBidPrice; if (auction->bid >= auction->startbid) { bidPrice = auction->GetAuctionOutBid(); @@ -371,6 +372,7 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) { inGameBuyPrice = 0; inGameBidPrice = 0; + minBidPrice = 0; } else { @@ -378,15 +380,16 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) maxBuyablePrice = maxBuyablePrice * 5; // if only one item exist can be bought if the price is high too. inGameBuyPrice = sameItemItr->second.BuyPrice / sameItemItr->second.ItemCount; inGameBidPrice = sameItemItr->second.BidPrice / sameItemItr->second.ItemCount; + minBidPrice = sameItemItr->second.MinBidPrice; } - double maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price + uint32 maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price TC_LOG_DEBUG("ahbot", "AHBot: Auction added with data:"); - TC_LOG_DEBUG("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, maxBuyablePrice / 10000); + TC_LOG_DEBUG("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, double(maxBuyablePrice) / 10000.0); TC_LOG_DEBUG("ahbot", "AHBot: GamePrice buy=%.1fg, bid=%.1fg.", inGameBuyPrice / 10000, inGameBidPrice / 10000); TC_LOG_DEBUG("ahbot", "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.", - sameItemItr->second.MinBuyPrice / 10000, sameItemItr->second.MinBidPrice / 10000); + sameItemItr->second.MinBuyPrice / 10000, minBidPrice / 10000); TC_LOG_DEBUG("ahbot", "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice / 10000); if (!auction->owner) // Original auction owner @@ -395,7 +398,7 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) { if (IsBuyableEntry(buyoutPrice, inGameBuyPrice, maxBuyablePrice, sameItemItr->second.MinBuyPrice, maxChance, config.FactionChance)) { - if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance / 2, config.FactionChance)) + if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance)) { if (urand(0, 5) == 0) PlaceBidToEntry(auction, bidPrice); @@ -405,10 +408,10 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) else BuyEntry(auction); } - else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance / 2, config.FactionChance)) + else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance)) PlaceBidToEntry(auction, bidPrice); } - else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance, config.FactionChance)) + else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance, config.FactionChance)) PlaceBidToEntry(auction, bidPrice); itr->second.LastChecked = now; diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h index 1148435f1c1..9c9a39cf567 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h @@ -85,7 +85,7 @@ private: BuyerConfiguration _houseConfig[MAX_AUCTION_HOUSE_TYPE]; void LoadBuyerValues(BuyerConfiguration& config); - bool IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, double maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio); + bool IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, uint32 maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio); bool IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, double maxBidablePrice, uint32 minBidPrice, uint32 maxChance, uint32 chanceRatio); void PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice); void BuyEntry(AuctionEntry* auction); diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index c11ee7a39b7..6f6d1b66308 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -655,17 +655,6 @@ void Battleground::RemoveAuraOnTeam(uint32 SpellID, uint32 TeamID) player->RemoveAura(SpellID); } -void Battleground::YellToAll(Creature* creature, char const* text, uint32 language) -{ - for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - if (Player* player = _GetPlayer(itr, "YellToAll")) - { - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, Language(language), creature, player, text); - player->SendDirectMessage(&data); - } -} - void Battleground::RewardHonorToTeam(uint32 Honor, uint32 TeamID) { for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) @@ -712,24 +701,6 @@ void Battleground::EndBattleground(uint32 winner) int32 winmsg_id = 0; - PreparedStatement* stmt; - PreparedQueryResult result; - uint64 battleground_id = 1; - - if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID); - result = CharacterDatabase.Query(stmt); - - if (result) - { - Field* fields = result->Fetch(); - battleground_id = fields[0].GetInt64() + 1; - } - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND); - } - if (winner == ALLIANCE) { winmsg_id = isBattleground() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS; @@ -737,9 +708,6 @@ void Battleground::EndBattleground(uint32 winner) PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound SetWinner(BG_TEAM_ALLIANCE); - - if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) - stmt->setUInt8(1, BG_TEAM_ALLIANCE); } else if (winner == HORDE) { @@ -748,23 +716,30 @@ void Battleground::EndBattleground(uint32 winner) PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound SetWinner(BG_TEAM_HORDE); - - if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) - stmt->setUInt8(1, BG_TEAM_HORDE); } else { SetWinner(BG_TEAM_NEUTRAL); - - if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) - stmt->setUInt8(1, BG_TEAM_NEUTRAL); } + PreparedStatement* stmt = nullptr; + uint64 battlegroundId = 1; if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) { - stmt->setUInt64(0, battleground_id); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + Field* fields = result->Fetch(); + battlegroundId = fields[0].GetUInt64() + 1; + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND); + stmt->setUInt64(0, battlegroundId); + stmt->setUInt8(1, GetWinner()); stmt->setUInt8(2, m_BracketId + 1); - stmt->setUInt8(3, GetTypeID()); + stmt->setUInt8(3, GetTypeID(true)); CharacterDatabase.Execute(stmt); } @@ -810,9 +785,7 @@ void Battleground::EndBattleground(uint32 winner) stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER); BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUIDLow()); - // battleground_id, character_guid, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done - - stmt->setUInt32(0, battleground_id); + stmt->setUInt32(0, battlegroundId); stmt->setUInt32(1, player->GetGUIDLow()); stmt->setUInt32(2, score->second->GetKillingBlows()); stmt->setUInt32(3, score->second->GetDeaths()); diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index c2e5b03e3ae..b0270192fd1 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -343,7 +343,6 @@ class Battleground virtual void FillInitialWorldStates(WorldPacket& /*data*/) { } void SendPacketToTeam(uint32 TeamID, WorldPacket* packet, Player* sender = NULL, bool self = true); void SendPacketToAll(WorldPacket* packet); - void YellToAll(Creature* creature, const char* text, uint32 language); void SendChatMessage(Creature* source, uint8 textId, WorldObject* target = NULL); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index eafb02f031d..fde358b4d61 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -25,6 +25,7 @@ #include "GameObject.h" #include "Language.h" #include "Player.h" +#include "ScriptedCreature.h" #include "SpellAuras.h" #include "WorldSession.h" @@ -85,7 +86,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) triggerSpawnID = AV_CPLACE_TRIGGER19; */ - if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) + if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS]) { CastSpellOnTeam(23658, HORDE); //this is a spell which finishes a quest where a player has to kill the boss RewardReputationToTeam(729, BG_AV_REP_BOSS, HORDE); @@ -93,7 +94,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) EndBattleground(HORDE); DelCreature(AV_CPLACE_TRIGGER17); } - else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) + else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS]) { CastSpellOnTeam(23658, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss RewardReputationToTeam(730, BG_AV_REP_BOSS, ALLIANCE); @@ -101,7 +102,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) EndBattleground(ALLIANCE); DelCreature(AV_CPLACE_TRIGGER19); } - else if (entry == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) + else if (entry == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN]) { if (!m_CaptainAlive[0]) { @@ -115,12 +116,12 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) //spawn destroyed aura for (uint8 i=0; i <= 9; i++) SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+i, RESPAWN_IMMEDIATELY); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, GetTrinityString(LANG_BG_AV_A_CAPTAIN_DEAD), LANG_UNIVERSAL); DelCreature(AV_CPLACE_TRIGGER16); + + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + herold->AI()->TalkToMap(TEXT_STORMPIKE_GENERAL_DEAD); } - else if (entry == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + else if (entry == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN]) { if (!m_CaptainAlive[1]) { @@ -134,14 +135,14 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer) //spawn destroyed aura for (uint8 i=0; i <= 9; i++) SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_HORDE+i, RESPAWN_IMMEDIATELY); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, GetTrinityString(LANG_BG_AV_H_CAPTAIN_DEAD), LANG_UNIVERSAL); DelCreature(AV_CPLACE_TRIGGER18); + + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + herold->AI()->TalkToMap(TEXT_FROSTWOLF_GENERAL_DEAD); } - else if (entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_H_4][0]) + else if (entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_N_4] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_A_4] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_H_4]) ChangeMineOwner(AV_NORTH_MINE, killer->GetTeam()); - else if (entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_H_4][0]) + else if (entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_N_4] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_A_4] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_H_4]) ChangeMineOwner(AV_SOUTH_MINE, killer->GetTeam()); } @@ -150,7 +151,7 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player) if (GetStatus() != STATUS_IN_PROGRESS) return;//maybe we should log this, cause this must be a cheater or a big bug uint8 team = GetTeamIndexByTeamId(player->GetTeam()); - /// @todo add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor + /// @todo add reputation, events (including quest not available anymore, next quest available, go/npc de/spawning)and maybe honor TC_LOG_DEBUG("bg.battleground", "BG_AV Quest %i completed", questid); switch (questid) { @@ -290,11 +291,11 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) } else { - creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0], type, BG_AV_CreaturePos[type]); + creature = AddCreature(BG_AV_CreatureInfo[cinfoid], type, BG_AV_CreaturePos[type]); } if (!creature) return NULL; - if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN]) creature->SetRespawnDelay(RESPAWN_ONE_DAY); /// @todo look if this can be done by database + also add this for the wingcommanders if ((isStatic && cinfoid >= 10 && cinfoid <= 14) || (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) || @@ -317,22 +318,22 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) uint32 triggerSpawnID = 0; uint32 newFaction = 0; - if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) + if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN]) { triggerSpawnID = AV_CPLACE_TRIGGER16; newFaction = 84; } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS]) { triggerSpawnID = AV_CPLACE_TRIGGER17; newFaction = 84; } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN]) { triggerSpawnID = AV_CPLACE_TRIGGER18; newFaction = 83; } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS]) { triggerSpawnID = AV_CPLACE_TRIGGER19; newFaction = 83; @@ -364,16 +365,14 @@ void BattlegroundAV::PostUpdateImpl(uint32 diff) if (i == 0) { CastSpellOnTeam(AV_BUFF_A_CAPTAIN, ALLIANCE); - Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61); - if (creature) - YellToAll(creature, LANG_BG_AV_A_CAPTAIN_BUFF, LANG_COMMON); + if (Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61)) + creature->AI()->DoAction(ACTION_BUFF_YELL); } else { CastSpellOnTeam(AV_BUFF_H_CAPTAIN, HORDE); - Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); /// @todo make the captains a dynamic creature - if (creature) - YellToAll(creature, LANG_BG_AV_H_CAPTAIN_BUFF, LANG_ORCISH); + if (Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59)) + creature->AI()->DoAction(ACTION_BUFF_YELL); } m_CaptainBuffTimer[i] = 120000 + urand(0, 4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times } @@ -601,16 +600,10 @@ void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) } } } - //send a nice message to all :) - char buf[256]; - if (IsTower(node)) - sprintf(buf, GetTrinityString(LANG_BG_AV_TOWER_TAKEN), GetNodeName(node), (owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - else - sprintf(buf, GetTrinityString(LANG_BG_AV_GRAVE_TAKEN), GetNodeName(node), (owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) :GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, buf, LANG_UNIVERSAL); + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + herold->AI()->TalkToMap(owner == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture); } void BattlegroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) @@ -621,8 +614,6 @@ void BattlegroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) ASSERT(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE); if (team != ALLIANCE && team != HORDE) team = AV_NEUTRAL_TEAM; - else - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); if (m_Mine_Owner[mine] == team && !initial) return; @@ -684,19 +675,21 @@ void BattlegroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) if (team == ALLIANCE || team == HORDE) { m_Mine_Reclaim_Timer[mine]=AV_MINE_RECLAIM_TIMER; - char buf[256]; - sprintf(buf, GetTrinityString(LANG_BG_AV_MINE_TAKEN), GetTrinityString((mine == AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH), - (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, buf, LANG_UNIVERSAL); + + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + { + if (mine == AV_NORTH_MINE) + herold->AI()->TalkToMap(team == ALLIANCE ? TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN : TEXT_IRONDEEP_MINE_HORDE_TAKEN); + else if (mine == AV_SOUTH_MINE) + herold->AI()->TalkToMap(team == ALLIANCE ? TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN : TEXT_COLDTOOTH_MINE_HORDE_TAKEN); + } } else { if (mine == AV_SOUTH_MINE) //i think this gets called all the time { if (Creature* creature = GetBGCreature(AV_CPLACE_MINE_S_3)) - YellToAll(creature, LANG_BG_AV_S_MINE_BOSS_CLAIMS, LANG_UNIVERSAL); + creature->AI()->Talk(TEXT_SNIVVLE_RANDOM); } } return; @@ -927,19 +920,13 @@ void BattlegroundAV::EventPlayerDefendsPoint(Player* player, uint32 object) SpawnBGObject(((team == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i, RESPAWN_IMMEDIATELY); } } - //send a nice message to all :) - char buf[256]; - sprintf(buf, GetTrinityString((IsTower(node)) ? LANG_BG_AV_TOWER_DEFENDED : LANG_BG_AV_GRAVE_DEFENDED), GetNodeName(node), - (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, buf, LANG_UNIVERSAL); - //update the statistic for the defending player - UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_DEFENDED : SCORE_GRAVEYARDS_DEFENDED, 1); - if (IsTower(node)) - PlaySoundToAll(AV_SOUND_BOTH_TOWER_DEFEND); - else - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); + + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + herold->AI()->TalkToMap(team == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture); + + // update the statistic for the defending player + UpdatePlayerScore(player, IsTower(node) ? SCORE_TOWERS_DEFENDED : SCORE_GRAVEYARDS_DEFENDED, 1); } void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object) @@ -1025,42 +1012,29 @@ void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object) AssaultNode(node, team); UpdateNodeWorldState(node); - //send a nice message to all :) - char buf[256]; - sprintf(buf, (IsTower(node)) ? GetTrinityString(LANG_BG_AV_TOWER_ASSAULTED) : GetTrinityString(LANG_BG_AV_GRAVE_ASSAULTED), GetNodeName(node), - (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature, buf, LANG_UNIVERSAL); - //update the statistic for the assaulting player + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) + if (Creature* herold = GetBGCreature(AV_CPLACE_HERALD)) + herold->AI()->TalkToMap(team == ALLIANCE ? nodeInfo->TextIds.AllianceAttack : nodeInfo->TextIds.HordeAttack); + + // update the statistic for the assaulting player UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_ASSAULTED : SCORE_GRAVEYARDS_ASSAULTED, 1); - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_ASSAULTS:AV_SOUND_HORDE_ASSAULTS); } void BattlegroundAV::FillInitialWorldStates(WorldPacket& data) { - bool stateok; - //graveyards - for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; i++) + for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) { - for (uint8 j =1; j <= 3; j+=2) - {//j=1=assaulted j=3=controled - stateok = (m_Nodes[i].State == j); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); - } + uint16 owner = m_Nodes[i].Owner; + BG_AV_States state = m_Nodes[i].State; + + data << uint32(BGAVNodeInfo[i].WorldStateIds.AllianceAssault) << uint32(owner == ALLIANCE && state == POINT_ASSAULTED); + data << uint32(BGAVNodeInfo[i].WorldStateIds.AllianceControl) << uint32(owner == ALLIANCE && state >= POINT_DESTROYED); + data << uint32(BGAVNodeInfo[i].WorldStateIds.HordeAssault) << uint32(owner == HORDE && state == POINT_ASSAULTED); + data << uint32(BGAVNodeInfo[i].WorldStateIds.HordeControl) << uint32(owner == HORDE && state >= POINT_DESTROYED); } - //towers - for (uint8 i = BG_AV_NODES_DUNBALDAR_SOUTH; i < BG_AV_NODES_MAX; ++i) - for (uint8 j =1; j <= 3; j+=2) - {//j=1=assaulted j=3=controled //i dont have j=2=destroyed cause destroyed is the same like enemy-team controll - stateok = (m_Nodes[i].State == j || (m_Nodes[i].State == POINT_DESTROYED && j == 3)); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j, HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); - } - if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == AV_NEUTRAL_TEAM) //cause neutral teams aren't handled generic - data << uint32(AV_SNOWFALL_N) << uint32(1); + data << uint32(AV_SNOWFALL_N) << uint32(m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == AV_NEUTRAL_TEAM); + data << uint32(AV_Alliance_Score) << uint32(m_Team_Scores[0]); data << uint32(AV_Horde_Score) << uint32(m_Team_Scores[1]); if (GetStatus() == STATUS_IN_PROGRESS){ //only if game started the teamscores are displayed @@ -1076,36 +1050,21 @@ void BattlegroundAV::FillInitialWorldStates(WorldPacket& data) SendMineWorldStates(AV_SOUTH_MINE); } -uint8 BattlegroundAV::GetWorldStateType(uint8 state, uint16 team) //this is used for node worldstates and returns values which fit good into the worldstatesarray +void BattlegroundAV::UpdateNodeWorldState(BG_AV_Nodes node) { - //neutral stuff cant get handled (currently its only snowfall) - ASSERT(team != AV_NEUTRAL_TEAM); - //a_c a_a h_c h_a the positions in worldstate-array - if (team == ALLIANCE) - { - if (state == POINT_CONTROLED || state == POINT_DESTROYED) - return 0; - if (state == POINT_ASSAULTED) - return 1; - } - if (team == HORDE) + if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node)) { - if (state == POINT_DESTROYED || state == POINT_CONTROLED) - return 2; - if (state == POINT_ASSAULTED) - return 3; + uint16 owner = m_Nodes[node].Owner; + BG_AV_States state = m_Nodes[node].State; + + UpdateWorldState(nodeInfo->WorldStateIds.AllianceAssault, owner == ALLIANCE && state == POINT_ASSAULTED); + UpdateWorldState(nodeInfo->WorldStateIds.AllianceControl, owner == ALLIANCE && state >= POINT_DESTROYED); + UpdateWorldState(nodeInfo->WorldStateIds.HordeAssault, owner == HORDE && state == POINT_ASSAULTED); + UpdateWorldState(nodeInfo->WorldStateIds.HordeControl, owner == HORDE && state >= POINT_DESTROYED); } - TC_LOG_ERROR("bg.battleground", "BG_AV: should update a strange worldstate state:%i team:%i", state, team); - return 5; //this will crash the game, but i want to know if something is wrong here -} -void BattlegroundAV::UpdateNodeWorldState(BG_AV_Nodes node) -{ - UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].State, m_Nodes[node].Owner)], 1); - if (m_Nodes[node].PrevOwner == AV_NEUTRAL_TEAM) //currently only snowfall is supported as neutral node (i don't want to make an extra row (neutral states) in worldstatesarray just for one node - UpdateWorldState(AV_SNOWFALL_N, 0); - else - UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].PrevState, m_Nodes[node].PrevOwner)], 0); + if (node == BG_AV_NODES_SNOWFALL_GRAVE) + UpdateWorldState(AV_SNOWFALL_N, m_Nodes[node].Owner == AV_NEUTRAL_TEAM); } void BattlegroundAV::SendMineWorldStates(uint32 mine) @@ -1440,33 +1399,6 @@ bool BattlegroundAV::SetupBattleground() return true; } -char const* BattlegroundAV::GetNodeName(BG_AV_Nodes node) -{ - switch (node) - { - case BG_AV_NODES_FIRSTAID_STATION: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORM_AID); - case BG_AV_NODES_DUNBALDAR_SOUTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_S); - case BG_AV_NODES_DUNBALDAR_NORTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_N); - case BG_AV_NODES_STORMPIKE_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORMPIKE); - case BG_AV_NODES_ICEWING_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICEWING); - case BG_AV_NODES_STONEHEART_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STONE); - case BG_AV_NODES_STONEHEART_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_STONE); - case BG_AV_NODES_SNOWFALL_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_SNOW); - case BG_AV_NODES_ICEBLOOD_TOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICE); - case BG_AV_NODES_ICEBLOOD_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_ICE); - case BG_AV_NODES_TOWER_POINT: return GetTrinityString(LANG_BG_AV_NODE_TOWER_POINT); - case BG_AV_NODES_FROSTWOLF_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST); - case BG_AV_NODES_FROSTWOLF_ETOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_E); - case BG_AV_NODES_FROSTWOLF_WTOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_W); - case BG_AV_NODES_FROSTWOLF_HUT: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST_HUT); - default: - TC_LOG_ERROR("bg.battleground", "tried to get name for node %u", node); - break; - } - - return "Unknown"; -} - void BattlegroundAV::AssaultNode(BG_AV_Nodes node, uint16 team) { if (m_Nodes[node].TotalOwner == team) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index b56ec2ca489..22534d2015b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -23,10 +23,6 @@ #include "BattlegroundScore.h" #include "Object.h" -#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!" -#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!" -#define LANG_BG_AV_S_MINE_BOSS_CLAIMS "Snivvle is here! Snivvle claims the Coldtooth Mine!" - #define BG_AV_CAPTIME 240000 //4:00 #define BG_AV_SNOWFALL_FIRSTCAP 300000 //5:00 but i also have seen 4:05 @@ -54,6 +50,11 @@ #define BG_AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz +enum SharedActions +{ + ACTION_BUFF_YELL = -30001 +}; + enum BG_AV_Sounds { /// @todo: get out if there comes a sound when neutral team captures mine @@ -1041,63 +1042,63 @@ enum BG_AV_CreatureIds //entry, team, minlevel, maxlevel /// @todo: this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) -const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = +const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX] = { - { 12050, 1216, 58, 58 }, //Stormpike Defender - { 13326, 1216, 59, 59 }, //Seasoned Defender - { 13331, 1216, 60, 60 }, //Veteran Defender - { 13422, 1216, 61, 61 }, //Champion Defender - { 13358, 1216, 59, 60 }, //Stormpike Bowman /// @todo: Confirm if this is correct. Author assumpted 60, 61 & 69, 70, but wouldn't work here - { 11949, 469, 0, 0}, //not spawned with this data, but used for handlekillunit - { 11948, 469, 0, 0}, //not spawned with this data, but used for handlekillunit - { 12053, 1214, 58, 58 }, //Frostwolf Guardian - { 13328, 1214, 59, 59 }, //Seasoned Guardian - { 13332, 1214, 60, 60 }, //Veteran Guardian - { 13421, 1214, 61, 61 }, //Champion Guardian - { 13359, 1214, 59, 60 }, //Frostwolf Bowman - { 11947, 67, 0, 0}, //not spawned with this data, but used for handlekillunit - { 11946, 67, 0, 0}, //not spawned with this data, but used for handlekillunit - { 14763, 1534, 60, 60 }, //Dun Baldar South Marshal - { 14762, 1534, 60, 60 }, //Dun Baldar North Marshal - { 14764, 1534, 60, 60 }, //Icewing Marshal - { 14765, 1534, 60, 60 }, //Stonehearth Marshal - - { 14773, 1214, 60, 60 }, //Iceblood Warmaster - { 14776, 1214, 60, 60 }, //Tower Point Warmaster - { 14772, 1214, 60, 60 }, //East Frostwolf Warmaster - { 14777, 1214, 60, 60 }, //West Frostwolf Warmaster - - { 10987, 59, 52, 53 }, //Irondeep Trogg - { 11600, 59, 53, 54 }, //Irondeep Shaman - { 11602, 59, 54, 55 }, //Irondeep Skullthumper - { 11657, 59, 58, 58 }, //Morloch - - {13396, 469, 52, 53}, // irondeep alliance /// @todo: Correct and give correct ids - {13080, 469, 53, 54}, - {13098, 469, 54, 55}, - {13078, 469, 58, 58}, - - {13397, 67, 52, 53}, //irondeep horde - {13099, 67, 53, 54}, - {13081, 67, 54, 55}, - {13079, 67, 58, 58}, - - { 11603, 59, 52, 53 }, //south mine neutral - { 11604, 59, 53, 54 }, - { 11605, 59, 54, 55 }, - { 11677, 59, 58, 58 }, - { 10982, 59, 52, 53 }, //vermin - - {13317, 469, 52, 53}, //alliance - {13096, 469, 54, 55}, //explorer - {13087, 469, 54, 55}, //invader - {13086, 469, 58, 58}, - - {13316, 67, 52, 53}, //horde - {13097, 67, 54, 55}, //surveypr - {13089, 67, 54, 55}, //guard - {13088, 67, 58, 58}, - {14848, 67, 58, 58} //Herald + 12050, // Stormpike Defender + 13326, // Seasoned Defender + 13331, // Veteran Defender + 13422, // Champion Defender + 13358, // Stormpike Bowman /// @todo: Confirm if this is correct. Author assumpted 60, 61 & 69, 70, but wouldn't work here + 11949, // not spawned with this data, but used for handlekillunit + 11948, // not spawned with this data, but used for handlekillunit + 12053, // Frostwolf Guardian + 13328, // Seasoned Guardian + 13332, // Veteran Guardian + 13421, // Champion Guardian + 13359, // Frostwolf Bowman + 11947, // not spawned with this data, but used for handlekillunit + 11946, // not spawned with this data, but used for handlekillunit + 14763, // Dun Baldar South Marshal + 14762, // Dun Baldar North Marshal + 14764, // Icewing Marshal + 14765, // Stonehearth Marshal + + 14773, // Iceblood Warmaster + 14776, // Tower Point Warmaster + 14772, // East Frostwolf Warmaster + 14777, // West Frostwolf Warmaster + + 10987, // Irondeep Trogg + 11600, // Irondeep Shaman + 11602, // Irondeep Skullthumper + 11657, // Morloch + + 13396, // irondeep alliance /// @todo: Correct and give correct ids + 13080, + 13098, + 13078, + + 13397, // irondeep horde + 13099, + 13081, + 13079, + + 11603, // south mine neutral + 11604, + 11605, + 11677, + 10982, // vermin + + 13317, // alliance + 13096, // explorer + 13087, // invader + 13086, + + 13316, // horde + 13097, // surveypr + 13089, // guard + 13088, + 14848 // Herald }; //x, y, z, o, static_creature_info-id @@ -1444,41 +1445,6 @@ const uint32 BG_AV_MineWorldStates[2][3] = {1355, 1357, 1356} }; -//alliance_control alliance_assault h_control h_assault -const uint32 BG_AV_NodeWorldStates[16][4] = -{ - //Stormpike first aid station - {1325, 1326, 1327, 1328}, - //Stormpike Graveyard - {1333, 1335, 1334, 1336}, - //Stoneheart Grave - {1302, 1304, 1301, 1303}, - //Snowfall Grave - {1341, 1343, 1342, 1344}, - //Iceblood grave - {1346, 1348, 1347, 1349}, - //Frostwolf Grave - {1337, 1339, 1338, 1340}, - //Frostwolf Hut - {1329, 1331, 1330, 1332}, - //Dunbaldar South Bunker - {1361, 1375, 1370, 1378}, - //Dunbaldar North Bunker - {1362, 1374, 1371, 1379}, - //Icewing Bunker - {1363, 1376, 1372, 1380}, - //Stoneheart Bunker - {1364, 1377, 1373, 1381}, - //Iceblood Tower - {1368, 1390, 1385, 1395}, - //Tower Point - {1367, 1389, 1384, 1394}, - //Frostwolf East - {1366, 1388, 1383, 1393}, - //Frostwolf West - {1365, 1387, 1382, 1392}, -}; - enum BG_AV_QuestIds { AV_QUEST_A_SCRAPS1 = 7223, @@ -1513,6 +1479,63 @@ enum BG_AV_Objectives AV_OBJECTIVE_DEFEND_GRAVEYARD = 65 }; +struct StaticNodeInfo +{ + BG_AV_Nodes NodeId; + + struct + { + uint8 AllianceCapture; + uint8 AllianceAttack; + uint8 HordeCapture; + uint8 HordeAttack; + } TextIds; + + struct + { + uint32 AllianceControl; + uint32 AllianceAssault; + uint32 HordeControl; + uint32 HordeAssault; + } WorldStateIds; +}; + +static StaticNodeInfo const BGAVNodeInfo[] = +{ + { BG_AV_NODES_FIRSTAID_STATION, { 47, 48, 45, 46 }, { 1325, 1326, 1327, 1328 } }, // Stormpike First Aid Station + { BG_AV_NODES_STORMPIKE_GRAVE, { 1, 2, 3, 4 }, { 1333, 1335, 1334, 1336 } }, // Stormpike Graveyard + { BG_AV_NODES_STONEHEART_GRAVE, { 55, 56, 53, 54 }, { 1302, 1304, 1301, 1303 } }, // Stoneheart Graveyard + { BG_AV_NODES_SNOWFALL_GRAVE, { 5, 6, 7, 8 }, { 1341, 1343, 1342, 1344 } }, // Snowfall Graveyard + { BG_AV_NODES_ICEBLOOD_GRAVE, { 59, 60, 57, 58 }, { 1346, 1348, 1347, 1349 } }, // Iceblood Graveyard + { BG_AV_NODES_FROSTWOLF_GRAVE, { 9, 10, 11, 12 }, { 1337, 1339, 1338, 1340 } }, // Frostwolf Graveyard + { BG_AV_NODES_FROSTWOLF_HUT, { 51, 52, 49, 50 }, { 1329, 1331, 1330, 1332 } }, // Frostwolf Hut + { BG_AV_NODES_DUNBALDAR_SOUTH, { 16, 15, 14, 13 }, { 1361, 1375, 1370, 1378 } }, // Dunbaldar South Bunker + { BG_AV_NODES_DUNBALDAR_NORTH, { 20, 19, 18, 17 }, { 1362, 1374, 1371, 1379 } }, // Dunbaldar North Bunker + { BG_AV_NODES_ICEWING_BUNKER, { 24, 23, 22, 21 }, { 1363, 1376, 1372, 1380 } }, // Icewing Bunker + { BG_AV_NODES_STONEHEART_BUNKER, { 28, 27, 26, 25 }, { 1364, 1377, 1373, 1381 } }, // Stoneheart Bunker + { BG_AV_NODES_ICEBLOOD_TOWER, { 44, 43, 42, 41 }, { 1368, 1390, 1385, 1395 } }, // Iceblood Tower + { BG_AV_NODES_TOWER_POINT, { 40, 39, 38, 37 }, { 1367, 1389, 1384, 1394 } }, // Tower Point + { BG_AV_NODES_FROSTWOLF_ETOWER, { 36, 35, 34, 33 }, { 1366, 1388, 1383, 1393 } }, // Frostwolf East Tower + { BG_AV_NODES_FROSTWOLF_WTOWER, { 32, 31, 30, 29 }, { 1365, 1387, 1382, 1392 } }, // Frostwolf West Tower +}; + +enum Texts +{ + // Herold + // Towers/Graveyards = 1 - 60 + TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN = 61, + TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN = 62, + TEXT_COLDTOOTH_MINE_HORDE_TAKEN = 63, + TEXT_IRONDEEP_MINE_HORDE_TAKEN = 64, + TEXT_FROSTWOLF_GENERAL_DEAD = 65, /// @todo: sound is missing + TEXT_STORMPIKE_GENERAL_DEAD = 66, /// @todo: sound is missing + TEXT_ALLIANCE_WINS = 67, // NYI /// @todo: sound is missing + TEXT_HORDE_WINS = 68, // NYI /// @todo: sound is missing + + // Taskmaster Snivvle + TEXT_SNIVVLE_RANDOM = 0 +}; + struct BG_AV_NodeInfo { BG_AV_States State; @@ -1524,7 +1547,7 @@ struct BG_AV_NodeInfo bool Tower; }; -inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); } +inline BG_AV_Nodes &operator++(BG_AV_Nodes& i) { return i = BG_AV_Nodes(i + 1); } struct BattlegroundAVScore final : public BattlegroundScore { @@ -1633,9 +1656,16 @@ class BattlegroundAV : public Battleground void PopulateNode(BG_AV_Nodes node); void DePopulateNode(BG_AV_Nodes node); + StaticNodeInfo const* GetStaticNodeInfo(BG_AV_Nodes node) const + { + for (uint8 i = 0; i < BG_AV_NODES_MAX; ++i) + if (BGAVNodeInfo[i].NodeId == node) + return &BGAVNodeInfo[i]; + return nullptr; + } + BG_AV_Nodes GetNodeThroughObject(uint32 object); uint32 GetObjectThroughNode(BG_AV_Nodes node); - char const* GetNodeName(BG_AV_Nodes node); bool IsTower(BG_AV_Nodes node) { return m_Nodes[node].Tower; } /*mine*/ @@ -1643,7 +1673,6 @@ class BattlegroundAV : public Battleground /*worldstates*/ void FillInitialWorldStates(WorldPacket& data) override; - uint8 GetWorldStateType(uint8 state, uint16 team); void SendMineWorldStates(uint32 mine); void UpdateNodeWorldState(BG_AV_Nodes node); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d1495f02614..158ff17ea11 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15297,18 +15297,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, SendNewItem(item, quest->RewardItemIdCount[i], true, false); } else if (quest->IsDFQuest()) - { - MailSender sender(MAIL_CREATURE, 34337 /* The Postmaster */ ); - MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed. - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (Item* item = Item::CreateItem(quest->RewardItemId[i], quest->RewardItemIdCount[i], 0)) - { - item->SaveToDB(trans); - draft.AddItem(item); - } - draft.SendMailTo(trans, MailReceiver(this, this->GetGUIDLow()), sender); - CharacterDatabase.CommitTransaction(trans); - } + SendItemRetrievalMail(quest->RewardItemId[i], quest->RewardItemIdCount[i]); } } } @@ -15322,7 +15311,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool rewarded = (m_RewardedQuests.find(quest_id) != m_RewardedQuests.end()); // Not give XP in case already completed once repeatable quest - uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this)*sWorld->getRate(RATE_XP_QUEST)); + uint32 XP = rewarded && !quest->IsDFQuest() ? 0 : uint32(quest->XPValue(this)*sWorld->getRate(RATE_XP_QUEST)); // handle SPELL_AURA_MOD_XP_QUEST_PCT auras Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT); @@ -15448,6 +15437,10 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, void Player::FailQuest(uint32 questId) { + // Already complete quests shouldn't turn failed. + if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + return; + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) { SetQuestStatus(questId, QUEST_STATUS_FAILED); @@ -26497,6 +26490,22 @@ void Player::RefundItem(Item* item) CharacterDatabase.CommitTransaction(trans); } +void Player::SendItemRetrievalMail(uint32 itemEntry, uint32 count) +{ + MailSender sender(MAIL_CREATURE, 34337 /* The Postmaster */); + MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed. + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + if (Item* item = Item::CreateItem(itemEntry, count, 0)) + { + item->SaveToDB(trans); + draft.AddItem(item); + } + + draft.SendMailTo(trans, MailReceiver(this, GetGUIDLow()), sender); + CharacterDatabase.CommitTransaction(trans); +} + void Player::SetRandomWinner(bool isWinner) { m_IsBGRandomWinner = isWinner; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b1fd9d5a97f..27ea8355345 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1571,6 +1571,8 @@ class Player : public Unit, public GridObject<Player> PlayerMails::iterator GetMailBegin() { return m_mail.begin();} PlayerMails::iterator GetMailEnd() { return m_mail.end();} + void SendItemRetrievalMail(uint32 itemEntry, uint32 count); // Item retrieval mails sent by The Postmaster (34337), used in multiple places. + /*********************************************************/ /*** MAILED ITEMS SYSTEM ***/ /*********************************************************/ diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 8068e82f676..88a83ab6fde 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1420,8 +1420,25 @@ void Group::CountTheRoll(Rolls::iterator rollI) roll->getLoot()->NotifyItemRemoved(roll->itemSlot); roll->getLoot()->unlootedCount--; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(roll->itemid); - player->AutoStoreLoot(pProto->DisenchantID, LootTemplates_Disenchant, true); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant + + ItemPosCountVec dest; + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count); + if (msg == EQUIP_ERR_OK) + player->AutoStoreLoot(pProto->DisenchantID, LootTemplates_Disenchant, true); + else // If the player's inventory is full, send the disenchant result in a mail. + { + Loot loot; + loot.FillLoot(pProto->DisenchantID, LootTemplates_Disenchant, player, true); + + uint32 max_slot = loot.GetMaxSlotInLootFor(player); + for (uint32 i = 0; i < max_slot; ++i) + { + LootItem* lootItem = loot.LootItemInSlot(i, player); + player->SendEquipError(msg, NULL, NULL, lootItem->itemid); + player->SendItemRetrievalMail(lootItem->itemid, lootItem->count); + } + } } } } diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index cb868097ac6..66cae69cb33 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -999,48 +999,18 @@ enum TrinityStrings LANG_BG_IC_REFINERY = 1222, LANG_BG_IC_QUARRY = 1223, LANG_BG_IC_HANGAR = 1224, + // 1225-1299 LANG_BG_IC_ALLIANCE = 1300, LANG_BG_IC_HORDE = 1301, - // FREE IDS 1228-9999 - + // 1302-1325 // AV - LANG_BG_AV_ALLY = 1300, - LANG_BG_AV_HORDE = 1301, - LANG_BG_AV_TOWER_TAKEN = 1302, - LANG_BG_AV_TOWER_ASSAULTED = 1303, - LANG_BG_AV_TOWER_DEFENDED = 1304, - LANG_BG_AV_GRAVE_TAKEN = 1305, - LANG_BG_AV_GRAVE_DEFENDED = 1306, - LANG_BG_AV_GRAVE_ASSAULTED = 1307, - - LANG_BG_AV_MINE_TAKEN = 1308, - LANG_BG_AV_MINE_NORTH = 1309, - LANG_BG_AV_MINE_SOUTH = 1310, - - LANG_BG_AV_NODE_GRAVE_STORM_AID = 1311, - LANG_BG_AV_NODE_TOWER_DUN_S = 1312, - LANG_BG_AV_NODE_TOWER_DUN_N = 1313, - LANG_BG_AV_NODE_GRAVE_STORMPIKE = 1314, - LANG_BG_AV_NODE_TOWER_ICEWING = 1315, - LANG_BG_AV_NODE_GRAVE_STONE = 1316, - LANG_BG_AV_NODE_TOWER_STONE = 1317, - LANG_BG_AV_NODE_GRAVE_SNOW = 1318, - LANG_BG_AV_NODE_TOWER_ICE = 1319, - LANG_BG_AV_NODE_GRAVE_ICE = 1320, - LANG_BG_AV_NODE_TOWER_POINT = 1321, - LANG_BG_AV_NODE_GRAVE_FROST = 1322, - LANG_BG_AV_NODE_TOWER_FROST_E = 1323, - LANG_BG_AV_NODE_TOWER_FROST_W = 1324, - LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325, - LANG_BG_AV_START_ONE_MINUTE = 1326, LANG_BG_AV_START_HALF_MINUTE = 1327, LANG_BG_AV_HAS_BEGUN = 1328, LANG_BG_AV_A_NEAR_LOSE = 1329, LANG_BG_AV_H_NEAR_LOSE = 1330, - LANG_BG_AV_H_CAPTAIN_DEAD = 1331, - LANG_BG_AV_A_CAPTAIN_DEAD = 1332, + // 1331-1332 LANG_BG_AV_START_TWO_MINUTES = 1333, // FREE IDS 1334-1999 diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0f79c4d0780..de6effb8b14 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6446,7 +6446,12 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo break; } - if (IsTriggered() || m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS)) + // check for ignore LOS on the effect itself + if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS)) + return true; + + // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour + if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, NULL, SPELL_DISABLE_LOS))) return true; /// @todo shit below shouldn't be here, but it's temporary diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index f9c8c800ca5..79dc565487d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2552,7 +2552,7 @@ void World::_UpdateGameTime() } /// Shutdown the server -void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode) +void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode, const std::string& reason) { // ignore if server shutdown at next tick if (IsStopped()) @@ -2573,14 +2573,14 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode) else { m_ShutdownTimer = time; - ShutdownMsg(true); + ShutdownMsg(true, nullptr, reason); } sScriptMgr->OnShutdownInitiate(ShutdownExitCode(exitcode), ShutdownMask(options)); } /// Display a shutdown message to the user(s) -void World::ShutdownMsg(bool show, Player* player) +void World::ShutdownMsg(bool show, Player* player, const std::string& reason) { // not show messages for idle shutdown mode if (m_ShutdownMask & SHUTDOWN_MASK_IDLE) @@ -2595,6 +2595,8 @@ void World::ShutdownMsg(bool show, Player* player) (m_ShutdownTimer > 12 * HOUR && (m_ShutdownTimer % (12 * HOUR)) == 0)) // > 12 h ; every 12 h { std::string str = secsToTimeString(m_ShutdownTimer); + if (!reason.empty()) + str += " - " + reason; ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME; diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index b77f8777bdc..8a36a0af71a 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -637,9 +637,9 @@ class World /// Are we in the middle of a shutdown? bool IsShuttingDown() const { return m_ShutdownTimer > 0; } uint32 GetShutDownTimeLeft() const { return m_ShutdownTimer; } - void ShutdownServ(uint32 time, uint32 options, uint8 exitcode); + void ShutdownServ(uint32 time, uint32 options, uint8 exitcode, const std::string& reason = std::string()); void ShutdownCancel(); - void ShutdownMsg(bool show = false, Player* player = NULL); + void ShutdownMsg(bool show = false, Player* player = NULL, const std::string& reason = std::string()); static uint8 GetExitCode() { return m_ExitCode; } static void StopNow(uint8 exitcode) { m_stopEvent = true; m_ExitCode = exitcode; } static bool IsStopped() { return m_stopEvent; } diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 0359cbbe379..7b074087c0f 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -247,45 +247,31 @@ public: static bool HandleGuildInfoCommand(ChatHandler* handler, char const* args) { - Player* target; - uint32 guildId; - std::string guildName; - std::string guildMasterName; - Guild* guild; + Guild* guild = nullptr; - if (!*args) + if (args && strlen(args) > 0) { - // Look for the guild of the selected player or ourselves - if (target = handler->getSelectedPlayerOrSelf()) - guild = target->GetGuild(); + if (isNumeric(args)) + { + uint32 guildId = uint32(atoi(args)); + guild = sGuildMgr->GetGuildById(guildId); + } else - // getSelectedPlayerOrSelf will return null if there is no session - // so target becomes nullptr if the command is ran through console - // without specifying args. - return false; - } - else if (guildId = atoi(args)) // Try searching by Id - guild = sGuildMgr->GetGuildById(guildId); - else - { - // Try to extract a guild name - char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; - if (!tailStr) - return false; - - char* guildStr = handler->extractQuotedArg((char*)args); - if (!guildStr) - return false; - - guildName = guildStr; - guild = sGuildMgr->GetGuildByName(guildName); + { + std::string guildName = args; + guild = sGuildMgr->GetGuildByName(guildName); + } } + else if (Player* target = handler->getSelectedPlayerOrSelf()) + guild = target->GetGuild(); if (!guild) return false; // Display Guild Information handler->PSendSysMessage(LANG_GUILD_INFO_NAME, guild->GetName().c_str(), guild->GetId()); // Guild Id + Name + + std::string guildMasterName; if (sObjectMgr->GetPlayerNameByGUID(guild->GetLeaderGUID(), guildMasterName)) handler->PSendSysMessage(LANG_GUILD_INFO_GUILD_MASTER, guildMasterName.c_str(), guild->GetLeaderGUID()); // Guild Master diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 04cc9ae4ad5..43afea1b381 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -30,6 +30,8 @@ EndScriptData */ #include "ScriptMgr.h" #include "SystemConfig.h" +#include <regex> + class server_commandscript : public CommandScript { public: @@ -201,145 +203,22 @@ public: static bool HandleServerShutDownCommand(ChatHandler* /*handler*/, char const* args) { - if (!*args) - return false; - - char* timeStr = strtok((char*) args, " "); - char* exitCodeStr = strtok(NULL, ""); - - int32 time = atoi(timeStr); - - // Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (timeStr[0] != '0' || timeStr[1] != '\0')) || time < 0) - return false; - - if (exitCodeStr) - { - int32 exitCode = atoi(exitCodeStr); - - // Handle atoi() errors - if (exitCode == 0 && (exitCodeStr[0] != '0' || exitCodeStr[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitCode < 0 || exitCode > 125) - return false; - - sWorld->ShutdownServ(time, 0, exitCode); - } - else - sWorld->ShutdownServ(time, 0, SHUTDOWN_EXIT_CODE); - - return true; + return ShutdownServer(args, 0, SHUTDOWN_EXIT_CODE); } static bool HandleServerRestartCommand(ChatHandler* /*handler*/, char const* args) { - if (!*args) - return false; - - char* timeStr = strtok((char*) args, " "); - char* exitCodeStr = strtok(NULL, ""); - - int32 time = atoi(timeStr); - - // Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (timeStr[0] != '0' || timeStr[1] != '\0')) || time < 0) - return false; - - if (exitCodeStr) - { - int32 exitCode = atoi(exitCodeStr); - - // Handle atoi() errors - if (exitCode == 0 && (exitCodeStr[0] != '0' || exitCodeStr[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitCode < 0 || exitCode > 125) - return false; - - sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART, exitCode); - } - else - sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE); - - return true; + return ShutdownServer(args, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE); } static bool HandleServerIdleRestartCommand(ChatHandler* /*handler*/, char const* args) { - if (!*args) - return false; - - char* timeStr = strtok((char*) args, " "); - char* exitCodeStr = strtok(NULL, ""); - - int32 time = atoi(timeStr); - - // Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (timeStr[0] != '0' || timeStr[1] != '\0')) || time < 0) - return false; - - if (exitCodeStr) - { - int32 exitCode = atoi(exitCodeStr); - - // Handle atoi() errors - if (exitCode == 0 && (exitCodeStr[0] != '0' || exitCodeStr[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitCode < 0 || exitCode > 125) - return false; - - sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, exitCode); - } - else - sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE); - return true; + return ShutdownServer(args, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE); } static bool HandleServerIdleShutDownCommand(ChatHandler* /*handler*/, char const* args) { - if (!*args) - return false; - - char* timeStr = strtok((char*) args, " "); - char* exitCodeStr = strtok(NULL, ""); - - int32 time = atoi(timeStr); - - // Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (timeStr[0] != '0' || timeStr[1] != '\0')) || time < 0) - return false; - - if (exitCodeStr) - { - int32 exitCode = atoi(exitCodeStr); - - // Handle atoi() errors - if (exitCode == 0 && (exitCodeStr[0] != '0' || exitCodeStr[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitCode < 0 || exitCode > 125) - return false; - - sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, exitCode); - } - else - sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE); - - return true; + return ShutdownServer(args, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE); } // Exit the realm @@ -415,6 +294,56 @@ public: return true; } + +private: + static bool ParseExitCode(std::string const& exitCodeStr, int32& exitCode) + { + exitCode = atoi(exitCodeStr.c_str()); + + // Handle atoi() errors + if (exitCode == 0 && (exitCodeStr[0] != '0' || exitCodeStr[1] != '\0')) + return false; + + // Exit code should be in range of 0-125, 126-255 is used + // in many shells for their own return codes and code > 255 + // is not supported in many others + if (exitCode < 0 || exitCode > 125) + return false; + + return true; + } + + static bool ShutdownServer(char const* args, uint32 shutdownMask, int32 defaultExitCode) + { + if (!*args) + return false; + + // #delay [#exit_code] [reason] + std::regex regex("([0-9]+) ([0-9]*) ?(.*)"); + std::cmatch cm; + + if (!std::regex_match(args, cm, regex)) + return false; + + std::string delayStr = cm[1]; + std::string exitCodeStr = cm[2]; + std::string reason = cm[3]; + + int32 delay = atoi(delayStr.c_str()); + + // Prevent interpret wrong arg value as 0 secs shutdown time + if ((delay == 0 && (delayStr[0] != '0' || delayStr[1] != '\0')) || delay < 0) + return false; + + int32 exitCode = defaultExitCode; + if (exitCodeStr.length() > 0) + if (!ParseExitCode(exitCodeStr, exitCode)) + return false; + + sWorld->ShutdownServ(delay, shutdownMask, static_cast<uint8>(exitCode), reason); + + return true; + } }; void AddSC_server_commandscript() diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp index 60a8e943bc7..52a05f6c0a3 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp @@ -20,27 +20,32 @@ enum Spells { - SPELL_ARCANE_EXPLOSION = 46608, - SPELL_CONE_OF_COLD = 38384, - SPELL_FIREBALL = 46988, - SPELL_FROSTBOLT = 46987 + SPELL_ARCANE_EXPLOSION = 46608, + SPELL_CONE_OF_COLD = 38384, + SPELL_FIREBALL = 46988, + SPELL_FROSTBOLT = 46987 }; enum Yells { - YELL_AGGRO = 0, - YELL_EVADE = 1, - YELL_SALVATION = 2, + YELL_AGGRO = 0, + YELL_EVADE = 1, + YELL_SALVATION = 2, }; enum Creatures { - NPC_WATER_ELEMENTAL = 25040 + NPC_WATER_ELEMENTAL = 25040 +}; + +enum Action +{ + ACTION_BUFF_YELL = -30001 // shared from Battleground }; enum WaterElementalSpells { - SPELL_WATERBOLT = 46983 + SPELL_WATERBOLT = 46983 }; class npc_water_elemental : public CreatureScript @@ -151,6 +156,12 @@ public: summons.DespawnAll(); } + void DoAction(int32 actionId) override + { + if (actionId == ACTION_BUFF_YELL) + Talk(YELL_AGGRO); + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp index c00b7db2ce7..9e4fc5838ad 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp @@ -30,7 +30,13 @@ enum Spells enum Yells { YELL_AGGRO = 0, - YELL_EVADE = 1 + YELL_EVADE = 1, + YELL_BUFF = 2 +}; + +enum Action +{ + ACTION_BUFF_YELL = -30001 // shared from Battleground }; class boss_galvangar : public CreatureScript @@ -69,6 +75,12 @@ public: Reset(); } + void DoAction(int32 actionId) override + { + if (actionId == ACTION_BUFF_YELL) + Talk(YELL_BUFF); + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index 26937a83e63..cdfcede1c93 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -124,7 +124,7 @@ class boss_arcanist_doan : public CreatureScript CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_arcanist_doanAI>(creature); + return GetScarletMonasteryAI<boss_arcanist_doanAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 71a5343d160..c3c74e4c83d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -15,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Azshir_the_Sleepless -SD%Complete: 80 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "scarlet_monastery.h" @@ -70,9 +63,9 @@ class boss_azshir_the_sleepless : public CreatureScript _JustDied(); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(50) && !_siphon) + if (!_siphon && me->HealthBelowPctDamaged(50, damage)) { DoCastVictim(SPELL_SOUL_SIPHON); events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000); @@ -120,7 +113,7 @@ class boss_azshir_the_sleepless : public CreatureScript CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_azshir_the_sleeplessAI>(creature); + return GetScarletMonasteryAI<boss_azshir_the_sleeplessAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 18369c7adfc..14698faaa97 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -80,9 +80,9 @@ class boss_bloodmage_thalnos : public CreatureScript Talk(SAY_KILL); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(35) && !_hpYell) + if (!_hpYell && me->HealthBelowPctDamaged(35, damage)) { Talk(SAY_HEALTH); _hpYell = true; @@ -114,18 +114,13 @@ class boss_bloodmage_thalnos : public CreatureScript } } - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } - private: bool _hpYell; }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_bloodmage_thalnosAI>(creature); + return GetScarletMonasteryAI<boss_bloodmage_thalnosAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index d1d25dd2ba6..d77334785ef 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -100,9 +100,9 @@ class boss_herod : public CreatureScript me->SummonCreature(NPC_SCARLET_TRAINEE, ScarletTraineePos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(30) && !_enrage) + if (!_enrage && me->HealthBelowPctDamaged(30, damage)) { Talk(EMOTE_ENRAGE); Talk(SAY_ENRAGE); @@ -129,18 +129,13 @@ class boss_herod : public CreatureScript } } - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } - private: bool _enrage; }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_herodAI>(creature); + return GetScarletMonasteryAI<boss_herodAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 40c7667843b..0e1b51f9a83 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -73,16 +73,11 @@ class boss_houndmaster_loksey : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_houndmaster_lokseyAI>(creature); + return GetScarletMonasteryAI<boss_houndmaster_lokseyAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index 24efd7017ec..d64e556c011 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -1,6 +1,5 @@ /* * 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 @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Scorn -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "scarlet_monastery.h" @@ -95,16 +87,11 @@ class boss_scorn : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_scornAI>(creature); + return GetScarletMonasteryAI<boss_scornAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp index 78837912688..dc65bd42bf4 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp @@ -28,7 +28,7 @@ DoorData const doorData[] = class instance_scarlet_monastery : public InstanceMapScript { public: - instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { } + instance_scarlet_monastery() : InstanceMapScript(SMScriptName, 189) { } struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript { diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h index d4ce3f1614f..a74efba751f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h @@ -18,6 +18,7 @@ #ifndef SCARLET_M_ #define SCARLET_M_ +#define SMScriptName "instance_scarlet_monastery" uint32 const EncounterCount = 10; enum DataTypes @@ -57,4 +58,10 @@ enum GameObjectIds GO_PUMPKIN_SHRINE = 186267 }; +template<class AI> +inline AI* GetScarletMonasteryAI(Creature* creature) +{ + return GetInstanceAI<AI>(creature, SMScriptName); +} + #endif // SCARLET_M_ diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 1ff7e1b1352..9d24ad062df 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -643,7 +643,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr, ++i) { Unit* target = *itr; - target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true); + target->CastSpell(target, BoneSpikeSummonId[i], true); } marrowgarAI->Talk(SAY_BONESPIKE); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index f60a7ba278b..11f20129b3e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1269,7 +1269,13 @@ class spell_putricide_mutated_plague : public SpellScriptLoader void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { uint32 healSpell = uint32(GetSpellInfo()->Effects[EFFECT_0].CalcValue()); - GetTarget()->CastSpell(GetTarget(), healSpell, true, NULL, NULL, GetCasterGUID()); + SpellInfo const* healSpellInfo = sSpellMgr->GetSpellInfo(healSpell); + + if (!healSpellInfo) + return; + + int32 heal = healSpellInfo->Effects[0].CalcValue() * GetStackAmount(); + GetTarget()->CastCustomSpell(healSpell, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, NULL, NULL, GetCasterGUID()); } void Register() override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index f1d44e72684..3a137a8658e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -172,7 +172,7 @@ enum Spells SPELL_MAGNETIC_CORE = 64436, SPELL_MAGNETIC_CORE_VISUAL = 64438, SPELL_HALF_HEAL = 64188, - SPELL_CLEAR_ALL_DEBUFFS = 34098, // TODO: make use of this spell... + SPELL_CLEAR_ALL_DEBUFFS = 34098, /// @todo: make use of this spell... SPELL_FREEZE_ANIM_STUN = 63354, // used to prevent mkii from doing stuff?.. SPELL_FREEZE_ANIM = 16245 // Idle aura. Freezes animation. }; @@ -303,17 +303,10 @@ enum Actions enum Phases { - // Leviathan MK II - PHASE_LEVIATHAN_SOLO = 1, - PHASE_LEVIATHAN_ASSEMBLED, - - // VX-001 - PHASE_VX001_SOLO, - PHASE_VX001_ASSEMBLED, - - // Aerial Command Unit - PHASE_AERIAL_SOLO, - PHASE_AERIAL_ASSEMBLED + PHASE_LEVIATHAN_MK_II = 1, + PHASE_VX_001, + PHASE_AERIAL_COMMAND_UNIT, + PHASE_VOL7RON }; enum Waypoints @@ -434,7 +427,7 @@ class boss_mimiron : public CreatureScript events.ScheduleEvent(EVENT_SUMMON_FLAMES, 3000); events.ScheduleEvent(EVENT_INTRO_1, 1500); } - + void JustDied(Unit* /*who*/) override { instance->SetBossState(BOSS_MIMIRON, DONE); @@ -456,7 +449,9 @@ class boss_mimiron : public CreatureScript _Reset(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - instance->SetData(DATA_MIMIRON_ELEVATOR, GO_STATE_ACTIVE); + + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_ACTIVE); if (_fireFighter) if (Creature* computer = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_COMPUTER))) @@ -526,15 +521,17 @@ class boss_mimiron : public CreatureScript events.ScheduleEvent(EVENT_VX001_ACTIVATION_4, 5000); break; case EVENT_VX001_ACTIVATION_4: - instance->SetData(DATA_MIMIRON_ELEVATOR, GO_STATE_READY); + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_READY); if (Unit* worldtrigger = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_MIMIRON_WORLD_TRIGGER))) worldtrigger->CastSpell(worldtrigger, SPELL_ELEVATOR_KNOCKBACK); events.ScheduleEvent(EVENT_VX001_ACTIVATION_5, 6000); break; case EVENT_VX001_ACTIVATION_5: + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); if (Creature* vx001 = me->SummonCreature(NPC_VX_001, VX001SummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000)) vx001->CastSpell(vx001, SPELL_FREEZE_ANIM); - instance->SetData(DATA_MIMIRON_ELEVATOR, GO_STATE_ACTIVE_ALTERNATIVE); events.ScheduleEvent(EVENT_VX001_ACTIVATION_6, 19000); break; case EVENT_VX001_ACTIVATION_6: @@ -579,7 +576,7 @@ class boss_mimiron : public CreatureScript break; case EVENT_AERIAL_ACTIVATION_6: if (Creature* acu = me->GetVehicleCreatureBase()) - acu->GetAI()->DoAction(_fireFighter? DO_HARDMODE_AERIAL : DO_START_AERIAL); + acu->AI()->DoAction(_fireFighter? DO_HARDMODE_AERIAL : DO_START_AERIAL); break; case EVENT_VOL7RON_ACTIVATION_1: if (Creature* mkii = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) @@ -694,7 +691,7 @@ class boss_leviathan_mk_ii : public CreatureScript me->SetReactState(REACT_PASSIVE); me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); - if (events.IsInPhase(PHASE_LEVIATHAN_SOLO)) + if (events.IsInPhase(PHASE_LEVIATHAN_MK_II)) { me->CastStop(); if (Unit* turret = me->GetVehicleKit()->GetPassenger(3)) @@ -703,7 +700,7 @@ class boss_leviathan_mk_ii : public CreatureScript me->SetSpeed(MOVE_RUN, 1.5f, true); me->GetMotionMaster()->MovePoint(WP_MKII_P1_IDLE, VehicleRelocation[WP_MKII_P1_IDLE]); } - else if (events.IsInPhase(PHASE_LEVIATHAN_ASSEMBLED)) + else if (events.IsInPhase(PHASE_VOL7RON)) { me->SetStandState(UNIT_STAND_STATE_DEAD); @@ -725,14 +722,14 @@ class boss_leviathan_mk_ii : public CreatureScript _fireFighter = true; DoCast(me, SPELL_EMERGENCY_MODE); DoCastAOE(SPELL_EMERGENCY_MODE_TURRET); - events.ScheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_SOLO); + events.ScheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_MK_II); // Missing break intended. case DO_START_MKII: me->SetReactState(REACT_AGGRESSIVE); - events.SetPhase(PHASE_LEVIATHAN_SOLO); + events.SetPhase(PHASE_LEVIATHAN_MK_II); - events.ScheduleEvent(EVENT_NAPALM_SHELL, 3000, 0, PHASE_LEVIATHAN_SOLO); - events.ScheduleEvent(EVENT_PLASMA_BLAST, 15000, 0, PHASE_LEVIATHAN_SOLO); + events.ScheduleEvent(EVENT_NAPALM_SHELL, 3000, 0, PHASE_LEVIATHAN_MK_II); + events.ScheduleEvent(EVENT_PLASMA_BLAST, 15000, 0, PHASE_LEVIATHAN_MK_II); events.ScheduleEvent(EVENT_PROXIMITY_MINE, 5000); events.ScheduleEvent(EVENT_SHOCK_BLAST, 18000); break; @@ -741,7 +738,7 @@ class boss_leviathan_mk_ii : public CreatureScript me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); - events.SetPhase(PHASE_LEVIATHAN_ASSEMBLED); + events.SetPhase(PHASE_VOL7RON); events.ScheduleEvent(EVENT_PROXIMITY_MINE, 15000); events.ScheduleEvent(EVENT_SHOCK_BLAST, 45000); break; @@ -776,14 +773,14 @@ class boss_leviathan_mk_ii : public CreatureScript { if (victim->GetTypeId() == TYPEID_PLAYER) if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) - mimiron->AI()->Talk(events.IsInPhase(PHASE_LEVIATHAN_SOLO) ? SAY_MKII_SLAY : SAY_V07TRON_SLAY); + mimiron->AI()->Talk(events.IsInPhase(PHASE_LEVIATHAN_MK_II) ? SAY_MKII_SLAY : SAY_V07TRON_SLAY); } void MovementInform(uint32 type, uint32 point) override { if (type != POINT_MOTION_TYPE) return; - + switch (point) { case WP_MKII_P1_IDLE: @@ -845,7 +842,7 @@ class boss_leviathan_mk_ii : public CreatureScript { if (!UpdateVictim() || !CheckInRoom()) return; - + events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) @@ -861,10 +858,10 @@ class boss_leviathan_mk_ii : public CreatureScript break; case EVENT_PLASMA_BLAST: DoCastVictim(SPELL_SCRIPT_EFFECT_PLASMA_BLAST); - events.RescheduleEvent(EVENT_PLASMA_BLAST, urand(30000, 45000), 0, PHASE_LEVIATHAN_SOLO); + events.RescheduleEvent(EVENT_PLASMA_BLAST, urand(30000, 45000), 0, PHASE_LEVIATHAN_MK_II); if (events.GetTimeUntilEvent(EVENT_NAPALM_SHELL) < 9000) - events.RescheduleEvent(EVENT_NAPALM_SHELL, 9000, 0, PHASE_LEVIATHAN_SOLO); // The actual spell is cast by the turret, we should not let it interrupt itself. + events.RescheduleEvent(EVENT_NAPALM_SHELL, 9000, 0, PHASE_LEVIATHAN_MK_II); // The actual spell is cast by the turret, we should not let it interrupt itself. break; case EVENT_SHOCK_BLAST: DoCastAOE(SPELL_SHOCK_BLAST); @@ -872,14 +869,14 @@ class boss_leviathan_mk_ii : public CreatureScript break; case EVENT_FLAME_SUPPRESSANT_MK: DoCastAOE(SPELL_FLAME_SUPPRESSANT_MK); - events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_SOLO); + events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_MK_II); break; case EVENT_NAPALM_SHELL: DoCastAOE(SPELL_FORCE_CAST_NAPALM_SHELL); - events.RescheduleEvent(EVENT_NAPALM_SHELL, urand(6000, 15000), 0, PHASE_LEVIATHAN_SOLO); + events.RescheduleEvent(EVENT_NAPALM_SHELL, urand(6000, 15000), 0, PHASE_LEVIATHAN_MK_II); if (events.GetTimeUntilEvent(EVENT_PLASMA_BLAST) < 2000) - events.RescheduleEvent(EVENT_PLASMA_BLAST, 2000, 0, PHASE_LEVIATHAN_SOLO); // The actual spell is cast by the turret, we should not let it interrupt itself. + events.RescheduleEvent(EVENT_PLASMA_BLAST, 2000, 0, PHASE_LEVIATHAN_MK_II); // The actual spell is cast by the turret, we should not let it interrupt itself. break; case EVENT_MOVE_POINT_2: me->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_2, VehicleRelocation[WP_MKII_P4_POS_2]); @@ -893,7 +890,7 @@ class boss_leviathan_mk_ii : public CreatureScript default: break; } - } + } DoMeleeAttackIfReady(); } @@ -934,7 +931,7 @@ class boss_vx_001 : public CreatureScript DoCast(me, SPELL_VEHICLE_DAMAGED, true); me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); - if (events.IsInPhase(PHASE_VX001_SOLO)) + if (events.IsInPhase(PHASE_VX_001)) { me->CastStop(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // | UNIT_FLAG_NOT_SELECTABLE); @@ -942,9 +939,9 @@ class boss_vx_001 : public CreatureScript DoCast(me, SPELL_TORSO_DISABLED); if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) mimiron->AI()->DoAction(DO_ACTIVATE_AERIAL); - } - else if (events.IsInPhase(PHASE_VX001_ASSEMBLED)) - { + } + else if (events.IsInPhase(PHASE_VOL7RON)) + { me->SetStandState(UNIT_STAND_STATE_DEAD); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -975,19 +972,19 @@ class boss_vx_001 : public CreatureScript //me->SetUInt32Value(UNIT_FIELD_BYTES_1, 33554432); Blizzard handles hover animation like this it seems. DoCast(me, SPELL_HEAT_WAVE_AURA); - events.SetPhase(PHASE_VX001_SOLO); + events.SetPhase(PHASE_VX_001); events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); - events.ScheduleEvent(EVENT_RAPID_BURST, 500, 0, PHASE_VX001_SOLO); + events.ScheduleEvent(EVENT_RAPID_BURST, 500, 0, PHASE_VX_001); break; case DO_ASSEMBLED_COMBAT: me->SetStandState(UNIT_STAND_STATE_STAND); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - events.SetPhase(PHASE_VX001_ASSEMBLED); + events.SetPhase(PHASE_VOL7RON); events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); - events.ScheduleEvent(EVENT_HAND_PULSE, 500, 0, PHASE_VX001_ASSEMBLED); + events.ScheduleEvent(EVENT_HAND_PULSE, 500, 0, PHASE_VOL7RON); if (_fireFighter) events.ScheduleEvent(EVENT_FROST_BOMB, 1000); break; @@ -1012,9 +1009,9 @@ class boss_vx_001 : public CreatureScript { if (victim->GetTypeId() == TYPEID_PLAYER) if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) - mimiron->AI()->Talk(events.IsInPhase(PHASE_VX001_SOLO) ? SAY_VX001_SLAY : SAY_V07TRON_SLAY); + mimiron->AI()->Talk(events.IsInPhase(PHASE_VX_001) ? SAY_VX001_SLAY : SAY_V07TRON_SLAY); } - + void SpellHit(Unit* caster, SpellInfo const* /*spellProto*/) override { if (caster->GetEntry() == NPC_BURST_TARGET && !me->HasUnitState(UNIT_STATE_CASTING)) @@ -1043,10 +1040,10 @@ class boss_vx_001 : public CreatureScript case EVENT_RAPID_BURST: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 120, true)) DoCast(target, SPELL_SUMMON_BURST_TARGET); - events.RescheduleEvent(EVENT_RAPID_BURST, 3000, 0, PHASE_VX001_SOLO); + events.RescheduleEvent(EVENT_RAPID_BURST, 3000, 0, PHASE_VX_001); break; case EVENT_ROCKET_STRIKE: - DoCastAOE(events.IsInPhase(PHASE_VX001_SOLO) ? SPELL_ROCKET_STRIKE_LEFT : SPELL_ROCKET_STRIKE_BOTH); + DoCastAOE(events.IsInPhase(PHASE_VX_001) ? SPELL_ROCKET_STRIKE_LEFT : SPELL_ROCKET_STRIKE_BOTH); events.ScheduleEvent(EVENT_RELOAD, 10000); events.RescheduleEvent(EVENT_ROCKET_STRIKE, urand(20000, 25000)); break; @@ -1058,7 +1055,7 @@ class boss_vx_001 : public CreatureScript case EVENT_HAND_PULSE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 120, true)) DoCast(target, urand(0, 1) == 0 ? SPELL_HAND_PULSE_LEFT : SPELL_HAND_PULSE_RIGHT); - events.RescheduleEvent(EVENT_HAND_PULSE, urand(1500, 3000), 0, PHASE_VX001_ASSEMBLED); + events.RescheduleEvent(EVENT_HAND_PULSE, urand(1500, 3000), 0, PHASE_VOL7RON); break; case EVENT_FROST_BOMB: DoCastAOE(SPELL_SCRIPT_EFFECT_FROST_BOMB); @@ -1071,7 +1068,7 @@ class boss_vx_001 : public CreatureScript break; case EVENT_FLAME_SUPPRESSANT_VX: DoCastAOE(SPELL_FLAME_SUPPRESSANT_VX); - events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_VX, urand(10000, 12000), 0, PHASE_VX001_SOLO); + events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_VX, urand(10000, 12000), 0, PHASE_VX_001); break; default: break; @@ -1113,12 +1110,12 @@ class boss_aerial_command_unit : public CreatureScript DoCast(me, SPELL_VEHICLE_DAMAGED, true); me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); - if (events.IsInPhase(PHASE_AERIAL_SOLO)) + if (events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT)) { me->GetMotionMaster()->Clear(true); me->GetMotionMaster()->MovePoint(WP_AERIAL_P4_POS, VehicleRelocation[WP_AERIAL_P4_POS]); } - else if (events.IsInPhase(PHASE_AERIAL_ASSEMBLED)) + else if (events.IsInPhase(PHASE_VOL7RON)) { me->SetStandState(UNIT_STAND_STATE_DEAD); @@ -1139,16 +1136,16 @@ class boss_aerial_command_unit : public CreatureScript case DO_HARDMODE_AERIAL: fireFigther = true; DoCast(me, SPELL_EMERGENCY_MODE); - events.ScheduleEvent(EVENT_SUMMON_FIRE_BOTS, 1000, 0, PHASE_AERIAL_SOLO); + events.ScheduleEvent(EVENT_SUMMON_FIRE_BOTS, 1000, 0, PHASE_AERIAL_COMMAND_UNIT); // Missing break intended. case DO_START_AERIAL: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); - events.SetPhase(PHASE_AERIAL_SOLO); - events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 5000, 0, PHASE_AERIAL_SOLO); - events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 9000, 0, PHASE_AERIAL_SOLO); - events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 9000, 0, PHASE_AERIAL_SOLO); + events.SetPhase(PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 5000, 0, PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 9000, 0, PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 9000, 0, PHASE_AERIAL_COMMAND_UNIT); break; case DO_DISABLE_AERIAL: me->CastStop(); @@ -1164,7 +1161,7 @@ class boss_aerial_command_unit : public CreatureScript me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); me->SetReactState(REACT_AGGRESSIVE); me->SetStandState(UNIT_STAND_STATE_STAND); - events.SetPhase(PHASE_AERIAL_ASSEMBLED); + events.SetPhase(PHASE_VOL7RON); break; default: break; @@ -1187,7 +1184,7 @@ class boss_aerial_command_unit : public CreatureScript { if (victim->GetTypeId() == TYPEID_PLAYER) if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) - mimiron->AI()->Talk(events.IsInPhase(PHASE_AERIAL_SOLO) ? SAY_AERIAL_SLAY : SAY_V07TRON_SLAY); + mimiron->AI()->Talk(events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT) ? SAY_AERIAL_SLAY : SAY_V07TRON_SLAY); } void MovementInform(uint32 type, uint32 point) override @@ -1195,47 +1192,47 @@ class boss_aerial_command_unit : public CreatureScript if (type == POINT_MOTION_TYPE && point == WP_AERIAL_P4_POS) { me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) mimiron->AI()->DoAction(DO_ACTIVATE_V0L7R0N_1); } } - + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; - + events.Update(diff); - + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { case EVENT_SUMMON_FIRE_BOTS: me->CastCustomSpell(SPELL_SUMMON_FIRE_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 3, NULL, true); - events.RescheduleEvent(EVENT_SUMMON_FIRE_BOTS, 45000, 0, PHASE_AERIAL_SOLO); + events.RescheduleEvent(EVENT_SUMMON_FIRE_BOTS, 45000, 0, PHASE_AERIAL_COMMAND_UNIT); break; case EVENT_SUMMON_JUNK_BOT: me->CastCustomSpell(SPELL_SUMMON_JUNK_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, NULL, true); - events.RescheduleEvent(EVENT_SUMMON_JUNK_BOT, urand(11000, 12000), 0, PHASE_AERIAL_SOLO); + events.RescheduleEvent(EVENT_SUMMON_JUNK_BOT, urand(11000, 12000), 0, PHASE_AERIAL_COMMAND_UNIT); break; case EVENT_SUMMON_ASSAULT_BOT: me->CastCustomSpell(SPELL_SUMMON_ASSAULT_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, NULL, true); - events.RescheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 30000, 0, PHASE_AERIAL_SOLO); + events.RescheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 30000, 0, PHASE_AERIAL_COMMAND_UNIT); break; case EVENT_SUMMON_BOMB_BOT: DoCast(me, SPELL_SUMMON_BOMB_BOT); - events.RescheduleEvent(EVENT_SUMMON_BOMB_BOT, urand(15000, 20000), 0, PHASE_AERIAL_SOLO); + events.RescheduleEvent(EVENT_SUMMON_BOMB_BOT, urand(15000, 20000), 0, PHASE_AERIAL_COMMAND_UNIT); break; default: break; } } - DoSpellAttackIfReady(events.IsInPhase(PHASE_AERIAL_SOLO) ? SPELL_PLASMA_BALL_P1 : SPELL_PLASMA_BALL_P2); + DoSpellAttackIfReady(events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT) ? SPELL_PLASMA_BALL_P1 : SPELL_PLASMA_BALL_P2); } private: @@ -1344,7 +1341,7 @@ class npc_mimiron_emergency_fire_bot : public CreatureScript isWaterSprayReady = true; moveNew = true; } - + void UpdateAI(uint32 diff) override { if (!isWaterSprayReady) @@ -1497,7 +1494,7 @@ class npc_mimiron_flames : public CreatureScript { events.ScheduleEvent(EVENT_SPREAD_FLAMES, 4000); } - + void UpdateAI(uint32 diff) override { if (instance->GetBossState(BOSS_MIMIRON) != IN_PROGRESS) @@ -1544,7 +1541,7 @@ class npc_mimiron_frost_bomb : public CreatureScript { events.ScheduleEvent(EVENT_FROST_BOMB_EXPLOSION, 10000); } - + void UpdateAI(uint32 diff) override { events.Update(diff); @@ -1592,7 +1589,7 @@ class npc_mimiron_proximity_mine : public CreatureScript { events.ScheduleEvent(EVENT_PROXIMITY_MINE_ARM, 1500); } - + void UpdateAI(uint32 diff) override { events.Update(diff); @@ -1630,14 +1627,13 @@ class go_mimiron_hardmode_button : public GameObjectScript { public: go_mimiron_hardmode_button() : GameObjectScript("go_mimiron_hardmode_button") { } - + bool OnGossipHello(Player* /*player*/, GameObject* go) { InstanceScript* instance = go->GetInstanceScript(); - if (!instance) return false; - + if (Creature* computer = ObjectAccessor::GetCreature(*go, instance->GetData64(DATA_COMPUTER))) computer->AI()->DoAction(DO_ACTIVATE_COMPUTER); go->SetGoState(GO_STATE_ACTIVE); @@ -1646,7 +1642,7 @@ class go_mimiron_hardmode_button : public GameObjectScript } }; -// 63801 Bomb Bot +// 63801 - Bomb Bot class spell_mimiron_bomb_bot : public SpellScriptLoader { public: @@ -1860,7 +1856,7 @@ class spell_mimiron_magnetic_core : public SpellScriptLoader { if (Creature* target = GetTarget()->ToCreature()) { - target->GetAI()->DoAction(DO_DISABLE_AERIAL); + target->AI()->DoAction(DO_DISABLE_AERIAL); target->CastSpell(target, SPELL_MAGNETIC_CORE_VISUAL, true); } } @@ -1869,7 +1865,7 @@ class spell_mimiron_magnetic_core : public SpellScriptLoader { if (Creature* target = GetTarget()->ToCreature()) { - target->GetAI()->DoAction(DO_ENABLE_AERIAL); + target->AI()->DoAction(DO_ENABLE_AERIAL); target->RemoveAurasDueToSpell(SPELL_MAGNETIC_CORE_VISUAL); } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 1f9bfe4c3f3..a074ce28181 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -15,12 +15,13 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ulduar.h" +#include "InstanceScript.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptMgr.h" #include "SpellScript.h" #include "WorldPacket.h" +#include "ulduar.h" static DoorData const doorData[] = { @@ -821,10 +822,6 @@ class instance_ulduar : public InstanceMapScript case DATA_UNBROKEN: Unbroken = data != 0; break; - case DATA_MIMIRON_ELEVATOR: - if (GameObject* gameObject = instance->GetGameObject(MimironElevatorGUID)) - gameObject->SetGoState((GOState)data); - break; case DATA_ILLUSION: illusion = data; break; @@ -924,6 +921,8 @@ class instance_ulduar : public InstanceMapScript return MimironComputerGUID; case DATA_MIMIRON_WORLD_TRIGGER: return MimironWorldTriggerGUID; + case DATA_MIMIRON_ELEVATOR: + return MimironElevatorGUID; case DATA_MIMIRON_BUTTON: return MimironButtonGUID; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 81cb469318f..5dfc2b54f6e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -18,8 +18,6 @@ #ifndef DEF_ULDUAR_H #define DEF_ULDUAR_H -#include "InstanceScript.h" -#include "ObjectMgr.h" #define UlduarScriptName "instance_ulduar" extern Position const ObservationRingKeepersPos[4]; diff --git a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp index 9cb7505c015..1776cccb6cc 100644 --- a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp +++ b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp @@ -1,6 +1,5 @@ /* * 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 @@ -16,15 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Talon_King_Ikiss -SD%Complete: 80 -SDComment: Heroic supported. Some details missing, but most are spell related. -SDCategory: Auchindoun, Sethekk Halls -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "sethekk_halls.h" enum Says @@ -33,7 +26,7 @@ enum Says SAY_AGGRO = 1, SAY_SLAY = 2, SAY_DEATH = 3, - EMOTE_ARCANE_EXP = 4 + EMOTE_ARCANE_EXPLOSION = 4 }; enum Spells @@ -42,13 +35,19 @@ enum Spells SPELL_BLINK_TELEPORT = 38203, SPELL_MANA_SHIELD = 38151, SPELL_ARCANE_BUBBLE = 9438, - H_SPELL_SLOW = 35032, + SPELL_SLOW = 35032, SPELL_POLYMORPH = 38245, - H_SPELL_POLYMORPH = 43309, SPELL_ARCANE_VOLLEY = 35059, - H_SPELL_ARCANE_VOLLEY = 40424, SPELL_ARCANE_EXPLOSION = 38197, - H_SPELL_ARCANE_EXPLOSION = 40425 +}; + +enum Events +{ + EVENT_POLYMORPH = 1, + EVENT_BLINK, + EVENT_SLOW, + EVENT_ARCANE_VOLLEY, + EVENT_ARCANE_EXPLOSION }; class boss_talon_king_ikiss : public CreatureScript @@ -58,16 +57,15 @@ public: struct boss_talon_king_ikissAI : public BossAI { - boss_talon_king_ikissAI(Creature* creature) : BossAI(creature, DATA_TALON_KING_IKISS) { } + boss_talon_king_ikissAI(Creature* creature) : BossAI(creature, DATA_TALON_KING_IKISS) + { + Intro = false; + ManaShield = false; + } void Reset() override { _Reset(); - ArcaneVolley_Timer = 5000; - Sheep_Timer = 8000; - Blink_Timer = 35000; - Slow_Timer = 15000 + rand32() % 15000; - Blink = false; Intro = false; ManaShield = false; } @@ -87,10 +85,7 @@ public: float attackRadius = me->GetAttackDistance(who); if (me->IsWithinDistInMap(who, attackRadius) && me->IsWithinLOSInMap(who)) - { - //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); AttackStart(who); - } } } @@ -98,6 +93,57 @@ public: { _EnterCombat(); Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_ARCANE_VOLLEY, 5000); + events.ScheduleEvent(EVENT_POLYMORPH, 8000); + events.ScheduleEvent(EVENT_BLINK, 35000); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SLOW, urand(15000, 30000)); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_POLYMORPH: + // Second top aggro in normal, random target in heroic. + if (IsHeroic()) + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_POLYMORPH); + else + DoCast(SelectTarget(SELECT_TARGET_TOPAGGRO, 1), SPELL_POLYMORPH); + events.ScheduleEvent(EVENT_POLYMORPH, urand(15000, 17500)); + break; + case EVENT_ARCANE_VOLLEY: + DoCast(me, SPELL_ARCANE_VOLLEY); + events.ScheduleEvent(EVENT_ARCANE_VOLLEY, urand(7000, 12000)); + break; + case EVENT_SLOW: + DoCast(me, SPELL_SLOW); + events.ScheduleEvent(EVENT_SLOW, urand(15000, 40000)); + break; + case EVENT_BLINK: + if (me->IsNonMeleeSpellCast(false)) + me->InterruptNonMeleeSpells(false); + Talk(EMOTE_ARCANE_EXPLOSION); + DoCastAOE(SPELL_BLINK); + events.ScheduleEvent(EVENT_BLINK, urand(35000, 40000)); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 1000); + break; + case EVENT_ARCANE_EXPLOSION: + DoCast(me, SPELL_ARCANE_EXPLOSION); + DoCast(me, SPELL_ARCANE_BUBBLE, true); + break; + default: + break; + } + } + + void DamageTaken(Unit* /*who*/, uint32& damage) override + { + if (!ManaShield && me->HealthBelowPctDamaged(20, damage)) + { + DoCast(me, SPELL_MANA_SHIELD); + ManaShield = true; + } } void JustDied(Unit* /*killer*/) override @@ -112,101 +158,62 @@ public: Talk(SAY_SLAY); } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (Blink) - { - DoCast(me, SPELL_ARCANE_EXPLOSION); - DoCast(me, SPELL_ARCANE_BUBBLE, true); - Blink = false; - } - - if (ArcaneVolley_Timer <= diff) - { - DoCast(me, SPELL_ARCANE_VOLLEY); - ArcaneVolley_Timer = 7000 + rand32() % 5000; - } else ArcaneVolley_Timer -= diff; - - if (Sheep_Timer <= diff) - { - Unit* target; - - //second top aggro target in normal, random target in heroic correct? - if (IsHeroic()) - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - else - target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1); - - if (target) - DoCast(target, SPELL_POLYMORPH); - Sheep_Timer = 15000 + rand32() % 2500; - } else Sheep_Timer -= diff; - - //may not be correct time to cast - if (!ManaShield && HealthBelowPct(20)) - { - DoCast(me, SPELL_MANA_SHIELD); - ManaShield = true; - } - - if (IsHeroic()) - { - if (Slow_Timer <= diff) - { - DoCast(me, H_SPELL_SLOW); - Slow_Timer = 15000 + rand32() % 25000; - } else Slow_Timer -= diff; - } - - if (Blink_Timer <= diff) - { - Talk(EMOTE_ARCANE_EXP); - - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - if (me->IsNonMeleeSpellCast(false)) - me->InterruptNonMeleeSpells(false); + private: + bool ManaShield; + bool Intro; + }; - //Spell doesn't work, but we use for visual effect at least - DoCast(target, SPELL_BLINK); + CreatureAI* GetAI(Creature* creature) const override + { + return GetSethekkHallsAI<boss_talon_king_ikissAI>(creature); + } +}; - float X = target->GetPositionX(); - float Y = target->GetPositionY(); - float Z = target->GetPositionZ(); +// 38194 - Blink +class spell_talon_king_ikiss_blink : public SpellScriptLoader +{ + public: + spell_talon_king_ikiss_blink() : SpellScriptLoader("spell_talon_king_ikiss_blink") { } - DoTeleportTo(X, Y, Z); + class spell_talon_king_ikiss_blink_SpellScript : public SpellScript + { + PrepareSpellScript(spell_talon_king_ikiss_blink_SpellScript); - DoCast(target, SPELL_BLINK_TELEPORT); - Blink = true; - } - Blink_Timer = 35000 + rand32() % 5000; - } else Blink_Timer -= diff; + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_BLINK)) + return false; + return true; + } - if (!Blink) - DoMeleeAttackIfReady(); + void FilterTargets(std::list<WorldObject*>& targets) + { + uint8 maxSize = 1; + if (targets.size() > maxSize) + Trinity::Containers::RandomResizeList(targets, maxSize); } - private: - uint32 ArcaneVolley_Timer; - uint32 Sheep_Timer; - uint32 Blink_Timer; - uint32 Slow_Timer; + void HandleDummyHitTarget(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetCaster(), SPELL_BLINK_TELEPORT, true); + } - bool ManaShield; - bool Blink; - bool Intro; + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_talon_king_ikiss_blink_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_talon_king_ikiss_blink_SpellScript::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; - CreatureAI* GetAI(Creature* creature) const override + SpellScript* GetSpellScript() const override { - return GetSethekkHallsAI<boss_talon_king_ikissAI>(creature); + return new spell_talon_king_ikiss_blink_SpellScript(); } }; void AddSC_boss_talon_king_ikiss() { new boss_talon_king_ikiss(); + new spell_talon_king_ikiss_blink(); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp index d4fdb262c8e..dfbc49e1e34 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp @@ -110,11 +110,6 @@ class boss_hydromancer_thespia : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override |