diff options
Diffstat (limited to 'src')
36 files changed, 1211 insertions, 224 deletions
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 7efd5481ae8..02686993fbb 100755 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -130,19 +130,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: if (!classRace.class_id && !classRace.race_id) { - sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", criteria->ID, criteria->requiredType, dataType); return false; } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { - sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { - sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); return false; } @@ -277,6 +277,26 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return false; } return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: + if (!classRace.class_id && !classRace.race_id) + { + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", + criteria->ID, criteria->requiredType, dataType); + return false; + } + if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) + { + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", + criteria->ID, criteria->requiredType, dataType, classRace.class_id); + return false; + } + if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) + { + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", + criteria->ID, criteria->requiredType, dataType, classRace.race_id); + return false; + } + return true; default: sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->requiredType, dataType); return false; @@ -301,6 +321,14 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un if (classRace.race_id && classRace.race_id != target->ToPlayer()->getRace()) return false; return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: + if (!source || source->GetTypeId() != TYPEID_PLAYER) + return false; + if (classRace.class_id && classRace.class_id != source->ToPlayer()->getClass()) + return false; + if (classRace.race_id && classRace.race_id != source->ToPlayer()->getRace()) + return false; + return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: if (!target || target->GetTypeId() != TYPEID_PLAYER) return false; diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 640b5de98c9..c7d838fcb44 100755 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -63,9 +63,10 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id }; -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 21 // maximum value in AchievementCriteriaDataType enum +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 22 // maximum value in AchievementCriteriaDataType enum class Player; class Unit; @@ -82,6 +83,7 @@ struct AchievementCriteriaData uint32 id; } creature; // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2 + // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21 struct { uint32 class_id; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 8ca4b73d105..6a758695116 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1245,8 +1245,6 @@ void Battleground::EventPlayerLoggedOut(Player* player) if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) EndBattleground(GetOtherTeam(player->GetTeam())); } - - player->LeaveBattleground(); } // This method should be called only once ... it adds pointer to queue diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 91ccb42f1d0..035fbaf5b78 100755 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -885,11 +885,11 @@ bool ChatHandler::ShowHelpForSubCommands(ChatCommand* table, char const* cmd, ch std::string list; for (uint32 i = 0; table[i].Name != NULL; ++i) { - // must be available (ignore handler existence for show command with possibe avalable subcomands + // must be available (ignore handler existence for show command with possible available subcommands) if (!isAvailable(table[i])) continue; - /// for empty subcmd show all available + // for empty subcmd show all available if (*subcmd && !hasStringAbbr(table[i].Name, subcmd)) continue; @@ -924,7 +924,7 @@ bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd) { for (uint32 i = 0; table[i].Name != NULL; ++i) { - // must be available (ignore handler existence for show command with possibe avalable subcomands + // must be available (ignore handler existence for show command with possible available subcommands) if (!isAvailable(table[i])) continue; @@ -954,7 +954,7 @@ bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd) { for (uint32 i = 0; table[i].Name != NULL; ++i) { - // must be available (ignore handler existence for show command with possibe avalable subcomands + // must be available (ignore handler existence for show command with possible available subcommands) if (!isAvailable(table[i])) continue; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 96890eb3095..3e06f9e73db 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1507,9 +1507,6 @@ void Creature::setDeathState(DeathState s) if (m_formation && m_formation->getLeader() == this) m_formation->FormationReset(true); - if (ZoneScript* zoneScript = GetZoneScript()) - zoneScript->OnCreatureDeath(this); - if ((canFly() || IsFlying()) && FallGround()) return; @@ -1644,7 +1641,20 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo) if (!spellInfo) return false; - if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1))) + // Spells that don't have effectMechanics. + if (!spellInfo->HasAnyEffectMechanic() && GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1))) + return true; + + // This check must be done instead of 'if (GetCreatureInfo()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))' for not break + // the check of mechanic immunity on DB (tested) because GetCreatureInfo()->MechanicImmuneMask and m_spellImmune[IMMUNITY_MECHANIC] don't have same data. + bool immunedToAllEffects = true; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (!IsImmunedToSpellEffect(spellInfo, i)) + { + immunedToAllEffects = false; + break; + } + if (immunedToAllEffects) return true; return Unit::IsImmunedToSpell(spellInfo); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 10ec8500923..09b19223039 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14529,7 +14529,7 @@ bool Player::CanSeeStartQuest(Quest const* quest) SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) && SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) && - !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this)) + SatisfyQuestSeasonal(quest, false) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this)) { return getLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= quest->GetMinLevel(); } @@ -14545,7 +14545,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg) && SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg) && SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg) && SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg) - && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) + && SatisfyQuestSeasonal(quest,msg) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestConditions(quest, msg); } @@ -14669,7 +14669,7 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg) return false; // daily quest can't be rewarded (25 daily quest already completed) - if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true)) + if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true) || !SatisfyQuestSeasonal(quest,true)) return false; // rewarded and not repeatable quest (only cheating case, then ignore without message) @@ -14978,6 +14978,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, } else if (quest->IsWeekly()) SetWeeklyQuestStatus(quest_id); + else if (quest->IsSeasonal()) + SetSeasonalQuestStatus(quest_id); RemoveActiveQuest(quest_id); m_RewardedQuests.insert(quest_id); @@ -15333,7 +15335,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) // not allow have daily quest if daily quest from exclusive group already recently completed Quest const* Nquest = sObjectMgr->GetQuestTemplate(exclude_Id); - if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false)) + if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false) || !SatisfyQuestSeasonal(Nquest,false)) { if (msg) SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); @@ -15342,7 +15344,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) } // alternative quest already started or completed - but don't check rewarded states if both are repeatable - if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && m_RewardedQuests.find(exclude_Id) != m_RewardedQuests.end())) + if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && (m_RewardedQuests.find(exclude_Id) != m_RewardedQuests.end()))) { if (msg) SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); @@ -15443,6 +15445,19 @@ bool Player::SatisfyQuestWeek(Quest const* qInfo, bool /*msg*/) return m_weeklyquests.find(qInfo->GetQuestId()) == m_weeklyquests.end(); } +bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/) +{ + if (!qInfo->IsSeasonal() || m_seasonalquests.empty()) + return true; + + uint16 eventId = sGameEventMgr->GetEventIdForQuest(qInfo); + if (m_seasonalquests.find(eventId) == m_seasonalquests.end()) + return false; + + // if not found in cooldown list + return m_seasonalquests[eventId].find(qInfo->GetQuestId()) == m_seasonalquests[eventId].end(); +} + bool Player::GiveQuestSourceItem(Quest const* quest) { uint32 srcitem = quest->GetSrcItemId(); @@ -16659,10 +16674,10 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) if (player_at_bg && currentBg->GetStatus() != STATUS_WAIT_LEAVE) { - BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(currentBg->GetTypeID(true), currentBg->GetArenaType()); + BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType()); AddBattlegroundQueueId(bgQueueTypeId); - m_bgData.bgTypeID = currentBg->GetTypeID(true); + m_bgData.bgTypeID = currentBg->GetTypeID(); //join player to battleground group currentBg->EventPlayerLoggedIn(this); @@ -16834,7 +16849,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) } // if the player is in an instance and it has been reset in the meantime teleport him to the entrance - if (instanceId && !sInstanceSaveMgr->GetInstanceSave(instanceId)) + if (instanceId && !sInstanceSaveMgr->GetInstanceSave(instanceId) && !map->IsBattlegroundOrArena()) { AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(mapId); if (at) @@ -16980,7 +16995,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) _LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS)); _LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW)); _LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS)); - _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS)); + _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS)); + _LoadSeasonalQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS)); _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADRANDOMBG)); // after spell and quest load @@ -17832,7 +17848,8 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result) { do { - uint32 quest_id = (*result)[0].GetUInt32(); + Field* fields = result->Fetch(); + uint32 quest_id = fields[0].GetUInt32(); Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id); if (!quest) continue; @@ -17846,6 +17863,30 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result) m_WeeklyQuestChanged = false; } +void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result) +{ + m_seasonalquests.clear(); + + if (result) + { + do + { + Field* fields = result->Fetch(); + uint32 quest_id = fields[0].GetUInt32(); + uint32 event_id = fields[1].GetUInt32(); + Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id); + if (!quest) + continue; + + m_seasonalquests[event_id].insert(quest_id); + sLog->outDebug(LOG_FILTER_PLAYER_LOADING, "Seasonal quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow()); + } + while (result->NextRow()); + } + + m_SeasonalQuestChanged = false; +} + void Player::_LoadSpells(PreparedQueryResult result) { //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, active, disabled FROM character_spell WHERE guid = '%u'", GetGUIDLow()); @@ -18572,6 +18613,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveQuestStatus(trans); _SaveDailyQuestStatus(trans); _SaveWeeklyQuestStatus(trans); + _SaveSeasonalQuestStatus(trans); _SaveTalents(trans); _SaveSpells(trans); _SaveSpellCooldowns(trans); @@ -18910,18 +18952,28 @@ void Player::_SaveDailyQuestStatus(SQLTransaction& trans) // save last daily quest time for all quests: we need only mostly reset time for reset check anyway // we don't need transactions here. - trans->PAppend("DELETE FROM character_queststatus_daily WHERE guid = '%u'", GetGUIDLow()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_DAILY_CHAR); + stmt->setUInt32(0, GetGUIDLow()); + trans->Append(stmt); for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) if (GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) - trans->PAppend("INSERT INTO character_queststatus_daily (guid, quest, time) VALUES ('%u', '%u', '" UI64FMTD "')", - GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx), uint64(m_lastDailyQuestTime)); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS); + stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt32(1, GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)); + stmt->setUInt64(2, uint64(m_lastDailyQuestTime)); + trans->Append(stmt); + } if (!m_DFQuests.empty()) { for (DFQuestsDoneList::iterator itr = m_DFQuests.begin(); itr != m_DFQuests.end(); ++itr) { - trans->PAppend("INSERT INTO character_queststatus_daily (guid, quest, time) VALUES ('%u', '%u', '" UI64FMTD "')", - GetGUIDLow(), (*itr), uint64(m_lastDailyQuestTime)); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS); + stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt32(1, (*itr)); + stmt->setUInt64(2, uint64(m_lastDailyQuestTime)); + trans->Append(stmt); } } } @@ -18932,18 +18984,51 @@ void Player::_SaveWeeklyQuestStatus(SQLTransaction& trans) return; // we don't need transactions here. - trans->PAppend("DELETE FROM character_queststatus_weekly WHERE guid = '%u'", GetGUIDLow()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR); + stmt->setUInt32(0, GetGUIDLow()); + trans->Append(stmt); for (QuestSet::const_iterator iter = m_weeklyquests.begin(); iter != m_weeklyquests.end(); ++iter) { uint32 quest_id = *iter; - trans->PAppend("INSERT INTO character_queststatus_weekly (guid, quest) VALUES ('%u', '%u')", GetGUIDLow(), quest_id); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS); + stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt32(1, quest_id); + trans->Append(stmt); } m_WeeklyQuestChanged = false; } +void Player::_SaveSeasonalQuestStatus(SQLTransaction& trans) +{ + if (!m_SeasonalQuestChanged || m_seasonalquests.empty()) + return; + + // we don't need transactions here. + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR); + stmt->setUInt32(0, GetGUIDLow()); + trans->Append(stmt); + + for (SeasonalEventQuestMap::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter) + { + uint16 event_id = iter->first; + for (SeasonalQuestSet::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr) + { + uint32 quest_id = (*itr); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS); + stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt32(1, quest_id); + stmt->setUInt32(2, event_id); + trans->Append(stmt); + } + } + + m_SeasonalQuestChanged = false; +} + void Player::_SaveSkills(SQLTransaction& trans) { // we don't need transactions here. @@ -22036,6 +22121,16 @@ void Player::SetWeeklyQuestStatus(uint32 quest_id) m_WeeklyQuestChanged = true; } +void Player::SetSeasonalQuestStatus(uint32 quest_id) +{ + Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id); + if (!quest) + return; + + m_seasonalquests[sGameEventMgr->GetEventIdForQuest(quest)].insert(quest_id); + m_SeasonalQuestChanged = true; +} + void Player::ResetDailyQuestStatus() { for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) @@ -22058,6 +22153,16 @@ void Player::ResetWeeklyQuestStatus() m_WeeklyQuestChanged = false; } +void Player::ResetSeasonalQuestStatus(uint16 event_id) +{ + if (m_seasonalquests.empty() || m_seasonalquests[event_id].empty()) + return; + + m_seasonalquests.erase(event_id); + // DB data deleted in caller + m_SeasonalQuestChanged = false; +} + Battleground* Player::GetBattleground() const { if (GetBattlegroundId() == 0) @@ -23201,6 +23306,9 @@ void Player::RemoveRunesByAuraEffect(AuraEffect const* aura) void Player::RestoreBaseRune(uint8 index) { AuraEffect const* aura = m_runes->runes[index].ConvertAura; + // If rune was converted by a non-pasive aura that still active we should keep it converted + if (aura && !(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_PASSIVE)) + return; ConvertRune(index, GetBaseRune(index)); SetRuneConvertAura(index, NULL); // Don't drop passive talents providing rune convertion diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7da008d597b..21c87a993dc 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -815,11 +815,12 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOADTALENTS = 23, PLAYER_LOGIN_QUERY_LOADACCOUNTDATA = 24, PLAYER_LOGIN_QUERY_LOADSKILLS = 25, - PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS = 26, + PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS = 26, PLAYER_LOGIN_QUERY_LOADRANDOMBG = 27, PLAYER_LOGIN_QUERY_LOADBANNED = 28, PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW = 29, PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES = 30, + PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS = 31, MAX_PLAYER_LOGIN_QUERY, }; @@ -1422,6 +1423,7 @@ class Player : public Unit, public GridObject<Player> bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg); bool SatisfyQuestDay(Quest const* qInfo, bool msg); bool SatisfyQuestWeek(Quest const* qInfo, bool msg); + bool SatisfyQuestSeasonal(Quest const* qInfo, bool msg); bool GiveQuestSourceItem(Quest const* quest); bool TakeQuestSourceItem(uint32 questId, bool msg); bool GetQuestRewardStatus(uint32 quest_id) const; @@ -1432,8 +1434,10 @@ class Player : public Unit, public GridObject<Player> void SetDailyQuestStatus(uint32 quest_id); void SetWeeklyQuestStatus(uint32 quest_id); + void SetSeasonalQuestStatus(uint32 quest_id); void ResetDailyQuestStatus(); void ResetWeeklyQuestStatus(); + void ResetSeasonalQuestStatus(uint16 event_id); uint16 FindQuestSlot(uint32 quest_id) const; uint32 GetQuestSlotQuestId(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET); } @@ -2558,8 +2562,11 @@ class Player : public Unit, public GridObject<Player> //We allow only one timed quest active at the same time. Below can then be simple value instead of set. typedef std::set<uint32> QuestSet; + typedef std::set<uint32> SeasonalQuestSet; + typedef UNORDERED_MAP<uint32,SeasonalQuestSet> SeasonalEventQuestMap; QuestSet m_timedquests; QuestSet m_weeklyquests; + SeasonalEventQuestMap m_seasonalquests; uint64 m_divider; uint32 m_ingametime; @@ -2580,6 +2587,7 @@ class Player : public Unit, public GridObject<Player> void _LoadQuestStatusRewarded(PreparedQueryResult result); void _LoadDailyQuestStatus(PreparedQueryResult result); void _LoadWeeklyQuestStatus(PreparedQueryResult result); + void _LoadSeasonalQuestStatus(PreparedQueryResult result); void _LoadRandomBGStatus(PreparedQueryResult result); void _LoadGroup(PreparedQueryResult result); void _LoadSkills(PreparedQueryResult result); @@ -2605,6 +2613,7 @@ class Player : public Unit, public GridObject<Player> void _SaveQuestStatus(SQLTransaction& trans); void _SaveDailyQuestStatus(SQLTransaction& trans); void _SaveWeeklyQuestStatus(SQLTransaction& trans); + void _SaveSeasonalQuestStatus(SQLTransaction& trans); void _SaveSkills(SQLTransaction& trans); void _SaveSpells(SQLTransaction& trans); void _SaveEquipmentSets(SQLTransaction& trans); @@ -2716,6 +2725,7 @@ class Player : public Unit, public GridObject<Player> bool m_DailyQuestChanged; bool m_WeeklyQuestChanged; + bool m_SeasonalQuestChanged; time_t m_lastDailyQuestTime; uint32 m_drunkTimer; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 7d470d663d2..fdc6eef8407 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1127,7 +1127,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID); if (spellProto == NULL) { - sLog->outDebug(LOG_FILTER_UNITS, "Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID); + sLog->outDebug(LOG_FILTER_UNITS, "Unit::DealSpellDamage has wrong damageInfo->SpellID: %u", damageInfo->SpellID); return; } @@ -2397,7 +2397,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell) case MELEE_HIT_BLOCK: canBlock = false; break; case MELEE_HIT_PARRY: canParry = false; break; default: - sLog->outStaticDebug("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue()); + sLog->outStaticDebug("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue()); break; } } @@ -4643,7 +4643,7 @@ void Unit::AddGameObject(GameObject* gameObj) SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId()); // Need disable spell use for owner if (createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true); } } @@ -4673,7 +4673,7 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del) SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid); // Need activate spell use for owner if (createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE) - // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases) + // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) ToPlayer()->SendCooldownEvent(createBySpell); } } @@ -4968,7 +4968,7 @@ bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (!triggerEntry) { - sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", hasteSpell->Id, triggered_spell_id); + sLog->outError("Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", hasteSpell->Id, triggered_spell_id); return false; } @@ -5026,7 +5026,7 @@ bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEf if (!triggerEntry) { - sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id); + sLog->outError("Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id); return false; } @@ -5622,7 +5622,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere case SPELLFAMILY_MAGE: { // Magic Absorption - if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura + if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura { if (getPowerType() != POWER_MANA) return false; @@ -7003,26 +7003,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere { switch (dummySpell->Id) { - // Earthen Power (Rank 1, 2) - case 51523: - case 51524: - { - // Totem itself must be a caster of this spell - Unit* caster = NULL; - for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) { - if ((*itr)->GetEntry() != 2630) - continue; - - caster = *itr; - break; - } - - if (!caster) - return false; - - caster->CastSpell(caster, 59566, true, castItem, triggeredByAura, originalCaster); - return true; - } // Tidal Force case 55198: { @@ -7069,7 +7049,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 28850; break; } - // Windfury Weapon (Passive) 1-5 Ranks + // Windfury Weapon (Passive) 1-8 Ranks case 33757: { Player* player = ToPlayer(); @@ -7084,8 +7064,10 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); - if ((attType != BASE_ATTACK && attType != OFF_ATTACK) || !isAttackReady(attType)) - return false; + if ((attType != BASE_ATTACK && attType != OFF_ATTACK) + || attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK + || attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) + return false; // Now compute real proc chance... uint32 chance = 20; @@ -7124,15 +7106,20 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere SpellInfo const* windfurySpellInfo = sSpellMgr->GetSpellInfo(spellId); if (!windfurySpellInfo) { - sLog->outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)", spellId); + sLog->outError("Unit::HandleDummyAuraProc: non-existing spell id: %u (Windfury)", spellId); return false; } int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellInfo, 1); // Value gained from additional AP - basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(BASE_ATTACK) / 1000); - triggered_spell_id = 25504; + basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(attType) / 1000); + + if (procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) + triggered_spell_id = 25504; + + if (procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) + triggered_spell_id = 33750; // apply cooldown before cast to prevent processing itself if (cooldown) @@ -7370,6 +7357,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->isAlive() || !castItem || !castItem->IsEquipped()) return false; + Player* player = ToPlayer(); + WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); + if ((attType != BASE_ATTACK && attType != OFF_ATTACK) + || attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK + || attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) + return false; + float fire_onhit = float(CalculatePctF(dummySpell->Effects[EFFECT_0]. CalcValue(), 1.0f)); float add_spellpower = (float)(SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FIRE) @@ -7379,7 +7373,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere ApplyPctF(add_spellpower, 3.84f); // Enchant on Off-Hand and ready? - if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK)) + if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) { float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f; @@ -7389,7 +7383,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } // Enchant on Main-Hand and ready? - else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK)) + else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) { float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f; @@ -7431,7 +7425,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return false; } // Lightning Overload - if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura + if (dummySpell->SpellIconID == 2018) // only this spell has SpellFamily Shaman SpellIconID == 2018 and dummy aura { if (!procSpell || GetTypeId() != TYPEID_PLAYER || !victim) return false; @@ -7483,7 +7477,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (!roll_chance_f(chance)) return false; - // Remove cooldown (Chain Lightning - have Category Recovery time) + // Remove cooldown (Chain Lightning - has Category Recovery time) ToPlayer()->RemoveSpellCooldown(spellId); } @@ -7794,7 +7788,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!triggerEntry) { - sLog->outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id); + sLog->outError("Unit::HandleDummyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id); return false; } @@ -7852,7 +7846,7 @@ bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffec // Try handle unknown trigger spells if (!triggerEntry) { - sLog->outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id); + sLog->outError("Unit::HandleObsModEnergyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id); return false; } @@ -7905,7 +7899,7 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, Aura if (!triggerEntry) { - sLog->outError("Unit::HandleModDamagePctTakenAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id); + sLog->outError("Unit::HandleModDamagePctTakenAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id); return false; } @@ -8651,8 +8645,8 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id); if (triggerEntry == NULL) { - // Not cast unknown spell - // sLog->outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); + // Don't cast unknown spell + // sLog->outError("Unit::HandleProcTriggerSpell: Spell %u has 0 in EffectTriggered[%d]. Unhandled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex()); return false; } @@ -8739,7 +8733,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg if (!victim || !victim->isAlive()) return false; - // Not give if target already have full health + // Doesn't proc if target already has full health if (victim->IsFullHealth()) return false; // If your Greater Heal brings the target to full health, you gain $37595s1 mana. @@ -8950,7 +8944,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg if ((maelstrom->GetStackAmount() == maelstrom->GetSpellInfo()->StackAmount) && roll_chance_i(aurEff->GetAmount())) CastSpell(this, 70831, true, castItem, triggeredByAura); - // have rank dependent proc chance, ignore too often cases + // has rank dependant proc chance, ignore too often cases // PPM = 2.5 * (rank of talent), uint32 rank = auraSpellInfo->GetRank(); // 5 rank -> 100% 4 rank -> 80% and etc from full rate @@ -9304,7 +9298,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const && selfPlayerOwner->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) return REP_HOSTILE; - // if faction have reputation then hostile state dependent only from at_war state + // if faction has reputation, hostile state depends only from AtWar state if (selfPlayerOwner->GetReputationMgr().IsAtWar(targetFactionEntry)) return REP_HOSTILE; return REP_FRIENDLY; @@ -10450,7 +10444,7 @@ uint32 Unit::SpellDamageBonus(Unit* victim, SpellInfo const* spellProto, uint32 { if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) { - // effect 0 have expected value but in negative state + // effect 0 has expected value but in negative state int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount(); AddPctN(DoneTotalMod, bonus); } @@ -11481,7 +11475,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) return true; } - if (spellInfo->Mechanic) + // Spells that don't have effectMechanics. + if (!spellInfo->HasAnyEffectMechanic() && spellInfo->Mechanic) { SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) @@ -11489,14 +11484,19 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) return true; } - for (int i = 0; i < MAX_SPELL_EFFECTS; ++i) + bool immuneToAllEffects = true; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately - if (!spellInfo->Effects[i].Mechanic) - if (IsImmunedToSpellEffect(spellInfo, i)) - return true; + if (spellInfo->Effects[i].Mechanic || !IsImmunedToSpellEffect(spellInfo, i)) + { + immuneToAllEffects = false; + break; + } } + if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects. + return true; if (spellInfo->Id != 42292 && spellInfo->Id !=59752) { @@ -11708,7 +11708,7 @@ void Unit::MeleeDamageBonus(Unit* victim, uint32 *pdamage, WeaponAttackType attT { if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) { - // effect 0 have expected value but in negative state + // effect 0 has expected value but in negative state int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount(); AddPctN(DoneTotalMod, bonus); } @@ -12750,6 +12750,10 @@ void Unit::setDeathState(DeathState s) // do not why since in IncreaseMaxHealth currenthealth is checked SetHealth(0); SetPower(getPowerType(), 0); + + // players in instance don't have ZoneScript, but they have InstanceScript + if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : (ZoneScript*)GetInstanceScript()) + zoneScript->OnUnitDeath(this); } else if (s == JUST_ALIVED) RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground) @@ -12973,7 +12977,7 @@ Unit* Creature::SelectVictim() // last case when creature must not go to evade mode: // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list // for example at owner command to pet attack some far away creature - // Note: creature not have targeted movement generator but have attacker in this case + // Note: creature does not have targeted movement generator but has attacker in this case for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) { if ((*itr) && !canCreatureAttack(*itr) && (*itr)->GetTypeId() != TYPEID_PLAYER @@ -13359,7 +13363,7 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f { if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) { - sLog->outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!"); + sLog->outError("ERROR in HandleStatModifier(): non-existing UnitMods or wrong UnitModifierType!"); return false; } @@ -13424,7 +13428,7 @@ float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) co { if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END) { - sLog->outError("trial to access non existed modifier value from UnitMods!"); + sLog->outError("attempt to access non-existing modifier value from UnitMods!"); return 0.0f; } @@ -13454,7 +13458,7 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const { if (unitMod >= UNIT_MOD_END) { - sLog->outError("trial to access non existed UnitMods in GetTotalAuraModValue()!"); + sLog->outError("attempt to access non-existing UnitMods in GetTotalAuraModValue()!"); return 0.0f; } @@ -13683,7 +13687,7 @@ void Unit::SetMaxPower(Powers power, uint32 val) uint32 Unit::GetCreatePowers(Powers power) const { - // POWER_FOCUS and POWER_HAPPINESS only have hunter pet + // Only hunter pets have POWER_FOCUS and POWER_HAPPINESS switch (power) { case POWER_MANA: return GetCreateMana(); @@ -14111,12 +14115,12 @@ bool InitTriggerAuraData() isTriggerAura[SPELL_AURA_DUMMY] = true; isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; isTriggerAura[SPELL_AURA_MOD_THREAT] = true; - isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura not have charges but need remove him on trigger + isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; - isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura not have charges but need remove him on trigger + isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger isTriggerAura[SPELL_AURA_MOD_ROOT] = true; isTriggerAura[SPELL_AURA_TRANSFORM] = true; isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; @@ -15325,7 +15329,7 @@ bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura) damageSpellId = 43594; break; default: - sLog->outError("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id); + sLog->outError("Unit::HandleAuraRaidProcFromCharge, received unhandled spell: %u", spellProto->Id); return false; } @@ -15738,7 +15742,7 @@ void Unit::SetStunned(bool apply) if (!owner || (owner->GetTypeId() == TYPEID_PLAYER && !owner->ToPlayer()->IsMounted())) RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - if (!HasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect + if (!HasUnitState(UNIT_STAT_ROOT)) // prevent moving if it also has root effect { WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4); data.append(GetPackGUID()); @@ -15780,7 +15784,7 @@ void Unit::SetRooted(bool apply) } else { - if (!HasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect + if (!HasUnitState(UNIT_STAT_STUNNED)) // prevent moving if it also has stun effect { if (GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 8b9e2fe047b..6f5dc0e511e 100755 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -759,6 +759,50 @@ void GameEventMgr::LoadFromDB() } } + sLog->outString("Loading Game Event Seasonal Quest Relations..."); + { + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT questId, eventEntry FROM game_event_seasonal_questrelation"); + + if (!result) + { + sLog->outString(">> Loaded 0 seasonal quests additions in game events. DB table `game_event_seasonal_questrelation` is empty."); + sLog->outString(); + } + else + { + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 questId = fields[0].GetUInt32(); + uint16 eventEntry = fields[1].GetUInt16(); + + if (!sObjectMgr->GetQuestTemplate(questId)) + { + sLog->outErrorDb("`game_event_seasonal_questrelation` quest id (%u) does not exist in `quest_template`", questId); + continue; + } + + if (eventEntry >= mGameEvent.size()) + { + sLog->outErrorDb("`game_event_seasonal_questrelation` event id (%u) is out of range compared to max event in `game_event`", eventEntry); + continue; + } + + _questToEventLinks[questId] = eventEntry; + ++count; + } + while (result->NextRow()); + + sLog->outString(">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); + } + } + sLog->outString("Loading Game Event Vendor Additions Data..."); { uint32 oldMSTime = getMSTime(); @@ -1079,6 +1123,8 @@ void GameEventMgr::UnApplyEvent(uint16 event_id) UpdateEventNPCVendor(event_id, false); // update bg holiday UpdateBattlegroundSettings(); + // check for seasonal quest reset. + sWorld->ResetEventSeasonalQuests(event_id); } void GameEventMgr::ApplyNewEvent(uint16 event_id) @@ -1628,6 +1674,18 @@ void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate) } } +uint16 GameEventMgr::GetEventIdForQuest(Quest const* quest) const +{ + if (!quest) + return 0; + + UNORDERED_MAP<uint32, uint16>::const_iterator itr = _questToEventLinks.find(quest->GetQuestId()); + if (itr == _questToEventLinks.end()) + return 0; + + return itr->second; +} + bool IsHolidayActive(HolidayIds id) { if (id == HOLIDAY_NONE) @@ -1643,7 +1701,7 @@ bool IsHolidayActive(HolidayIds id) return false; } - bool IsEventActive(uint16 event_id) +bool IsEventActive(uint16 event_id) { GameEventMgr::ActiveEvents const& ae = sGameEventMgr->GetActiveEventList(); return ae.find(event_id) != ae.end(); diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index 34258bac499..d9b5890bfe5 100755 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -89,6 +89,7 @@ struct NPCVendorEntry class Player; class Creature; +class Quest; class GameEventMgr { @@ -118,6 +119,7 @@ class GameEventMgr void HandleWorldEventGossip(Player* player, Creature* c); uint32 GetNPCFlag(Creature* cr); uint32 GetNpcTextId(uint32 guid); + uint16 GetEventIdForQuest(Quest const* quest) const; private: void SendWorldStateUpdate(Player* player, uint16 event_id); void AddActiveEvent(uint16 event_id) { m_ActiveEvents.insert(event_id); } @@ -169,6 +171,7 @@ class GameEventMgr QuestIdToEventConditionMap mQuestToEventConditions; GameEventNPCFlagMap mGameEventNPCFlags; ActiveEvents m_ActiveEvents; + UNORDERED_MAP<uint32, uint16> _questToEventLinks; bool isSystemInit; public: GameEventGuidMap mGameEventCreatureGuids; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 57c6fe1ad2f..126cca59ef0 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -670,6 +670,7 @@ class ObjectMgr return NULL; return info; } + void GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const; uint64 GetPlayerGUIDByName(std::string name) const; @@ -687,6 +688,7 @@ class ObjectMgr QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); return itr != mQuestTemplates.end() ? itr->second : NULL; } + QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const @@ -696,6 +698,7 @@ class ObjectMgr return itr->second; return 0; } + bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.find(Trigger_ID) != mTavernAreaTriggerSet.end(); diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 2dafd44b0d1..fbe609bee23 100755 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -124,9 +124,17 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) // the instance id is set in battlegroundid NewInstanceId = player->GetBattlegroundId(); if (!NewInstanceId) return NULL; - map = FindInstanceMap(NewInstanceId); + map = sMapMgr->FindMap(mapId, NewInstanceId); if (!map) - map = CreateBattleground(NewInstanceId, player->GetBattleground()); + { + if (Battleground* bg = player->GetBattleground()) + map = CreateBattleground(NewInstanceId, bg); + else + { + player->TeleportToBGEntryPoint(); + return NULL; + } + } } else { diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index 8112d101c24..df6349a7664 100755 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -37,7 +37,7 @@ class ZoneScript virtual void OnGameObjectCreate(GameObject* /*go*/) {} virtual void OnGameObjectRemove(GameObject* /*go*/) {} - virtual void OnCreatureDeath(Creature* /*creature*/) {} + virtual void OnUnitDeath(Unit* /*unit*/) {} //All-purpose data storage 64 bit virtual uint64 GetData64(uint32 /*DataId*/) { return 0; } diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 14a6577b1b5..0467eaa3253 100755 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -77,7 +77,7 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) RewardChoiceItemCount[i] = questRecord[57+i].GetUInt32(); - + for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) RewardFactionId[i] = questRecord[63+i].GetUInt32(); @@ -86,7 +86,7 @@ Quest::Quest(Field* questRecord) for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) RewardFactionValueIdOverride[i] = questRecord[73+i].GetInt32(); - + PointMapId = questRecord[78].GetUInt32(); PointX = questRecord[79].GetFloat(); PointY = questRecord[80].GetFloat(); @@ -202,7 +202,7 @@ uint32 Quest::XPValue(Player* player) const return 0; } -int32 Quest::GetRewOrReqMoney() const +int32 Quest::GetRewOrReqMoney() const { if (RewardOrRequiredMoney <= 0) return RewardOrRequiredMoney; diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 90905f2fa34..3e142e1d84c 100755 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -251,6 +251,7 @@ class Quest uint32 GetFlags() const { return Flags; } bool IsDaily() const { return Flags & QUEST_FLAGS_DAILY; } bool IsWeekly() const { return Flags & QUEST_FLAGS_WEEKLY; } + bool IsSeasonal() const { return ZoneOrSort == -QUEST_SORT_SEASONAL; } bool IsDailyOrWeekly() const { return Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); } bool IsAutoAccept() const { return Flags & QUEST_FLAGS_AUTO_ACCEPT; } bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25; } diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 11de2c68ca1..fd649175f76 100755..100644 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -93,9 +93,13 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS, stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS); stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS, stmt); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS, stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION); stmt->setUInt32(0, lowGuid); @@ -1796,7 +1800,9 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recv_data) if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) { // Reset guild - trans->PAppend("DELETE FROM `guild_member` WHERE `guid`= '%u'", lowGuid); + if (QueryResult result = CharacterDatabase.PQuery("SELECT guildid FROM `guild_member` WHERE guid ='%u'", lowGuid)) + if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32())) + guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER)); } if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 3d964a6e14e..5577422919f 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1567,6 +1567,16 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b break; } break; + case SPELLFAMILY_DRUID: + // Enrage + if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x80000) && GetSpellInfo()->SpellIconID == 961) + { + if (target->HasAura(70726)) // Item - Druid T10 Feral 4P Bonus + if (apply) + target->CastSpell(target, 70725, true); + break; + } + break; case SPELLFAMILY_ROGUE: // Stealth if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00400000) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index bbc07c0572e..f76dbd7be47 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1562,7 +1562,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, const uint32 effectMask, bool } for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) + if (effectMask & (1 << effectNumber) && !unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) //Handle effect only if the target isn't immune. HandleEffects(unit, NULL, NULL, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); return SPELL_MISS_NONE; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2fa7bf37de9..40b3101cfd5 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1145,9 +1145,13 @@ void Spell::EffectDummy(SpellEffIndex effIndex) return; m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true); return; - case 54171: //Divine Storm + case 54171: // Divine Storm { - m_caster->CastCustomSpell(unitTarget, 54172, &damage, 0, 0, true); + if (m_UniqueTargetInfo.size()) + { + int32 heal = damage / m_UniqueTargetInfo.size(); + m_caster->CastCustomSpell(unitTarget, 54172, &heal, NULL, NULL, true); + } return; } case 58418: // Portal to Orgrimmar @@ -1374,16 +1378,6 @@ void Spell::EffectDummy(SpellEffIndex effIndex) } break; case SPELLFAMILY_PALADIN: - // Divine Storm - if (m_spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_PALADIN_DIVINESTORM && effIndex == 1) - { - int32 dmg = CalculatePctN(m_damage, damage); - if (!unitTarget) - unitTarget = m_caster; - m_caster->CastCustomSpell(unitTarget, 54171, &dmg, 0, 0, true); - return; - } - switch (m_spellInfo->Id) { case 31789: // Righteous Defense (step 1) @@ -7002,10 +6996,35 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) { if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) { + if (m_spellInfo->Id == 45529) + if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) + continue; player->SetRuneCooldown(j, 0); --count; } } + + // Blood Tap + if (m_spellInfo->Id == 45529 && count > 0) + { + for (uint32 l = 0; l < MAX_RUNES && count > 0; ++l) + { + // Check if both runes are on cd as that is the only time when this needs to come into effect + 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)) + l++; + player->SetRuneCooldown(l, 0); + --count; + // is needed to push through to the client that the rune is active + player->ResyncRunes(MAX_RUNES); + } + else + break; + } + } + // Empower rune weapon if (m_spellInfo->Id == 47568) { diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 7836c177c26..fb8018fb5ae 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1755,6 +1755,14 @@ Mechanics SpellInfo::GetEffectMechanic(uint8 effIndex) const return MECHANIC_NONE; } +bool SpellInfo::HasAnyEffectMechanic() const +{ + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (Effects[i].Mechanic) + return true; + return false; +} + uint32 SpellInfo::GetDispelMask() const { return GetDispelMask(DispelType(Dispel)); diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index cdc24f9ceac..90b79d4da28 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -446,6 +446,7 @@ public: uint32 GetEffectMechanicMask(uint8 effIndex) const; uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const; Mechanics GetEffectMechanic(uint8 effIndex) const; + bool HasAnyEffectMechanic() const; uint32 GetDispelMask() const; static uint32 GetDispelMask(DispelType type); uint32 GetExplicitTargetMask() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index b7c31ee29c6..e57cbf4a390 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2960,8 +2960,10 @@ void SpellMgr::LoadDbcDataCorrections() switch (spellInfo->Id) { - case 42835: // Spout - spellInfo->Effect[0] = 0; // remove damage effect, only anim is needed + case 40244: case 40245: // Simon Game Visual + case 40246: case 40247: // Simon Game Visual + case 42835: // Spout, remove damage effect, only anim is needed + spellInfo->Effect[0] = 0; break; case 30657: // Quake spellInfo->EffectTriggerSpell[0] = 30571; @@ -3495,6 +3497,11 @@ void SpellMgr::LoadDbcDataCorrections() case 72405: // Broken Frostmourne spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd break; + case 40055: // Introspection + case 40165: // Introspection + case 40166: // Introspection + case 40167: // Introspection + spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; default: break; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 388bafc503d..426a93fda57 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2748,6 +2748,17 @@ void World::ResetWeeklyQuests() sPoolMgr->ChangeWeeklyQuests(); } +void World::ResetEventSeasonalQuests(uint16 event_id) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL); + stmt->setUInt16(0,event_id); + CharacterDatabase.Execute(stmt); + + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if (itr->second->GetPlayer()) + itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id); +} + void World::ResetRandomBG() { sLog->outDetail("Random BG status reset for all characters."); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 02438375058..bedd8a87b20 100755 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -746,6 +746,7 @@ class World uint32 GetCleaningFlags() const { return m_CleaningFlags; } void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; } + void ResetEventSeasonalQuests(uint16 event_id); protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3ab0306f55a..bd415c0f79f 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -109,6 +109,7 @@ public: { case AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); + sLog->outChar("Account: %d (IP: %s) Character:[%s] (GUID: %u) Change Password.", handler->GetSession()->GetAccountId(),handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUIDLow()); break; case AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index b1aaf82e35b..4d8ce4ef4ed 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -36,6 +36,7 @@ EndScriptData */ #include "SkillDiscovery.h" #include "SkillExtraItems.h" #include "Chat.h" +#include "WaypointManager.h" class reload_commandscript : public CommandScript { @@ -144,13 +145,14 @@ public: { "spell_linked_spell", SEC_ADMINISTRATOR, true, &HandleReloadSpellLinkedSpellCommand, "", NULL }, { "spell_pet_auras", SEC_ADMINISTRATOR, true, &HandleReloadSpellPetAurasCommand, "", NULL }, { "spell_proc_event", SEC_ADMINISTRATOR, true, &HandleReloadSpellProcEventCommand, "", NULL }, - { "spell_proc", SEC_ADMINISTRATOR, true, &HandleReloadSpellProcsCommand, "", NULL }, + { "spell_proc", SEC_ADMINISTRATOR, true, &HandleReloadSpellProcsCommand, "", NULL }, { "spell_scripts", SEC_ADMINISTRATOR, true, &HandleReloadSpellScriptsCommand, "", NULL }, { "spell_target_position", SEC_ADMINISTRATOR, true, &HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_threats", SEC_ADMINISTRATOR, true, &HandleReloadSpellThreatsCommand, "", NULL }, { "spell_group_stack_rules", SEC_ADMINISTRATOR, true, &HandleReloadSpellGroupStackRulesCommand, "", NULL }, { "trinity_string", SEC_ADMINISTRATOR, true, &HandleReloadTrinityStringCommand, "", NULL }, { "waypoint_scripts", SEC_ADMINISTRATOR, true, &HandleReloadWpScriptsCommand, "", NULL }, + { "waypoint_data", SEC_ADMINISTRATOR, true, &HandleReloadWpCommand, "", NULL }, { "vehicle_accessory", SEC_ADMINISTRATOR, true, &HandleReloadVehicleAccessoryCommand, "", NULL }, { "vehicle_template_accessory", SEC_ADMINISTRATOR, true, &HandleReloadVehicleTemplateAccessoryCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } @@ -264,6 +266,7 @@ public: handler->SendGlobalGMSysMessage("DB tables `*_scripts` reloaded."); HandleReloadDbScriptStringCommand(handler, "a"); HandleReloadWpScriptsCommand(handler, "a"); + HandleReloadWpCommand(handler, "a"); return true; } @@ -986,6 +989,19 @@ public: return true; } + static bool HandleReloadWpCommand(ChatHandler* handler, const char* args) + { + if (*args != 'a') + sLog->outString("Re-Loading Waypoints data from 'waypoints_data'"); + + sWaypointMgr->Load(); + + if (*args != 'a') + sLog->outString("DB Table 'waypoint_data' reloaded."); + + return true; + } + static bool HandleReloadEventAITextsCommand(ChatHandler* handler, const char* /*args*/) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 946321c3de3..2a61d00d119 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -335,8 +335,12 @@ class instance_icecrown_citadel : public InstanceMapScript return entry; } - void OnCreatureDeath(Creature* creature) + void OnUnitDeath(Unit* unit) { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + switch (creature->GetEntry()) { case NPC_YMIRJAR_BATTLE_MAIDEN: diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index cc03caef58e..32cb279ce5f 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -121,24 +121,24 @@ public: LoadMinionData(minionData); } - std::set<uint64> HeiganEruptionGUID[4]; - uint64 GothikGateGUID; - uint64 HorsemenChestGUID; - uint64 SapphironGUID; - uint64 uiFaerlina; - uint64 uiThane; - uint64 uiLady; - uint64 uiBaron; - uint64 uiSir; - - uint64 uiThaddius; - uint64 uiHeigan; - uint64 uiFeugen; - uint64 uiStalagg; - - uint64 uiKelthuzad; - uint64 uiKelthuzadTrigger; - uint64 uiPortals[4]; + std::set<uint64> heiganEruptionGUID[4]; + uint64 gothikGateGUID; + uint64 horsemenChestGUID; + uint64 sapphironGUID; + uint64 faerlinaGUID; + uint64 thaneGUID; + uint64 ladyGUID; + uint64 baronGUID; + uint64 sirGUID; + + uint64 thaddiusGUID; + uint64 heiganGUID; + uint64 feugenGUID; + uint64 stalaggGUID; + + uint64 kelthuzadGUID; + uint64 kelthuzadTriggerGUID; + uint64 portalsGUID[4]; uint32 AbominationCount; @@ -147,41 +147,46 @@ public: time_t minHorsemenDiedTime; time_t maxHorsemenDiedTime; + uint32 playerDied; + void Initialize() { - GothikGateGUID = 0; - HorsemenChestGUID = 0; - SapphironGUID = 0; - uiFaerlina = 0; - uiThane = 0; - uiLady = 0; - uiBaron = 0; - uiSir = 0; - uiThaddius = 0; - uiHeigan = 0; - uiFeugen = 0; - uiStalagg = 0; - uiKelthuzad = 0; - uiKelthuzadTrigger = 0; - - memset(uiPortals, 0, sizeof(uiPortals)); + gothikGateGUID = 0; + horsemenChestGUID = 0; + sapphironGUID = 0; + faerlinaGUID = 0; + thaneGUID = 0; + ladyGUID = 0; + baronGUID = 0; + sirGUID = 0; + thaddiusGUID = 0; + heiganGUID = 0; + feugenGUID = 0; + stalaggGUID = 0; + kelthuzadGUID = 0; + kelthuzadTriggerGUID = 0; + + playerDied = 0; + gothikDoorState = GO_STATE_ACTIVE; + + memset(portalsGUID, 0, sizeof(portalsGUID)); } void OnCreatureCreate(Creature* creature) { switch (creature->GetEntry()) { - case 15989: SapphironGUID = creature->GetGUID(); return; - case 15953: uiFaerlina = creature->GetGUID(); return; - case 16064: uiThane = creature->GetGUID(); return; - case 16065: uiLady = creature->GetGUID(); return; - case 30549: uiBaron = creature->GetGUID(); return; - case 16063: uiSir = creature->GetGUID(); return; - case 15928: uiThaddius = creature->GetGUID(); return; - case 15936: uiHeigan = creature->GetGUID(); return; - case 15930: uiFeugen = creature->GetGUID(); return; - case 15929: uiStalagg = creature->GetGUID(); return; - case 15990: uiKelthuzad = creature->GetGUID(); return; + case 15989: sapphironGUID = creature->GetGUID(); return; + case 15953: faerlinaGUID = creature->GetGUID(); return; + case 16064: thaneGUID = creature->GetGUID(); return; + case 16065: ladyGUID = creature->GetGUID(); return; + case 30549: baronGUID = creature->GetGUID(); return; + case 16063: sirGUID = creature->GetGUID(); return; + case 15928: thaddiusGUID = creature->GetGUID(); return; + case 15936: heiganGUID = creature->GetGUID(); return; + case 15930: feugenGUID = creature->GetGUID(); return; + case 15929: stalaggGUID = creature->GetGUID(); return; + case 15990: kelthuzadGUID = creature->GetGUID(); return; } AddMinion(creature, true); @@ -197,7 +202,7 @@ public: if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287) { uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY()); - HeiganEruptionGUID[section].insert(go->GetGUID()); + heiganEruptionGUID[section].insert(go->GetGUID()); return; } @@ -205,29 +210,29 @@ public: switch (go->GetEntry()) { case GO_GOTHIK_GATE: - GothikGateGUID = go->GetGUID(); + gothikGateGUID = go->GetGUID(); go->SetGoState(gothikDoorState); break; case GO_HORSEMEN_CHEST: - HorsemenChestGUID = go->GetGUID(); + horsemenChestGUID = go->GetGUID(); break; case GO_HORSEMEN_CHEST_HERO: - HorsemenChestGUID = go->GetGUID(); + horsemenChestGUID = go->GetGUID(); break; case GO_KELTHUZAD_PORTAL01: - uiPortals[0] = go->GetGUID(); + portalsGUID[0] = go->GetGUID(); break; case GO_KELTHUZAD_PORTAL02: - uiPortals[1] = go->GetGUID(); + portalsGUID[1] = go->GetGUID(); break; case GO_KELTHUZAD_PORTAL03: - uiPortals[2] = go->GetGUID(); + portalsGUID[2] = go->GetGUID(); break; case GO_KELTHUZAD_PORTAL04: - uiPortals[3] = go->GetGUID(); + portalsGUID[3] = go->GetGUID(); break; case GO_KELTHUZAD_TRIGGER: - uiKelthuzadTrigger = go->GetGUID(); + kelthuzadTriggerGUID = go->GetGUID(); break; default: break; @@ -242,16 +247,16 @@ public: { uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY()); - HeiganEruptionGUID[section].erase(go->GetGUID()); + heiganEruptionGUID[section].erase(go->GetGUID()); return; } switch (go->GetEntry()) { case GO_BIRTH: - if (SapphironGUID) + if (sapphironGUID) { - if (Creature* pSapphiron = instance->GetCreature(SapphironGUID)) + if (Creature* pSapphiron = instance->GetCreature(sapphironGUID)) pSapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); return; } @@ -263,6 +268,15 @@ public: AddDoor(go, false); } + void OnUnitDeath(Unit* unit) + { + if (unit->GetTypeId() == TYPEID_PLAYER && IsEncounterInProgress()) + { + playerDied = 1; + SaveToDB(); + } + } + void SetData(uint32 id, uint32 value) { switch (id) @@ -271,11 +285,10 @@ public: HeiganErupt(value); break; case DATA_GOTHIK_GATE: - if (GameObject* gothikGate = instance->GetGameObject(GothikGateGUID)) + if (GameObject* gothikGate = instance->GetGameObject(gothikGateGUID)) gothikGate->SetGoState(GOState(value)); gothikDoorState = GOState(value); break; - case DATA_HORSEMEN0: case DATA_HORSEMEN1: case DATA_HORSEMEN2: @@ -319,35 +332,35 @@ public: switch (id) { case DATA_FAERLINA: - return uiFaerlina; + return faerlinaGUID; case DATA_THANE: - return uiThane; + return thaneGUID; case DATA_LADY: - return uiLady; + return ladyGUID; case DATA_BARON: - return uiBaron; + return baronGUID; case DATA_SIR: - return uiSir; + return sirGUID; case DATA_THADDIUS: - return uiThaddius; + return thaddiusGUID; case DATA_HEIGAN: - return uiHeigan; + return heiganGUID; case DATA_FEUGEN: - return uiFeugen; + return feugenGUID; case DATA_STALAGG: - return uiStalagg; + return stalaggGUID; case DATA_KELTHUZAD: - return uiKelthuzad; + return kelthuzadGUID; case DATA_KELTHUZAD_PORTAL01: - return uiPortals[0]; + return portalsGUID[0]; case DATA_KELTHUZAD_PORTAL02: - return uiPortals[1]; + return portalsGUID[1]; case DATA_KELTHUZAD_PORTAL03: - return uiPortals[2]; + return portalsGUID[2]; case DATA_KELTHUZAD_PORTAL04: - return uiPortals[3]; + return portalsGUID[3]; case DATA_KELTHUZAD_TRIGGER: - return uiKelthuzadTrigger; + return kelthuzadTriggerGUID; } return 0; } @@ -359,7 +372,7 @@ public: if (id == BOSS_HORSEMEN && state == DONE) { - if (GameObject* pHorsemenChest = instance->GetGameObject(HorsemenChestGUID)) + if (GameObject* pHorsemenChest = instance->GetGameObject(horsemenChestGUID)) pHorsemenChest->SetRespawnTime(pHorsemenChest->GetRespawnDelay()); } @@ -373,7 +386,7 @@ public: if (i == section) continue; - for (std::set<uint64>::const_iterator itr = HeiganEruptionGUID[i].begin(); itr != HeiganEruptionGUID[i].end(); ++itr) + for (std::set<uint64>::const_iterator itr = heiganEruptionGUID[i].begin(); itr != heiganEruptionGUID[i].end(); ++itr) { if (GameObject* pHeiganEruption = instance->GetGameObject(*itr)) { @@ -384,6 +397,21 @@ public: } } + // This Function is called in CheckAchievementCriteriaMeet and CheckAchievementCriteriaMeet is called before SetBossState(bossId, DONE), + // so to check if all bosses are done the checker must exclude 1 boss, the last done, if there is at most 1 encouter in progress when is + // called this function then all bosses are done. The one boss that check is the boss that calls this function, so it is dead. + bool AreAllEncoutersDone() + { + uint32 numBossAlive = 0; + for (uint32 i = 0; i < MAX_BOSS_NUMBER; ++i) + if (GetBossState(i) != DONE) + numBossAlive++; + + if (numBossAlive > 1) + return false; + return true; + } + bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target = NULL*/, uint32 /*miscvalue1 = 0*/) { switch (criteria_id) @@ -396,12 +424,22 @@ public: if (Difficulty(instance->GetSpawnMode()) == RAID_DIFFICULTY_25MAN_NORMAL && (maxHorsemenDiedTime - minHorsemenDiedTime) < 15) return true; return false; - case 13233: // Criteria for achievement 2186: The Immortal (25-man) - // TODO. - break; - case 13237: // Criteria for achievement 2187: The Undying (10-man) - // TODO. - break; + // Difficulty checks are done on DB. + // Criteria for achievement 2186: The Immortal (25-man) + case 13233: // The Four Horsemen + case 13234: // Maexxna + case 13235: // Thaddius + case 13236: // Loatheb + case 7616: // Kel'Thuzad + // Criteria for achievement 2187: The Undying (10-man) + case 13237: // The Four Horsemen + case 13238: // Maexxna + case 13239: // Loatheb + case 13240: // Thaddius + case 7617: // Kel'Thuzad + if (AreAllEncoutersDone() && !playerDied) + return true; + return false; } return false; } @@ -409,16 +447,22 @@ public: std::string GetSaveData() { std::ostringstream saveStream; - saveStream << GetBossSaveData() << ' ' << gothikDoorState; + saveStream << GetBossSaveData() << gothikDoorState << ' ' << playerDied; return saveStream.str(); } void Load(const char * data) { std::istringstream loadStream(LoadBossState(data)); - uint32 buff; + uint32 temp, buff, buff2; + + for (uint32 i = 0; i < MAX_BOSS_NUMBER; ++i) + loadStream >> temp; + loadStream >> buff; gothikDoorState = GOState(buff); + loadStream >> buff2; + playerDied = buff2; } }; diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index 1a62a6236e1..46498a69c6f 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -58,8 +58,12 @@ public: gameObjectList.clear(); } - void OnCreatureDeath(Creature* creature) + void OnUnitDeath(Unit* unit) { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + if (creature->GetEntry() != NPC_CENTRIFUGE_CONSTRUCT) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 7c8121f475f..f62c2d6c596 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -436,7 +436,7 @@ class boss_freya : public CreatureScript break; case EVENT_WAVE: SpawnWave(); - if (waveCount < 6) + if (waveCount <= 6) // If set to 6 The Bombs appear during the Final Add wave events.ScheduleEvent(EVENT_WAVE, WAVE_TIME); else events.ScheduleEvent(EVENT_NATURE_BOMB, urand(10000, 20000)); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index a6f7af6e492..e12393f047f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -358,8 +358,12 @@ class instance_ulduar : public InstanceMapScript } } - void OnCreatureDeath(Creature* creature) + void OnUnitDeath(Unit* unit) { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + switch (creature->GetEntry()) { case NPC_CORRUPTED_SERVITOR: diff --git a/src/server/scripts/Outland/blades_edge_mountains.cpp b/src/server/scripts/Outland/blades_edge_mountains.cpp index d78d4afbfb8..97ce9f45430 100644 --- a/src/server/scripts/Outland/blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/blades_edge_mountains.cpp @@ -562,6 +562,564 @@ class go_thunderspike : public GameObjectScript } }; +enum SimonGame +{ + NPC_SIMON_BUNNY = 22923, + NPC_APEXIS_GUARDIAN = 22275, + + GO_APEXIS_RELIC = 185890, + GO_APEXIS_MONUMENT = 185944, + GO_AURA_BLUE = 185872, + GO_AURA_GREEN = 185873, + GO_AURA_RED = 185874, + GO_AURA_YELLOW = 185875, + + GO_BLUE_CLUSTER_DISPLAY = 7369, + GO_GREEN_CLUSTER_DISPLAY = 7371, + GO_RED_CLUSTER_DISPLAY = 7373, + GO_YELLOW_CLUSTER_DISPLAY = 7375, + GO_BLUE_CLUSTER_DISPLAY_LARGE = 7364, + GO_GREEN_CLUSTER_DISPLAY_LARGE = 7365, + GO_RED_CLUSTER_DISPLAY_LARGE = 7366, + GO_YELLOW_CLUSTER_DISPLAY_LARGE = 7367, + + SPELL_PRE_GAME_BLUE = 40176, + SPELL_PRE_GAME_GREEN = 40177, + SPELL_PRE_GAME_RED = 40178, + SPELL_PRE_GAME_YELLOW = 40179, + SPELL_VISUAL_BLUE = 40244, + SPELL_VISUAL_GREEN = 40245, + SPELL_VISUAL_RED = 40246, + SPELL_VISUAL_YELLOW = 40247, + + SOUND_BLUE = 11588, + SOUND_GREEN = 11589, + SOUND_RED = 11590, + SOUND_YELLOW = 11591, + SOUND_DISABLE_NODE = 11758, + + SPELL_AUDIBLE_GAME_TICK = 40391, + SPELL_VISUAL_START_PLAYER_LEVEL = 40436, + SPELL_VISUAL_START_AI_LEVEL = 40387, + + SPELL_BAD_PRESS_TRIGGER = 41241, + SPELL_BAD_PRESS_DAMAGE = 40065, + SPELL_REWARD_BUFF_1 = 40310, + SPELL_REWARD_BUFF_2 = 40311, + SPELL_REWARD_BUFF_3 = 40312, +}; + +enum SimonEvents +{ + EVENT_SIMON_SETUP_PRE_GAME = 1, + EVENT_SIMON_PLAY_SEQUENCE = 2, + EVENT_SIMON_RESET_CLUSTERS = 3, + EVENT_SIMON_PERIODIC_PLAYER_CHECK = 4, + EVENT_SIMON_TOO_LONG_TIME = 5, + EVENT_SIMON_GAME_TICK = 6, + EVENT_SIMON_ROUND_FINISHED = 7, + + ACTION_SIMON_CORRECT_FULL_SEQUENCE = 8, + ACTION_SIMON_WRONG_SEQUENCE = 9, + ACTION_SIMON_ROUND_FINISHED = 10, +}; + +enum SimonColors +{ + SIMON_BLUE = 0, + SIMON_RED = 1, + SIMON_GREEN = 2, + SIMON_YELLOW = 3, + SIMON_MAX_COLORS = 4, +}; + +class npc_simon_bunny : public CreatureScript +{ + public: + npc_simon_bunny() : CreatureScript("npc_simon_bunny") { } + + struct npc_simon_bunnyAI : public ScriptedAI + { + npc_simon_bunnyAI(Creature* creature) : ScriptedAI(creature) { } + + bool large; + bool listening; + uint8 gameLevel; + uint8 fails; + uint8 gameTicks; + uint64 playerGUID; + uint32 clusterIds[SIMON_MAX_COLORS]; + float zCoordCorrection; + float searchDistance; + EventMap _events; + std::list<uint8> colorSequence, playableSequence, playerSequence; + + void UpdateAI(const uint32 diff) + { + _events.Update(diff); + + switch(_events.ExecuteEvent()) + { + case EVENT_SIMON_PERIODIC_PLAYER_CHECK: + if (!CheckPlayer()) + ResetNode(); + else + _events.ScheduleEvent(EVENT_SIMON_PERIODIC_PLAYER_CHECK, 2000); + break; + case EVENT_SIMON_SETUP_PRE_GAME: + SetUpPreGame(); + _events.CancelEvent(EVENT_SIMON_GAME_TICK); + _events.ScheduleEvent(EVENT_SIMON_PLAY_SEQUENCE, 1000); + break; + case EVENT_SIMON_PLAY_SEQUENCE: + if (!playableSequence.empty()) + { + PlayNextColor(); + _events.ScheduleEvent(EVENT_SIMON_PLAY_SEQUENCE, 1500); + } + else + { + listening = true; + DoCast(SPELL_VISUAL_START_PLAYER_LEVEL); + playerSequence.clear(); + PrepareClusters(); + gameTicks = 0; + _events.ScheduleEvent(EVENT_SIMON_GAME_TICK, 3000); + } + break; + case EVENT_SIMON_GAME_TICK: + DoCast(SPELL_AUDIBLE_GAME_TICK); + + if (gameTicks > gameLevel) + _events.ScheduleEvent(EVENT_SIMON_TOO_LONG_TIME, 500); + else + _events.ScheduleEvent(EVENT_SIMON_GAME_TICK, 3000); + gameTicks++; + break; + case EVENT_SIMON_RESET_CLUSTERS: + PrepareClusters(true); + break; + case EVENT_SIMON_TOO_LONG_TIME: + DoAction(ACTION_SIMON_WRONG_SEQUENCE); + break; + case EVENT_SIMON_ROUND_FINISHED: + DoAction(ACTION_SIMON_ROUND_FINISHED); + break; + } + } + + void DoAction(const int32 action) + { + switch (action) + { + case ACTION_SIMON_ROUND_FINISHED: + listening = false; + DoCast(SPELL_VISUAL_START_AI_LEVEL); + GiveRewardForLevel(gameLevel); + _events.CancelEventGroup(0); + if (gameLevel == 10) + ResetNode(); + else + _events.ScheduleEvent(EVENT_SIMON_SETUP_PRE_GAME, 1000); + break; + case ACTION_SIMON_CORRECT_FULL_SEQUENCE: + gameLevel++; + DoAction(ACTION_SIMON_ROUND_FINISHED); + break; + case ACTION_SIMON_WRONG_SEQUENCE: + GivePunishment(); + DoAction(ACTION_SIMON_ROUND_FINISHED); + break; + } + } + + // Called by color clusters script (go_simon_cluster) and used for knowing the button pressed by player + void SetData(uint32 type, uint32 /*data*/) + { + if (!listening) + return; + + uint8 pressedColor; + + if (type == clusterIds[SIMON_RED]) + pressedColor = SIMON_RED; + else if (type == clusterIds[SIMON_BLUE]) + pressedColor = SIMON_BLUE; + else if (type == clusterIds[SIMON_GREEN]) + pressedColor = SIMON_GREEN; + else if (type == clusterIds[SIMON_YELLOW]) + pressedColor = SIMON_YELLOW; + + PlayColor(pressedColor); + playerSequence.push_back(pressedColor); + _events.ScheduleEvent(EVENT_SIMON_RESET_CLUSTERS, 500); + CheckPlayerSequence(); + } + + // Used for getting involved player guid. Parameter id is used for defining if is a large(Monument) or small(Relic) node + void SetGUID(uint64 guid, int32 id) + { + me->SetFlying(true); + + large = (bool)id; + playerGUID = guid; + StartGame(); + } + + /* + Resets all variables and also find the ids of the four closests color clusters, since every simon + node have diferent ids for clusters this is absolutely NECESSARY. + */ + void StartGame() + { + listening = false; + gameLevel = 0; + fails = 0; + gameTicks = 0; + zCoordCorrection = large ? 8.0f : 2.75f; + searchDistance = large ? 13.0f : 5.0f; + colorSequence.clear(); + playableSequence.clear(); + playerSequence.clear(); + me->SetFloatValue(OBJECT_FIELD_SCALE_X, large ? 2 : 1); + + std::list<WorldObject*> ClusterList; + Trinity::AllWorldObjectsInRange objects(me, searchDistance); + Trinity::WorldObjectListSearcher<Trinity::AllWorldObjectsInRange> searcher(me, ClusterList, objects); + me->VisitNearbyObject(searchDistance, searcher); + + for (std::list<WorldObject*>::const_iterator i = ClusterList.begin(); i != ClusterList.end(); ++i) + { + if (GameObject* go = (*i)->ToGameObject()) + { + // We are checking for displayid because all simon nodes have 4 clusters with different entries + if (large) + { + switch (go->GetGOInfo()->displayId) + { + case GO_BLUE_CLUSTER_DISPLAY_LARGE: clusterIds[SIMON_BLUE] = go->GetEntry(); break; + case GO_RED_CLUSTER_DISPLAY_LARGE: clusterIds[SIMON_RED] = go->GetEntry(); break; + case GO_GREEN_CLUSTER_DISPLAY_LARGE: clusterIds[SIMON_GREEN] = go->GetEntry(); break; + case GO_YELLOW_CLUSTER_DISPLAY_LARGE: clusterIds[SIMON_YELLOW] = go->GetEntry(); break; + } + } + else + { + switch (go->GetGOInfo()->displayId) + { + case GO_BLUE_CLUSTER_DISPLAY: clusterIds[SIMON_BLUE] = go->GetEntry(); break; + case GO_RED_CLUSTER_DISPLAY: clusterIds[SIMON_RED] = go->GetEntry(); break; + case GO_GREEN_CLUSTER_DISPLAY: clusterIds[SIMON_GREEN] = go->GetEntry(); break; + case GO_YELLOW_CLUSTER_DISPLAY: clusterIds[SIMON_YELLOW] = go->GetEntry(); break; + } + } + } + } + + _events.Reset(); + _events.ScheduleEvent(EVENT_SIMON_ROUND_FINISHED, 1000); + _events.ScheduleEvent(EVENT_SIMON_PERIODIC_PLAYER_CHECK, 2000); + + if (GameObject* relic = me->FindNearestGameObject(large ? GO_APEXIS_MONUMENT : GO_APEXIS_RELIC, searchDistance)) + relic->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + + // Called when despawning the bunny. Sets all the node GOs to their default states. + void ResetNode() + { + DoPlaySoundToSet(me, SOUND_DISABLE_NODE); + + for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++) + if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], searchDistance)) + cluster->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + + for (uint32 auraId = GO_AURA_BLUE; auraId <= GO_AURA_YELLOW; auraId++) + if (GameObject* auraGo = me->FindNearestGameObject(auraId, searchDistance)) + auraGo->RemoveFromWorld(); + + if (GameObject* relic = me->FindNearestGameObject(large ? GO_APEXIS_MONUMENT : GO_APEXIS_RELIC, searchDistance)) + relic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + + me->ForcedDespawn(1000); + } + + /* + Called on every button click of player. Adds the clicked color to the player created sequence and + checks if it corresponds to the AI created sequence. If so, incremente gameLevel and start a new + round, if not, give punishment and restart current level. + */ + void CheckPlayerSequence() + { + bool correct = true; + if (playerSequence.size() <= colorSequence.size()) + for (std::list<uint8>::const_iterator i = playerSequence.begin(), j = colorSequence.begin(); i != playerSequence.end(); ++i, ++j) + if ((*i) != (*j)) + correct = false; + + if (correct && (playerSequence.size() == colorSequence.size())) + DoAction(ACTION_SIMON_CORRECT_FULL_SEQUENCE); + else if (!correct) + DoAction(ACTION_SIMON_WRONG_SEQUENCE); + } + + /* + Generates a random sequence of colors depending on the gameLevel. We also copy this sequence to + the playableSequence wich will be used when playing the sequence to the player. + */ + void GenerateColorSequence() + { + colorSequence.clear(); + for (uint8 i = 0; i <= gameLevel; i++) + colorSequence.push_back(RAND(SIMON_BLUE, SIMON_RED, SIMON_GREEN, SIMON_YELLOW)); + + for (std::list<uint8>::const_iterator i = colorSequence.begin(); i != colorSequence.end(); ++i) + playableSequence.push_back(*i); + } + + + // Remove any existant glowing auras over clusters and set clusters ready for interating with them. + void PrepareClusters(bool clustersOnly = false) + { + for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++) + if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], searchDistance)) + cluster->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + + if (clustersOnly) + return; + + for (uint32 auraId = GO_AURA_BLUE; auraId <= GO_AURA_YELLOW; auraId++) + if (GameObject* auraGo = me->FindNearestGameObject(auraId, searchDistance)) + auraGo->RemoveFromWorld(); + } + + /* + Called when AI is playing the sequence for player. We cast the visual spell and then remove the + casted color from the casting sequence. + */ + void PlayNextColor() + { + PlayColor(*playableSequence.begin()); + playableSequence.erase(playableSequence.begin()); + } + + // Casts a spell and plays a sound depending on parameter color. + void PlayColor(uint8 color) + { + switch (color) + { + case SIMON_BLUE: + DoCast(SPELL_VISUAL_BLUE); + DoPlaySoundToSet(me, SOUND_BLUE); + break; + case SIMON_GREEN: + DoCast(SPELL_VISUAL_GREEN); + DoPlaySoundToSet(me, SOUND_GREEN); + break; + case SIMON_RED: + DoCast(SPELL_VISUAL_RED); + DoPlaySoundToSet(me, SOUND_RED); + break; + case SIMON_YELLOW: + DoCast(SPELL_VISUAL_YELLOW); + DoPlaySoundToSet(me, SOUND_YELLOW); + break; + } + } + + /* + Creates the transparent glowing auras on every cluster of this node. + After calling this function bunny is teleported to the center of the node. + */ + void SetUpPreGame() + { + for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++) + { + if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], 2.0f*searchDistance)) + { + cluster->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + + // break since we don't need glowing auras for large clusters + if (large) + break; + + float x, y, z, o; + cluster->GetPosition(x, y, z, o); + me->NearTeleportTo(x, y, z, o); + + uint32 preGameSpellId; + if (cluster->GetEntry() == clusterIds[SIMON_RED]) + preGameSpellId = SPELL_PRE_GAME_RED; + else if (cluster->GetEntry() == clusterIds[SIMON_BLUE]) + preGameSpellId = SPELL_PRE_GAME_BLUE; + else if (cluster->GetEntry() == clusterIds[SIMON_GREEN]) + preGameSpellId = SPELL_PRE_GAME_GREEN; + else if (cluster->GetEntry() == clusterIds[SIMON_YELLOW]) + preGameSpellId = SPELL_PRE_GAME_YELLOW; + else break; + + me->CastSpell(cluster, preGameSpellId, true); + } + } + + if (GameObject* relic = me->FindNearestGameObject(large ? GO_APEXIS_MONUMENT : GO_APEXIS_RELIC, searchDistance)) + { + float x, y, z, o; + relic->GetPosition(x, y, z, o); + me->NearTeleportTo(x, y, z + zCoordCorrection, o); + } + + GenerateColorSequence(); + } + + // Handles the spell rewards. The spells also have the QuestCompleteEffect, so quests credits are working. + void GiveRewardForLevel(uint8 level) + { + uint32 rewSpell; + switch (level) + { + case 6: + if (large) + GivePunishment(); + else + rewSpell = SPELL_REWARD_BUFF_1; + break; + case 8: + rewSpell = SPELL_REWARD_BUFF_2; + break; + case 10: + rewSpell = SPELL_REWARD_BUFF_3; + break; + default: + rewSpell = 0; + } + + if (rewSpell) + if (Player* player = me->GetPlayer(*me, playerGUID)) + DoCast(player, rewSpell, true); + } + + /* + Depending on the number of failed pushes for player the damage of the spell scales, so we first + cast the spell on the target that hits for 50 and shows the visual and then forces the player + to cast the damaging spell on it self with the modified basepoints. + 4 fails = death. + On large nodes punishment and reward are the same, summoning the Apexis Guardian. + */ + void GivePunishment() + { + if (large) + { + if (Player* player = me->GetPlayer(*me, playerGUID)) + if (Creature* guardian = me->SummonCreature(NPC_APEXIS_GUARDIAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() - zCoordCorrection, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000)) + guardian->AI()->AttackStart(player); + + ResetNode(); + } + else + { + fails++; + + if (Player* player = me->GetPlayer(*me, playerGUID)) + DoCast(player, SPELL_BAD_PRESS_TRIGGER, true); + + if (fails >= 4) + ResetNode(); + } + } + + void SpellHitTarget(Unit* target, const SpellInfo* spell) + { + // Cast SPELL_BAD_PRESS_DAMAGE with scaled basepoints when the visual hits the target. + // Need Fix: When SPELL_BAD_PRESS_TRIGGER hits target it triggers spell SPELL_BAD_PRESS_DAMAGE by itself + // so player gets damage equal to calculated damage dbc basepoints for SPELL_BAD_PRESS_DAMAGE (~50) + if (spell->Id == SPELL_BAD_PRESS_TRIGGER) + { + int32 bp = (int32)((float)(fails)*0.33f*target->GetMaxHealth()); + target->CastCustomSpell(target, SPELL_BAD_PRESS_DAMAGE, &bp, NULL, NULL, true); + } + } + + // Checks if player has already die or has get too far from the current node + bool CheckPlayer() + { + if (Player* player = me->GetPlayer(*me, playerGUID)) + { + if (player->isDead()) + return false; + if (player->GetDistance2d(me) >= 2.0f*searchDistance) + { + GivePunishment(); + return false; + } + } + else + return false; + + return true; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_simon_bunnyAI(creature); + } +}; + +class go_simon_cluster : public GameObjectScript +{ + public: + go_simon_cluster() : GameObjectScript("go_simon_cluster") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + if (Creature* bunny = go->FindNearestCreature(NPC_SIMON_BUNNY, 12.0f, true)) + bunny->AI()->SetData(go->GetEntry(), 0); + + player->CastSpell(player, go->GetGOInfo()->goober.spellId, true); + go->AddUse(); + return true; + } +}; + +enum ApexisRelic +{ + QUEST_CRYSTALS = 11025, + GOSSIP_TEXT_ID = 10948, + + ITEM_APEXIS_SHARD = 32569, + SPELL_TAKE_REAGENTS_SOLO = 41145, + SPELL_TAKE_REAGENTS_GROUP = 41146, +}; + +class go_apexis_relic : public GameObjectScript +{ + public: + go_apexis_relic() : GameObjectScript("go_apexis_relic") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + player->PrepareGossipMenu(go, go->GetGOInfo()->questgiver.gossipID); + player->SendPreparedGossip(go); + return true; + } + + bool OnGossipSelect(Player* player, GameObject* go, uint32 /*sender*/, uint32 /*action*/) + { + player->CLOSE_GOSSIP_MENU(); + + bool large = (go->GetEntry() == GO_APEXIS_MONUMENT); + if (player->HasItemCount(ITEM_APEXIS_SHARD, large ? 35 : 1)) + { + player->CastSpell(player, large ? SPELL_TAKE_REAGENTS_GROUP : SPELL_TAKE_REAGENTS_SOLO, false); + + if (Creature* bunny = player->SummonCreature(NPC_SIMON_BUNNY, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ())) + bunny->AI()->SetGUID(player->GetGUID(), large); + } + + return true; + } +}; + void AddSC_blades_edge_mountains() { new mobs_bladespire_ogre(); @@ -573,4 +1131,7 @@ void AddSC_blades_edge_mountains() new npc_bloodmaul_brutebane(); new npc_ogre_brute(); new go_thunderspike(); + new npc_simon_bunny(); + new go_simon_cluster(); + new go_apexis_relic(); } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index f7cdfa552ee..39360e04aa1 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -37,6 +37,10 @@ enum PaladinSpells SPELL_BLESSING_OF_LOWER_CITY_PALADIN = 37879, SPELL_BLESSING_OF_LOWER_CITY_PRIEST = 37880, SPELL_BLESSING_OF_LOWER_CITY_SHAMAN = 37881, + + SPELL_DIVINE_STORM = 53385, + SPELL_DIVINE_STORM_DUMMY = 54171, + SPELL_DIVINE_STORM_HEAL = 54172, }; // 31850 - Ardent Defender @@ -327,6 +331,40 @@ public: } }; +class spell_pal_divine_storm : public SpellScriptLoader +{ +public: + spell_pal_divine_storm() : SpellScriptLoader("spell_pal_divine_storm") { } + + class spell_pal_divine_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pal_divine_storm_SpellScript); + + uint32 healPct; + + bool Load() + { + healPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(GetCaster()); + return true; + } + + void TriggerHeal() + { + GetCaster()->CastCustomSpell(SPELL_DIVINE_STORM_DUMMY, SPELLVALUE_BASE_POINT0, (GetHitDamage() * healPct) / 100, GetCaster(), true); + } + + void Register() + { + AfterHit += SpellHitFn(spell_pal_divine_storm_SpellScript::TriggerHeal); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_pal_divine_storm_SpellScript(); + } +}; + void AddSC_paladin_spell_scripts() { new spell_pal_ardent_defender(); @@ -335,4 +373,5 @@ void AddSC_paladin_spell_scripts() new spell_pal_guarded_by_the_light(); new spell_pal_holy_shock(); new spell_pal_judgement_of_command(); + new spell_pal_divine_storm(); } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 9e8b8a9eda4..b0116d6d33d 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -26,16 +26,16 @@ enum ShamanSpells { - SHAMAN_SPELL_GLYPH_OF_MANA_TIDE = 55441, - SHAMAN_SPELL_MANA_TIDE_TOTEM = 39609, - SHAMAN_SPELL_FIRE_NOVA_R1 = 1535, - SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, - SHAMAN_SPELL_SATED = 57724, - SHAMAN_SPELL_EXHAUSTION = 57723, - - //For Earthen Power - SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM = 6474, //Spell casted by totem - SHAMAN_TOTEM_SPELL_EARTHEN_POWER = 59566, //Spell witch remove snare effect + SHAMAN_SPELL_GLYPH_OF_MANA_TIDE = 55441, + SHAMAN_SPELL_MANA_TIDE_TOTEM = 39609, + SHAMAN_SPELL_FIRE_NOVA_R1 = 1535, + SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, + SHAMAN_SPELL_SATED = 57724, + SHAMAN_SPELL_EXHAUSTION = 57723, + + // For Earthen Power + SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM = 6474, + SHAMAN_TOTEM_SPELL_EARTHEN_POWER = 59566, }; // 51474 - Astral shift @@ -125,7 +125,7 @@ class spell_sha_fire_nova : public SpellScriptLoader { Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1]); if (totem && totem->isTotem()) - totem->CastSpell(totem, spellId, true); + caster->CastSpell(totem, spellId, true); } } @@ -215,9 +215,11 @@ class spell_sha_earthbind_totem : public SpellScriptLoader { Unit* target = GetTarget(); if (Unit* caster = aurEff->GetBase()->GetCaster()) - if (AuraEffect* aur = caster->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 2289, 0)) - if (roll_chance_i(aur->GetBaseAmount())) - target->CastSpell(target, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true, NULL, aurEff); + if (TempSummon* summon = caster->ToTempSummon()) + if (Unit* owner = summon->GetOwner()) + if (AuraEffect* aur = owner->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 2289, 0)) + if (roll_chance_i(aur->GetBaseAmount()) && target->HasAuraWithMechanic(1 << MECHANIC_SNARE)) + caster->CastSpell(caster, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true, NULL, aurEff); } void Register() diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index b5b174a19eb..a24f17a8b76 100755..100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -46,6 +46,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_SEL_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY_CHAR, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC); @@ -63,7 +67,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, " "itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC) - PREPARE_STATEMENT(CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_INS_CHARACTER_DAILYQUESTSTATUS, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC) diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index a0f5b9a9954..a239e274a54 100755..100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -66,6 +66,10 @@ enum CharacterDatabaseStatements CHAR_SEL_GUID_RACE_ACC_BY_NAME, CHAR_DEL_QUEST_STATUS_DAILY, CHAR_DEL_QUEST_STATUS_WEEKLY, + CHAR_DEL_QUEST_STATUS_SEASONAL, + CHAR_DEL_QUEST_STATUS_DAILY_CHAR, + CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR, + CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR, CHAR_DEL_BATTLEGROUND_RANDOM, CHAR_INS_BATTLEGROUND_RANDOM, @@ -76,7 +80,11 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_SPELL, CHAR_SEL_CHARACTER_QUESTSTATUS, CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, - CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS, + CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, + CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS, + CHAR_INS_CHARACTER_DAILYQUESTSTATUS, + CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, + CHAR_INS_CHARACTER_SEASONALQUESTSTATUS, CHAR_SEL_CHARACTER_REPUTATION, CHAR_SEL_CHARACTER_INVENTORY, CHAR_SEL_CHARACTER_ACTIONS, |