diff options
Diffstat (limited to 'src')
87 files changed, 4305 insertions, 749 deletions
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index 57ab1ffa4ed..6d756434a20 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -80,6 +80,8 @@ target_link_libraries(authserver shared ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${ACE_LIBRARY} ) if( WIN32 ) diff --git a/src/server/collision/BoundingIntervalHierarchy.cpp b/src/server/collision/BoundingIntervalHierarchy.cpp index 340d66ddaf0..c5ae1f2a265 100644 --- a/src/server/collision/BoundingIntervalHierarchy.cpp +++ b/src/server/collision/BoundingIntervalHierarchy.cpp @@ -272,7 +272,7 @@ bool BIH::readFromFile(FILE* rf) check += fread(&count, sizeof(uint32), 1, rf); objects.resize(count); // = new uint32[nObjects]; check += fread(&objects[0], sizeof(uint32), count, rf); - return check == (3 + 3 + 2 + treeSize + count); + return uint64(check) == uint64(3 + 3 + 1 + 1 + uint64(treeSize) + uint64(count)); } void BIH::BuildStats::updateLeaf(int depth, int n) diff --git a/src/server/collision/Management/MMapFactory.cpp b/src/server/collision/Management/MMapFactory.cpp index 7adf7fbfa66..6aa71d77ed8 100644 --- a/src/server/collision/Management/MMapFactory.cpp +++ b/src/server/collision/Management/MMapFactory.cpp @@ -25,7 +25,7 @@ namespace MMAP { // ######################## MMapFactory ######################## // our global singleton copy - MMapManager *g_MMapManager = NULL; + MMapManager* g_MMapManager = NULL; MMapManager* MMapFactory::createOrGetMMapManager() { diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index 70ae878aa6b..a3f89f42443 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -109,7 +109,7 @@ namespace MMAP snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); - FILE *file = fopen(fileName, "rb"); + FILE* file = fopen(fileName, "rb"); if (!file) { TC_LOG_DEBUG(LOG_FILTER_MAPS, "MMAP:loadMap: Could not open mmtile file '%s'", fileName); @@ -123,6 +123,7 @@ namespace MMAP if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC) { TC_LOG_ERROR(LOG_FILTER_MAPS, "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y); + fclose(file); return false; } @@ -130,6 +131,7 @@ namespace MMAP { TC_LOG_ERROR(LOG_FILTER_MAPS, "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION); + fclose(file); return false; } @@ -154,7 +156,7 @@ namespace MMAP { mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef)); ++loadedTiles; - TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y); + TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y); return true; } else @@ -203,7 +205,7 @@ namespace MMAP { mmap->mmapLoadedTiles.erase(packedGridPos); --loadedTiles; - TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); + TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); return true; } @@ -230,7 +232,7 @@ namespace MMAP else { --loadedTiles; - TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); + TC_LOG_INFO(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); } } diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp index ba1ae275c9a..aca7c02e79f 100644 --- a/src/server/collision/Maps/TileAssembler.cpp +++ b/src/server/collision/Maps/TileAssembler.cpp @@ -516,7 +516,8 @@ namespace VMAP for (uint32 g = 0; g < groups && succeed; ++g) succeed = groupsArray[g].Read(rf); - fclose(rf); + if (succeed) /// rf will be freed inside Read if the function had any errors. + fclose(rf); return succeed; } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index b4053da2932..576d77a2e24 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1470,8 +1470,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!einfo) { TC_LOG_ERROR(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u", equipId, npc->GetEntry()); + delete targets; return; } + npc->SetCurrentEquipmentId(equipId); slot[0] = einfo->ItemEntry[0]; slot[1] = einfo->ItemEntry[1]; @@ -2576,6 +2578,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui return; ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim()); + break; } case SMART_EVENT_FRIENDLY_HEALTH: { diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 6d58e41e2ab..668858618cb 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -367,31 +367,31 @@ void ArenaTeam::Roster(WorldSession* session) uint8 unk308 = 0; WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100); - data << uint32(GetId()); // team id - data << uint8(unk308); // 308 unknown value but affect packet structure - data << uint32(GetMembersSize()); // members count - data << uint32(GetType()); // arena team type? + data << uint32(GetId()); // team id + data << uint8(unk308); // 3.0.8 unknown value but affect packet structure + data << uint32(GetMembersSize()); // members count + data << uint32(GetType()); // arena team type? for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr) { player = ObjectAccessor::FindPlayer(itr->Guid); - data << uint64(itr->Guid); // guid + data << uint64(itr->Guid); // guid data << uint8((player ? 1 : 0)); // online flag - data << itr->Name; // member name - data << uint32((itr->Guid == GetCaptain() ? 0 : 1));// captain flag 0 captain 1 member - data << uint8((player ? player->getLevel() : 0)); // unknown, level? - data << uint8(itr->Class); // class - data << uint32(itr->WeekGames); // played this week - data << uint32(itr->WeekWins); // wins this week - data << uint32(itr->SeasonGames); // played this season - data << uint32(itr->SeasonWins); // wins this season - data << uint32(itr->PersonalRating); // personal rating - if (unk308) - { - data << float(0.0f); // 308 unk - data << float(0.0f); // 308 unk - } + data << itr->Name; // member name + data << uint32((itr->Guid == GetCaptain() ? 0 : 1)); // captain flag 0 captain 1 member + data << uint8((player ? player->getLevel() : 0)); // unknown, level? + data << uint8(itr->Class); // class + data << uint32(itr->WeekGames); // played this week + data << uint32(itr->WeekWins); // wins this week + data << uint32(itr->SeasonGames); // played this season + data << uint32(itr->SeasonWins); // wins this season + data << uint32(itr->PersonalRating); // personal rating + //if (unk308) + //{ + // data << float(0.0f); // 308 unk + // data << float(0.0f); // 308 unk + //} } session->SendPacket(&data); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 18afd190739..0ad4afc9028 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -812,6 +812,7 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original { case BATTLEGROUND_RB: isRandom = true; + /// Intentional fallback, "All Arenas" is random too case BATTLEGROUND_AA: bgTypeId = GetRandomBG(originalBgTypeId); break; @@ -1335,7 +1336,7 @@ void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 ar { //This method must be atomic, @todo add mutex //we will use only 1 number created of bgTypeId and bracket_id - uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id; + uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | (uint32(arenaType) << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id; if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end()) m_QueueUpdateScheduler.push_back(scheduleId); } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 7a0af0b06d7..bbe3b064c35 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1046,7 +1046,7 @@ const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { 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 + { 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 diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index 5dd332a0ae1..0aa46d0d10b 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -159,20 +159,20 @@ void CalendarMgr::RemoveEvent(uint64 eventId, uint64 remover) PreparedStatement* stmt; MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody()); - CalendarInviteStore::iterator itr = _invites[eventId].begin(); - while (itr != _invites[eventId].end()) + CalendarInviteStore& eventInvites = _invites[eventId]; + for (size_t i = 0; i < eventInvites.size(); ++i) { + CalendarInvite* invite = eventInvites[i]; stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CALENDAR_INVITE); - stmt->setUInt64(0, (*itr)->GetInviteId()); + stmt->setUInt64(0, invite->GetInviteId()); trans->Append(stmt); // guild events only? check invite status here? // When an event is deleted, all invited (accepted/declined? - verify) guildies are notified via in-game mail. (wowwiki) - if (remover && (*itr)->GetInviteeGUID() != remover) - mail.SendMailTo(trans, MailReceiver((*itr)->GetInviteeGUID()), calendarEvent, MAIL_CHECK_MASK_COPIED); + if (remover && invite->GetInviteeGUID() != remover) + mail.SendMailTo(trans, MailReceiver(invite->GetInviteeGUID()), calendarEvent, MAIL_CHECK_MASK_COPIED); - delete *itr; - _invites[eventId].erase(itr); + delete invite; } _invites.erase(eventId); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 43ac9d1c30a..507f8e066e3 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1134,6 +1134,9 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) if ((1<<firstEffIndex) & *itr) break; + if (firstEffIndex >= MAX_SPELL_EFFECTS) + return false; + // get shared data ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions; @@ -1153,9 +1156,18 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) { // add new list, create new shared mask sharedList = new ConditionList(); + bool assigned = false; for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) + { if ((1<<i) & commonMask) + { spellInfo->Effects[i].ImplicitTargetConditions = sharedList; + assigned = true; + } + } + + if (!assigned) + delete sharedList; } sharedList->push_back(cond); break; diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index eb7d93723f2..5ee2721e610 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -853,6 +853,18 @@ AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_ return NULL; } +char const* GetRaceName(uint8 race, uint8 /*locale*/) +{ + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race); + return raceEntry ? raceEntry->name : NULL; +} + +char const* GetClassName(uint8 class_, uint8 /*locale*/) +{ + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); + return classEntry ? classEntry->name : NULL; +} + uint32 GetAreaFlagByMapId(uint32 mapid) { AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid); @@ -1226,7 +1238,7 @@ LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty) if (!dungeon) continue; - if (dungeon->map == mapId && Difficulty(dungeon->difficulty) == difficulty) + if (dungeon->map == int32(mapId) && Difficulty(dungeon->difficulty) == difficulty) return dungeon; } diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index b49a1a96bd2..0a8ebad7bc8 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -37,6 +37,9 @@ AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id); AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id); uint32 GetAreaFlagByMapId(uint32 mapid); +char const* GetRaceName(uint8 race, uint8 locale); +char const* GetClassName(uint8 class_, uint8 locale); + WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid); uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index bbb27a8f354..b39942929ce 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2624,8 +2624,9 @@ void Player::Regenerate(Powers power) } break; case POWER_RUNES: - case POWER_HEALTH: break; + case POWER_HEALTH: + return; default: break; } @@ -4223,6 +4224,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) // learnSpell(prev_id, false); } // if ranked non-stackable spell: need activate lesser rank and update dendence state + /// No need to check for spellInfo != NULL here because if cur_active is true, then that means that the spell was already in m_spells, and only valid spells can be pushed there. else if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked()) { // need manually update dependence state (learn spell ignore like attempts) @@ -4746,12 +4748,6 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC charDelete_method = CHAR_DELETE_REMOVE; else if (CharacterNameData const* nameData = sWorld->GetCharacterNameData(guid)) // To avoid a query, we select loaded data. If it doesn't exist, return. { - if (!nameData) - { - TC_LOG_ERROR(LOG_FILTER_PLAYER, "Cannot find CharacterNameData entry for player %u from account %u. Could not delete character.", guid, accountId); - return; - } - // Define the required variables uint32 charDelete_minLvl = sWorld->getIntConfig(nameData->m_class != CLASS_DEATH_KNIGHT ? CONFIG_CHARDELETE_MIN_LEVEL : CONFIG_CHARDELETE_HEROIC_MIN_LEVEL); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e0f4a771396..a0aea414cef 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -6895,6 +6895,8 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 /*damage*/, Aura* triggeredByAura // Glyph of Divinity else if (dummySpell->Id == 54939) { + if (!procSpell) + return false; *handled = true; // Check if we are the target and prevent mana gain if (victim && triggeredByAura->GetCasterGUID() == victim->GetGUID()) @@ -7143,6 +7145,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg Aura* charge = GetAura(50241); if (charge && charge->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL)) RemoveAurasDueToSpell(50240); + break; } // Warrior - Vigilance, SPELLFAMILY_GENERIC if (auraSpellInfo->Id == 50720) @@ -9382,6 +9385,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas default: return false; } + break; case SPELL_DAMAGE_CLASS_MAGIC: { if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) @@ -9525,6 +9529,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas break; } } + /// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells case SPELL_DAMAGE_CLASS_RANGED: { if (victim) @@ -15893,7 +15898,7 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a } } - if (aurApp && aurApp->GetRemoveMode()) + if (!aurApp || aurApp->GetRemoveMode()) return; if (Player* player = ToPlayer()) diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 8e39b39be0c..214a47a6611 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -353,8 +353,9 @@ SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const } else { - if (seat-- == Seats.begin()) + if (seat == Seats.begin()) seat = Seats.end(); + --seat; } // Make sure we don't loop indefinetly @@ -417,7 +418,7 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ * @author Machiavelli * @date 17-2-2013 * - * @param [in,out] The prospective passenger. + * @param [in, out] The prospective passenger. * @param seatId Identifier for the seat. Value of -1 indicates the next available seat. * * @return true if it succeeds, false if it fails. @@ -492,7 +493,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) * @author Machiavelli * @date 17-2-2013 * - * @param [in,out] unit The passenger to remove. + * @param [in, out] unit The passenger to remove. */ void Vehicle::RemovePassenger(Unit* unit) @@ -615,7 +616,7 @@ void Vehicle::InitMovementInfoForBase() * @author Machiavelli * @date 17-2-2013 * - * @param [in,out] The passenger for which we check the seat info. + * @param [in, out] The passenger for which we check the seat info. * * @return null if passenger not found on vehicle, else the DBC record for the seat. */ @@ -637,7 +638,7 @@ VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit const* passenger) cons * @author Machiavelli * @date 17-2-2013 * - * @param [in,out] passenger Passenger to look up. + * @param [in, out] passenger Passenger to look up. * * @return The seat iterator for specified passenger if it's found on the vehicle. Otherwise Seats.end() (invalid iterator). */ diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index a150c7a016d..bfb0e005eda 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -396,24 +396,21 @@ bool Group::AddMember(Player* player) SubGroupCounterIncrease(subGroup); - if (player) + player->SetGroupInvite(NULL); + if (player->GetGroup()) { - player->SetGroupInvite(NULL); - if (player->GetGroup()) - { - if (isBGGroup() || isBFGroup()) // if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() - player->SetBattlegroundOrBattlefieldRaid(this, subGroup); - else //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() - player->SetOriginalGroup(this, subGroup); - } - else //if player is not in group, then call set group - player->SetGroup(this, subGroup); - - // if the same group invites the player back, cancel the homebind timer - InstanceGroupBind* bind = GetBoundInstance(player); - if (bind && bind->save->GetInstanceId() == player->GetInstanceId()) - player->m_InstanceValid = true; + if (isBGGroup() || isBFGroup()) // if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() + player->SetBattlegroundOrBattlefieldRaid(this, subGroup); + else //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() + player->SetOriginalGroup(this, subGroup); } + else //if player is not in group, then call set group + player->SetGroup(this, subGroup); + + // if the same group invites the player back, cancel the homebind timer + InstanceGroupBind* bind = GetBoundInstance(player); + if (bind && bind->save->GetInstanceId() == player->GetInstanceId()) + player->m_InstanceValid = true; if (!isRaidGroup()) // reset targetIcons for non-raid-groups { @@ -439,89 +436,86 @@ bool Group::AddMember(Player* player) SendUpdate(); sScriptMgr->OnGroupAddMember(this, player->GetGUID()); - if (player) + if (!IsLeader(player->GetGUID()) && !isBGGroup() && !isBFGroup()) { - if (!IsLeader(player->GetGUID()) && !isBGGroup() && !isBFGroup()) - { - // reset the new member's instances, unless he is currently in one of them - // including raid/heroic instances that they are not permanently bound to! - player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, false); - player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, true); + // reset the new member's instances, unless he is currently in one of them + // including raid/heroic instances that they are not permanently bound to! + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, false); + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN, true); - if (player->getLevel() >= LEVELREQUIREMENT_HEROIC) + if (player->getLevel() >= LEVELREQUIREMENT_HEROIC) + { + if (player->GetDungeonDifficulty() != GetDungeonDifficulty()) { - if (player->GetDungeonDifficulty() != GetDungeonDifficulty()) - { - player->SetDungeonDifficulty(GetDungeonDifficulty()); - player->SendDungeonDifficulty(true); - } - if (player->GetRaidDifficulty() != GetRaidDifficulty()) - { - player->SetRaidDifficulty(GetRaidDifficulty()); - player->SendRaidDifficulty(true); - } + player->SetDungeonDifficulty(GetDungeonDifficulty()); + player->SendDungeonDifficulty(true); + } + if (player->GetRaidDifficulty() != GetRaidDifficulty()) + { + player->SetRaidDifficulty(GetRaidDifficulty()); + player->SendRaidDifficulty(true); } } - player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); - UpdatePlayerOutOfRange(player); + } + player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); + UpdatePlayerOutOfRange(player); - // quest related GO state dependent from raid membership - if (isRaidGroup()) - player->UpdateForQuestWorldObjects(); + // quest related GO state dependent from raid membership + if (isRaidGroup()) + player->UpdateForQuestWorldObjects(); - { - // Broadcast new player group member fields to rest of the group - player->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); + { + // Broadcast new player group member fields to rest of the group + player->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); - UpdateData groupData(player->GetMapId()); - WorldPacket groupDataPacket; + UpdateData groupData(player->GetMapId()); + WorldPacket groupDataPacket; - // Broadcast group members' fields to player - for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) - { - if (itr->getSource() == player) - continue; + // Broadcast group members' fields to player + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + if (itr->getSource() == player) + continue; - if (Player* member = itr->getSource()) + if (Player* member = itr->getSource()) + { + if (player->HaveAtClient(member)) { - if (player->HaveAtClient(member)) // must be on the same map, or shit will break - { - member->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); - member->BuildValuesUpdateBlockForPlayer(&groupData, player); - member->RemoveFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); - } + member->SetFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); + member->BuildValuesUpdateBlockForPlayer(&groupData, player); + member->RemoveFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); + } - if (member->HaveAtClient(player)) + if (member->HaveAtClient(player)) + { + UpdateData newData(player->GetMapId()); + WorldPacket newDataPacket; + player->BuildValuesUpdateBlockForPlayer(&newData, member); + if (newData.HasData()) { - UpdateData newData(player->GetMapId()); - WorldPacket newDataPacket; - player->BuildValuesUpdateBlockForPlayer(&newData, member); - if (newData.HasData()) - { - newData.BuildPacket(&newDataPacket); - member->SendDirectMessage(&newDataPacket); - } + newData.BuildPacket(&newDataPacket); + member->SendDirectMessage(&newDataPacket); } } } + } - if (groupData.HasData()) - { - groupData.BuildPacket(&groupDataPacket); - player->SendDirectMessage(&groupDataPacket); - } - - player->RemoveFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); + if (groupData.HasData()) + { + groupData.BuildPacket(&groupDataPacket); + player->SendDirectMessage(&groupDataPacket); } - if (m_maxEnchantingLevel < player->GetSkillValue(SKILL_ENCHANTING)) - m_maxEnchantingLevel = player->GetSkillValue(SKILL_ENCHANTING); + player->RemoveFieldNotifyFlag(UF_FLAG_PARTY_MEMBER); } + if (m_maxEnchantingLevel < player->GetSkillValue(SKILL_ENCHANTING)) + m_maxEnchantingLevel = player->GetSkillValue(SKILL_ENCHANTING); + return true; } -bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /*= 0*/, const char* reason /*= NULL*/) +bool Group::RemoveMember(uint64 guid, const RemoveMethod& method /*= GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /*= 0*/, const char* reason /*= NULL*/) { BroadcastGroupUpdate(); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 10163294f1b..89a3da610a9 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -2989,7 +2989,7 @@ inline int32 Guild::_GetMemberRemainingSlots(Member const* member, uint8 tabId) uint8 rankId = member->GetRankId(); if (rankId == GR_GUILDMASTER) return GUILD_WITHDRAW_SLOT_UNLIMITED; - if ((_GetRankBankTabRights(rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != GR_RIGHT_EMPTY) + if ((_GetRankBankTabRights(rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != 0) { int32 remaining = _GetRankBankTabSlotsPerDay(rankId, tabId) - member->GetBankWithdrawValue(tabId); if (remaining > 0) @@ -3007,7 +3007,7 @@ inline int32 Guild::_GetMemberRemainingMoney(Member const* member) const if (rankId == GR_GUILDMASTER) return GUILD_WITHDRAW_MONEY_UNLIMITED; - if ((_GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != GR_RIGHT_EMPTY) + if ((_GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) { int32 remaining = _GetRankBankMoneyPerDay(rankId) - member->GetBankWithdrawValue(GUILD_BANK_MAX_TABS); if (remaining > 0) diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 906a5ff5b88..cc3b065dbe4 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -254,146 +254,143 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) } } - for (uint32 i = 0; i < itemsCount; ++i) + Item* item = items[0]; + + uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); + if (!_player->HasEnoughMoney((uint64)deposit)) { - Item* item = items[i]; + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); + return; + } - uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + AuctionEntry* AH = new AuctionEntry(); + + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + AH->auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD + else + AH->auctioneer = GUID_LOPART(auctioneer); - uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); - if (!_player->HasEnoughMoney((uint64)deposit)) + // Required stack size of auction matches to current item stack size, just move item to auctionhouse + if (itemsCount == 1 && item->GetCount() == count[0]) + { + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { - SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); - return; + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", + GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } - _player->ModifyMoney(-int32(deposit)); - - AuctionEntry* AH = new AuctionEntry; AH->Id = sObjectMgr->GenerateAuctionID(); - - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - AH->auctioneer = 23442; - else - AH->auctioneer = GUID_LOPART(auctioneer); - - // Required stack size of auction matches to current item stack size, just move item to auctionhouse - if (itemsCount == 1 && item->GetCount() == count[i]) + AH->itemGUIDLow = item->GetGUIDLow(); + AH->itemEntry = item->GetEntry(); + AH->itemCount = item->GetCount(); + AH->owner = _player->GetGUIDLow(); + AH->startbid = bid; + AH->bidder = 0; + AH->bid = 0; + AH->buyout = buyout; + AH->expire_time = time(NULL) + auctionTime; + AH->deposit = deposit; + AH->auctionHouseEntry = auctionHouseEntry; + + TC_LOG_INFO(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) " + "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", + _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), + AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); + sAuctionMgr->AddAItem(item); + auctionHouse->AddAuction(AH); + + _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + item->DeleteFromInventoryDB(trans); + item->SaveToDB(trans); + AH->SaveToDB(trans); + _player->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); + + SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + + GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); + } + else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size + { + Item* newItem = item->CloneItem(finalCount, _player); + if (!newItem) { - if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) - { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", - GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); - } - - AH->itemGUIDLow = item->GetGUIDLow(); - AH->itemEntry = item->GetEntry(); - AH->itemCount = item->GetCount(); - AH->owner = _player->GetGUIDLow(); - AH->startbid = bid; - AH->bidder = 0; - AH->bid = 0; - AH->buyout = buyout; - AH->expire_time = time(NULL) + auctionTime; - AH->deposit = deposit; - AH->auctionHouseEntry = auctionHouseEntry; - - TC_LOG_INFO(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) " - "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", - _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), - AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); - sAuctionMgr->AddAItem(item); - auctionHouse->AddAuction(AH); - - _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - item->DeleteFromInventoryDB(trans); - item->SaveToDB(trans); - AH->SaveToDB(trans); - _player->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); - - SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); - - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); + TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); + SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); + delete AH; return; } - else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size + + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { - Item* newItem = item->CloneItem(finalCount, _player); - if (!newItem) - { - TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); - SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); - return; - } + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", + GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); + } - if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) + AH->Id = sObjectMgr->GenerateAuctionID(); + AH->itemGUIDLow = newItem->GetGUIDLow(); + AH->itemEntry = newItem->GetEntry(); + AH->itemCount = newItem->GetCount(); + AH->owner = _player->GetGUIDLow(); + AH->startbid = bid; + AH->bidder = 0; + AH->bid = 0; + AH->buyout = buyout; + AH->expire_time = time(NULL) + auctionTime; + AH->deposit = deposit; + AH->auctionHouseEntry = auctionHouseEntry; + + TC_LOG_INFO(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to " + "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", + _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), + newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); + sAuctionMgr->AddAItem(newItem); + auctionHouse->AddAuction(AH); + + for (uint32 j = 0; j < itemsCount; ++j) + { + Item* item2 = items[j]; + + // Item stack count equals required count, ready to delete item - cloned item will be used for auction + if (item2->GetCount() == count[j]) { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", - GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); - } + _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); - AH->itemGUIDLow = newItem->GetGUIDLow(); - AH->itemEntry = newItem->GetEntry(); - AH->itemCount = newItem->GetCount(); - AH->owner = _player->GetGUIDLow(); - AH->startbid = bid; - AH->bidder = 0; - AH->bid = 0; - AH->buyout = buyout; - AH->expire_time = time(NULL) + auctionTime; - AH->deposit = deposit; - AH->auctionHouseEntry = auctionHouseEntry; - - TC_LOG_INFO(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to " - "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", - _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), - newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); - sAuctionMgr->AddAItem(newItem); - auctionHouse->AddAuction(AH); - - for (uint32 j = 0; j < itemsCount; ++j) + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + item2->DeleteFromInventoryDB(trans); + item2->DeleteFromDB(trans); + CharacterDatabase.CommitTransaction(trans); + } + else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { - Item* item2 = items[j]; - - // Item stack count equals required count, ready to delete item - cloned item will be used for auction - if (item2->GetCount() == count[j]) - { - _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - item2->DeleteFromInventoryDB(trans); - item2->DeleteFromDB(trans); - CharacterDatabase.CommitTransaction(trans); - } - else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction - { - item2->SetCount(item2->GetCount() - count[j]); - item2->SetState(ITEM_CHANGED, _player); - _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); - item2->SendUpdateToPlayer(_player); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - item2->SaveToDB(trans); - CharacterDatabase.CommitTransaction(trans); - } + item2->SetCount(item2->GetCount() - count[j]); + item2->SetState(ITEM_CHANGED, _player); + _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); + item2->SendUpdateToPlayer(_player); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + item2->SaveToDB(trans); + CharacterDatabase.CommitTransaction(trans); } + } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - newItem->SaveToDB(trans); - AH->SaveToDB(trans); - _player->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + newItem->SaveToDB(trans); + AH->SaveToDB(trans); + _player->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); - SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); + SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); - GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); - return; - } + GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } + + _player->ModifyMoney(-int32(deposit)); } // this function is called when client bids or buys out auction diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 5832cf6e095..3c28a32af93 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -450,8 +450,8 @@ void WorldSession::HandleCalendarEventInvite(WorldPacket& recvData) } // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(inviteId, 0, inviteeGuid, playerGuid, 946684800, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); - sCalendarMgr->SendCalendarEventInvite(*invite); + CalendarInvite invite(inviteId, 0, inviteeGuid, playerGuid, 946684800, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); + sCalendarMgr->SendCalendarEventInvite(invite); } } diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 3d62fbcc740..9ec018aaf78 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -346,7 +346,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to // We also do that if a player is under the required level for whispers. - if (receiver->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) || + if (receiver->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) || (HasPermission(RBAC_PERM_CAN_FILTER_WHISPERS) && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID()))) sender->AddWhisperWhiteList(receiver->GetGUID()); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 0905e33097f..2a21eedf354 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1001,7 +1001,7 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recvData) TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "RAD: type %u", type); - if (type > NUM_ACCOUNT_DATA_TYPES) + if (type >= NUM_ACCOUNT_DATA_TYPES) return; AccountData* adata = GetAccountData(AccountDataType(type)); diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index d39099485a5..57d41be9e23 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -83,6 +83,7 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData) { TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "CMSG_GMTICKET_CREATE possibly corrupt. Uncompression failed."); recvData.rfinish(); + delete ticket; return; } diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 6d5170e0f49..7da7cd975ee 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -158,6 +158,12 @@ uint32 LootStore::LoadLootTable() continue; // error already printed to log/console. } + if (group >= 1 << 7) // it stored in 7 bit field + { + TC_LOG_ERROR(LOG_FILTER_SQL, "Table '%s' entry %d item %d: group (%u) must be less %u - skipped", GetName(), entry, item, group, 1 << 7); + return false; + } + LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); if (!storeitem->IsValid(*this, entry)) // Validity checks @@ -293,12 +299,6 @@ bool LootStoreItem::Roll(bool rate) const // Checks correctness of values bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const { - if (group >= 1 << 7) // it stored in 7 bit field - { - TC_LOG_ERROR(LOG_FILTER_SQL, "Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7); - return false; - } - if (mincountOrRef == 0) { TC_LOG_ERROR(LOG_FILTER_SQL, "Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index c9bf5df4cf8..45ce43bc3fc 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -672,6 +672,8 @@ void Map::ProcessRelocationNotifies(const uint32 diff) void Map::RemovePlayerFromMap(Player* player, bool remove) { + sScriptMgr->OnPlayerLeaveMap(this, player); + player->RemoveFromWorld(); SendRemoveTransports(player); @@ -682,11 +684,7 @@ void Map::RemovePlayerFromMap(Player* player, bool remove) ASSERT(remove); //maybe deleted in logoutplayer when player is not in a map if (remove) - { DeleteFromWorld(player); - - sScriptMgr->OnPlayerLeaveMap(this, player); - } } template<class T> diff --git a/src/server/game/Maps/PhaseMgr.h b/src/server/game/Maps/PhaseMgr.h index ec41146ded7..21f67038c3f 100644 --- a/src/server/game/Maps/PhaseMgr.h +++ b/src/server/game/Maps/PhaseMgr.h @@ -113,8 +113,9 @@ private: struct PhaseUpdateData { - void AddConditionType(ConditionTypes conditionType) { _conditionTypeFlags |= (1 << conditionType); } - void AddQuestUpdate(uint32 questId); + PhaseUpdateData(): _conditionTypeFlags(0), _questId(0) { } + void AddConditionType(ConditionTypes const conditionType) { _conditionTypeFlags |= (1 << conditionType); } + void AddQuestUpdate(uint32 const questId); bool IsConditionRelated(Condition const* condition) const; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 62a0841405c..c26bbc1dfc9 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -209,15 +209,17 @@ enum TrinityStrings LANG_YOU_CHANGE_RUNIC_POWER = 173, LANG_YOURS_RUNIC_POWER_CHANGED = 174, LANG_LIQUID_STATUS = 175, + LANG_INVALID_GAMEOBJECT_TYPE = 176, + LANG_GAMEOBJECT_DAMAGED = 177, - LANG_PHASING_REPORT_STATUS = 176, - LANG_PHASING_NO_DEFINITIONS = 177, // Phasing LANG_PHASING_SUCCESS = 178, LANG_PHASING_FAILED = 179, LANG_PHASING_LAST_PHASE = 180, LANG_PHASING_LIST = 181, LANG_PHASING_PHASEMASK = 182, - // Room for more level 1 183-199 not used + LANG_PHASING_REPORT_STATUS = 183, + LANG_PHASING_NO_DEFINITIONS = 184, // Phasing + // Room for more level 1 185-199 not used // level 2 chat LANG_NO_SELECTION = 200, diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index abb4ac9964b..8086e60c912 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -27,7 +27,7 @@ #include "Player.h" template<class T, typename D> -void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool updateDestination) +void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T* owner, bool updateDestination) { if (!i_target.isValid() || !i_target->IsInWorld()) return; @@ -117,7 +117,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool upd } template<class T, typename D> -bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff) +bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; @@ -185,7 +185,7 @@ template<class T> void ChaseMovementGenerator<T>::_reachTarget(T* owner) { if (owner->IsWithinMeleeRange(this->i_target.getTarget())) - owner->Attack(this->i_target.getTarget(),true); + owner->Attack(this->i_target.getTarget(), true); } template<> @@ -303,14 +303,14 @@ void FollowMovementGenerator<Creature>::MovementInform(Creature* unit) } //-----------------------------------------------// -template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool); -template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool); -template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); -template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); -template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32); -template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32); -template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); -template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); +template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool); +template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool); +template void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); +template void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); +template bool TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32); +template bool TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32); +template bool TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); +template bool TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); template void ChaseMovementGenerator<Player>::_reachTarget(Player*); template void ChaseMovementGenerator<Creature>::_reachTarget(Creature*); diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 80e8f1e1f44..3fd7e7ee393 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -701,7 +701,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo // Find movement delta. float delta[VERTEX_SIZE]; dtVsub(delta, steerPos, iterPos); - float len = dtSqrt(dtVdot(delta,delta)); + float len = dtSqrt(dtVdot(delta, delta)); // If the steer target is end of path or off-mesh link, do not move past the location. if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE) len = 1.0f; diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h index 39f05184cf6..9814d1c65e1 100644 --- a/src/server/game/Movement/Waypoints/Path.h +++ b/src/server/game/Movement/Waypoints/Path.h @@ -40,13 +40,13 @@ class Path void erase(uint32 idx) { i_nodes.erase(i_nodes.begin()+idx); } void crop(unsigned int start, unsigned int end) { - while(start && !i_nodes.empty()) + while (start && !i_nodes.empty()) { i_nodes.pop_front(); --start; } - while(end && !i_nodes.empty()) + while (end && !i_nodes.empty()) { i_nodes.pop_back(); --end; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index fbfd467e7eb..ec1b7ac609e 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -446,6 +446,7 @@ void AddSC_ulduar_teleporter(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); +void AddSC_boss_yogg_saron(); void AddSC_boss_algalon_the_observer(); void AddSC_instance_ulduar(); void AddSC_boss_keleseth(); //Utgarde Keep @@ -1188,6 +1189,7 @@ void AddNorthrendScripts() AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); + AddSC_boss_yogg_saron(); AddSC_boss_algalon_the_observer(); AddSC_instance_ulduar(); AddSC_boss_keleseth(); //Utgarde Keep diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 92e72627668..cdfb706d173 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -683,7 +683,7 @@ void AuraEffect::CalculateSpellMod() m_spellmod->op = SpellModOp(GetMiscValue()); ASSERT(m_spellmod->op < MAX_SPELLMOD); - m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types + m_spellmod->type = SpellModType(uint32(GetAuraType())); // SpellModType value == spell aura types m_spellmod->spellId = GetId(); m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; m_spellmod->charges = GetBase()->GetCharges(); @@ -1788,17 +1788,17 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo int32 basePoints = std::min<int32>(oldPower, FurorChance); target->SetPower(POWER_ENERGY, 0); target->CastCustomSpell(target, 17099, &basePoints, NULL, NULL, true, NULL, this); + break; } - break; case FORM_BEAR: - if (irand(0, 99) < FurorChance) + if (urand(0, 99) < FurorChance) target->CastSpell(target, 17057, true); default: { int32 newEnergy = std::min(target->GetPower(POWER_ENERGY), FurorChance); target->SetPower(POWER_ENERGY, newEnergy); + break; } - break; } break; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c4a6b6e6d1c..4cbb9a28603 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2613,7 +2613,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { // for delayed spells ignore negative spells (after duel end) for friendly targets /// @todo this cause soul transfer bugged - if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive()) + // 63881 - Malady of the Mind jump spell (Yogg-Saron) + if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive() && m_spellInfo->Id != 63881) return SPELL_MISS_EVADE; // assisting case, healing and resurrection @@ -3344,7 +3345,7 @@ void Spell::handle_immediate() if (m_spellInfo->IsChanneled()) { int32 duration = m_spellInfo->GetDuration(); - if (duration) + if (duration > 0) { // First mod_duration then haste - see Missile Barrage // Apply duration mod diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index e74fac2ed7c..ca176e0e202 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5417,7 +5417,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l+1) && player->GetCurrentRune(l+1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB))) { // Should always update the rune with the lowest cd - if (player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1)) + if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1)) l++; player->SetRuneCooldown(l, 0); --count; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index aa6dac2d79a..88cda9d5db9 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2690,7 +2690,7 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const continue; // if non-positive trigger cast targeted to positive target this main cast is non-positive // this will place this spell auras as debuffs - if (!_IsPositiveTarget(spellTriggeredProto->Effects[i].TargetA.GetTarget(), spellTriggeredProto->Effects[i].TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(i, true)) + if (_IsPositiveTarget(spellTriggeredProto->Effects[i].TargetA.GetTarget(), spellTriggeredProto->Effects[i].TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(i, true)) return false; } } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8c497ce6fdb..a2a4a85808a 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -84,6 +84,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, // ToC Icehowl Arctic Breath else if (spellproto->SpellVisual[0] == 14153) return DIMINISHING_NONE; + // Black Plague + else if (spellproto->Id == 64155) + return DIMINISHING_NONE; break; } // Event spells @@ -3374,6 +3377,14 @@ void SpellMgr::LoadSpellInfoCorrections() // that will be clear if we get more spells with problem like this spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; break; + case 61791: // Ride Vehicle (Yogg-Saron) + // TODO: remove this when basepoints of all Ride Vehicle auras are calculated correctly + spellInfo->Effects[EFFECT_0].BasePoints = 1; + break; + case 64468: // Empowering Shadows (Yogg-Saron) + case 64486: // Empowering Shadows (Yogg-Saron) + spellInfo->MaxAffectedTargets = 3; // same for both modes? + break; case 62301: // Cosmic Smash (Algalon the Observer) spellInfo->MaxAffectedTargets = 1; break; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 66dc5225a35..b61c5ac5de3 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2203,7 +2203,7 @@ namespace Trinity { WorldPacket* data = new WorldPacket(); - uint32 lineLength = (line ? strlen(line) : 0) + 1; + uint32 lineLength = strlen(line) + 1; data->Initialize(SMSG_MESSAGECHAT, 100); // guess size *data << uint8(CHAT_MSG_SYSTEM); diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 9aa68e0892c..c347648abab 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -482,7 +482,7 @@ public: char* arg3 = strtok(NULL, " "); bool isAccountNameGiven = true; - if (arg1 && !arg3) + if (!arg3) { if (!handler->getSelectedPlayer()) return false; diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 727aa55597f..2b316803029 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -320,7 +320,7 @@ public: // check online security if (handler->HasLowerSecurity(target, 0)) return false; - + playerOldName = target->GetName(); } else @@ -345,7 +345,7 @@ public: handler->SetSentErrorMessage(true); return false; } - + if (WorldSession* session = handler->GetSession()) { if (!session->HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(newName)) diff --git a/src/server/scripts/Commands/cs_deserter.cpp b/src/server/scripts/Commands/cs_deserter.cpp index 3850456fcb3..ef2cd7b45b9 100644 --- a/src/server/scripts/Commands/cs_deserter.cpp +++ b/src/server/scripts/Commands/cs_deserter.cpp @@ -45,20 +45,20 @@ public: ChatCommand* GetCommands() const { - static ChatCommand deserterInstanceCommandTable[] = + static ChatCommand deserterInstanceCommandTable[] = { { "add", SEC_ADMINISTRATOR, false, &HandleDeserterInstanceAdd, "", NULL }, { "remove", SEC_ADMINISTRATOR, false, &HandleDeserterInstanceRemove, "", NULL }, { NULL, SEC_PLAYER, false, NULL, "", NULL } }; - static ChatCommand deserterBGCommandTable[] = + static ChatCommand deserterBGCommandTable[] = { { "add", SEC_ADMINISTRATOR, false, &HandleDeserterBGAdd, "", NULL }, { "remove", SEC_ADMINISTRATOR, false, &HandleDeserterBGRemove, "", NULL }, { NULL, SEC_PLAYER, false, NULL, "", NULL } }; - static ChatCommand deserterCommandTable[] = + static ChatCommand deserterCommandTable[] = { { "instance", SEC_ADMINISTRATOR, false, NULL, "", deserterInstanceCommandTable }, { "bg", SEC_ADMINISTRATOR, false, NULL, "", deserterBGCommandTable }, diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp index bbff716253e..364746adae9 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -518,7 +518,7 @@ public: uint32 copp = (money % GOLD) % SILVER; std::string receiverStr = handler->playerLink(receiver); std::string senderStr = handler->playerLink(sender); - handler->PSendSysMessage(LANG_LIST_MAIL_INFO_1 , messageId, subject.c_str(),gold, silv, copp); + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_1, messageId, subject.c_str(), gold, silv, copp); handler->PSendSysMessage(LANG_LIST_MAIL_INFO_2, senderStr.c_str(), senderId, receiverStr.c_str(), receiverId); handler->PSendSysMessage(LANG_LIST_MAIL_INFO_3, TimeToTimestampStr(deliverTime).c_str(), TimeToTimestampStr(expireTime).c_str()); if (hasItem == 1) @@ -541,7 +541,7 @@ public: uint32 item_entry = fields[0].GetUInt32(); uint32 item_count = fields[1].GetUInt32(); QueryResult result4; - result4 = WorldDatabase.PQuery("SELECT name,quality FROM item_template WHERE entry = '%u'", item_entry); + result4 = WorldDatabase.PQuery("SELECT name, quality FROM item_template WHERE entry = '%u'", item_entry); Field* fields1 = result4->Fetch(); std::string item_name = fields1[0].GetString(); int item_quality = fields1[1].GetUInt8(); diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index e28251bebb4..ff5ece84272 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -869,12 +869,7 @@ public: uint32 id = atoi((char*)args); - bool found = false; - uint32 count = 0; - uint32 maxResults = 1; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(id); - if (spellInfo) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(id)) { int locale = handler->GetSessionDbcLocale(); std::string name = spellInfo->SpellName; @@ -884,14 +879,6 @@ public: return true; } - if (locale < TOTAL_LOCALES) - { - if (maxResults && count++ == maxResults) - { - handler->PSendSysMessage(LANG_COMMAND_LOOKUP_MAX_RESULTS, maxResults); - return true; - } - bool known = target && target->HasSpell(id); bool learn = (spellInfo->Effects[0].Effect == SPELL_EFFECT_LEARN_SPELL); @@ -935,13 +922,8 @@ public: ss << handler->GetTrinityString(LANG_ACTIVE); handler->SendSysMessage(ss.str().c_str()); - - if (!found) - found = true; - } } - - if (!found) + else handler->SendSysMessage(LANG_COMMAND_NOSPELLFOUND); return true; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index c5182f7cf4c..489c11e0f94 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1070,9 +1070,7 @@ public: Player* player = handler->GetSession()->GetPlayer(); uint32 zone_id = player->GetZoneId(); - WorldSafeLocsEntry const* graveyard = sObjectMgr->GetClosestGraveYard( - player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), team); - + WorldSafeLocsEntry const* graveyard = sObjectMgr->GetClosestGraveYard(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), team); if (graveyard) { uint32 graveyardId = graveyard->ID; @@ -1102,14 +1100,12 @@ public: { std::string team_name; - if (team == 0) - team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY); - else if (team == HORDE) + if (team == HORDE) team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE); else if (team == ALLIANCE) team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - if (team == ~uint32(0)) + if (!team) handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id); else handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id, team_name.c_str()); @@ -2046,6 +2042,70 @@ public: if (!*args) return false; + char* str = strtok((char*)args, " "); + + if (strcmp(str, "go") == 0) + { + char* guidStr = strtok(NULL, " "); + if (!guidStr) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + int32 guid = atoi(guidStr); + if (!guid) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + char* damageStr = strtok(NULL, " "); + if (!damageStr) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + int32 damage = atoi(damageStr); + if (!damage) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + if (Player* player = handler->GetSession()->GetPlayer()) + { + GameObject* go = NULL; + + if (GameObjectData const* goData = sObjectMgr->GetGOData(guid)) + go = handler->GetObjectGlobalyWithGuidOrNearWithDbGuid(guid, goData->id); + + if (!go) + { + handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, guid); + handler->SetSentErrorMessage(true); + return false; + } + + if (!go->IsDestructibleBuilding()) + { + handler->SendSysMessage(LANG_INVALID_GAMEOBJECT_TYPE); + handler->SetSentErrorMessage(true); + return false; + } + + go->ModifyHealth(-damage, player); + handler->PSendSysMessage(LANG_GAMEOBJECT_DAMAGED, go->GetName().c_str(), guid, -damage, go->GetGOValue()->Building.Health); + } + + return true; + } + Unit* target = handler->getSelectedUnit(); if (!target || !handler->GetSession()->GetPlayer()->GetSelection()) { @@ -2084,7 +2144,7 @@ public: return true; } - uint32 school = schoolStr ? atoi((char*)schoolStr) : SPELL_SCHOOL_NORMAL; + uint32 school = atoi((char*)schoolStr); if (school >= MAX_SPELL_SCHOOL) return false; diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index 55b6edbadbe..300b39fc389 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -128,7 +128,7 @@ public: int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS; handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gy, gx); - handler->PSendSysMessage("gridloc [%i,%i]", gx, gy); + handler->PSendSysMessage("gridloc [%i, %i]", gx, gy); // calculate navmesh tile location dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); @@ -148,7 +148,7 @@ public: int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS); int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS); - handler->PSendSysMessage("Calc [%02i,%02i]", tilex, tiley); + handler->PSendSysMessage("Calc [%02i, %02i]", tilex, tiley); // navmesh poly -> navmesh tile location dtQueryFilter filter = dtQueryFilter(); @@ -156,16 +156,16 @@ public: navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL); if (polyRef == INVALID_POLYREF) - handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); + handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)"); else { dtMeshTile const* tile; dtPoly const* poly; navmesh->getTileAndPolyByRef(polyRef, &tile, &poly); if (tile) - handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); + handler->PSendSysMessage("Dt [%02i, %02i]", tile->header->x, tile->header->y); else - handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); + handler->PSendSysMessage("Dt [??, ??] (no tile loaded)"); } return true; @@ -190,7 +190,7 @@ public: if (!tile || !tile->header) continue; - handler->PSendSysMessage("[%02i,%02i]", tile->header->x, tile->header->y); + handler->PSendSysMessage("[%02i, %02i]", tile->header->x, tile->header->y); } return true; diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index be111c9356b..ed933ffd5bc 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -310,24 +310,14 @@ public: if (!pfactionid) { - if (target) - { - uint32 factionid = target->getFaction(); - uint32 flag = target->GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); - uint32 dyflag = target->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - handler->PSendSysMessage(LANG_CURRENT_FACTION, target->GetGUIDLow(), factionid, flag, npcflag, dyflag); - } + uint32 factionid = target->getFaction(); + uint32 flag = target->GetUInt32Value(UNIT_FIELD_FLAGS); + uint32 npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 dyflag = target->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + handler->PSendSysMessage(LANG_CURRENT_FACTION, target->GetGUIDLow(), factionid, flag, npcflag, dyflag); return true; } - if (!target) - { - handler->SendSysMessage(LANG_NO_CHAR_SELECTED); - handler->SetSentErrorMessage(true); - return false; - } - uint32 factionid = atoi(pfactionid); uint32 flag; @@ -341,7 +331,7 @@ public: uint32 npcflag; if (!pnpcflag) - npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); + npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); else npcflag = atoi(pnpcflag); @@ -349,7 +339,7 @@ public: uint32 dyflag; if (!pdyflag) - dyflag = target->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + dyflag = target->GetUInt32Value(UNIT_DYNAMIC_FLAGS); else dyflag = atoi(pdyflag); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index a398ac9004b..eadfd3b8da0 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -254,7 +254,7 @@ public: return false; } - uint32 vendor_entry = vendor ? vendor->GetEntry() : 0; + uint32 vendor_entry = vendor->GetEntry(); if (!sObjectMgr->IsVendorItemValid(vendor_entry, itemId, maxcount, incrtime, extendedcost, type, handler->GetSession()->GetPlayer())) { diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp index 604218c2e68..667815ce16c 100644 --- a/src/server/scripts/Commands/cs_rbac.cpp +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -32,6 +32,12 @@ EndScriptData */ struct RBACCommandData
{
RBACCommandData(): id(0), realmId(0), rbac(NULL), needDelete(false) { }
+ ~RBACCommandData()
+ {
+ if (needDelete)
+ delete rbac;
+ }
+
uint32 id;
int32 realmId;
RBACData* rbac;
@@ -230,8 +236,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -266,8 +271,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -295,8 +299,7 @@ public: }
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -335,8 +338,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -375,8 +377,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -411,8 +412,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -453,8 +453,7 @@ public: }
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -493,8 +492,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -533,8 +531,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -569,8 +566,7 @@ public: break;
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -613,8 +609,7 @@ public: }
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
@@ -643,8 +638,7 @@ public: }
}
- if (command->needDelete)
- delete command;
+ delete command;
return true;
}
diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index b162e0c51a4..745cc80ab41 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -800,7 +800,7 @@ public: if (show == "info") { // Check if the user did specify a visual waypoint - if (target->GetEntry() != VISUAL_WAYPOINT) + if (target && target->GetEntry() != VISUAL_WAYPOINT) { handler->PSendSysMessage(LANG_WAYPOINT_VP_SELECT); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp index 97b8e0334ee..3585debb1c2 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp @@ -146,49 +146,51 @@ class boss_kirtonos_the_herald : public CreatureScript { events.Update(diff); - while (uint32 eventId = events.ExecuteEvent() && !UpdateVictim()) + if (!UpdateVictim()) { - switch (eventId) + while (uint32 eventId = events.ExecuteEvent()) { - case INTRO_1: - me->GetMotionMaster()->MovePath(KIRTONOS_PATH, false); - break; - case INTRO_2: - me->GetMotionMaster()->MovePoint(0, PosMove[0]); - events.ScheduleEvent(INTRO_3, 1000); - break; - case INTRO_3: - if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_KIRTONOS))) - gate->SetGoState(GO_STATE_READY); - me->SetFacingTo(0.01745329f); - events.ScheduleEvent(INTRO_4, 3000); - break; - case INTRO_4: - if (GameObject* brazier = me->GetMap()->GetGameObject(instance->GetData64(GO_BRAZIER_OF_THE_HERALD))) - brazier->SetGoState(GO_STATE_READY); - me->SetWalk(true); - me->SetDisableGravity(false); - DoCast(me, SPELL_KIRTONOS_TRANSFORM); - me->SetCanFly(false); - events.ScheduleEvent(INTRO_5, 1000); - break; - case INTRO_5: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_KIRTONOS_STAFF)); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - events.ScheduleEvent(INTRO_6, 5000); - break; - case INTRO_6: - me->GetMotionMaster()->MovePoint(0, PosMove[1]); - break; - default: - break; + switch (eventId) + { + case INTRO_1: + me->GetMotionMaster()->MovePath(KIRTONOS_PATH, false); + break; + case INTRO_2: + me->GetMotionMaster()->MovePoint(0, PosMove[0]); + events.ScheduleEvent(INTRO_3, 1000); + break; + case INTRO_3: + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_KIRTONOS))) + gate->SetGoState(GO_STATE_READY); + me->SetFacingTo(0.01745329f); + events.ScheduleEvent(INTRO_4, 3000); + break; + case INTRO_4: + if (GameObject* brazier = me->GetMap()->GetGameObject(instance->GetData64(GO_BRAZIER_OF_THE_HERALD))) + brazier->SetGoState(GO_STATE_READY); + me->SetWalk(true); + me->SetDisableGravity(false); + DoCast(me, SPELL_KIRTONOS_TRANSFORM); + me->SetCanFly(false); + events.ScheduleEvent(INTRO_5, 1000); + break; + case INTRO_5: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_KIRTONOS_STAFF)); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(INTRO_6, 5000); + break; + case INTRO_6: + me->GetMotionMaster()->MovePoint(0, PosMove[1]); + break; + default: + break; + } } - } - if (!UpdateVictim()) return; + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 630c379e71e..87a09749724 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -773,7 +773,7 @@ public: void JustSummoned(Creature* summon) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30, true); - if (target && summon) + if (target) summon->Attack(target, false); summons.Summon(summon); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp index aec78581514..397d20e92f9 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp @@ -34,13 +34,13 @@ enum Spells enum Events { - EVENT_STINGER_SPRAY = 0, - EVENT_POISON_STINGER = 1, - EVENT_SUMMON_SWARMER = 2, - EVENT_SWARMER_ATTACK = 3, - EVENT_PARALYZE = 4, - EVENT_LASH = 5, - EVENT_TRASH = 6 + EVENT_STINGER_SPRAY = 1, + EVENT_POISON_STINGER = 2, + EVENT_SUMMON_SWARMER = 3, + EVENT_SWARMER_ATTACK = 4, + EVENT_PARALYZE = 5, + EVENT_LASH = 6, + EVENT_TRASH = 7 }; enum Emotes diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index 0ad077aaa4e..5da6606f05f 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -42,11 +42,11 @@ enum Spells enum Events { - EVENT_DISMEMBER = 0, - EVENT_GATHERING_SPEED = 1, - EVENT_FULL_SPEED = 2, - EVENT_CREEPING_PLAGUE = 3, - EVENT_RESPAWN_EGG = 4 + EVENT_DISMEMBER = 1, + EVENT_GATHERING_SPEED = 2, + EVENT_FULL_SPEED = 3, + EVENT_CREEPING_PLAGUE = 4, + EVENT_RESPAWN_EGG = 5 }; enum Phases diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp index 79bc0c5accf..901438409a4 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp @@ -40,10 +40,10 @@ enum Spells enum Events { - EVENT_ARCANE_EXPLOSION = 0, - EVENT_FULLFILMENT = 1, - EVENT_BLINK = 2, - EVENT_EARTH_SHOCK = 3 + EVENT_ARCANE_EXPLOSION = 1, + EVENT_FULLFILMENT = 2, + EVENT_BLINK = 3, + EVENT_EARTH_SHOCK = 4 }; uint32 const BlinkSpells[3] = { 4801, 8195, 20449 }; diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp index 318fccfb5b6..ed50f1a79f1 100644 --- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp @@ -58,8 +58,8 @@ enum HauntingWitchHill NPC_RISEN_SPIRIT = 23554, // Events - EVENT_CONSUME_FLESH = 0, - EVENT_INTANGIBLE_PRESENCE = 1, + EVENT_CONSUME_FLESH = 1, + EVENT_INTANGIBLE_PRESENCE = 2, }; class mobs_risen_husk_spirit : public CreatureScript diff --git a/src/server/scripts/Kalimdor/zone_winterspring.cpp b/src/server/scripts/Kalimdor/zone_winterspring.cpp index 2b68c0a2cb6..6458047bb60 100644 --- a/src/server/scripts/Kalimdor/zone_winterspring.cpp +++ b/src/server/scripts/Kalimdor/zone_winterspring.cpp @@ -154,14 +154,14 @@ struct DialogueEntry class DialogueHelper { public: - // The array MUST be terminated by {0,0,0} + // The array MUST be terminated by {0, 0, 0} DialogueHelper(DialogueEntry const* dialogueArray) : _dialogueArray(dialogueArray), _currentEntry(NULL), _actionTimer(0), _isFirstSide(true) {} - // The array MUST be terminated by {0,0,0,0,0} + // The array MUST be terminated by {0, 0, 0, 0, 0} /// Function to initialize the dialogue helper for instances. If not used with instances, GetSpeakerByEntry MUST be overwritten to obtain the speakers /// Set if take first entries or second entries @@ -182,9 +182,7 @@ public: } if (!found) - { return; - } DoNextDialogueStep(); } @@ -210,7 +208,7 @@ private: void DoNextDialogueStep() { // Last Dialogue Entry done? - if (_currentEntry && !_currentEntry->TextEntry) + if (!_currentEntry || !_currentEntry->TextEntry) { _actionTimer = 0; return; @@ -400,7 +398,7 @@ public: void WaypointReached(uint32 pointId) { - switch(pointId) + switch (pointId) { case 3: Talk(SAY_ENTER_OWL_THICKET); @@ -439,7 +437,7 @@ public: SetEscortPaused(true); DoSummonPriestess(); Talk(SAY_RANSHALLA_ALTAR_2); - events.ScheduleEvent(EVENT_RESUME,2000); + events.ScheduleEvent(EVENT_RESUME, 2000); break; case 44: // Stop the escort and turn towards the altar diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 1da1e4ab178..674c35836a2 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -26,7 +26,7 @@ set(scripts_STAT_SRCS Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp Northrend/Ulduar/Ulduar/instance_ulduar.cpp Northrend/Ulduar/Ulduar/boss_auriaya.cpp - Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp + Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp Northrend/Ulduar/Ulduar/boss_hodir.cpp Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp index a68ea1025d5..090ebbca69d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -149,6 +149,9 @@ class npc_announcer_toc10 : public CreatureScript } } + if (i >= NUM_MESSAGES) + return false; + player->SEND_GOSSIP_MENU(_GossipMessage[i].msgnum, creature->GetGUID()); return true; } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index 3e44fe9eba4..9e369fa83bb 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -33,10 +33,10 @@ enum Spells enum Events { - EVENT_BERSERK = 0, - EVENT_CLOUD = 1, - EVENT_INJECT = 2, - EVENT_SPRAY = 3 + EVENT_BERSERK = 1, + EVENT_CLOUD = 2, + EVENT_INJECT = 3, + EVENT_SPRAY = 4 }; enum CreatureId @@ -46,7 +46,8 @@ enum CreatureId class boss_grobbulus : public CreatureScript { -public: boss_grobbulus() : CreatureScript("boss_grobbulus") { } +public: + boss_grobbulus() : CreatureScript("boss_grobbulus") { } CreatureAI* GetAI(Creature* creature) const { diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index d861343116f..b85c24a22eb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -754,7 +754,7 @@ public: void UpdateAI(uint32 diff) { - if (!UpdateVictim() && _phase != PHASE_NOT_STARTED && _phase != PHASE_TWO) + if (!instance || (!UpdateVictim() && _phase != PHASE_NOT_STARTED && _phase != PHASE_TWO)) return; events.Update(diff); @@ -854,7 +854,7 @@ public: } } - if (_arcaneReinforcements && instance) + if (_arcaneReinforcements) { for (uint8 rangeDisks = 0; rangeDisks < (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 5); rangeDisks++) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp index 1f8ba3edade..71ef0cbe3ce 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp @@ -110,103 +110,107 @@ class npc_verdisa_beglaristrasz_eternos : public CreatureScript public: npc_verdisa_beglaristrasz_eternos() : CreatureScript("npc_verdisa_beglaristrasz_eternos") { } - InstanceScript* instance; - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) { player->PlayerTalkClass->ClearMenus(); switch (creature->GetEntry()) { - case NPC_VERDISA: //Verdisa - switch (action) + case NPC_VERDISA: //Verdisa { - case GOSSIP_ACTION_INFO_DEF + 1: - if (!HAS_ESSENCE(player)) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA1, creature->GetGUID()); - } - else + switch (action) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA2, creature->GetGUID()); + case GOSSIP_ACTION_INFO_DEF + 1: + if (!HAS_ESSENCE(player)) + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA1, creature->GetGUID()); + } + else + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_VERDISA2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA2, creature->GetGUID()); + } + break; + case GOSSIP_ACTION_INFO_DEF + 2: + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_EMERALD_ESSENCE, 1); + if (msg == EQUIP_ERR_OK) + player->StoreNewItem(dest, ITEM_EMERALD_ESSENCE, true); + player->CLOSE_GOSSIP_MENU(); + break; + } + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA3, creature->GetGUID()); + break; } break; - case GOSSIP_ACTION_INFO_DEF + 2: - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_EMERALD_ESSENCE, 1); - if (msg == EQUIP_ERR_OK) - player->StoreNewItem(dest, ITEM_EMERALD_ESSENCE, true); - player->CLOSE_GOSSIP_MENU(); - break; } - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_VERDISA3, creature->GetGUID()); - break; - } - break; - case NPC_BELGARISTRASZ: //Belgaristrasz - switch (action) + case NPC_BELGARISTRASZ: //Belgaristrasz { - case GOSSIP_ACTION_INFO_DEF + 1: - if (!HAS_ESSENCE(player)) + switch (action) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ1, creature->GetGUID()); - } - else - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ2, creature->GetGUID()); + case GOSSIP_ACTION_INFO_DEF + 1: + if (!HAS_ESSENCE(player)) + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ1, creature->GetGUID()); + } + else + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BELGARISTRASZ2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ2, creature->GetGUID()); + } + break; + case GOSSIP_ACTION_INFO_DEF + 2: + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_RUBY_ESSENCE, 1); + if (msg == EQUIP_ERR_OK) + player->StoreNewItem(dest, ITEM_RUBY_ESSENCE, true); + player->CLOSE_GOSSIP_MENU(); + break; + } + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ3, creature->GetGUID()); + break; } break; - case GOSSIP_ACTION_INFO_DEF + 2: - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_RUBY_ESSENCE, 1); - if (msg == EQUIP_ERR_OK) - player->StoreNewItem(dest, ITEM_RUBY_ESSENCE, true); - player->CLOSE_GOSSIP_MENU(); - break; - } - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_BELGARISTRASZ3, creature->GetGUID()); - break; } - break; - case NPC_ETERNOS: //Eternos - switch (action) + case NPC_ETERNOS: //Eternos { - case GOSSIP_ACTION_INFO_DEF + 1: - if (!HAS_ESSENCE(player)) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS1, creature->GetGUID()); - } - else + switch (action) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS2, creature->GetGUID()); + case GOSSIP_ACTION_INFO_DEF + 1: + if (!HAS_ESSENCE(player)) + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS1, creature->GetGUID()); + } + else + { + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ETERNOS2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS2, creature->GetGUID()); + } + break; + case GOSSIP_ACTION_INFO_DEF + 2: + { + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_AMBER_ESSENCE, 1); + if (msg == EQUIP_ERR_OK) + player->StoreNewItem(dest, ITEM_AMBER_ESSENCE, true); + player->CLOSE_GOSSIP_MENU(); + break; + } + case GOSSIP_ACTION_INFO_DEF + 3: + player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS3, creature->GetGUID()); + break; } break; - case GOSSIP_ACTION_INFO_DEF + 2: - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_AMBER_ESSENCE, 1); - if (msg == EQUIP_ERR_OK) - player->StoreNewItem(dest, ITEM_AMBER_ESSENCE, true); - player->CLOSE_GOSSIP_MENU(); - break; - } - case GOSSIP_ACTION_INFO_DEF + 3: - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ETERNOS3, creature->GetGUID()); - break; } - break; } return true; @@ -235,15 +239,15 @@ public: void MovementInform(uint32 /*type*/, uint32 id) { + if (id) + return; + // When Belgaristraz finish his moving say grateful text if (me->GetEntry() == NPC_BELGARISTRASZ) - if (id == 0) - { - Talk(SAY_BELGARISTRASZ); - } + Talk(SAY_BELGARISTRASZ); + // The gossip flag should activate when Drakos die and not from DB - if (id == 0) - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp new file mode 100644 index 00000000000..105b4757066 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -0,0 +1,3221 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "PassiveAI.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "MoveSplineInit.h" +#include "CreatureTextMgr.h" +#include "ulduar.h" + +enum Yells +{ + // Sara + SAY_SARA_ULDUAR_SCREAM_1 = 0, // screams randomly in a whole instance, unused on retail + SAY_SARA_ULDUAR_SCREAM_2 = 1, // screams randomly in a whole instance, unused on retail + SAY_SARA_AGGRO = 2, + SAY_SARA_FERVOR_HIT = 3, + SAY_SARA_BLESSING_HIT = 4, + SAY_SARA_KILL = 5, + SAY_SARA_TRANSFORM_1 = 6, + SAY_SARA_TRANSFORM_2 = 7, + SAY_SARA_TRANSFORM_3 = 8, + SAY_SARA_TRANSFORM_4 = 9, + SAY_SARA_DEATH_RAY = 10, + SAY_SARA_PSYCHOSIS_HIT = 11, + + // Yogg-Saron + SAY_YOGG_SARON_SPAWN = 0, + SAY_YOGG_SARON_MADNESS = 1, + EMOTE_YOGG_SARON_MADNESS = 2, + SAY_YOGG_SARON_PHASE_3 = 3, + SAY_YOGG_SARON_DEAFENING_ROAR = 4, + EMOTE_YOGG_SARON_DEAFENING_ROAR = 5, + SAY_YOGG_SARON_DEATH = 6, + EMOTE_YOGG_SARON_EMPOWERING_SHADOWS = 7, + EMOTE_YOGG_SARON_EXTINGUISH_ALL_LIFE = 8, + + // Voice of Yogg-Saron + WHISPER_VOICE_PHASE_1_WIPE = 0, + WHISPER_VOICE_INSANE = 1, + + // Brain of Yogg-Saron + EMOTE_BRAIN_ILLUSION_SHATTERED = 0, + + // Ominous Cloud + EMOTE_OMINOUS_CLOUD_PLAYER_TOUCH = 0, + + // Keepers + SAY_KEEPER_CHOSEN_1 = 0, + SAY_KEEPER_CHOSEN_2 = 1, + + // Yogg-Saron illusions + SAY_STORMWIND_ROLEPLAY_4 = 0, + SAY_STORMWIND_ROLEPLAY_7 = 1, + SAY_ICECROWN_ROLEPLAY_5 = 2, + SAY_ICECROWN_ROLEPLAY_6 = 3, + SAY_CHAMBER_ROLEPLAY_5 = 4, + + // Neltharion + SAY_CHAMBER_ROLEPLAY_1 = 0, + SAY_CHAMBER_ROLEPLAY_3 = 1, + + // Ysera + SAY_CHAMBER_ROLEPLAY_2 = 0, + + // Malygos + SAY_CHAMBER_ROLEPLAY_4 = 0, + + // Immolated Champion + SAY_ICECROWN_ROLEPLAY_1 = 0, + SAY_ICECROWN_ROLEPLAY_3 = 1, + + // The Lich King + SAY_ICECROWN_ROLEPLAY_2 = 0, + SAY_ICECROWN_ROLEPLAY_4 = 1, + + // Garona + SAY_STORMWIND_ROLEPLAY_1 = 0, + SAY_STORMWIND_ROLEPLAY_2 = 1, + SAY_STORMWIND_ROLEPLAY_3 = 2, + SAY_STORMWIND_ROLEPLAY_6 = 3, + + // King Llane + SAY_STORMWIND_ROLEPLAY_5 = 0, +}; + +enum Spells +{ + // Voice of Yogg-Saron + SPELL_SUMMON_GUARDIAN_2 = 62978, + SPELL_SANITY_PERIODIC = 63786, + SPELL_SANITY = 63050, + SPELL_INSANE_PERIODIC = 64554, + SPELL_INSANE = 63120, + //SPELL_CLEAR_INSANE = 63122, // when it should be casted? + SPELL_CONSTRICTOR_TENTACLE = 64132, + SPELL_CRUSHER_TENTACLE_SUMMON = 64139, + SPELL_CORRUPTOR_TENTACLE_SUMMON = 64143, + SPELL_IMMORTAL_GUARDIAN = 64158, + + // Sara + SPELL_SARAS_FERVOR = 63138, + SPELL_SARAS_FERVOR_TARGET_SELECTOR = 63747, + SPELL_SARAS_BLESSING = 63134, + SPELL_SARAS_BLESSING_TARGET_SELECTOR = 63745, + SPELL_SARAS_ANGER = 63147, + SPELL_SARAS_ANGER_TARGET_SELECTOR = 63744, + SPELL_FULL_HEAL = 43978, + SPELL_PHASE_2_TRANSFORM = 65157, + SPELL_SHADOWY_BARRIER_SARA = 64775, + SPELL_RIDE_YOGG_SARON_VEHICLE = 61791, + SPELL_PSYCHOSIS = 63795, + SPELL_MALADY_OF_THE_MIND = 63830, + SPELL_BRAIN_LINK = 63802, + SPELL_BRAIN_LINK_DAMAGE = 63803, // red beam + SPELL_BRAIN_LINK_NO_DAMAGE = 63804, // yellow beam + SPELL_DEATH_RAY = 63891, + + // Ominous Cloud + SPELL_OMINOUS_CLOUD_VISUAL = 63084, + SPELL_SUMMON_GUARDIAN_1 = 63031, + + // Guardian of Yogg-Saron + SPELL_DARK_VOLLEY = 63038, + SPELL_SHADOW_NOVA = 62714, + SPELL_SHADOW_NOVA_2 = 65719, + + // Yogg-Saron + SPELL_EXTINGUISH_ALL_LIFE = 64166, + SPELL_SHADOWY_BARRIER_YOGG = 63894, + SPELL_KNOCK_AWAY = 64022, + SPELL_PHASE_3_TRANSFORM = 63895, + SPELL_DEAFENING_ROAR = 64189, + SPELL_LUNATIC_GAZE = 64163, + SPELL_LUNATIC_GAZE_DAMAGE = 64164, + SPELL_SHADOW_BEACON = 64465, + + // Brain of Yogg-Saron + SPELL_MATCH_HEALTH = 64066, + SPELL_MATCH_HEALTH_2 = 64069, + SPELL_INDUCE_MADNESS = 64059, + SPELL_BRAIN_HURT_VISUAL = 64361, + SPELL_SHATTERED_ILLUSION = 64173, + SPELL_SHATTERED_ILLUSION_REMOVE = 65238, + + // Tentacles + SPELL_ERUPT = 64144, + SPELL_TENTACLE_VOID_ZONE = 64017, // used by Corruptor Tentacle and Crusher Tentacle only + + // Crusher Tentacle + SPELL_DIMINISH_POWER = 64145, + SPELL_DIMINSH_POWER = 64148, + SPELL_FOCUSED_ANGER = 57688, + SPELL_CRUSH = 64146, + //SPELL_CRUSH_2 = 65201, // triggered by SPELL_CRUSH, basepoints of SPELL_MALADY_OF_THE_MIND + + // Constrictor Tentacle + SPELL_TENTACLE_VOID_ZONE_2 = 64384, + SPELL_LUNGE = 64131, + + // Corruptor Tentacle + SPELL_APATHY = 64156, + SPELL_BLACK_PLAGUE = 64153, + SPELL_CURSE_OF_DOOM = 64157, + SPELL_DRAINING_POISON = 64152, + + // Immortal Guardian + SPELL_EMPOWERING_SHADOWS = 64468, + SPELL_EMPOWERED = 64161, + SPELL_EMPOWERED_BUFF = 65294, + SPELL_WEAKENED = 64162, + SPELL_DRAIN_LIFE = 64159, + SPELL_RECENTLY_SPAWNED = 64497, + SPELL_SIMPLE_TELEPORT = 64195, + + // Keepers at Observation Ring + SPELL_TELEPORT = 62940, + + // Keepers + SPELL_SIMPLE_TELEPORT_KEEPERS = 12980, + SPELL_KEEPER_ACTIVE = 62647, + + // Mimiron + SPELL_SPEED_OF_INVENTION = 62671, + SPELL_DESTABILIZATION_MATRIX = 65206, + + // Freya + SPELL_RESILIENCE_OF_NATURE = 62670, + SPELL_SANITY_WELL_SUMMON = 64170, + + // Sanity Well + SPELL_SANITY_WELL_VISUAL = 63288, + SPELL_SANITY_WELL = 64169, + + // Thorim + SPELL_FURY_OF_THE_STORM = 62702, + SPELL_TITANIC_STORM = 64171, + + // Hodir + SPELL_FORTITUDE_OF_FROST = 62650, + SPELL_HODIRS_PROTECTIVE_GAZE = 64174, + SPELL_FLASH_FREEZE_VISUAL = 64176, + + // Death Orb + SPELL_DEATH_RAY_ORIGIN_VISUAL = 63893, + + // Death Ray + SPELL_DEATH_RAY_WARNING_VISUAL = 63882, + SPELL_DEATH_RAY_PERIODIC = 63883, + SPELL_DEATH_RAY_DAMAGE_VISUAL = 63886, + + // Laughing Skull + SPELL_LUNATIC_GAZE_SKULL = 64167, + + // Descend Into Madness + SPELL_TELEPORT_PORTAL_VISUAL = 64416, + + // Illusions + SPELL_GRIM_REPRISAL = 63305, + SPELL_GRIM_REPRISAL_DAMAGE = 64039, + + // Suit of Armor + SPELL_NONDESCRIPT_1 = 64013, + + // Dragon Consorts & Deathsworn Zealot + SPELL_NONDESCRIPT_2 = 64010, + + // Garona + SPELL_ASSASSINATE = 64063, + + // King Llane + SPELL_PERMANENT_FEIGN_DEATH = 29266, + + // The Lich King + SPELL_DEATHGRASP = 63037, + + // Turned Champion + SPELL_VERTEX_COLOR_BLACK = 39662, + + // Player self cast spells + SPELL_MALADY_OF_THE_MIND_JUMP = 63881, + SPELL_ILLUSION_ROOM = 63988, + SPELL_HATE_TO_ZERO = 63984, + SPELL_TELEPORT_BACK_TO_MAIN_ROOM = 63992, + SPELL_INSANE_VISUAL = 64464, + SPELL_CONSTRICTOR_TENTACLE_SUMMON = 64133, + SPELL_SQUEEZE = 64125, + SPELL_FLASH_FREEZE = 64175, + SPELL_LOW_SANITY_SCREEN_EFFECT = 63752, + + SPELL_IN_THE_MAWS_OF_THE_OLD_GOD = 64184, +}; + +enum Phases +{ + PHASE_ONE = 1, + PHASE_TRANSFORM = 2, + PHASE_TWO = 3, + PHASE_THREE = 4, +}; + +enum Events +{ + // Voice of Yogg-Saron + EVENT_LOCK_DOOR = 1, + EVENT_SUMMON_GUARDIAN_OF_YOGG_SARON = 2, + EVENT_SUMMON_CORRUPTOR_TENTACLE = 3, + EVENT_SUMMON_CONSTRICTOR_TENTACLE = 4, + EVENT_SUMMON_CRUSHER_TENTACLE = 5, + EVENT_ILLUSION = 6, + EVENT_SUMMON_IMMORTAL_GUARDIAN = 7, + EVENT_EXTINGUISH_ALL_LIFE = 8, // handled by Voice, timer starts at the beginning of the fight (Yogg-Saron is not spawned at this moment) + + // Sara + EVENT_SARAS_FERVOR = 9, + EVENT_SARAS_BLESSING = 10, + EVENT_SARAS_ANGER = 11, + EVENT_TRANSFORM_1 = 12, + EVENT_TRANSFORM_2 = 13, + EVENT_TRANSFORM_3 = 14, + EVENT_TRANSFORM_4 = 15, + EVENT_PSYCHOSIS = 16, + EVENT_MALADY_OF_THE_MIND = 17, + EVENT_BRAIN_LINK = 18, + EVENT_DEATH_RAY = 19, + + // Tentacles + EVENT_DIMINISH_POWER = 20, + EVENT_CAST_RANDOM_SPELL = 21, + + // Yogg-Saron + EVENT_YELL_BOW_DOWN = 22, + EVENT_SHADOW_BEACON = 23, + EVENT_LUNATIC_GAZE = 24, + EVENT_DEAFENING_ROAR = 25, // only on 25-man with 0-3 keepers active (Hard Mode) + + // Guardian of Yogg-Saron + EVENT_DARK_VOLLEY = 26, + + // Immortal Guardian + EVENT_DRAIN_LIFE = 27, + + // Keepers + EVENT_DESTABILIZATION_MATRIX = 28, + EVENT_HODIRS_PROTECTIVE_GAZE = 29, + + // Chamber Illusion + EVENT_CHAMBER_ROLEPLAY_1 = 30, + EVENT_CHAMBER_ROLEPLAY_2 = 31, + EVENT_CHAMBER_ROLEPLAY_3 = 32, + EVENT_CHAMBER_ROLEPLAY_4 = 33, + EVENT_CHAMBER_ROLEPLAY_5 = 34, + + // Icecrown Illusion + EVENT_ICECROWN_ROLEPLAY_1 = 35, + EVENT_ICECROWN_ROLEPLAY_2 = 36, + EVENT_ICECROWN_ROLEPLAY_3 = 37, + EVENT_ICECROWN_ROLEPLAY_4 = 38, + EVENT_ICECROWN_ROLEPLAY_5 = 39, + EVENT_ICECROWN_ROLEPLAY_6 = 40, + + // Stormwind Illusion + EVENT_STORMWIND_ROLEPLAY_1 = 41, + EVENT_STORMWIND_ROLEPLAY_2 = 42, + EVENT_STORMWIND_ROLEPLAY_3 = 43, + EVENT_STORMWIND_ROLEPLAY_4 = 44, + EVENT_STORMWIND_ROLEPLAY_5 = 45, + EVENT_STORMWIND_ROLEPLAY_6 = 46, + EVENT_STORMWIND_ROLEPLAY_7 = 47, +}; + +enum EventGroups +{ + EVENT_GROUP_SUMMON_TENTACLES = 1, +}; + +enum Actions +{ + ACTION_PHASE_TRANSFORM = 0, + ACTION_PHASE_TWO = 1, + ACTION_PHASE_THREE = 2, + ACTION_INDUCE_MADNESS = 3, + ACTION_SANITY_WELLS = 4, + ACTION_FLASH_FREEZE = 5, + ACTION_TENTACLE_KILLED = 6, + ACTION_START_ROLEPLAY = 8, + ACTION_TOGGLE_SHATTERED_ILLUSION = 9, +}; + +enum CreatureGroups +{ + CREATURE_GROUP_CLOUDS = 0, + CREATURE_GROUP_PORTALS_10 = 1, + CREATURE_GROUP_PORTALS_25 = 2, +}; + +Position const YoggSaronSpawnPos = {1980.43f, -25.7708f, 324.9724f, 3.141593f}; +Position const ObservationRingKeepersPos[4] = +{ + {1945.682f, 33.34201f, 411.4408f, 5.270895f}, // Freya + {1945.761f, -81.52171f, 411.4407f, 1.029744f}, // Hodir + {2028.822f, -65.73573f, 411.4426f, 2.460914f}, // Thorim + {2028.766f, 17.42014f, 411.4446f, 3.857178f}, // Mimiron +}; +Position const YSKeepersPos[4] = +{ + {2036.873f, 25.42513f, 338.4984f, 3.909538f}, // Freya + {1939.045f, -90.87457f, 338.5426f, 0.994837f}, // Hodir + {1939.148f, 42.49035f, 338.5427f, 5.235988f}, // Thorim + {2036.658f, -73.58822f, 338.4985f, 2.460914f}, // Mimiron +}; +Position const IllusionsMiscPos[2] = +{ + {1928.793f, 65.03109f, 242.3763f, 0.0f}, // Garona end position + {1912.324f, -155.7967f, 239.9896f, 0.0f}, // Saurfang end position +}; + +enum MiscData +{ + ACHIEV_TIMED_START_EVENT = 21001, + SOUND_LUNATIC_GAZE = 15757, +}; + +class StartAttackEvent : public BasicEvent +{ + public: + StartAttackEvent(Creature* summoner, Creature* owner) + : _summoner(summoner), _owner(owner) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + _owner->SetReactState(REACT_AGGRESSIVE); + if (Unit* target = _summoner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 300.0f)) + _owner->AI()->AttackStart(target); + return true; + } + + private: + Creature* _summoner; + Creature* _owner; +}; + +class boss_voice_of_yogg_saron : public CreatureScript +{ + public: + boss_voice_of_yogg_saron() : CreatureScript("boss_voice_of_yogg_saron") { } + + struct boss_voice_of_yogg_saronAI : public BossAI + { + boss_voice_of_yogg_saronAI(Creature* creature) : BossAI(creature, BOSS_YOGG_SARON) + { + SetCombatMovement(false); + } + + void MoveInLineOfSight(Unit* who) + { + // TODO: MoveInLineOfSight doesn't work for such a big distance + if (who->GetTypeId() == TYPEID_PLAYER && me->GetDistance2d(who) < 99.0f && !me->isInCombat()) + me->SetInCombatWithZone(); + } + + void EnterEvadeMode() + { + BossAI::EnterEvadeMode(); + + for (uint8 i = DATA_SARA; i <= DATA_MIMIRON_YS; ++i) + if (Creature* creature = ObjectAccessor::GetCreature(*me, instance->GetData64(i))) + creature->AI()->EnterEvadeMode(); + + // not sure, spoken by Sara (sound), regarding to wowwiki Voice whispers it + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + { + if (events.IsInPhase(PHASE_ONE)) + Talk(WHISPER_VOICE_PHASE_1_WIPE, player->GetGUID()); + + player->RemoveAurasDueToSpell(SPELL_SANITY); + player->RemoveAurasDueToSpell(SPELL_INSANE); + } + } + + void Reset() + { + _Reset(); + events.SetPhase(PHASE_ONE); + + instance->SetData(DATA_DRIVE_ME_CRAZY, uint32(true)); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + + _guardiansCount = 0; + _guardianTimer = 20000; + _illusionShattered = false; + + bool clockwise = false; + std::list<TempSummon*> clouds; + me->SummonCreatureGroup(CREATURE_GROUP_CLOUDS, &clouds); + clouds.sort(Trinity::ObjectDistanceOrderPred(me, true)); + for (std::list<TempSummon*>::const_iterator itr = clouds.begin(); itr != clouds.end(); ++itr) + { + (*itr)->AI()->DoAction(int32(clockwise)); + clockwise = !clockwise; + } + } + + void EnterCombat(Unit* /*who*/) + { + if (Creature* sara = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARA))) + sara->SetInCombatWith(me); + + for (uint8 i = DATA_FREYA_YS; i <= DATA_MIMIRON_YS; ++i) + if (Creature* keeper = ObjectAccessor::GetCreature(*me, instance->GetData64(i))) + keeper->SetInCombatWith(me); + + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + + me->CastCustomSpell(SPELL_SUMMON_GUARDIAN_2, SPELLVALUE_MAX_TARGETS, 1); + DoCast(me, SPELL_SANITY_PERIODIC); + + events.ScheduleEvent(EVENT_LOCK_DOOR, 15000); + events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_YOGG_SARON, _guardianTimer, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_EXTINGUISH_ALL_LIFE, 900000); // 15 minutes + } + + void JustDied(Unit* killer) + { + // don't despawn Yogg-Saron's corpse, remove him from SummonList! + if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_YOGG_SARON))) + summons.Despawn(yogg); + + BossAI::JustDied(killer); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + // don't summon tentacles when illusion is shattered, delay them + if (_illusionShattered) + events.DelayEvents(diff, EVENT_GROUP_SUMMON_TENTACLES); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_LOCK_DOOR: + DoCast(me, SPELL_INSANE_PERIODIC); + instance->SetBossState(BOSS_YOGG_SARON, IN_PROGRESS); + break; + case EVENT_EXTINGUISH_ALL_LIFE: + if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_YOGG_SARON))) + { + yogg->AI()->Talk(EMOTE_YOGG_SARON_EXTINGUISH_ALL_LIFE, me->GetGUID()); + yogg->CastSpell((Unit*)NULL, SPELL_EXTINGUISH_ALL_LIFE, true); + } + events.ScheduleEvent(EVENT_EXTINGUISH_ALL_LIFE, 10000); // cast it again after a short while, players can survive + break; + case EVENT_SUMMON_GUARDIAN_OF_YOGG_SARON: + me->CastCustomSpell(SPELL_SUMMON_GUARDIAN_2, SPELLVALUE_MAX_TARGETS, 1); + ++_guardiansCount; + if (_guardiansCount <= 6 && _guardiansCount % 3 == 0) + _guardianTimer -= 5000; + events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_YOGG_SARON, _guardianTimer, 0, PHASE_ONE); + break; + case EVENT_SUMMON_CORRUPTOR_TENTACLE: + DoCastAOE(SPELL_CORRUPTOR_TENTACLE_SUMMON); + events.ScheduleEvent(EVENT_SUMMON_CORRUPTOR_TENTACLE, 30000, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + break; + case EVENT_SUMMON_CONSTRICTOR_TENTACLE: + me->CastCustomSpell(SPELL_CONSTRICTOR_TENTACLE, SPELLVALUE_MAX_TARGETS, 1); + events.ScheduleEvent(EVENT_SUMMON_CONSTRICTOR_TENTACLE, 25000, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + break; + case EVENT_SUMMON_CRUSHER_TENTACLE: + DoCastAOE(SPELL_CRUSHER_TENTACLE_SUMMON); + events.ScheduleEvent(EVENT_SUMMON_CRUSHER_TENTACLE, 60000, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + break; + case EVENT_ILLUSION: + { + if (Creature* yogg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_YOGG_SARON))) + { + yogg->AI()->Talk(EMOTE_YOGG_SARON_MADNESS); + yogg->AI()->Talk(SAY_YOGG_SARON_MADNESS); + } + + me->SummonCreatureGroup(CREATURE_GROUP_PORTALS_10); + if (me->GetMap()->Is25ManRaid()) + me->SummonCreatureGroup(CREATURE_GROUP_PORTALS_25); + + uint8 illusion = urand(CHAMBER_ILLUSION, STORMWIND_ILLUSION); + instance->SetData(DATA_ILLUSION, illusion); + + if (Creature* brain = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BRAIN_OF_YOGG_SARON))) + brain->AI()->DoAction(ACTION_INDUCE_MADNESS); + events.ScheduleEvent(EVENT_ILLUSION, 80000, 0, PHASE_TWO); // wowwiki says 80 secs, wowhead says something about 90 secs + break; + } + case EVENT_SUMMON_IMMORTAL_GUARDIAN: + DoCastAOE(SPELL_IMMORTAL_GUARDIAN); + events.ScheduleEvent(EVENT_SUMMON_IMMORTAL_GUARDIAN, 15000, 0, PHASE_THREE); + break; + default: + break; + } + } + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_PHASE_TRANSFORM: + events.SetPhase(PHASE_TRANSFORM); + summons.DespawnEntry(NPC_OMINOUS_CLOUD); + break; + case ACTION_PHASE_TWO: + events.SetPhase(PHASE_TWO); + me->SummonCreature(NPC_YOGG_SARON, YoggSaronSpawnPos); + if (Creature* brain = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BRAIN_OF_YOGG_SARON))) + brain->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_SUMMON_CORRUPTOR_TENTACLE, 1, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + events.ScheduleEvent(EVENT_SUMMON_CONSTRICTOR_TENTACLE, 1, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + events.ScheduleEvent(EVENT_SUMMON_CRUSHER_TENTACLE, 1, EVENT_GROUP_SUMMON_TENTACLES, PHASE_TWO); + events.ScheduleEvent(EVENT_ILLUSION, 60000, 0, PHASE_TWO); + break; + case ACTION_TOGGLE_SHATTERED_ILLUSION: + _illusionShattered = !_illusionShattered; + break; + case ACTION_PHASE_THREE: + events.SetPhase(PHASE_THREE); + events.ScheduleEvent(EVENT_SUMMON_IMMORTAL_GUARDIAN, 1000, 0, PHASE_THREE); + break; + default: + break; + } + } + + void JustSummoned(Creature* summon) + { + switch (summon->GetEntry()) + { + case NPC_GUARDIAN_OF_YOGG_SARON: + summon->m_Events.AddEvent(new StartAttackEvent(me, summon), summon->m_Events.CalculateTime(1000)); + break; + case NPC_YOGG_SARON: + summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + break; + case NPC_CONSTRICTOR_TENTACLE: + summon->CastSpell(summon, SPELL_LUNGE, true); + break; + case NPC_CRUSHER_TENTACLE: + case NPC_CORRUPTOR_TENTACLE: + summon->SetReactState(REACT_PASSIVE); + summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + summon->m_Events.AddEvent(new StartAttackEvent(me, summon), summon->m_Events.CalculateTime(5000)); + break; + case NPC_DESCEND_INTO_MADNESS: + summon->CastSpell(summon, SPELL_TELEPORT_PORTAL_VISUAL, true); + break; + case NPC_IMMORTAL_GUARDIAN: + summon->CastSpell(summon, SPELL_SIMPLE_TELEPORT, true); + break; + } + + BossAI::JustSummoned(summon); + } + + private: + uint8 _guardiansCount; + uint32 _guardianTimer; + bool _illusionShattered; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<boss_voice_of_yogg_saronAI>(creature); + } +}; + +class boss_sara : public CreatureScript +{ + public: + boss_sara() : CreatureScript("boss_sara") { } + + struct boss_saraAI : public ScriptedAI + { + boss_saraAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + uint64 GetLinkedPlayerGUID(uint64 guid) const + { + std::map<uint64, uint64>::const_iterator itr = _linkData.find(guid); + if (itr != _linkData.end()) + return itr->second; + + return 0; + } + + void SetLinkBetween(uint64 player1, uint64 player2) + { + _linkData[player1] = player2; + _linkData[player2] = player1; + } + + // called once for each target on aura remove + void RemoveLinkFrom(uint64 player1) + { + _linkData.erase(player1); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (_events.IsInPhase(PHASE_ONE) && damage >= me->GetHealth()) + { + damage = 0; + + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->DoAction(ACTION_PHASE_TRANSFORM); + + Talk(SAY_SARA_TRANSFORM_1); + _events.SetPhase(PHASE_TRANSFORM); + _events.ScheduleEvent(EVENT_TRANSFORM_1, 4700, 0, PHASE_TRANSFORM); + _events.ScheduleEvent(EVENT_TRANSFORM_2, 9500, 0, PHASE_TRANSFORM); + _events.ScheduleEvent(EVENT_TRANSFORM_3, 14300, 0, PHASE_TRANSFORM); + _events.ScheduleEvent(EVENT_TRANSFORM_4, 14500, 0, PHASE_TRANSFORM); + } + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) + { + if (!roll_chance_i(30) || _events.IsInPhase(PHASE_TRANSFORM)) + return; + + switch (spell->Id) + { + case SPELL_SARAS_FERVOR: + Talk(SAY_SARA_FERVOR_HIT); + break; + case SPELL_SARAS_BLESSING: + Talk(SAY_SARA_BLESSING_HIT); + break; + case SPELL_PSYCHOSIS: + Talk(SAY_SARA_PSYCHOSIS_HIT); + break; + default: + break; + } + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode()) + Talk(SAY_SARA_KILL); + } + + void EnterCombat(Unit* /*who*/) + { + Talk(SAY_SARA_AGGRO); + _events.ScheduleEvent(EVENT_SARAS_FERVOR, 5000, 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_SARAS_BLESSING, urand(10000, 30000), 0, PHASE_ONE); + _events.ScheduleEvent(EVENT_SARAS_ANGER, urand(15000, 25000), 0, PHASE_ONE); + } + + void Reset() + { + me->RemoveAllAuras(); + me->SetReactState(REACT_PASSIVE); + me->setFaction(35); + _events.Reset(); + _events.SetPhase(PHASE_ONE); + } + + void UpdateAI(uint32 diff) + { + if (!me->isInCombat()) + return; + + if (me->HasAura(SPELL_SHATTERED_ILLUSION)) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SARAS_FERVOR: + me->CastCustomSpell(SPELL_SARAS_FERVOR_TARGET_SELECTOR, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_SARAS_FERVOR, 6000, 0, PHASE_ONE); + break; + case EVENT_SARAS_ANGER: + me->CastCustomSpell(SPELL_SARAS_ANGER_TARGET_SELECTOR, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_SARAS_ANGER, urand(6000, 8000), 0, PHASE_ONE); + break; + case EVENT_SARAS_BLESSING: + me->CastCustomSpell(SPELL_SARAS_BLESSING_TARGET_SELECTOR, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_SARAS_BLESSING, urand(6000, 30000), 0, PHASE_ONE); + break; + case EVENT_TRANSFORM_1: + Talk(SAY_SARA_TRANSFORM_2); + break; + case EVENT_TRANSFORM_2: + Talk(SAY_SARA_TRANSFORM_3); + break; + case EVENT_TRANSFORM_3: + Talk(SAY_SARA_TRANSFORM_4); + DoCast(me, SPELL_FULL_HEAL); + me->setFaction(16); + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->DoAction(ACTION_PHASE_TWO); + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_MIMIRON_YS))) + mimiron->AI()->DoAction(ACTION_PHASE_TWO); + break; + case EVENT_TRANSFORM_4: + DoCast(me, SPELL_PHASE_2_TRANSFORM); + if (Creature* yogg = ObjectAccessor::GetCreature(*me, _instance->GetData64(BOSS_YOGG_SARON))) + DoCast(yogg, SPELL_RIDE_YOGG_SARON_VEHICLE); + DoCast(me, SPELL_SHADOWY_BARRIER_SARA); + _events.SetPhase(PHASE_TWO); + _events.ScheduleEvent(EVENT_DEATH_RAY, 20000, 0, PHASE_TWO); // almost never casted at scheduled time, why? + _events.ScheduleEvent(EVENT_MALADY_OF_THE_MIND, 18000, 0, PHASE_TWO); + _events.ScheduleEvent(EVENT_PSYCHOSIS, 1, 0, PHASE_TWO); + _events.ScheduleEvent(EVENT_BRAIN_LINK, 23000, 0, PHASE_TWO); + break; + case EVENT_DEATH_RAY: + DoCast(me, SPELL_DEATH_RAY); + _events.ScheduleEvent(EVENT_DEATH_RAY, 21000, 0, PHASE_TWO); + break; + case EVENT_MALADY_OF_THE_MIND: + me->CastCustomSpell(SPELL_MALADY_OF_THE_MIND, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_MALADY_OF_THE_MIND, urand(18000, 25000), 0, PHASE_TWO); + break; + case EVENT_PSYCHOSIS: + me->CastCustomSpell(SPELL_PSYCHOSIS, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_PSYCHOSIS, 4000, 0, PHASE_TWO); + break; + case EVENT_BRAIN_LINK: + me->CastCustomSpell(SPELL_BRAIN_LINK, SPELLVALUE_MAX_TARGETS, 2); + _events.ScheduleEvent(EVENT_BRAIN_LINK, urand(23000, 26000), 0, PHASE_TWO); + break; + default: + break; + } + } + } + + void JustSummoned(Creature* summon) + { + summon->SetReactState(REACT_PASSIVE); + + switch (summon->GetEntry()) + { + case NPC_DEATH_ORB: + Talk(SAY_SARA_DEATH_RAY); + summon->CastSpell(summon, SPELL_DEATH_RAY_ORIGIN_VISUAL); + for (uint8 i = 0; i < 4; ++i) + { + Position pos; + float radius = frand(25.0f, 50.0f); + float angle = frand(0.0f, 2.0f * M_PI); + pos.m_positionX = YoggSaronSpawnPos.GetPositionX() + radius * cosf(angle); + pos.m_positionY = YoggSaronSpawnPos.GetPositionY() + radius * sinf(angle); + pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), YoggSaronSpawnPos.GetPositionZ() + 5.0f); + me->SummonCreature(NPC_DEATH_RAY, pos, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + break; + case NPC_DEATH_RAY: + summon->CastSpell(summon, SPELL_DEATH_RAY_WARNING_VISUAL); + break; + } + + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->JustSummoned(summon); + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_PHASE_THREE: // Sara does nothing in phase 3 + _events.SetPhase(PHASE_THREE); + break; + default: + break; + } + } + + private: + EventMap _events; + InstanceScript* _instance; + std::map<uint64, uint64> _linkData; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<boss_saraAI>(creature); + } +}; + +class boss_yogg_saron : public CreatureScript +{ + public: + boss_yogg_saron() : CreatureScript("boss_yogg_saron") { } + + struct boss_yogg_saronAI : public PassiveAI + { + boss_yogg_saronAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() + { + _events.Reset(); + _events.SetPhase(PHASE_TWO); + _events.ScheduleEvent(EVENT_YELL_BOW_DOWN, 3000, 0, PHASE_TWO); + DoCast(me, SPELL_SHADOWY_BARRIER_YOGG); + DoCast(me, SPELL_KNOCK_AWAY); + + me->ResetLootMode(); + switch (_instance->GetData(DATA_KEEPERS_COUNT)) + { + case 0: + me->AddLootMode(LOOT_MODE_HARD_MODE_4); + case 1: + me->AddLootMode(LOOT_MODE_HARD_MODE_3); + case 2: + me->AddLootMode(LOOT_MODE_HARD_MODE_2); + case 3: + me->AddLootMode(LOOT_MODE_HARD_MODE_1); + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_IN_THE_MAWS_OF_THE_OLD_GOD) + me->AddLootMode(32); + } + + void JustDied(Unit* /*killer*/) + { + Talk(SAY_YOGG_SARON_DEATH); + + if (Creature* creature = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + me->Kill(creature); + + for (uint8 i = DATA_SARA; i <= DATA_BRAIN_OF_YOGG_SARON; ++i) + if (Creature* creature = ObjectAccessor::GetCreature(*me, _instance->GetData64(i))) + creature->DisappearAndDie(); + + for (uint8 i = DATA_FREYA_YS; i <= DATA_MIMIRON_YS; ++i) + if (Creature* creature = ObjectAccessor::GetCreature(*me, _instance->GetData64(i))) + creature->AI()->EnterEvadeMode(); + + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + { + player->RemoveAurasDueToSpell(SPELL_SANITY); + player->RemoveAurasDueToSpell(SPELL_INSANE); + } + } + + void UpdateAI(uint32 diff) + { + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_YELL_BOW_DOWN: + Talk(SAY_YOGG_SARON_SPAWN); + break; + case EVENT_SHADOW_BEACON: + DoCastAOE(SPELL_SHADOW_BEACON); + Talk(EMOTE_YOGG_SARON_EMPOWERING_SHADOWS); + _events.ScheduleEvent(EVENT_SHADOW_BEACON, 45000, 0, PHASE_THREE); + break; + case EVENT_LUNATIC_GAZE: + DoCast(me, SPELL_LUNATIC_GAZE); + sCreatureTextMgr->SendSound(me, SOUND_LUNATIC_GAZE, CHAT_MSG_MONSTER_YELL, 0, TEXT_RANGE_NORMAL, TEAM_OTHER, false); + _events.ScheduleEvent(EVENT_LUNATIC_GAZE, 12000, 0, PHASE_THREE); + break; + case EVENT_DEAFENING_ROAR: + DoCastAOE(SPELL_DEAFENING_ROAR); + Talk(SAY_YOGG_SARON_DEAFENING_ROAR); + Talk(EMOTE_YOGG_SARON_DEAFENING_ROAR); + _events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(20000, 25000), 0, PHASE_THREE); // timer guessed + break; + default: + break; + } + } + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_PHASE_THREE: + _events.SetPhase(PHASE_THREE); + _events.ScheduleEvent(EVENT_SHADOW_BEACON, 45000, 0, PHASE_THREE); + _events.ScheduleEvent(EVENT_LUNATIC_GAZE, 12000, 0, PHASE_THREE); + if (me->GetMap()->Is25ManRaid() && _instance->GetData(DATA_KEEPERS_COUNT) < 4) + _events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(20000, 25000), 0, PHASE_THREE); // timer guessed + Talk(SAY_YOGG_SARON_PHASE_3); + DoCast(me, SPELL_PHASE_3_TRANSFORM); + me->RemoveAurasDueToSpell(SPELL_SHADOWY_BARRIER_YOGG); + break; + default: + break; + } + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<boss_yogg_saronAI>(creature); + } +}; + +class boss_brain_of_yogg_saron : public CreatureScript +{ + public: + boss_brain_of_yogg_saron() : CreatureScript("boss_brain_of_yogg_saron") { } + + struct boss_brain_of_yogg_saronAI : public PassiveAI + { + boss_brain_of_yogg_saronAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()), _summons(creature) { } + + void Reset() + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_MATCH_HEALTH); + _summons.DespawnAll(); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (me->HealthBelowPctDamaged(30, damage) && !me->HasAura(SPELL_BRAIN_HURT_VISUAL)) + { + me->RemoveAllAuras(); + me->InterruptNonMeleeSpells(true); + DoCastAOE(SPELL_SHATTERED_ILLUSION_REMOVE, true); + DoCast(me, SPELL_MATCH_HEALTH_2, true); // it doesn't seem to hit Yogg-Saron here + DoCast(me, SPELL_BRAIN_HURT_VISUAL, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->DoAction(ACTION_PHASE_THREE); + if (Creature* sara = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_SARA))) + sara->AI()->DoAction(ACTION_PHASE_THREE); + if (Creature* yogg = ObjectAccessor::GetCreature(*me, _instance->GetData64(BOSS_YOGG_SARON))) + yogg->AI()->DoAction(ACTION_PHASE_THREE); + + for (uint8 i = DATA_THORIM_YS; i <= DATA_MIMIRON_YS; ++i) + if (Creature* keeper = ObjectAccessor::GetCreature(*me, _instance->GetData64(i))) + keeper->AI()->DoAction(ACTION_PHASE_THREE); + } + } + + void UpdateAI(uint32 /*diff*/) { } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_INDUCE_MADNESS: + { + _tentaclesKilled = 0; + + me->SummonCreatureGroup(_instance->GetData(DATA_ILLUSION)); + + // make sure doors won't be opened + for (uint32 i = GO_BRAIN_ROOM_DOOR_1; i <= GO_BRAIN_ROOM_DOOR_3; ++i) + _instance->HandleGameObject(_instance->GetData64(i), false); + + DoCastAOE(SPELL_INDUCE_MADNESS); + break; + } + case ACTION_TENTACLE_KILLED: + { + uint8 illusion = _instance->GetData(DATA_ILLUSION); + if (++_tentaclesKilled >= (illusion == ICECROWN_ILLUSION ? 9 : 8)) + { + sCreatureTextMgr->SendChat(me, EMOTE_BRAIN_ILLUSION_SHATTERED, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_AREA); + _summons.DespawnAll(); + DoCastAOE(SPELL_SHATTERED_ILLUSION, true); + _instance->HandleGameObject(_instance->GetData64(GO_BRAIN_ROOM_DOOR_1 + illusion), true); + + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->DoAction(ACTION_TOGGLE_SHATTERED_ILLUSION); + } + break; + } + default: + break; + } + } + + void JustSummoned(Creature* summon) + { + _summons.Summon(summon); + } + + private: + InstanceScript* _instance; + SummonList _summons; + uint8 _tentaclesKilled; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<boss_brain_of_yogg_saronAI>(creature); + } +}; + +class npc_ominous_cloud : public CreatureScript +{ + public: + npc_ominous_cloud() : CreatureScript("npc_ominous_cloud") { } + + struct npc_ominous_cloudAI : public PassiveAI + { + npc_ominous_cloudAI(Creature* creature) : PassiveAI(creature) { } + + void Reset() + { + DoCast(me, SPELL_OMINOUS_CLOUD_VISUAL); + } + + void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise) + { + float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f; + float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY()); + + for (uint8 i = 0; i < 16; angle += step, ++i) + { + G3D::Vector3 point; + point.x = centerPos.GetPositionX() + radius * cosf(angle); + point.y = centerPos.GetPositionY() + radius * sinf(angle); + point.z = me->GetMap()->GetHeight(me->GetPhaseMask(), point.x, point.y, z + 5.0f); + path.push_back(point); + } + } + + void UpdateAI(uint32 /*diff*/) { } + + void DoAction(int32 action) + { + Movement::MoveSplineInit init(me); + FillCirclePath(YoggSaronSpawnPos, me->GetDistance2d(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY()), me->GetPositionZ(), init.Path(), action); + init.SetWalk(true); + init.SetCyclic(); + init.Launch(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_ominous_cloudAI>(creature); + } +}; + +class npc_guardian_of_yogg_saron : public CreatureScript +{ + public: + npc_guardian_of_yogg_saron() : CreatureScript("npc_guardian_of_yogg_saron") { } + + struct npc_guardian_of_yogg_saronAI : public ScriptedAI + { + npc_guardian_of_yogg_saronAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void JustDied(Unit* /*killer*/) + { + DoCastAOE(SPELL_SHADOW_NOVA); + DoCastAOE(SPELL_SHADOW_NOVA_2); + } + + void Reset() + { + _events.ScheduleEvent(EVENT_DARK_VOLLEY, urand(10000, 15000)); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DARK_VOLLEY: + DoCastAOE(SPELL_DARK_VOLLEY); + _events.ScheduleEvent(EVENT_DARK_VOLLEY, urand(10000, 15000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void IsSummonedBy(Unit* summoner) + { + if (summoner->GetEntry() != NPC_OMINOUS_CLOUD) + return; + + // Guardian can be summoned both by Voice of Yogg-Saron and by Ominous Cloud + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->JustSummoned(me); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_guardian_of_yogg_saronAI>(creature); + } +}; + +class npc_corruptor_tentacle : public CreatureScript +{ + public: + npc_corruptor_tentacle() : CreatureScript("npc_corruptor_tentacle") { } + + struct npc_corruptor_tentacleAI : public ScriptedAI + { + npc_corruptor_tentacleAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } + + void Reset() + { + DoCast(me, SPELL_TENTACLE_VOID_ZONE); + DoCastAOE(SPELL_ERUPT); + _events.ScheduleEvent(EVENT_CAST_RANDOM_SPELL, 1); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + if (me->HasAura(SPELL_SHATTERED_ILLUSION)) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CAST_RANDOM_SPELL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, RAND(SPELL_BLACK_PLAGUE, SPELL_CURSE_OF_DOOM, SPELL_APATHY, SPELL_DRAINING_POISON)); + _events.ScheduleEvent(EVENT_CAST_RANDOM_SPELL, 3000); + break; + default: + break; + } + } + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_corruptor_tentacleAI>(creature); + } +}; + +class npc_constrictor_tentacle : public CreatureScript +{ + public: + npc_constrictor_tentacle() : CreatureScript("npc_constrictor_tentacle") { } + + struct npc_constrictor_tentacleAI : public ScriptedAI + { + npc_constrictor_tentacleAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + } + + void Reset() + { + DoCast(me, SPELL_TENTACLE_VOID_ZONE_2); + DoCastAOE(SPELL_ERUPT); + } + + void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) + { + if (!apply) + passenger->RemoveAurasDueToSpell(SPELL_SQUEEZE); + } + + void UpdateAI(uint32 /*diff*/) + { + UpdateVictim(); + } + + void IsSummonedBy(Unit* /*summoner*/) + { + if (Creature* voice = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->JustSummoned(me); + } + + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_constrictor_tentacleAI>(creature); + } +}; + +class npc_crusher_tentacle : public CreatureScript +{ + public: + npc_crusher_tentacle() : CreatureScript("npc_crusher_tentacle") { } + + struct npc_crusher_tentacleAI : public ScriptedAI + { + npc_crusher_tentacleAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } + + void Reset() + { + DoCast(me, SPELL_CRUSH); + DoCast(me, SPELL_TENTACLE_VOID_ZONE); + DoCast(me, SPELL_DIMINSH_POWER); + DoCast(me, SPELL_FOCUSED_ANGER); + DoCastAOE(SPELL_ERUPT); + + _events.ScheduleEvent(EVENT_DIMINISH_POWER, urand(6000, 8000)); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + if (me->HasAura(SPELL_SHATTERED_ILLUSION) || me->HasUnitState(UNIT_STATE_CASTING)) + return; + + // update timers when the Diminish Power is not being channeled so the next one + // is not cast immediately after interrupt + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DIMINISH_POWER: + DoCast(SPELL_DIMINISH_POWER); + _events.ScheduleEvent(EVENT_DIMINISH_POWER, urand(20000, 30000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_crusher_tentacleAI>(creature); + } +}; + +class npc_influence_tentacle : public CreatureScript +{ + public: + npc_influence_tentacle() : CreatureScript("npc_influence_tentacle") { } + + struct npc_influence_tentacleAI : public PassiveAI + { + npc_influence_tentacleAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() + { + DoCast(me, me->GetEntry() == NPC_SUIT_OF_ARMOR ? SPELL_NONDESCRIPT_1 : SPELL_NONDESCRIPT_2); + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* brain = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_BRAIN_OF_YOGG_SARON))) + brain->AI()->DoAction(ACTION_TENTACLE_KILLED); + } + + void UpdateAI(uint32 /*diff*/) { } + + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_influence_tentacleAI>(creature); + } +}; + +typedef boss_sara::boss_saraAI SaraAI; + +class npc_descend_into_madness : public CreatureScript +{ + public: + npc_descend_into_madness() : CreatureScript("npc_descend_into_madness") { } + + struct npc_descend_into_madnessAI : public PassiveAI + { + npc_descend_into_madnessAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { } + + void OnSpellClick(Unit* clicker) + { + clicker->RemoveAurasDueToSpell(SPELL_BRAIN_LINK); + me->DespawnOrUnsummon(); + } + + void UpdateAI(uint32 /*diff*/) { } + + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_descend_into_madnessAI>(creature); + } +}; + +class npc_immortal_guardian : public CreatureScript +{ + public: + npc_immortal_guardian() : CreatureScript("npc_immortal_guardian") { } + + struct npc_immortal_guardianAI : public ScriptedAI + { + npc_immortal_guardianAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() + { + DoCast(me, SPELL_EMPOWERED); + DoCast(me, SPELL_RECENTLY_SPAWNED); + _events.ScheduleEvent(EVENT_DRAIN_LIFE, urand(3000, 13000)); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (me->HealthBelowPctDamaged(1, damage)) + damage = me->GetHealth() - me->CountPctFromMaxHealth(1); // or set immune to damage? should be done here or in SPELL_WEAKENED spell script? + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DRAIN_LIFE: + DoCast(SPELL_DRAIN_LIFE); + _events.ScheduleEvent(EVENT_DRAIN_LIFE, urand(20000, 30000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_immortal_guardianAI>(creature); + } +}; + +class npc_observation_ring_keeper : public CreatureScript +{ + public: + npc_observation_ring_keeper() : CreatureScript("npc_observation_ring_keeper") { } + + struct npc_observation_ring_keeperAI : public ScriptedAI + { + npc_observation_ring_keeperAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() + { + DoCast(SPELL_SIMPLE_TELEPORT_KEEPERS); // not visible here + DoCast(SPELL_KEEPER_ACTIVE); + } + + void sGossipSelect(Player* player, uint32 sender, uint32 /*action*/) + { + if (sender != 10333) + return; + + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->DespawnOrUnsummon(2000); + DoCast(SPELL_TELEPORT); + Talk(SAY_KEEPER_CHOSEN_1, player->GetGUID()); + Talk(SAY_KEEPER_CHOSEN_2, player->GetGUID()); + + switch (me->GetEntry()) + { + case NPC_FREYA_OBSERVATION_RING: + me->SummonCreature(NPC_FREYA_YS, YSKeepersPos[0]); + break; + case NPC_HODIR_OBSERVATION_RING: + me->SummonCreature(NPC_HODIR_YS, YSKeepersPos[1]); + break; + case NPC_THORIM_OBSERVATION_RING: + me->SummonCreature(NPC_THORIM_YS, YSKeepersPos[2]); + break; + case NPC_MIMIRON_OBSERVATION_RING: + me->SummonCreature(NPC_MIMIRON_YS, YSKeepersPos[3]); + break; + } + } + + void UpdateAI(uint32 /*diff*/) { } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_observation_ring_keeperAI>(creature); + } +}; + +class npc_yogg_saron_keeper : public CreatureScript +{ + public: + npc_yogg_saron_keeper() : CreatureScript("npc_yogg_saron_keeper") { } + + struct npc_yogg_saron_keeperAI : public ScriptedAI + { + npc_yogg_saron_keeperAI(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(Unit* /*summoner*/) + { + DoCast(SPELL_SIMPLE_TELEPORT_KEEPERS); + } + + void Reset() + { + _events.Reset(); + _events.SetPhase(PHASE_ONE); + me->SetReactState(REACT_PASSIVE); + me->RemoveAllAuras(); + + DoCast(SPELL_KEEPER_ACTIVE); // can we skip removing this aura somehow? + + if (me->GetEntry() == NPC_FREYA_YS) + { + std::list<Creature*> wells; + GetCreatureListWithEntryInGrid(wells, me, NPC_SANITY_WELL, 200.0f); + for (std::list<Creature*>::const_iterator itr = wells.begin(); itr != wells.end(); ++itr) + { + (*itr)->RemoveAurasDueToSpell(SPELL_SANITY_WELL); + (*itr)->RemoveAurasDueToSpell(SPELL_SANITY_WELL_VISUAL); + } + } + } + + void EnterCombat(Unit* /*who*/) + { + switch (me->GetEntry()) + { + case NPC_FREYA_YS: + DoCast(SPELL_RESILIENCE_OF_NATURE); + DoCast(SPELL_SANITY_WELL_SUMMON); + break; + case NPC_HODIR_YS: + DoCast(SPELL_FORTITUDE_OF_FROST); + DoCast(SPELL_HODIRS_PROTECTIVE_GAZE); + break; + case NPC_THORIM_YS: + DoCast(SPELL_FURY_OF_THE_STORM); + break; + case NPC_MIMIRON_YS: + DoCast(SPELL_SPEED_OF_INVENTION); + break; + } + } + + void UpdateAI(uint32 diff) + { + if (!me->isInCombat()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DESTABILIZATION_MATRIX: + me->CastCustomSpell(SPELL_DESTABILIZATION_MATRIX, SPELLVALUE_MAX_TARGETS, 1); + _events.ScheduleEvent(EVENT_DESTABILIZATION_MATRIX, urand(15000, 25000), 0, PHASE_TWO); + break; + case EVENT_HODIRS_PROTECTIVE_GAZE: + DoCast(SPELL_HODIRS_PROTECTIVE_GAZE); + break; + } + } + } + + void DoAction(int32 action) + { + switch (action) + { + // setting the phases is only for Thorim and Mimiron + case ACTION_PHASE_TWO: + _events.SetPhase(PHASE_TWO); + _events.ScheduleEvent(EVENT_DESTABILIZATION_MATRIX, urand(5000, 15000), 0, PHASE_TWO); + break; + case ACTION_PHASE_THREE: + _events.SetPhase(PHASE_THREE); + if (me->GetEntry() == NPC_THORIM_YS) + DoCast(SPELL_TITANIC_STORM); + break; + case ACTION_SANITY_WELLS: + { + std::list<Creature*> wells; + GetCreatureListWithEntryInGrid(wells, me, NPC_SANITY_WELL, 200.0f); + for (std::list<Creature*>::const_iterator itr = wells.begin(); itr != wells.end(); ++itr) + { + (*itr)->CastSpell(*itr, SPELL_SANITY_WELL); + (*itr)->CastSpell(*itr, SPELL_SANITY_WELL_VISUAL); + } + break; + } + case ACTION_FLASH_FREEZE: + DoCast(SPELL_FLASH_FREEZE_VISUAL); + _events.ScheduleEvent(EVENT_HODIRS_PROTECTIVE_GAZE, urand(25000, 30000)); + break; + } + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_yogg_saron_keeperAI>(creature); + } +}; + +class npc_yogg_saron_illusions : public CreatureScript +{ + public: + npc_yogg_saron_illusions() : CreatureScript("npc_yogg_saron_illusions") { } + + struct npc_yogg_saron_illusionsAI : public ScriptedAI + { + npc_yogg_saron_illusionsAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void IsSummonedBy(Unit* /*summoner*/) + { + switch (_instance->GetData(DATA_ILLUSION)) + { + case CHAMBER_ILLUSION: + // i think the first Talk should be delayed as in this moment + // players are too far away to be able to see it + if (Creature* neltharion = me->FindNearestCreature(NPC_NELTHARION, 50.0f)) + neltharion->AI()->Talk(SAY_CHAMBER_ROLEPLAY_1); + + _events.ScheduleEvent(EVENT_CHAMBER_ROLEPLAY_1, 16000); + _events.ScheduleEvent(EVENT_CHAMBER_ROLEPLAY_2, 22000); + _events.ScheduleEvent(EVENT_CHAMBER_ROLEPLAY_3, 28000); + _events.ScheduleEvent(EVENT_CHAMBER_ROLEPLAY_4, 36000); + break; + case ICECROWN_ILLUSION: + // same here + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_1, 1000); + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_2, 7500); + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_3, 19500); + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_4, 25500); + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_5, 33000); + _events.ScheduleEvent(EVENT_ICECROWN_ROLEPLAY_6, 41300); + break; + case STORMWIND_ILLUSION: + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_4, 33800); // "A thousand deaths..." + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_5, 38850); + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_7, 58750); + // TODO: use "or one murder." sound and split the text in DB + break; + } + } + + void UpdateAI(uint32 diff) + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHAMBER_ROLEPLAY_1: + if (Creature* ysera = me->FindNearestCreature(NPC_YSERA, 50.0f)) + ysera->AI()->Talk(SAY_CHAMBER_ROLEPLAY_2); + break; + case EVENT_CHAMBER_ROLEPLAY_2: + if (Creature* neltharion = me->FindNearestCreature(NPC_NELTHARION, 50.0f)) + neltharion->AI()->Talk(SAY_CHAMBER_ROLEPLAY_3); + break; + case EVENT_CHAMBER_ROLEPLAY_3: + if (Creature* malygos = me->FindNearestCreature(NPC_MALYGOS, 50.0f)) + malygos->AI()->Talk(SAY_CHAMBER_ROLEPLAY_4); + break; + case EVENT_CHAMBER_ROLEPLAY_4: + Talk(SAY_CHAMBER_ROLEPLAY_5); + break; + case EVENT_ICECROWN_ROLEPLAY_1: + if (Creature* bolvar = me->FindNearestCreature(NPC_IMMOLATED_CHAMPION, 50.0f)) + { + bolvar->AI()->Talk(SAY_ICECROWN_ROLEPLAY_1); + + if (Creature* lichKing = me->FindNearestCreature(NPC_THE_LICH_KING, 50.0f)) + lichKing->CastSpell(bolvar, SPELL_DEATHGRASP); + } + break; + case EVENT_ICECROWN_ROLEPLAY_2: + if (Creature* lichKing = me->FindNearestCreature(NPC_THE_LICH_KING, 50.0f)) + lichKing->AI()->Talk(SAY_ICECROWN_ROLEPLAY_2); + break; + case EVENT_ICECROWN_ROLEPLAY_3: + if (Creature* bolvar = me->FindNearestCreature(NPC_IMMOLATED_CHAMPION, 50.0f)) + bolvar->AI()->Talk(SAY_ICECROWN_ROLEPLAY_3); + if (Creature* saurfang = me->FindNearestCreature(NPC_TURNED_CHAMPION, 50.0f)) + saurfang->AI()->DoAction(ACTION_START_ROLEPLAY); + break; + case EVENT_ICECROWN_ROLEPLAY_4: + if (Creature* lichKing = me->FindNearestCreature(NPC_THE_LICH_KING, 50.0f)) + lichKing->AI()->Talk(SAY_ICECROWN_ROLEPLAY_4); + break; + case EVENT_ICECROWN_ROLEPLAY_5: + Talk(SAY_ICECROWN_ROLEPLAY_5); + break; + case EVENT_ICECROWN_ROLEPLAY_6: + Talk(SAY_ICECROWN_ROLEPLAY_6); + break; + case EVENT_STORMWIND_ROLEPLAY_4: + Talk(SAY_STORMWIND_ROLEPLAY_4); + break; + case EVENT_STORMWIND_ROLEPLAY_5: + if (Creature* llane = me->FindNearestCreature(NPC_KING_LLANE, 50.0f)) + llane->AI()->Talk(SAY_STORMWIND_ROLEPLAY_5); + break; + case EVENT_STORMWIND_ROLEPLAY_7: + Talk(SAY_STORMWIND_ROLEPLAY_7); + break; + default: + break; + } + } + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_yogg_saron_illusionsAI>(creature); + } +}; + +class npc_garona : public CreatureScript +{ + public: + npc_garona() : CreatureScript("npc_garona") { } + + struct npc_garonaAI : public ScriptedAI + { + npc_garonaAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() + { + _events.Reset(); + + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(0, IllusionsMiscPos[0]); + + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_1, 9250); + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_2, 16700); + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_3, 24150); + _events.ScheduleEvent(EVENT_STORMWIND_ROLEPLAY_6, 52700); + } + + void UpdateAI(uint32 diff) + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STORMWIND_ROLEPLAY_1: + Talk(SAY_STORMWIND_ROLEPLAY_1); + break; + case EVENT_STORMWIND_ROLEPLAY_2: + Talk(SAY_STORMWIND_ROLEPLAY_2); + break; + case EVENT_STORMWIND_ROLEPLAY_3: + Talk(SAY_STORMWIND_ROLEPLAY_3); + break; + case EVENT_STORMWIND_ROLEPLAY_6: + Talk(SAY_STORMWIND_ROLEPLAY_6); + if (Creature* llane = me->FindNearestCreature(NPC_KING_LLANE, 50.0f)) + { + DoCast(SPELL_ASSASSINATE); + llane->CastSpell(llane, SPELL_PERMANENT_FEIGN_DEATH); + } + break; + default: + break; + } + } + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_garonaAI>(creature); + } +}; + +class npc_turned_champion : public CreatureScript +{ + public: + npc_turned_champion() : CreatureScript("npc_turned_champion") { } + + struct npc_turned_championAI : public ScriptedAI + { + npc_turned_championAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() + { + DoCast(SPELL_VERTEX_COLOR_BLACK); + } + + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE || pointId != 0) + return; + + me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + } + + void DoAction(int32 action) + { + if (action != ACTION_START_ROLEPLAY) + return; + + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(0, IllusionsMiscPos[1]); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_turned_championAI>(creature); + } +}; + +class npc_laughing_skull : public CreatureScript +{ + public: + npc_laughing_skull() : CreatureScript("npc_laughing_skull") { } + + struct npc_laughing_skullAI : public ScriptedAI + { + npc_laughing_skullAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() + { + me->SetReactState(REACT_PASSIVE); + DoCast(me, SPELL_LUNATIC_GAZE_SKULL); + } + + // don't evade, otherwise the Lunatic Gaze aura is removed + void UpdateAI(uint32 /*diff*/) { } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetUlduarAI<npc_laughing_skullAI>(creature); + } +}; + +class spell_yogg_saron_target_selectors : public SpellScriptLoader // 63744, 63745, 63747, 65206 +{ + public: + spell_yogg_saron_target_selectors() : SpellScriptLoader("spell_yogg_saron_target_selectors") { } + + class spell_yogg_saron_target_selectors_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_target_selectors_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + GetCaster()->CastSpell(target, uint32(GetEffectValue())); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_target_selectors_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_target_selectors_SpellScript(); + } +}; + +class SanityReduction : public SpellScript +{ + public: + SanityReduction() : SpellScript() { } + SanityReduction(uint8 stacks) : SpellScript(), _stacks(stacks) { } + + void RemoveSanity(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (Aura* sanity = target->GetAura(SPELL_SANITY)) + sanity->ModStackAmount(-int32(_stacks), AURA_REMOVE_BY_ENEMY_SPELL); + } + + protected: + uint8 _stacks; +}; + +class HighSanityTargetSelector +{ + public: + HighSanityTargetSelector() { } + + bool operator()(WorldObject* object) + { + if (Unit* unit = object->ToUnit()) + if (Aura* sanity = unit->GetAura(SPELL_SANITY)) + return sanity->GetStackAmount() <= 40; + return true; + } +}; + +class spell_yogg_saron_psychosis : public SpellScriptLoader // 63795, 65301 +{ + public: + spell_yogg_saron_psychosis() : SpellScriptLoader("spell_yogg_saron_psychosis") { } + + class spell_yogg_saron_psychosis_SpellScript : public SanityReduction + { + PrepareSpellScript(spell_yogg_saron_psychosis_SpellScript); + + bool Load() + { + _stacks = GetSpellInfo()->Id == SPELL_PSYCHOSIS ? 9 : 12; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(HighSanityTargetSelector()); + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_ILLUSION_ROOM)); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_psychosis_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_psychosis_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_psychosis_SpellScript::RemoveSanity, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_psychosis_SpellScript(); + } +}; + +class spell_yogg_saron_malady_of_the_mind : public SpellScriptLoader // 63830, 63881 +{ + public: + spell_yogg_saron_malady_of_the_mind() : SpellScriptLoader("spell_yogg_saron_malady_of_the_mind") { } + + class spell_yogg_saron_malady_of_the_mind_SpellScript : public SanityReduction + { + public: + spell_yogg_saron_malady_of_the_mind_SpellScript() : SanityReduction(3) { } + + PrepareSpellScript(spell_yogg_saron_malady_of_the_mind_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(HighSanityTargetSelector()); + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_ILLUSION_ROOM)); + } + + void Register() + { + if (m_scriptSpellId == SPELL_MALADY_OF_THE_MIND) + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_malady_of_the_mind_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_malady_of_the_mind_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_malady_of_the_mind_SpellScript::FilterTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); + } + + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_malady_of_the_mind_SpellScript::RemoveSanity, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + class spell_yogg_saron_malady_of_the_mind_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_malady_of_the_mind_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_MALADY_OF_THE_MIND_JUMP)) + return false; + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + switch (GetTargetApplication()->GetRemoveMode()) + { + case AURA_REMOVE_BY_ENEMY_SPELL: + case AURA_REMOVE_BY_EXPIRE: + case AURA_REMOVE_BY_DEATH: + break; + default: + return; + } + + GetTarget()->CastSpell(GetTarget(), SPELL_MALADY_OF_THE_MIND_JUMP); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_malady_of_the_mind_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_MOD_FEAR, AURA_EFFECT_HANDLE_REAL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_malady_of_the_mind_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_malady_of_the_mind_AuraScript(); + } +}; + +class spell_yogg_saron_brain_link : public SpellScriptLoader // 63802 +{ + public: + spell_yogg_saron_brain_link() : SpellScriptLoader("spell_yogg_saron_brain_link") { } + + class spell_yogg_saron_brain_link_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_brain_link_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_ILLUSION_ROOM)); + + if (targets.size() != 2) + { + targets.clear(); + return; + } + + if (SaraAI* ai = CAST_AI(SaraAI, GetCaster()->GetAI())) + ai->SetLinkBetween(targets.front()->GetGUID(), targets.back()->GetGUID()); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_brain_link_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + class spell_yogg_saron_brain_link_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_brain_link_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_BRAIN_LINK_DAMAGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_BRAIN_LINK_NO_DAMAGE)) + return false; + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + if (SaraAI* ai = CAST_AI(SaraAI, caster->GetAI())) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + ai->RemoveLinkFrom(GetTarget()->GetGUID()); + else + { + if (Player* player = ObjectAccessor::GetPlayer(*GetTarget(), ai->GetLinkedPlayerGUID(GetTarget()->GetGUID()))) + { + ai->RemoveLinkFrom(GetTarget()->GetGUID()); + player->RemoveAurasDueToSpell(SPELL_BRAIN_LINK); + } + } + } + } + + void DummyTick(AuraEffect const* aurEff) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + SaraAI* ai = CAST_AI(SaraAI, caster->GetAI()); + if (!ai) + return; + + Player* linked = ObjectAccessor::GetPlayer(*GetTarget(), ai->GetLinkedPlayerGUID(GetTarget()->GetGUID())); + if (!linked) + return; + + GetTarget()->CastSpell(linked, (GetTarget()->GetDistance(linked) > (float)aurEff->GetAmount()) ? SPELL_BRAIN_LINK_DAMAGE : SPELL_BRAIN_LINK_NO_DAMAGE, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_brain_link_AuraScript::DummyTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_brain_link_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_brain_link_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_brain_link_AuraScript(); + } +}; + +class spell_yogg_saron_brain_link_damage : public SpellScriptLoader // 63803 +{ + public: + spell_yogg_saron_brain_link_damage() : SpellScriptLoader("spell_yogg_saron_brain_link_damage") { } + + class spell_yogg_saron_brain_link_damage_SpellScript : public SanityReduction + { + public: + spell_yogg_saron_brain_link_damage_SpellScript() : SanityReduction(2) { } + + PrepareSpellScript(spell_yogg_saron_brain_link_damage_SpellScript); + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_brain_link_damage_SpellScript::RemoveSanity, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_brain_link_damage_SpellScript(); + } +}; + +class spell_yogg_saron_boil_ominously : public SpellScriptLoader // 63030 +{ + public: + spell_yogg_saron_boil_ominously() : SpellScriptLoader("spell_yogg_saron_boil_ominously") { } + + class spell_yogg_saron_boil_ominously_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_boil_ominously_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_GUARDIAN_1)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (!target->HasAura(SPELL_FLASH_FREEZE) && !GetCaster()->HasAura(SPELL_SUMMON_GUARDIAN_1) && !GetCaster()->HasAura(SPELL_SUMMON_GUARDIAN_2)) + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->Talk(EMOTE_OMINOUS_CLOUD_PLAYER_TOUCH, target->GetGUID()); + + GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_GUARDIAN_1, true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_boil_ominously_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_boil_ominously_SpellScript(); + } +}; + +class spell_yogg_saron_shadow_beacon : public SpellScriptLoader // 64465 +{ + public: + spell_yogg_saron_shadow_beacon() : SpellScriptLoader("spell_yogg_saron_shadow_beacon") { } + + class spell_yogg_saron_shadow_beacon_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_shadow_beacon_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->SetEntry(NPC_MARKED_IMMORTAL_GUARDIAN); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->SetEntry(NPC_IMMORTAL_GUARDIAN); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_shadow_beacon_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_shadow_beacon_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_shadow_beacon_AuraScript(); + } +}; + +class spell_yogg_saron_empowering_shadows_range_check : public SpellScriptLoader // 64466 +{ + public: + spell_yogg_saron_empowering_shadows_range_check() : SpellScriptLoader("spell_yogg_saron_empowering_shadows_range_check") { } + + class spell_yogg_saron_empowering_shadows_range_check_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_empowering_shadows_range_check_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell(GetCaster(), uint32(GetEffectValue()), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_empowering_shadows_range_check_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_empowering_shadows_range_check_SpellScript(); + } +}; + +class spell_yogg_saron_empowering_shadows_missile : public SpellScriptLoader // 64467 +{ + public: + spell_yogg_saron_empowering_shadows_missile() : SpellScriptLoader("spell_yogg_saron_empowering_shadows_missile") { } + + class spell_yogg_saron_empowering_shadows_missile_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_empowering_shadows_missile_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_EMPOWERING_SHADOWS)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell((Unit*)NULL, SPELL_EMPOWERING_SHADOWS, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_empowering_shadows_missile_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_empowering_shadows_missile_SpellScript(); + } +}; + +// it works, but is it scripted correctly? why is it aura with 2500ms duration? +class spell_yogg_saron_constrictor_tentacle : public SpellScriptLoader // 64132 +{ + public: + spell_yogg_saron_constrictor_tentacle() : SpellScriptLoader("spell_yogg_saron_constrictor_tentacle") { } + + class spell_yogg_saron_constrictor_tentacle_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_constrictor_tentacle_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_CONSTRICTOR_TENTACLE_SUMMON)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->CastSpell(GetTarget(), SPELL_CONSTRICTOR_TENTACLE_SUMMON); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_constrictor_tentacle_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_constrictor_tentacle_AuraScript(); + } +}; + +class spell_yogg_saron_lunge : public SpellScriptLoader // 64131 +{ + public: + spell_yogg_saron_lunge() : SpellScriptLoader("spell_yogg_saron_lunge") { } + + class spell_yogg_saron_lunge_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_lunge_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SQUEEZE)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_SQUEEZE, true); + target->CastSpell(GetCaster(), uint32(GetEffectValue()), true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_lunge_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_lunge_SpellScript(); + } +}; + +class spell_yogg_saron_squeeze : public SpellScriptLoader // 64125 +{ + public: + spell_yogg_saron_squeeze() : SpellScriptLoader("spell_yogg_saron_squeeze") { } + + class spell_yogg_saron_squeeze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_squeeze_AuraScript); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* vehicle = GetTarget()->GetVehicleBase()) + if (vehicle->isAlive()) + vehicle->Kill(vehicle); // should tentacle die or just release its target? + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_squeeze_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_squeeze_AuraScript(); + } +}; + +class spell_yogg_saron_diminsh_power : public SpellScriptLoader // 64148 +{ + public: + spell_yogg_saron_diminsh_power() : SpellScriptLoader("spell_yogg_saron_diminsh_power") { } + + class spell_yogg_saron_diminsh_power_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_diminsh_power_AuraScript); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + if (Spell* spell = GetTarget()->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (spell->getState() == SPELL_STATE_CASTING) + GetTarget()->InterruptSpell(CURRENT_CHANNELED_SPELL); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_yogg_saron_diminsh_power_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_diminsh_power_AuraScript(); + } +}; + +// not sure about SPELL_WEAKENED part, where should it be handled? +class spell_yogg_saron_empowered : public SpellScriptLoader // 64161 +{ + public: + spell_yogg_saron_empowered() : SpellScriptLoader("spell_yogg_saron_empowered") { } + + class spell_yogg_saron_empowered_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_empowered_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_EMPOWERED_BUFF)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_WEAKENED)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->CastCustomSpell(SPELL_EMPOWERED_BUFF, SPELLVALUE_AURA_STACK, 9, GetTarget(), TRIGGERED_FULL_MASK); + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + float stack = ceil((target->GetHealthPct() / 10) - 1); + target->RemoveAurasDueToSpell(SPELL_EMPOWERED_BUFF); + + if (stack) + { + target->RemoveAurasDueToSpell(SPELL_WEAKENED); + target->CastCustomSpell(SPELL_EMPOWERED_BUFF, SPELLVALUE_AURA_STACK, stack, target, TRIGGERED_FULL_MASK); + } + else if (!target->HealthAbovePct(1) && !target->HasAura(SPELL_WEAKENED)) + target->CastSpell(target, SPELL_WEAKENED, true); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_empowered_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_empowered_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_empowered_AuraScript(); + } +}; + +class spell_yogg_saron_match_health : public SpellScriptLoader // 64069 +{ + public: + spell_yogg_saron_match_health() : SpellScriptLoader("spell_yogg_saron_match_health") { } + + class spell_yogg_saron_match_health_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_match_health_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->SetHealth(target->CountPctFromMaxHealth((int32)GetCaster()->GetHealthPct())); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_match_health_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_match_health_SpellScript(); + } +}; + +class spell_yogg_saron_shattered_illusion : public SpellScriptLoader // 65238 +{ + public: + spell_yogg_saron_shattered_illusion() : SpellScriptLoader("spell_yogg_saron_shattered_illusion") { } + + class spell_yogg_saron_shattered_illusion_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_shattered_illusion_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->RemoveAurasDueToSpell(uint32(GetEffectValue())); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_shattered_illusion_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_shattered_illusion_SpellScript(); + } +}; + +class spell_yogg_saron_death_ray_warning_visual : public SpellScriptLoader // 63882 +{ + public: + spell_yogg_saron_death_ray_warning_visual() : SpellScriptLoader("spell_yogg_saron_death_ray_warning_visual") { } + + class spell_yogg_saron_death_ray_warning_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_death_ray_warning_visual_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DEATH_RAY_PERIODIC)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_DEATH_RAY_DAMAGE_VISUAL)) + return false; + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + { + caster->CastSpell(caster, SPELL_DEATH_RAY_PERIODIC, true); + caster->CastSpell((Unit*)NULL, SPELL_DEATH_RAY_DAMAGE_VISUAL, true); + // TODO: set better movement + caster->GetMotionMaster()->MoveConfused(); + } + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_death_ray_warning_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_death_ray_warning_visual_AuraScript(); + } +}; + +class spell_yogg_saron_cancel_illusion_room_aura : public SpellScriptLoader // 63993 +{ + public: + spell_yogg_saron_cancel_illusion_room_aura() : SpellScriptLoader("spell_yogg_saron_cancel_illusion_room_aura") { } + + class spell_yogg_saron_cancel_illusion_room_aura_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_cancel_illusion_room_aura_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_TELEPORT_BACK_TO_MAIN_ROOM)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_TELEPORT_BACK_TO_MAIN_ROOM); + target->RemoveAurasDueToSpell(uint32(GetEffectValue())); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_cancel_illusion_room_aura_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_cancel_illusion_room_aura_SpellScript(); + } +}; + +class spell_yogg_saron_nondescript : public SpellScriptLoader // 64010, 64013 +{ + public: + spell_yogg_saron_nondescript() : SpellScriptLoader("spell_yogg_saron_nondescript") { } + + class spell_yogg_saron_nondescript_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_nondescript_AuraScript); + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + GetTarget()->CastSpell(GetTarget(), uint32(aurEff->GetAmount()), true); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_nondescript_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_nondescript_AuraScript(); + } +}; + +class spell_yogg_saron_revealed_tentacle : public SpellScriptLoader // 64012 +{ + public: + spell_yogg_saron_revealed_tentacle() : SpellScriptLoader("spell_yogg_saron_revealed_tentacle") { } + + class spell_yogg_saron_revealed_tentacle_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_revealed_tentacle_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_TENTACLE_VOID_ZONE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_GRIM_REPRISAL)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Creature* caster = GetCaster()->ToCreature()) + { + caster->CastSpell(caster, SPELL_TENTACLE_VOID_ZONE, true); + caster->CastSpell(caster, SPELL_GRIM_REPRISAL, true); + caster->UpdateEntry(NPC_INFLUENCE_TENTACLE, 0, caster->GetCreatureData()); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_revealed_tentacle_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_revealed_tentacle_SpellScript(); + } +}; + +class spell_yogg_saron_grim_reprisal : public SpellScriptLoader // 63305 +{ + public: + spell_yogg_saron_grim_reprisal() : SpellScriptLoader("spell_yogg_saron_grim_reprisal") { } + + class spell_yogg_saron_grim_reprisal_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_grim_reprisal_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_GRIM_REPRISAL_DAMAGE)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + int32 damage = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), 60); + GetTarget()->CastCustomSpell(SPELL_GRIM_REPRISAL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetDamageInfo()->GetAttacker(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_yogg_saron_grim_reprisal_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_grim_reprisal_AuraScript(); + } +}; + +class spell_yogg_saron_induce_madness : public SpellScriptLoader // 64059 +{ + public: + spell_yogg_saron_induce_madness() : SpellScriptLoader("spell_yogg_saron_induce_madness") { } + + class spell_yogg_saron_induce_madness_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_induce_madness_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_TELEPORT_BACK_TO_MAIN_ROOM)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHATTERED_ILLUSION_REMOVE)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_TELEPORT_BACK_TO_MAIN_ROOM); + target->RemoveAurasDueToSpell(SPELL_SANITY, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL); + target->RemoveAurasDueToSpell(uint32(GetEffectValue())); + } + } + + void ClearShatteredIllusion() + { + GetCaster()->CastSpell((Unit*)NULL, SPELL_SHATTERED_ILLUSION_REMOVE); + + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* voice = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_VOICE_OF_YOGG_SARON))) + voice->AI()->DoAction(ACTION_TOGGLE_SHATTERED_ILLUSION); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_induce_madness_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + AfterCast += SpellCastFn(spell_yogg_saron_induce_madness_SpellScript::ClearShatteredIllusion); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_induce_madness_SpellScript(); + } +}; + +class spell_yogg_saron_sanity : public SpellScriptLoader // 63050 +{ + public: + spell_yogg_saron_sanity() : SpellScriptLoader("spell_yogg_saron_sanity") { } + + class spell_yogg_saron_sanity_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_sanity_SpellScript); + + // don't target players outside of room or handle it in SPELL_INSANE_PERIODIC? + + void ModSanityStacks() + { + GetSpell()->SetSpellValue(SPELLVALUE_AURA_STACK, 100); + } + + void Register() + { + BeforeCast += SpellCastFn(spell_yogg_saron_sanity_SpellScript::ModSanityStacks); + } + }; + + class spell_yogg_saron_sanity_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_sanity_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_LOW_SANITY_SCREEN_EFFECT)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_INSANE)) + return false; + return true; + } + + void DummyTick(AuraEffect const* /*aurEff*/) + { + if (GetTarget()->HasAura(SPELL_SANITY_WELL)) + ModStackAmount(20); + + if (GetStackAmount() <= 40 && !GetTarget()->HasAura(SPELL_LOW_SANITY_SCREEN_EFFECT)) + GetTarget()->CastSpell(GetTarget(), SPELL_LOW_SANITY_SCREEN_EFFECT, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) + return; + + if (InstanceScript* instance = GetTarget()->GetInstanceScript()) + instance->SetData(DATA_DRIVE_ME_CRAZY, uint32(false)); + + GetTarget()->RemoveAurasDueToSpell(SPELL_BRAIN_LINK); + + if (Unit* caster = GetCaster()) + caster->CastSpell(GetTarget(), SPELL_INSANE, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_sanity_AuraScript::DummyTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_sanity_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_sanity_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_sanity_AuraScript(); + } +}; + +class spell_yogg_saron_insane : public SpellScriptLoader // 63120 +{ + public: + spell_yogg_saron_insane() : SpellScriptLoader("spell_yogg_saron_insane") { } + + class spell_yogg_saron_insane_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_insane_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_INSANE_VISUAL)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (Creature* yogg = caster->ToCreature()) + yogg->AI()->Talk(WHISPER_VOICE_INSANE, GetTarget()->GetGUID()); + + GetTarget()->CastSpell(GetTarget(), SPELL_INSANE_VISUAL, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->isAlive()) + GetTarget()->Kill(GetTarget()); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_insane_AuraScript::OnApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_insane_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_insane_AuraScript(); + } +}; + +class spell_yogg_saron_insane_periodic : public SpellScriptLoader // 64555 +{ + public: + spell_yogg_saron_insane_periodic() : SpellScriptLoader("spell_yogg_saron_insane_periodic") { } + + class spell_yogg_saron_insane_periodic_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_insane_periodic_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + GetCaster()->CastSpell(target, uint32(GetEffectValue()), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_insane_periodic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_insane_periodic_SpellScript(); + } +}; + +class LunaticGazeTargetSelector +{ + public: + LunaticGazeTargetSelector(Unit* caster) : _caster(caster) { } + + bool operator()(WorldObject* object) + { + return !object->HasInArc(static_cast<float>(M_PI), _caster); + } + + private: + Unit* _caster; +}; + +class spell_yogg_saron_lunatic_gaze : public SpellScriptLoader // 64164, 64168 +{ + public: + spell_yogg_saron_lunatic_gaze() : SpellScriptLoader("spell_yogg_saron_lunatic_gaze") { } + + class spell_yogg_saron_lunatic_gaze_SpellScript : public SanityReduction + { + PrepareSpellScript(spell_yogg_saron_lunatic_gaze_SpellScript); + + bool Load() + { + _stacks = GetSpellInfo()->Id == SPELL_LUNATIC_GAZE_DAMAGE ? 4 : 2; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(LunaticGazeTargetSelector(GetCaster())); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_lunatic_gaze_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_lunatic_gaze_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_lunatic_gaze_SpellScript::RemoveSanity, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_lunatic_gaze_SpellScript(); + } +}; + +class spell_yogg_saron_keeper_aura : public SpellScriptLoader // 62650, 62670, 62671, 62702 +{ + public: + spell_yogg_saron_keeper_aura() : SpellScriptLoader("spell_yogg_saron_keeper_aura") { } + + class spell_yogg_saron_keeper_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_keeper_aura_AuraScript); + + bool CanApply(Unit* target) + { + if (target->GetTypeId() != TYPEID_PLAYER && target != GetCaster()) + return false; + return true; + } + + void Register() + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_yogg_saron_keeper_aura_AuraScript::CanApply); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_keeper_aura_AuraScript(); + } +}; + +class spell_yogg_saron_hate_to_zero : public SpellScriptLoader // 63984 +{ + public: + spell_yogg_saron_hate_to_zero() : SpellScriptLoader("spell_yogg_saron_hate_to_zero") { } + + class spell_yogg_saron_hate_to_zero_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_hate_to_zero_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (target->CanHaveThreatList()) + target->getThreatManager().modifyThreatPercent(GetCaster(), -100); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_hate_to_zero_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_hate_to_zero_SpellScript(); + } +}; + +class spell_yogg_saron_in_the_maws_of_the_old_god : public SpellScriptLoader // 64184 +{ + public: + spell_yogg_saron_in_the_maws_of_the_old_god() : SpellScriptLoader("spell_yogg_saron_in_the_maws_of_the_old_god") { } + + class spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript); + + SpellCastResult CheckRequirement() + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* yogg = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(BOSS_YOGG_SARON))) + if (yogg->FindCurrentSpellBySpellId(SPELL_DEAFENING_ROAR)) + { + if (GetCaster()->GetDistance(yogg) > 20.0f) + return SPELL_FAILED_OUT_OF_RANGE; + else + return SPELL_CAST_OK; + } + + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + } + + void Register() + { + OnCheckCast += SpellCheckCastFn(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript(); + } +}; + +class spell_yogg_saron_titanic_storm : public SpellScriptLoader // 64172 +{ + public: + spell_yogg_saron_titanic_storm() : SpellScriptLoader("spell_yogg_saron_titanic_storm") { } + + class spell_yogg_saron_titanic_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_titanic_storm_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + GetCaster()->Kill(target); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_titanic_storm_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_yogg_saron_titanic_storm_SpellScript(); + } +}; + +class spell_yogg_saron_hodirs_protective_gaze : public SpellScriptLoader // 64174 +{ + public: + spell_yogg_saron_hodirs_protective_gaze() : SpellScriptLoader("spell_yogg_saron_hodirs_protective_gaze") { } + + class spell_yogg_saron_hodirs_protective_gaze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_hodirs_protective_gaze_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_FLASH_FREEZE)) + return false; + return true; + } + + bool CanApply(Unit* target) + { + if (target->GetTypeId() != TYPEID_PLAYER && target != GetCaster()) + return false; + return true; + } + + void OnAbsorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount) + { + if (dmgInfo.GetDamage() >= GetTarget()->GetHealth()) + { + absorbAmount = dmgInfo.GetDamage(); + // or absorbAmount = dmgInfo.GetDamage() - GetTarget()->GetHealth() + 1 + GetTarget()->CastSpell(GetTarget(), SPELL_FLASH_FREEZE, true); + } + else + PreventDefaultAction(); + } + + void Register() + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_yogg_saron_hodirs_protective_gaze_AuraScript::CanApply); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_yogg_saron_hodirs_protective_gaze_AuraScript::OnAbsorb, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_yogg_saron_hodirs_protective_gaze_AuraScript(); + } +}; + +void AddSC_boss_yogg_saron() +{ + new boss_voice_of_yogg_saron(); + new boss_sara(); + new boss_yogg_saron(); + new boss_brain_of_yogg_saron(); + new npc_ominous_cloud(); + new npc_guardian_of_yogg_saron(); + new npc_corruptor_tentacle(); + new npc_constrictor_tentacle(); + new npc_crusher_tentacle(); + new npc_influence_tentacle(); + new npc_descend_into_madness(); + new npc_immortal_guardian(); + new npc_observation_ring_keeper(); + new npc_yogg_saron_keeper(); + new npc_yogg_saron_illusions(); + new npc_garona(); + new npc_turned_champion(); + new npc_laughing_skull(); + new spell_yogg_saron_target_selectors(); + new spell_yogg_saron_psychosis(); + new spell_yogg_saron_malady_of_the_mind(); + new spell_yogg_saron_brain_link(); + new spell_yogg_saron_brain_link_damage(); + new spell_yogg_saron_boil_ominously(); + new spell_yogg_saron_shadow_beacon(); + new spell_yogg_saron_empowering_shadows_range_check(); + new spell_yogg_saron_empowering_shadows_missile(); + new spell_yogg_saron_constrictor_tentacle(); + new spell_yogg_saron_lunge(); + new spell_yogg_saron_squeeze(); + new spell_yogg_saron_diminsh_power(); + new spell_yogg_saron_empowered(); + new spell_yogg_saron_match_health(); + new spell_yogg_saron_shattered_illusion(); + new spell_yogg_saron_death_ray_warning_visual(); + new spell_yogg_saron_cancel_illusion_room_aura(); + new spell_yogg_saron_nondescript(); + new spell_yogg_saron_revealed_tentacle(); + new spell_yogg_saron_grim_reprisal(); + new spell_yogg_saron_induce_madness(); + new spell_yogg_saron_sanity(); + new spell_yogg_saron_insane(); + new spell_yogg_saron_insane_periodic(); + new spell_yogg_saron_lunatic_gaze(); + new spell_yogg_saron_keeper_aura(); + new spell_yogg_saron_hate_to_zero(); + new spell_yogg_saron_in_the_maws_of_the_old_god(); + new spell_yogg_saron_titanic_storm(); + new spell_yogg_saron_hodirs_protective_gaze(); +} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp deleted file mode 100644 index 4bcb1b9e584..00000000000 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptMgr.h" -#include "ulduar.h" - -enum Sara -{ - // text - YELL_SARA_PREFIGHT = 0, - YELL_COMBAT_PHASE_1 = 1, - YELL_COMBAT_PHASE_2 = 2, - YELL_SLAY = 3, - - // Phase 1 spells - SPELL_SARAS_ANGER_1 = 63147, // Target Entry 33136 - SPELL_SARAS_ANGER_2 = 63744, // Target Entry 33136 - SPELL_SARAS_FEVOR_1 = 63138, // Target Player - SPELL_SARAS_FEVOR_2 = 63747, // Target Player - SPELL_SARAS_BLESSING_1 = 63134, // Target Player - SPELL_SARAS_BLESSING_2 = 63745, // Target Self - - // Phase 2 spells - SPELL_PHYCHOSIS = 63795, // Target Self - SPELL_MALADY_OF_THE_MIND = 63830, // Target Self - SPELL_DEATH_RAY = 63891, // Target Self - SPELL_BRAIN_LINK = 63802, // Target Self -}; - -enum YoggSaron_Yells -{ -}; - -enum -{ - ACHIEV_TIMED_START_EVENT = 21001, -}; -//not in scriptloader yet just to remove warning boss_yoggsaron.obj : warning LNK4221: no public symbols found; archive member will be inaccessible -void AddSC_boss_yoggsaron() -{ -} diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 125f66497bf..421d0ecf3c9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -24,14 +24,15 @@ static DoorData const doorData[] = { - {GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, - {GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, - {GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_W }, - {GO_DOODAD_UL_UNIVERSEFLOOR_01, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_NONE }, - {GO_DOODAD_UL_UNIVERSEFLOOR_02, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, - {GO_DOODAD_UL_UNIVERSEGLOBE01, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, - {GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, - {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + {GO_LEVIATHAN_DOOR, BOSS_LEVIATHAN, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_XT_002_DOOR, BOSS_XT002, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_YOGG_SARON_DOOR, BOSS_YOGG_SARON, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_W }, + {GO_DOODAD_UL_UNIVERSEFLOOR_01, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + {GO_DOODAD_UL_UNIVERSEFLOOR_02, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {GO_DOODAD_UL_UNIVERSEGLOBE01, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, BOSS_ALGALON, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_NONE }, + {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }, }; MinionData const minionData[] = @@ -56,7 +57,6 @@ class instance_ulduar : public InstanceMapScript uint64 IgnisGUID; uint64 RazorscaleGUID; uint64 RazorscaleController; - uint64 RazorHarpoonGUIDs[4]; uint64 ExpeditionCommanderGUID; uint64 XT002GUID; uint64 XTToyPileGUIDs[4]; @@ -67,14 +67,18 @@ class instance_ulduar : public InstanceMapScript uint64 HodirGUID; uint64 ThorimGUID; uint64 FreyaGUID; - uint64 KeeperGUIDs[3]; + uint64 ElderGUIDs[3]; uint64 VezaxGUID; uint64 YoggSaronGUID; + uint64 VoiceOfYoggSaronGUID; + uint64 SaraGUID; + uint64 BrainOfYoggSaronGUID; uint64 AlgalonGUID; - uint64 LeviathanGateGUID; - uint64 VezaxDoorGUID; + uint64 BrannBronzebeardAlgGUID; // GameObjects + uint64 LeviathanGateGUID; + uint64 RazorHarpoonGUIDs[4]; uint64 KologarnChestGUID; uint64 KologarnBridgeGUID; uint64 KologarnDoorGUID; @@ -84,11 +88,13 @@ class instance_ulduar : public InstanceMapScript uint64 HodirDoorGUID; uint64 HodirIceDoorGUID; uint64 ArchivumDoorGUID; + uint64 VezaxDoorGUID; + uint64 BrainRoomDoorGUIDs[3]; + uint64 KeeperGUIDs[4]; uint64 AlgalonSigilDoorGUID[3]; uint64 AlgalonFloorGUID[2]; uint64 AlgalonUniverseGUID; uint64 AlgalonTrapdoorGUID; - uint64 BrannBronzebeardAlgGUID; uint64 GiftOfTheObserverGUID; // Miscellaneous @@ -96,8 +102,11 @@ class instance_ulduar : public InstanceMapScript uint32 HodirRareCacheData; uint32 ColossusData; uint8 elderCount; + uint8 illusion; + uint8 keepersCount; bool conSpeedAtory; bool Unbroken; + bool IsDriveMeCrazyEligible; std::set<uint64> mRubbleSpawns; @@ -119,6 +128,9 @@ class instance_ulduar : public InstanceMapScript FreyaGUID = 0; VezaxGUID = 0; YoggSaronGUID = 0; + VoiceOfYoggSaronGUID = 0; + SaraGUID = 0; + BrainOfYoggSaronGUID = 0; AlgalonGUID = 0; KologarnChestGUID = 0; KologarnBridgeGUID = 0; @@ -141,6 +153,8 @@ class instance_ulduar : public InstanceMapScript HodirRareCacheData = 0; ColossusData = 0; elderCount = 0; + illusion = 0; + keepersCount = 0; conSpeedAtory = false; Unbroken = true; _algalonSummoned = false; @@ -151,7 +165,11 @@ class instance_ulduar : public InstanceMapScript memset(XTToyPileGUIDs, 0, sizeof(XTToyPileGUIDs)); memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs)); memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs)); + memset(ElderGUIDs, 0, sizeof(ElderGUIDs)); + memset(BrainRoomDoorGUIDs, 0, sizeof(BrainRoomDoorGUIDs)); memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs)); + memset(_summonObservationRingKeeper, false, sizeof(_summonObservationRingKeeper)); + memset(_summonYSKeeper, false, sizeof(_summonYSKeeper)); } void FillInitialWorldStates(WorldPacket& packet) @@ -174,6 +192,38 @@ class instance_ulduar : public InstanceMapScript else algalon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } + + // Keepers at Observation Ring + if (GetBossState(BOSS_FREYA) == DONE && _summonObservationRingKeeper[0] && !KeeperGUIDs[0]) + { + _summonObservationRingKeeper[0] = false; + instance->SummonCreature(NPC_FREYA_OBSERVATION_RING, ObservationRingKeepersPos[0]); + } + if (GetBossState(BOSS_HODIR) == DONE && _summonObservationRingKeeper[1] && !KeeperGUIDs[1]) + { + _summonObservationRingKeeper[1] = false; + instance->SummonCreature(NPC_HODIR_OBSERVATION_RING, ObservationRingKeepersPos[1]); + } + if (GetBossState(BOSS_THORIM) == DONE && _summonObservationRingKeeper[2] && !KeeperGUIDs[2]) + { + _summonObservationRingKeeper[2] = false; + instance->SummonCreature(NPC_THORIM_OBSERVATION_RING, ObservationRingKeepersPos[2]); + } + if (GetBossState(BOSS_MIMIRON) == DONE && _summonObservationRingKeeper[3] && !KeeperGUIDs[3]) + { + _summonObservationRingKeeper[3] = false; + instance->SummonCreature(NPC_MIMIRON_OBSERVATION_RING, ObservationRingKeepersPos[3]); + } + + // Keepers in Yogg-Saron's room + if (_summonYSKeeper[0]) + instance->SummonCreature(NPC_FREYA_YS, YSKeepersPos[0]); + if (_summonYSKeeper[1]) + instance->SummonCreature(NPC_HODIR_YS, YSKeepersPos[1]); + if (_summonYSKeeper[2]) + instance->SummonCreature(NPC_THORIM_YS, YSKeepersPos[2]); + if (_summonYSKeeper[3]) + instance->SummonCreature(NPC_MIMIRON_YS, YSKeepersPos[3]); } void OnCreatureCreate(Creature* creature) @@ -194,6 +244,8 @@ class instance_ulduar : public InstanceMapScript case NPC_IGNIS: IgnisGUID = creature->GetGUID(); break; + + // Razorscale case NPC_RAZORSCALE: RazorscaleGUID = creature->GetGUID(); break; @@ -203,6 +255,8 @@ class instance_ulduar : public InstanceMapScript case NPC_EXPEDITION_COMMANDER: ExpeditionCommanderGUID = creature->GetGUID(); break; + + // XT-002 Deconstructor case NPC_XT002: XT002GUID = creature->GetGUID(); break; @@ -229,24 +283,6 @@ class instance_ulduar : public InstanceMapScript AddMinion(creature, true); break; - // Freya's Keeper - case NPC_IRONBRANCH: - KeeperGUIDs[0] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - case NPC_BRIGHTLEAF: - KeeperGUIDs[1] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - case NPC_STONEBARK: - KeeperGUIDs[2] = creature->GetGUID(); - if (GetBossState(BOSS_FREYA) == DONE) - creature->DespawnOrUnsummon(); - break; - - // Kologarn case NPC_KOLOGARN: KologarnGUID = creature->GetGUID(); break; @@ -256,25 +292,11 @@ class instance_ulduar : public InstanceMapScript case NPC_MIMIRON: MimironGUID = creature->GetGUID(); break; + + // Hodir case NPC_HODIR: HodirGUID = creature->GetGUID(); break; - case NPC_THORIM: - ThorimGUID = creature->GetGUID(); - break; - case NPC_FREYA: - FreyaGUID = creature->GetGUID(); - break; - case NPC_VEZAX: - VezaxGUID = creature->GetGUID(); - break; - case NPC_YOGGSARON: - YoggSaronGUID = creature->GetGUID(); - break; - case NPC_ALGALON: - AlgalonGUID = creature->GetGUID(); - break; - // Hodir's Helper NPCs case NPC_EIVI_NIGHTFEATHER: if (TeamInInstance == HORDE) creature->UpdateEntry(NPC_TOR_GREYCLOUD, HORDE); @@ -307,6 +329,80 @@ class instance_ulduar : public InstanceMapScript if (TeamInInstance == HORDE) creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA, HORDE); break; + + case NPC_THORIM: + ThorimGUID = creature->GetGUID(); + break; + + // Freya + case NPC_FREYA: + FreyaGUID = creature->GetGUID(); + break; + case NPC_IRONBRANCH: + ElderGUIDs[0] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + case NPC_BRIGHTLEAF: + ElderGUIDs[1] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + case NPC_STONEBARK: + ElderGUIDs[2] = creature->GetGUID(); + if (GetBossState(BOSS_FREYA) == DONE) + creature->DespawnOrUnsummon(); + break; + + case NPC_VEZAX: + VezaxGUID = creature->GetGUID(); + break; + + // Yogg-Saron + case NPC_YOGG_SARON: + YoggSaronGUID = creature->GetGUID(); + break; + case NPC_VOICE_OF_YOGG_SARON: + VoiceOfYoggSaronGUID = creature->GetGUID(); + break; + case NPC_BRAIN_OF_YOGG_SARON: + BrainOfYoggSaronGUID = creature->GetGUID(); + break; + case NPC_SARA: + SaraGUID = creature->GetGUID(); + break; + case NPC_FREYA_YS: + KeeperGUIDs[0] = creature->GetGUID(); + _summonYSKeeper[0] = false; + SaveToDB(); + ++keepersCount; + break; + case NPC_HODIR_YS: + KeeperGUIDs[1] = creature->GetGUID(); + _summonYSKeeper[1] = false; + SaveToDB(); + ++keepersCount; + break; + case NPC_THORIM_YS: + KeeperGUIDs[2] = creature->GetGUID(); + _summonYSKeeper[2] = false; + SaveToDB(); + ++keepersCount; + break; + case NPC_MIMIRON_YS: + KeeperGUIDs[3] = creature->GetGUID(); + _summonYSKeeper[3] = false; + SaveToDB(); + ++keepersCount; + break; + case NPC_SANITY_WELL: + creature->SetReactState(REACT_PASSIVE); + break; + + // Algalon + case NPC_ALGALON: + AlgalonGUID = creature->GetGUID(); + break; case NPC_BRANN_BRONZBEARD_ALG: BrannBronzebeardAlgGUID = creature->GetGUID(); break; @@ -418,6 +514,18 @@ class instance_ulduar : public InstanceMapScript if (GetBossState(BOSS_ASSEMBLY_OF_IRON) != DONE) HandleGameObject(ArchivumDoorGUID, false); break; + case GO_YOGG_SARON_DOOR: + AddDoor(gameObject, true); + break; + case GO_BRAIN_ROOM_DOOR_1: + BrainRoomDoorGUIDs[0] = gameObject->GetGUID(); + break; + case GO_BRAIN_ROOM_DOOR_2: + BrainRoomDoorGUIDs[1] = gameObject->GetGUID(); + break; + case GO_BRAIN_ROOM_DOOR_3: + BrainRoomDoorGUIDs[2] = gameObject->GetGUID(); + break; case GO_CELESTIAL_PLANETARIUM_ACCESS_10: case GO_CELESTIAL_PLANETARIUM_ACCESS_25: if (_algalonSummoned) @@ -509,27 +617,36 @@ class instance_ulduar : public InstanceMapScript { // Flame Leviathan's Tower Event triggers Creature* FlameLeviathan = instance->GetCreature(LeviathanGUID); - if (FlameLeviathan && FlameLeviathan->isAlive()) // No leviathan, no event triggering ;) + + switch (eventId) { - switch (eventId) - { - case EVENT_TOWER_OF_STORM_DESTROYED: + case EVENT_TOWER_OF_STORM_DESTROYED: + if (FlameLeviathan && FlameLeviathan->isAlive()) FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_STORM_DESTROYED); - break; - case EVENT_TOWER_OF_FROST_DESTROYED: + break; + case EVENT_TOWER_OF_FROST_DESTROYED: + if (FlameLeviathan && FlameLeviathan->isAlive()) FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FROST_DESTROYED); - break; - case EVENT_TOWER_OF_FLAMES_DESTROYED: + break; + case EVENT_TOWER_OF_FLAMES_DESTROYED: + if (FlameLeviathan && FlameLeviathan->isAlive()) FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_FLAMES_DESTROYED); - break; - case EVENT_TOWER_OF_LIFE_DESTROYED: + break; + case EVENT_TOWER_OF_LIFE_DESTROYED: + if (FlameLeviathan && FlameLeviathan->isAlive()) FlameLeviathan->AI()->DoAction(ACTION_TOWER_OF_LIFE_DESTROYED); - break; - } + break; + case EVENT_ACTIVATE_SANITY_WELL: + if (Creature* freya = instance->GetCreature(KeeperGUIDs[0])) + freya->AI()->DoAction(4/*ACTION_SANITY_WELLS*/); + break; + case EVENT_HODIRS_PROTECTIVE_GAZE_PROC: + if (Creature* hodir = instance->GetCreature(KeeperGUIDs[1])) + hodir->AI()->DoAction(5/*ACTION_FLASH_FREEZE*/); + break; } } - bool SetBossState(uint32 type, EncounterState state) { if (!InstanceScript::SetBossState(type, state)) @@ -542,8 +659,14 @@ class instance_ulduar : public InstanceMapScript case BOSS_RAZORSCALE: case BOSS_XT002: case BOSS_AURIAYA: + break; case BOSS_MIMIRON: + if (state == DONE) + instance->SummonCreature(NPC_MIMIRON_OBSERVATION_RING, ObservationRingKeepersPos[3]); + break; case BOSS_FREYA: + if (state == DONE) + instance->SummonCreature(NPC_FREYA_OBSERVATION_RING, ObservationRingKeepersPos[0]); break; case BOSS_ASSEMBLY_OF_IRON: if (state == DONE) @@ -553,7 +676,7 @@ class instance_ulduar : public InstanceMapScript if (state == DONE) HandleGameObject(VezaxDoorGUID, true); break; - case BOSS_YOGGSARON: + case BOSS_YOGG_SARON: break; case BOSS_KOLOGARN: if (state == DONE) @@ -576,12 +699,18 @@ class instance_ulduar : public InstanceMapScript HodirChest->SetRespawnTime(HodirChest->GetRespawnDelay()); HandleGameObject(HodirDoorGUID, true); HandleGameObject(HodirIceDoorGUID, true); + + instance->SummonCreature(NPC_HODIR_OBSERVATION_RING, ObservationRingKeepersPos[1]); } break; case BOSS_THORIM: if (state == DONE) + { if (GameObject* gameObject = instance->GetGameObject(ThorimChestGUID)) gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + + instance->SummonCreature(NPC_THORIM_OBSERVATION_RING, ObservationRingKeepersPos[2]); + } break; case BOSS_ALGALON: if (state == DONE) @@ -661,6 +790,12 @@ class instance_ulduar : public InstanceMapScript case DATA_UNBROKEN: Unbroken = bool(data); break; + case DATA_ILLUSION: + illusion = data; + break; + case DATA_DRIVE_ME_CRAZY: + IsDriveMeCrazyEligible = data ? true : false; + break; case EVENT_DESPAWN_ALGALON: DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 1); DoUpdateWorldState(WORLD_STATE_ALGALON_DESPAWN_TIMER, 60); @@ -688,10 +823,24 @@ class instance_ulduar : public InstanceMapScript return LeviathanGUID; case BOSS_IGNIS: return IgnisGUID; + + // Razorscale case BOSS_RAZORSCALE: return RazorscaleGUID; case DATA_RAZORSCALE_CONTROL: return RazorscaleController; + case DATA_EXPEDITION_COMMANDER: + return ExpeditionCommanderGUID; + case GO_RAZOR_HARPOON_1: + return RazorHarpoonGUIDs[0]; + case GO_RAZOR_HARPOON_2: + return RazorHarpoonGUIDs[1]; + case GO_RAZOR_HARPOON_3: + return RazorHarpoonGUIDs[2]; + case GO_RAZOR_HARPOON_4: + return RazorHarpoonGUIDs[3]; + + // XT-002 Deconstructor case BOSS_XT002: return XT002GUID; case DATA_TOY_PILE_0: @@ -699,6 +848,15 @@ class instance_ulduar : public InstanceMapScript case DATA_TOY_PILE_2: case DATA_TOY_PILE_3: return XTToyPileGUIDs[data - DATA_TOY_PILE_0]; + + // Assembly of Iron + case DATA_STEELBREAKER: + return AssemblyGUIDs[0]; + case DATA_MOLGEIM: + return AssemblyGUIDs[1]; + case DATA_BRUNDIR: + return AssemblyGUIDs[2]; + case BOSS_KOLOGARN: return KologarnGUID; case BOSS_AURIAYA: @@ -709,42 +867,47 @@ class instance_ulduar : public InstanceMapScript return HodirGUID; case BOSS_THORIM: return ThorimGUID; + + // Freya case BOSS_FREYA: return FreyaGUID; + case BOSS_BRIGHTLEAF: + return ElderGUIDs[0]; + case BOSS_IRONBRANCH: + return ElderGUIDs[1]; + case BOSS_STONEBARK: + return ElderGUIDs[2]; + case BOSS_VEZAX: return VezaxGUID; - case BOSS_YOGGSARON: - return YoggSaronGUID; - case BOSS_ALGALON: - return AlgalonGUID; - // Razorscale expedition commander - case DATA_EXPEDITION_COMMANDER: - return ExpeditionCommanderGUID; - case GO_RAZOR_HARPOON_1: - return RazorHarpoonGUIDs[0]; - case GO_RAZOR_HARPOON_2: - return RazorHarpoonGUIDs[1]; - case GO_RAZOR_HARPOON_3: - return RazorHarpoonGUIDs[2]; - case GO_RAZOR_HARPOON_4: - return RazorHarpoonGUIDs[3]; - - // Assembly of Iron - case DATA_STEELBREAKER: - return AssemblyGUIDs[0]; - case DATA_MOLGEIM: - return AssemblyGUIDs[1]; - case DATA_BRUNDIR: - return AssemblyGUIDs[2]; - - // Freya's Keepers - case BOSS_BRIGHTLEAF: + // Yogg-Saron + case BOSS_YOGG_SARON: + return YoggSaronGUID; + case DATA_VOICE_OF_YOGG_SARON: + return VoiceOfYoggSaronGUID; + case DATA_BRAIN_OF_YOGG_SARON: + return BrainOfYoggSaronGUID; + case DATA_SARA: + return SaraGUID; + case GO_BRAIN_ROOM_DOOR_1: + return BrainRoomDoorGUIDs[0]; + case GO_BRAIN_ROOM_DOOR_2: + return BrainRoomDoorGUIDs[1]; + case GO_BRAIN_ROOM_DOOR_3: + return BrainRoomDoorGUIDs[2]; + case DATA_FREYA_YS: return KeeperGUIDs[0]; - case BOSS_IRONBRANCH: + case DATA_HODIR_YS: return KeeperGUIDs[1]; - case BOSS_STONEBARK: + case DATA_THORIM_YS: return KeeperGUIDs[2]; + case DATA_MIMIRON_YS: + return KeeperGUIDs[3]; + + // Algalon + case BOSS_ALGALON: + return AlgalonGUID; case DATA_SIGILDOOR_01: return AlgalonSigilDoorGUID[0]; case DATA_SIGILDOOR_02: @@ -776,6 +939,10 @@ class instance_ulduar : public InstanceMapScript return HodirRareCacheData; case DATA_UNBROKEN: return uint32(Unbroken); + case DATA_ILLUSION: + return illusion; + case DATA_KEEPERS_COUNT: + return keepersCount; default: break; } @@ -789,6 +956,30 @@ class instance_ulduar : public InstanceMapScript { case CRITERIA_HERALD_OF_TITANS: return _maxArmorItemLevel <= MAX_HERALD_ARMOR_ITEMLEVEL && _maxWeaponItemLevel <= MAX_HERALD_WEAPON_ITEMLEVEL; + case CRITERIA_WAITS_DREAMING_STORMWIND_25: + case CRITERIA_WAITS_DREAMING_STORMWIND_10: + return illusion == STORMWIND_ILLUSION; + case CRITERIA_WAITS_DREAMING_CHAMBER_25: + case CRITERIA_WAITS_DREAMING_CHAMBER_10: + return illusion == CHAMBER_ILLUSION; + case CRITERIA_WAITS_DREAMING_ICECROWN_25: + case CRITERIA_WAITS_DREAMING_ICECROWN_10: + return illusion == ICECROWN_ILLUSION; + case CRITERIA_DRIVE_ME_CRAZY_10: + case CRITERIA_DRIVE_ME_CRAZY_25: + return IsDriveMeCrazyEligible; + case CRITERIA_THREE_LIGHTS_IN_THE_DARKNESS_10: + case CRITERIA_THREE_LIGHTS_IN_THE_DARKNESS_25: + return keepersCount <= 3; + case CRITERIA_TWO_LIGHTS_IN_THE_DARKNESS_10: + case CRITERIA_TWO_LIGHTS_IN_THE_DARKNESS_25: + return keepersCount <= 2; + case CRITERIA_ONE_LIGHT_IN_THE_DARKNESS_10: + case CRITERIA_ONE_LIGHT_IN_THE_DARKNESS_25: + return keepersCount <= 1; + case CRITERIA_ALONE_IN_THE_DARKNESS_10: + case CRITERIA_ALONE_IN_THE_DARKNESS_25: + return keepersCount == 0; } return false; @@ -801,6 +992,9 @@ class instance_ulduar : public InstanceMapScript std::ostringstream saveStream; saveStream << "U U " << GetBossSaveData() << GetData(DATA_COLOSSUS) << ' ' << _algalonTimer << ' ' << (_algalonSummoned ? 1 : 0); + for (uint8 i = 0; i < 4; ++i) + saveStream << ' ' << (KeeperGUIDs[i] ? 1 : 0); + OUT_SAVE_INST_DATA_COMPLETE; return saveStream.str(); } @@ -851,6 +1045,21 @@ class instance_ulduar : public InstanceMapScript DoUpdateWorldState(WORLD_STATE_ALGALON_DESPAWN_TIMER, _algalonTimer); } } + + for (uint8 i = 0; i < 4; ++i) + { + loadStream >> tempState; + _summonYSKeeper[i] = tempState != 0; + } + + if (GetBossState(BOSS_FREYA) == DONE && !_summonYSKeeper[0]) + _summonObservationRingKeeper[0] = true; + if (GetBossState(BOSS_HODIR) == DONE && !_summonYSKeeper[1]) + _summonObservationRingKeeper[1] = true; + if (GetBossState(BOSS_THORIM) == DONE && !_summonYSKeeper[2]) + _summonObservationRingKeeper[2] = true; + if (GetBossState(BOSS_MIMIRON) == DONE && !_summonYSKeeper[3]) + _summonObservationRingKeeper[3] = true; } OUT_LOAD_INST_DATA_COMPLETE; @@ -889,6 +1098,8 @@ class instance_ulduar : public InstanceMapScript uint32 _algalonTimer; bool _summonAlgalon; bool _algalonSummoned; + bool _summonObservationRingKeeper[4]; + bool _summonYSKeeper[4]; uint32 _maxArmorItemLevel; uint32 _maxWeaponItemLevel; }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 08fd95d0e26..612be3b71e8 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -21,6 +21,8 @@ #include "ObjectMgr.h" #define UlduarScriptName "instance_ulduar" +extern Position const ObservationRingKeepersPos[4]; +extern Position const YSKeepersPos[4]; extern Position const AlgalonLandPos; enum UlduarBosses @@ -42,7 +44,7 @@ enum UlduarBosses BOSS_IRONBRANCH = 12, BOSS_STONEBARK = 13, BOSS_VEZAX = 14, - BOSS_YOGGSARON = 15, + BOSS_YOGG_SARON = 15, BOSS_ALGALON = 16, }; @@ -74,7 +76,7 @@ enum UlduarNPCs NPC_THORIM = 32865, NPC_FREYA = 32906, NPC_VEZAX = 33271, - NPC_YOGGSARON = 33288, + NPC_YOGG_SARON = 33288, NPC_ALGALON = 32871, // Mimiron @@ -115,6 +117,39 @@ enum UlduarNPCs NPC_NATURES_BLADE = 33527, NPC_GUARDIAN_OF_LIFE = 33528, + // Yogg-Saron + NPC_SARA = 33134, + NPC_GUARDIAN_OF_YOGG_SARON = 33136, + NPC_HODIR_OBSERVATION_RING = 33213, + NPC_FREYA_OBSERVATION_RING = 33241, + NPC_THORIM_OBSERVATION_RING = 33242, + NPC_MIMIRON_OBSERVATION_RING = 33244, + NPC_VOICE_OF_YOGG_SARON = 33280, + NPC_OMINOUS_CLOUD = 33292, + NPC_FREYA_YS = 33410, + NPC_HODIR_YS = 33411, + NPC_MIMIRON_YS = 33412, + NPC_THORIM_YS = 33413, + NPC_SUIT_OF_ARMOR = 33433, + NPC_KING_LLANE = 33437, + NPC_THE_LICH_KING = 33441, + NPC_IMMOLATED_CHAMPION = 33442, + NPC_YSERA = 33495, + NPC_NELTHARION = 33523, + NPC_MALYGOS = 33535, + NPC_DEATH_RAY = 33881, + NPC_DEATH_ORB = 33882, + NPC_BRAIN_OF_YOGG_SARON = 33890, + NPC_INFLUENCE_TENTACLE = 33943, + NPC_TURNED_CHAMPION = 33962, + NPC_CRUSHER_TENTACLE = 33966, + NPC_CONSTRICTOR_TENTACLE = 33983, + NPC_CORRUPTOR_TENTACLE = 33985, + NPC_IMMORTAL_GUARDIAN = 33988, + NPC_SANITY_WELL = 33991, + NPC_DESCEND_INTO_MADNESS = 34072, + NPC_MARKED_IMMORTAL_GUARDIAN = 36064, + // Algalon the Observer NPC_BRANN_BRONZBEARD_ALG = 34064, NPC_AZEROTH = 34246, @@ -155,6 +190,12 @@ enum UlduarGameObjects GO_HODIR_ICE_DOOR = 194441, GO_ARCHIVUM_DOOR = 194556, + // Yogg-Saron + GO_YOGG_SARON_DOOR = 194773, + GO_BRAIN_ROOM_DOOR_1 = 194635, + GO_BRAIN_ROOM_DOOR_2 = 194636, + GO_BRAIN_ROOM_DOOR_3 = 194637, + // Algalon the Observer GO_CELESTIAL_PLANETARIUM_ACCESS_10 = 194628, GO_CELESTIAL_PLANETARIUM_ACCESS_25 = 194752, @@ -169,12 +210,18 @@ enum UlduarGameObjects GO_GIFT_OF_THE_OBSERVER_25 = 194822, }; -enum LeviathanData +enum EventIds { EVENT_TOWER_OF_STORM_DESTROYED = 21031, EVENT_TOWER_OF_FROST_DESTROYED = 21032, EVENT_TOWER_OF_FLAMES_DESTROYED = 21033, EVENT_TOWER_OF_LIFE_DESTROYED = 21030, + EVENT_ACTIVATE_SANITY_WELL = 21432, + EVENT_HODIRS_PROTECTIVE_GAZE_PROC = 21437, +}; + +enum LeviathanActions +{ ACTION_TOWER_OF_STORM_DESTROYED = 1, ACTION_TOWER_OF_FROST_DESTROYED = 2, ACTION_TOWER_OF_FLAMES_DESTROYED = 3, @@ -184,14 +231,30 @@ enum LeviathanData enum UlduarAchievementCriteriaIds { - CRITERIA_CON_SPEED_ATORY = 21597, - CRITERIA_DISARMED = 21687, - CRITERIA_HERALD_OF_TITANS = 10678, + CRITERIA_CON_SPEED_ATORY = 21597, + CRITERIA_DISARMED = 21687, + CRITERIA_WAITS_DREAMING_STORMWIND_25 = 10321, + CRITERIA_WAITS_DREAMING_CHAMBER_25 = 10322, + CRITERIA_WAITS_DREAMING_ICECROWN_25 = 10323, + CRITERIA_WAITS_DREAMING_STORMWIND_10 = 10324, + CRITERIA_WAITS_DREAMING_CHAMBER_10 = 10325, + CRITERIA_WAITS_DREAMING_ICECROWN_10 = 10326, + CRITERIA_DRIVE_ME_CRAZY_10 = 10185, + CRITERIA_DRIVE_ME_CRAZY_25 = 10296, + CRITERIA_THREE_LIGHTS_IN_THE_DARKNESS_10 = 10410, + CRITERIA_THREE_LIGHTS_IN_THE_DARKNESS_25 = 10414, + CRITERIA_TWO_LIGHTS_IN_THE_DARKNESS_10 = 10388, + CRITERIA_TWO_LIGHTS_IN_THE_DARKNESS_25 = 10415, + CRITERIA_ONE_LIGHT_IN_THE_DARKNESS_10 = 10409, + CRITERIA_ONE_LIGHT_IN_THE_DARKNESS_25 = 10416, + CRITERIA_ALONE_IN_THE_DARKNESS_10 = 10412, + CRITERIA_ALONE_IN_THE_DARKNESS_25 = 10417, + CRITERIA_HERALD_OF_TITANS = 10678, }; enum UlduarData { - // Collosus (Leviathan) + // Colossus (Leviathan) DATA_COLOSSUS = 20, // Razorscale @@ -212,6 +275,18 @@ enum UlduarData // Hodir DATA_HODIR_RARE_CACHE, + // Yogg-Saron + DATA_VOICE_OF_YOGG_SARON, + DATA_SARA, + DATA_BRAIN_OF_YOGG_SARON, + DATA_FREYA_YS, + DATA_HODIR_YS, + DATA_THORIM_YS, + DATA_MIMIRON_YS, + DATA_ILLUSION, + DATA_DRIVE_ME_CRAZY, + DATA_KEEPERS_COUNT, + // Algalon the Observer DATA_ALGALON_SUMMON_STATE, DATA_SIGILDOOR_01, @@ -245,6 +320,13 @@ enum UlduarEvents ACTION_INIT_ALGALON = 6, }; +enum YoggSaronIllusions +{ + CHAMBER_ILLUSION = 0, + ICECROWN_ILLUSION = 1, + STORMWIND_ILLUSION = 2, +}; + template<class AI> CreatureAI* GetUlduarAI(Creature* creature) { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp index 2b1d850ab25..8e726c10fca 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp @@ -23,6 +23,7 @@ SDComment: SDCategory: Script Data End */ +#include <algorithm> #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "utgarde_pinnacle.h" @@ -105,20 +106,25 @@ public: uint32 uiWaitingTimer; Phase currentPhase; uint8 AddCount; - bool DoneAdds[4]; + Phase Sequence[4]; InstanceScript* instance; void Reset() { + /// There is a good reason to store them like this, we are going to shuffle the order. + for (uint32 i = PHASE_FRENZIED_WORGEN; i < PHASE_GORTOK_PALEHOOF; ++i) + Sequence[i] = Phase(i); + + /// This ensures a random order and only executes each phase once. + std::random_shuffle(Sequence, Sequence + PHASE_GORTOK_PALEHOOF); + uiArcingSmashTimer = 15000; uiImpaleTimer = 12000; uiWhiteringRoarTimer = 10000; me->GetMotionMaster()->MoveTargetedHome(); - for (uint32 i = 0; i < 4; i++) - DoneAdds[i] = false; AddCount = 0; currentPhase = PHASE_NONE; @@ -235,26 +241,7 @@ public: if (AddCount >= DUNGEON_MODE(2, 4)) move = PHASE_GORTOK_PALEHOOF; else - { - //select random not yet defeated add - uint8 next = urand(0, 3); - for (uint8 i = 0; i < 16; i++) - { - if (!DoneAdds[i % 4]) - { - if (next == 0) - { - move = (Phase)(i % 4); - break; - } - else if (next > 0) - --next; - } - } - ++AddCount; - DoneAdds[move] = true; - move = (Phase)(move % 4); - } + move = Sequence[AddCount++]; //send orb to summon spot Creature* pOrb = Unit::GetCreature((*me), instance ? instance->GetData64(DATA_MOB_ORB) : 0); if (pOrb && pOrb->isAlive()) diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 70b500166c9..0447d70b502 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -921,7 +921,7 @@ class npc_frostbrood_skytalon : public CreatureScript if (id == POINT_GRAB_DECOY) if (TempSummon* summon = me->ToTempSummon()) if (Unit* summoner = summon->GetSummoner()) - DoCast(summoner, SPELL_GRAB); + DoCast(summoner, SPELL_GRAB); } void UpdateAI(uint32 diff) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp index 55bb61b8c42..0ffab435a9c 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp @@ -62,6 +62,8 @@ OPvPCapturePointHP::OPvPCapturePointHP(OutdoorPvP* pvp, OutdoorPvPHPTowerType ty OutdoorPvPHP::OutdoorPvPHP() { m_TypeId = OUTDOOR_PVP_HP; + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; } bool OutdoorPvPHP::SetupOutdoorPvP() diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp index bd6fd96451f..fe3489b4a7e 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp @@ -27,6 +27,7 @@ OutdoorPvPNA::OutdoorPvPNA() { m_TypeId = OUTDOOR_PVP_NA; + m_obj = NULL; } void OutdoorPvPNA::HandleKillImpl(Player* player, Unit* killed) @@ -216,8 +217,8 @@ bool OutdoorPvPNA::SetupOutdoorPvP() m_obj = new OPvPCapturePointNA(this); if (!m_obj) return false; - AddCapturePoint(m_obj); + AddCapturePoint(m_obj); return true; } diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp index bd8b6cfd982..98b0ee5c5f4 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp @@ -28,6 +28,17 @@ OutdoorPvPTF::OutdoorPvPTF() { m_TypeId = OUTDOOR_PVP_TF; + + m_IsLocked = false; + m_LockTimer = TF_LOCK_TIME; + m_LockTimerUpdate = 0; + + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + + hours_left = 6; + second_digit = 0; + first_digit = 0; } OPvPCapturePointTF::OPvPCapturePointTF(OutdoorPvP* pvp, OutdoorPvPTF_TowerType type) diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp index 2b597be8a9f..18ea83f7121 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp @@ -45,9 +45,9 @@ enum Spells enum Events { - EVENT_STREAM_OF_MACHINE_FLUID = 0, - EVENT_SAW_BLADE = 1, - EVENT_SHADOW_POWER = 2 + EVENT_STREAM_OF_MACHINE_FLUID = 1, + EVENT_SAW_BLADE = 2, + EVENT_SHADOW_POWER = 3 }; class boss_gatewatcher_gyrokill : public CreatureScript diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp index 902fb8e76b3..ce1322088e2 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp @@ -52,11 +52,11 @@ enum Spells enum Events { - EVENT_FROST_ATTACK = 0, - EVENT_ARCANE_BLAST = 1, - EVENT_DRAGONS_BREATH = 2, - EVENT_KNOCKBACK = 3, - EVENT_SOLARBURN = 4 + EVENT_FROST_ATTACK = 1, + EVENT_ARCANE_BLAST = 2, + EVENT_DRAGONS_BREATH = 3, + EVENT_KNOCKBACK = 4, + EVENT_SOLARBURN = 5 }; class boss_nethermancer_sepethrea : public CreatureScript diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp index 65cd195fb80..d179e47b942 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp @@ -54,11 +54,11 @@ enum Spells enum Events { - EVENT_SUMMON = 0, - EVENT_MANA_TAP = 1, - EVENT_ARCANE_TORRENT = 2, - EVENT_DOMINATION = 3, - EVENT_ARCANE_EXPLOSION = 4 + EVENT_SUMMON = 1, + EVENT_MANA_TAP = 2, + EVENT_ARCANE_TORRENT = 3, + EVENT_DOMINATION = 4, + EVENT_ARCANE_EXPLOSION = 5 }; enum Creatures diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index b7719ae09fa..c1edf4b05d4 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -918,7 +918,7 @@ class spell_mage_ring_of_frost : public SpellScriptLoader return true; } - void HandleEffectPeriodic(AuraEffect const* aurEff) + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) { if (ringOfFrost) if (GetMaxDuration() - (int32)ringOfFrost->GetTimer() >= sSpellMgr->GetSpellInfo(SPELL_MAGE_RING_OF_FROST_DUMMY)->GetDuration()) @@ -1018,7 +1018,7 @@ class spell_mage_ring_of_frost_freeze : public SpellScriptLoader return true; } - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) if (GetCaster()) diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index f430c93ccae..a5058cbf1d7 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1745,7 +1745,7 @@ public: { me->HandleEmoteCommand(emote); Unit* owner = me->GetOwner(); - if (emote != TEXT_EMOTE_KISS || owner || owner->GetTypeId() != TYPEID_PLAYER || + if (emote != TEXT_EMOTE_KISS || !owner || owner->GetTypeId() != TYPEID_PLAYER || owner->ToPlayer()->GetTeam() != player->GetTeam()) { return; diff --git a/src/server/shared/Cryptography/SHA1.cpp b/src/server/shared/Cryptography/SHA1.cpp index d02e9711014..00d7e520d51 100644 --- a/src/server/shared/Cryptography/SHA1.cpp +++ b/src/server/shared/Cryptography/SHA1.cpp @@ -23,6 +23,7 @@ SHA1Hash::SHA1Hash() { SHA1_Init(&mC); + memset(mDigest, 0, SHA_DIGEST_LENGTH * sizeof(uint8)); } SHA1Hash::~SHA1Hash() diff --git a/src/server/shared/Database/Field.cpp b/src/server/shared/Database/Field.cpp index 9bd37641813..51d918e716e 100644 --- a/src/server/shared/Database/Field.cpp +++ b/src/server/shared/Database/Field.cpp @@ -22,6 +22,7 @@ Field::Field() data.value = NULL; data.type = MYSQL_TYPE_NULL; data.length = 0; + data.raw = false; } Field::~Field() diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 846c8ce72fe..4307cab98f2 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -84,8 +84,10 @@ bool MySQLConnection::Open() int port; char const* unix_socket; + //unsigned int timeout = 10; mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8"); + //mysql_options(mysqlInit, MYSQL_OPT_READ_TIMEOUT, (char const*)&timeout); #ifdef _WIN32 if (m_connectionInfo.host == ".") // named pipe use option (Windows) { diff --git a/src/server/shared/Database/PreparedStatement.cpp b/src/server/shared/Database/PreparedStatement.cpp index 06f9ff51132..24097ca41c5 100644 --- a/src/server/shared/Database/PreparedStatement.cpp +++ b/src/server/shared/Database/PreparedStatement.cpp @@ -203,6 +203,7 @@ void PreparedStatement::setNull(const uint8 index) } MySQLPreparedStatement::MySQLPreparedStatement(MYSQL_STMT* stmt) : +m_stmt(NULL), m_Mstmt(stmt), m_bind(NULL) { diff --git a/src/server/shared/Debugging/Errors.cpp b/src/server/shared/Debugging/Errors.cpp index 10ede3ae402..1bfe8c8e949 100644 --- a/src/server/shared/Debugging/Errors.cpp +++ b/src/server/shared/Debugging/Errors.cpp @@ -20,33 +20,37 @@ #include <ace/Stack_Trace.h> #include <ace/OS_NS_unistd.h> +#include <cstdlib> namespace Trinity { -void Assert(char const *file, int line, char const *function, char const *message) +void Assert(char const* file, int line, char const* function, char const* message) { ACE_Stack_Trace st; fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", file, line, function, message, st.c_str()); *((volatile int*)NULL) = 0; + exit(1); } -void Fatal(char const *file, int line, char const *function, char const *message) +void Fatal(char const* file, int line, char const* function, char const* message) { fprintf(stderr, "\n%s:%i in %s FATAL ERROR:\n %s\n", file, line, function, message); ACE_OS::sleep(10); *((volatile int*)NULL) = 0; + exit(1); } -void Error(char const *file, int line, char const *function, char const *message) +void Error(char const* file, int line, char const* function, char const* message) { fprintf(stderr, "\n%s:%i in %s ERROR:\n %s\n", file, line, function, message); *((volatile int*)NULL) = 0; + exit(1); } -void Warning(char const *file, int line, char const *function, char const *message) +void Warning(char const* file, int line, char const* function, char const* message) { fprintf(stderr, "\n%s:%i in %s WARNING:\n %s\n", file, line, function, message); diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index 554b20c3648..2821ca504e7 100644 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -19,22 +19,25 @@ #ifndef TRINITYCORE_ERRORS_H #define TRINITYCORE_ERRORS_H -namespace Trinity { +#include "Define.h" -void Assert(char const *file, int line, char const *function, char const *message); +namespace Trinity +{ -void Fatal(char const *file, int line, char const *function, char const *message); + DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; -void Error(char const *file, int line, char const *function, char const *message); + DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; -void Warning(char const *file, int line, char const *function, char const *message); + DECLSPEC_NORETURN void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; + + void Warning(char const* file, int line, char const* function, char const* message); } // namespace Trinity -#define WPAssert(cond) do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond); } while(0) -#define WPFatal(cond, msg) do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) -#define WPError(cond, msg) do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) -#define WPWarning(cond, msg) do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) +#define WPAssert(cond) do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond); } while (0) +#define WPFatal(cond, msg) do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) +#define WPError(cond, msg) do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) +#define WPWarning(cond, msg) do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) #define ASSERT WPAssert diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index d7612c76738..e35e4f3ab7f 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -96,14 +96,14 @@ inline bool Log::ShouldLog(LogFilterType type, LogLevel level) const #define sLog ACE_Singleton<Log, ACE_Thread_Mutex>::instance() -#if PLATFORM != PLATFORM_WINDOWS -# define TC_LOG_MESSAGE_BODY(level__, call__, filterType__, ...) \ +#if COMPILER != COMPILER_MICROSOFT +#define TC_LOG_MESSAGE_BODY(level__, call__, filterType__, ...) \ do { \ if (sLog->ShouldLog(filterType__, level__)) \ sLog->call__(filterType__, __VA_ARGS__); \ } while (0) #else -# define TC_LOG_MESSAGE_BODY(level__, call__, filterType__, ...) \ +#define TC_LOG_MESSAGE_BODY(level__, call__, filterType__, ...) \ __pragma(warning(push)) \ __pragma(warning(disable:4127)) \ do { \ diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 0bbaff38be1..51b1a615bf1 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -37,7 +37,7 @@ class ByteBufferException : public std::exception public: ~ByteBufferException() throw() { } - char const * what() const throw() { return msg_.c_str(); } + char const* what() const throw() { return msg_.c_str(); } protected: std::string & message() throw() { return msg_; } diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h index f6bc1581857..e0215f5b3d3 100644 --- a/src/server/shared/Threading/Callback.h +++ b/src/server/shared/Threading/Callback.h @@ -35,7 +35,7 @@ template <typename Result, typename ParamType, bool chain = false> class QueryCallback { public: - QueryCallback() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) {} + QueryCallback() : _param(), _stage(chain ? 0 : CALLBACK_STAGE_INVALID) {} //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery void SetFutureResult(ACE_Future<Result> value) diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 1f9231ac0b8..e269c799f42 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -178,6 +178,7 @@ target_link_libraries(worldserver ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} ) if( WIN32 ) diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 3f6a6d56c8b..f9c672b4945 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -58,15 +58,15 @@ uint32 realmID; ///< Id of the realm /// Print out the usage string for this program on the console. void usage(const char *prog) { - TC_LOG_INFO(LOG_FILTER_WORLDSERVER, "Usage: \n %s [<options>]\n" - " -c config_file use config_file as configuration file\n\r" - #ifdef _WIN32 - " Running as service functions:\n\r" - " --service run as service\n\r" - " -s install install service\n\r" - " -s uninstall uninstall service\n\r" - #endif - , prog); + printf("Usage:\n"); + printf(" %s [<options>]\n", prog); + printf(" -c config_file use config_file as configuration file\n"); +#ifdef _WIN32 + printf(" Running as service functions:\n"); + printf(" --service run as service\n"); + printf(" -s install install service\n"); + printf(" -s uninstall uninstall service\n"); +#endif } /// Launch the Trinity server @@ -135,6 +135,7 @@ extern int main(int argc, char **argv) printf("Verify that the file exists and has \'[worldserver]' written in the top of the file!\n"); return 1; } + TC_LOG_INFO(LOG_FILTER_WORLDSERVER, "Using configuration file %s.", cfg_file); TC_LOG_INFO(LOG_FILTER_WORLDSERVER, "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); diff --git a/src/server/worldserver/TCSoap/TCSoap.h b/src/server/worldserver/TCSoap/TCSoap.h index b786ee94e81..63ccb6b304e 100644 --- a/src/server/worldserver/TCSoap/TCSoap.h +++ b/src/server/worldserver/TCSoap/TCSoap.h @@ -27,7 +27,7 @@ class TCSoapRunnable: public ACE_Based::Runnable { public: - TCSoapRunnable() { } + TCSoapRunnable() : m_host(""), m_port(0) { } void run(); void setListenArguments(std::string host, uint16 port) { diff --git a/src/tools/mmaps_generator/Info/readme.txt b/src/tools/mmaps_generator/Info/readme.txt index 8d7c4f9d2e0..ff3f2f43526 100644 --- a/src/tools/mmaps_generator/Info/readme.txt +++ b/src/tools/mmaps_generator/Info/readme.txt @@ -1,5 +1,8 @@ Generator command line args +--threads [#] Max number of threads used by the generator + Default: 3 + --offMeshInput [file.*] Path to file containing off mesh connections data. Format must be: (see offmesh_example.txt) "map_id tile_x,tile_y (start_x start_y start_z) (end_x end_y end_z) size //optional comments" @@ -63,4 +66,4 @@ movement_extractor 0 builds all tiles of map 0 movement_extractor 0 --tile 34,46 -builds only tile 34,46 of map 0 (this is the southern face of blackrock mountain)
\ No newline at end of file +builds only tile 34,46 of map 0 (this is the southern face of blackrock mountain) |