diff options
Diffstat (limited to 'src/game')
72 files changed, 5631 insertions, 2071 deletions
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index da192844a70..26df402e5aa 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -37,56 +37,6 @@ INSTANTIATE_SINGLETON_1(AchievementGlobalMgr); -const CriteriaCastSpellRequirement AchievementGlobalMgr::m_criteriaCastSpellRequirements[CRITERIA_CAST_SPELL_REQ_COUNT] = - { - {5272, 3057, 0, 0}, - {5273, 2784, 0, 0}, - {5752, 9099, 0, 0}, - {5753, 8403, 0, 0}, - {5772, 0, 0, RACE_GNOME}, - {5774, 0, 0, RACE_BLOODELF}, - {5775, 0, 0, RACE_DRAENEI}, - {5776, 0, 0, RACE_DWARF}, - {5777, 0, 0, RACE_HUMAN}, - {5778, 0, 0, RACE_NIGHTELF}, - {5779, 0, 0, RACE_ORC}, - {5780, 0, 0, RACE_TAUREN}, - {5781, 0, 0, RACE_TROLL}, - {5782, 0, 0, RACE_UNDEAD_PLAYER}, - {6225, 5661, 0, 0}, - {6226, 26044, 0, 0}, - {6228, 739, 0, 0}, - {6229, 927, 0, 0}, - {6230, 1444, 0, 0}, - {6231, 8140, 0, 0}, - {6232, 5489, 0, 0}, - {6233,12336, 0, 0}, - {6234, 1351, 0, 0}, - {6235, 5484, 0, 0}, - {6236, 1182, 0, 0}, - {6237, 0, CLASS_DEATH_KNIGHT, RACE_ORC}, - {6238, 0, CLASS_WARRIOR, RACE_HUMAN}, - {6239, 0, CLASS_SHAMAN, RACE_TAUREN}, - {6240, 0, CLASS_DRUID, RACE_NIGHTELF}, - {6241, 0, CLASS_ROGUE, RACE_UNDEAD_PLAYER}, - {6242, 0, CLASS_HUNTER, RACE_TROLL}, - {6243, 0, CLASS_MAGE, RACE_GNOME}, - {6244, 0, CLASS_PALADIN, RACE_DWARF}, - {6245, 0, CLASS_WARLOCK, RACE_BLOODELF}, - {6246, 0, CLASS_PRIEST, RACE_DRAENEI}, - {6312, 0, CLASS_WARLOCK, RACE_GNOME}, - {6313, 0, CLASS_DEATH_KNIGHT, RACE_HUMAN}, - {6314, 0, CLASS_PRIEST, RACE_NIGHTELF}, - {6315, 0, CLASS_SHAMAN, RACE_ORC}, - {6316, 0, CLASS_DRUID, RACE_TAUREN}, - {6317, 0, CLASS_ROGUE, RACE_TROLL}, - {6318, 0, CLASS_WARRIOR, RACE_UNDEAD_PLAYER}, - {6319, 0, CLASS_MAGE, RACE_BLOODELF}, - {6320, 0, CLASS_PALADIN, RACE_DRAENEI}, - {6321, 0, CLASS_HUNTER, RACE_DWARF}, - {6662, 31261, 0, 0} - }; - namespace MaNGOS { class AchievementChatBuilder @@ -117,6 +67,156 @@ namespace MaNGOS }; } // namespace MaNGOS + +bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) +{ + if(dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE) + { + sLog.outErrorDb( "Table `achievement_criteria_data` for criteria (Entry: %u) have wrong data type (%u), ignore.", criteria->ID,dataType); + return false; + } + + switch(criteria->requiredType) + { + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + break; + default: + sLog.outErrorDb( "Table `achievement_criteria_data` have data for not supported criteria type (Entry: %u Type: %u), ignore.", criteria->ID, criteria->requiredType); + return false; + } + + switch(dataType) + { + case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: + if(!creature.id || !objmgr.GetCreatureTemplate(creature.id)) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) have not existed creature id in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,creature.id); + return false; + } + return true; + 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 have not 0 in one from value fields, ignore.", + 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_CREATURE (%u) have not existed class in value1 (%u), ignore.", + 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_CREATURE (%u) have not existed race in value2 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,classRace.race_id); + return false; + } + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: + if(health.percent < 1 || health.percent > 100) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) have wrong percent value in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,health.percent); + return false; + } + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: + { + SpellEntry const* spellEntry = sSpellStore.LookupEntry(aura.spell_id); + if(!spellEntry) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell id in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.spell_id); + return false; + } + if(aura.effect_idx >= 3) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell effect index in value2 (%u), ignore.", + criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.effect_idx); + return false; + } + if(!spellEntry->EffectApplyAuraName[aura.effect_idx]) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have non-aura spell effect (ID: %u Effect: %u), ignore.", + criteria->ID, criteria->requiredType,(dataType==ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"),dataType,aura.spell_id,aura.effect_idx); + return false; + } + return true; + } + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: + if(!GetAreaEntryByAreaID(area.id)) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) have wrong area id in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,area.id); + return false; + } + return true; + default: + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType); + return false; + } + return false; +} + +bool AchievementCriteriaData::Meets(Player const* source, Unit const* target) const +{ + switch(dataType) + { + case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: + if (!target || target->GetTypeId()!=TYPEID_UNIT) + return false; + if (target->GetEntry() != creature.id) + return false; + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: + if (!target || target->GetTypeId()!=TYPEID_PLAYER) + return false; + if(classRace.class_id && classRace.class_id != ((Player*)target)->getClass()) + return false; + if(classRace.race_id && classRace.race_id != ((Player*)target)->getRace()) + return false; + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: + if (!target || target->GetTypeId()!=TYPEID_PLAYER) + return false; + return target->GetHealth()*100 <= health.percent*target->GetMaxHealth(); + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: + return target && target->GetTypeId() == TYPEID_PLAYER && !target->isAlive() && ((Player*)target)->GetDeathTimer() != 0; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA: + return source->HasAura(aura.spell_id,aura.effect_idx); + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: + { + uint32 zone_id,area_id; + source->GetZoneAndAreaId(zone_id,area_id); + return area.id==zone_id || area.id==area_id; + } + case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA: + return target && target->HasAura(aura.spell_id,aura.effect_idx); + } + + return false; +} + +bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target) const +{ + for(Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr) + if(!itr->Meets(source,target)) + return false; + + return true; +} + AchievementMgr::AchievementMgr(Player *player) { m_player = player; @@ -542,6 +642,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui } case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE: { + // speedup for non-login case + if(miscvalue1 && miscvalue1 != achievementCriteria->complete_quests_in_zone.zoneID) + continue; + uint32 counter =0; for(QuestStatusMap::iterator itr = GetPlayer()->getQuestStatusMap().begin(); itr!=GetPlayer()->getQuestStatusMap().end(); itr++) { @@ -573,14 +677,14 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case if(!miscvalue1) continue; - // skip wrong arena achievements, if not achievIdByArenaSlot then normal totla death counter + // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter bool notfit = false; for(int i = 0; i < MAX_ARENA_SLOT; ++i) { if(achievIdByArenaSlot[i] == achievement->ID) { BattleGround* bg = GetPlayer()->GetBattleGround(); - if(!bg || ArenaTeam::GetSlotByType(bg->GetArenaType())!=i) + if(!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != i) notfit = true; break; @@ -805,22 +909,18 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: { // miscvalue1 = emote - // miscvalue2 = achievement->ID for special requirement if(!miscvalue1) continue; if(miscvalue1 != achievementCriteria->do_emote.emoteID) continue; if(achievementCriteria->do_emote.count) { - // harcoded case - if(achievement->ID==247) - { - if (!unit || unit->GetTypeId() != TYPEID_PLAYER || - unit->isAlive() || ((Player*)unit)->GetDeathTimer() == 0) - continue; - } - // expected as scripted case - else if(!miscvalue2 || !achievement->ID != miscvalue2) + // those requirements couldn't be found in the dbc + AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria); + if(!data) + continue; + + if(!data->Meets(GetPlayer(),unit)) continue; } @@ -884,24 +984,19 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: { + if (!miscvalue1) + continue; + if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID) continue; // those requirements couldn't be found in the dbc - if (CriteriaCastSpellRequirement const* requirement = AchievementGlobalMgr::GetCriteriaCastSpellRequirement(achievementCriteria)) - { - if (!unit) - continue; - - if (requirement->creatureEntry && unit->GetEntry() != requirement->creatureEntry) - continue; - - if (requirement->playerRace && (unit->GetTypeId() != TYPEID_PLAYER || unit->getRace()!=requirement->playerRace)) - continue; + AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria); + if(!data) + continue; - if (requirement->playerClass && (unit->GetTypeId() != TYPEID_PLAYER || unit->getClass()!=requirement->playerClass)) - continue; - } + if(!data->Meets(GetPlayer(),unit)) + continue; SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; @@ -966,6 +1061,13 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if(IsCompletedCriteria(achievementCriteria,achievement)) CompletedCriteria(achievementCriteria,achievement); + // check again the completeness for SUMM and REQ COUNT achievements, + // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria + if (achievement->flags & ACHIEVEMENT_FLAG_SUMM) + { + if (IsCompletedAchievement(achievement)) + CompletedAchievement(achievement); + } if(AchievementEntryList const* achRefList = achievementmgr.GetAchievementByReferencedId(achievement->ID)) { @@ -1111,9 +1213,12 @@ void AchievementMgr::CompletedCriteria(AchievementCriteriaEntry const* criteria, CompletedAchievement(achievement); } -// TODO: achievement 705 requires 4 criteria to be fulfilled bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) { + // counter can never complete + if(entry->flags & ACHIEVEMENT_FLAG_COUNTER) + return false; + // for achievement with referenced achievement criterias get from referenced and counter from self uint32 achievmentForTestId = entry->refAchievement ? entry->refAchievement : entry->ID; uint32 achievmentForTestCount = entry->count; @@ -1121,10 +1226,32 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) AchievementCriteriaEntryList const* cList = achievementmgr.GetAchievementCriteriaByAchievement(achievmentForTestId); if(!cList) return false; - uint32 count = 0; - bool completed_all = true; + // For SUMM achievements, we have to count the progress of each criteria of the achievement. + // Oddly, the target count is NOT countained in the achievement, but in each individual criteria + if (entry->flags & ACHIEVEMENT_FLAG_SUMM) + { + for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) + { + AchievementCriteriaEntry const* criteria = *itr; + + CriteriaProgressMap::const_iterator itrProgress = m_criteriaProgress.find(criteria->ID); + if(itrProgress == m_criteriaProgress.end()) + continue; + + CriteriaProgress const* progress = &itrProgress->second; + count += progress->counter; + + // for counters, field4 contains the main count requirement + if (count >= criteria->raw.count) + return true; + } + return false; + } + + // Default case - need complete all or + bool completed_all = true; for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) { AchievementCriteriaEntry const* criteria = *itr; @@ -1388,6 +1515,83 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() sLog.outString(">> Loaded %u achievement references.",count); } +void AchievementGlobalMgr::LoadAchievementCriteriaData() +{ + m_criteriaDataMap.clear(); // need for reload case + + QueryResult *result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2 FROM achievement_criteria_data"); + + if(!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty."); + return; + } + + uint32 count = 0; + barGoLink bar(result->GetRowCount()); + do + { + bar.step(); + Field *fields = result->Fetch(); + uint32 criteria_id = fields[0].GetUInt32(); + + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id); + + if (!criteria) + { + sLog.outErrorDb( "Table `achievement_criteria_data` have data for not existed criteria (Entry: %u), ignore.", criteria_id); + continue; + } + + AchievementCriteriaData data(fields[1].GetUInt32(),fields[2].GetUInt32(),fields[3].GetUInt32()); + + if(!data.IsValid(criteria)) + continue; + + // this will allocate empty data set storage + AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id]; + + // add real data only for not NONE data types + if(data.dataType!=ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE) + dataSet.Add(data); + + // counting data by and data types + ++count; + } while(result->NextRow()); + + delete result; + + // post loading checks + for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) + { + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId); + if(!criteria) + continue; + + switch(criteria->requiredType) + { + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + if(!GetCriteriaDataSet(criteria)) + sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType); + break; + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases + if(criteria->do_emote.count && !GetCriteriaDataSet(criteria)) + sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType); + break; + default: // unexpected case processed in IsValid check + break; + } + + } + + sLog.outString(); + sLog.outString(">> Loaded %u additional achievement criteria data.",count); +} + void AchievementGlobalMgr::LoadCompletedAchievements() { QueryResult *result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement"); @@ -1418,7 +1622,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements() void AchievementGlobalMgr::LoadRewards() { - m_achievementRewards.clear(); // need for reload case + m_achievementRewards.clear(); // need for reload case // 0 1 2 3 4 5 6 QueryResult *result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text FROM achievement_reward"); @@ -1434,6 +1638,7 @@ void AchievementGlobalMgr::LoadRewards() return; } + uint32 count = 0; barGoLink bar(result->GetRowCount()); do @@ -1517,13 +1722,14 @@ void AchievementGlobalMgr::LoadRewards() } m_achievementRewards[entry] = reward; + ++count; } while (result->NextRow()); delete result; sLog.outString(); - sLog.outString( ">> Loaded %lu achievement reward locale strings", (unsigned long)m_achievementRewardLocales.size() ); + sLog.outString( ">> Loaded %u achievement rewards", count ); } void AchievementGlobalMgr::LoadRewardLocales() diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index b45c63f7301..391afedbb46 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -27,9 +27,6 @@ #include <map> #include <string> -#define CRITERIA_CAST_SPELL_REQ_COUNT 46 -#define ACHIEVEMENT_REWARD_COUNT 57 - typedef std::list<AchievementCriteriaEntry const*> AchievementCriteriaEntryList; typedef std::list<AchievementEntry const*> AchievementEntryList; @@ -43,14 +40,92 @@ struct CriteriaProgress bool changed; }; -struct CriteriaCastSpellRequirement +enum AchievementCriteriaDataType +{ // value1 value2 comment + ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4, // 0 0 not corpse (not released body) + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx +}; + +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 8 // maximum value in AchievementCriteriaDataType enum + +class Player; +class Unit; + +struct AchievementCriteriaData +{ + AchievementCriteriaDataType dataType; + union + { + // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE + struct + { + uint32 id; + } creature; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE + struct + { + uint32 class_id; + uint32 race_id; + } classRace; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH + struct + { + uint32 percent; + } health; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA + // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA + struct + { + uint32 spell_id; + uint32 effect_idx; + } aura; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA + struct + { + uint32 id; + } area; + // ... + struct + { + uint32 value1; + uint32 value2; + } raw; + }; + + AchievementCriteriaData() : dataType(ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE) + { + raw.value1 = 0; + raw.value2 = 0; + } + + AchievementCriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2) : dataType(AchievementCriteriaDataType(_dataType)) + { + raw.value1 = _value1; + raw.value2 = _value2; + } + + bool IsValid(AchievementCriteriaEntry const* criteria); + bool Meets(Player const* source, Unit const* target) const; +}; + +struct AchievementCriteriaDataSet { - uint32 achievementCriteriaId; - uint32 creatureEntry; - uint8 playerClass; - uint8 playerRace; + typedef std::vector<AchievementCriteriaData> Storage; + void Add(AchievementCriteriaData const& data) { storage.push_back(data); } + bool Meets(Player const* source, Unit const* target) const; + private: + Storage storage; }; + +typedef std::map<uint32,AchievementCriteriaDataSet> AchievementCriteriaDataMap; + struct AchievementReward { uint32 titleId[2]; @@ -145,13 +220,10 @@ class AchievementGlobalMgr return iter!=m_achievementRewardLocales.end() ? &iter->second : NULL; } - static CriteriaCastSpellRequirement const * GetCriteriaCastSpellRequirement(AchievementCriteriaEntry const *achievementCriteria) + AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const *achievementCriteria) { - for (uint32 i=0; i < CRITERIA_CAST_SPELL_REQ_COUNT; ++i) - if (m_criteriaCastSpellRequirements[i].achievementCriteriaId == achievementCriteria->ID) - return &m_criteriaCastSpellRequirements[i]; - - return NULL; + AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID); + return iter!=m_criteriaDataMap.end() ? &iter->second : NULL; } bool IsRealmCompleted(AchievementEntry const* achievement) const @@ -165,12 +237,13 @@ class AchievementGlobalMgr } void LoadAchievementCriteriaList(); + void LoadAchievementCriteriaData(); void LoadAchievementReferenceList(); void LoadCompletedAchievements(); void LoadRewards(); void LoadRewardLocales(); private: - static const CriteriaCastSpellRequirement m_criteriaCastSpellRequirements[]; + AchievementCriteriaDataMap m_criteriaDataMap; // store achievement criterias by type to speed up lookup AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 9add7ed98da..fffedb56ad8 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -46,7 +46,7 @@ namespace MaNGOS { char const* text = objmgr.GetMangosString(i_textId,loc_idx); - if(i_args) + if (i_args) { // we need copy va_list before use or original va_list will corrupted va_list ap; @@ -121,7 +121,7 @@ template<class Do> void BattleGround::BroadcastWorker(Do& _do) { for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - if(Player *plr = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) + if (Player *plr = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) _do(plr); } @@ -223,8 +223,8 @@ BattleGround::~BattleGround() sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID()); // unload map - if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) - if(map->IsBattleGroundOrArena()) + if (Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) + if (map->IsBattleGroundOrArena()) ((BattleGroundMap*)map)->SetUnload(); // remove from bg free slot queue this->RemoveFromBGFreeSlotQueue(); @@ -232,17 +232,17 @@ BattleGround::~BattleGround() void BattleGround::Update(uint32 diff) { - if(!GetPlayersSize() && !GetReviveQueueSize()) + if (!GetPlayersSize() && !GetReviveQueueSize()) //BG is empty return; // remove offline players from bg after 5 minutes - if( !m_OfflineQueue.empty() ) + if (!m_OfflineQueue.empty()) { BattleGroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin())); - if( itr != m_Players.end() ) + if (itr != m_Players.end()) { - if( itr->second.OfflineRemoveTime <= sWorld.GetGameTime() ) + if (itr->second.OfflineRemoveTime <= sWorld.GetGameTime()) { RemovePlayerAtLeave(itr->first, true, true);// remove player from BG m_OfflineQueue.pop_front(); // remove from offline queue @@ -259,7 +259,7 @@ void BattleGround::Update(uint32 diff) m_LastResurrectTime += diff; if (m_LastResurrectTime >= RESURRECTION_INTERVAL) { - if(GetReviveQueueSize()) + if (GetReviveQueueSize()) { for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr) { @@ -267,7 +267,7 @@ void BattleGround::Update(uint32 diff) for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2) { Player *plr = objmgr.GetPlayer(*itr2); - if(!plr) + if (!plr) continue; if (!sh) @@ -296,7 +296,7 @@ void BattleGround::Update(uint32 diff) for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) { Player *plr = objmgr.GetPlayer(*itr); - if(!plr) + if (!plr) continue; plr->ResurrectPlayer(1.0f); plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true); @@ -310,20 +310,20 @@ void BattleGround::Update(uint32 diff) /*********************************************************/ // if less then minimum players are in on one side, then start premature finish timer - if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) + if (GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) { - if(!m_PrematureCountDown) + if (!m_PrematureCountDown) { m_PrematureCountDown = true; m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime(); } - else if(m_PrematureCountDownTimer < diff) + else if (m_PrematureCountDownTimer < diff) { // time's up! uint32 winner = 0; - if( GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam() ) + if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam()) winner = ALLIANCE; - else if( GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam() ) + else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam()) winner = HORDE; EndBattleGround(winner); @@ -333,15 +333,15 @@ void BattleGround::Update(uint32 diff) { uint32 newtime = m_PrematureCountDownTimer - diff; // announce every minute - if( newtime > (MINUTE * IN_MILISECONDS) ) + if (newtime > (MINUTE * IN_MILISECONDS)) { - if( newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS) ) + if (newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS)) PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS))); } else { //announce every 15 seconds - if( newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS) ) + if (newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS)) PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS)); } m_PrematureCountDownTimer = newtime; @@ -363,7 +363,7 @@ void BattleGround::Update(uint32 diff) m_Events |= BG_STARTING_EVENT_1; // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) + if (!SetupBattleGround()) { EndNow(); return; @@ -398,12 +398,12 @@ void BattleGround::Update(uint32 diff) SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]); //remove preparation - if( isArena() ) + if (isArena()) { //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START); for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player *plr = objmgr.GetPlayer(itr->first)) + if (Player *plr = objmgr.GetPlayer(itr->first)) plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); CheckArenaWinConditions(); @@ -414,10 +414,10 @@ void BattleGround::Update(uint32 diff) PlaySoundToAll(SOUND_BG_START); for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player* plr = objmgr.GetPlayer(itr->first)) + if (Player* plr = objmgr.GetPlayer(itr->first)) plr->RemoveAurasDueToSpell(SPELL_PREPARATION); //Announce BG starting - if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) + if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE)) { sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel()); } @@ -429,11 +429,11 @@ void BattleGround::Update(uint32 diff) /*** BATTLEGROUND ENDING SYSTEM ***/ /*********************************************************/ - if(GetStatus() == STATUS_WAIT_LEAVE) + if (GetStatus() == STATUS_WAIT_LEAVE) { // remove all players from battleground after 2 minutes m_EndTime -= diff; - if( m_EndTime <= 0) + if (m_EndTime <= 0) { m_EndTime = 0; BattleGroundPlayerMap::iterator itr, next; @@ -466,7 +466,7 @@ void BattleGround::SendPacketToAll(WorldPacket *packet) for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); - if(plr) + if (plr) plr->GetSession()->SendPacket(packet); else sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); @@ -479,19 +479,19 @@ void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player * { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr) + if (!plr) { sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; } - if(!self && sender == plr) + if (!self && sender == plr) continue; uint32 team = itr->second.Team; if(!team) team = plr->GetTeam(); - if(team == TeamID) + if (team == TeamID) plr->GetSession()->SendPacket(packet); } } @@ -511,7 +511,7 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID) { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr) + if (!plr) { sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; @@ -520,7 +520,7 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID) uint32 team = itr->second.Team; if(!team) team = plr->GetTeam(); - if(team == TeamID) + if (team == TeamID) { sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID); plr->GetSession()->SendPacket(&data); @@ -534,7 +534,7 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID) { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr) + if (!plr) { sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; @@ -543,7 +543,7 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID) uint32 team = itr->second.Team; if(!team) team = plr->GetTeam(); - if(team == TeamID) + if (team == TeamID) plr->CastSpell(plr, SpellID, true); } } @@ -571,7 +571,7 @@ void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID) { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr) + if (!plr) { sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; @@ -580,7 +580,7 @@ void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID) uint32 team = itr->second.Team; if(!team) team = plr->GetTeam(); - if(team == TeamID) + if (team == TeamID) UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor); } } @@ -589,14 +589,14 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, { FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id); - if(!factionEntry) + if (!factionEntry) return; for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr) + if (!plr) { sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; @@ -605,7 +605,7 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 team = itr->second.Team; if(!team) team = plr->GetTeam(); - if(team == TeamID) + if (team == TeamID) plr->GetReputationMgr().ModifyReputation(factionEntry, Reputation); } } @@ -635,7 +635,7 @@ void BattleGround::EndBattleGround(uint32 winner) WorldPacket data; int32 winmsg_id = 0; - if(winner == ALLIANCE) + if (winner == ALLIANCE) { winmsg_id = isBattleGround() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS; @@ -643,7 +643,7 @@ void BattleGround::EndBattleGround(uint32 winner) SetWinner(WINNER_ALLIANCE); } - else if(winner == HORDE) + else if (winner == HORDE) { winmsg_id = isBattleGround() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS; @@ -661,11 +661,11 @@ void BattleGround::EndBattleGround(uint32 winner) m_EndTime = TIME_TO_AUTOREMOVE; // arena rating calculation - if(isArena() && isRated()) + if (isArena() && isRated()) { winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner)); loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner))); - if( winner_arena_team && loser_arena_team ) + if (winner_arena_team && loser_arena_team) { loser_rating = loser_arena_team->GetStats().rating; winner_rating = winner_arena_team->GetStats().rating; @@ -687,12 +687,12 @@ void BattleGround::EndBattleGround(uint32 winner) Player *plr = objmgr.GetPlayer(itr->first); uint32 team = itr->second.Team; - if(!plr) + if (!plr) { //if rated arena match - make member lost! - if(isArena() && isRated() && winner_arena_team && loser_arena_team) + if (isArena() && isRated() && winner_arena_team && loser_arena_team) { - if(team == winner) + if (team == winner) winner_arena_team->OfflineMemberLost(itr->first, loser_rating); else loser_arena_team->OfflineMemberLost(itr->first, winner_rating); @@ -705,7 +705,7 @@ void BattleGround::EndBattleGround(uint32 winner) if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) plr->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); - if(!plr->isAlive()) + if (!plr->isAlive()) { plr->ResurrectPlayer(1.0f); plr->SpawnCorpseBones(); @@ -715,15 +715,15 @@ void BattleGround::EndBattleGround(uint32 winner) //if(!team) team = plr->GetTeam(); // per player calculation - if(isArena() && isRated() && winner_arena_team && loser_arena_team) + if (isArena() && isRated() && winner_arena_team && loser_arena_team) { - if(team == winner) + if (team == winner) winner_arena_team->MemberWon(plr,loser_rating); else loser_arena_team->MemberLost(plr,winner_rating); } - if(team == winner) + if (team == winner) { RewardMark(plr,ITEM_WINNER_COUNT); RewardQuest(plr); @@ -746,7 +746,7 @@ void BattleGround::EndBattleGround(uint32 winner) plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } - if(isArena() && isRated() && winner_arena_team && loser_arena_team) + if (isArena() && isRated() && winner_arena_team && loser_arena_team) { // update arena points only after increasing the player's match count! //obsolete: winner_arena_team->UpdateArenaPointsHelper(); @@ -760,10 +760,7 @@ void BattleGround::EndBattleGround(uint32 winner) loser_arena_team->NotifyStatsChanged(); } - // inform invited players about the removal - sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); - - if(winmsg_id) + if (winmsg_id) SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL); } @@ -789,7 +786,7 @@ uint32 BattleGround::GetBattlemasterEntry() const void BattleGround::RewardMark(Player *plr,uint32 count) { // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) return; if(!plr || !count) @@ -826,7 +823,7 @@ void BattleGround::RewardMark(Player *plr,uint32 count) if(Item* item = plr->StoreNewItem( dest, mark, true, 0)) plr->SendNewItem(item,count,false,true); - if(no_space_count > 0) + if (no_space_count > 0) SendRewardMarkByMail(plr,mark,no_space_count); } } @@ -834,14 +831,14 @@ void BattleGround::RewardMark(Player *plr,uint32 count) void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) { uint32 bmEntry = GetBattlemasterEntry(); - if(!bmEntry) + if (!bmEntry) return; ItemPrototype const* markProto = objmgr.GetItemPrototype(mark); - if(!markProto) + if (!markProto) return; - if(Item* markItem = Item::CreateItem(mark,count,plr)) + if (Item* markItem = Item::CreateItem(mark,count,plr)) { // save new item before send markItem->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted @@ -853,8 +850,8 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) // subject: item name std::string subject = markProto->Name1; int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex(); - if ( loc_idx >= 0 ) - if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId)) + if (loc_idx >= 0 ) + if (ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId)) if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) subject = il->Name[loc_idx]; @@ -871,7 +868,7 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) void BattleGround::RewardQuest(Player *plr) { // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) return; uint32 quest; @@ -907,7 +904,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac bool participant = false; // Remove from lists/maps BattleGroundPlayerMap::iterator itr = m_Players.find(guid); - if(itr != m_Players.end()) + if (itr != m_Players.end()) { UpdatePlayersCountByTeam(team, true); // -1 player m_Players.erase(itr); @@ -916,7 +913,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac } std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid); - if(itr2 != m_PlayerScores.end()) + if (itr2 != m_PlayerScores.end()) { delete itr2->second; // delete player's score m_PlayerScores.erase(itr2); @@ -942,38 +939,32 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac { BattleGroundTypeId bgTypeId = GetTypeID(); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); - if(plr) + if (plr) { plr->ClearAfkReports(); if(!team) team = plr->GetTeam(); // if arena, remove the specific arena auras - if(isArena()) + if (isArena()) { plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) - // summon old pet if there was one and there isn't a current pet - if(!plr->GetGuardianPet() && plr->GetTemporaryUnsummonedPetNumber()) - { - Pet* NewPet = new Pet(plr); - if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true)) - delete NewPet; + // unsummon current and summon old pet if there was one and there isn't a current pet + plr->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT); + plr->ResummonPetTemporaryUnSummonedIfAny(); - (plr)->SetTemporaryUnsummonedPetNumber(0); - } - - if(isRated() && GetStatus() == STATUS_IN_PROGRESS) + if (isRated() && GetStatus() == STATUS_IN_PROGRESS) { //left a rated match while the encounter was in progress, consider as loser ArenaTeam * winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team))); ArenaTeam * loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team)); - if(winner_arena_team && loser_arena_team) + if (winner_arena_team && loser_arena_team) loser_arena_team->MemberLost(plr,winner_arena_team->GetRating()); } } - if(SendPacket) + if (SendPacket) { WorldPacket data; sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0); @@ -986,18 +977,18 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac else // removing offline participant { - if(isRated() && GetStatus() == STATUS_IN_PROGRESS) + if (isRated() && GetStatus() == STATUS_IN_PROGRESS) { //left a rated match while the encounter was in progress, consider as loser ArenaTeam * others_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team))); ArenaTeam * players_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team)); - if( others_arena_team && players_arena_team ) + if (others_arena_team && players_arena_team) players_arena_team->OfflineMemberLost(guid, others_arena_team->GetRating()); } } // remove from raid group if player is member - if(Group *group = GetBgRaid(team)) + if (Group *group = GetBgRaid(team)) { if( !group->RemoveMember(guid, 0) ) // group was disbanded { @@ -1007,7 +998,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac } DecreaseInvitedCount(team); //we should update battleground queue, but only if bg isn't ending - if( isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE ) + if (isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); // Let others know WorldPacket data; @@ -1015,20 +1006,20 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac SendPacketToTeam(team, &data, plr, false); } - if( plr ) + if (plr) { // Do next only if found in battleground plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team plr->SetBGTeam(0); - if(Transport) + if (Transport) plr->TeleportTo(plr->GetBattleGroundEntryPoint()); sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } - if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) + if (!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) { // if no players left AND no invitees left, set this bg to delete in next update // direct deletion could cause crashes @@ -1095,40 +1086,28 @@ void BattleGround::AddPlayer(Player *plr) SendPacketToTeam(team, &data, plr, false); // add arena specific auras - if(isArena()) + if (isArena()) { plr->RemoveArenaSpellCooldowns(); plr->RemoveArenaAuras(); plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT); if(team == ALLIANCE) // gold { - if(plr->GetTeam() == HORDE) + if (plr->GetTeam() == HORDE) plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true); else plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true); } else // green { - if(plr->GetTeam() == HORDE) + if (plr->GetTeam() == HORDE) plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true); else plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true); } plr->DestroyConjuredItems(true); - - Pet* pet = plr->GetPet(); - if(pet) - { - if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET) - { - (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); - (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - } - (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); - } - else - (plr)->SetTemporaryUnsummonedPetNumber(0); + plr->UnsummonPetTemporaryIfAny(); if(GetStatus() == STATUS_WAIT_JOIN) // not started yet { @@ -1164,7 +1143,7 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, } else // raid already exist { - if(group->IsMember(plr_guid)) + if (group->IsMember(plr_guid)) { uint8 subgroup = group->GetMemberGroup(plr_guid); plr->SetBattleGroundRaid(group, subgroup); @@ -1172,8 +1151,8 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, else { group->AddMember(plr_guid, plr->GetName()); - if( Group* originalGroup = plr->GetOriginalGroup() ) - if( originalGroup->IsLeader(plr_guid) ) + if (Group* originalGroup = plr->GetOriginalGroup()) + if (originalGroup->IsLeader(plr_guid)) group->ChangeLeader(plr_guid); } } @@ -1185,7 +1164,7 @@ void BattleGround::EventPlayerLoggedIn(Player* player, uint64 plr_guid) // player is correct pointer for(std::deque<uint64>::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr) { - if( *itr == plr_guid ) + if (*itr == plr_guid) { m_OfflineQueue.erase(itr); break; @@ -1203,14 +1182,14 @@ void BattleGround::EventPlayerLoggedOut(Player* player) // player is correct pointer, it is checked in WorldSession::LogoutPlayer() m_OfflineQueue.push_back(player->GetGUID()); m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME; - if( GetStatus() == STATUS_IN_PROGRESS ) + if (GetStatus() == STATUS_IN_PROGRESS) { - if( isBattleGround() ) + if (isBattleGround()) EventPlayerDroppedFlag(player); else { //1 player is logging out, if it is the last, then end arena! - if( GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())) ) + if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) EndBattleGround(GetOtherTeam(player->GetTeam())); } } @@ -1220,7 +1199,7 @@ void BattleGround::EventPlayerLoggedOut(Player* player) void BattleGround::AddToBGFreeSlotQueue() { // make sure to add only once - if(!m_InBGFreeSlotQueue && isBattleGround()) + if (!m_InBGFreeSlotQueue && isBattleGround()) { sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this); m_InBGFreeSlotQueue = true; @@ -1280,10 +1259,10 @@ void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) break; case SCORE_BONUS_HONOR: // Honor bonus // do not add honor in arenas - if(isBattleGround()) + if (isBattleGround()) { // reward honor instantly - if(Source->RewardHonor(NULL, 1, value)) + if (Source->RewardHonor(NULL, 1, value)) itr->second->BonusHonor += value; } break; @@ -1305,12 +1284,11 @@ void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid m_ReviveQueue[npc_guid].push_back(player_guid); Player *plr = objmgr.GetPlayer(player_guid); - if(!plr) + if (!plr) return; - plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true); SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT ); - if(spellInfo) + if (spellInfo) { Aura *Aur = new Aura(spellInfo, 1, NULL, plr); plr->AddAura(Aur); @@ -1323,12 +1301,12 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid) { for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2) { - if(*itr2 == player_guid) + if (*itr2 == player_guid) { (itr->second).erase(itr2); Player *plr = objmgr.GetPlayer(player_guid); - if(!plr) + if (!plr) return; plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT); @@ -1342,7 +1320,7 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid) bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime) { Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if(!map) + if (!map) return false; // must be created this way, adding to godatamap would add it to the base map of the instance @@ -1380,7 +1358,7 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float data.go_state = 1; */ // add to world, so it can be later looked up from HashMapHolder - go->AddToWorld(); + map->Add(go); m_BgObjects[type] = go->GetGUID(); return true; } @@ -1390,10 +1368,10 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float void BattleGround::DoorClose(uint32 type) { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); - if(obj) + if (obj) { //if doors are open, close it - if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() ) + if (obj->getLootState() == GO_ACTIVATED && !obj->GetGoState()) { //change state to allow door to be closed obj->SetLootState(GO_READY); @@ -1409,7 +1387,7 @@ void BattleGround::DoorClose(uint32 type) void BattleGround::DoorOpen(uint32 type) { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); - if(obj) + if (obj) { //change state to be sure they will be opened obj->SetLootState(GO_READY); @@ -1440,15 +1418,15 @@ Creature* BattleGround::GetBGCreature(uint32 type) void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) { Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if(!map) + if (!map) return; - if( respawntime == 0 ) + if (respawntime == 0) { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); - if(obj) + if (obj) { //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again - if( obj->getLootState() == GO_JUST_DEACTIVATED ) + if (obj->getLootState() == GO_JUST_DEACTIVATED) obj->SetLootState(GO_READY); obj->SetRespawnTime(0); map->Add(obj); @@ -1457,7 +1435,7 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) else { GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); - if(obj) + if (obj) { map->Add(obj); obj->SetRespawnTime(respawntime); @@ -1469,7 +1447,7 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime) { Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if(!map) + if (!map) return NULL; Creature* pCreature = new Creature; @@ -1482,7 +1460,7 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f pCreature->Relocate(x, y, z, o); - if(!pCreature->IsPositionValid()) + if (!pCreature->IsPositionValid()) { sLog.outError("Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY()); delete pCreature; @@ -1502,13 +1480,13 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime) { Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId()); - if(!map) + if (!map) return false; - if(respawntime == 0) + if (respawntime == 0) { Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]); - if(obj) + if (obj) { //obj->Respawn(); // bugged obj->SetRespawnTime(0); @@ -1519,7 +1497,7 @@ void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime) else { Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]); - if(obj) + if (obj) { obj->setDeathState(DEAD); obj->SetRespawnTime(respawntime); @@ -1530,11 +1508,11 @@ void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime) */ bool BattleGround::DelCreature(uint32 type) { - if(!m_BgCreatures[type]) + if (!m_BgCreatures[type]) return true; Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]); - if(!cr) + if (!cr) { sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type])); return false; @@ -1548,11 +1526,11 @@ bool BattleGround::DelCreature(uint32 type) bool BattleGround::DelObject(uint32 type) { - if(!m_BgObjects[type]) + if (!m_BgObjects[type]) return true; GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); - if(!obj) + if (!obj) { sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type])); return false; @@ -1567,13 +1545,13 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float { uint32 entry = 0; - if(team == ALLIANCE) + if (team == ALLIANCE) entry = 13116; else entry = 13117; Creature* pCreature = AddCreature(entry,type,team,x,y,z,o); - if(!pCreature) + if (!pCreature) { sLog.outError("Can't create Spirit guide. BattleGround not created!"); EndNow(); @@ -1631,8 +1609,6 @@ void BattleGround::EndNow() RemoveFromBGFreeSlotQueue(); SetStatus(STATUS_WAIT_LEAVE); SetEndTime(0); - // inform invited players about the removal - sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); } //to be removed @@ -1650,7 +1626,7 @@ buffs are in their positions when battleground starts void BattleGround::HandleTriggerBuff(uint64 const& go_guid) { GameObject *obj = HashMapHolder<GameObject>::Find(go_guid); - if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned()) + if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned()) return; //change buff type, when buff is used: @@ -1666,13 +1642,13 @@ void BattleGround::HandleTriggerBuff(uint64 const& go_guid) //randomly select new buff uint8 buff = urand(0, 2); uint32 entry = obj->GetEntry(); - if( m_BuffChange && entry != Buff_Entries[buff] ) + if (m_BuffChange && entry != Buff_Entries[buff]) { //despawn current buff SpawnBGObject(index, RESPAWN_ONE_DAY); //set index for new one for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex) - if( entry == Buff_Entries[currBuffTypeIndex] ) + if (entry == Buff_Entries[currBuffTypeIndex]) { index -= currBuffTypeIndex; index += buff; @@ -1690,7 +1666,7 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) UpdatePlayerScore(player, SCORE_DEATHS, 1); // add +1 kills to group and +1 killing_blows to killer - if( killer ) + if (killer) { UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1); UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1); @@ -1699,16 +1675,16 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) { Player *plr = objmgr.GetPlayer(itr->first); - if(!plr || plr == killer) + if (!plr || plr == killer) continue; - if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) ) + if (plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player)) UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1); } } // to be able to remove insignia -- ONLY IN BattleGrounds - if( !isArena() ) + if (!isArena()) player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE ); } @@ -1717,7 +1693,7 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) uint32 BattleGround::GetPlayerTeam(uint64 guid) { BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid); - if(itr!=m_Players.end()) + if (itr!=m_Players.end()) return itr->second.Team; return 0; } @@ -1730,14 +1706,14 @@ uint32 BattleGround::GetOtherTeam(uint32 teamId) bool BattleGround::IsPlayerInBattleGround(uint64 guid) { BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid); - if(itr != m_Players.end()) + if (itr != m_Players.end()) return true; return false; } void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr) { - if(GetStatus() != STATUS_WAIT_LEAVE) + if (GetStatus() != STATUS_WAIT_LEAVE) return; WorldPacket data; @@ -1757,10 +1733,10 @@ uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const int count = 0; for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { - if(itr->second.Team == Team) + if (itr->second.Team == Team) { Player * pl = objmgr.GetPlayer(itr->first); - if(pl && pl->isAlive()) + if (pl && pl->isAlive()) ++count; } } @@ -1790,9 +1766,9 @@ void BattleGround::HandleKillUnit(Creature *creature, Player *killer) void BattleGround::CheckArenaWinConditions() { - if( !GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE) ) + if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) EndBattleGround(HORDE); - else if( GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE) ) + else if (GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE)) EndBattleGround(ALLIANCE); } diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index d33eb76e02c..9788f264502 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -361,7 +361,7 @@ class BattleGround void IncreaseInvitedCount(uint32 team) { (team == ALLIANCE) ? ++m_InvitedAlliance : ++m_InvitedHorde; } uint32 GetInvitedCount(uint32 team) const { - if( team == ALLIANCE ) + if (team == ALLIANCE) return m_InvitedAlliance; else return m_InvitedHorde; @@ -444,7 +444,7 @@ class BattleGround uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases void UpdatePlayersCountByTeam(uint32 Team, bool remove) { - if(remove) + if (remove) --m_PlayersCount[GetTeamIndexByTeamId(Team)]; else ++m_PlayersCount[GetTeamIndexByTeamId(Team)]; diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp index 90bbd411773..40f60960377 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -60,16 +60,16 @@ void BattleGroundAB::Update(uint32 diff) { BattleGround::Update(diff); - if( GetStatus() == STATUS_IN_PROGRESS ) + if (GetStatus() == STATUS_IN_PROGRESS) { int team_points[BG_TEAMS_COUNT] = { 0, 0 }; for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) { // 3 sec delay to spawn new banner instead previous despawned one - if( m_BannerTimers[node].timer ) + if (m_BannerTimers[node].timer) { - if( m_BannerTimers[node].timer > diff ) + if (m_BannerTimers[node].timer > diff) m_BannerTimers[node].timer -= diff; else { @@ -79,9 +79,9 @@ void BattleGroundAB::Update(uint32 diff) } // 1-minute to occupy a node from contested state - if( m_NodeTimers[node] ) + if (m_NodeTimers[node]) { - if( m_NodeTimers[node] > diff ) + if (m_NodeTimers[node] > diff) m_NodeTimers[node] -= diff; else { @@ -98,7 +98,7 @@ void BattleGroundAB::Update(uint32 diff) _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); // Message to chatlog - if(teamIndex == 0) + if (teamIndex == 0) { // FIXME: team and node names not localized SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node)); @@ -114,7 +114,7 @@ void BattleGroundAB::Update(uint32 diff) } for (int team = 0; team < BG_TEAMS_COUNT; ++team) - if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED ) + if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED) ++team_points[team]; } @@ -122,28 +122,28 @@ void BattleGroundAB::Update(uint32 diff) for (int team = 0; team < BG_TEAMS_COUNT; ++team) { int points = team_points[team]; - if( !points ) + if (!points) continue; m_lastTick[team] += diff; - if( m_lastTick[team] > BG_AB_TickIntervals[points] ) + if (m_lastTick[team] > BG_AB_TickIntervals[points]) { m_lastTick[team] -= BG_AB_TickIntervals[points]; m_TeamScores[team] += BG_AB_TickPoints[points]; m_HonorScoreTics[team] += BG_AB_TickPoints[points]; m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; - if( m_ReputationScoreTics[team] >= m_ReputationTics ) + if (m_ReputationScoreTics[team] >= m_ReputationTics) { (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); m_ReputationScoreTics[team] -= m_ReputationTics; } - if( m_HonorScoreTics[team] >= m_HonorTics ) + if (m_HonorScoreTics[team] >= m_HonorTics) { RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); m_HonorScoreTics[team] -= m_HonorTics; } - if( !m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE ) + if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE) { - if( team == BG_TEAM_ALLIANCE ) + if (team == BG_TEAM_ALLIANCE) SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); else SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); @@ -151,19 +151,19 @@ void BattleGroundAB::Update(uint32 diff) m_IsInformedNearVictory = true; } - if( m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE ) + if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE) m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE; - if( team == BG_TEAM_ALLIANCE ) + if (team == BG_TEAM_ALLIANCE) UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); - if( team == BG_TEAM_HORDE ) + if (team == BG_TEAM_HORDE) UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]); } } // Test win condition - if( m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE ) + if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE) EndBattleGround(ALLIANCE); - if( m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE ) + if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE) EndBattleGround(HORDE); } } @@ -218,19 +218,19 @@ void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger) { - if( GetStatus() != STATUS_IN_PROGRESS ) + if (GetStatus() != STATUS_IN_PROGRESS) return; switch(Trigger) { case 3948: // Arathi Basin Alliance Exit. - if( Source->GetTeam() != ALLIANCE ) + if (Source->GetTeam() != ALLIANCE) Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); else Source->LeaveBattleground(); break; case 3949: // Arathi Basin Horde Exit. - if( Source->GetTeam() != HORDE ) + if (Source->GetTeam() != HORDE) Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); else Source->LeaveBattleground(); @@ -255,7 +255,7 @@ void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay) { // Just put it into the queue - if( delay ) + if (delay) { m_BannerTimers[node].timer = 2000; m_BannerTimers[node].type = type; @@ -268,7 +268,7 @@ void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool SpawnBGObject(obj, RESPAWN_IMMEDIATELY); // handle aura with banner - if( !type ) + if (!type) return; obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); SpawnBGObject(obj, RESPAWN_IMMEDIATELY); @@ -280,7 +280,7 @@ void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex) SpawnBGObject(obj, RESPAWN_ONE_DAY); // handle aura with banner - if( !type ) + if (!type) return; obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); SpawnBGObject(obj, RESPAWN_ONE_DAY); @@ -317,9 +317,9 @@ void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) // How many bases each team owns uint8 ally = 0, horde = 0; for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) - if( m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED ) + if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ++ally; - else if( m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED ) + else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) ++horde; data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally); @@ -340,7 +340,7 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node) // Send node owner state update to refresh map icons on client const uint8 plusArray[] = {0, 2, 3, 0, 1}; - if( m_prevNodes[node] ) + if (m_prevNodes[node]) UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0); else UpdateWorldState(BG_AB_OP_NODEICONS[node], 0); @@ -350,9 +350,9 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node) // How many bases each team owns uint8 ally = 0, horde = 0; for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - if( m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED ) + if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ++ally; - else if( m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED ) + else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) ++horde; UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally); @@ -361,30 +361,30 @@ void BattleGroundAB::_SendNodeUpdate(uint8 node) void BattleGroundAB::_NodeOccupied(uint8 node,Team team) { - if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) ) + if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team)) sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team); // SpawnBGCreature(node,RESPAWN_IMMEDIATELY); uint8 capturedNodes = 0; for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) { - if( m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i]) + if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i]) ++capturedNodes; } - if(capturedNodes >= 5) + if (capturedNodes >= 5) CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team); - if(capturedNodes >= 4) + if (capturedNodes >= 4) CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team); } void BattleGroundAB::_NodeDeOccupied(uint8 node) { - if( node >= BG_AB_DYNAMIC_NODES_COUNT) + if (node >= BG_AB_DYNAMIC_NODES_COUNT) return; // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]]; - if( !ghost_list.empty() ) + if (!ghost_list.empty()) { WorldSafeLocsEntry const *ClosestGrave = NULL; for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) @@ -401,7 +401,7 @@ void BattleGroundAB::_NodeDeOccupied(uint8 node) } } - if( m_BgCreatures[node] ) + if (m_BgCreatures[node]) DelCreature(node); // buff object isn't despawned @@ -410,7 +410,7 @@ void BattleGroundAB::_NodeDeOccupied(uint8 node) /* Invoked if a player used a banner as a gameobject */ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/) { - if( GetStatus() != STATUS_IN_PROGRESS ) + if (GetStatus() != STATUS_IN_PROGRESS) return; uint8 node = BG_AB_NODE_STABLES; @@ -421,7 +421,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]); } - if( node == BG_AB_DYNAMIC_NODES_COUNT) + if (node == BG_AB_DYNAMIC_NODES_COUNT) { // this means our player isn't close to any of banners - maybe cheater ?? return; @@ -430,13 +430,13 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam()); // Check if player really could use this banner, not cheated - if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) ) + if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2)) return; source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); uint32 sound = 0; // If node is neutral, change to contested - if( m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL ) + if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL) { UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); m_prevNodes[node] = m_Nodes[node]; @@ -449,7 +449,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; // FIXME: team and node names not localized - if(teamIndex == 0) + if (teamIndex == 0) SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY); else SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE); @@ -457,10 +457,10 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ sound = BG_AB_SOUND_NODE_CLAIMED; } // If node is contested - else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) ) + else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED)) { // If last state is NOT occupied, change node to enemy-contested - if( m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED ) + if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED) { UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); m_prevNodes[node] = m_Nodes[node]; @@ -473,7 +473,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; // FIXME: node names not localized - if(teamIndex == 0) + if (teamIndex == 0) SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); @@ -493,7 +493,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); // FIXME: node names not localized - if(teamIndex == 0) + if (teamIndex == 0) SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); @@ -515,7 +515,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; // FIXME: node names not localized - if(teamIndex == 0) + if (teamIndex == 0) SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); @@ -524,10 +524,10 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ } // If node is occupied again, send "X has taken the Y" msg. - if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED ) + if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED) { // FIXME: team and node names not localized - if(teamIndex == 0) + if (teamIndex == 0) SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node)); @@ -539,7 +539,7 @@ bool BattleGroundAB::SetupBattleGround() { for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) { - if( !AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) @@ -553,7 +553,7 @@ bool BattleGroundAB::SetupBattleGround() return false; } } - if( !AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY) + if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY) || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY) ) { @@ -563,7 +563,7 @@ bool BattleGroundAB::SetupBattleGround() //buffs for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) { - if( !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) + if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) ) @@ -600,16 +600,16 @@ void BattleGroundAB::Reset() } for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i) - if(m_BgCreatures[i]) + if (m_BgCreatures[i]) DelCreature(i); } void BattleGroundAB::EndBattleGround(uint32 winner) { //win reward - if( winner == ALLIANCE ) + if (winner == ALLIANCE) RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - if( winner == HORDE ) + if (winner == HORDE) RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); //complete map_end rewards (even if no team wins) RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); @@ -625,12 +625,12 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) // Is there any occupied node for this team? std::vector<uint8> nodes; for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - if( m_Nodes[i] == teamIndex + 3 ) + if (m_Nodes[i] == teamIndex + 3) nodes.push_back(i); WorldSafeLocsEntry const* good_entry = NULL; // If so, select the closest node to place ghost on - if( !nodes.empty() ) + if (!nodes.empty()) { float plr_x = player->GetPositionX(); float plr_y = player->GetPositionY(); @@ -639,10 +639,10 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) for (uint8 i = 0; i < nodes.size(); ++i) { WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] ); - if( !entry ) + if (!entry) continue; float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y); - if( mindist > dist ) + if (mindist > dist) { mindist = dist; good_entry = entry; @@ -651,7 +651,7 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) nodes.clear(); } // If not, place ghost on starting location - if( !good_entry ) + if (!good_entry) good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] ); return good_entry; diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp index 6320623f453..bc0b50d21f0 100644 --- a/src/game/BattleGroundAV.cpp +++ b/src/game/BattleGroundAV.cpp @@ -543,7 +543,7 @@ void BattleGroundAV::RemovePlayer(Player* plr,uint64 /*guid*/) void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; uint32 SpellId = 0; @@ -576,7 +576,7 @@ void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger) break; } - if(SpellId) + if (SpellId) Source->CastSpell(Source, SpellId, true); } diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp index f417c353c1c..dd45b78d924 100644 --- a/src/game/BattleGroundBE.cpp +++ b/src/game/BattleGroundBE.cpp @@ -50,7 +50,7 @@ void BattleGroundBE::Update(uint32 diff) { BattleGround::Update(diff); - /*if(GetStatus() == STATUS_IN_PROGRESS) + /*if (GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ @@ -88,7 +88,7 @@ void BattleGroundBE::AddPlayer(Player *plr) void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) { - if(GetStatus() == STATUS_WAIT_LEAVE) + if (GetStatus() == STATUS_WAIT_LEAVE) return; UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE)); @@ -99,10 +99,10 @@ void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; - if(!killer) + if (!killer) { sLog.outError("Killer player not found"); return; @@ -125,7 +125,7 @@ bool BattleGroundBE::HandlePlayerUnderMap(Player *player) void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; //uint32 SpellId = 0; @@ -144,7 +144,7 @@ void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger) break; } - //if(buff_guid) + //if (buff_guid) // HandleTriggerBuff(buff_guid,Source); } @@ -164,7 +164,7 @@ void BattleGroundBE::Reset() bool BattleGroundBE::SetupBattleGround() { // gates - if( !AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) + if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) || !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) || !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) || !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index f50f2d332e1..04ab25c30cc 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -59,10 +59,10 @@ void BattleGroundEY::Update(uint32 diff) { BattleGround::Update(diff); - if( GetStatus() == STATUS_IN_PROGRESS ) + if (GetStatus() == STATUS_IN_PROGRESS) { m_PointAddingTimer -= diff; - if(m_PointAddingTimer <= 0) + if (m_PointAddingTimer <= 0) { m_PointAddingTimer = BG_EY_FPOINTS_TICK_TIME; if (m_TeamPointsCount[BG_TEAM_ALLIANCE] > 0) @@ -71,11 +71,11 @@ void BattleGroundEY::Update(uint32 diff) AddPoints(HORDE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_HORDE] - 1]); } - if(m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND) + if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND) { m_FlagsTimer -= diff; - if(m_FlagsTimer < 0) + if (m_FlagsTimer < 0) { m_FlagsTimer = 0; if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN) @@ -86,7 +86,7 @@ void BattleGroundEY::Update(uint32 diff) } m_TowerCapCheckTimer -= diff; - if(m_TowerCapCheckTimer <= 0) + if (m_TowerCapCheckTimer <= 0) { //check if player joined point /*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times @@ -150,7 +150,7 @@ void BattleGroundEY::CheckSomeoneJoinedPoint() while (j < m_PlayersNearPoint[EY_POINTS_MAX].size()) { Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]); - if(!plr) + if (!plr) { sLog.outError("BattleGroundEY: Player " I64FMTD " not found!", m_PlayersNearPoint[EY_POINTS_MAX][j]); ++j; @@ -184,7 +184,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint() for(uint8 i = 0; i < EY_POINTS_MAX; ++i) { obj = HashMapHolder<GameObject>::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]); - if(obj) + if (obj) { uint8 j = 0; while (j < m_PlayersNearPoint[i].size()) @@ -268,9 +268,9 @@ void BattleGroundEY::UpdateTeamScore(uint32 Team) { uint32 score = GetTeamScore(Team); //TODO there should be some sound played when one team is near victory!! - and define variables - /*if( !m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE ) + /*if (!m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE) { - if( Team == ALLIANCE ) + if (Team == ALLIANCE) SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); else SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); @@ -278,13 +278,13 @@ void BattleGroundEY::UpdateTeamScore(uint32 Team) m_IsInformedNearVictory = true; }*/ - if( score >= BG_EY_MAX_TEAM_SCORE ) + if (score >= BG_EY_MAX_TEAM_SCORE) { score = BG_EY_MAX_TEAM_SCORE; EndBattleGround(Team); } - if(Team == ALLIANCE) + if (Team == ALLIANCE) UpdateWorldState(EY_ALLIANCE_RESOURCES, score); else UpdateWorldState(EY_HORDE_RESOURCES, score); @@ -293,9 +293,9 @@ void BattleGroundEY::UpdateTeamScore(uint32 Team) void BattleGroundEY::EndBattleGround(uint32 winner) { //win reward - if( winner == ALLIANCE ) + if (winner == ALLIANCE) RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - if( winner == HORDE ) + if (winner == HORDE) RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); //complete map reward RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); @@ -306,7 +306,7 @@ void BattleGroundEY::EndBattleGround(uint32 winner) void BattleGroundEY::UpdatePointsCount(uint32 Team) { - if(Team == ALLIANCE) + if (Team == ALLIANCE) UpdateWorldState(EY_ALLIANCE_BASE, m_TeamPointsCount[BG_TEAM_ALLIANCE]); else UpdateWorldState(EY_HORDE_BASE, m_TeamPointsCount[BG_TEAM_HORDE]); @@ -318,14 +318,14 @@ void BattleGroundEY::UpdatePointsIcons(uint32 Team, uint32 Point) if (m_PointState[Point] == EY_POINT_UNDER_CONTROL) { UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 0); - if(Team == ALLIANCE) + if (Team == ALLIANCE) UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 1); else UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 1); } else { - if(Team == ALLIANCE) + if (Team == ALLIANCE) UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 0); else UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 0); @@ -350,15 +350,15 @@ void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid) for (int j = EY_POINTS_MAX; j >= 0; --j) { for(int i = 0; i < m_PlayersNearPoint[j].size(); ++i) - if(m_PlayersNearPoint[j][i] == guid) + if (m_PlayersNearPoint[j][i] == guid) m_PlayersNearPoint[j].erase(m_PlayersNearPoint[j].begin() + i); } - if(IsFlagPickedup()) + if (IsFlagPickedup()) { - if(m_FlagKeeper == guid) + if (m_FlagKeeper == guid) { - if(plr) - this->EventPlayerDroppedFlag(plr); + if (plr) + EventPlayerDroppedFlag(plr); else { SetFlagPicker(0); @@ -370,7 +370,7 @@ void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid) void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; if(!Source->isAlive()) //hack code, must be removed later @@ -379,23 +379,23 @@ void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger) switch(Trigger) { case TR_BLOOD_ELF_POINT: - if(m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam()) - if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + if (m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_BLOOD_ELF); break; case TR_FEL_REALVER_POINT: - if(m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam()) - if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + if (m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_FEL_REALVER); break; case TR_MAGE_TOWER_POINT: - if(m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam()) - if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + if (m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_MAGE_TOWER); break; case TR_DRAENEI_RUINS_POINT: - if(m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam()) - if(m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + if (m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_DRAENEI_RUINS); break; case 4512: @@ -419,7 +419,7 @@ void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger) bool BattleGroundEY::SetupBattleGround() { // doors - if( !AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY) + if (!AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY) || !AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY) // banners (alliance) || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) @@ -481,12 +481,12 @@ bool BattleGroundEY::SetupBattleGround() for (int i = 0; i < EY_POINTS_MAX; ++i) { AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(m_Points_Trigger[i]); - if( !at ) + if (!at) { sLog.outError("BattleGroundEY: Unknown trigger: %u", m_Points_Trigger[i]); continue; } - if ( !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) + if (!AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) ) @@ -495,14 +495,14 @@ bool BattleGroundEY::SetupBattleGround() WorldSafeLocsEntry const *sg = NULL; sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE); - if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE) ) + if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) { sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); return false; } sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE); - if( !sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE) ) + if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) { sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); return false; @@ -552,7 +552,7 @@ void BattleGroundEY::RespawnFlag(bool send_message) m_FlagState = BG_EY_FLAG_STATE_ON_BASE; SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY); - if(send_message) + if (send_message) { SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL); PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound... @@ -566,7 +566,7 @@ void BattleGroundEY::RespawnFlagAfterDrop() RespawnFlag(true); GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID()); - if(obj) + if (obj) obj->Delete(); else sLog.outError("BattleGroundEY: Unknown dropped flag guid: %u",GUID_LOPART(GetDroppedFlagGUID())); @@ -576,7 +576,7 @@ void BattleGroundEY::RespawnFlagAfterDrop() void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; BattleGround::HandleKillPlayer(player, killer); @@ -585,11 +585,11 @@ void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer) void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) { // if not running, do not cast things at the dropper player, neither send unnecessary messages // just take off the aura - if(IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID()) + if (IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID()) { SetFlagPicker(0); Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); @@ -597,10 +597,10 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) return; } - if(!IsFlagPickedup()) + if (!IsFlagPickedup()) return; - if(GetFlagPickerGUID() != Source->GetGUID()) + if (GetFlagPickerGUID() != Source->GetGUID()) return; SetFlagPicker(0); @@ -613,7 +613,7 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN); UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL); else SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL); @@ -621,10 +621,10 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) { - if(GetStatus() != STATUS_IN_PROGRESS || this->IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10)) + if (GetStatus() != STATUS_IN_PROGRESS || IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10)) return; - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER); PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE); @@ -645,7 +645,7 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true); Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName()); else PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName()); @@ -653,13 +653,13 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; //Natural point uint32 Team = m_PointOwnedByTeam[Point]; - if(!Team) + if (!Team) return; if (Team == ALLIANCE) @@ -697,7 +697,7 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; uint32 Team = Source->GetTeam(); @@ -731,12 +731,12 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) else SendMessageToAll(m_CapturingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); - if(m_BgCreatures[Point]) + if (m_BgCreatures[Point]) DelCreature(Point); WorldSafeLocsEntry const *sg = NULL; sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId); - if(!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team)) + if (!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team)) sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u", Point, Team, m_CapturingPointTypes[Point].GraveYardId); @@ -748,7 +748,7 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType) { - if(GetStatus() != STATUS_IN_PROGRESS || this->GetFlagPickerGUID() != Source->GetGUID()) + if (GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() != Source->GetGUID()) return; SetFlagPicker(0); @@ -757,7 +757,7 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE); else PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE); @@ -768,7 +768,7 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType m_FlagCapturedBgObjectType = BgObjectType; uint8 team_id = 0; - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { team_id = BG_TEAM_ALLIANCE; SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); @@ -779,7 +779,7 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, Source); } - if(m_TeamPointsCount[team_id] > 0) + if (m_TeamPointsCount[team_id] > 0) AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]); UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); @@ -871,7 +871,7 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player) entry = sWorldSafeLocsStore.LookupEntry(g_id); nearestEntry = entry; - if(!entry) + if (!entry) { sLog.outError("BattleGroundEY: Not found the main team graveyard. Graveyard system isn't working!"); return NULL; @@ -887,15 +887,15 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player) for(uint8 i = 0; i < EY_POINTS_MAX; ++i) { - if(m_PointOwnedByTeam[i]==player->GetTeam() && m_PointState[i]==EY_POINT_UNDER_CONTROL) + if (m_PointOwnedByTeam[i]==player->GetTeam() && m_PointState[i]==EY_POINT_UNDER_CONTROL) { entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId); - if(!entry) + if (!entry) sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId); else { distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); - if(distance < nearestDistance) + if (distance < nearestDistance) { nearestDistance = distance; nearestEntry = entry; diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index f3be835e0f2..6e94a8c8a9f 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -43,7 +43,7 @@ void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data ) sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid); Creature *unit = ObjectAccessor::GetCreature(*_player, guid); - if(!unit) + if (!unit) return; if(!unit->isBattleMaster()) // it's not battlemaster @@ -54,7 +54,7 @@ void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data ) BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry()); - if(!_player->GetBGAccessByLevel(bgTypeId)) + if (!_player->GetBGAccessByLevel(bgTypeId)) { // temp, must be gossip message... SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR); @@ -87,7 +87,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) recv_data >> instanceId; // instance id, 0 if First Available selected recv_data >> joinAsGroup; // join as group - if(!sBattlemasterListStore.LookupEntry(bgTypeId_)) + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow()); return; @@ -101,11 +101,11 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0); // ignore if player is already in BG - if(_player->InBattleGround()) + if (_player->InBattleGround()) return; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); - if(!unit) + if (!unit) return; if(!unit->isBattleMaster()) // it's not battlemaster @@ -113,20 +113,20 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) // get bg instance or bg template if instance not found BattleGround * bg = NULL; - if(instanceId) + if (instanceId) BattleGround *bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) + if (!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) { sLog.outError("Battleground: no available bg / template found"); return; } // check queueing conditions - if(!joinAsGroup) + if (!joinAsGroup) { // check Deserter debuff - if( !_player->CanJoinToBattleground() ) + if (!_player->CanJoinToBattleground()) { WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4); data << uint32(0xFFFFFFFE); @@ -138,14 +138,14 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) //player is already in this queue return; // check if has free queue slots - if(!_player->HasFreeBattleGroundQueueId()) + if (!_player->HasFreeBattleGroundQueueId()) return; } else { grp = _player->GetGroup(); // no group found, error - if(!grp) + if (!grp) return; uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); @@ -160,7 +160,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) // _player->GetGroup() was already checked, grp is already initialized GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0); uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(joinAsGroup /* && _player->GetGroup()*/) + if (joinAsGroup /* && _player->GetGroup()*/) { sLog.outDebug("Battleground: the following players are joining as group:"); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) @@ -200,7 +200,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(!ginfo->IsInvitedToBGInstanceGUID) + if (!ginfo->IsInvitedToBGInstanceGUID) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } @@ -213,40 +213,62 @@ void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv if(!bg) // can't be received if player not in battleground return; - if(bg->GetTypeID() == BATTLEGROUND_WS) + switch( bg->GetTypeID() ) { - uint32 count1 = 0; - uint32 count2 = 0; + case BATTLEGROUND_WS: + { + uint32 count1 = 0; //always constant zero? + uint32 count2 = 0; //count of next fields - Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID()); - if(ap) ++count2; + Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID()); + if (ali_plr) + ++count2; - Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID()); - if(hp) ++count2; + Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID()); + if (horde_plr) + ++count2; - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2)); - data << count1; // alliance flag holders count - /*for(uint8 i = 0; i < count1; i++) - { - data << uint64(0); // guid - data << (float)0; // x - data << (float)0; // y - }*/ - data << count2; // horde flag holders count - if(ap) - { - data << (uint64)ap->GetGUID(); - data << (float)ap->GetPositionX(); - data << (float)ap->GetPositionY(); - } - if(hp) - { - data << (uint64)hp->GetGUID(); - data << (float)hp->GetPositionX(); - data << (float)hp->GetPositionY(); - } + WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2)); + data << count1; // alliance flag holders count - obsolete, now always 0 + /*for(uint8 i = 0; i < count1; i++) + { + data << uint64(0); // guid + data << (float)0; // x + data << (float)0; // y + }*/ + data << count2; // horde flag holders count - obsolete, now count of next fields + if (ali_plr) + { + data << (uint64)ali_plr->GetGUID(); + data << (float)ali_plr->GetPositionX(); + data << (float)ali_plr->GetPositionY(); + } + if (horde_plr) + { + data << (uint64)horde_plr->GetGUID(); + data << (float)horde_plr->GetPositionX(); + data << (float)horde_plr->GetPositionY(); + } - SendPacket(&data); + SendPacket(&data); + } + break; + case BATTLEGROUND_EY: + //TODO : fix me! + break; + case BATTLEGROUND_AB: + case BATTLEGROUND_AV: + { + //for other BG types - send default + WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4)); + data << uint32(0); + data << uint32(0); + SendPacket(&data); + } + break; + default: + //maybe it is sent also in arena - do nothing + break; } } @@ -255,7 +277,7 @@ void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message"); BattleGround *bg = _player->GetBattleGround(); - if(!bg) + if (!bg) return; WorldPacket data; @@ -275,7 +297,7 @@ void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data ) recv_data >> bgTypeId; // id from DBC BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); - if(!bl) + if (!bl) { sLog.outError("Battleground: invalid bgtype received."); return; @@ -301,25 +323,25 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; - if( !sBattlemasterListStore.LookupEntry(bgTypeId_) ) + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { sLog.outError("Battleground: invalid bgtype (%u) received.", bgTypeId_); // update battleground slots for the player to fix his UI and sent data. // this is a HACK, I don't know why the client starts sending invalid packets in the first place. // it usually happens with extremely high latency (if debugging / stepping in the code for example) - if( _player->InBattleGroundQueue() ) + if (_player->InBattleGroundQueue()) { // update all queues, send invitation info if player is invited, queue info if queued for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if( !bgQueueTypeId ) + if (!bgQueueTypeId) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); // if the player is not in queue, continue or no group information - this should never happen - if( itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo ) + if (itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) continue; BattleGround * bg = NULL; @@ -328,7 +350,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated; uint8 status = 0; - if( !itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID ) + if (!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) { // not invited to bg, get template bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); @@ -342,7 +364,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) } // if bg not found, then continue, don't invite if already in the instance - if( !bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID()) ) + if (!bg || (_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())) continue; // re - invite player with proper data @@ -359,7 +381,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if( itrPlayerStatus == qpMap.end() ) + if (itrPlayerStatus == qpMap.end()) { sLog.outError("Battleground: itrplayerstatus not found."); return; @@ -367,7 +389,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID; // if action == 1, then instanceId is required - if( !instanceId && action == 1 ) + if (!instanceId && action == 1) { sLog.outError("Battleground: instance not found."); return; @@ -376,15 +398,15 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet - if( !bg && action == 0 ) + if (!bg && action == 0) bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if( !bg ) + if (!bg) { sLog.outError("Battleground: bg_template not found for type id %u.", bgTypeId); return; } - if( _player->InBattleGroundQueue() ) + if (_player->InBattleGroundQueue()) { //we must use temporary variables, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function! uint32 team = itrPlayerStatus->second.GroupInfo->Team; @@ -394,10 +416,10 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) uint32 opponentsRating = itrPlayerStatus->second.GroupInfo->OpponentsTeamRating; //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it - if( action == 1 && arenaType == 0) + if (action == 1 && arenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if( !_player->CanJoinToBattleground() ) + if (!_player->CanJoinToBattleground()) { //send bg command result to show nice message WorldPacket data2(SMSG_GROUP_JOINED_BATTLEGROUND, 4); @@ -407,7 +429,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); } //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue - if( _player->getLevel() > bg->GetMaxLevel() ) + if (_player->getLevel() > bg->GetMaxLevel()) { sLog.outError("Battleground: Player %s (%u) has level higher than maxlevel of battleground! Do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); action = 0; @@ -418,16 +440,16 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) switch( action ) { case 1: // port to battleground - if( !_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId) ) + if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) return; // cheating? // resurrect the player - if( !_player->isAlive() ) + if (!_player->isAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } // stop taxi flight at port - if(_player->isInFlight()) + if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); _player->m_taxi.ClearTaxiDestinations(); @@ -439,7 +461,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new - if( BattleGround *currentBg = _player->GetBattleGround() ) + if (BattleGround *currentBg = _player->GetBattleGround()) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id @@ -454,10 +476,10 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) break; case 0: // leave queue // if player leaves rated arena match before match start, it is counted as he played but he lost - if( isRated ) + if (isRated) { ArenaTeam * at = objmgr.GetArenaTeamById(team); - if( at ) + if (at) { sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), opponentsRating); at->MemberLost(_player, opponentsRating); @@ -468,7 +490,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue - if( !arenaType ) + if (!arenaType) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenaType, isRated, rating); SendPacket(&data); sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); @@ -496,9 +518,9 @@ void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ ) // return; // not allow leave battleground in combat - if(_player->isInCombat()) - if(BattleGround* bg = _player->GetBattleGround()) - if(bg->GetStatus() != STATUS_WAIT_LEAVE) + if (_player->isInCombat()) + if (BattleGround* bg = _player->GetBattleGround()) + if (bg->GetStatus() != STATUS_WAIT_LEAVE) return; _player->LeaveBattleground(); @@ -515,16 +537,16 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if( !bgQueueTypeId ) + if (!bgQueueTypeId) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId); - if( bgTypeId == _player->GetBattleGroundTypeId() ) + if (bgTypeId == _player->GetBattleGroundTypeId()) { bg = _player->GetBattleGround(); //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena //so i must use bg pointer to get that information - if( bg && bg->GetArenaType() == arenaType ) + if (bg && bg->GetArenaType() == arenaType) { // this line is checked, i only don't know if GetStartTime is changing itself after bg end! // send status in BattleGround @@ -537,12 +559,12 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) //get GroupQueueInfo for queue status BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if( itrPlayerStatus == qpMap.end() ) + if (itrPlayerStatus == qpMap.end()) continue; - if( itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID ) + if (itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) { bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId); - if( !bg ) + if (!bg) continue; uint32 remainingTime = getMSTimeDiff(getMSTime(), itrPlayerStatus->second.GroupInfo->RemoveInviteTime); // send status invited to BattleGround @@ -552,7 +574,7 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) else { BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if( !bg ) + if (!bg) continue; uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); // send status in BattleGround Queue @@ -569,14 +591,14 @@ void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data ) CHECK_PACKET_SIZE(recv_data, 8); BattleGround *bg = _player->GetBattleGround(); - if(!bg) + if (!bg) return; uint64 guid; recv_data >> guid; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); - if(!unit) + if (!unit) return; if(!unit->isSpiritService()) // it's not spirit service @@ -592,14 +614,14 @@ void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data ) CHECK_PACKET_SIZE(recv_data, 8); BattleGround *bg = _player->GetBattleGround(); - if(!bg) + if (!bg) return; uint64 guid; recv_data >> guid; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); - if(!unit) + if (!unit) return; if(!unit->isSpiritService()) // it's not spirit service @@ -616,7 +638,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) recv_data.hexlike(); // ignore if we already in BG or BG queue - if(_player->InBattleGround()) + if (_player->InBattleGround()) return; uint64 guid; // arena Battlemaster guid @@ -628,7 +650,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) recv_data >> guid >> arenaslot >> asGroup >> isRated; Creature *unit = ObjectAccessor::GetCreature(*_player, guid); - if(!unit) + if (!unit) return; if(!unit->isBattleMaster()) // it's not battle master @@ -655,7 +677,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) //check existance BattleGround* bg = NULL; - if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) ) + if (!(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA))) { sLog.outError("Battleground: template bg (all arenas) not found"); return; @@ -665,21 +687,21 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype); // check queueing conditions - if(!asGroup) + if (!asGroup) { // check if already in queue if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue return; // check if has free queue slots - if(!_player->HasFreeBattleGroundQueueId()) + if (!_player->HasFreeBattleGroundQueueId()) return; } else { grp = _player->GetGroup(); // no group found, error - if(!grp) + if (!grp) return; uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); if (err != BG_JOIN_ERR_OK) @@ -691,12 +713,12 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) uint32 ateamId = 0; - if(isRated) + if (isRated) { ateamId = _player->GetArenaTeamId(arenaslot); // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) ArenaTeam * at = objmgr.GetArenaTeamById(ateamId); - if(!at) + if (!at) { _player->GetSession()->SendNotInArenaTeamPacket(arenatype); return; @@ -714,20 +736,20 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5); } - if( arenatype ) + if (arenatype) avg_pers_rating /= arenatype; // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating - if(avg_pers_rating + 150 < arenaRating) + if (avg_pers_rating + 150 < arenaRating) arenaRating = avg_pers_rating; } GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(asGroup) + if (asGroup) { sLog.outDebug("Battleground: arena join as group start"); - if(isRated) + if (isRated) sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -749,7 +771,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: arena join as group end"); - if(isRated) + if (isRated) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } else @@ -777,7 +799,7 @@ void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data ) recv_data >> playerGuid; Player *reportedPlayer = objmgr.GetPlayer(playerGuid); - if(!reportedPlayer) + if (!reportedPlayer) { sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found"); return; diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index b3c21d6cb7d..6b7b3c99fe0 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -102,7 +102,7 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) GroupsQueueType::iterator groupToKick = SelectedGroups.begin(); for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr) { - if( abs((int32)((*itr)->Players.size() - size)) <= 1 ) + if (abs((int32)((*itr)->Players.size() - size)) <= 1) { groupToKick = itr; found = true; @@ -111,7 +111,7 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) groupToKick = itr; } //if pool is empty, do nothing - if( GetPlayerCount() ) + if (GetPlayerCount()) { //update player count GroupQueueInfo* ginfo = (*groupToKick); @@ -131,14 +131,14 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount) { //if group is larger than desired count - don't allow to add it to pool - if( !ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size() ) + if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size()) { SelectedGroups.push_back(ginfo); // increase selected players count PlayerCount += ginfo->Players.size(); return true; } - if( PlayerCount < desiredCount ) + if (PlayerCount < desiredCount) return true; return false; } @@ -171,9 +171,9 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId //compute index (if group is premade or joined a rated match) to queues uint32 index = 0; - if(!isRated && !isPremade) + if (!isRated && !isPremade) index += BG_TEAMS_COUNT; - if(ginfo->Team == HORDE) + if (ginfo->Team == HORDE) index++; sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index); @@ -199,14 +199,14 @@ void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* g { uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime()); uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas! - if( !ginfo->ArenaType ) + if (!ginfo->ArenaType) { - if( ginfo->Team == HORDE ) + if (ginfo->Team == HORDE) team_index = BG_TEAM_HORDE; } else { - if( ginfo->IsRated ) + if (ginfo->IsRated) team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE } @@ -226,18 +226,18 @@ void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* g uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id) { uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas! - if( !ginfo->ArenaType ) + if (!ginfo->ArenaType) { - if( ginfo->Team == HORDE ) + if (ginfo->Team == HORDE) team_index = BG_TEAM_HORDE; } else { - if( ginfo->IsRated ) + if (ginfo->IsRated) team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE } //check if there is enought values(we always add values > 0) - if(m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] ) + if (m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] ) return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME); else //if there aren't enough values return 0 - not available @@ -254,7 +254,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou //remove player from map, if he's there itr = m_QueuedPlayers.find(guid); - if( itr == m_QueuedPlayers.end() ) + if (itr == m_QueuedPlayers.end()) { sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid)); return; @@ -275,7 +275,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou { for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp) { - if( (*group_itr_tmp) == group ) + if ((*group_itr_tmp) == group) { queue_id = queue_id_tmp; group_itr = group_itr_tmp; @@ -287,7 +287,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou } } //player can't be in queue without group, but just in case - if( queue_id == -1 ) + if (queue_id == -1) { sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid)); return; @@ -301,14 +301,14 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou // remove player queue info from group queue info std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid); - if( pitr != group->Players.end() ) + if (pitr != group->Players.end()) group->Players.erase(pitr); // if invited to bg, and should decrease invited count, then do it - if( decreaseInvitedCount && group->IsInvitedToBGInstanceGUID ) + if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID) { BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId); - if( bg ) + if (bg) bg->DecreaseInvitedCount(group->Team); } @@ -316,18 +316,18 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou m_QueuedPlayers.erase(itr); //if we left BG queue(not porting) OR if arena team left queue for rated match - if( (decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()) ) + if ((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty())) AnnounceWorld(group, guid, false); //if player leaves queue and he is invited to rated arena match, then he have to loose - if( group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount ) + if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount) { ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId); - if( at ) + if (at) { sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating); Player *plr = objmgr.GetPlayer(guid); - if( plr ) + if (plr) at->MemberLost(plr, group->OpponentsTeamRating); else at->OfflineMemberLost(guid, group->OpponentsTeamRating); @@ -336,7 +336,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou } // remove group queue info if needed - if( group->Players.empty() ) + if (group->Players.empty()) { m_QueuedGroups[queue_id][index].erase(group_itr); delete group; @@ -344,11 +344,11 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou // if group wasn't empty, so it wasn't deleted, and player have left a rated // queue -> everyone from the group should leave too // don't remove recursively if already invited to bg! - else if( !group->IsInvitedToBGInstanceGUID && group->IsRated ) + else if (!group->IsInvitedToBGInstanceGUID && group->IsRated) { // remove next player, this is recursive // first send removal information - if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first)) + if (Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first)) { BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType); @@ -369,14 +369,14 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe { if(ginfo->ArenaType) //if Arena { - if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated ) + if (sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated) { BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId); - if(!bg) + if (!bg) return; char const* bgName = bg->GetName(); - if(isAddedToQueue) + if (isAddedToQueue) sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating); else sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating); @@ -384,11 +384,11 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe } else //if BG { - if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) + if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE)) { Player *plr = objmgr.GetPlayer(playerGUID); BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId); - if(!bg || !plr) + if (!bg || !plr) return; BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID()); @@ -399,14 +399,14 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe uint32 q_min_level = (queue_id + 1) * 10; GroupsQueueType::const_iterator itr; for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr) - if( !(*itr)->IsInvitedToBGInstanceGUID ) + if (!(*itr)->IsInvitedToBGInstanceGUID) qAlliance += (*itr)->Players.size(); for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr) - if( !(*itr)->IsInvitedToBGInstanceGUID ) + if (!(*itr)->IsInvitedToBGInstanceGUID) qHorde += (*itr)->Players.size(); // Show queue status to player only (when joining queue) - if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY) ) + if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) { ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers); @@ -424,29 +424,48 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side) { // set side if needed - if( side ) + if (side) ginfo->Team = side; - if( !ginfo->IsInvitedToBGInstanceGUID ) + if (!ginfo->IsInvitedToBGInstanceGUID) { // not yet invited // set invitation ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID(); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); + BattleGroundTypeId bgTypeId = bg->GetTypeID(); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType()); BGQueueIdBasedOnLevel queue_id = bg->GetQueueId(); + + // set ArenaTeamId for rated matches + if (bg->isArena() && bg->isRated()) + bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId); + + ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME; + // loop through the players for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr) { // get the player Player* plr = objmgr.GetPlayer(itr->first); // if offline, skip him, this should not happen - player is removed from queue when he logs out - if( !plr ) + if (!plr) continue; // invite the player PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id); - ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME; - sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team); + //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team); + + // set invited player counters + bg->IncreaseInvitedCount(ginfo->Team); + + plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID); + + // create remind invite events + BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime); + plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME)); + // create automatic remove events + BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime); + plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME)); WorldPacket data; @@ -464,63 +483,6 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b return false; } -// used to remove the Enter Battle window if the battle has already ended, but someone still has it -// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event -void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg) -{ - BGQueueIdBasedOnLevel queue_id = bg->GetQueueId(); - uint32 bgInstanceId = bg->GetInstanceID(); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - GroupsQueueType::iterator itr, next; - for(uint32 i = 0; i < BG_QUEUE_GROUP_TYPES_COUNT; i++) - { - itr = m_QueuedGroups[queue_id][i].begin(); - next = itr; - while (next != m_QueuedGroups[queue_id][i].end()) - { - // must do this way, because the groupinfo will be deleted when all playerinfos are removed - itr = next; - ++next; - GroupQueueInfo * ginfo = (*itr); - // if group was invited to this bg instance, then remove all references - if( ginfo->IsInvitedToBGInstanceGUID == bgInstanceId ) - { - // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop - uint32 to_remove = ginfo->Players.size(); - for(uint32 j = 0; j < to_remove; j++) - { - // always remove the first one in the group - std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin(); - if( itr2 == ginfo->Players.end() ) - { - sLog.outError("Empty Players in ginfo, this should never happen!"); - return; - } - // get the player - Player * plr = objmgr.GetPlayer(itr2->first); - if( !plr ) - { - sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen."); - continue; - } - - // get the queueslot - uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); - if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue - { - plr->RemoveBattleGroundQueueId(bgQueueTypeId); - // remove player from queue, this might delete the ginfo as well! don't use that pointer after this! - RemovePlayer(itr2->first, true); - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); - plr->GetSession()->SendPacket(&data); - } - } - } - } - } -} - /* This function is inviting players to already running battlegrounds Invitation type is based on config file @@ -564,18 +526,18 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) ) { //each cycle execution we need to kick at least 1 group - if( diffAli < diffHorde ) + if (diffAli < diffHorde) { //kick alliance group, add to pool new group if needed - if( m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli) ) + if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli)) { for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++) ++Ali_itr; } //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break; - if( !m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) { - if( aliFree <= diffHorde + 1 ) + if (aliFree <= diffHorde + 1) break; m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli); } @@ -583,14 +545,14 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel else { //kick horde group, add to pool new group if needed - if( m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde) ) + if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde)) { for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++) ++Horde_itr; } - if( !m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) { - if( hordeFree <= diffAli + 1 ) + if (hordeFree <= diffAli + 1) break; m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde); } @@ -607,19 +569,19 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam) { //check match - if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty()) + if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty()) { //start premade match //if groups aren't invited GroupsQueueType::const_iterator ali_group, horde_group; for( ali_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group) - if( !(*ali_group)->IsInvitedToBGInstanceGUID ) + if (!(*ali_group)->IsInvitedToBGInstanceGUID) break; for( horde_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group) - if( !(*horde_group)->IsInvitedToBGInstanceGUID ) + if (!(*horde_group)->IsInvitedToBGInstanceGUID) break; - if( ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end()) + if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end()) { m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam); m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam); @@ -631,7 +593,7 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr) { //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool - if( !(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers) ) + if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers)) break; } } @@ -646,10 +608,10 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) { - if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) + if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) { GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin(); - if(!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam)) + if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam)) { //we must insert group to normal queue and erase pointer from premade queue m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr)); @@ -670,17 +632,17 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i])) { - if( !(*(itr_team[i]))->IsInvitedToBGInstanceGUID ) + if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID) { m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers); - if( m_SelectionPools[i].GetPlayerCount() >= minPlayers ) + if (m_SelectionPools[i].GetPlayerCount() >= minPlayers) break; } } } //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg uint32 j = BG_TEAM_ALLIANCE; - if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) j = BG_TEAM_HORDE; if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers ) @@ -689,16 +651,16 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break; for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j])) { - if( !(*(itr_team[j]))->IsInvitedToBGInstanceGUID ) - if( !m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) ) + if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID) + if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount())) break; } // do not allow to start bg with more than 2 players more on 1 faction - if( abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2 ) + if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2) return false; } //allow 1v0 if debug bg - if( sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) ) + if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())) return true; //return true if there are enough players in selection pools - enable to work .debug bg command correctly return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers; @@ -707,12 +669,12 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas // this method will check if we can invite players to same faction skirmish match bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam) { - if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam ) + if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam) return false; uint32 teamIndex = BG_TEAM_ALLIANCE; uint32 otherTeam = BG_TEAM_HORDE; uint32 otherTeamId = HORDE; - if ( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam ) + if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam ) { teamIndex = BG_TEAM_HORDE; otherTeam = BG_TEAM_ALLIANCE; @@ -725,9 +687,9 @@ bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_ //set itr_team to group that was added to selection pool latest GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin(); for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team) - if( ginfo == *itr_team ) + if (ginfo == *itr_team) break; - if( itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end() ) + if (itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end()) return false; GroupsQueueType::iterator itr_team2 = itr_team; ++itr_team2; @@ -735,10 +697,10 @@ bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_ for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2) { //if selection pool is full then break; - if( !(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam) ) + if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam)) break; } - if( m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam ) + if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam) return false; //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue @@ -753,7 +715,7 @@ bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_ ++itr2; for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2) { - if( *itr2 == *itr ) + if (*itr2 == *itr) { m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2); break; @@ -806,7 +768,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++itr) InviteGroupToBG((*itr), bg, (*itr)->Team); - if( !bg->HasFreeSlots() ) + if (!bg->HasFreeSlots()) { // remove BG from BGFreeSlotQueue bg->RemoveFromBGFreeSlotQueue(); @@ -817,7 +779,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve // finished iterating through the bgs with free slots, maybe we need to create a new bg BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if( !bg_template ) + if (!bg_template) { sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId); return; @@ -825,11 +787,11 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!) uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam(); uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam(); - if( sBattleGroundMgr.isTesting() ) + if (sBattleGroundMgr.isTesting()) MinPlayersPerTeam = 1; - if( bg_template->isArena() ) + if (bg_template->isArena()) { - if( sBattleGroundMgr.isArenaTesting() ) + if (sBattleGroundMgr.isArenaTesting()) { MaxPlayersPerTeam = 1; MinPlayersPerTeam = 1; @@ -860,14 +822,14 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve m_SelectionPools[BG_TEAM_ALLIANCE].Init(); m_SelectionPools[BG_TEAM_HORDE].Init(); - if( bg_template->isBattleGround() ) + if (bg_template->isBattleGround()) { //check if there is premade against premade match - if( CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) ) + if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)) { //create new battleground BattleGround * bg2 = NULL; - if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)) ) + if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false))) { sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId); return; @@ -885,15 +847,15 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve } // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena) - if( !isRated ) + if (!isRated) { // if there are enough players in pools, start new battleground or non rated arena - if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) + if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) ) { // we successfully created a pool BattleGround * bg2 = NULL; - if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)) ) + if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false))) { sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId); return; @@ -907,31 +869,31 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve bg2->StartBattleGround(); } } - else if( bg_template->isArena() ) + else if (bg_template->isArena()) { // found out the minimum and maximum ratings the newly added team should battle against // arenaRating is the rating of the latest joined team, or 0 // 0 is on (automatic update call) and we must set it to team's with longest wait time - if ( !arenaRating ) + if (!arenaRating ) { GroupQueueInfo* front1 = NULL; GroupQueueInfo* front2 = NULL; - if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() ) + if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty()) { front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front(); arenaRating = front1->ArenaTeamRating; } - if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() ) + if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty()) { front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front(); arenaRating = front2->ArenaTeamRating; } - if( front1 && front2 ) + if (front1 && front2) { - if( front1->JoinTime < front2->JoinTime ) + if (front1->JoinTime < front2->JoinTime) arenaRating = front1->ArenaTeamRating; } - else if( !front1 && !front2 ) + else if (!front1 && !front2) return; //queues are empty } @@ -971,7 +933,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve // if we don't have, we must try to continue search in same queue // tmp variables are correctly set // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue - if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) { itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE]; ++itr_team[BG_TEAM_ALLIANCE]; @@ -987,7 +949,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve } } // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue - if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount()) { itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE]; ++itr_team[BG_TEAM_HORDE]; @@ -1004,10 +966,10 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve } //if we have 2 teams, then start new arena and invite players! - if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) { BattleGround* arena = NULL; - if( !(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)) ) + if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true))) { sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!"); return; @@ -1018,7 +980,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating; sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating); // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer - if( (*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE ) + if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE) { // add to alliance queue m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE])); @@ -1026,7 +988,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]); itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); } - if( (*(itr_team[BG_TEAM_HORDE]))->Team != HORDE ) + if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE) { m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE])); m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]); @@ -1050,28 +1012,27 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { Player* plr = objmgr.GetPlayer( m_PlayerGuid ); - // player logged off (we should do nothing, he is correctly removed from queue in another procedure) if (!plr) return true; - // Player can be in another BG queue and must be removed in normal way in any case - BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId); + //if battleground ended and its instance deleted - do nothing if (!bg) return true; BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); - if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue + if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground { - // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems + // check if player is invited to this bg BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid); - if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) + if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID + && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime ) { WorldPacket data; - //here must be remaining time + //we must send remaining time in queue sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType); plr->GetSession()->SendPacket(&data); } @@ -1081,10 +1042,18 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) void BGQueueInviteEvent::Abort(uint64 /*e_time*/) { - //this should not be called - sLog.outError("Battleground invite event ABORTED!"); + //do nothing } +/* + this event has many possibilities when it is executed: + 1. player is in battleground ( he clicked enter on invitation window ) + 2. player left battleground queue and he isn't there any more + 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0 + 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet + 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer + we must remove player in the 5. case even if battleground object doesn't exist! +*/ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { Player* plr = objmgr.GetPlayer( m_PlayerGuid ); @@ -1093,30 +1062,32 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) return true; BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId); - if (!bg) - return true; - - sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID); + //battleground can be deleted already when we are removing queue info + //bg pointer can be NULL! so use it carefully! - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); - if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue + uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId); + if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground { - // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; + // check if player is in queue for this BG and if we are removing his invite event + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid); - if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) + if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo + && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID + && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime ) { - plr->RemoveBattleGroundQueueId(bgQueueTypeId); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId()); + sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID); + + plr->RemoveBattleGroundQueueId(m_BgQueueTypeId); + sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true); + //update queues if battleground isn't ended + if (bg) + sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].Update(m_BgTypeId, bg->GetQueueId()); + WorldPacket data; sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); plr->GetSession()->SendPacket(&data); } } - else - sLog.outDebug("Battleground: Player was already removed from queue"); //event will be deleted return true; @@ -1124,8 +1095,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) void BGQueueRemoveEvent::Abort(uint64 /*e_time*/) { - //this should not be called - sLog.outError("Battleground remove event ABORTED!"); + //do nothing } /*********************************************************/ @@ -1153,7 +1123,7 @@ void BattleGroundMgr::DeleteAllBattleGrounds() { BattleGround * bg = itr->second; m_BattleGrounds[i].erase(itr++); - if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) + if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID()); delete bg; } @@ -1176,7 +1146,7 @@ void BattleGroundMgr::Update(uint32 diff) { itr = m_BattleGrounds[i].begin(); // skip updating battleground template - if( itr != m_BattleGrounds[i].end() ) + if (itr != m_BattleGrounds[i].end()) ++itr; for(; itr != m_BattleGrounds[i].end(); itr = next) { @@ -1185,21 +1155,21 @@ void BattleGroundMgr::Update(uint32 diff) itr->second->Update(diff); // use the SetDeleteThis variable // direct deletion caused crashes - if(itr->second->m_SetDeleteThis) + if (itr->second->m_SetDeleteThis) { BattleGround * bg = itr->second; m_BattleGrounds[i].erase(itr); - if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) + if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID()); delete bg; } } } // if rating difference counts, maybe force-update queues - if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER)) + if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER)) { // it's time to force update - if(m_NextRatingDiscardUpdate < diff) + if (m_NextRatingDiscardUpdate < diff) { // forced update for level 70 rated arenas sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES"); @@ -1214,9 +1184,9 @@ void BattleGroundMgr::Update(uint32 diff) else m_NextRatingDiscardUpdate -= diff; } - if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) + if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) { - if(m_AutoDistributionTimeChecker < diff) + if (m_AutoDistributionTimeChecker < diff) { if(time(NULL) > m_NextAutoDistributionTime) { @@ -1234,7 +1204,8 @@ void BattleGroundMgr::Update(uint32 diff) void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype) { // we can be in 3 queues in same time... - if(StatusID == 0) + + if (StatusID == 0 || !bg) { data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3); *data << uint32(QueueSlot); // queue id (0...2) @@ -1291,7 +1262,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro break; } - if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE)) + if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE)) *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so. else *data << uint32(bg->GetTypeID()); // BG id from DBC @@ -1344,14 +1315,14 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) { uint32 at_id = bg->m_ArenaTeamIds[i]; ArenaTeam * at = objmgr.GetArenaTeamById(at_id); - if(at) + if (at) *data << at->GetName(); else *data << (uint8)0; } } - if(bg->GetStatus() != STATUS_WAIT_LEAVE) + if (bg->GetStatus() != STATUS_WAIT_LEAVE) { *data << uint8(0); // bg not ended } @@ -1367,7 +1338,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) { *data << (uint64)itr->first; *data << (int32)itr->second->KillingBlows; - if(type == 0) + if (type == 0) { *data << (int32)itr->second->HonorableKills; *data << (int32)itr->second->Deaths; @@ -1377,9 +1348,9 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) { Player *plr = objmgr.GetPlayer(itr->first); uint32 team = bg->GetPlayerTeam(itr->first); - if(!team && plr) + if (!team && plr) team = plr->GetTeam(); - if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) ) + if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE )) *data << uint8(1); else *data << uint8(0); @@ -1467,57 +1438,20 @@ void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Pla *data << uint64(plr->GetGUID()); } -void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team) -{ - // set invited player counters: - BattleGround* bg = GetBattleGround(bgInstanceGUID, bgTypeId); - if(!bg) - return; - bg->IncreaseInvitedCount(team); - - plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID); - - // set the arena teams for rated matches - if(bg->isArena() && bg->isRated()) - { - switch(bg->GetArenaType()) - { - case ARENA_TYPE_2v2: - bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0)); - break; - case ARENA_TYPE_3v3: - bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1)); - break; - case ARENA_TYPE_5v5: - bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2)); - break; - default: - break; - } - } - - // create invite events: - //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events - BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId); - plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME)); - BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId, team); - plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME)); -} - BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) { //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id BattleGround* bg = GetBattleGroundTemplate(bgTypeId); - if( !bg ) + if (!bg) return NULL; - if(bg->isArena()) + if (bg->isArena()) return GetBattleGround(instanceId, bgTypeId); for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr) { - if(itr->second->GetClientInstanceID() == instanceId) + if (itr->second->GetClientInstanceID() == instanceId) return itr->second; } return NULL; @@ -1527,12 +1461,12 @@ BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundT { //search if needed BattleGroundSet::iterator itr; - if( bgTypeId == BATTLEGROUND_TYPE_NONE) + if (bgTypeId == BATTLEGROUND_TYPE_NONE) { for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++) { itr = m_BattleGrounds[i].find(InstanceID); - if( itr != m_BattleGrounds[i].end() ) + if (itr != m_BattleGrounds[i].end()) return itr->second; } return NULL; @@ -1549,7 +1483,7 @@ BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTyp uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) { - if( IsArenaType(bgTypeId) ) + if (IsArenaType(bgTypeId)) return 0; //arenas don't have client-instanceids // we create here an instanceid, which is just for @@ -1574,20 +1508,20 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI { // get the template BG BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId); - if(!bg_template) + if (!bg_template) { sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId); return NULL; } //for arenas there is random map used - if(bg_template->isArena()) + if (bg_template->isArena()) { BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL}; uint32 arena_num = urand(0,2); bgTypeId = arenas[arena_num]; bg_template = GetBattleGroundTemplate(bgTypeId); - if(!bg_template) + if (!bg_template) { sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId); return NULL; @@ -1713,7 +1647,7 @@ void BattleGroundMgr::CreateInitialBattleGrounds() // 0 1 2 3 4 5 6 7 8 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template"); - if(!result) + if (!result) { barGoLink bar(1); @@ -1735,7 +1669,7 @@ void BattleGroundMgr::CreateInitialBattleGrounds() // can be overwrite by values from DB bl = sBattlemasterListStore.LookupEntry(bgTypeID_); - if(!bl) + if (!bl) { sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_); continue; @@ -1749,12 +1683,12 @@ void BattleGroundMgr::CreateInitialBattleGrounds() MinLvl = fields[3].GetUInt32(); MaxLvl = fields[4].GetUInt32(); //check values from DB - if( MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam ) + if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam) { MaxPlayersPerTeam = bl->maxplayersperteam; MinPlayersPerTeam = bl->maxplayersperteam / 2; } - if( MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl ) + if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl) { MinLvl = bl->minlvl; MaxLvl = bl->maxlvl; @@ -1763,14 +1697,14 @@ void BattleGroundMgr::CreateInitialBattleGrounds() start1 = fields[5].GetUInt32(); start = sWorldSafeLocsStore.LookupEntry(start1); - if(start) + if (start) { AStartLoc[0] = start->x; AStartLoc[1] = start->y; AStartLoc[2] = start->z; AStartLoc[3] = fields[6].GetFloat(); } - else if(bgTypeID == BATTLEGROUND_AA) + else if (bgTypeID == BATTLEGROUND_AA) { AStartLoc[0] = 0; AStartLoc[1] = 0; @@ -1786,14 +1720,14 @@ void BattleGroundMgr::CreateInitialBattleGrounds() start2 = fields[7].GetUInt32(); start = sWorldSafeLocsStore.LookupEntry(start2); - if(start) + if (start) { HStartLoc[0] = start->x; HStartLoc[1] = start->y; HStartLoc[2] = start->z; HStartLoc[3] = fields[8].GetFloat(); } - else if(bgTypeID == BATTLEGROUND_AA) + else if (bgTypeID == BATTLEGROUND_AA) { HStartLoc[0] = 0; HStartLoc[1] = 0; @@ -1807,7 +1741,7 @@ void BattleGroundMgr::CreateInitialBattleGrounds() } //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl); - if(!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3])) + if (!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3])) continue; ++count; @@ -1821,11 +1755,11 @@ void BattleGroundMgr::CreateInitialBattleGrounds() void BattleGroundMgr::InitAutomaticArenaPointDistribution() { - if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) + if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS)) { sLog.outDebug("Initializing Automatic Arena Point Distribution"); QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables"); - if(!result) + if (!result) { sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now."); m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS); @@ -1853,7 +1787,7 @@ void BattleGroundMgr::DistributeArenaPoints() //at first update all points for all team members for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr) { - if(ArenaTeam * at = team_itr->second) + if (ArenaTeam * at = team_itr->second) { at->UpdateArenaPointsHelper(PlayerPoints); } @@ -1877,7 +1811,7 @@ void BattleGroundMgr::DistributeArenaPoints() sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START); for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr) { - if(ArenaTeam * at = titr->second) + if (ArenaTeam * at = titr->second) { at->FinishWeek(); // set played this week etc values to 0 in memory, too at->SaveToDB(); // save changes @@ -1894,7 +1828,7 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint6 { uint32 PlayerLevel = 10; - if(plr) + if (plr) PlayerLevel = plr->getLevel(); data->Initialize(SMSG_BATTLEFIELD_LIST); @@ -1926,12 +1860,12 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint6 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId) { BattleGround *bg = GetBattleGround(instanceId, bgTypeId); - if(bg) + if (bg) { uint32 mapid = bg->GetMapId(); float x, y, z, O; uint32 team = pl->GetBGTeam(); - if(team==0) + if (team==0) team = pl->GetTeam(); bg->GetTeamStartLoc(team, x, y, z, O); @@ -1948,7 +1882,7 @@ void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround * { WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds - if(time_ == uint32(-1)) + if (time_ == uint32(-1)) time_ = 0; data << guid << time_; pl->GetSession()->SendPacket(&data); @@ -2039,7 +1973,7 @@ uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId) void BattleGroundMgr::ToggleTesting() { m_Testing = !m_Testing; - if(m_Testing) + if (m_Testing) sWorld.SendWorldText(LANG_DEBUG_BG_ON); else sWorld.SendWorldText(LANG_DEBUG_BG_OFF); @@ -2048,7 +1982,7 @@ void BattleGroundMgr::ToggleTesting() void BattleGroundMgr::ToggleArenaTesting() { m_ArenaTesting = !m_ArenaTesting; - if(m_ArenaTesting) + if (m_ArenaTesting) sWorld.SendWorldText(LANG_DEBUG_ARENA_ON); else sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF); @@ -2092,7 +2026,7 @@ void BattleGroundMgr::LoadBattleMastersEntry() uint32 count = 0; - if( !result ) + if (!result) { barGoLink bar( 1 ); bar.step(); diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index e43b6e0e4a1..889b8b6f4fe 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -86,7 +86,6 @@ class BattleGroundQueue uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); - void BGEndedRemoveInvites(BattleGround * bg); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap; @@ -138,8 +137,8 @@ class BattleGroundQueue class BGQueueInviteEvent : public BasicEvent { public: - BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId) : - m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId) + BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 removeTime) : + m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_RemoveTime(removeTime) { }; virtual ~BGQueueInviteEvent() {}; @@ -149,17 +148,20 @@ class BGQueueInviteEvent : public BasicEvent private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; + uint32 m_RemoveTime; BattleGroundTypeId m_BgTypeId; }; /* - This class is used to remove player from BG queue after 2 minutes from first invitation + This class is used to remove player from BG queue after 1 minute 20 seconds from first invitation + We must store removeInvite time in case player left queue and joined and is invited again + We must store bgQueueTypeId, because battleground can be deleted already, when player entered it */ class BGQueueRemoveEvent : public BasicEvent { public: - BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 playersTeam) : - m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_BgTypeId(BgTypeId), m_PlayersTeam(playersTeam) + BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, BattleGroundQueueTypeId bgQueueTypeId, uint32 removeTime) : + m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_BgTypeId(BgTypeId), m_BgQueueTypeId(bgQueueTypeId), m_RemoveTime(removeTime) { }; virtual ~BGQueueRemoveEvent() {}; @@ -169,8 +171,9 @@ class BGQueueRemoveEvent : public BasicEvent private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; - uint32 m_PlayersTeam; + uint32 m_RemoveTime; BattleGroundTypeId m_BgTypeId; + BattleGroundQueueTypeId m_BgQueueTypeId; }; class BattleGroundMgr @@ -192,10 +195,6 @@ class BattleGroundMgr void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); - /* Player invitation */ - // called from Queue update, or from Addplayer to queue - void InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team); - /* Battlegrounds */ BattleGround* GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown @@ -234,7 +233,7 @@ class BattleGroundMgr BattleGroundTypeId GetBattleMasterBG(uint32 entry) const { BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry); - if(itr != mBattleMastersMap.end()) + if (itr != mBattleMastersMap.end()) return itr->second; return BATTLEGROUND_WS; } diff --git a/src/game/BattleGroundNA.cpp b/src/game/BattleGroundNA.cpp index b4c1b22d2de..364ba972bec 100644 --- a/src/game/BattleGroundNA.cpp +++ b/src/game/BattleGroundNA.cpp @@ -50,7 +50,7 @@ void BattleGroundNA::Update(uint32 diff) { BattleGround::Update(diff); - /*if(GetStatus() == STATUS_IN_PROGRESS) + /*if (GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ @@ -85,7 +85,7 @@ void BattleGroundNA::AddPlayer(Player *plr) void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) { - if(GetStatus() == STATUS_WAIT_LEAVE) + if (GetStatus() == STATUS_WAIT_LEAVE) return; UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE)); @@ -96,10 +96,10 @@ void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; - if(!killer) + if (!killer) { sLog.outError("BattleGroundNA: Killer player not found"); return; @@ -121,7 +121,7 @@ bool BattleGroundNA::HandlePlayerUnderMap(Player *player) void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; //uint32 SpellId = 0; @@ -137,7 +137,7 @@ void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) break; } - //if(buff_guid) + //if (buff_guid) // HandleTriggerBuff(buff_guid,Source); } @@ -157,7 +157,7 @@ void BattleGroundNA::Reset() bool BattleGroundNA::SetupBattleGround() { // gates - if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) + if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) || !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) || !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) diff --git a/src/game/BattleGroundRL.cpp b/src/game/BattleGroundRL.cpp index 0e764d3f4c7..033733aa61a 100644 --- a/src/game/BattleGroundRL.cpp +++ b/src/game/BattleGroundRL.cpp @@ -50,7 +50,7 @@ void BattleGroundRL::Update(uint32 diff) { BattleGround::Update(diff); - /*if(GetStatus() == STATUS_IN_PROGRESS) + /*if (GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ @@ -85,7 +85,7 @@ void BattleGroundRL::AddPlayer(Player *plr) void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) { - if(GetStatus() == STATUS_WAIT_LEAVE) + if (GetStatus() == STATUS_WAIT_LEAVE) return; UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE)); @@ -96,10 +96,10 @@ void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; - if(!killer) + if (!killer) { sLog.outError("Killer player not found"); return; @@ -122,7 +122,7 @@ bool BattleGroundRL::HandlePlayerUnderMap(Player *player) void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; //uint32 SpellId = 0; @@ -138,7 +138,7 @@ void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger) break; } - //if(buff_guid) + //if (buff_guid) // HandleTriggerBuff(buff_guid,Source); } @@ -158,7 +158,7 @@ void BattleGroundRL::Reset() bool BattleGroundRL::SetupBattleGround() { // gates - if( !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY) + if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY) || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY) // buffs || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120) diff --git a/src/game/BattleGroundSA.cpp b/src/game/BattleGroundSA.cpp index 68ef2af19be..5e6b02edfce 100644 --- a/src/game/BattleGroundSA.cpp +++ b/src/game/BattleGroundSA.cpp @@ -65,7 +65,7 @@ void BattleGroundSA::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) void BattleGroundSA::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; } diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp index ecf93db7cfa..fac59229e63 100644 --- a/src/game/BattleGroundWS.cpp +++ b/src/game/BattleGroundWS.cpp @@ -67,43 +67,43 @@ void BattleGroundWS::Update(uint32 diff) { BattleGround::Update(diff); - if(GetStatus() == STATUS_IN_PROGRESS) + if (GetStatus() == STATUS_IN_PROGRESS) { - if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) { m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff; - if(m_FlagsTimer[BG_TEAM_ALLIANCE] < 0) + if (m_FlagsTimer[BG_TEAM_ALLIANCE] < 0) { m_FlagsTimer[BG_TEAM_ALLIANCE] = 0; RespawnFlag(ALLIANCE, true); } } - if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) { m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff; - if(m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0) + if (m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0) { m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0; RespawnFlagAfterDrop(ALLIANCE); } } - if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) { m_FlagsTimer[BG_TEAM_HORDE] -= diff; - if(m_FlagsTimer[BG_TEAM_HORDE] < 0) + if (m_FlagsTimer[BG_TEAM_HORDE] < 0) { m_FlagsTimer[BG_TEAM_HORDE] = 0; RespawnFlag(HORDE, true); } } - if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) { m_FlagsDropTimer[BG_TEAM_HORDE] -= diff; - if(m_FlagsDropTimer[BG_TEAM_HORDE] < 0) + if (m_FlagsDropTimer[BG_TEAM_HORDE] < 0) { m_FlagsDropTimer[BG_TEAM_HORDE] = 0; RespawnFlagAfterDrop(HORDE); @@ -150,7 +150,7 @@ void BattleGroundWS::AddPlayer(Player *plr) void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) { - if(Team == ALLIANCE) + if (Team == ALLIANCE) { sLog.outDebug("Respawn Alliance flag"); m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; @@ -161,7 +161,7 @@ void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; } - if(captured) + if (captured) { //when map_update will be allowed for battlegrounds this code will be useless SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); @@ -173,11 +173,11 @@ void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; RespawnFlag(team,false); - if(team == ALLIANCE) + if (team == ALLIANCE) { SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); SendMessageToAll(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); @@ -191,7 +191,7 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID(team)); - if(obj) + if (obj) obj->Delete(); else sLog.outError("unknown droped flag bg, guid: %u",GUID_LOPART(GetDroppedFlagGUID(team))); @@ -201,13 +201,13 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; uint32 winner = 0; Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { if (!this->IsHordeFlagPickedup()) return; @@ -216,7 +216,7 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; // Drop Horde Flag from Player Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); - if(GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE) + if (GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE) AddPoint(ALLIANCE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); @@ -230,7 +230,7 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; // Drop Alliance Flag from Player Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); - if(GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE) + if (GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE) AddPoint(HORDE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); RewardReputationToTeam(889, m_ReputationCapture, HORDE); @@ -241,7 +241,7 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME); SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); else SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, Source); @@ -251,13 +251,13 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) // only flag capture should be updated UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures - if(GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) + if (GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) winner = ALLIANCE; - if(GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE) + if (GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE) winner = HORDE; - if(winner) + if (winner) { UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 0); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 0); @@ -275,15 +275,15 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) { // if not running, do not cast things at the dropper player (prevent spawning the "dropped" flag), neither send unnecessary messages // just take off the aura - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { - if(!this->IsHordeFlagPickedup()) + if (!this->IsHordeFlagPickedup()) return; - if(GetHordeFlagPickerGUID() == Source->GetGUID()) + if (GetHordeFlagPickerGUID() == Source->GetGUID()) { SetHordeFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); @@ -291,9 +291,9 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) } else { - if(!this->IsAllianceFlagPickedup()) + if (!this->IsAllianceFlagPickedup()) return; - if(GetAllianceFlagPickerGUID() == Source->GetGUID()) + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) { SetAllianceFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); @@ -304,11 +304,11 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) bool set = false; - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { - if(!this->IsHordeFlagPickedup()) + if (!IsHordeFlagPickedup()) return; - if(GetHordeFlagPickerGUID() == Source->GetGUID()) + if (GetHordeFlagPickerGUID() == Source->GetGUID()) { SetHordeFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); @@ -319,9 +319,9 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) } else { - if(!this->IsAllianceFlagPickedup()) + if (!IsAllianceFlagPickedup()) return; - if(GetAllianceFlagPickerGUID() == Source->GetGUID()) + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) { SetAllianceFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); @@ -336,7 +336,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); UpdateFlagState(Source->GetTeam(), 1); - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, Source); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1)); @@ -353,7 +353,7 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; int32 message_id = 0; @@ -392,9 +392,9 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target } //Alliance flag on ground(not in base) (returned or picked up again from ground!) - if(this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->id == BG_OBJECT_A_FLAG_GROUND_WS_ENTRY) + if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) { - if(Source->GetTeam() == ALLIANCE) + if (Source->GetTeam() == ALLIANCE) { message_id = LANG_BG_WS_RETURNED_AF; type = CHAT_MSG_BG_SYSTEM_ALLIANCE; @@ -421,9 +421,9 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target } //Horde flag on ground(not in base) (returned or picked up again) - if(this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10) && target_obj->GetGOInfo()->id == BG_OBJECT_H_FLAG_GROUND_WS_ENTRY) + if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) { - if(Source->GetTeam() == HORDE) + if (Source->GetTeam() == HORDE) { message_id = LANG_BG_WS_RETURNED_HF; type = CHAT_MSG_BG_SYSTEM_HORDE; @@ -459,9 +459,9 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid) { // sometimes flag aura not removed :( - if(IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid) + if (IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid) { - if(!plr) + if (!plr) { sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); this->SetAllianceFlagPicker(0); @@ -470,9 +470,9 @@ void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid) else this->EventPlayerDroppedFlag(plr); } - if(IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid) + if (IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid) { - if(!plr) + if (!plr) { sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); this->SetHordeFlagPicker(0); @@ -485,7 +485,7 @@ void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid) void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value) { - if(team == ALLIANCE) + if (team == ALLIANCE) UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, value); else UpdateWorldState(BG_WS_FLAG_STATE_HORDE, value); @@ -493,7 +493,7 @@ void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value) void BattleGroundWS::UpdateTeamScore(uint32 team) { - if(team == ALLIANCE) + if (team == ALLIANCE) UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team)); else UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team)); @@ -502,7 +502,7 @@ void BattleGroundWS::UpdateTeamScore(uint32 team) void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger) { // this is wrong way to implement these things. On official it done by gameobject spell cast. - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; //uint32 SpellId = 0; @@ -528,13 +528,13 @@ void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger) //buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_2]; break; case 3646: // Alliance Flag spawn - if(m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE]) - if(GetHordeFlagPickerGUID() == Source->GetGUID()) + if (m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE]) + if (GetHordeFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source); break; case 3647: // Horde Flag spawn - if(m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE]) - if(GetAllianceFlagPickerGUID() == Source->GetGUID()) + if (m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE]) + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) EventPlayerCapturedFlag(Source); break; case 3649: // unk1 @@ -548,14 +548,14 @@ void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger) break; } - //if(buff_guid) + //if (buff_guid) // HandleTriggerBuff(buff_guid,Source); } bool BattleGroundWS::SetupBattleGround() { // flags - if( !AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000) + if (!AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000) || !AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, BG_WS_FLAG_RESPAWN_TIME/1000) // buffs || !AddObject(BG_WS_OBJECT_SPEEDBUFF_1, BG_OBJECTID_SPEEDBUFF_ENTRY, 1449.93f, 1470.71f, 342.6346f, -1.64061f, 0, 0, 0.7313537f, -0.6819983f, BUFF_RESPAWN_TIME) @@ -583,14 +583,14 @@ bool BattleGroundWS::SetupBattleGround() } WorldSafeLocsEntry const *sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); - if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) + if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) { sLog.outErrorDb("BatteGroundWS: Failed to spawn Alliance spirit guide! BattleGround not created!"); return false; } sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); - if(!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) + if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) { sLog.outErrorDb("BatteGroundWS: Failed to spawn Horde spirit guide! BattleGround not created!"); return false; @@ -620,9 +620,9 @@ void BattleGroundWS::Reset() m_HonorEndKills = (isBGWeekend) ? 4 : 2; /* Spirit nodes is static at this BG and then not required deleting at BG reset. - if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) + if (m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) DelCreature(WS_SPIRIT_MAIN_ALLIANCE); - if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) + if (m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) DelCreature(WS_SPIRIT_MAIN_HORDE); */ } @@ -630,9 +630,9 @@ void BattleGroundWS::Reset() void BattleGroundWS::EndBattleGround(uint32 winner) { //win reward - if( winner == ALLIANCE ) + if (winner == ALLIANCE) RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE); - if( winner == HORDE ) + if (winner == HORDE) RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE); //complete map_end rewards (even if no team wins) RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE); @@ -643,7 +643,7 @@ void BattleGroundWS::EndBattleGround(uint32 winner) void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer) { - if(GetStatus() != STATUS_IN_PROGRESS) + if (GetStatus() != STATUS_IN_PROGRESS) return; EventPlayerDroppedFlag(player); @@ -680,16 +680,16 @@ WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player) //if a player dies in preparation phase - then the player can't cheat //and teleport to the graveyard outside the flagroom //and start running around, while the doors are still closed - if(player->GetTeam() == ALLIANCE) + if (player->GetTeam() == ALLIANCE) { - if(GetStatus() == STATUS_IN_PROGRESS) + if (GetStatus() == STATUS_IN_PROGRESS) return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); else return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_ALLIANCE); } else { - if(GetStatus() == STATUS_IN_PROGRESS) + if (GetStatus() == STATUS_IN_PROGRESS) return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); else return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_HORDE); @@ -701,14 +701,14 @@ void BattleGroundWS::FillInitialWorldStates(WorldPacket& data) data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE)); data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(HORDE)); - if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(-1); else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(1); else data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(0); - if(m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(-1); else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(1); diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 97f6c3bde6f..081d9669696 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -73,6 +73,8 @@ SET(game_STAT_SRCS CreatureAIRegistry.h CreatureAISelector.cpp CreatureAISelector.h + CreatureEventAI.cpp + CreatureEventAIMgr.cpp Creature.cpp Creature.h CreatureGroups.cpp @@ -293,4 +295,4 @@ SET(game_STAT_SRCS ) add_library(game STATIC ${game_STAT_SRCS}) -ADD_DEPENDENCIES(game revision.h)
\ No newline at end of file +ADD_DEPENDENCIES(game revision.h) diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index eaf0ec5af0f..a2e189603f9 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -165,7 +165,7 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ ) "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, " // 9 10 11 12 13 "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid " - "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='0' " + "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' " "LEFT JOIN guild_member ON characters.guid = guild_member.guid " "WHERE characters.account = '%u' ORDER BY characters.guid" : @@ -174,11 +174,11 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ ) "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, " // 9 10 11 12 13 14 "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, genitive " - "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='0' " + "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' " "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid " "LEFT JOIN guild_member ON characters.guid = guild_member.guid " "WHERE characters.account = '%u' ORDER BY characters.guid", - GetAccountId()); + PET_SAVE_AS_CURRENT,GetAccountId()); } void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) @@ -814,9 +814,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) SendDoFlight( MountId, path, startNode ); } - // Load pet if any and player is alive and not in taxi flight - if(pCurrChar->isAlive() && pCurrChar->m_taxi.GetTaxiSource()==0) - pCurrChar->LoadPet(); + // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) + pCurrChar->LoadPet(); // Set FFA PvP for non GM in non-rest mode if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) ) diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 50bb6b7832f..f63a550b7de 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -136,6 +136,8 @@ ChatCommand * ChatHandler::getCommandTable() static ChatCommand debugCommandTable[] = { { "setbit", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSet32Bit, "", NULL }, + { "threat", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugThreatList, "", NULL }, + { "hostil", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugHostilRefList, "", NULL }, { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL }, { "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL }, { "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL }, @@ -232,7 +234,7 @@ ChatCommand * ChatHandler::getCommandTable() { "listbinds", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceListBindsCommand, "", NULL }, { "unbind", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceUnbindCommand, "", NULL }, { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleInstanceStatsCommand, "", NULL }, - { "savedata", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL }, + { "savedata", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -384,6 +386,7 @@ ChatCommand * ChatHandler::getCommandTable() static ChatCommand reloadCommandTable[] = { { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllCommand, "", NULL }, + { "all_achievement",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAchievementCommand,"", NULL }, { "all_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAreaCommand, "", NULL }, { "all_loot", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLootCommand, "", NULL }, { "all_npc", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllNpcCommand, "", NULL }, @@ -395,6 +398,8 @@ ChatCommand * ChatHandler::getCommandTable() { "config", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConfigCommand, "", NULL }, + { "achievement_criteria_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementCriteriaDataCommand, "", NULL }, + { "achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementRewardCommand, "", NULL }, { "areatrigger_tavern", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, { "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL }, { "access_requirement", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAccessRequirementCommand, "", NULL }, @@ -415,7 +420,7 @@ ChatCommand * ChatHandler::getCommandTable() { "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL }, { "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, - { "trinity_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadTrinityStringCommand, "", NULL }, + { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL }, { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL }, { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL }, { "locales_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesItemCommand, "", NULL }, @@ -458,6 +463,7 @@ ChatCommand * ChatHandler::getCommandTable() { "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL }, { "spell_disabled", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellDisabledCommand, "", NULL }, + { "trinity_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadTrinityStringCommand, "", NULL }, { "auctions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAuctionsCommand, "", NULL }, { "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL }, { "gm_tickets", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMTicketReloadCommand, "", NULL }, @@ -518,6 +524,7 @@ ChatCommand * ChatHandler::getCommandTable() { { "difftime", SEC_CONSOLE, true, &ChatHandler::HandleServerSetDiffTimeCommand, "", NULL }, { "loglevel", SEC_CONSOLE, true, &ChatHandler::HandleServerSetLogLevelCommand, "", NULL }, + { "logfilelevel", SEC_CONSOLE, true, &ChatHandler::HandleServerSetLogFileLevelCommand, "", NULL }, { "motd", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetMotdCommand, "", NULL }, { "closed", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetClosedCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } diff --git a/src/game/Chat.h b/src/game/Chat.h index 05892202718..7065c6dd0ed 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -291,6 +291,7 @@ class ChatHandler bool HandleQuestComplete(const char * args); bool HandleReloadAllCommand(const char* args); + bool HandleReloadAllAchievementCommand(const char* args); bool HandleReloadAllAreaCommand(const char* args); bool HandleReloadAllItemCommand(const char* args); bool HandleReloadAllLootCommand(const char* args); @@ -302,7 +303,8 @@ class ChatHandler bool HandleReloadConfigCommand(const char* args); - bool HandleReloadWpScriptsCommand(const char* args); + bool HandleReloadAchievementCriteriaDataCommand(const char* args); + bool HandleReloadAchievementRewardCommand(const char* args); bool HandleReloadAreaTriggerTavernCommand(const char* args); bool HandleReloadAreaTriggerTeleportCommand(const char* args); bool HandleReloadAccessRequirementCommand(const char* args); @@ -317,6 +319,7 @@ class ChatHandler bool HandleReloadGOQuestRelationsCommand(const char* args); bool HandleReloadGOQuestInvRelationsCommand(const char* args); bool HandleReloadItemEnchantementsCommand(const char* args); + bool HandleReloadLocalesAchievementRewardCommand(const char* args); bool HandleReloadLocalesCreatureCommand(const char* args); bool HandleReloadLocalesGameobjectCommand(const char* args); bool HandleReloadLocalesItemCommand(const char* args); @@ -367,6 +370,7 @@ class ChatHandler bool HandleReloadSpellPetAurasCommand(const char* args); bool HandleReloadSpellDisabledCommand(const char* args); bool HandleReloadAuctionsCommand(const char* args); + bool HandleReloadWpScriptsCommand(const char* args); bool HandleResetAchievementsCommand(const char * args); bool HandleResetAllCommand(const char * args); @@ -390,6 +394,7 @@ class ChatHandler bool HandleServerRestartCommand(const char* args); bool HandleServerSetMotdCommand(const char* args); bool HandleServerSetLogLevelCommand(const char* args); + bool HandleServerSetLogFileLevelCommand(const char* args); bool HandleServerSetDiffTimeCommand(const char* args); bool HandleServerShutDownCommand(const char* args); bool HandleServerShutDownCancelCommand(const char* args); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 74ebe4406c8..7a4cac89408 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -116,7 +116,7 @@ bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { while (!m_assistants.empty()) { - Creature* assistant = (Creature*)Unit::GetUnit(m_owner, *m_assistants.begin()); + Creature* assistant = Unit::GetCreature(m_owner, *m_assistants.begin()); m_assistants.pop_front(); if (assistant && assistant->CanAssistTo(&m_owner, victim)) @@ -151,6 +151,7 @@ m_creatureInfo(NULL), m_reactState(REACT_AGGRESSIVE), m_formation(NULL), m_summo m_CreatureCategoryCooldowns.clear(); m_GlobalCooldown = 0; m_unit_movement_flags = MOVEMENTFLAG_WALK_MODE; + DisableReputationGain = false; } Creature::~Creature() diff --git a/src/game/Creature.h b/src/game/Creature.h index 02111ea9f70..ce890c34902 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -134,6 +134,7 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) //CREATURE_FLAG_EXTRA_CHARM_AI = 0x00008000, // use ai when charmed CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00010000, // cannot be taunted + CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes }; enum SummonMask @@ -325,6 +326,29 @@ enum InhabitTypeValues INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR }; +// Enums used by StringTextData::Type (CreatureEventAI) +enum ChatType +{ + CHAT_TYPE_SAY = 0, + CHAT_TYPE_YELL = 1, + CHAT_TYPE_TEXT_EMOTE = 2, + CHAT_TYPE_BOSS_EMOTE = 3, + CHAT_TYPE_WHISPER = 4, + CHAT_TYPE_BOSS_WHISPER = 5, + CHAT_TYPE_ZONE_YELL = 6 +}; + +//Selection method used by SelectTarget (CreatureEventAI) +enum AttackingTarget +{ + ATTACKING_TARGET_RANDOM = 0, //Just selects a random target + ATTACKING_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom + ATTACKING_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top + ATTACKING_TARGET_RANDOM_PLAYER, //Just selects a random target (player only) + ATTACKING_TARGET_TOPAGGRO_PLAYER, //Selects targes from top aggro to bottom (player only) + ATTACKING_TARGET_BOTTOMAGGRO_PLAYER, //Selects targets from bottom aggro to top (player only) +}; + // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform #if defined( __GNUC__ ) #pragma pack() @@ -658,6 +682,8 @@ class TRINITY_DLL_SPEC Creature : public Unit Unit *SelectVictim(); void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;} + void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; } + bool IsReputationGainDisabled() { return DisableReputationGain; } protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); @@ -706,6 +732,8 @@ class TRINITY_DLL_SPEC Creature : public Unit float mHome_Z; float mHome_O; + bool DisableReputationGain; + private: //WaypointMovementGenerator vars uint32 m_waypointID; diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 45608ef317e..e7043c6042f 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -70,6 +70,38 @@ void CreatureAI::OnCharmed(bool apply) me->IsAIEnabled = false; } +void CreatureAI::DoZoneInCombat(Unit* pUnit) +{ + if (!pUnit) + pUnit = me; + + Map *map = pUnit->GetMap(); + + if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated + { + sLog.outError("DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); + return; + } + + if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty()) + { + sLog.outError("DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0); + return; + } + + Map::PlayerList const &PlayerList = map->GetPlayers(); + for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (Player* i_pl = i->getSource()) + if (i_pl->isAlive()) + { + pUnit->SetInCombatWith(i_pl); + i_pl->SetInCombatWith(pUnit); + pUnit->AddThreat(i_pl, 0.0f); + } + } +} + void CreatureAI::MoveInLineOfSight(Unit *who) { if(!me->getVictim() && me->canStartAttack(who)) diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index 7388aab786c..11d5bd372fd 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -158,6 +158,8 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI // Called at reaching home after evade virtual void JustReachedHome() {} + + void DoZoneInCombat(Unit* pUnit = NULL); }; struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature> diff --git a/src/game/CreatureAIRegistry.cpp b/src/game/CreatureAIRegistry.cpp index 3d7fe1848fb..6253c06b8bc 100644 --- a/src/game/CreatureAIRegistry.cpp +++ b/src/game/CreatureAIRegistry.cpp @@ -26,6 +26,7 @@ #include "PossessedAI.h" #include "TotemAI.h" #include "OutdoorPvPObjectiveAI.h" +#include "CreatureEventAI.h" #include "RandomMovementGenerator.h" #include "CreatureAIImpl.h" #include "MovementGeneratorImpl.h" @@ -46,6 +47,7 @@ namespace AIRegistry (new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf(); (new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf(); (new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf(); + (new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf(); (new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf(); (new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf(); diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 74275c8b173..88384fd6f21 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -35,24 +35,24 @@ namespace FactorySelector { CreatureAI* selectAI(Creature *creature) { - //if(creature->isPossessed()) - // creature->InitPossessedAI(); + const CreatureAICreator *ai_factory = NULL; + CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance()); + + //player-controlled guardians with pet bar + if(creature->HasSummonMask(SUMMON_MASK_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) + ai_factory = ai_registry.GetRegistryItem("PetAI"); - // Allow scripting AI for normal creatures and not controlled pets (guardians and mini-pets) - if((!creature->isPet() || !((Pet*)creature)->isControlled()) && !creature->isCharmed()) + //scriptname in db + if(!ai_factory) if(CreatureAI* scriptedAI = Script->GetAI(creature)) return scriptedAI; - CreatureAIRegistry &ai_registry(CreatureAIRepository::Instance()); - assert( creature->GetCreatureInfo() != NULL ); - CreatureInfo const *cinfo=creature->GetCreatureInfo(); - - const CreatureAICreator *ai_factory = NULL; + CreatureInfo const *cinfo = creature->GetCreatureInfo(); + assert(cinfo); + // this seems to be useless std::string ainame=cinfo->AIName; - - // select by script name - if( !ainame.empty()) + if(!ai_factory && !ainame.empty()) ai_factory = ai_registry.GetRegistryItem( ainame.c_str() ); // select by NPC flags @@ -60,21 +60,12 @@ namespace FactorySelector { if( creature->isGuard() ) ai_factory = ai_registry.GetRegistryItem("GuardAI"); - else if(creature->isPet() || (creature->isCharmed() && !creature->isPossessed())) + else if(creature->HasSummonMask(SUMMON_MASK_GUARDIAN)) ai_factory = ai_registry.GetRegistryItem("PetAI"); else if(creature->isTotem()) ai_factory = ai_registry.GetRegistryItem("TotemAI"); else if(creature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); - else if(creature->isSummon() && ((TempSummon*)creature)->m_Properties) - { - if(((TempSummon*)creature)->m_Properties->Category == SUMMON_CATEGORY_PET - || ((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_GUARDIAN - || ((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_MINION) - ai_factory = ai_registry.GetRegistryItem("PetAI"); - else if(((TempSummon*)creature)->m_Properties->Type == SUMMON_TYPE_MINIPET) - ai_factory = ai_registry.GetRegistryItem("CritterAI"); - } else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER) ai_factory = ai_registry.GetRegistryItem("CritterAI"); } diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp new file mode 100644 index 00000000000..daf5c74ca72 --- /dev/null +++ b/src/game/CreatureEventAI.cpp @@ -0,0 +1,1661 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "CreatureEventAI.h" +#include "CreatureEventAIMgr.h" +#include "ObjectMgr.h" +#include "Spell.h" +#include "World.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GameEventMgr.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "WorldPacket.h" +#include "InstanceData.h" + +int CreatureEventAI::Permissible(const Creature *creature) +{ + if( creature->GetCreatureInfo()->AIName == "EventAI" ) + return PERMIT_BASE_SPECIAL; + return PERMIT_BASE_NO; +} + +CreatureEventAI::CreatureEventAI(Creature *c) : CreatureAI(c), m_creature(*c), InCombat(false) +{ + CreatureEventAI_Event_Map::iterator CreatureEvents = CreatureEAI_Mgr.GetCreatureEventAIMap().find(m_creature.GetEntry()); + if (CreatureEvents != CreatureEAI_Mgr.GetCreatureEventAIMap().end()) + { + std::vector<CreatureEventAI_Event>::iterator i; + for (i = (*CreatureEvents).second.begin(); i != (*CreatureEvents).second.end(); ++i) + { + + //Debug check + #ifndef _DEBUG + if ((*i).event_flags & EFLAG_DEBUG_ONLY) + continue; + #endif + if(((*i).event_flags & (EFLAG_HEROIC | EFLAG_NORMAL)) && m_creature.GetMap()->IsDungeon() ) + { + if( (m_creature.GetMap()->IsHeroic() && (*i).event_flags & EFLAG_HEROIC) || + (!m_creature.GetMap()->IsHeroic() && (*i).event_flags & EFLAG_NORMAL)) + { + //event flagged for instance mode + CreatureEventAIList.push_back(CreatureEventAIHolder(*i)); + } + continue; + } + CreatureEventAIList.push_back(CreatureEventAIHolder(*i)); + } + //EventMap had events but they were not added because they must be for instance + if (CreatureEventAIList.empty()) + sLog.outError("CreatureEventAI: CreatureId has events but no events added to list because of instance flags.", m_creature.GetEntry()); + } + else + sLog.outError("CreatureEventAI: EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature.GetEntry()); + + bEmptyList = CreatureEventAIList.empty(); + Phase = 0; + CombatMovementEnabled = true; + MeleeEnabled = true; + AttackDistance = 0; + AttackAngle = 0.0f; + + //Handle Spawned Events + if (!bEmptyList) + { + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_SPAWNED) + ProcessEvent(*i); + } + } +} + +bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker) +{ + if (!pHolder.Enabled || pHolder.Time) + return false; + + //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask) + if (pHolder.Event.event_inverse_phase_mask & (1 << Phase)) + return false; + + //Store random here so that all random actions match up + uint32 rnd = rand(); + + //Return if chance for event is not met + if (pHolder.Event.event_chance <= rnd % 100) + return false; + + union + { + uint32 param1; + int32 param1_s; + }; + + union + { + uint32 param2; + int32 param2_s; + }; + + union + { + uint32 param3; + int32 param3_s; + }; + + union + { + uint32 param4; + int32 param4_s; + }; + + param1 = pHolder.Event.event_param1; + param2 = pHolder.Event.event_param2; + param3 = pHolder.Event.event_param3; + param4 = pHolder.Event.event_param4; + + //Check event conditions based on the event type, also reset events + switch (pHolder.Event.event_type) + { + case EVENT_T_TIMER: + { + if (!InCombat) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_TIMER_OOC: + { + if (InCombat) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_HP: + { + if (!InCombat || !m_creature.GetMaxHealth()) + return false; + + uint32 perc = (m_creature.GetHealth()*100) / m_creature.GetMaxHealth(); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_MANA: + { + if (!InCombat || !m_creature.GetMaxPower(POWER_MANA)) + return false; + + uint32 perc = (m_creature.GetPower(POWER_MANA)*100) / m_creature.GetMaxPower(POWER_MANA); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_AGGRO: + { + } + break; + case EVENT_T_KILL: + { + //Repeat Timers + if (param1 == param2) + { + pHolder.Time = param1; + + }else if (param2 > param1) + pHolder.Time = urand(param1, param2); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + case EVENT_T_DEATH: + { + } + break; + case EVENT_T_EVADE: + { + } + break; + case EVENT_T_SPELLHIT: + { + //Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_RANGE: + { + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_OOC_LOS: + { + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_SPAWNED: + { + } + break; + case EVENT_T_TARGET_HP: + { + if (!InCombat || !m_creature.getVictim() || !m_creature.getVictim()->GetMaxHealth()) + return false; + + uint32 perc = (m_creature.getVictim()->GetHealth()*100) / m_creature.getVictim()->GetMaxHealth(); + + if (perc > param1 || perc < param2) + return false; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_TARGET_CASTING: + { + if (!InCombat || !m_creature.getVictim() || !m_creature.getVictim()->IsNonMeleeSpellCasted(false, false, true)) + return false; + + //Repeat Timers + if (param1 == param2) + { + pHolder.Time = param1; + + }else if (param2 > param1) + pHolder.Time = urand(param1, param2); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_HP: + { + if (!InCombat) + return false; + + Unit* pUnit = DoSelectLowestHpFriendly(param2, param1); + + if (!pUnit) + return false; + + pActionInvoker = pUnit; + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_IS_CC: + { + if (!InCombat) + return false; + + std::list<Creature*> pList; + DoFindFriendlyCC(pList, param2); + + //List is empty + if (pList.empty()) + return false; + + //We don't really care about the whole list, just return first available + pActionInvoker = *(pList.begin()); + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_FRIENDLY_MISSING_BUFF: + { + std::list<Creature*> pList; + DoFindFriendlyMissingBuff(pList, param2, param1); + + //List is empty + if (pList.empty()) + return false; + + //We don't really care about the whole list, just return first available + pActionInvoker = *(pList.begin()); + + //Repeat Timers + if (param3 == param4) + { + pHolder.Time = param3; + + }else if (param4 > param3) + pHolder.Time = urand(param3, param4); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_SUMMONED_UNIT: + { + //Prevent event from occuring on no unit or non creatures + if (!pActionInvoker || pActionInvoker->GetTypeId()!=TYPEID_UNIT) + return false; + + //Creature id doesn't match up + if (param1 && ((Creature*)pActionInvoker)->GetEntry() != param1) + return false; + + //Repeat Timers + if (param2 == param3) + { + pHolder.Time = param2; + + }else if (param3 > param2) + pHolder.Time = urand(param2, param3); + else + { + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + pHolder.Enabled = false; + } + } + break; + case EVENT_T_REACHED_HOME: + { + } + break; + case EVENT_T_RECEIVE_EMOTE: + { + } + break; + default: + + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature.GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); + break; + } + + //Disable non-repeatable events + if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE)) + pHolder.Enabled = false; + + //Process actions + for (uint32 j = 0; j < MAX_ACTIONS; j++) + ProcessAction(pHolder.Event.action[j].type, pHolder.Event.action[j].param1, pHolder.Event.action[j].param2, pHolder.Event.action[j].param3, rnd, pHolder.Event.event_id, pActionInvoker); + + return true; +} + +void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker) +{ + switch (type) + { + case ACTION_T_TEXT: + { + if (!param1) + return; + + uint32 temp = 0; + + if (param2 && param3) + { + switch( rand()%3 ) + { + case 0: temp = param1; break; + case 2: temp = param2; break; + case 3: temp = param3; break; + } + }else if ( param2 && urand(0,1) ) + { + temp = param2; + }else + { + temp = param1; + } + + if (temp) + { + Unit* target = NULL; + Unit* owner = NULL; + + if (pActionInvoker) + { + if (pActionInvoker->GetTypeId() == TYPEID_PLAYER) + target = pActionInvoker; + else if (owner = pActionInvoker->GetOwner()) + { + if (owner->GetTypeId() == TYPEID_PLAYER) + target = owner; + } + } + else if (target = m_creature.getVictim()) + { + if (target->GetTypeId() != TYPEID_PLAYER) + { + if (owner = target->GetOwner()) + { + if (owner->GetTypeId() == TYPEID_PLAYER) + target = owner; + } + } + } + + DoScriptText(temp, &m_creature, target); + } + } + break; + case ACTION_T_SET_FACTION: + { + if (param1) + m_creature.setFaction(param1); + else + { + if (CreatureInfo const* ci = GetCreatureTemplateStore(m_creature.GetEntry())) + { + //if no id provided, assume reset and then use default + if (m_creature.getFaction() != ci->faction_A) + m_creature.setFaction(ci->faction_A); + } + } + } + break; + case ACTION_T_MORPH_TO_ENTRY_OR_MODEL: + { + if (param1 || param2) + { + //set model based on entry from creature_template + if (param1) + { + if (CreatureInfo const* ci = GetCreatureTemplateStore(param1)) + { + //use default display + if (ci->Modelid1) + m_creature.SetDisplayId(ci->Modelid1); + } + } + //if no param1, then use value from param2 (modelId) + else + m_creature.SetDisplayId(param2); + } + else + m_creature.DeMorph(); + } + break; + case ACTION_T_SOUND: + m_creature.PlayDirectSound(param1); + break; + case ACTION_T_EMOTE: + m_creature.HandleEmoteCommand(param1); + break; + case ACTION_T_RANDOM_SOUND: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != uint32(0xffffffff)) + m_creature.PlayDirectSound( temp ); + } + break; + case ACTION_T_RANDOM_EMOTE: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + if (temp != uint32(0xffffffff)) + m_creature.HandleEmoteCommand(temp); + } + break; + case ACTION_T_CAST: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + Unit* caster = &m_creature; + + if (!target) + return; + + //Cast is always triggered if target is forced to cast on self + if (param3 & CAST_FORCE_TARGET_SELF) + { + param3 |= CAST_TRIGGERED; + caster = target; + } + + //Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered + bool canCast = !(caster->IsNonMeleeSpellCasted(false) && (param3 & CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS)); + + // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them + if(param3 & CAST_AURA_NOT_PRESENT) + { + if(target->HasAura(param1)) + return; + } + + if (canCast) + { + const SpellEntry* tSpell = GetSpellStore()->LookupEntry(param1); + + //Verify that spell exists + if (tSpell) + { + //Check if cannot cast spell + if (!(param3 & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) && + !CanCast(target, tSpell, (param3 & CAST_TRIGGERED))) + { + //Melee current victim if flag not set + if (!(param3 & CAST_NO_MELEE_IF_OOM)) + { + if (m_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + { + AttackDistance = 0; + AttackAngle = 0; + + m_creature.GetMotionMaster()->MoveChase(m_creature.getVictim(), AttackDistance, AttackAngle); + } + } + + } + else + { + //Interrupt any previous spell + if (caster->IsNonMeleeSpellCasted(false) && param3 & CAST_INTURRUPT_PREVIOUS) + caster->InterruptNonMeleeSpells(false); + + caster->CastSpell(target, param1, (param3 & CAST_TRIGGERED)); + } + + }else + sLog.outErrorDb("CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature.GetEntry(), param1); + } + } + break; + case ACTION_T_SUMMON: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + Creature* pCreature = NULL; + + if (param3) + pCreature = m_creature.SummonCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, param3); + else + pCreature = m_creature.SummonCreature(param1, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + + if (!pCreature) + { + + sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d", param1, EventId, m_creature.GetEntry()); + } + else if (param2 != TARGET_T_SELF && target) + pCreature->AI()->AttackStart(target); + } + break; + case ACTION_T_THREAT_SINGLE_PCT: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + m_creature.getThreatManager().modifyThreatPercent(target, param1); + } + break; + case ACTION_T_THREAT_ALL_PCT: + { + Unit* Temp = NULL; + + std::list<HostilReference*>::iterator i = m_creature.getThreatManager().getThreatList().begin(); + for (; i != m_creature.getThreatManager().getThreatList().end(); ++i) + { + Temp = Unit::GetUnit(m_creature,(*i)->getUnitGuid()); + if (Temp) + m_creature.getThreatManager().modifyThreatPercent(Temp, param1); + } + } + break; + case ACTION_T_QUEST_EVENT: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target && target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->AreaExploredOrEventHappens(param1); + } + break; + case ACTION_T_CASTCREATUREGO: + { + Unit* target = GetTargetByType(param3, pActionInvoker); + + if (target && target->GetTypeId() == TYPEID_PLAYER) + ((Player*)target)->CastedCreatureOrGO(param1, m_creature.GetGUID(), param2); + } + break; + case ACTION_T_SET_UNIT_FIELD: + { + Unit* target = GetTargetByType(param3, pActionInvoker); + + if (param1 < OBJECT_END || param1 >= UNIT_END) + return; + + if (target) + target->SetUInt32Value(param1, param2); + } + break; + case ACTION_T_SET_UNIT_FLAG: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + target->SetFlag(UNIT_FIELD_FLAGS, param1); + } + break; + case ACTION_T_REMOVE_UNIT_FLAG: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + if (target) + target->RemoveFlag(UNIT_FIELD_FLAGS, param1); + } + break; + case ACTION_T_AUTO_ATTACK: + { + if (param1) + MeleeEnabled = true; + else MeleeEnabled = false; + } + break; + case ACTION_T_COMBAT_MOVEMENT: + { + CombatMovementEnabled = param1; + + //Allow movement (create new targeted movement gen only if idle) + if (CombatMovementEnabled) + { + m_creature.GetMotionMaster()->MoveChase(m_creature.getVictim(), AttackDistance, AttackAngle); + } + else + { + m_creature.GetMotionMaster()->MoveIdle(); + } + } + break; + case ACTION_T_SET_PHASE: + { + Phase = param1; + } + break; + case ACTION_T_INC_PHASE: + { + Phase += param1; + + if (Phase > 31) + + sLog.outErrorDb( "CreatureEventAI: Event %d incremented Phase above 31. Phase mask cannot be used with phases past 31. CreatureEntry = %d", EventId, m_creature.GetEntry()); + } + break; + case ACTION_T_EVADE: + { + EnterEvadeMode(); + } + break; + case ACTION_T_FLEE: + { + if(m_creature.HasAuraType(SPELL_AURA_PREVENTS_FLEEING)) + break; + TimetoFleeLeft = 8000; + m_creature.DoFleeToGetAssistance(); + IsFleeing = true; + } + break; + case ACTION_T_QUEST_EVENT_ALL: + { + Unit* Temp = NULL; + if( pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER ) + { + Temp = Unit::GetUnit(m_creature,pActionInvoker->GetGUID()); + if( Temp ) + ((Player*)Temp)->GroupEventHappens(param1,&m_creature); + } + } + break; + case ACTION_T_CASTCREATUREGO_ALL: + { + Unit* Temp = NULL; + + std::list<HostilReference*>::iterator i = m_creature.getThreatManager().getThreatList().begin(); + for (; i != m_creature.getThreatManager().getThreatList().end(); ++i) + { + Temp = Unit::GetUnit(m_creature,(*i)->getUnitGuid()); + if (Temp && Temp->GetTypeId() == TYPEID_PLAYER) + ((Player*)Temp)->CastedCreatureOrGO(param1, m_creature.GetGUID(), param2); + } + } + break; + case ACTION_T_REMOVEAURASFROMSPELL: + { + Unit* target = GetTargetByType(param1, pActionInvoker); + + if (target) + target->RemoveAurasDueToSpell(param2); + } + break; + case ACTION_T_RANGED_MOVEMENT: + { + AttackDistance = param1; + AttackAngle = ((float)param2/180)*M_PI; + + if (CombatMovementEnabled) + { + m_creature.GetMotionMaster()->MoveChase(m_creature.getVictim(), AttackDistance, AttackAngle); + } + } + break; + case ACTION_T_RANDOM_PHASE: + { + uint32 temp = GetRandActionParam(rnd, param1, param2, param3); + + Phase = temp; + } + break; + case ACTION_T_RANDOM_PHASE_RANGE: + { + if (param2 > param1) + { + Phase = param1 + (rnd % (param2 - param1)); + } + else + sLog.outErrorDb( "CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 <= Param1. Divide by Zero. Event = %d. CreatureEntry = %d", EventId, m_creature.GetEntry()); + } + break; + case ACTION_T_SUMMON_ID: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + + //Duration + Creature* pCreature = NULL; + + CreatureEventAI_Summon_Map::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAISummonMap().find(param3); + if (i == CreatureEAI_Mgr.GetCreatureEventAISummonMap().end()) + { + + sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", param1, param3, EventId, m_creature.GetEntry()); + return; + } + + if ((*i).second.SpawnTimeSecs) + pCreature = m_creature.SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs); + else pCreature = m_creature.SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + + if (!pCreature) + { + + sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d", param1, EventId, m_creature.GetEntry()); + } + else if (param2 != TARGET_T_SELF && target) + pCreature->AI()->AttackStart(target); + } + break; + case ACTION_T_KILLED_MONSTER: + { + //first attempt player who tapped creature + if (Player* pPlayer = m_creature.GetLootRecipient()) + pPlayer->RewardPlayerAndGroupAtEvent(param1, &m_creature); + else + { + //if not available, use pActionInvoker + Unit* pTarget = GetTargetByType(param2, pActionInvoker); + + if (Player* pPlayer = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself()) + pPlayer->RewardPlayerAndGroupAtEvent(param1, &m_creature); + } + } + break; + case ACTION_T_SET_INST_DATA: + { + InstanceData* pInst = (InstanceData*)m_creature.GetInstanceData(); + if (!pInst) + { + sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data without instance script. Creature %d", EventId, m_creature.GetEntry()); + return; + } + + pInst->SetData(param1, param2); + } + break; + case ACTION_T_SET_INST_DATA64: + { + Unit* target = GetTargetByType(param2, pActionInvoker); + if (!target) + { + sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature.GetEntry()); + return; + } + + InstanceData* pInst = (InstanceData*)m_creature.GetInstanceData(); + if (!pInst) + { + sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 without instance script. Creature %d", EventId, m_creature.GetEntry()); + return; + } + + pInst->SetData64(param1, target->GetGUID()); + } + break; + case ACTION_T_UPDATE_TEMPLATE: + { + if (m_creature.GetEntry() == param1) + { + + sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, m_creature.GetEntry()); + return; + } + + m_creature.UpdateEntry(param1, param2 ? HORDE : ALLIANCE); + } + break; + case ACTION_T_DIE: + { + if (m_creature.isDead()) + { + + sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_DIE on dead creature. Creature %d", EventId, m_creature.GetEntry()); + return; + } + m_creature.DealDamage(&m_creature, m_creature.GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + break; + case ACTION_T_ZONE_COMBAT_PULSE: + { + if (!m_creature.isInCombat() || !m_creature.GetMap()->IsDungeon()) + { + + sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature.GetEntry()); + return; + } + + DoZoneInCombat(&m_creature); + } + break; + + // TRINITY ONLY + case ACTION_T_SET_ACTIVE: + me->setActive(param1 ? true : false); + break; + case ACTION_T_SET_AGGRESSIVE: + me->SetReactState(ReactStates(param1)); + break; + case ACTION_T_ATTACK_START_PULSE: + AttackStart(me->SelectNearestTarget((float)param1)); + break; + } +} + +void CreatureEventAI::JustRespawned() +{ + InCombat = false; + IsFleeing = false; + Reset(); + + if (bEmptyList) + return; + + //Handle Spawned Events + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_SPAWNED) + ProcessEvent(*i); + } +} + +void CreatureEventAI::Reset() +{ + EventUpdateTime = EVENT_UPDATE_TIME; + EventDiff = 0; + + TimetoFleeLeft = 0; + IsFleeing = false; + + if (bEmptyList) + return; + + //Reset all events to enabled + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + switch ((*i).Event.event_type) + { + //Reset all out of combat timers + case EVENT_T_TIMER_OOC: + { + if ((*i).Event.event_param2 == (*i).Event.event_param1) + { + (*i).Time = (*i).Event.event_param1; + (*i).Enabled = true; + } + else if ((*i).Event.event_param2 > (*i).Event.event_param1) + { + (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); + (*i).Enabled = true; + } + else + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature.GetEntry(), (*i).Event.event_id, (*i).Event.event_type); + } + break; + //default: + //TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void Aggro() + //(*i).Enabled = true; + //(*i).Time = 0; + //break; + } + } +} + +void CreatureEventAI::JustReachedHome() +{ + m_creature.LoadCreaturesAddon(); + + if (!bEmptyList) + { + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_REACHED_HOME) + ProcessEvent(*i); + } + } + + Reset(); +} + +void CreatureEventAI::EnterEvadeMode() +{ + m_creature.InterruptNonMeleeSpells(true); + m_creature.RemoveAllAuras(); + m_creature.DeleteThreatList(); + m_creature.CombatStop(); + + if (m_creature.isAlive()) + m_creature.GetMotionMaster()->MoveTargetedHome(); + + m_creature.SetLootRecipient(NULL); + + InCombat = false; + + if (bEmptyList) + return; + + //Handle Evade events + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_EVADE) + ProcessEvent(*i); + } +} + +void CreatureEventAI::JustDied(Unit* killer) +{ + InCombat = false; + IsFleeing = false; + Reset(); + + if (bEmptyList) + return; + + //Handle Evade events + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_DEATH) + ProcessEvent(*i, killer); + } +} + +void CreatureEventAI::KilledUnit(Unit* victim) +{ + if (bEmptyList || victim->GetTypeId() != TYPEID_PLAYER) + return; + + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_KILL) + ProcessEvent(*i, victim); + } +} + +void CreatureEventAI::JustSummoned(Creature* pUnit) +{ + if (bEmptyList || !pUnit) + return; + + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT) + ProcessEvent(*i, pUnit); + } +} + +void CreatureEventAI::Aggro(Unit *who) +{ + //Check for on combat start events + if (!bEmptyList) + { + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + switch ((*i).Event.event_type) + { + case EVENT_T_AGGRO: + (*i).Enabled = true; + ProcessEvent(*i, who); + break; + //Reset all in combat timers + case EVENT_T_TIMER: + if ((*i).Event.event_param2 == (*i).Event.event_param1) + { + (*i).Time = (*i).Event.event_param1; + (*i).Enabled = true; + } + else if ((*i).Event.event_param2 > (*i).Event.event_param1) + { + (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); + (*i).Enabled = true; + } + else + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature.GetEntry(), (*i).Event.event_id, (*i).Event.event_type); + break; + //All normal events need to be re-enabled and their time set to 0 + default: + (*i).Enabled = true; + (*i).Time = 0; + break; + } + } + } + + EventUpdateTime = EVENT_UPDATE_TIME; + EventDiff = 0; +} + +void CreatureEventAI::AttackStart(Unit *who) +{ + if (!who) + return; + + if (m_creature.Attack(who, MeleeEnabled)) + { + if (!InCombat) + { + InCombat = true; + Aggro(who); + } + + if (CombatMovementEnabled) + { + m_creature.GetMotionMaster()->MoveChase(who, AttackDistance, AttackAngle); + } + else + { + m_creature.GetMotionMaster()->MoveIdle(); + } + } +} + +void CreatureEventAI::MoveInLineOfSight(Unit *who) +{ + if (!who || InCombat) + return; + + //Check for OOC LOS Event + if (!bEmptyList && !m_creature.getVictim()) + { + for (std::list<CreatureEventAIHolder>::iterator itr = CreatureEventAIList.begin(); itr != CreatureEventAIList.end(); ++itr) + { + if ((*itr).Event.event_type == EVENT_T_OOC_LOS) + { + //can trigger if closer than fMaxAllowedRange + float fMaxAllowedRange = (*itr).Event.event_param2; + + //if range is ok and we are actually in LOS + if (m_creature.IsWithinDistInMap(who, fMaxAllowedRange) && m_creature.IsWithinLOSInMap(who)) + { + //if friendly event&&who is not hostile OR hostile event&&who is hostile + if (((*itr).Event.event_param1 && !m_creature.IsHostileTo(who)) || + ((!(*itr).Event.event_param1) && m_creature.IsHostileTo(who))) + ProcessEvent(*itr, who); + } + } + } + } + + //if (m_creature.isCivilian() && m_creature.IsNeutralToAll()) + // return; + + if(me->canStartAttack(who)) + AttackStart(who); +} + +void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell) +{ + + if (bEmptyList) + return; + + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + if ((*i).Event.event_type == EVENT_T_SPELLHIT) + { + //If spell id matches (or no spell id) & if spell school matches (or no spell school) + if (!(*i).Event.event_param1 || pSpell->Id == (*i).Event.event_param1) + { + if ((*i).Event.event_param2_s == -1 || pSpell->SchoolMask == (*i).Event.event_param2) + ProcessEvent(*i, pUnit); + } + } + } +} + +void CreatureEventAI::UpdateAI(const uint32 diff) +{ + //Check if we are in combat (also updates calls threat update code) + bool Combat = InCombat ? UpdateVictim() : false; + + //Must return if creature isn't alive. Normally select hostil target and get victim prevent this + if (!m_creature.isAlive()) + return; + + if (IsFleeing) + { + if(TimetoFleeLeft < diff) + { + me->SetControlled(false, UNIT_STAT_FLEEING); + me->SetNoCallAssistance(false); + me->CallAssistance(); + if(me->getVictim()) + me->GetMotionMaster()->MoveChase(me->getVictim()); + IsFleeing = false; + } + else + TimetoFleeLeft -= diff; + + return; + } + + if (!bEmptyList) + { + //Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events + if (EventUpdateTime < diff) + { + EventDiff += diff; + + //Check for time based events + for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) + { + //Decrement Timers + if ((*i).Time) + { + if ((*i).Time > EventDiff) + { + //Do not decrement timers if event cannot trigger in this phase + if (!((*i).Event.event_inverse_phase_mask & (1 << Phase))) + (*i).Time -= EventDiff; + + //Skip processing of events that have time remaining + continue; + } + else (*i).Time = 0; + } + + //Events that are updated every EVENT_UPDATE_TIME + switch ((*i).Event.event_type) + { + case EVENT_T_TIMER_OOC: + ProcessEvent(*i); + break; + case EVENT_T_TIMER: + case EVENT_T_MANA: + case EVENT_T_HP: + case EVENT_T_TARGET_HP: + case EVENT_T_TARGET_CASTING: + case EVENT_T_FRIENDLY_HP: + if (Combat) + ProcessEvent(*i); + break; + case EVENT_T_RANGE: + if (Combat) + { + if (m_creature.IsWithinDistInMap(m_creature.getVictim(),(float)(*i).Event.event_param2)) + { + if (m_creature.GetDistance(m_creature.getVictim()) >= (float)(*i).Event.event_param1) + ProcessEvent(*i); + } + } + break; + } + } + + EventDiff = 0; + EventUpdateTime = EVENT_UPDATE_TIME; + } + else + { + EventDiff += diff; + EventUpdateTime -= diff; + } + } + + //Melee Auto-Attack + if (Combat && MeleeEnabled) + DoMeleeAttackIfReady(); +} + +inline Unit* CreatureEventAI::SelectUnit(AttackingTarget target, uint32 position) +{ + //ThreatList m_threatlist; + std::list<HostilReference*>& m_threatlist = m_creature.getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator i = m_threatlist.begin(); + std::list<HostilReference*>::reverse_iterator r = m_threatlist.rbegin(); + + if (position >= m_threatlist.size() || !m_threatlist.size()) + return NULL; + + switch (target) + { + case ATTACKING_TARGET_RANDOM: + { + advance ( i , position + (rand() % (m_threatlist.size() - position ) )); + return Unit::GetUnit(m_creature,(*i)->getUnitGuid()); + } + case ATTACKING_TARGET_TOPAGGRO: + { + advance ( i , position); + return Unit::GetUnit(m_creature,(*i)->getUnitGuid()); + } + case ATTACKING_TARGET_BOTTOMAGGRO: + { + advance ( r , position); + return Unit::GetUnit(m_creature,(*r)->getUnitGuid()); + } + } + return NULL; +} + +inline uint32 CreatureEventAI::GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3) +{ + switch (rnd % 3) + { + case 0: + return param1; + break; + case 1: + return param2; + break; + case 2: + return param3; + break; + } + return 0; +} + +inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker) +{ + switch (Target) + { + case TARGET_T_SELF: + return &m_creature; + break; + case TARGET_T_HOSTILE: + return m_creature.getVictim(); + break; + case TARGET_T_HOSTILE_SECOND_AGGRO: + return SelectUnit(ATTACKING_TARGET_TOPAGGRO,1); + break; + case TARGET_T_HOSTILE_LAST_AGGRO: + return SelectUnit(ATTACKING_TARGET_BOTTOMAGGRO,0); + break; + case TARGET_T_HOSTILE_RANDOM: + return SelectUnit(ATTACKING_TARGET_RANDOM,0); + break; + case TARGET_T_HOSTILE_RANDOM_NOT_TOP: + return SelectUnit(ATTACKING_TARGET_RANDOM,1); + break; + case TARGET_T_ACTION_INVOKER: + return pActionInvoker; + break; + default: + return NULL; + break; + }; +} + +Unit* CreatureEventAI::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature.GetPositionX(), m_creature.GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Unit* pUnit = NULL; + + MaNGOS::MostHPMissingInRange u_check(&m_creature, range, MinHPDiff); + MaNGOS::UnitLastSearcher<MaNGOS::MostHPMissingInRange> searcher(&m_creature, pUnit, u_check); + + /* + typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes; + This means that if we only search grid then we cannot possibly return pets or players so this is safe + */ + TypeContainerVisitor<MaNGOS::UnitLastSearcher<MaNGOS::MostHPMissingInRange>, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_unit_searcher, *m_creature.GetMap()); + return pUnit; +} + +void CreatureEventAI::DoFindFriendlyCC(std::list<Creature*>& _list, float range) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature.GetPositionX(), m_creature.GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::FriendlyCCedInRange u_check(&m_creature, range); + MaNGOS::CreatureListSearcher<MaNGOS::FriendlyCCedInRange> searcher(&m_creature, _list, u_check); + + TypeContainerVisitor<MaNGOS::CreatureListSearcher<MaNGOS::FriendlyCCedInRange>, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature.GetMap()); +} + +void CreatureEventAI::DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid) +{ + CellPair p(MaNGOS::ComputeCellPair(m_creature.GetPositionX(), m_creature.GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::FriendlyMissingBuffInRange u_check(&m_creature, range, spellid); + MaNGOS::CreatureListSearcher<MaNGOS::FriendlyMissingBuffInRange> searcher(&m_creature, _list, u_check); + + TypeContainerVisitor<MaNGOS::CreatureListSearcher<MaNGOS::FriendlyMissingBuffInRange>, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature.GetMap()); +} + +//********************************* +//*** Functions used globally *** + +void CreatureEventAI::DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target) +{ + if (!pSource) + { + sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i, invalid Source pointer.",textEntry); + return; + } + + if (textEntry >= 0) + { + sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry); + return; + } + + CreatureEventAI_TextMap::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAITextMap().find(textEntry); + + if (i == CreatureEAI_Mgr.GetCreatureEventAITextMap().end()) + { + sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry); + return; + } + + sLog.outDebug("CreatureEventAI: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u",textEntry,(*i).second.SoundId,(*i).second.Type,(*i).second.Language,(*i).second.Emote); + + if((*i).second.SoundId) + { + if (GetSoundEntriesStore()->LookupEntry((*i).second.SoundId)) + pSource->PlayDirectSound((*i).second.SoundId); + else + sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process invalid sound id %u.",textEntry,(*i).second.SoundId); + } + + if((*i).second.Emote) + { + if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER) + { + ((Unit*)pSource)->HandleEmoteCommand((*i).second.Emote); + } + else + sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process emote for invalid TypeId (%u).",textEntry,pSource->GetTypeId()); + } + + switch((*i).second.Type) + { + case CHAT_TYPE_SAY: + pSource->MonsterSay(textEntry, (*i).second.Language, target ? target->GetGUID() : 0); + break; + case CHAT_TYPE_YELL: + pSource->MonsterYell(textEntry, (*i).second.Language, target ? target->GetGUID() : 0); + break; + case CHAT_TYPE_TEXT_EMOTE: + pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0); + break; + case CHAT_TYPE_BOSS_EMOTE: + pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0, true); + break; + case CHAT_TYPE_WHISPER: + { + if (target && target->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(textEntry, target->GetGUID()); + else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry); + }break; + case CHAT_TYPE_BOSS_WHISPER: + { + if (target && target->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(textEntry, target->GetGUID(), true); + else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry); + }break; + case CHAT_TYPE_ZONE_YELL: + pSource->MonsterYellToZone(textEntry, (*i).second.Language, target ? target->GetGUID() : 0); + break; + } +} + +bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered) +{ + //No target so we can't cast + if (!Target || !Spell) + return false; + + //Silenced so we can't cast + if (!Triggered && me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + return false; + + //Check for power + if (!Triggered && me->GetPower((Powers)Spell->powerType) < Spell->manaCost) + return false; + + SpellRangeEntry const *TempRange = NULL; + + TempRange = GetSpellRangeStore()->LookupEntry(Spell->rangeIndex); + + //Spell has invalid range store so we can't use it + if (!TempRange) + return false; + + //Unit is out of range of this spell + if (me->GetDistance(Target) > me->GetSpellMaxRangeForTarget(Target, TempRange) + || me->GetDistance(Target) < me->GetSpellMinRangeForTarget(Target, TempRange)) + return false; + + return true; +} + +bool CreatureEventAI::ReceiveEmote(Player* pPlayer, Creature* pCreature, uint32 uiEmote) +{ + if(pCreature->isCharmed()) + return true; + + CreatureEventAI* pTmpCreature = (CreatureEventAI*)(pCreature->AI()); + + if (pTmpCreature->bEmptyList) + return true; + + for (std::list<CreatureEventAIHolder>::iterator itr = pTmpCreature->CreatureEventAIList.begin(); itr != pTmpCreature->CreatureEventAIList.end(); ++itr) + { + if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE) + { + if ((*itr).Event.event_param1 != uiEmote) + return true; + + bool bProcess = false; + + switch((*itr).Event.event_param2) + { + //enum ConditionType + case CONDITION_NONE: // 0 0 + bProcess = true; + break; + case CONDITION_AURA: // spell_id effindex + if (pPlayer->HasAura((*itr).Event.event_param3,(*itr).Event.event_param4)) + bProcess = true; + break; + case CONDITION_ITEM: // item_id count + if (pPlayer->HasItemCount((*itr).Event.event_param3,(*itr).Event.event_param4)) + bProcess = true; + break; + case CONDITION_ITEM_EQUIPPED: // item_id count + if (pPlayer->HasItemOrGemWithIdEquipped((*itr).Event.event_param3,(*itr).Event.event_param4)) + bProcess = true; + break; + case CONDITION_ZONEID: // zone_id 0 + if (pPlayer->GetZoneId() == (*itr).Event.event_param3) + bProcess = true; + break; + case CONDITION_REPUTATION_RANK: // faction_id min_rank + if (pPlayer->GetReputationRank((*itr).Event.event_param3) >= (*itr).Event.event_param4) + bProcess = true; + break; + case CONDITION_TEAM: // player_team 0, (469 - Alliance 67 - Horde) + if (pPlayer->GetTeam() == (*itr).Event.event_param3) + bProcess = true; + break; + case CONDITION_SKILL: // skill_id min skill_value + if (pPlayer->HasSkill((*itr).Event.event_param3) && pPlayer->GetSkillValue((*itr).Event.event_param3) >= (*itr).Event.event_param4) + bProcess = true; + break; + case CONDITION_QUESTREWARDED: // quest_id 0 + if (pPlayer->GetQuestRewardStatus((*itr).Event.event_param3)) + bProcess = true; + break; + case CONDITION_QUESTTAKEN: // quest_id 0, for condition true while quest active. + if (pPlayer->GetQuestStatus((*itr).Event.event_param3) == QUEST_STATUS_INCOMPLETE) + bProcess = true; + break; + case CONDITION_ACTIVE_EVENT: // event_id 0 + if (IsHolidayActive(HolidayIds((*itr).Event.event_param3))) + bProcess = true; + break; + } + + if (bProcess) + { + sLog.outDebug("CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing"); + pTmpCreature->ProcessEvent(*itr, pPlayer); + } + } + } + + return true; +} diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h new file mode 100644 index 00000000000..74ea7a40a6a --- /dev/null +++ b/src/game/CreatureEventAI.h @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MANGOS_CREATURE_EAI_H +#define MANGOS_CREATURE_EAI_H + +#include "Common.h" +#include "Creature.h" +#include "CreatureAI.h" +#include "Unit.h" + +class Player; +class WorldObject; + +#define EVENT_UPDATE_TIME 500 +#define SPELL_RUN_AWAY 8225 +#define MAX_ACTIONS 3 +#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available + +enum Event_Types +{ + EVENT_T_TIMER = 0, //InitialMin, InitialMax, RepeatMin, RepeatMax + EVENT_T_TIMER_OOC = 1, //InitialMin, InitialMax, RepeatMin, RepeatMax + EVENT_T_HP = 2, //HPMax%, HPMin%, RepeatMin, RepeatMax + EVENT_T_MANA = 3, //ManaMax%,ManaMin% RepeatMin, RepeatMax + EVENT_T_AGGRO = 4, //NONE + EVENT_T_KILL = 5, //RepeatMin, RepeatMax + EVENT_T_DEATH = 6, //NONE + EVENT_T_EVADE = 7, //NONE + EVENT_T_SPELLHIT = 8, //SpellID, School, RepeatMin, RepeatMax + EVENT_T_RANGE = 9, //MinDist, MaxDist, RepeatMin, RepeatMax + EVENT_T_OOC_LOS = 10, //NoHostile, NoFriendly, RepeatMin, RepeatMax + EVENT_T_SPAWNED = 11, //NONE + EVENT_T_TARGET_HP = 12, //HPMax%, HPMin%, RepeatMin, RepeatMax + EVENT_T_TARGET_CASTING = 13, //RepeatMin, RepeatMax + EVENT_T_FRIENDLY_HP = 14, //HPDeficit, Radius, RepeatMin, RepeatMax + EVENT_T_FRIENDLY_IS_CC = 15, //DispelType, Radius, RepeatMin, RepeatMax + EVENT_T_FRIENDLY_MISSING_BUFF = 16, //SpellId, Radius, RepeatMin, RepeatMax + EVENT_T_SUMMONED_UNIT = 17, //CreatureId, RepeatMin, RepeatMax + EVENT_T_TARGET_MANA = 18, //ManaMax%, ManaMin%, RepeatMin, RepeatMax + EVENT_T_QUEST_ACCEPT = 19, //QuestID + EVENT_T_QUEST_COMPLETE = 20, // + EVENT_T_REACHED_HOME = 21, //NONE + EVENT_T_RECEIVE_EMOTE = 22, //EmoteId, Condition, CondValue1, CondValue2 + + EVENT_T_END, +}; + +enum Action_Types +{ + ACTION_T_NONE = 0, //No action + ACTION_T_TEXT = 1, //-TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values. + ACTION_T_SET_FACTION = 2, //FactionId (or 0 for default) + ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, //Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph) + ACTION_T_SOUND = 4, //SoundId + ACTION_T_EMOTE = 5, //EmoteId + ACTION_T_RANDOM_SAY = 6, //UNUSED + ACTION_T_RANDOM_YELL = 7, //UNUSED + ACTION_T_RANDOM_TEXTEMOTE = 8, //UNUSED + ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field) + ACTION_T_RANDOM_EMOTE = 10, //EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field) + ACTION_T_CAST = 11, //SpellId, Target, CastFlags + ACTION_T_SUMMON = 12, //CreatureID, Target, Duration in ms + ACTION_T_THREAT_SINGLE_PCT = 13, //Threat%, Target + ACTION_T_THREAT_ALL_PCT = 14, //Threat% + ACTION_T_QUEST_EVENT = 15, //QuestID, Target + ACTION_T_CASTCREATUREGO = 16, //QuestID, SpellId, Target + ACTION_T_SET_UNIT_FIELD = 17, //Field_Number, Value, Target + ACTION_T_SET_UNIT_FLAG = 18, //Flags (may be more than one field OR'd together), Target + ACTION_T_REMOVE_UNIT_FLAG = 19, //Flags (may be more than one field OR'd together), Target + ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking) + ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking) + ACTION_T_SET_PHASE = 22, //Phase + ACTION_T_INC_PHASE = 23, //Value (may be negative to decrement phase, should not be 0) + ACTION_T_EVADE = 24, //No Params + ACTION_T_FLEE = 25, //No Params + ACTION_T_QUEST_EVENT_ALL = 26, //QuestID + ACTION_T_CASTCREATUREGO_ALL = 27, //QuestId, SpellId + ACTION_T_REMOVEAURASFROMSPELL = 28, //Target, Spellid + ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle + ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3 + ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax + ACTION_T_SUMMON_ID = 32, //CreatureId, Target, SpawnId + ACTION_T_KILLED_MONSTER = 33, //CreatureId, Target + ACTION_T_SET_INST_DATA = 34, //Field, Data + ACTION_T_SET_INST_DATA64 = 35, //Field, Target + ACTION_T_UPDATE_TEMPLATE = 36, //Entry, Team + ACTION_T_DIE = 37, //No Params + ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params + + ACTION_T_SET_ACTIVE = 101, //Apply + ACTION_T_SET_AGGRESSIVE = 102, //Apply + ACTION_T_ATTACK_START_PULSE = 103, //Distance + + ACTION_T_END, +}; + +enum Target +{ + //Self (m_creature) + TARGET_T_SELF = 0, //Self cast + + //Hostile targets (if pet then returns pet owner) + TARGET_T_HOSTILE, //Our current target (ie: highest aggro) + TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) + TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) + TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list + TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat + + //Invoker targets (if pet then returns pet owner) + TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) + + //Hostile targets (including pets) + TARGET_T_HOSTILE_WPET, //Current target (can be a pet) + TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks) + TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for) + TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list + TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat + + TARGET_T_ACTION_INVOKER_WPET, + + TARGET_T_END +}; + +enum CastFlags +{ + CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting + CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time) + CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range + CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range + CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself + CAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell +}; + +enum EventFlags +{ + EFLAG_REPEATABLE = 0x01, //Event repeats + EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty + EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty + EFLAG_RESERVED_3 = 0x08, + EFLAG_RESERVED_4 = 0x10, + EFLAG_RESERVED_5 = 0x20, + EFLAG_RESERVED_6 = 0x40, + EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build of SD2 only +}; + +// String text additional data, used in (CreatureEventAI) +struct StringTextData +{ + uint32 SoundId; + uint8 Type; + uint32 Language; + uint32 Emote; +}; +// Text Maps +typedef UNORDERED_MAP<int32, StringTextData> CreatureEventAI_TextMap; + +struct CreatureEventAI_Event +{ + uint32 event_id; + + uint32 creature_id; + + uint16 event_type; + uint32 event_inverse_phase_mask; + uint8 event_chance; + uint8 event_flags; + union + { + uint32 event_param1; + int32 event_param1_s; + }; + union + { + uint32 event_param2; + int32 event_param2_s; + }; + union + { + uint32 event_param3; + int32 event_param3_s; + }; + union + { + uint32 event_param4; + int32 event_param4_s; + }; + + struct _action + { + uint16 type; + union + { + uint32 param1; + int32 param1_s; + }; + union + { + uint32 param2; + int32 param2_s; + }; + union + { + uint32 param3; + int32 param3_s; + }; + }action[MAX_ACTIONS]; +}; +//Event_Map +typedef UNORDERED_MAP<uint32, std::vector<CreatureEventAI_Event> > CreatureEventAI_Event_Map; + +struct CreatureEventAI_Summon +{ + uint32 id; + + float position_x; + float position_y; + float position_z; + float orientation; + uint32 SpawnTimeSecs; +}; + +//EventSummon_Map +typedef UNORDERED_MAP<uint32, CreatureEventAI_Summon> CreatureEventAI_Summon_Map; + +struct CreatureEventAIHolder +{ + CreatureEventAIHolder(CreatureEventAI_Event p) : Event(p), Time(0), Enabled(true){} + + CreatureEventAI_Event Event; + uint32 Time; + bool Enabled; +}; + +class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI +{ + + public: + CreatureEventAI(Creature *c); + ~CreatureEventAI() + { + CreatureEventAIList.clear(); + } + void JustRespawned(); + void Reset(); + void JustReachedHome(); + void EnterEvadeMode(); + void JustDied(Unit* killer); + void KilledUnit(Unit* victim); + void JustSummoned(Creature* pUnit); + void Aggro(Unit *who); + void AttackStart(Unit *who); + void MoveInLineOfSight(Unit *who); + void SpellHit(Unit* pUnit, const SpellEntry* pSpell); + void UpdateAI(const uint32 diff); + static int Permissible(const Creature *); + + bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL); + void ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker); + inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3); + inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker); + inline Unit* SelectUnit(AttackingTarget target, uint32 position); + + void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target); + bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered); + bool ReceiveEmote(Player* pPlayer, Creature* pCreature, uint32 uiEmote); + + Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff); + void DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid); + void DoFindFriendlyCC(std::list<Creature*>& _list, float range); + + //Pointer to creature we are manipulating + Creature& m_creature; + + //Bool for if we are in combat or not + bool InCombat; + + //Holder for events (stores enabled, time, and eventid) + std::list<CreatureEventAIHolder> CreatureEventAIList; + uint32 EventUpdateTime; //Time between event updates + uint32 EventDiff; //Time between the last event call + bool bEmptyList; + + //Variables used by Events themselves + uint8 Phase; //Current phase, max 32 phases + bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat) + bool MeleeEnabled; //If we allow melee auto attack + uint32 AttackDistance; //Distance to attack from + float AttackAngle; //Angle of attack + + uint32 TimetoFleeLeft; + bool IsFleeing; +}; +#endif diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp new file mode 100644 index 00000000000..3e6c2822759 --- /dev/null +++ b/src/game/CreatureEventAIMgr.cpp @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Database/SQLStorage.h" +#include "CreatureEventAI.h" +#include "CreatureEventAIMgr.h" +#include "ObjectMgr.h" +#include "ProgressBar.h" +#include "Policies/SingletonImp.h" +#include "ObjectDefines.h" + +INSTANTIATE_SINGLETON_1(CreatureEventAIMgr); + +// ------------------- +void CreatureEventAIMgr::LoadCreatureEventAI_Texts() +{ + // Drop Existing Text Map, only done once and we are ready to add data from multiple sources. + m_CreatureEventAI_TextMap.clear(); + + // Load EventAI Text + LoadTrinityStrings(WorldDatabase,"creature_ai_texts",-1,1+(TEXT_SOURCE_RANGE)); + + // Gather Additional data from EventAI Texts + QueryResult *result = WorldDatabase.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts"); + + sLog.outString("Loading EventAI Texts additional data..."); + if (result) + { + barGoLink bar(result->GetRowCount()); + uint32 count = 0; + + do + { + bar.step(); + Field* fields = result->Fetch(); + StringTextData temp; + + int32 i = fields[0].GetInt32(); + temp.SoundId = fields[1].GetInt32(); + temp.Type = fields[2].GetInt32(); + temp.Language = fields[3].GetInt32(); + temp.Emote = fields[4].GetInt32(); + + if (i >= 0) + { + sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is not a negative value.",i); + continue; + } + + if (i <= TEXT_SOURCE_RANGE) + { + sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is out of accepted entry range for table.",i); + continue; + } + + if (temp.SoundId) + { + if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId)) + sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has soundId %u but sound does not exist.",i,temp.SoundId); + } + + if (!GetLanguageDescByID(temp.Language)) + sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` using Language %u but Language does not exist.",i,temp.Language); + + if (temp.Type > CHAT_TYPE_BOSS_WHISPER) + sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Type %u but this Chat Type does not exist.",i,temp.Type); + + m_CreatureEventAI_TextMap[i] = temp; + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u additional CreatureEventAI Texts data.", count); + }else + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 additional CreatureEventAI Texts data. DB table `creature_ai_texts` is empty."); + } + +} + +// ------------------- +void CreatureEventAIMgr::LoadCreatureEventAI_Summons() +{ + + //Drop Existing EventSummon Map + m_CreatureEventAI_Summon_Map.clear(); + + //Gather additional data for EventAI + QueryResult *result = WorldDatabase.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons"); + if (result) + { + barGoLink bar(result->GetRowCount()); + uint32 Count = 0; + + do + { + bar.step(); + Field *fields = result->Fetch(); + + CreatureEventAI_Summon temp; + + uint32 i = fields[0].GetUInt32(); + temp.position_x = fields[1].GetFloat(); + temp.position_y = fields[2].GetFloat(); + temp.position_z = fields[3].GetFloat(); + temp.orientation = fields[4].GetFloat(); + temp.SpawnTimeSecs = fields[5].GetUInt32(); + + //Add to map + m_CreatureEventAI_Summon_Map[i] = temp; + ++Count; + }while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u CreatureEventAI summon definitions", Count); + }else + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 CreatureEventAI Summon definitions. DB table `creature_ai_summons` is empty."); + } + +} + +// ------------------- +void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() +{ + //Drop Existing EventAI List + m_CreatureEventAI_Event_Map.clear(); + + //Gather event data + QueryResult *result = WorldDatabase.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, " + "event_param1, event_param2, event_param3, event_param4, " + "action1_type, action1_param1, action1_param2, action1_param3, " + "action2_type, action2_param1, action2_param2, action2_param3, " + "action3_type, action3_param1, action3_param2, action3_param3 " + "FROM creature_ai_scripts"); + if (result) + { + barGoLink bar(result->GetRowCount()); + uint32 Count = 0; + + do + { + bar.step(); + Field *fields = result->Fetch(); + + CreatureEventAI_Event temp; + + temp.event_id = fields[0].GetUInt32(); + uint32 i = temp.event_id; + temp.creature_id = fields[1].GetUInt32(); + uint32 creature_id = temp.creature_id; + temp.event_type = fields[2].GetUInt16(); + temp.event_inverse_phase_mask = fields[3].GetUInt32(); + temp.event_chance = fields[4].GetUInt8(); + temp.event_flags = fields[5].GetUInt8(); + temp.event_param1 = fields[6].GetUInt32(); + temp.event_param2 = fields[7].GetUInt32(); + temp.event_param3 = fields[8].GetUInt32(); + temp.event_param4 = fields[9].GetUInt32(); + + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(temp.creature_id); + //Creature does not exist in database + if (!cInfo) + { + sLog.outErrorDb("CreatureEventAI: Event %u has script for non-existing creature.", i); + continue; + } + + //Report any errors in event + if (temp.event_type >= EVENT_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u has incorrect event type. Maybe DB requires updated version of SD2.", i); + + //No chance of this event occuring + if (temp.event_chance == 0) + sLog.outErrorDb("CreatureEventAI: Event %u has 0 percent chance. Event will never trigger!", i); + + //Chance above 100, force it to be 100 + if (temp.event_chance > 100) + { + sLog.outErrorDb("CreatureEventAI: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp.creature_id, i); + temp.event_chance = 100; + } + + //Individual event checks + switch (temp.event_type) + { + case EVENT_T_HP: + case EVENT_T_MANA: + case EVENT_T_TARGET_HP: + { + if (temp.event_param2 > 100) + sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i); + + if (temp.event_param1 <= temp.event_param2) + sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i); + + if (temp.event_flags & EFLAG_REPEATABLE && !temp.event_param3 && !temp.event_param4) + { + sLog.outErrorDb("CreatureEventAI: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i); + temp.event_flags &= ~EFLAG_REPEATABLE; + } + } + break; + + case EVENT_T_SPELLHIT: + { + if (temp.event_param1) + { + SpellEntry const* pSpell = GetSpellStore()->LookupEntry(temp.event_param1); + if (!pSpell) + { + sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i); + continue; + } + + if (temp.event_param2_s != -1 && temp.event_param2 != pSpell->SchoolMask) + sLog.outErrorDb("CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.event_param1, i); + } + + //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0 + //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit() + if (temp.event_param2_s != -1 && temp.event_param2_s > SPELL_SCHOOL_MASK_ALL) + sLog.outErrorDb("CreatureEventAI: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.event_param2, i); + + if (temp.event_param4 < temp.event_param3) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + } + break; + + case EVENT_T_RANGE: + case EVENT_T_OOC_LOS: + case EVENT_T_FRIENDLY_HP: + case EVENT_T_FRIENDLY_IS_CC: + case EVENT_T_FRIENDLY_MISSING_BUFF: + { + if (temp.event_param4 < temp.event_param3) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + } + break; + + case EVENT_T_TIMER: + case EVENT_T_TIMER_OOC: + { + if (temp.event_param2 < temp.event_param1) + sLog.outErrorDb("CreatureEventAI: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i); + + if (temp.event_param4 < temp.event_param3) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + } + break; + + case EVENT_T_KILL: + case EVENT_T_TARGET_CASTING: + { + if (temp.event_param2 < temp.event_param1) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + } + break; + + case EVENT_T_AGGRO: + case EVENT_T_DEATH: + case EVENT_T_EVADE: + case EVENT_T_SPAWNED: + case EVENT_T_REACHED_HOME: + { + if (temp.event_flags & EFLAG_REPEATABLE) + { + sLog.outErrorDb("CreatureEventAI: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp.creature_id, i); + temp.event_flags &= ~EFLAG_REPEATABLE; + } + } + break; + } + + for (uint32 j = 0; j < MAX_ACTIONS; j++) + { + temp.action[j].type = fields[10+(j*4)].GetUInt16(); + temp.action[j].param1 = fields[11+(j*4)].GetUInt32(); + temp.action[j].param2 = fields[12+(j*4)].GetUInt32(); + temp.action[j].param3 = fields[13+(j*4)].GetUInt32(); + + //Report any errors in actions + switch (temp.action[j].type) + { + case ACTION_T_TEXT: + { + if (temp.action[j].param1_s < 0) + { + if (m_CreatureEventAI_TextMap.find(temp.action[j].param1_s) == m_CreatureEventAI_TextMap.end()) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 refrences non-existing entry in texts table.", i, j+1); + } + if (temp.action[j].param2_s < 0) + { + if (m_CreatureEventAI_TextMap.find(temp.action[j].param2_s) == m_CreatureEventAI_TextMap.end()) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 refrences non-existing entry in texts table.", i, j+1); + + if (!temp.action[j].param1_s) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i, j+1); + } + if (temp.action[j].param3_s < 0) + { + if (m_CreatureEventAI_TextMap.find(temp.action[j].param3_s) == m_CreatureEventAI_TextMap.end()) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 refrences non-existing entry in texts table.", i, j+1); + + if (!temp.action[j].param1_s || !temp.action[j].param2_s) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i, j+1); + } + } + break; + case ACTION_T_SET_FACTION: + if (temp.action[j].param1 !=0 && !GetFactionStore()->LookupEntry(temp.action[j].param1)) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant FactionId %u.", i, j+1, temp.action[j].param1); + temp.action[j].param1 = 0; + } + break; + case ACTION_T_MORPH_TO_ENTRY_OR_MODEL: + if (temp.action[j].param1 !=0 || temp.action[j].param2 !=0) + { + if (temp.action[j].param1 && !GetCreatureTemplateStore(temp.action[j].param1)) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, temp.action[j].param1); + temp.action[j].param1 = 0; + } + + if (temp.action[j].param2 && !GetCreatureDisplayStore()->LookupEntry(temp.action[j].param2)) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i, j+1, temp.action[j].param2); + temp.action[j].param2 = 0; + } + } + break; + case ACTION_T_SOUND: + if (!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, temp.action[j].param1); + break; +/* + case ACTION_T_RANDOM_SOUND: + { + if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, temp.action[j].param1); + if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param2)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, temp.action[j].param2); + if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param3)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, temp.action[j].param3); + } + break; + */ + case ACTION_T_CAST: + { + const SpellEntry *spell = GetSpellStore()->LookupEntry(temp.action[j].param1); + if (!spell) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1); + else + { + if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE) + { + //output as debug for now, also because there's no general rule all spells have RecoveryTime + if (temp.event_param3 < spell->RecoveryTime) + debug_log("CreatureEventAI: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i, j+1,temp.action[j].param1, spell->RecoveryTime, temp.event_param3); + } + } + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_REMOVEAURASFROMSPELL: + { + if (!GetSpellStore()->LookupEntry(temp.action[j].param2)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2); + + if (temp.action[j].param1 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_QUEST_EVENT: + { + if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1)) + { + if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1); + } + else + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1); + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_QUEST_EVENT_ALL: + { + if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1)) + { + if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1); + } + else + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1); + } + break; + case ACTION_T_CASTCREATUREGO: + { + if (!GetCreatureTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1); + + if (!GetSpellStore()->LookupEntry(temp.action[j].param2)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2); + + if (temp.action[j].param3 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_CASTCREATUREGO_ALL: + { + if (!GetQuestTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1); + + if (!GetSpellStore()->LookupEntry(temp.action[j].param2)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2); + } + break; + + //2nd param target + case ACTION_T_SUMMON_ID: + { + if (!GetCreatureTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1); + + if (m_CreatureEventAI_Summon_Map.find(temp.action[j].param3) == m_CreatureEventAI_Summon_Map.end()) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j+1, temp.action[j].param3); + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_KILLED_MONSTER: + { + if (!GetCreatureTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1); + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_SUMMON: + { + if (!GetCreatureTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1); + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_THREAT_SINGLE_PCT: + case ACTION_T_SET_UNIT_FLAG: + case ACTION_T_REMOVE_UNIT_FLAG: + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + break; + + //3rd param target + case ACTION_T_SET_UNIT_FIELD: + if (temp.action[j].param1 < OBJECT_END || temp.action[j].param1 >= UNIT_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1); + if (temp.action[j].param3 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + break; + + case ACTION_T_SET_PHASE: + if (temp.action[j].param1 > 31) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i, j+1); + break; + + case ACTION_T_INC_PHASE: + if (!temp.action[j].param1) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1); + break; + + case ACTION_T_SET_INST_DATA: + { + if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1); + + if (temp.action[j].param2 > 4/*SPECIAL*/) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1); + } + break; + case ACTION_T_SET_INST_DATA64: + { + if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1); + + if (temp.action[j].param2 >= TARGET_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); + } + break; + case ACTION_T_UPDATE_TEMPLATE: + { + if (!GetCreatureTemplateStore(temp.action[j].param1)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1); + } + break; + case ACTION_T_RANDOM_SAY: + case ACTION_T_RANDOM_YELL: + case ACTION_T_RANDOM_TEXTEMOTE: + sLog.outErrorDb("CreatureEventAI: Event %u Action %u currently unused ACTION type. Did you forget to update database?", i, j+1); + break; + + default: + if (temp.action[j].type >= ACTION_T_END) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u has incorrect action type. Maybe DB requires updated version of SD2.", i, j+1); + break; + } + } + + //Add to list + m_CreatureEventAI_Event_Map[creature_id].push_back(temp); + ++Count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u CreatureEventAI scripts", Count); + }else + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 CreatureEventAI scripts. DB table `creature_ai_scripts` is empty."); + } +} diff --git a/src/game/CreatureEventAIMgr.h b/src/game/CreatureEventAIMgr.h new file mode 100644 index 00000000000..ea5989a74ed --- /dev/null +++ b/src/game/CreatureEventAIMgr.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MANGOS_CREATURE_EAI_MGR_H +#define MANGOS_CREATURE_EAI_MGR_H + +#include "Common.h" +#include "CreatureEventAI.h" + +class CreatureEventAIMgr +{ + public: + CreatureEventAIMgr(){}; + ~CreatureEventAIMgr(){}; + + void LoadCreatureEventAI_Texts(); + void LoadCreatureEventAI_Summons(); + void LoadCreatureEventAI_Scripts(); + + CreatureEventAI_Event_Map& GetCreatureEventAIMap() { return m_CreatureEventAI_Event_Map; } + CreatureEventAI_Summon_Map& GetCreatureEventAISummonMap() { return m_CreatureEventAI_Summon_Map; } + CreatureEventAI_TextMap& GetCreatureEventAITextMap() { return m_CreatureEventAI_TextMap; } + + private: + CreatureEventAI_Event_Map m_CreatureEventAI_Event_Map; + CreatureEventAI_Summon_Map m_CreatureEventAI_Summon_Map; + CreatureEventAI_TextMap m_CreatureEventAI_TextMap; +}; + +#define CreatureEAI_Mgr MaNGOS::Singleton<CreatureEventAIMgr>::Instance() +#endif diff --git a/src/game/CreatureGroups.cpp b/src/game/CreatureGroups.cpp index ed0fde19eb0..3b7a27cdab5 100644 --- a/src/game/CreatureGroups.cpp +++ b/src/game/CreatureGroups.cpp @@ -23,62 +23,52 @@ #include "ObjectMgr.h" #include "ProgressBar.h" #include "Policies/SingletonImp.h" +#include "CreatureAI.h" #define MAX_DESYNC 5.0f INSTANTIATE_SINGLETON_1(CreatureGroupManager); -CreatureGroupHolderType CreatureGroupHolder; CreatureGroupInfoType CreatureGroupMap; -void CreatureGroupManager::AddCreatureToGroup(uint32 group_id, Creature *member) +void CreatureGroupManager::AddCreatureToGroup(uint32 groupId, Creature *member) { - CreatureGroupHolderType::iterator cgroup_data = CreatureGroupHolder.find(group_id); + Map *map = member->FindMap(); + if(!map) + return; + + CreatureGroupHolderType::iterator itr = map->CreatureGroupHolder.find(groupId); //Add member to an existing group - if(cgroup_data != CreatureGroupHolder.end()) + if(itr != map->CreatureGroupHolder.end()) { - typedef std::multimap<uint32, CreatureGroup *>::iterator multiplegroup; - std::pair<multiplegroup, multiplegroup> range = CreatureGroupHolder.equal_range(group_id); - - for(multiplegroup i = range.first; i != range.second; ++i) - { - if(i->second->getInstanceID() == member->GetInstanceId()) - { - sLog.outDebug("Group found: %u, inserting creature GUID: %u, Group InstanceID %u", group_id, member->GetGUIDLow(), i->second->getInstanceID()); - i->second->AddMember(member); - return; - } - } + sLog.outDebug("Group found: %u, inserting creature GUID: %u, Group InstanceID %u", groupId, member->GetGUIDLow(), member->GetInstanceId()); + itr->second->AddMember(member); } - //Create new group - sLog.outDebug("Group not found: %u. Creating new group.", group_id); - CreatureGroup* cgroup = new CreatureGroup(group_id, member->GetInstanceId()); - CreatureGroupHolder.insert(std::make_pair(group_id, cgroup)); - cgroup->AddMember(member); + else + { + sLog.outDebug("Group not found: %u. Creating new group.", groupId); + CreatureGroup* group = new CreatureGroup(groupId); + map->CreatureGroupHolder[groupId] = group; + group->AddMember(member); + } } -void CreatureGroupManager::RemoveCreatureFromGroup(CreatureGroup *formation, Creature *member) +void CreatureGroupManager::RemoveCreatureFromGroup(CreatureGroup *group, Creature *member) { - sLog.outDebug("Deleting member pointer to GUID: %u from group %u", formation->GetId(), member->GetDBTableGUIDLow()); - formation->RemoveMember(member); + sLog.outDebug("Deleting member pointer to GUID: %u from group %u", group->GetId(), member->GetDBTableGUIDLow()); + group->RemoveMember(member); - if(formation->isEmpty()) + if(group->isEmpty()) { - uint32 id = formation->GetId(); - typedef std::multimap<uint32, CreatureGroup *>::iterator multiplegroup; - std::pair<multiplegroup, multiplegroup> range = CreatureGroupHolder.equal_range(id); + Map *map = member->FindMap(); + if(!map) + return; - for(multiplegroup i = range.first; i != range.second; ++i) - { - if(i->second == formation) - { - sLog.outDebug("Deleting group with InstanceID %u", i->second->getInstanceID()); - CreatureGroupHolder.erase(i); - delete formation; - } - } + sLog.outDebug("Deleting group with InstanceID %u", member->GetInstanceId()); + map->CreatureGroupHolder.erase(group->GetId()); + delete group; } } @@ -244,7 +234,11 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z) float dx = x + cos(angle + pathangle) * dist; float dy = y + sin(angle + pathangle) * dist; - float dz; + float dz = z; + + Trinity::NormalizeMapCoord(dx); + Trinity::NormalizeMapCoord(dy); + member->UpdateGroundPositionZ(dx, dy, dz); if(member->GetDistance(m_leader) < dist + MAX_DESYNC) diff --git a/src/game/CreatureGroups.h b/src/game/CreatureGroups.h index aba86ffcaac..8c345aadd40 100644 --- a/src/game/CreatureGroups.h +++ b/src/game/CreatureGroups.h @@ -41,10 +41,8 @@ class CreatureGroupManager void LoadCreatureFormations(); }; -typedef std::multimap<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType; typedef UNORDERED_MAP<uint32/*memberDBGUID*/, FormationInfo*> CreatureGroupInfoType; -extern CreatureGroupHolderType CreatureGroupHolder; extern CreatureGroupInfoType CreatureGroupMap; class CreatureGroup @@ -54,17 +52,16 @@ class CreatureGroup typedef std::map<Creature*, FormationInfo*> CreatureGroupMemberType; CreatureGroupMemberType m_members; - uint32 m_groupID, mInstanceID; + uint32 m_groupID; bool m_Formed; public: //Group cannot be created empty - explicit CreatureGroup(uint32 id, uint32 InstanceID) : m_groupID(id), m_leader(NULL), mInstanceID(InstanceID), m_Formed(false) {} - ~CreatureGroup(){sLog.outDebug("Destroying group");} + explicit CreatureGroup(uint32 id) : m_groupID(id), m_leader(NULL), m_Formed(false) {} + ~CreatureGroup() { sLog.outDebug("Destroying group"); } Creature* getLeader() const { return m_leader; } uint32 GetId() const { return m_groupID; } - uint32 getInstanceID() const { return mInstanceID; } bool isEmpty() const { return m_members.empty(); } bool isFormed() const { return m_Formed; } diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index c3139dc2a37..078804c19f4 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -45,9 +45,9 @@ enum AchievementFlags ACHIEVEMENT_FLAG_COUNTER = 0x00000001, // Just count statistic (never stop and complete) ACHIEVEMENT_FLAG_UNK2 = 0x00000002, // not used ACHIEVEMENT_FLAG_STORE_MAX_VALUE = 0x00000004, // Store only max value? used only in "Reach level xx" - ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all reqirements (and calculate max vale) - ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max vale ??) - ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max vale) + ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all reqirements (and calculate max value) + ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max value ??) + ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max value) ACHIEVEMENT_FLAG_AVERANGE = 0x00000040, // Show as averange value (value / time_in_days) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_BAR = 0x00000080, // Show as progress bar (value / max vale) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, // diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index c46de44bf1f..7d3dea72ccf 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -479,7 +479,7 @@ struct AchievementCriteriaEntry struct { uint32 field3; // 3 main requirement - uint32 field4; // 4 main requirement count + uint32 count; // 4 main requirement count uint32 additionalRequirement1_type; // 5 additional requirement 1 type uint32 additionalRequirement1_value; // 6 additional requirement 1 value uint32 additionalRequirement2_type; // 7 additional requirement 2 type diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index def17130372..89a03cac016 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -610,37 +610,34 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map) if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) ) return false; - switch(GetGOInfo()->type) + if(!GetDespawnPossibility()) { - case GAMEOBJECT_TYPE_DOOR: - case GAMEOBJECT_TYPE_BUTTON: - /* this code (in comment) isn't correct because in battlegrounds we need despawnable doors and buttons, pls remove - SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); + SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); + m_spawnedByDefault = true; + m_respawnDelayTime = 0; + m_respawnTime = 0; + } + else + { + if(data->spawntimesecs >= 0) + { m_spawnedByDefault = true; - m_respawnDelayTime = 0; - m_respawnTime = 0; - break;*/ - default: - if(data->spawntimesecs >= 0) - { - m_spawnedByDefault = true; - m_respawnDelayTime = data->spawntimesecs; - m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId()); + m_respawnDelayTime = data->spawntimesecs; + m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId()); - // ready to respawn - if(m_respawnTime && m_respawnTime <= time(NULL)) - { - m_respawnTime = 0; - objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0); - } - } - else + // ready to respawn + if(m_respawnTime && m_respawnTime <= time(NULL)) { - m_spawnedByDefault = false; - m_respawnDelayTime = -data->spawntimesecs; m_respawnTime = 0; + objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0); } - break; + } + else + { + m_spawnedByDefault = false; + m_respawnDelayTime = -data->spawntimesecs; + m_respawnTime = 0; + } } return true; diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 3d2d3c2de57..b0019048827 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -482,6 +482,20 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject } } + bool GetDespawnPossibility() const + { + switch(GetGoType()) + { + case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.noDamageImmune; + case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.noDamageImmune; + case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.noDamageImmune; + case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.noDamageImmune; + case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.noDamageImmune; + case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.noDamageImmune; + default: return true; + } + } + time_t GetRespawnTime() const { return m_respawnTime; } time_t GetRespawnTimeEx() const { diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index a7b8c753782..521a543c08c 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -628,6 +628,62 @@ namespace Trinity // Unit checks + class MostHPMissingInRange + { + public: + MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {} + bool operator()(Unit* u) + { + if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp) + { + i_hp = u->GetMaxHealth() - u->GetHealth(); + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + uint32 i_hp; + }; + + class FriendlyCCedInRange + { + public: + FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Unit* u) + { + if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && + (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED))) + { + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + }; + + class FriendlyMissingBuffInRange + { + public: + FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {} + bool operator()(Unit* u) + { + if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && + !(u->HasAura(i_spell, 0) || u->HasAura(i_spell, 1) || u->HasAura(i_spell, 2))) + { + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + uint32 i_spell; + }; + class AnyUnfriendlyUnitInObjectRangeCheck { public: @@ -915,63 +971,6 @@ namespace Trinity float i_range; }; - // Searchers used by ScriptedAI - class MostHPMissingInRange - { - public: - MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {} - bool operator()(Unit* u) - { - if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp) - { - i_hp = u->GetMaxHealth() - u->GetHealth(); - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - uint32 i_hp; - }; - - class FriendlyCCedInRange - { - public: - FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Unit* u) - { - if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && - (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED))) - { - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - }; - - class FriendlyMissingBuffInRange - { - public: - FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {} - bool operator()(Unit* u) - { - if(u->isAlive() && u->isInCombat() && /*!i_obj->IsHostileTo(u)*/ i_obj->IsFriendlyTo(u) && i_obj->IsWithinDistInMap(u, i_range) && - !(u->HasAura(i_spell))) - { - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - uint32 i_spell; - }; - class AllFriendlyCreaturesInGrid { public: diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp index 17174919b15..4f0ca2f8cec 100644 --- a/src/game/HomeMovementGenerator.cpp +++ b/src/game/HomeMovementGenerator.cpp @@ -69,7 +69,7 @@ HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff // restore orientation of not moving creature at returning to home if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE) { - sLog.outDebug("Entering HomeMovement::GetDestination(z,y,z)"); + //sLog.outDebug("Entering HomeMovement::GetDestination(z,y,z)"); owner.SetOrientation(ori); WorldPacket packet; owner.BuildHeartBeatMsg(&packet); diff --git a/src/game/InstanceData.h b/src/game/InstanceData.h index b2571de66bd..c33beccfffb 100644 --- a/src/game/InstanceData.h +++ b/src/game/InstanceData.h @@ -67,6 +67,10 @@ class TRINITY_DLL_SPEC InstanceData //called on creature creation virtual void OnCreatureCreate(Creature * /*creature*/, uint32 /*creature_entry*/) {} + //All-purpose data storage 64 bit + virtual uint64 GetData64(uint32 /*Data*/) { return 0; } + virtual void SetData64(uint32 /*Data*/, uint64 /*Value*/) { } + //All-purpose data storage 32 bit virtual uint32 GetData(uint32) { return 0; } virtual void SetData(uint32, uint32 data) {} diff --git a/src/game/Language.h b/src/game/Language.h index 51df64227f8..8217193ea50 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -84,7 +84,8 @@ enum TrinityStrings LANG_MOTD_CURRENT = 56, LANG_USING_WORLD_DB = 57, LANG_USING_SCRIPT_LIB = 58, - // Room for more level 0 59-99 not used + LANG_USING_EVENT_AI = 59, + // Room for more level 0 60-99 not used // level 1 chat LANG_GLOBAL_NOTIFY = 100, diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp index 50aa1e46538..5f8a6cf86ef 100644 --- a/src/game/Level0.cpp +++ b/src/game/Level0.cpp @@ -102,6 +102,7 @@ bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) //SendSysMessage(full); //PSendSysMessage(LANG_USING_SCRIPT_LIB,sWorld.GetScriptsVersion()); //PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion()); + //PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion()); PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); PSendSysMessage(LANG_UPTIME, str.c_str()); PSendSysMessage("Update time diff: %u.", updateTime); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 10b0cd198a0..8122166ef31 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -529,6 +529,7 @@ bool ChatHandler::HandleReloadAllCommand(const char*) { HandleReloadSkillFishingBaseLevelCommand(""); + HandleReloadAllAchievementCommand(""); HandleReloadAllAreaCommand(""); HandleReloadAllLootCommand(""); HandleReloadAllNpcCommand(""); @@ -544,6 +545,13 @@ bool ChatHandler::HandleReloadAllCommand(const char*) return true; } +bool ChatHandler::HandleReloadAllAchievementCommand(const char*) +{ + HandleReloadAchievementCriteriaDataCommand(""); + HandleReloadAchievementRewardCommand(""); + return true; +} + bool ChatHandler::HandleReloadAllAreaCommand(const char*) { //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand @@ -632,6 +640,7 @@ bool ChatHandler::HandleReloadAllItemCommand(const char*) bool ChatHandler::HandleReloadAllLocalesCommand(const char* /*args*/) { + HandleReloadLocalesAchievementRewardCommand("a"); HandleReloadLocalesCreatureCommand("a"); HandleReloadLocalesGameobjectCommand("a"); HandleReloadLocalesItemCommand("a"); @@ -650,6 +659,22 @@ bool ChatHandler::HandleReloadConfigCommand(const char* /*args*/) return true; } +bool ChatHandler::HandleReloadAchievementCriteriaDataCommand(const char*) +{ + sLog.outString( "Re-Loading Additional Achievement Criteria Data..." ); + achievementmgr.LoadAchievementCriteriaData(); + SendGlobalSysMessage("DB table `achievement_criteria_data` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAchievementRewardCommand(const char*) +{ + sLog.outString( "Re-Loading Achievement Reward Data..." ); + achievementmgr.LoadRewards(); + SendGlobalSysMessage("DB table `achievement_reward` reloaded."); + return true; +} + bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) { sLog.outString( "Re-Loading Tavern Area Triggers..." ); @@ -1194,6 +1219,14 @@ bool ChatHandler::HandleReloadSpellDisabledCommand(const char* /*arg*/) return true; } +bool ChatHandler::HandleReloadLocalesAchievementRewardCommand(const char*) +{ + sLog.outString( "Re-Loading Locales Achievement Reward Data..." ); + achievementmgr.LoadRewardLocales(); + SendGlobalSysMessage("DB table `locales_achievement_reward` reloaded."); + return true; +} + bool ChatHandler::HandleReloadLocalesCreatureCommand(const char* /*arg*/) { sLog.outString( "Re-Loading Locales Creature ..."); diff --git a/src/game/Makefile.am b/src/game/Makefile.am index de27815594a..47c072a1188 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -31,6 +31,7 @@ noinst_LIBRARIES = libmangosgame.a # libmangossgame library will later be reused by ... libmangosgame_a_SOURCES = \ <<<<<<< HEAD:src/game/Makefile.am +<<<<<<< HEAD:src/game/Makefile.am AccountMgr.cpp \ AccountMgr.h \ AchievementMgr.h \ @@ -572,6 +573,272 @@ libmangosgame_a_SOURCES = \ GroupReference.h \ GroupRefManager.h >>>>>>> 2429aaf2276d689e101ed88285f18449dbe4280d:src/game/Makefile.am +======= + AccountMgr.cpp \ + AccountMgr.h \ + AchievementMgr.h \ + AchievementMgr.cpp \ + AggressorAI.cpp \ + AggressorAI.h \ + AnimalRandomMovementGenerator.h \ + ArenaTeam.cpp \ + ArenaTeam.h \ + ArenaTeamHandler.cpp \ + AuctionHouseHandler.cpp \ + AuctionHouseMgr.cpp \ + AuctionHouseMgr.h \ + Bag.cpp \ + Bag.h \ + BattleGround.cpp \ + BattleGroundAA.cpp \ + BattleGroundAB.cpp \ + BattleGroundAV.cpp \ + BattleGroundBE.cpp \ + BattleGroundDS.cpp \ + BattleGroundEY.cpp \ + BattleGroundNA.cpp \ + BattleGroundRL.cpp \ + BattleGroundRV.cpp \ + BattleGroundSA.cpp \ + BattleGroundWS.cpp \ + BattleGround.h \ + BattleGroundAA.h \ + BattleGroundAB.h \ + BattleGroundAV.h \ + BattleGroundBE.h \ + BattleGroundDS.h \ + BattleGroundEY.h \ + BattleGroundNA.h \ + BattleGroundRL.h \ + BattleGroundRV.h \ + BattleGroundSA.h \ + BattleGroundWS.h \ + BattleGroundHandler.cpp \ + BattleGroundMgr.cpp \ + BattleGroundMgr.h \ + Calendar.cpp \ + Calendar.h \ + CalendarHandler.cpp \ + Cell.h \ + CellImpl.h \ + Channel.cpp \ + Channel.h \ + ChannelHandler.cpp \ + ChannelMgr.h \ + CharacterHandler.cpp \ + Chat.cpp \ + Chat.h \ + ChatHandler.cpp \ + CombatHandler.cpp \ + ConfusedMovementGenerator.cpp \ + ConfusedMovementGenerator.h \ + Corpse.cpp \ + Corpse.h \ + CreatureAI.cpp \ + CreatureAI.h \ + CreatureAIImpl.h \ + CreatureAIRegistry.cpp \ + CreatureAIRegistry.h \ + CreatureAISelector.cpp \ + CreatureAISelector.h \ + CreatureEventAI.cpp \ + CreatureEventAI.h \ + CreatureEventAIMgr.cpp \ + CreatureEventAIMgr.h \ + Creature.cpp \ + Creature.h \ + DBCEnums.h \ + DBCfmt.h \ + DBCStores.cpp \ + DBCStores.h \ + DBCStructure.h \ + debugcmds.cpp \ + DestinationHolder.cpp \ + DestinationHolder.h \ + DestinationHolderImp.h \ + DuelHandler.cpp \ + DynamicObject.cpp \ + DynamicObject.h \ + FleeingMovementGenerator.cpp \ + FleeingMovementGenerator.h \ + Formulas.h \ + GameEventMgr.cpp \ + GameEventMgr.h \ + GameObject.cpp \ + GameObject.h \ + GlobalEvents.cpp \ + GlobalEvents.h \ + GMTicketHandler.cpp \ + GMTicketMgr.cpp \ + GMTicketMgr.h \ + GossipDef.cpp \ + GossipDef.h \ + GridDefines.h \ + GridNotifiers.cpp \ + GridNotifiers.h \ + GridNotifiersImpl.h \ + GridStates.cpp \ + GridStates.h \ + Group.cpp \ + Group.h \ + GroupHandler.cpp \ + GuardAI.cpp \ + GuardAI.h \ + Guild.cpp \ + Guild.h \ + GuildHandler.cpp \ + HomeMovementGenerator.cpp \ + HomeMovementGenerator.h \ + HostilRefManager.cpp \ + HostilRefManager.h \ + IdleMovementGenerator.cpp \ + IdleMovementGenerator.h \ + InstanceData.cpp \ + InstanceData.h \ + InstanceSaveMgr.cpp \ + InstanceSaveMgr.h \ + Item.cpp \ + Item.h \ + ItemEnchantmentMgr.cpp \ + ItemEnchantmentMgr.h \ + ItemHandler.cpp \ + ItemPrototype.h \ + Language.h \ + Level0.cpp \ + Level1.cpp \ + Level2.cpp \ + Level3.cpp \ + LFGHandler.cpp \ + LootHandler.cpp \ + LootMgr.cpp \ + LootMgr.h \ + Mail.cpp \ + Mail.h \ + Map.cpp \ + Map.h \ + MapInstanced.cpp \ + MapInstanced.h \ + MapManager.cpp \ + MapManager.h \ + MapReference.h \ + MapRefManager.h \ + MiscHandler.cpp \ + MotionMaster.cpp \ + MotionMaster.h \ + MovementGenerator.cpp \ + MovementGenerator.h \ + MovementGeneratorImpl.h \ + MovementHandler.cpp \ + NPCHandler.cpp \ + NPCHandler.h \ + NullCreatureAI.cpp \ + NullCreatureAI.h \ + ObjectAccessor.cpp \ + ObjectAccessor.h \ + Object.cpp \ + ObjectDefines.h \ + ObjectGridLoader.cpp \ + ObjectGridLoader.h \ + Object.h \ + ObjectMgr.cpp \ + ObjectMgr.h \ + ObjectPosSelector.cpp \ + ObjectPosSelector.h \ + Opcodes.cpp \ + Opcodes.h \ + Path.h \ + PetAI.cpp \ + PetAI.h \ + Pet.cpp \ + Pet.h \ + PetHandler.cpp \ + PetitionsHandler.cpp \ + Player.cpp \ + Player.h \ + PlayerDump.cpp \ + PlayerDump.h \ + PointMovementGenerator.cpp \ + PointMovementGenerator.h \ + PoolHandler.cpp \ + PoolHandler.h \ + QueryHandler.cpp \ + QuestDef.cpp \ + QuestDef.h \ + QuestHandler.cpp \ + RandomMovementGenerator.cpp \ + RandomMovementGenerator.h \ + ReactorAI.cpp \ + ReactorAI.h \ + ReputationMgr.cpp \ + ReputationMgr.h \ + ScriptCalls.cpp \ + ScriptCalls.h \ + SharedDefines.h \ + SkillHandler.cpp \ + SpellAuraDefines.h \ + SpellAuras.cpp \ + SpellAuras.h \ + Spell.cpp \ + SpellEffects.cpp \ + Spell.h \ + SkillDiscovery.cpp \ + SkillDiscovery.h \ + SkillExtraItems.cpp \ + SkillExtraItems.h \ + SpellHandler.cpp \ + SocialMgr.cpp \ + SocialMgr.h \ + SpellMgr.cpp \ + SpellMgr.h \ + StatSystem.cpp \ + TargetedMovementGenerator.cpp \ + TargetedMovementGenerator.h \ + TaxiHandler.cpp \ + TemporarySummon.cpp \ + TemporarySummon.h \ + TotemAI.cpp \ + TotemAI.h \ + Totem.cpp \ + Totem.h \ + TradeHandler.cpp \ + Transports.cpp \ + Transports.h \ + ThreatManager.cpp \ + ThreatManager.h \ + Traveller.h \ + Unit.cpp \ + Unit.h \ + UnitEvents.h \ + UpdateData.cpp \ + UpdateData.h \ + UpdateFields.h \ + UpdateMask.h \ + Vehicle.cpp \ + Vehicle.h \ + VoiceChatHandler.cpp \ + WaypointManager.cpp \ + WaypointManager.h \ + WaypointMovementGenerator.cpp \ + WaypointMovementGenerator.h \ + Weather.cpp \ + Weather.h \ + World.cpp \ + World.h \ + WorldLog.cpp \ + WorldLog.h \ + WorldSession.cpp \ + WorldSession.h \ + WorldSocket.cpp \ + WorldSocket.h \ + WorldSocketMgr.cpp \ + WorldSocketMgr.h \ + FollowerReference.cpp \ + FollowerReference.h \ + FollowerRefManager.h \ + GroupReference.cpp \ + GroupReference.h \ + GroupRefManager.h +>>>>>>> 5a6594330caefc0dc00a5fe792dcb0e344b457cb:src/game/Makefile.am ## Link against shared library libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a diff --git a/src/game/Map.cpp b/src/game/Map.cpp index d6f06051c59..ac81b9c2a6d 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -307,9 +307,21 @@ void Map::RemoveFromGrid(DynamicObject* obj, NGridType *grid, Cell const& cell) template<class T> void Map::SwitchGridContainers(T* obj, bool on) { - CellPair pair = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - Cell cell(pair); + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP ) + { + sLog.outError("Map::SwitchGridContainers: Object " I64FMT " have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) ) + return; + + DEBUG_LOG("Switch object " I64FMT " from grid[%u,%u] %u", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y, on); NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY()); + assert( ngrid != NULL ); + GridType &grid = (*ngrid)(cell.CellX(), cell.CellY()); if(on) @@ -465,7 +477,7 @@ bool Map::Add(Player *player) SendInitTransports(player); player->m_clientGUIDs.clear(); - AddNotifier(player); + //AddNotifier(player); return true; } @@ -505,7 +517,7 @@ Map::Add(T *obj) //if(obj->GetTypeId() != TYPEID_UNIT) UpdateObjectVisibility(obj,cell,p); - AddNotifier(obj); + //AddNotifier(obj); } void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self, bool to_possessor) @@ -711,7 +723,7 @@ void Map::Update(const uint32 &t_diff) } } - if(plr->m_seer != plr) + if(plr->m_seer != plr && !plr->hasUnitState(UNIT_STAT_ONVEHICLE)) { Trinity::PlayerVisibilityNotifier notifier(*plr); VisitAll(plr->m_seer->GetPositionX(), plr->m_seer->GetPositionY(), World::GetMaxVisibleDistance(), notifier); @@ -1765,8 +1777,6 @@ float Map::GetVmapHeight(float x, float y, float z, bool useMaps) const return vmapHeight; } -#include "World.h" - uint16 Map::GetAreaFlag(float x, float y, float z) const { uint16 areaflag; @@ -1791,9 +1801,9 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const case 2456: // Death's Breach (Eastern Plaguelands) if(z > 350.0f) areaflag = 1950; break; // Dalaran - case 1593: - case 2484: - case 2492: + case 1593: // Crystalsong Forest + case 2484: // The Twilight Rivulet (Crystalsong Forest) + case 2492: // Forlorn Woods (Crystalsong Forest) if (x > 5568.0f && x < 6116.0f && y > 282.0f && y < 982.0f && z > 563.0f) areaflag = 2153; break; // Maw of Neltharion (cave) case 164: // Dragonblight @@ -1801,6 +1811,27 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const case 1827: // Wintergrasp case 2591: // The Cauldron of Flames (Wintergrasp) if (x > 4364.0f && x < 4632.0f && y > 1545.0f && y < 1886.0f && z < 200.0f) areaflag = 1853; break; + // Undercity (sewers enter and path) + case 179: // Tirisfal Glades + if (x > 1595.0f && x < 1699.0f && y > 535.0f && y < 643.5f && z < 30.5f) areaflag = 685; break; + // Undercity (Royal Quarter) + case 210: // Silverpine Forest + case 316: // The Shining Strand (Silverpine Forest) + case 438: // Lordamere Lake (Silverpine Forest) + if (x > 1237.0f && x < 1401.0f && y > 284.0f && y < 440.0f && z < -40.0f) areaflag = 685; break; + // Undercity (cave and ground zone, part of royal quarter) + case 607: // Ruins of Lordaeron (Tirisfal Glades) + // ground and near to ground (by city walls) + if(z > 0.0f) + { + if (x > 1510.0f && x < 1839.0f && y > 29.77f && y < 433.0f) areaflag = 685; + } + // more wide underground, part of royal quarter + else + { + if (x > 1299.0f && x < 1839.0f && y > 10.0f && y < 440.0f) areaflag = 685; + } + break; } return areaflag; diff --git a/src/game/Map.h b/src/game/Map.h index 4d00a287b03..3d533da1675 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -44,6 +44,7 @@ class Group; class InstanceSave; class WorldObject; class TempSummon; +class CreatureGroup; namespace ZThread { @@ -248,6 +249,8 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList; #define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE #define MIN_UNLOAD_DELAY 1 // immediate unload +typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType; + class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::ObjectLevelLockable<Map, ZThread::Mutex> { friend class MapReference; @@ -416,6 +419,9 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); TempSummon *SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties = NULL, uint32 duration = 0, Unit *summoner = NULL); + + CreatureGroupHolderType CreatureGroupHolder; + private: void LoadMapAndVMap(int gx, int gy); void LoadVMap(int gx, int gy); diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index ca2c5609692..0ced3a57201 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -1171,22 +1171,6 @@ void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/) */ } -void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/) -{ - /* - CHECK_PACKET_SIZE(recv_data,8+4); - - sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); - uint64 guid; - uint32 flags, time; - - recv_data >> guid; - recv_data >> flags >> time; - DEBUG_LOG("Guid " I64FMTD,guid); - DEBUG_LOG("Flags %u, time %u",flags, time/IN_MILISECONDS); - */ -} - void WorldSession::HandleSetActionBar(WorldPacket& recv_data) { CHECK_PACKET_SIZE(recv_data,1); diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index 6d7a40da045..ee6cc05a5d2 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -208,7 +208,7 @@ MotionMaster::MoveTargetedHome() DEBUG_LOG("Pet or controlled unit (Entry: %u GUID: %u) targeting home", i_owner->GetEntry(), i_owner->GetGUIDLow() ); - MoveFollow(i_owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); + MoveFollow(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); } else if(i_owner->GetTypeId() == TYPEID_UNIT) { @@ -305,7 +305,7 @@ MotionMaster::MovePoint(uint32 id, float x, float y, float z) } } -void MotionMaster::MoveJumpFrom(float srcX, float srcY, float speedXY, float speedZ) +void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ) { //this function may make players fall below map if(i_owner->GetTypeId()==TYPEID_PLAYER) @@ -317,6 +317,18 @@ void MotionMaster::MoveJumpFrom(float srcX, float srcY, float speedXY, float spe MoveJump(x, y, z, speedXY, speedZ); } +void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) +{ + //this function may make players fall below map + if(i_owner->GetTypeId()==TYPEID_PLAYER) + return; + + float x, y, z; + float dist = speedXY * speedZ * 0.1f; + i_owner->GetClosePoint(x, y, z, i_owner->GetObjectSize(), dist, angle); + MoveJump(x, y, z, speedXY, speedZ); +} + void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ) { uint32 moveFlag = MOVEFLAG_JUMP | MOVEFLAG_WALK; diff --git a/src/game/MotionMaster.h b/src/game/MotionMaster.h index 38a2b58825f..ea71495d216 100644 --- a/src/game/MotionMaster.h +++ b/src/game/MotionMaster.h @@ -141,7 +141,8 @@ class TRINITY_DLL_SPEC MotionMaster //: private std::stack<MovementGenerator *> void MoveFleeing(Unit* enemy); void MovePoint(uint32 id, float x,float y,float z); void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE); - void MoveJumpFrom(float srcX, float srcY, float speedXY, float speedZ); + void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); + void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJump(float x, float y, float z, float speedXY, float speedZ); void MoveTaxiFlight(uint32 path, uint32 pathnode); void MoveDistract(uint32 time); diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 69a8572e7a5..64c4fecdb53 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -41,6 +41,10 @@ void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ ) void WorldSession::HandleMoveWorldportAckOpcode() { + // ignore unexpected far teleports + if(!GetPlayer()->IsBeingTeleportedFar()) + return; + // get the teleport destination WorldLocation &loc = GetPlayer()->GetTeleportDest(); @@ -59,7 +63,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() if(GetPlayer()->m_InstanceValid == false && !mInstance) GetPlayer()->m_InstanceValid = true; - GetPlayer()->SetSemaphoreTeleport(false); + GetPlayer()->SetSemaphoreTeleportFar(false); // relocate the player to the teleport destination GetPlayer()->SetMapId(loc.mapid); @@ -79,7 +83,6 @@ void WorldSession::HandleMoveWorldportAckOpcode() { sLog.outDebug("WORLD: teleport of player %s (%d) to location %d,%f,%f,%f,%f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.x, loc.y, loc.z, loc.o); // teleport the player home - GetPlayer()->SetDontMove(false); if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation())) { // the player must always be able to teleport home @@ -116,7 +119,6 @@ void WorldSession::HandleMoveWorldportAckOpcode() if(!_player->InBattleGround()) { // short preparations to continue flight - GetPlayer()->SetDontMove(false); FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); flight->Initialize(*GetPlayer()); return; @@ -157,16 +159,53 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->CastSpell(GetPlayer(), 2479, true); // resummon pet - if(GetPlayer()->m_temporaryUnsummonedPetNumber) - { - Pet* NewPet = new Pet(GetPlayer()); - if(!NewPet->LoadPetFromDB(GetPlayer(), 0, GetPlayer()->m_temporaryUnsummonedPetNumber, true)) - delete NewPet; + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); +} + +void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) +{ + CHECK_PACKET_SIZE(recv_data,8+4); + + sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); + uint64 guid; + uint32 flags, time; - GetPlayer()->m_temporaryUnsummonedPetNumber = 0; + recv_data >> guid; + recv_data >> flags >> time; + DEBUG_LOG("Guid " I64FMTD,guid); + DEBUG_LOG("Flags %u, time %u",flags, time/IN_MILISECONDS); + + Unit *mover = _player->m_mover; + Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL; + + if(!plMover || !plMover->IsBeingTeleportedNear()) + return; + + if(guid != plMover->GetGUID()) + return; + + plMover->SetSemaphoreTeleportNear(false); + + uint32 old_zone = plMover->GetZoneId(); + + WorldLocation const& dest = plMover->GetTeleportDest(); + + plMover->SetPosition(dest.x, dest.y, dest.z, dest.o, true); + + uint32 newzone, newarea; + plMover->GetZoneAndAreaId(newzone,newarea); + plMover->UpdateZone(newzone,newarea); + + // new zone + if(old_zone != newzone) + { + // honorless target + if(plMover->pvpInfo.inHostileArea) + plMover->CastSpell(plMover, 2479, true); } - GetPlayer()->SetDontMove(false); + // resummon pet + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); } void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) @@ -174,7 +213,11 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) uint32 opcode = recv_data.GetOpcode(); //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); - if(GetPlayer()->GetDontMove()) + Unit *mover = _player->m_mover; + Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL; + + // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck + if(plMover && plMover->IsBeingTeleported()) return; /* extract packet */ @@ -192,9 +235,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) return; - Unit *mover = _player->m_mover; - Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL; - /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { @@ -258,7 +298,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); plMover->m_movementInfo = movementInfo; plMover->SetUnitMovementFlags(movementInfo.flags); - plMover->UpdateFallInformationIfNeed(movementInfo,recv_data.GetOpcode()); if(plMover->isMovingOrTurning()) @@ -280,10 +319,14 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) if(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); - // change the death state to CORPSE to prevent the death timer from - // starting in the next player update - plMover->KillPlayer(); - plMover->BuildPlayerRepop(); + // pl can be alive if GM/etc + if(!plMover->isAlive()) + { + // change the death state to CORPSE to prevent the death timer from + // starting in the next player update + plMover->KillPlayer(); + plMover->BuildPlayerRepop(); + } } // cancel the death timer here if started @@ -294,7 +337,12 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) else // creature charmed { if(Map *map = mover->GetMap()) + { + //if(GetPlayer()->m_seer != mover) + if(((Creature*)mover)->isVehicle()) + map->PlayerRelocation(GetPlayer(), movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); map->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); + } mover->SetUnitMovementFlags(movementInfo.flags); } } @@ -435,8 +483,6 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) if(Vehicle *vehicle = ObjectAccessor::GetVehicle(vehicleGUID)) { _player->ExitVehicle(vehicle); - if(!vehicle->GetDBTableGUIDLow()) - vehicle->Dismiss(); } } diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index f3a268a3b06..8d1427c86b8 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -481,7 +481,6 @@ void WorldSession::SendBindPoint(Creature *npc) _player->PlayerTalkClass->CloseGossip(); } -//Need fix void WorldSession::HandleListStabledPetsOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); @@ -518,7 +517,9 @@ void WorldSession::SendStablePet(uint64 guid ) Pet *pet = _player->GetPet(); + size_t wpos = data.wpos(); data << uint8(0); // place holder for slot show number + data << uint8(GetPlayer()->m_stableSlots); uint8 num = 0; // counter for place holder @@ -530,12 +531,13 @@ void WorldSession::SendStablePet(uint64 guid ) data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); data << pet->GetName(); // petname - data << uint8(0x01); // flags?, client slot 1 == current pet (0) + data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) ++num; } - // 0 1 2 3 4 5 - QueryResult* result = CharacterDatabase.PQuery("SELECT owner, slot, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 5",_player->GetGUIDLow()); + // 0 1 2 3 4 + QueryResult* result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot", + _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); if(result) { @@ -543,11 +545,11 @@ void WorldSession::SendStablePet(uint64 guid ) { Field *fields = result->Fetch(); - data << uint32(fields[2].GetUInt32()); // petnumber - data << uint32(fields[3].GetUInt32()); // creature entry - data << uint32(fields[4].GetUInt32()); // level - data << fields[5].GetString(); // name - data << uint8(fields[1].GetUInt32()+1); // slot + data << uint32(fields[1].GetUInt32()); // petnumber + data << uint32(fields[2].GetUInt32()); // creature entry + data << uint32(fields[3].GetUInt32()); // level + data << fields[4].GetString(); // name + data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) ++num; }while( result->NextRow() ); @@ -555,7 +557,7 @@ void WorldSession::SendStablePet(uint64 guid ) delete result; } - data.put<uint8>(8, num); // set real data to placeholder + data.put<uint8>(wpos, num); // set real data to placeholder SendPacket(&data); } @@ -596,7 +598,8 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data ) uint32 free_slot = 1; - QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot > 0 AND slot < 5 ORDER BY slot ",_player->GetGUIDLow()); + QueryResult *result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ", + _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); if(result) { do @@ -605,11 +608,16 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data ) uint32 slot = fields[1].GetUInt32(); - if(slot==free_slot) // this slot not free - ++free_slot; + // slots ordered in query, and if not equal then free + if(slot!=free_slot) + break; + + // this slot not free, skip + ++free_slot; }while( result->NextRow() ); + + delete result; } - delete result; if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) { @@ -648,8 +656,7 @@ void WorldSession::HandleUnstablePet( WorldPacket & recv_data ) Pet* pet = _player->GetPet(); if(pet && pet->isAlive()) { - uint8 i = 0x06; - data << uint8(i); + data << uint8(0x06); SendPacket(&data); return; } @@ -660,7 +667,8 @@ void WorldSession::HandleUnstablePet( WorldPacket & recv_data ) Pet *newpet = NULL; - QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot > 0 AND slot < 5",_player->GetGUIDLow(),petnumber); + QueryResult *result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'", + _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); if(result) { Field *fields = result->Fetch(); @@ -704,7 +712,7 @@ void WorldSession::HandleBuyStableSlot( WorldPacket & recv_data ) WorldPacket data(SMSG_STABLE_RESULT, 200); - if(GetPlayer()->m_stableSlots < 4) // max slots amount = 4 + if(GetPlayer()->m_stableSlots < MAX_PET_STABLES) { StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); if(_player->GetMoney() >= SlotPrice->Price) @@ -756,7 +764,8 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data ) return; // find swapped pet slot in stable - QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'",_player->GetGUIDLow(),pet_number); + QueryResult *result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'", + _player->GetGUIDLow(),pet_number); if(!result) return; @@ -766,7 +775,7 @@ void WorldSession::HandleStableSwapPet( WorldPacket & recv_data ) uint32 petentry = fields[1].GetUInt32(); delete result; - // move alive pet to slot or delele dead pet + // move alive pet to slot or delete dead pet _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); // summon unstabled pet diff --git a/src/game/Object.cpp b/src/game/Object.cpp index b5f25596af3..c22d00628b2 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -85,17 +85,16 @@ Object::~Object( ) //if(m_objectUpdated) // ObjectAccessor::Instance().RemoveUpdateObject(this); - if(m_uint32Values) + if(IsInWorld()) { - if(IsInWorld()) - { - ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash - sLog.outCrash("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId()); - assert(false); - } + sLog.outCrash("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId()); + assert(false); + } - assert(!m_objectUpdated); + assert(!m_objectUpdated); + if(m_uint32Values) + { //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this); delete [] m_uint32Values; delete [] m_uint32Values_mirror; @@ -286,7 +285,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2) { flags2 = ((Player*)this)->GetUnitMovementFlags(); - if(((Player*)this)->GetTransport()) + if(((Player*)this)->GetTransport() || ((Player*)this)->hasUnitState(UNIT_STAT_ONVEHICLE)) flags2 |= MOVEMENTFLAG_ONTRANSPORT; else flags2 &= ~MOVEMENTFLAG_ONTRANSPORT; @@ -336,7 +335,10 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2) { if(GetTypeId() == TYPEID_PLAYER) { - *data << (uint64)((Player*)this)->GetTransport()->GetGUID(); + if(((Player*)this)->hasUnitState(UNIT_STAT_ONVEHICLE)) + *data << (uint64)((Player*)this)->GetCharmGUID(); + else + *data << (uint64)((Player*)this)->GetTransport()->GetGUID(); *data << (float)((Player*)this)->GetTransOffsetX(); *data << (float)((Player*)this)->GetTransOffsetY(); *data << (float)((Player*)this)->GetTransOffsetZ(); @@ -667,13 +669,15 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask if(GetTypeId() == TYPEID_PLAYER && target != this && ((Player*)this)->IsInSameRaidWith(target)) { - /*if(index == UNIT_FIELD_BYTES_2) + // Allow targetting opposite faction in party when enabled in config + if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && index == UNIT_FIELD_BYTES_2) { DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (flag)", target->GetName(), ((Player*)this)->GetName()); - *data << ( m_uint32Values[ index ] & (UNIT_BYTE2_FLAG_SANCTUARY << 8) ); // this flag is at uint8 offset 1 !! + *data << ( m_uint32Values[ index ] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8) ); // this flag is at uint8 offset 1 !! + ch = true; } - else*/ + else { FactionTemplateEntry const *ft1, *ft2; ft1 = ((Player*)this)->getFactionTemplateEntry(); @@ -745,20 +749,10 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask void Object::ClearUpdateMask(bool remove) { - if(!m_uint32Values_mirror || !m_uint32Values) - { - sLog.outCrash("Object::ClearUpdateMask: Object entry %u (type %u) does not have uint32Values", GetEntry(), GetTypeId()); - return; - } + uint32 *temp = m_uint32Values; - uint32 temp = m_uint32Values[0]; - temp = m_uint32Values_mirror[0]; + memcpy(m_uint32Values_mirror, m_uint32Values, m_valuesCount*sizeof(uint32)); - for( uint16 index = 0; index < m_valuesCount; index ++ ) - { - if(m_uint32Values_mirror[index]!= m_uint32Values[index]) - m_uint32Values_mirror[index] = m_uint32Values[index]; - } if(m_objectUpdated) { if(remove) @@ -802,27 +796,23 @@ bool Object::LoadValues(const char* data) void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const { - if(!m_uint32Values_mirror || !m_uint32Values) - { - sLog.outCrash("Object::_SetUpdateBits: Object entry %u (type %u) does not have uint32Values", GetEntry(), GetTypeId()); - return; - } - - uint32 temp = m_uint32Values[0]; - temp = m_uint32Values_mirror[0]; + uint32 *value = m_uint32Values; + uint32 *mirror = m_uint32Values_mirror; - for(uint16 index = 0; index < m_valuesCount; ++index) + for(uint16 index = 0; index < m_valuesCount; ++index, ++value, ++mirror) { - if(m_uint32Values_mirror[index]!= m_uint32Values[index]) + if(*mirror != *value) updateMask->SetBit(index); } } void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const { - for( uint16 index = 0; index < m_valuesCount; index++ ) + uint32 *value = m_uint32Values; + + for(uint16 index = 0; index < m_valuesCount; ++index, ++value) { - if(GetUInt32Value(index) != 0) + if(*value) updateMask->SetBit(index); } } @@ -1147,8 +1137,7 @@ bool Object::PrintIndexError(uint32 index, bool set) const WorldObject::WorldObject() : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), - m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f), - mSemaphoreTeleport(false) + m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f) { m_positionX = 0.0f; m_positionY = 0.0f; @@ -1160,8 +1149,6 @@ WorldObject::WorldObject() m_name = ""; - mSemaphoreTeleport = false; - m_isActive = false; IsTempWorldObject = false; } @@ -1256,6 +1243,13 @@ float WorldObject::GetDistance2d(float x, float y) const return ( dist > 0 ? dist : 0); } +float WorldObject::GetExactDistance2d(const float x, const float y) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + return sqrt((dx*dx) + (dy*dy)); +} + float WorldObject::GetDistance(const float x, const float y, const float z) const { float dx = GetPositionX() - x; @@ -1618,7 +1612,17 @@ void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const *data << m_positionY; *data << m_positionZ; *data << m_orientation; - *data << uint32(0); + if(GetTypeId() == TYPEID_PLAYER && ((Unit*)this)->hasUnitState(UNIT_STAT_ONVEHICLE)) + { + *data << uint64(((Unit*)this)->GetCharmGUID()); + *data << float(((Player*)this)->GetTransOffsetX()); + *data << float(((Player*)this)->GetTransOffsetY()); + *data << float(((Player*)this)->GetTransOffsetZ()); + *data << float(((Player*)this)->GetTransOffsetO()); + *data << uint32(((Player*)this)->GetTransTime()); + *data << uint8(((Player*)this)->GetTransSeat()); + } + *data << uint32(0); //fall time } void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const @@ -1637,6 +1641,16 @@ void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float *data << y; *data << z; *data << ang; + if(GetTypeId() == TYPEID_PLAYER && ((Unit*)this)->hasUnitState(UNIT_STAT_ONVEHICLE)) + { + *data << uint64(((Unit*)this)->GetCharmGUID()); + *data << float(((Player*)this)->GetTransOffsetX()); + *data << float(((Player*)this)->GetTransOffsetY()); + *data << float(((Player*)this)->GetTransOffsetZ()); + *data << float(((Player*)this)->GetTransOffsetO()); + *data << uint32(((Player*)this)->GetTransTime()); + *data << uint8(((Player*)this)->GetTransSeat()); + } *data << uint32(0); } @@ -1674,7 +1688,9 @@ Map const* WorldObject::GetBaseMap() const void WorldObject::AddObjectToRemoveList() { - Map* map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + assert(m_uint32Values); + + Map* map = FindMap(); if(!map) { sLog.outError("Object (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u).",GetTypeId(),GetEntry(),GetGUIDLow(),GetMapId()); diff --git a/src/game/Object.h b/src/game/Object.h index a4b7506ca30..d46abd6d263 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -28,7 +28,6 @@ #include "GameSystem/GridReference.h" #include "ObjectDefines.h" #include "GridDefines.h" -#include "CreatureAI.h" #include "Map.h" #include <set> @@ -106,6 +105,7 @@ class InstanceData; class GameObject; class TempSummon; class Vehicle; +class CreatureAI; typedef UNORDERED_MAP<Player*, UpdateData> UpdateDataMapType; @@ -127,7 +127,7 @@ class TRINITY_DLL_SPEC Object public: virtual ~Object ( ); - const bool& IsInWorld() const { return m_inWorld; } + const bool IsInWorld() const { return m_inWorld; } virtual void AddToWorld() { if(m_inWorld) @@ -455,6 +455,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object float GetDistanceSq(const float &x, const float &y, const float &z) const; float GetDistance2d(const WorldObject* obj) const; float GetDistance2d(const float x, const float y) const; + float GetExactDistance2d(const float x, const float y) const; float GetDistanceZ(const WorldObject* obj) const; bool IsInMap(const WorldObject* obj) const { @@ -474,8 +475,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor = true); void BuildHeartBeatMsg( WorldPacket *data ) const; void BuildTeleportAckMsg( WorldPacket *data, float x, float y, float z, float ang) const; - bool IsBeingTeleported() { return mSemaphoreTeleport; } - void SetSemaphoreTeleport(bool semphsetting) { mSemaphoreTeleport = semphsetting; } void MonsterSay(const char* text, uint32 language, uint64 TargetGuid); void MonsterYell(const char* text, uint32 language, uint64 TargetGuid); @@ -538,8 +537,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object float m_positionY; float m_positionZ; float m_orientation; - - bool mSemaphoreTeleport; }; #endif diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index d1549712f30..1f413e2db40 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -164,22 +164,11 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor return HashMapHolder<Creature>::GetContainer(); } - HashMapHolder<Unit>::MapType& GetUnits() - { - return HashMapHolder<Unit>::GetContainer(); - } - HashMapHolder<GameObject>::MapType& GetGameObjects() { return HashMapHolder<GameObject>::GetContainer(); } - // note: possibly very heavy - HashMapHolder<WorldObject>::MapType& GetWorldObjects() - { - return HashMapHolder<WorldObject>::GetContainer(); - } - template<class T> void AddObject(T *object) { HashMapHolder<T>::Insert(object); diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 78727fc7c0a..d3e8397baaa 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -28,6 +28,7 @@ #include "Corpse.h" #include "World.h" #include "CellImpl.h" +#include "CreatureAI.h" class TRINITY_DLL_DECL ObjectGridRespawnMover { @@ -53,11 +54,10 @@ ObjectGridRespawnMover::Visit(CreatureMapType &m) // creature in unloading grid can have respawn point in another grid // if it will be unloaded then it will not respawn in original grid until unload/load original grid // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn. - for(CreatureMapType::iterator iter=m.begin(), next; iter != m.end(); iter = next) + for(CreatureMapType::iterator iter = m.begin(); iter != m.end();) { - next = iter; ++next; - Creature * c = iter->getSource(); + ++iter; assert(!c->isWorldCreature() && "ObjectGridRespawnMover don't must be called for pets"); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 1b0f347b8aa..efb5d0974ca 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -5585,6 +5585,61 @@ struct SQLGameObjectLoader : public SQLStorageLoaderBase<SQLGameObjectLoader> } }; +inline void CheckGOLockId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (sLockStore.LookupEntry(dataN)) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.", + goInfo->id,goInfo->type,N,goInfo->door.lockId,goInfo->door.lockId); +} + +inline void CheckGOLinkedTrapId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(dataN)) + { + if (trapInfo->type!=GAMEOBJECT_TYPE_TRAP) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", + goInfo->id,goInfo->type,N,dataN,dataN,GAMEOBJECT_TYPE_TRAP); + } + /* disable check for while (too many error reports baout not existed in trap templates + else + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but trap GO (Entry %u) not exist in `gameobject_template`.", + goInfo->id,goInfo->type,N,dataN,dataN); + */ +} + +inline void CheckGOSpellId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (sSpellStore.LookupEntry(dataN)) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.", + goInfo->id,goInfo->type,N,dataN,dataN); +} + +inline void CheckAndFixGOChairHeightId(GameObjectInfo const* goInfo,uint32 const& dataN,uint32 N) +{ + if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR) ) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.", + goInfo->id,goInfo->type,N,dataN,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); + + // prevent client and server unexpected work + const_cast<uint32&>(dataN) = 0; +} + +inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + // 0/1 correct values + if (dataN <= 1) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.", + goInfo->id,goInfo->type,N,dataN); +} + void ObjectMgr::LoadGameobjectInfo() { SQLGameObjectLoader loader; @@ -5594,139 +5649,104 @@ void ObjectMgr::LoadGameobjectInfo() for(uint32 id = 1; id < sGOStorage.MaxEntry; id++) { GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id); - if(!goInfo) + if (!goInfo) continue; switch(goInfo->type) { case GAMEOBJECT_TYPE_DOOR: //0 { - if(goInfo->door.lockId) - { - if(!sLockStore.LookupEntry(goInfo->door.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId); - } + if (goInfo->door.lockId) + CheckGOLockId(goInfo,goInfo->door.lockId,1); + CheckGONoDamageImmuneId(goInfo,goInfo->door.noDamageImmune,3); break; } case GAMEOBJECT_TYPE_BUTTON: //1 { - if(goInfo->button.lockId) - { - if(!sLockStore.LookupEntry(goInfo->button.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId); - } + if (goInfo->button.lockId) + CheckGOLockId(goInfo,goInfo->button.lockId,1); + CheckGONoDamageImmuneId(goInfo,goInfo->button.noDamageImmune,4); + break; + } + case GAMEOBJECT_TYPE_QUESTGIVER: //2 + { + if (goInfo->questgiver.lockId) + CheckGOLockId(goInfo,goInfo->questgiver.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->questgiver.noDamageImmune,5); break; } case GAMEOBJECT_TYPE_CHEST: //3 { - if(goInfo->chest.lockId) - { - if(!sLockStore.LookupEntry(goInfo->chest.lockId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.", - id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId); - } - if(goInfo->chest.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId); - */ - } + if (goInfo->chest.lockId) + CheckGOLockId(goInfo,goInfo->chest.lockId,0); + + if (goInfo->chest.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7); break; } case GAMEOBJECT_TYPE_TRAP: //6 { - /* disable check for while - if(goInfo->trap.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->trap.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId); - } + if (goInfo->trap.lockId) + CheckGOLockId(goInfo,goInfo->trap.lockId,0); + /* disable check for while, too many not existed spells + if (goInfo->trap.spellId) // spell + CheckGOSpellId(goInfo,goInfo->trap.spellId,3); */ break; } case GAMEOBJECT_TYPE_CHAIR: //7 - if(goInfo->chair.height > (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR) ) - { - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..%i.", - id,goInfo->type,goInfo->chair.height,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); - - // prevent client and server unexpected work - const_cast<GameObjectInfo*>(goInfo)->chair.height = 0; - } + CheckAndFixGOChairHeightId(goInfo,goInfo->chair.height,1); break; case GAMEOBJECT_TYPE_SPELL_FOCUS: //8 { - if(goInfo->spellFocus.focusId) + if (goInfo->spellFocus.focusId) { - if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) + if (!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.", id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId); } - if(goInfo->spellFocus.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId); - */ - } + if (goInfo->spellFocus.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->spellFocus.linkedTrapId,2); break; } case GAMEOBJECT_TYPE_GOOBER: //10 { - if(goInfo->goober.pageId) // pageId + if (goInfo->goober.lockId) + CheckGOLockId(goInfo,goInfo->goober.lockId,0); + + if (goInfo->goober.pageId) // pageId { - if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId)) + if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId)) sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.", id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId); } - /* disable check for while - if(goInfo->goober.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->goober.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId); - } + /* disable check for while, too many not existed spells + if (goInfo->goober.spellId) // spell + CheckGOSpellId(goInfo,goInfo->goober.spellId,10); */ - if(goInfo->goober.linkedTrapId) // linked trap - { - if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId)) - { - if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId); - */ - } + CheckGONoDamageImmuneId(goInfo,goInfo->goober.noDamageImmune,11); + if (goInfo->goober.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->goober.linkedTrapId,12); + break; + } + case GAMEOBJECT_TYPE_AREADAMAGE: //12 + { + if (goInfo->areadamage.lockId) + CheckGOLockId(goInfo,goInfo->areadamage.lockId,0); + break; + } + case GAMEOBJECT_TYPE_CAMERA: //13 + { + if (goInfo->camera.lockId) + CheckGOLockId(goInfo,goInfo->camera.lockId,0); break; } case GAMEOBJECT_TYPE_MO_TRANSPORT: //15 { - if(goInfo->moTransport.taxiPathId) + if (goInfo->moTransport.taxiPathId) { - if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) + if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.", id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId); } @@ -5734,35 +5754,40 @@ void ObjectMgr::LoadGameobjectInfo() } case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18 { - /* disabled - if(goInfo->summoningRitual.spellId) - { - if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId); - } + /* disable check for while, too many not existed spells + // always must have spell + CheckGOSpellId(goInfo,goInfo->summoningRitual.spellId,1); */ break; } case GAMEOBJECT_TYPE_SPELLCASTER: //22 { - if(goInfo->spellcaster.spellId) // spell - { - if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.", - id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId); - } + // always must have spell + CheckGOSpellId(goInfo,goInfo->spellcaster.spellId,0); + break; + } + case GAMEOBJECT_TYPE_FLAGSTAND: //24 + { + if (goInfo->flagstand.lockId) + CheckGOLockId(goInfo,goInfo->flagstand.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->flagstand.noDamageImmune,5); + break; + } + case GAMEOBJECT_TYPE_FISHINGHOLE: //25 + { + if (goInfo->fishinghole.lockId) + CheckGOLockId(goInfo,goInfo->fishinghole.lockId,4); + break; + } + case GAMEOBJECT_TYPE_FLAGDROP: //26 + { + if (goInfo->flagdrop.lockId) + CheckGOLockId(goInfo,goInfo->flagdrop.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->flagdrop.noDamageImmune,3); break; } case GAMEOBJECT_TYPE_BARBER_CHAIR: //32 - if(goInfo->barberChair.chairheight > (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR) ) - { - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..%i.", - id,goInfo->type,goInfo->barberChair.chairheight,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); - - // prevent client and server unexpected work - const_cast<GameObjectInfo*>(goInfo)->barberChair.chairheight = 0; - } + CheckAndFixGOChairHeightId(goInfo,goInfo->barberChair.chairheight,0); break; } } diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 1d45ed3a7fd..e723298565a 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -99,20 +99,28 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool QueryResult *result; - if(petnumber) - // known petnumber entry 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND id = '%u'",ownerid, petnumber); - else if(current) - // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND slot = '0'",ownerid ); - else if(petentry) + if (petnumber) + // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + "FROM character_pet WHERE owner = '%u' AND id = '%u'", + ownerid, petnumber); + else if (current) + // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + "FROM character_pet WHERE owner = '%u' AND slot = '%u'", + ownerid, PET_SAVE_AS_CURRENT ); + else if (petentry) // known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets) - // 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '0' OR slot = '3') ",ownerid, petentry ); + // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + "FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ", + ownerid, petentry,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); else // any current or other non-stabled pet (for hunter "call pet") - // 0 1 2(?) 3 4 5 6 7 8(?) 9 10 11 12 13 14 15 16 17 18 19 20 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3') ",ownerid); + // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " + "FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ", + ownerid,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); if(!result) return false; @@ -121,7 +129,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool // update for case of current pet "slot = 0" petentry = fields[1].GetUInt32(); - if(!petentry) + if (!petentry) { delete result; return false; @@ -133,16 +141,24 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool bool is_temporary_summoned = spellInfo && GetSpellDuration(spellInfo) > 0; // check temporary summoned pets like mage water elemental - if(current && is_temporary_summoned) + if (current && is_temporary_summoned) { delete result; return false; } + uint32 pet_number = fields[0].GetUInt32(); + + if (current && owner->IsPetNeedBeTemporaryUnsummoned()) + { + owner->SetTemporaryUnsummonedPetNumber(pet_number); + delete result; + return false; + } + Map *map = owner->GetMap(); uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_PET); - uint32 pet_number = fields[0].GetUInt32(); - if(!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number)) + if (!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number)) { delete result; return false; @@ -151,7 +167,8 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool float px, py, pz; owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); Relocate(px, py, pz, owner->GetOrientation()); - if(!IsPositionValid()) + + if (!IsPositionValid()) { sLog.outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", GetGUIDLow(), GetEntry(), GetPositionX(), GetPositionY()); @@ -164,24 +181,29 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); CreatureInfo const *cinfo = GetCreatureInfo(); - if(cinfo->type == CREATURE_TYPE_CRITTER) + if (cinfo->type == CREATURE_TYPE_CRITTER) { map->Add((Creature*)this); delete result; return true; } - if(getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK)) + if (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK)) m_charmInfo->SetPetNumber(pet_number, true); else m_charmInfo->SetPetNumber(pet_number, false); // set current pet as current + // 0=current + // 1..MAX_PET_STABLES in stable slot + // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning)) if(fields[8].GetUInt32() != 0) { CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE character_pet SET slot = '3' WHERE owner = '%u' AND slot = '0' AND id <> '%u'", ownerid, m_charmInfo->GetPetNumber()); - CharacterDatabase.PExecute("UPDATE character_pet SET slot = '0' WHERE owner = '%u' AND id = '%u'", ownerid, m_charmInfo->GetPetNumber()); + CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u' AND id <> '%u'", + PET_SAVE_NOT_IN_SLOT, ownerid, PET_SAVE_AS_CURRENT, m_charmInfo->GetPetNumber()); + CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND id = '%u'", + PET_SAVE_AS_CURRENT, ownerid, m_charmInfo->GetPetNumber()); CharacterDatabase.CommitTransaction(); } @@ -191,7 +213,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetUInt32Value(UNIT_NPC_FLAGS, 0); SetName(fields[9].GetString()); - switch(getPetType()) + switch (getPetType()) { case SUMMON_PET: petlevel=owner->getLevel(); @@ -247,12 +269,12 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool _LoadSpells(); _LoadSpellCooldowns(); - if(!is_temporary_summoned) + if (!is_temporary_summoned) { // permanent controlled pets store state in DB Tokens tokens = StrSplit(fields[14].GetString(), " "); - if(tokens.size() != 20) + if (tokens.size() != 20) { delete result; return false; @@ -332,109 +354,112 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool void Pet::SavePetToDB(PetSaveMode mode) { - if(!GetEntry()) + if (!GetEntry()) return; // save only fully controlled creature - if(!isControlled()) + if (!isControlled()) return; + // not save not player pets + if(!IS_PLAYER_GUID(GetOwnerGUID())) + return; + + Player* pOwner = (Player*)GetOwner(); + if (!pOwner) + return; + + // not save pet as current if another pet temporary unsummoned + if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() && + pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber()) + { + // pet will lost anyway at restore temporary unsummoned + if(getPetType()==HUNTER_PET) + return; + + // for warlock case + mode = PET_SAVE_NOT_IN_SLOT; + } + uint32 curhealth = GetHealth(); uint32 curmana = GetPower(POWER_MANA); - switch(mode) + // stable and not in slot saves + if(mode > PET_SAVE_AS_CURRENT) { - case PET_SAVE_IN_STABLE_SLOT_1: - case PET_SAVE_IN_STABLE_SLOT_2: - case PET_SAVE_NOT_IN_SLOT: - { - RemoveAllAuras(); - - //only alive hunter pets get auras saved, the others don't - if(!(getPetType() == HUNTER_PET && isAlive())) - m_Auras.clear(); - } - default: - break; + RemoveAllAuras(); } _SaveSpells(); _SaveSpellCooldowns(); _SaveAuras(); - switch(mode) + // current/stable/not_in_slot + if(mode >= PET_SAVE_AS_CURRENT) { - case PET_SAVE_AS_CURRENT: - case PET_SAVE_IN_STABLE_SLOT_1: - case PET_SAVE_IN_STABLE_SLOT_2: - case PET_SAVE_NOT_IN_SLOT: + uint32 owner = GUID_LOPART(GetOwnerGUID()); + std::string name = m_name; + CharacterDatabase.escape_string(name); + CharacterDatabase.BeginTransaction(); + // remove current data + CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND id = '%u'", owner,m_charmInfo->GetPetNumber() ); + + // prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT) + if(mode <= PET_SAVE_LAST_STABLE_SLOT) + CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u'", + PET_SAVE_NOT_IN_SLOT, owner, uint32(mode) ); + + // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT + if(getPetType()==HUNTER_PET && (mode==PET_SAVE_AS_CURRENT||mode > PET_SAVE_LAST_STABLE_SLOT)) + CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u')", + owner,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); + // save pet + std::ostringstream ss; + ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " + << "VALUES (" + << m_charmInfo->GetPetNumber() << ", " + << GetEntry() << ", " + << owner << ", " + << GetNativeDisplayId() << ", " + << getLevel() << ", " + << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", " + << uint32(GetReactState()) << ", " + << uint32(GetFreeTalentPoints()) << ", " + << uint32(mode) << ", '" + << name.c_str() << "', " + << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", " + << (curhealth<1?1:curhealth) << ", " + << curmana << ", " + << GetPower(POWER_HAPPINESS) << ", '"; + + for(uint32 i = 0; i < 10; i++) + ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + ss << "', '"; + + //save spells the pet can teach to it's Master { - uint32 owner = GUID_LOPART(GetOwnerGUID()); - std::string name = m_name; - CharacterDatabase.escape_string(name); - CharacterDatabase.BeginTransaction(); - // remove current data - CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND id = '%u'", owner,m_charmInfo->GetPetNumber() ); - - // prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT) - if(mode!=PET_SAVE_NOT_IN_SLOT) - CharacterDatabase.PExecute("UPDATE character_pet SET slot = 3 WHERE owner = '%u' AND slot = '%u'", owner, uint32(mode) ); - - // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT - if(getPetType()==HUNTER_PET && (mode==PET_SAVE_AS_CURRENT||mode==PET_SAVE_NOT_IN_SLOT)) - CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '0' OR slot = '3')", owner ); - // save pet - std::ostringstream ss; - ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " - << "VALUES (" - << m_charmInfo->GetPetNumber() << ", " - << GetEntry() << ", " - << owner << ", " - << GetNativeDisplayId() << ", " - << getLevel() << ", " - << GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", " - << uint32(GetReactState()) << ", " - << uint32(GetFreeTalentPoints()) << ", " - << uint32(mode) << ", '" - << name.c_str() << "', " - << uint32((GetByteValue(UNIT_FIELD_BYTES_2, 2) == UNIT_RENAME_ALLOWED)?0:1) << ", " - << (curhealth<1?1:curhealth) << ", " - << curmana << ", " - << GetPower(POWER_HAPPINESS) << ", '"; - - for(uint32 i = 0; i < 10; i++) - ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; - ss << "', '"; - - //save spells the pet can teach to it's Master - { - int i = 0; - for(TeachSpellMap::iterator itr = m_teachspells.begin(); i < 4 && itr != m_teachspells.end(); ++i, ++itr) - ss << itr->first << " " << itr->second << " "; - for(; i < 4; ++i) - ss << uint32(0) << " " << uint32(0) << " "; - } - - ss << "', " - << time(NULL) << ", " - << uint32(m_resetTalentsCost) << ", " - << uint64(m_resetTalentsTime) << ", " - << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", " - << uint32(getPetType()) << ")"; + int i = 0; + for(TeachSpellMap::iterator itr = m_teachspells.begin(); i < 4 && itr != m_teachspells.end(); ++i, ++itr) + ss << itr->first << " " << itr->second << " "; + for(; i < 4; ++i) + ss << uint32(0) << " " << uint32(0) << " "; + } - CharacterDatabase.Execute( ss.str().c_str() ); + ss << "', " + << time(NULL) << ", " + << uint32(m_resetTalentsCost) << ", " + << uint64(m_resetTalentsTime) << ", " + << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", " + << uint32(getPetType()) << ")"; - CharacterDatabase.CommitTransaction(); - break; - } - case PET_SAVE_AS_DELETED: - { - RemoveAllAuras(); - DeleteFromDB(m_charmInfo->GetPetNumber()); - break; - } - default: - sLog.outError("Unknown pet save/remove mode: %d",mode); + CharacterDatabase.Execute( ss.str().c_str() ); + CharacterDatabase.CommitTransaction(); + } + // delete + else + { + RemoveAllAuras(); + DeleteFromDB(m_charmInfo->GetPetNumber()); } } @@ -1148,15 +1173,14 @@ void Pet::_SaveAuras() { // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras. // do not save single target auras (unless they were cast by the player) - if (itr->second->IsPassive() - || (itr->second->GetCasterGUID() != GetGUID() && itr->second->IsSingleTarget())) + if (itr->second->IsPassive() || itr->second->IsAuraType(SPELL_AURA_MOD_STEALTH)) continue; - SpellEntry const *spellInfo = itr->second->GetSpellProto(); - for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_STEALTH || - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_OWNER || - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PET ) + bool isCaster = itr->second->GetCasterGUID() == GetGUID(); + if (!isCaster) + if (itr->second->IsSingleTarget() + || itr->second->IsAreaAura()) continue; + uint32 amounts[MAX_SPELL_EFFECTS]; for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) { diff --git a/src/game/Pet.h b/src/game/Pet.h index 5879208a6b8..de998c20aac 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -35,13 +35,16 @@ enum PetType extern char const* petTypeSuffix[MAX_PET_TYPE]; +#define MAX_PET_STABLES 4 + +// stored in character_pet.slot enum PetSaveMode { - PET_SAVE_AS_DELETED =-1, - PET_SAVE_AS_CURRENT = 0, - PET_SAVE_IN_STABLE_SLOT_1 = 1, - PET_SAVE_IN_STABLE_SLOT_2 = 2, - PET_SAVE_NOT_IN_SLOT = 3 + PET_SAVE_AS_DELETED = -1, // not saved in fact + PET_SAVE_AS_CURRENT = 0, // in current slot (with player) + PET_SAVE_FIRST_STABLE_SLOT = 1, + PET_SAVE_LAST_STABLE_SLOT = MAX_PET_STABLES, // last in DB stable slot index (including), all higher have same meaning as PET_SAVE_NOT_IN_SLOT + PET_SAVE_NOT_IN_SLOT = 100 // for avoid conflict with stable size grow will use 100 }; enum HappinessState diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp index 0ec0eee3d9e..61485c3eb04 100644 --- a/src/game/PetitionsHandler.cpp +++ b/src/game/PetitionsHandler.cpp @@ -254,7 +254,7 @@ void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) QueryResult *result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); if(!result) { - sLog.outError("any petition on server..."); + sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); return; } Field *fields = result->Fetch(); @@ -462,7 +462,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) if(!result) { - sLog.outError("any petition on server..."); + sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); return; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 2eeb5d3548c..ae14d5ebc30 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -340,7 +340,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_atLoginFlags = AT_LOGIN_NONE; - m_dontMove = false; + mSemaphoreTeleport_Near = false; + mSemaphoreTeleport_Far = false; pTrader = 0; ClearTrade(); @@ -467,8 +468,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_isActive = true; - m_farsightVision = false; - m_runes = NULL; m_lastFallTime = 0; @@ -1645,9 +1644,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_movementInfo.t_time = 0; } - SetSemaphoreTeleport(true); - - // The player was ported to another map and looses the duel immediatly. + // The player was ported to another map and looses the duel immediately. // We have to perform this check before the teleport, otherwise the // ObjectAccessor won't find the flag. if (duel && GetMapId()!=mapid) @@ -1662,72 +1659,29 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if ((GetMapId() == mapid) && (!m_transport)) { - // prepare zone change detect - uint32 old_zone = GetZoneId(); - - // near teleport - if(!GetSession()->PlayerLogout()) - { - WorldPacket data; - BuildTeleportAckMsg(&data, x, y, z, orientation); - GetSession()->SendPacket(&data); - SetPosition( x, y, z, orientation, true); - } - else - // this will be used instead of the current location in SaveToDB - m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); - - SetFallInformation(0, z); - - //BuildHeartBeatMsg(&data); - //SendMessageToSet(&data, true); if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { - //same map, only remove pet if out of range - if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) - { - if(pet->isControlled() && !pet->isTemporarySummoned() ) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } + //same map, only remove pet if out of range for new position + if(pet && pet->GetDistance(x,y,z) >= OWNER_MAX_DISTANCE) + UnsummonPetTemporaryIfAny(); } if(!(options & TELE_TO_NOT_LEAVE_COMBAT)) CombatStop(); - if (!(options & TELE_TO_NOT_UNSUMMON_PET)) - { - // resummon pet - if(pet && m_temporaryUnsummonedPetNumber) - { - Pet* NewPet = new Pet(this); - if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) - delete NewPet; - - m_temporaryUnsummonedPetNumber = 0; - } - } - - uint32 newzone, newarea; - GetZoneAndAreaId(newzone,newarea); + // this will be used instead of the current location in SaveToDB + m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + SetFallInformation(0, z); + // code for finish transfer called in WorldSession::HandleMovementOpcodes() + // at client packet MSG_MOVE_TELEPORT_ACK + SetSemaphoreTeleportNear(true); + // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing if(!GetSession()->PlayerLogout()) { - // don't reset teleport semaphore while logging out, otherwise m_teleport_dest won't be used in Player::SaveToDB - SetSemaphoreTeleport(false); - - UpdateZone(newzone,newarea); - } - - // new zone - if(old_zone != newzone) - { - // honorless target - if(pvpInfo.inHostileArea) - CastSpell(this, 2479, true); + WorldPacket data; + BuildTeleportAckMsg(&data, x, y, z, orientation); + GetSession()->SendPacket(&data); } } else @@ -1739,10 +1693,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // Check enter rights before map getting to avoid creating instance copy for player // this check not dependent from map instance copy and same for all instance copies of selected map if (!MapManager::Instance().CanPlayerEnter(mapid, this)) - { - SetSemaphoreTeleport(false); return false; - } // If the map is not created, assume it is possible to enter it. // It will be created in the WorldPortAck. @@ -1767,15 +1718,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // remove pet on map change if (pet) - { - //leaving map -> delete pet right away (doing this later will cause problems) - if(pet->isControlled() && !pet->isTemporarySummoned()) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } + UnsummonPetTemporaryIfAny(); // remove all dyn objects RemoveAllDynObjects(); @@ -1835,10 +1778,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); // move packet sent by client always after far teleport - // SetPosition(final_x, final_y, final_z, final_o, true); - SetDontMove(true); - // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet + SetSemaphoreTeleportFar(true); } else return false; @@ -2474,7 +2415,7 @@ void Player::InitStatsForLevel(bool reapplyMods) SetUInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,0); for(int i = 0; i < MAX_SPELL_SCHOOL; ++i) { - SetFloatValue(UNIT_FIELD_POWER_COST_MODIFIER+i,0.0f); + SetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,0); SetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,0.0f); } // Reset no reagent cost field @@ -3299,7 +3240,6 @@ void Player::_LoadSpellCooldowns(QueryResult *result) // some cooldowns can be already set at aura loading... //QueryResult *result = CharacterDatabase.PQuery("SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'",GetGUIDLow()); - if(result) { time_t curTime = time(NULL); @@ -4688,24 +4628,24 @@ float Player::GetRatingBonusValue(CombatRating cr) const uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const { - float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.0f; - if (melee>25.0f) melee = 25.0f; + float melee = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*2.2f; + if (melee>33.0f) melee = 33.0f; return uint32 (melee * damage /100.0f); } uint32 Player::GetRangedCritDamageReduction(uint32 damage) const { - float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.0f; - if (ranged>25.0f) ranged=25.0f; + float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.2f; + if (ranged>33.0f) ranged=33.0f; return uint32 (ranged * damage /100.0f); } uint32 Player::GetSpellCritDamageReduction(uint32 damage) const { - float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.0f; - // In wow script resilience limited to 25% - if (spell>25.0f) - spell = 25.0f; + float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.2f; + // In wow script resilience limited to 33% + if (spell>33.0f) + spell = 33.0f; return uint32 (spell * damage / 100.0f); } @@ -5489,11 +5429,6 @@ void Player::removeActionButton(uint8 button) sLog.outDetail( "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow() ); } -void Player::SetDontMove(bool dontMove) -{ - m_dontMove = dontMove; -} - bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport) { // prevent crash when a bad coord is sent by the client @@ -5722,6 +5657,9 @@ void Player::RewardReputation(Unit *pVictim, float rate) if(!pVictim || pVictim->GetTypeId() == TYPEID_PLAYER) return; + if(((Creature*)pVictim)->IsReputationGainDisabled()) + return; + ReputationOnKillEntry const* Rep = objmgr.GetReputationOnKilEntry(((Creature*)pVictim)->GetCreatureInfo()->Entry); if(!Rep) @@ -6273,7 +6211,7 @@ void Player::DuelComplete(DuelCompleteType type) if(!duel) return; - sLog.outDebug("Dual Complete %s %s", GetName(), duel->opponent->GetName()); + sLog.outDebug("Duel Complete %s %s", GetName(), duel->opponent->GetName()); WorldPacket data(SMSG_DUEL_COMPLETE, (1)); data << (uint8)((type != DUEL_INTERUPTED) ? 1 : 0); @@ -10256,7 +10194,7 @@ Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update ) return NULL; Item* lastItem = pItem; - + uint32 entry = pItem->GetEntry(); for(ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ) { uint16 pos = itr->pos; @@ -10272,7 +10210,7 @@ Item* Player::StoreItem( ItemPosCountVec const& dest, Item* pItem, bool update ) lastItem = _StoreItem(pos,pItem,count,true,update); } - + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, entry); return lastItem; } @@ -12744,6 +12682,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver SendQuestReward( pQuest, XP, questGiver ); if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + if (pQuest->GetZoneOrSort() > 0) + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort()); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST); @@ -13398,7 +13338,6 @@ void Player::ItemAddedQuestCheck( uint32 entry, uint32 count ) } } UpdateForQuestsGO(); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, entry); } void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count ) @@ -14414,10 +14353,10 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) uint32 extraflags = fields[25].GetUInt32(); m_stableSlots = fields[26].GetUInt32(); - if(m_stableSlots > 4) + if(m_stableSlots > MAX_PET_STABLES) { - sLog.outError("Player can have not more 4 stable slots, but have in DB %u",uint32(m_stableSlots)); - m_stableSlots = 4; + sLog.outError("Player can have not more %u stable slots, but have in DB %u",MAX_PET_STABLES,uint32(m_stableSlots)); + m_stableSlots = MAX_PET_STABLES; } m_atLoginFlags = fields[27].GetUInt32(); @@ -15841,17 +15780,20 @@ void Player::_SaveAuras() AuraMap const& auras = GetAuras(); for(AuraMap::const_iterator itr = auras.begin(); itr !=auras.end() ; ++itr) { - // skip all auras from spell that apply at cast SPELL_AURA_MOD_SHAPESHIFT or pet area auras. - // do not save single target auras (unless they were cast by the player) + // skip: + // area auras or single cast auras casted by other unit + // passive auras and stances if (itr->second->IsPassive() - || (itr->second->GetCasterGUID() != GetGUID() && itr->second->IsSingleTarget()) + || itr->second->IsAuraType(SPELL_AURA_MOD_SHAPESHIFT) + || itr->second->IsAuraType(SPELL_AURA_MOD_STEALTH) || itr->second->IsRemovedOnShapeLost()) continue; - SpellEntry const *spellInfo = itr->second->GetSpellProto(); - for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) - if (spellInfo->Effect[i] == SPELL_AURA_MOD_SHAPESHIFT || - spellInfo->Effect[i] == SPELL_AURA_MOD_STEALTH ) + bool isCaster = itr->second->GetCasterGUID() == GetGUID(); + if (!isCaster) + if (itr->second->IsSingleTarget() + || itr->second->IsAreaAura()) continue; + int32 amounts[MAX_SPELL_EFFECTS]; for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) { @@ -16953,7 +16895,7 @@ void Player::RemoveSpellMods(Spell const* spell) if (mod && mod->charges == -1 && (mod->lastAffected == spell || mod->lastAffected==NULL)) { - RemoveAurasDueToSpell(mod->spellId); + RemoveAurasDueToSpell(mod->spellId, 0, AURA_REMOVE_BY_EXPIRE); if (m_spellMods[i].empty()) break; else @@ -18697,7 +18639,7 @@ void Player::SendAurasForTarget(Unit *target) // level data << aura->m_auraLevel; // charges - data << uint8(aura->GetStackAmount() ? aura->GetStackAmount() : aura->GetAuraCharges()); + data << uint8(aura->GetStackAmount()>1 ? aura->GetStackAmount() : aura->GetAuraCharges()); if(!(aura->m_auraFlags & AFLAG_CASTER)) { @@ -19534,7 +19476,7 @@ void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) } // Allow travel in dark water on taxi or transport - if (liquid_status.type & MAP_LIQUID_TYPE_DARK_WATER && !isInFlight() && !(GetUnitMovementFlags()&MOVEMENTFLAG_ONTRANSPORT)) + if ((liquid_status.type & MAP_LIQUID_TYPE_DARK_WATER) && !isInFlight() && !GetTransport()) m_MirrorTimerFlags |= UNDERWARER_INDARKWATER; else m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER; @@ -19645,14 +19587,17 @@ WorldObject* Player::GetViewpoint() const bool Player::CanUseBattleGroundObject() { + // TODO : some spells gives player ForceReaction to one faction (ReputationMgr::ApplyForceReaction) + // maybe gameobject code should handle that ForceReaction usage + // BUG: sometimes when player clicks on flag in AB - client won't send gameobject_use, only gameobject_report_use packet return ( //InBattleGround() && // in battleground - not need, check in other cases //!IsMounted() && - not correct, player is dismounted when he clicks on flag - //i'm not sure if these two are correct, because invisible players should get visible when they click on flag + //player cannot use object when he is invulnerable (immune) !isTotalImmune() && // not totally immune + //i'm not sure if these two are correct, because invisible players should get visible when they click on flag !HasStealthAura() && // not stealthed !HasInvisibilityAura() && // not invisible !HasAura(SPELL_RECENTLY_DROPPED_FLAG) && // can't pickup - //TODO player cannot use object when he is invulnerable (immune) - (ice block, divine shield, divine protection, divine intervention ...) isAlive() // live player ); } @@ -19744,37 +19689,31 @@ void Player::EnterVehicle(Vehicle *vehicle) StopCastingCharm(); StopCastingBindSight(); + SetCharm(vehicle, true); SetViewpoint(vehicle, true); SetMover(vehicle); - SetClientControl(vehicle, 1); // redirect controls to vehicle + addUnitState(UNIT_STAT_ONVEHICLE); + Relocate(vehicle->GetPositionX(), vehicle->GetPositionY(), vehicle->GetPositionZ(), vehicle->GetOrientation()); + AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + m_movementInfo.t_x = veSeat->m_attachmentOffsetX; + m_movementInfo.t_y = veSeat->m_attachmentOffsetY; + m_movementInfo.t_z = veSeat->m_attachmentOffsetZ; + m_movementInfo.t_o = 0; + m_movementInfo.t_time = getMSTime(); + m_movementInfo.t_seat = 0; + WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); GetSession()->SendPacket(&data); - data.Initialize(MSG_MOVE_TELEPORT_ACK, 30); - data.append(GetPackGUID()); - data << uint32(0); // counter? - data << uint32(MOVEMENTFLAG_ONTRANSPORT); // transport - data << uint16(0); // special flags - data << uint32(getMSTime()); // time - data << vehicle->GetPositionX(); // x - data << vehicle->GetPositionY(); // y - data << vehicle->GetPositionZ(); // z - data << vehicle->GetOrientation(); // o - // transport part, TODO: load/calculate seat offsets - data << uint64(vehicle->GetGUID()); // transport guid - data << float(veSeat->m_attachmentOffsetX); // transport offsetX - data << float(veSeat->m_attachmentOffsetY); // transport offsetY - data << float(veSeat->m_attachmentOffsetZ); // transport offsetZ - data << float(0); // transport orientation - data << uint32(getMSTime()); // transport time - data << uint8(0); // seat - // end of transport part - data << uint32(0); // fall time + BuildTeleportAckMsg(&data, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); GetSession()->SendPacket(&data); + BuildHeartBeatMsg(&data); + SendMessageToSet(&data, false); + VehicleSpellInitialize(); } @@ -19787,29 +19726,36 @@ void Player::ExitVehicle(Vehicle *vehicle) SetCharm(vehicle, false); SetViewpoint(vehicle, false); SetMover(this); - SetClientControl(vehicle, 0); - WorldPacket data(MSG_MOVE_TELEPORT_ACK, 30); - data.append(GetPackGUID()); - data << uint32(0); // counter? - data << uint32(MOVEMENTFLAG_FLY_UNK1); // fly unk - data << uint16(0x40); // special flags - data << uint32(getMSTime()); // time - data << vehicle->GetPositionX(); // x - data << vehicle->GetPositionY(); // y - data << vehicle->GetPositionZ(); // z - data << vehicle->GetOrientation(); // o - data << uint32(0); // fall time + clearUnitState(UNIT_STAT_ONVEHICLE); + Relocate(vehicle->GetPositionX(), vehicle->GetPositionY(), vehicle->GetPositionZ(), vehicle->GetOrientation()); + RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + m_movementInfo.t_x = 0; + m_movementInfo.t_y = 0; + m_movementInfo.t_z = 0; + m_movementInfo.t_o = 0; + m_movementInfo.t_time = 0; + m_movementInfo.t_seat = 0; + + WorldPacket data; + BuildTeleportAckMsg(&data, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); GetSession()->SendPacket(&data); + BuildHeartBeatMsg(&data); + SendMessageToSet(&data, false); + data.Initialize(SMSG_PET_SPELLS, 8+4); data << uint64(0); data << uint32(0); GetSession()->SendPacket(&data); // only for flyable vehicles? - CastSpell(this, 45472, true); // Parachute + //CastSpell(this, 45472, true); // Parachute + + //if(!vehicle->GetDBTableGUIDLow()) + if(vehicle->GetOwnerGUID() == GetGUID()) + vehicle->Dismiss(); } bool Player::isTotalImmune() @@ -20162,7 +20108,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) { // calculate total z distance of the fall float z_diff = m_lastFallZ - movementInfo.z; - sLog.outDebug("zDiff = %f", z_diff); + //sLog.outDebug("zDiff = %f", z_diff); //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored // 14.57 can be calculated by resolving damageperc formular below to 0 @@ -20475,3 +20421,37 @@ void Player::UpdateFallInformationIfNeed( MovementInfo const& minfo,uint16 opcod if (m_lastFallTime >= minfo.fallTime || m_lastFallZ <=minfo.z || opcode == MSG_MOVE_FALL_LAND) SetFallInformation(minfo.fallTime, minfo.z); } + +void Player::UnsummonPetTemporaryIfAny() +{ + Pet* pet = GetPet(); + if(!pet) + return; + + if(!m_temporaryUnsummonedPetNumber && pet->isControlled() && !pet->isTemporarySummoned() ) + { + m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); + m_oldpetspell = pet->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + RemovePet(pet, PET_SAVE_AS_CURRENT); +} + +void Player::ResummonPetTemporaryUnSummonedIfAny() +{ + if(!m_temporaryUnsummonedPetNumber) + return; + + // not resummon in not appropriate state + if(IsPetNeedBeTemporaryUnsummoned()) + return; + + if(GetPetGUID()) + return; + + Pet* NewPet = new Pet(this); + if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) + delete NewPet; + + m_temporaryUnsummonedPetNumber = 0; +} diff --git a/src/game/Player.h b/src/game/Player.h index 4738ce603a0..60b2c7a0a1d 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1663,8 +1663,12 @@ class TRINITY_DLL_SPEC Player : public Unit bool HasSkill(uint32 skill) const; void learnSkillRewardedSpells(uint32 id, uint32 value); - void SetDontMove(bool dontMove); - bool GetDontMove() const { return m_dontMove; } + WorldLocation& GetTeleportDest() { return m_teleport_dest; } + bool IsBeingTeleported() const { return mSemaphoreTeleport_Near || mSemaphoreTeleport_Far; } + bool IsBeingTeleportedNear() const { return mSemaphoreTeleport_Near; } + bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; } + void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; } + void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; } void CheckExploreSystem(void); @@ -1998,8 +2002,9 @@ class TRINITY_DLL_SPEC Player : public Unit // Temporarily removed pet cache uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } - uint32 GetOldPetSpell() const { return m_oldpetspell; } - void SetOldPetSpell(uint32 petspell) { m_oldpetspell = petspell; } + void UnsummonPetTemporaryIfAny(); + void ResummonPetTemporaryUnSummonedIfAny(); + bool IsPetNeedBeTemporaryUnsummoned() const { return !IsInWorld() || !isAlive() || IsMounted() /*+in flight*/; } void SendCinematicStart(uint32 CinematicSequenceId); void SendMovieStart(uint32 MovieId); @@ -2056,8 +2061,6 @@ class TRINITY_DLL_SPEC Player : public Unit bool isAllowedToLoot(Creature* creature); - WorldLocation& GetTeleportDest() { return m_teleport_dest; } - DeclinedName const* GetDeclinedNames() const { return m_declinedname; } uint8 GetRunesState() const { return m_runes->runeState; } uint8 GetBaseRune(uint8 index) const { return m_runes->runes[index].BaseRune; } @@ -2224,8 +2227,6 @@ class TRINITY_DLL_SPEC Player : public Unit typedef std::list<Channel*> JoinedChannelsList; JoinedChannelsList m_channels; - bool m_dontMove; - int m_cinematic; Player *pTrader; @@ -2290,10 +2291,6 @@ class TRINITY_DLL_SPEC Player : public Unit uint32 m_groupUpdateMask; uint64 m_auraRaidUpdateMask; - // Temporarily removed pet cache - uint32 m_temporaryUnsummonedPetNumber; - uint32 m_oldpetspell; - // Player summoning time_t m_summon_expire; uint32 m_summon_mapid; @@ -2301,11 +2298,6 @@ class TRINITY_DLL_SPEC Player : public Unit float m_summon_y; float m_summon_z; - // Far Teleport - WorldLocation m_teleport_dest; - - bool m_farsightVision; - DeclinedName *m_declinedname; Runes *m_runes; private: @@ -2333,6 +2325,15 @@ class TRINITY_DLL_SPEC Player : public Unit uint8 m_MirrorTimerFlagsLast; bool m_isInWater; + // Current teleport data + WorldLocation m_teleport_dest; + bool mSemaphoreTeleport_Near; + bool mSemaphoreTeleport_Far; + + // Temporary removed pet cache + uint32 m_temporaryUnsummonedPetNumber; + uint32 m_oldpetspell; + AchievementMgr m_achievementMgr; ReputationMgr m_reputationMgr; }; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 16cfe5b0e60..f14cc6b5ed3 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -307,6 +307,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_triggeringContainer = triggeringContainer; m_referencedFromCurrentSpell = false; m_executedCurrently = false; + m_needComboPoints = NeedsComboPoints(m_spellInfo); m_delayStart = 0; m_delayAtDamageCount = 0; @@ -945,6 +946,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him DoSpellHitOnUnit(m_caster, mask); } + // Do not take combo points on dodge + if (m_needComboPoints && m_targets.getUnitTargetGUID() == target->targetGUID) + if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS) + m_needComboPoints = false; /*else //TODO: This is a hack. need fix { uint32 tempMask = 0; @@ -1022,14 +1027,6 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo); } - // Take combo points after effects handling (combo points are used in effect handling) - if(!m_IsTriggeredSpell && !m_CastItem - && NeedsComboPoints(m_spellInfo) - && m_caster->GetTypeId()==TYPEID_PLAYER - && target->targetGUID == m_targets.getUnitTargetGUID() - && (missInfo == SPELL_MISS_NONE || missInfo == SPELL_MISS_MISS)) - ((Player*)m_caster)->ClearComboPoints(); - // Call scripted function for AI if this spell is casted upon a creature (except pets) if(IS_CREATURE_GUID(target->targetGUID)) { @@ -1103,8 +1100,8 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) } unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); - if(m_customAttr & SPELL_ATTR_CU_AURA_CC) - unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CC); + //if(m_customAttr & SPELL_ATTR_CU_AURA_CC) + //unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CC); } else { @@ -2192,6 +2189,10 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura // Prepare data for triggers prepareDataForTriggerSystem(); + // Set combo point requirement + if (m_IsTriggeredSpell || m_CastItem || m_caster->GetTypeId()!=TYPEID_PLAYER) + m_needComboPoints = false; + // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) m_casttime = GetSpellCastTime(m_spellInfo, this); @@ -2208,6 +2209,9 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura if(isSpellBreakStealth(m_spellInfo) ) m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); + if(!m_IsTriggeredSpell) + m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ANY_CAST); + m_caster->SetCurrentCastedSpell( this ); m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]); SendSpellStart(); @@ -2224,6 +2228,10 @@ void Spell::cancel() if(m_spellState == SPELL_STATE_FINISHED) return; + SetReferencedFromCurrent(false); + if(m_selfContainer && *m_selfContainer == this) + *m_selfContainer = NULL; + uint32 oldState = m_spellState; m_spellState = SPELL_STATE_FINISHED; @@ -2541,6 +2549,10 @@ void Spell::_handle_immediate_phase() void Spell::_handle_finish_phase() { + // Take for real after all targets are processed + if (m_needComboPoints) + ((Player*)m_caster)->ClearComboPoints(); + // spell log if(m_needSpellLog) SendLogExecute(); @@ -3693,7 +3705,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_TARGET_AURASTATE; // Not allow casting on flying player - if (target->isInFlight()) + if (target->hasUnitState(UNIT_STAT_UNATTACKABLE)) return SPELL_FAILED_BAD_TARGETS; if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) @@ -3997,8 +4009,18 @@ SpellCastResult Spell::CheckCast(bool strict) { if(m_spellInfo->SpellIconID == 1648) // Execute { - if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) + if(!m_targets.getUnitTarget()) return SPELL_FAILED_BAD_TARGETS; + if (m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) + { + bool found = false; + Unit::AuraEffectList const& stateAuras = m_caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); + for(Unit::AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j) + if((*j)->isAffectedOnSpell(m_spellInfo)) + found=true; + if (!found) + return SPELL_FAILED_BAD_TARGETS; + } } else if (m_spellInfo->Id == 51582) // Rocket Boots Engaged { @@ -4527,7 +4549,7 @@ SpellCastResult Spell::CheckCasterAuras() const dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); } //immune movement impairment and loss of control - if(m_spellInfo->Id==(uint32)42292) + if(m_spellInfo->Id==42292 || m_spellInfo->Id==59752) mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; } @@ -4559,7 +4581,7 @@ SpellCastResult Spell::CheckCasterAuras() const { if( GetAllSpellMechanicMask(itr->second->GetSpellProto()) & mechanic_immune ) continue; - if( GetAllSpellMechanicMask(itr->second->GetSpellProto()) & school_immune ) + if( GetSpellSchoolMask(itr->second->GetSpellProto()) & school_immune ) continue; if( (1<<(itr->second->GetSpellProto()->Dispel)) & dispel_immune) continue; @@ -4620,8 +4642,9 @@ bool Spell::CanAutoCast(Unit* target) } else { - if( (target->GetAuraEffect(m_spellInfo->Id, j))->GetParentAura()->GetStackAmount() >= m_spellInfo->StackAmount) - return false; + if( AuraEffect * aureff = target->GetAuraEffect(m_spellInfo->Id, j)) + if (aureff->GetParentAura()->GetStackAmount() >= m_spellInfo->StackAmount) + return false; } } else if ( IsAreaAuraEffect( m_spellInfo->Effect[j] )) diff --git a/src/game/Spell.h b/src/game/Spell.h index 7c52a4e8bb3..45a3a123bae 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -278,6 +278,7 @@ class Spell void EffectSummonWild(uint32 i); void EffectHealMechanical(uint32 i); void EffectJump(uint32 i); + void EffectJump2(uint32 i); void EffectTeleUnitsFaceCaster(uint32 i); void EffectLearnSkill(uint32 i); void EffectAddHonor(uint32 i); @@ -507,6 +508,7 @@ class Spell bool m_referencedFromCurrentSpell; // mark as references to prevent deleted and access by dead pointers bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers bool m_needSpellLog; // need to send spell log? + bool m_needComboPoints; uint8 m_applyMultiplierMask; // by effect: damage multiplier needed? float m_damageMultipliers[3]; // by effect: damage multiplier diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 89d5a5578d5..008ba1278a5 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -198,7 +198,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes &AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS &AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE - &AuraEffect::HandleModMechanicImmunity, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK + &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK &AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS &AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK &AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT @@ -344,8 +344,8 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= Aura::Aura(SpellEntry const* spellproto, uint32 effMask, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem) : m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target), -m_timeCla(1000), m_removeMode(AURA_NO_REMOVE_MODE), m_AuraDRGroup(DIMINISHING_NONE), -m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_auraStateMask(0), m_updated(false), m_in_use(false) +m_timeCla(1000), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE), +m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_auraStateMask(0), m_updated(false), m_isRemoved(false) { assert(target); @@ -415,7 +415,7 @@ m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_aura m_partAuras[i]=CreateAuraEffect(this, i, NULL , caster); // correct flags if aura couldn't be created if (!m_partAuras[i]) - m_auraFlags &= uint8(~(uint8(1) << i)); + m_auraFlags &= uint8(~(1<< i)); } else { @@ -462,19 +462,6 @@ m_target(parentAura->GetTarget()) m_effIndex = effIndex; m_auraName = AuraType(m_spellProto->EffectApplyAuraName[m_effIndex]); - /*if(currentBasePoints) - { - m_amount = *currentBasePoints; - m_currentBasePoints = m_amount - 1; - } - else - { - m_currentBasePoints = m_spellProto->EffectBasePoints[m_effIndex]; - if(caster) - m_amount = caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, m_target); - else - m_amount = m_currentBasePoints + 1; - }*/ if(currentBasePoints) m_currentBasePoints = *currentBasePoints; else @@ -637,12 +624,12 @@ void Aura::Update(uint32 diff) if (caster->GetHealth()>manaPerSecond) caster->ModifyHealth(-manaPerSecond); else - RemoveAura(); + m_target->RemoveAura(this); } else if (caster->GetPower(powertype)>=manaPerSecond) caster->ModifyPower(powertype,-manaPerSecond); else - RemoveAura(); + m_target->RemoveAura(this); } } } @@ -654,7 +641,7 @@ void Aura::Update(uint32 diff) Unit* caster = GetCaster(); if(!caster) { - RemoveAura(); + m_target->RemoveAura(this); return; } // Get spell range @@ -680,7 +667,7 @@ void Aura::Update(uint32 diff) if(!caster->IsWithinDistInMap(m_target,radius)) { - RemoveAura(); + m_target->RemoveAura(this); return; } } @@ -777,37 +764,41 @@ void AreaAuraEffect::Update(uint32 diff) } else // aura at non-caster { - Unit * tmp_target = m_target; + // WARNING: the aura may get deleted during the update + // DO NOT access its members after update! + AuraEffect::Update(diff); + + // Speedup - no need to do more checks + if (GetParentAura()->IsRemoved()) + return; + + // Caster may be deleted due to update Unit* caster = GetCaster(); uint32 tmp_spellId = GetId(); uint32 tmp_effIndex = GetEffIndex(); uint64 tmp_guid = GetCasterGUID(); - // WARNING: the aura may get deleted during the update - // DO NOT access its members after update! - AuraEffect::Update(diff); - // remove aura if out-of-range from caster (after teleport for example) // or caster is isolated or caster no longer has the aura // or caster is (no longer) friendly bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true); if( !caster || caster->hasUnitState(UNIT_STAT_ISOLATED) || !caster->HasAuraEffect(tmp_spellId, tmp_effIndex) || - caster->IsFriendlyTo(tmp_target) != needFriendly + caster->IsFriendlyTo(m_target) != needFriendly ) { - GetParentAura()->RemoveAura(); + m_target->RemoveAura(GetParentAura()); } - else if (!caster->IsWithinDistInMap(tmp_target, m_radius)) + else if (!caster->IsWithinDistInMap(m_target, m_radius)) { if (needFriendly) { m_removeTime -= diff; if (m_removeTime < 0) - GetParentAura()->RemoveAura(); + m_target->RemoveAura(GetParentAura()); } else - GetParentAura()->RemoveAura(); + m_target->RemoveAura(GetParentAura()); } else { @@ -815,18 +806,18 @@ void AreaAuraEffect::Update(uint32 diff) m_removeTime = FRIENDLY_AA_REMOVE_TIME; if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group { - if(!tmp_target->IsInPartyWith(caster)) - GetParentAura()->RemoveAura(); + if(!m_target->IsInPartyWith(caster)) + m_target->RemoveAura(GetParentAura()); } else if( m_areaAuraType == AREA_AURA_RAID) { - if(!tmp_target->IsInRaidWith(caster)) - GetParentAura()->RemoveAura(); + if(!m_target->IsInRaidWith(caster)) + m_target->RemoveAura(GetParentAura()); } else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER ) { - if( tmp_target->GetGUID() != caster->GetCharmerOrOwnerGUID() ) - GetParentAura()->RemoveAura(); + if( m_target->GetGUID() != caster->GetCharmerOrOwnerGUID() ) + m_target->RemoveAura(GetParentAura()); } } } @@ -854,22 +845,21 @@ void PersistentAreaAuraEffect::Update(uint32 diff) remove = true; if(remove) - GetParentAura()->RemoveAura(); + { + m_target->RemoveAura(GetParentAura()); + return; + } AuraEffect::Update(diff); } void AuraEffect::ApplyModifier(bool apply, bool Real) { - AuraType aura = m_auraName; + if (GetParentAura()->IsRemoved()) + return; - bool inuse = GetParentAura()->IsInUse(); - if (!inuse) - GetParentAura()->SetInUse(true); - if(aura<TOTAL_AURAS) - (*this.*AuraHandler [aura])(apply,Real); - if (!inuse) - GetParentAura()->SetInUse(false); + if(m_auraName<TOTAL_AURAS) + (*this.*AuraHandler [m_auraName])(apply,Real); } void AuraEffect::CleanupTriggeredSpells() @@ -921,7 +911,7 @@ void Aura::SendAuraUpdate() data << uint32(GetId()); data << uint8(m_auraFlags); data << uint8(m_auraLevel); - data << uint8(m_stackAmount ? m_stackAmount : m_procCharges); + data << uint8(m_stackAmount>1 ? m_stackAmount : m_procCharges); if(!(m_auraFlags & AFLAG_CASTER)) { @@ -952,7 +942,8 @@ void Aura::_AddAura() // set infinity cooldown state for spells if(caster && caster->GetTypeId() == TYPEID_PLAYER) { - if (m_spellProto->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) + // Do not apply cooldown for caster passive spells (needed by Reincarnation) + if (!(caster->HasSpell(GetId()) && IsPassive()) && m_spellProto->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) { Item* castItem = m_castItemGuid ? ((Player*)caster)->GetItemByGuid(m_castItemGuid) : NULL; ((Player*)caster)->AddSpellAndCategoryCooldowns(m_spellProto,castItem ? castItem->GetEntry() : 0, NULL,true); @@ -961,12 +952,15 @@ void Aura::_AddAura() // passive auras (except totem auras) do not get placed in the slots // area auras with SPELL_AURA_NONE are not shown on target - if((m_spellProto->Attributes & 0x80 && GetTalentSpellPos(GetId())) || !m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem()) - && (!IsAreaAura() - || m_target!=caster || - (m_spellProto->Effect[0]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY - && m_spellProto->Effect[1]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY - && m_spellProto->Effect[2]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY))) + if((m_spellProto->Attributes & 0x80 && GetTalentSpellPos(GetId())) + || !m_isPassive + || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem()) + || (IsAuraType(SPELL_AURA_ABILITY_IGNORE_AURASTATE)) + && (!IsAreaAura() + || m_target!=caster || + (m_spellProto->Effect[0]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY + && m_spellProto->Effect[1]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY + && m_spellProto->Effect[2]!=SPELL_EFFECT_APPLY_AREA_AURA_ENEMY))) { // Try find slot for aura uint8 slot = MAX_AURAS; @@ -1022,10 +1016,12 @@ void Aura::_AddAura() { if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA)) for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) + { if(*itr < 0) m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), m_target); else if(Unit* caster = GetCaster()) m_target->AddAura(*itr, m_target); + } } //***************************************************** @@ -1078,6 +1074,8 @@ void Aura::_AddAura() bool Aura::SetPartAura(AuraEffect* aurEff, uint8 effIndex) { + if (IsRemoved()) + return false; if (m_auraFlags & (1<<effIndex)) return false; m_auraFlags |= 1<<effIndex; @@ -1138,6 +1136,11 @@ void Aura::_RemoveAura() m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, foundMask, false); } + // since now aura cannot apply/remove it's modifiers + m_isRemoved = true; + // disable client server communication for removed aura + SetAuraSlot(MAX_AURAS); + // reset cooldown state for spells if(caster && caster->GetTypeId() == TYPEID_PLAYER) { @@ -1145,29 +1148,32 @@ void Aura::_RemoveAura() // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases) ((Player*)caster)->SendCooldownEvent(GetSpellProto()); } - if (m_removeMode==AURA_REMOVE_BY_EXPIRE) + uint32 id = GetId(); + // Remove Linked Auras + if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_REMOVE) { - // Remove Linked Auras (on last aura remove) - uint32 id = GetId(); - if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_REMOVE) - { - if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(-(int32)id)) - for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) - if(*itr < 0) - m_target->RemoveAurasDueToSpell(-(*itr)); - else if(Unit* caster = GetCaster()) + if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(-(int32)id)) + for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) + { + if(*itr < 0) + m_target->RemoveAurasDueToSpell(-(*itr)); + else if(Unit* caster = GetCaster()) + if (m_removeMode==AURA_REMOVE_BY_EXPIRE) m_target->CastSpell(m_target, *itr, true, 0, 0, caster->GetGUID()); - } - if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA) - { - if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA)) - for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) - if(*itr < 0) - m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), false); - else - m_target->RemoveAurasDueToSpell(*itr); - } + } + } + if(spellmgr.GetSpellCustomAttr(id) & SPELL_ATTR_CU_LINK_AURA) + { + if(const std::vector<int32> *spell_triggered = spellmgr.GetSpellLinked(id + SPELL_LINK_AURA)) + for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) + { + if(*itr < 0) + m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), false); + else + m_target->RemoveAurasDueToSpell(*itr); + } } + // Proc on aura remove (only spell flags for now) if (caster) { @@ -1199,22 +1205,23 @@ void Aura::SetStackAmount(uint8 stackAmount) { Unit *target = GetTarget(); Unit *caster = GetCaster(); - if (!target || !caster) - return; - m_stackAmount = stackAmount; - for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) + if (target && caster) { - if (AuraEffect * part = GetPartAura(i)) + m_stackAmount = stackAmount; + for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) { - int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, part->GetEffIndex(), part->GetBasePoints(), target); - // Reapply if amount change - if (amount!=part->GetAmount()) + if (AuraEffect * part = GetPartAura(i)) { - bool Real = bool (part->m_spellmod); - // Auras which are applying spellmod should have removed spellmods for real - part->ApplyModifier(false,Real); - part->SetAmount(amount); - part->ApplyModifier(true, Real); + int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, part->GetEffIndex(), part->GetBasePoints(), target); + // Reapply if amount change + if (amount!=part->GetAmount()) + { + bool Real = bool (part->m_spellmod); + // Auras which are applying spellmod should have removed spellmods for real + part->ApplyModifier(false,Real); + part->SetAmount(amount); + part->ApplyModifier(true, Real); + } } } } @@ -1486,23 +1493,6 @@ void AuraEffect::HandleAddModifier(bool apply, bool Real) if (apply) { - // Add custom charges for some mod aura - switch (m_spellProto->Id) - { - case 17941: // Shadow Trance - case 22008: // Netherwind Focus - case 31834: // Light's Grace - case 34754: // Clearcasting - case 34936: // Backlash - case 48108: // Hot Streak - case 51124: // Killing Machine - case 54741: // Firestarter - case 57761: // Fireball! - case 39805: // Lightning Overload - GetParentAura()->SetAuraCharges(1); - break; - - } SpellModifier *mod = new SpellModifier; mod->op = SpellModOp(GetMiscValue()); @@ -2456,14 +2446,6 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real) caster->CastSpell(m_target, GetAmount(), true); return; } - // Focused Magic - if(m_spellProto->Id == 54646) - { - // only on remove by crit - if(caster && GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) - caster->CastSpell(caster,54648, true); - return; - } break; } } @@ -3848,8 +3830,6 @@ void AuraEffect::HandleAuraModSilence(bool apply, bool Real) if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING ) { currentSpell->cancel(); - currentSpell->SetReferencedFromCurrent(false); - m_target->m_currentSpells[i] = NULL; } } } @@ -4013,7 +3993,7 @@ void AuraEffect::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real) //Players on flying mounts must be immune to polymorph if (m_target->GetTypeId()==TYPEID_PLAYER) - m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,1<<MECHANIC_POLYMORPH,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_POLYMORPH,apply); // Dragonmaw Illusion (overwrite mount model, mounted aura already applied) if( apply && m_target->HasAuraEffect(42016,0) && m_target->GetMountID()) @@ -4058,16 +4038,57 @@ void AuraEffect::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real) /*** IMMUNITY ***/ /*********************************************************/ +void AuraEffect::HandleModStateImmunityMask(bool apply, bool Real) +{ + std::list <AuraType> immunity_list; + if (GetMiscValue() & (1<<10)) + immunity_list.push_back(SPELL_AURA_MOD_STUN); + if (GetMiscValue() & (1<<7)) + immunity_list.push_back(SPELL_AURA_MOD_DISARM); + if (GetMiscValue() & (1<<1)) + immunity_list.push_back(SPELL_AURA_MOD_TAUNT); + + // These flag can be recognized wrong: + if (GetMiscValue() & (1<<6)) + immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); + if (GetMiscValue() & (1<<0)) + immunity_list.push_back(SPELL_AURA_MOD_ROOT); + if (GetMiscValue() & (1<<3)) + immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); + if (GetMiscValue() & (1<<9)) + immunity_list.push_back(SPELL_AURA_MOD_FEAR); + + // Patch 3.0.3 Bladestorm now breaks all snares and roots on the warrior when activated. + // however not all mechanic specified in immunity + if (apply && GetId()==46924) + { + m_target->RemoveAurasByType(SPELL_AURA_MOD_ROOT); + m_target->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + } + + if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY) + { + for (std::list <AuraType>::iterator iter = immunity_list.begin(); iter != immunity_list.end();++iter) + { + m_target->RemoveAurasByType(*iter); + } + } + for (std::list <AuraType>::iterator iter = immunity_list.begin(); iter != immunity_list.end();++iter) + { + m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,*iter,apply); + } +} + void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real) { uint32 mechanic; - if (GetSpellProto()->EffectApplyAuraName[GetEffIndex()]==SPELL_AURA_MECHANIC_IMMUNITY) - mechanic = 1 << GetMiscValue(); - else //SPELL_AURA_MECHANIC_IMMUNITY_MASK - mechanic = GetMiscValue(); + mechanic = 1 << GetMiscValue(); + //immune movement impairment and loss of control if(GetId()==42292 || GetId()==59752) mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; + if (!mechanic) + return; if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY) { @@ -4091,7 +4112,7 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real) } } - m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,mechanic,apply); + m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,GetMiscValue(),apply); // Bestial Wrath if ( GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->Id == 19574) @@ -4238,18 +4259,6 @@ void AuraEffect::HandleAuraProcTriggerSpell(bool apply, bool Real) { if(!Real) return; - - if(apply) - { - // some spell have charges by functionality not have its in spell data - switch (GetId()) - { - case 28200: // Ascendance (Talisman of Ascendance trinket) - GetParentAura()->SetAuraCharges(6); - break; - default: break; - } - } } void AuraEffect::HandleAuraModStalked(bool apply, bool Real) @@ -4270,7 +4279,7 @@ void AuraEffect::HandlePeriodicTriggerSpell(bool apply, bool Real) m_isPeriodic = apply; if (m_spellProto->Id == 66 && !apply) { - if (GetParentAura()->GetRemoveMode() && GetParentAura()->GetAuraDuration()<=0) + if (GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) m_target->CastSpell(m_target, 32612, true, NULL, this); } } @@ -5650,7 +5659,7 @@ void AuraEffect::PeriodicTick() 100; if(m_target->GetHealth()*100 >= m_target->GetMaxHealth()*percent ) { - GetParentAura()->RemoveAura(); + m_target->RemoveAurasDueToSpell(GetId()); return; } break; diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 3632c7b2121..fb8120a01e6 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -92,17 +92,14 @@ class TRINITY_DLL_SPEC Aura void SetNegative() { m_positive = false; } void SetPositive() { m_positive = true; } bool IsPermanent() const { return m_permanent; } - void RemoveAura(AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT) { m_permanent = false; m_duration=0; m_removeMode = mode; } bool IsPassive() const { return m_isPassive; } bool IsDeathPersistent() const { return m_isDeathPersist; } bool IsRemovedOnShapeLost() const { return m_isRemovedOnShapeLost; } bool IsUpdated() const { return m_updated; } + bool IsRemoved() const { return m_isRemoved; } void SetUpdated(bool val) { m_updated = val; } - bool IsInUse() const { return m_in_use; } - void SetInUse(bool val) { m_in_use = val; } - bool IsPersistent() const; bool IsAreaAura() const; bool IsAuraType(AuraType type) const; @@ -158,8 +155,8 @@ class TRINITY_DLL_SPEC Aura bool m_isPassive:1; bool m_positive:1; bool m_permanent:1; + bool m_isRemoved:1; bool m_updated:1; // Prevent remove aura by stack if set - bool m_in_use:1; bool m_isSingleTargetAura:1; // true if it's a single target spell and registered at caster - can change at spell steal for example }; class TRINITY_DLL_SPEC AuraEffect @@ -270,6 +267,7 @@ class TRINITY_DLL_SPEC AuraEffect void HandleFarSight(bool Apply, bool Real); void HandleModPossessPet(bool Apply, bool Real); void HandleModMechanicImmunity(bool Apply, bool Real); + void HandleModStateImmunityMask(bool apply, bool Real); void HandleAuraModSkill(bool Apply, bool Real); void HandleModDamagePercentDone(bool Apply, bool Real); void HandleModPercentStat(bool Apply, bool Real); @@ -334,6 +332,7 @@ class TRINITY_DLL_SPEC AuraEffect uint32 GetId() const { return m_spellProto->Id; } uint32 GetEffIndex() const { return m_effIndex; } int32 GetBasePoints() const { return m_currentBasePoints; } + int32 GetAuraAmplitude(){return m_amplitude;} void Update(uint32 diff); bool IsAreaAura() const { return m_isAreaAura; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 5dac4ca1a7e..d01e992ed90 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -105,7 +105,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD - &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP + &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP @@ -202,14 +202,14 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT - &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap + &Spell::EffectJump2, //138 SPELL_EFFECT_138 Leap &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID) &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed? &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER &Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_2 Spectral Blast - &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect + &Spell::EffectPlayerPull, //145 SPELL_EFFECT_145 Black Hole Effect &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused @@ -402,7 +402,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); } // Shield Slam - else if(m_spellInfo->SpellFamilyFlags[1] & 0x200) + else if(m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category==1209) damage += int32(m_caster->GetShieldBlockValue()); // Victory Rush else if(m_spellInfo->SpellFamilyFlags[1] & 0x100) @@ -430,6 +430,13 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 12 / 100); break; } + // Concussion Blow + else if(m_spellInfo->SpellFamilyFlags[0] & 0x4000000) + { + int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget); + damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100); + break; + } break; } case SPELLFAMILY_WARLOCK: @@ -1361,7 +1368,16 @@ void Spell::EffectDummy(uint32 i) spell_id = 20647; bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); - m_caster->SetPower(POWER_RAGE,0); + // Sudden death cost modifier + if (Aura * aur = m_caster->GetAura(52437)) + { + m_caster->ModifyPower(POWER_RAGE,- m_powerCost); + if (m_caster->GetPower(POWER_RAGE)<100) + m_caster->SetPower(POWER_RAGE,100); + m_caster->RemoveAura(aur); + } + else + m_caster->SetPower(POWER_RAGE,0); break; } // Slam @@ -1648,29 +1664,31 @@ void Spell::EffectDummy(uint32 i) return; } - case 561: // Judgement of command + } + + switch(m_spellInfo->Id) + { + case 20425: // Judgement of command { if(!unitTarget) return; - uint32 spell_id = m_spellInfo->EffectBasePoints[i]+1;//m_currentBasePoints[i]+1; - SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id); + SpellEntry const* spell_proto = sSpellStore.LookupEntry(damage); if(!spell_proto) return; - if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER) + if(unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER) { - // decreased damage (/2) for non-stunned target. + // always critical for stunned target SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_DAMAGE; - mod->value = -50; - mod->type = SPELLMOD_PCT; + mod->op = SPELLMOD_CRITICAL_CHANCE; + mod->value = 100; + mod->type = SPELLMOD_FLAT; mod->spellId = m_spellInfo->Id; mod->mask[1] = 0x00000200; ((Player*)m_caster)->AddSpellMod(mod, true); m_caster->CastSpell(unitTarget,spell_proto,true,NULL); - // mod deleted ((Player*)m_caster)->AddSpellMod(mod, false); } else @@ -1678,10 +1696,6 @@ void Spell::EffectDummy(uint32 i) return; } - } - - switch(m_spellInfo->Id) - { case 31789: // Righteous Defense (step 1) { // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target) @@ -1850,7 +1864,7 @@ void Spell::EffectDummy(uint32 i) return; } // Death Coil - if(m_spellInfo->SpellFamilyFlags[0] & 0x002000) + else if(m_spellInfo->SpellFamilyFlags[0] & 0x002000) { if(m_caster->IsFriendlyTo(unitTarget)) { @@ -1867,6 +1881,12 @@ void Spell::EffectDummy(uint32 i) } return; } + // Death Grip + else if(m_spellInfo->Id == 49560) + { + unitTarget->CastSpell(m_caster, damage, true); + return; + } break; } @@ -1984,6 +2004,7 @@ void Spell::EffectTriggerSpell(uint32 i) // get highest rank of the Stealth spell uint32 spellId = 0; + SpellEntry const *spellInfo; const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap(); for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) { @@ -1991,7 +2012,7 @@ void Spell::EffectTriggerSpell(uint32 i) if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + spellInfo = sSpellStore.LookupEntry(itr->first); if (!spellInfo) continue; @@ -2010,7 +2031,8 @@ void Spell::EffectTriggerSpell(uint32 i) if(((Player*)m_caster)->HasSpellCooldown(spellId)) ((Player*)m_caster)->RemoveSpellCooldown(spellId); - m_caster->CastSpell(m_caster, spellId, true); + // Push stealth to list because it must be handled after combat remove + m_TriggerSpells.push_back(spellInfo); return; } // just skip @@ -2202,7 +2224,16 @@ void Spell::EffectJump(uint32 i) return; } - m_caster->NearTeleportTo(x,y,z,o,true); + //m_caster->NearTeleportTo(x,y,z,o,true); + float speedZ; + if(m_spellInfo->EffectMiscValue[i]) + speedZ = float(m_spellInfo->EffectMiscValue[i])/10; + else if(m_spellInfo->EffectMiscValueB[i]) + speedZ = float(m_spellInfo->EffectMiscValueB[i])/10; + else + speedZ = 10.0f; + float speedXY = m_caster->GetExactDistance2d(x, y) * 10.0f / speedZ; + m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); } void Spell::EffectTeleportUnits(uint32 i) @@ -2527,12 +2558,23 @@ void Spell::SpellDamageHeal(uint32 /*i*/) addhealth += tickheal * tickcount; // Glyph of Swiftmend - if(!caster->GetAura(54824)) + if(!caster->GetDummyAura(54824)) unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID()); //addhealth += tickheal * tickcount; //addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); } + // Riptide - increase healing done by Chain Heal + else if (m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x100) + { + if (AuraEffect * aurEff = unitTarget->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, m_originalCasterGUID)) + { + addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); + addhealth *= 1.25f; + // consume aura + unitTarget->RemoveAura(aurEff->GetParentAura()); + } + } else addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); @@ -2552,6 +2594,9 @@ void Spell::EffectHealPct( uint32 /*i*/ ) return; uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100; + if(Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this); + caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false); int32 gain = unitTarget->ModifyHealth( int32(addhealth) ); @@ -4029,14 +4074,14 @@ void Spell::SpellDamageWeaponDmg(uint32 i) { if (m_caster->GetTypeId()!=TYPEID_PLAYER) return; + SpellEntry const *spellInfo = NULL; uint32 stack = 0; - int32 maxStack = 0; + if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_MOD_RESISTANCE,SPELLFAMILY_WARRIOR,SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR, 0, 0, m_caster->GetGUID())) { aur->GetParentAura()->RefreshAura(); + spellInfo = aur->GetSpellProto(); stack = aur->GetParentAura()->GetStackAmount(); - maxStack = aur->GetSpellProto()->StackAmount; - break; } for(int j = 0; j < 3; j++) @@ -4048,7 +4093,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i) } } - if(stack < maxStack) + if(!spellInfo) { // get highest rank of the Sunder Armor spell const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap(); @@ -4058,19 +4103,22 @@ void Spell::SpellDamageWeaponDmg(uint32 i) if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo) + SpellEntry const *spellProto = sSpellStore.LookupEntry(itr->first); + if (!spellProto) continue; - if (spellInfo->SpellFamilyFlags.IsEqual(SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR) - && spellInfo->Id != m_spellInfo->Id - && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR) + if (spellProto->SpellFamilyFlags[0] & SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR + && spellProto->Id != m_spellInfo->Id + && spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR) { - m_caster->CastSpell(unitTarget, spellInfo, true); + spellInfo = spellProto; break; } } } + if (!spellInfo) + break; + m_caster->CastSpell(unitTarget, spellInfo, true); if (stack) spell_bonus += stack * CalculateDamage(2, unitTarget); } @@ -4118,6 +4166,13 @@ void Spell::SpellDamageWeaponDmg(uint32 i) spell_bonus += int32(0.23f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget)); } + + // Seal of Command Unleashed + else if(m_spellInfo->Id==20467) + { + spell_bonus += int32(0.16f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); + spell_bonus += int32(0.25f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo))); + } break; } case SPELLFAMILY_SHAMAN: @@ -4871,8 +4926,14 @@ void Spell::EffectScriptEffect(uint32 effIndex) // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. if (familyFlag[1] & 0x00000080) { + int32 tickCount = (aura->GetAuraMaxDuration() - aura->GetAuraDuration()) / aura->GetPartAura(0)->GetAuraAmplitude(); spellId = 53358; // 53358 Chimera Shot - Viper - basePoint = aura->GetPartAura(0)->GetAmount() * 4 * 60 / 100; + // Amount of one aura tick + basePoint = aura->GetPartAura(0)->GetAmount() * aura->GetTarget()->GetMaxPower(POWER_MANA) / 100 ; + int32 casterBasePoint = aura->GetPartAura(0)->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50 ; + if (basePoint > casterBasePoint) + basePoint = casterBasePoint; + basePoint = basePoint * tickCount * 60 / 100; } // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. if (familyFlag[0] & 0x00008000) @@ -4915,18 +4976,33 @@ void Spell::EffectScriptEffect(uint32 effIndex) return; } // all seals have aura dummy in 2 effect - Unit::AuraEffectList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr) - { - SpellEntry const *spellInfo = (*itr)->GetSpellProto(); - // search seal (all seals have judgement's aura dummy spell id in 2 effect - if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo)) - continue; - spellId2 = (*itr)->GetAmount(); - SpellEntry const *judge = sSpellStore.LookupEntry(spellId2); - if (!judge) - continue; - break; + Unit::AuraMap & sealAuras = m_caster->GetAuras(); + for(Unit::AuraMap::iterator iter = sealAuras.begin(); iter != sealAuras.end();) + { + if (IsSealSpell(iter->second->GetSpellProto())) + { + if (AuraEffect * aureff = iter->second->GetPartAura(2)) + if (aureff->GetAuraName()==SPELL_AURA_DUMMY) + { + if (sSpellStore.LookupEntry(aureff->GetAmount())) + spellId2 = aureff->GetAmount(); + break; + } + if (!spellId2) + { + switch (iter->first) + { + // Seal of light, wisdom, justice + case 20165: + case 20166: + case 20164: + spellId2 = 54158; + } + } + break; + } + else + ++iter; } if (spellId1) m_caster->CastSpell(unitTarget, spellId1, true); @@ -5668,6 +5744,8 @@ void Spell::EffectSummonCritter(uint32 i) critter->SetReactState(REACT_PASSIVE); critter->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + critter->GetMotionMaster()->MoveTargetedHome(); + std::string name = player->GetName(); name.append(petTypeSuffix[3]); critter->SetName( name ); @@ -5691,26 +5769,28 @@ void Spell::EffectKnockBack(uint32 i) } float speedxy = float(m_spellInfo->EffectMiscValue[i])/10; - float speedz = float(damage/-10); + float speedz = float(damage/10); - if(unitTarget->GetTypeId() == TYPEID_UNIT) - { - unitTarget->GetMotionMaster()->MoveJumpFrom(x, y, speedxy, -speedz); - return; - } - - float vcos, vsin; - unitTarget->GetSinCos(x, y, vsin, vcos); + unitTarget->KnockbackFrom(x, y, speedxy, speedz); +} - WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); - data.append(unitTarget->GetPackGUID()); - data << uint32(0); // Sequence - data << float(vcos); // x direction - data << float(vsin); // y direction - data << float(speedxy); // Horizontal speed - data << float(speedz); // Z Movement speed (vertical) +void Spell::EffectJump2(uint32 i) +{ + if(!unitTarget) + return; - ((Player*)unitTarget)->GetSession()->SendPacket(&data); + float speedxy = float(m_spellInfo->EffectMiscValue[i])/10; + float speedz = float(damage/10); + if(!speedxy) + { + if(m_targets.getUnitTarget()) + unitTarget->JumpTo(m_targets.getUnitTarget(), speedz); + } + else + { + //1891: Disengage + unitTarget->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891); + } } void Spell::EffectSendTaxi(uint32 i) @@ -5796,7 +5876,7 @@ void Spell::EffectDispelMechanic(uint32 i) Unit::AuraMap& Auras = unitTarget->GetAuras(); for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); iter++) - if(GetAllSpellMechanicMask(iter->second->GetSpellProto()) & (1<<(mechanic-1))) + if(GetAllSpellMechanicMask(iter->second->GetSpellProto()) & (1<<(mechanic))) dispel_list.push(iter->second); for(;dispel_list.size();dispel_list.pop()) @@ -5844,10 +5924,14 @@ void Spell::EffectDestroyAllTotems(uint32 /*i*/) uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); if(spellInfo) - mana += spellInfo->manaCost * damage / 100; + { + mana += spellInfo->manaCost; + mana += spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; + } ((Totem*)totem)->UnSummon(); } } + mana = mana * damage / 100; int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana)); m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA); @@ -6417,6 +6501,7 @@ void Spell::SummonVehicle(uint32 entry, SummonPropertiesEntry const *properties) if(!vehicle) return; + vehicle->SetOwnerGUID(m_caster->GetGUID()); vehicle->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); if(damage) diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index daa1b2d9add..0efc4cb0ee4 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -387,8 +387,6 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) if(spell->m_spellInfo->Id==spellId) { spell->cancel(); - spell->SetReferencedFromCurrent(false); - _player->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; } } return; diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 57b68ae55d9..f3f8907cfc4 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -39,18 +39,10 @@ SpellMgr::SpellMgr() case SPELL_EFFECT_PERSISTENT_AREA_AURA: //27 case SPELL_EFFECT_SUMMON: //28 case SPELL_EFFECT_TRIGGER_MISSILE: //32 - //case SPELL_EFFECT_SUMMON_WILD: //41 not 303 - //case SPELL_EFFECT_SUMMON_GUARDIAN: //42 not 303 case SPELL_EFFECT_TRANS_DOOR: //50 summon object case SPELL_EFFECT_SUMMON_PET: //56 case SPELL_EFFECT_ADD_FARSIGHT: //72 - //case SPELL_EFFECT_SUMMON_POSSESSED: //73 - //case SPELL_EFFECT_SUMMON_TOTEM: //74 case SPELL_EFFECT_SUMMON_OBJECT_WILD: //76 - //case SPELL_EFFECT_SUMMON_TOTEM_SLOT1: //87 - //case SPELL_EFFECT_SUMMON_TOTEM_SLOT2: //88 - //case SPELL_EFFECT_SUMMON_TOTEM_SLOT3: //89 - //case SPELL_EFFECT_SUMMON_TOTEM_SLOT4: //90 //case SPELL_EFFECT_SUMMON_CRITTER: //97 not 303 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: //104 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: //105 @@ -75,6 +67,7 @@ SpellMgr::SpellMgr() case SPELL_EFFECT_FEED_PET: case SPELL_EFFECT_PROSPECTING: case SPELL_EFFECT_MILLING: + case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC: EffectTargetType[i] = SPELL_REQUIRE_ITEM; break; //caster must be pushed otherwise no sound @@ -83,6 +76,7 @@ SpellMgr::SpellMgr() case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: case SPELL_EFFECT_APPLY_AREA_AURA_PET: case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: + case SPELL_EFFECT_JUMP2: //42 EffectTargetType[i] = SPELL_REQUIRE_CASTER; break; default: @@ -533,6 +527,8 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) case 34700: // Allergic Reaction case 31719: // Suspension return false; + case 12042: // Arcane Power + return true; } switch(spellproto->Mechanic) @@ -597,6 +593,8 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) // non-positive targets of main spell return early for(int i = 0; i < 3; ++i) { + if (!spellTriggeredProto->Effect[i]) + continue; // if non-positive trigger cast targeted to positive target this main cast is non-positive // this will place this spell auras as debuffs if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i, true)) @@ -604,7 +602,6 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) } } } - break; case SPELL_AURA_PROC_TRIGGER_SPELL: // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example) break; @@ -715,7 +712,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) return false; if (!deep && spellproto->EffectTriggerSpell[effIndex] - && !spellproto->procFlags + && !spellproto->EffectApplyAuraName[effIndex] && IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex]) && !IsPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true)) return false; @@ -1198,7 +1195,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellP // spellFamilyName is Ok need check for spellFamilyMask if present if(spellProcEvent->spellFamilyMask) { - if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0) + if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0) return false; active = true; // Spell added manualy -> so its active spell } @@ -2368,6 +2365,25 @@ void SpellMgr::LoadSpellCustomAttr() case 18662: // Curse of Doom spellInfo->EffectBasePoints[0] = 0; //prevent summon too many of them break; + case 17941: // Shadow Trance + case 22008: // Netherwind Focus + case 31834: // Light's Grace + case 34754: // Clearcasting + case 34936: // Backlash + case 48108: // Hot Streak + case 51124: // Killing Machine + case 54741: // Firestarter + case 57761: // Fireball! + case 39805: // Lightning Overload + case 52437: // Sudden Death + spellInfo->procCharges=1; + break; + case 44544: // Fingers of Frost + spellInfo->procCharges=2; + break; + case 28200: // Ascendance (Talisman of Ascendance trinket) + spellInfo->procCharges=6; + break; default: break; } diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index acf0dbc78ba..c87ad91ff90 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -176,10 +176,22 @@ void TempSummon::InitSummon(uint32 duration) if(m_type == TEMPSUMMON_MANUAL_DESPAWN) m_type = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; + Unit* owner = GetSummoner(); + if(owner) + { + if(owner->GetTypeId()==TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled) + ((Creature*)owner)->AI()->JustSummoned(this); + + if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && m_spells[0]) + { + setFaction(owner->getFaction()); + CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID); + } + } + if(!m_Properties) return; - Unit* owner = GetSummoner(); if(uint32 slot = m_Properties->Slot) { if(owner) @@ -194,18 +206,6 @@ void TempSummon::InitSummon(uint32 duration) } } - if(owner) - { - if(owner->GetTypeId()==TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled) - ((Creature*)owner)->AI()->JustSummoned(this); - - if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && m_spells[0]) - { - setFaction(owner->getFaction()); - CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID); - } - } - if(m_Properties->Faction) setFaction(m_Properties->Faction); } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index e08d4c2d43e..f41637b6c75 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -159,7 +159,6 @@ Unit::Unit() for (int i = 0; i < MAX_MOVE_TYPE; ++i) m_speed_rate[i] = 1.0f; - m_removedAuras = 0; m_charmInfo = NULL; m_unit_movement_flags = 0; m_reducedThreatPercent = 0; @@ -344,38 +343,32 @@ void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 M WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) ); data.append(GetPackGUID()); - // Point A, starting location data << GetPositionX() << GetPositionY() << GetPositionZ(); - // unknown field - unrelated to orientation - // seems to increment about 1000 for every 1.7 seconds - // for now, we'll just use mstime - data << getMSTime(); + data << uint32(getMSTime()); data << uint8(type); // unknown switch(type) { case 0: // normal packet break; - case 1: // stop packet + case 1: // stop packet (raw pos?) SendMessageToSet( &data, true ); return; - case 2: // not used currently - data << float(0); // orientation + case 2: // facing spot, not used currently + data << float(0); data << float(0); data << float(0); break; case 3: // not used currently - data << uint64(0); // probably target guid + data << uint64(0); // probably target guid (facing target?) break; case 4: // not used currently - data << float(0); // probably orientation + data << float(0); // facing angle break; } - //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim) - data << uint32((MovementFlags & MOVEMENTFLAG_LEVITATING) ? MOVEFLAG_FLY : MOVEFLAG_WALK); - - data << Time; // Time in between points + data << uint32(MovementFlags); + data << uint32(Time); // Time in between points data << uint32(1); // 1 single waypoint data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B @@ -396,16 +389,12 @@ void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end) data << GetPositionX(); data << GetPositionY(); data << GetPositionZ(); - data << getMSTime(); - data << uint8( 0 ); data << uint32(((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) || isInFlight())? (MOVEFLAG_FLY|MOVEFLAG_WALK) : MOVEFLAG_WALK); data << uint32( traveltime ); data << uint32( pathSize ); data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 ); - - //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 ); SendMessageToSet(&data, true); } @@ -472,7 +461,10 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except) ++iter; if ((aur->GetSpellProto()->AuraInterruptFlags & flag) && (!except || aur->GetId() != except)) { + uint32 removedAuras = m_removedAuras.size(); RemoveAura(aur); + if (removedAuras+1<m_removedAuras.size()) + iter=m_interruptableAuras.begin(); } } @@ -513,14 +505,17 @@ void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell) ++iter; if ((!spell || aur->GetId() != spell) && roll_chance_f(chance)) { + uint32 removedAuras = m_removedAuras.size(); RemoveAura(aur); + if (removedAuras+1<m_removedAuras.size()) + iter=m_ccAuras.begin(); } } } uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss) { - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return 0; //You don't lose health from damage taken from another player while in a sanctuary @@ -1323,7 +1318,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) if(!this || !pVictim) return; - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return; SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID); @@ -1566,7 +1561,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) if(!this || !pVictim) return; - if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) + if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return; //You don't lose health from damage taken from another player while in a sanctuary @@ -1626,7 +1621,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) // If this is a creature and it attacks from behind it has a probability to daze it's victim if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) ) + GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) + && (pVictim->GetTypeId() == TYPEID_PLAYER || !((Creature*)pVictim)->isWorldBoss())) { // -probability is between 0% and 40% // 20% base chance @@ -1659,7 +1655,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) // victim's damage shield std::set<AuraEffect*> alreadyDone; - uint32 removedAuras = pVictim->m_removedAuras; + uint32 removedAuras = pVictim->m_removedAuras.size(); AuraEffectList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); for(AuraEffectList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) { @@ -1688,9 +1684,9 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true); - if (pVictim->m_removedAuras > removedAuras) + if (pVictim->m_removedAuras.size() > removedAuras) { - removedAuras = pVictim->m_removedAuras; + removedAuras = pVictim->m_removedAuras.size(); next = vDamageShields.begin(); } } @@ -2083,7 +2079,10 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe ++i; if (auraeff->GetAmount()<=0) { - pVictim->RemoveAura(aura); + uint32 removedAuras = pVictim->m_removedAuras.size(); + pVictim->RemoveAura(aura, AURA_REMOVE_BY_ENEMY_SPELL); + if (removedAuras+1<pVictim->m_removedAuras.size()) + i=vSchoolAbsorb.begin(); } } } @@ -2118,7 +2117,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe (*i)->SetAmount((*i)->GetAmount()-currentAbsorb); if((*i)->GetAmount() <= 0) { - pVictim->RemoveAurasDueToSpell((*i)->GetId()); + pVictim->RemoveAura((*i)->GetParentAura(), AURA_REMOVE_BY_ENEMY_SPELL); next = vManaShield.begin(); } @@ -2426,7 +2425,10 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack if (tmp > 0 && roll < (sum += tmp)) { DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum); - return MELEE_HIT_CRIT; + if(GetTypeId() == TYPEID_UNIT && (((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT)) + DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT DISABLED)"); + else + return MELEE_HIT_CRIT; } // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) @@ -2832,7 +2834,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell) HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f); if (HitChance < 100) HitChance = 100; - if (HitChance > 9900) HitChance = 9900; + if (HitChance > 10000) HitChance = 10000; int32 tmp = 10000 - HitChance; @@ -3183,6 +3185,67 @@ uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) return value; } +void Unit::_DeleteAuras() +{ + for (AuraList::iterator i = m_removedAuras.begin(); i != m_removedAuras.end();i = m_removedAuras.begin()) + { + Aura * Aur = *i; + SpellEntry const* AurSpellInfo = Aur->GetSpellProto(); + // Statue unsummoned at aura delete + Totem* statue = NULL; + if(Aur->GetAuraDuration() && !Aur->IsPersistent() && IsChanneledSpell(Aur->GetSpellProto())) + { + Unit* caster = Aur->GetCaster(); + if(caster && caster->isAlive()) + { + // stop caster chanelling state + if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]) + { + // same spell + if (AurSpellInfo == caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo + //prevent recurential call + && caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) + { + if (caster==this || !IsAreaOfEffectSpell(AurSpellInfo)) + { + // remove auras only for non-aoe spells or when chanelled aura is removed + // because aoe spells don't require aura on target to continue + caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); + } + + if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE) + statue = ((Totem*)caster); + } + } + + // Unsummon summon as possessed creatures on spell cancel + if(caster->GetTypeId() == TYPEID_PLAYER) + { + for(int i = 0; i < 3; ++i) + { + if(AurSpellInfo->Effect[i] == SPELL_EFFECT_SUMMON) + if(SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(AurSpellInfo->EffectMiscValueB[i])) + if(SummonProperties->Category == SUMMON_CATEGORY_POSSESSED) + { + ((Player*)caster)->StopCastingCharm(); + break; + } + } + } + } + } + if(statue) + { + sLog.outDebug("Statue %d is unsummoned by aura %d delete from unit %d", statue->GetGUIDLow(), Aur->GetId(),GetGUIDLow()); + statue->UnSummon(); + } + + sLog.outDebug("Aura %d is deleted from unit %d", Aur->GetId(), GetGUIDLow()); + m_removedAuras.pop_front(); + delete (Aur); + } +} + void Unit::_UpdateSpells( uint32 time ) { if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) @@ -3199,7 +3262,6 @@ void Unit::_UpdateSpells( uint32 time ) } // TODO: Find a better way to prevent crash when multiple auras are removed. - m_removedAuras = 0; for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) i->second->SetUpdated(false); @@ -3208,20 +3270,20 @@ void Unit::_UpdateSpells( uint32 time ) Aura *aur = i->second; // prevent double update - if (aur->IsUpdated()) + if(aur->IsUpdated()) + { + ++i; continue; + } + aur->SetUpdated(true); - aur->SetInUse(true); + uint32 removedAuras = m_removedAuras.size(); aur->Update( time ); - aur->SetInUse(false); // several auras can be deleted due to update - if(m_removedAuras) - { - m_removedAuras = 0; + if(removedAuras < m_removedAuras.size()) i = m_Auras.begin(); - } else ++i; } @@ -3234,6 +3296,8 @@ void Unit::_UpdateSpells( uint32 time ) ++i; } + _DeleteAuras(); + if(!m_gameObj.empty()) { std::list<GameObject*>::iterator ite1, dnext1; @@ -3696,6 +3760,8 @@ bool Unit::AddAura(Aura *Aur) { if(foundAura->GetStackAmount() < aurSpellInfo->StackAmount) foundAura->SetStackAmount(foundAura->GetStackAmount()+1); + else + foundAura->RefreshAura(); delete Aur; return true; } @@ -3751,7 +3817,7 @@ bool Unit::AddAura(Aura *Aur) } if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable - || (Aur->GetSpellProto()->Mechanic==MECHANIC_KNOCKOUT && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) + || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) { m_ccAuras.push_back(Aur); } @@ -3787,7 +3853,6 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) { next = i; ++next; - if ((*i).second->IsInUse()) continue; SpellEntry const* i_spellProto = (*i).second->GetSpellProto(); @@ -3863,12 +3928,9 @@ void Unit::RemoveAura(uint32 spellId, uint64 caster ,AuraRemoveMode removeMode) void Unit::RemoveAura(Aura * aur ,AuraRemoveMode mode) { - if (aur->IsInUse()) - { - if (!aur->GetRemoveMode()) - aur->RemoveAura(mode); + // no need to remove + if (!aur || aur->IsRemoved()) return; - } for(AuraMap::iterator iter = m_Auras.lower_bound(aur->GetId()); iter != m_Auras.upper_bound(aur->GetId());) { if (aur == iter->second) @@ -3885,7 +3947,7 @@ void Unit::RemoveAurasDueToSpell(uint32 spellId, uint64 caster ,AuraRemoveMode r { for(AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);) { - if ((!caster || iter->second->GetCasterGUID()==caster) && (!iter->second->IsInUse() || !iter->second->GetRemoveMode())) + if (!caster || iter->second->GetCasterGUID()==caster) { RemoveAura(iter, removeMode); iter = m_Auras.lower_bound(spellId); @@ -3958,15 +4020,15 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit else damage[i]=NULL; } - int32 dur = 2*MINUTE*IN_MILISECONDS > aur->GetAuraDuration() ? 2*MINUTE*IN_MILISECONDS : aur->GetAuraDuration(); + int32 dur = 2*MINUTE*IN_MILISECONDS < aur->GetAuraDuration() ? 2*MINUTE*IN_MILISECONDS : aur->GetAuraDuration(); Aura * new_aur = new Aura(aur->GetSpellProto(),aur->GetEffectMask(), NULL, stealer, stealer, NULL); new_aur->SetLoadedState(aur->GetCasterGUID(), dur, dur, aur->GetAuraCharges(), aur->GetStackAmount(), &damage[0]); // Unregister _before_ adding to stealer aur->UnregisterSingleCastAura(); - // strange but intended behaviour: Stolen single target auras won't be treated as single targeted new_aur->SetIsSingleTarget(false); + stealer->AddAura(new_aur); RemoveAuraFromStack(iter, AURA_REMOVE_BY_ENEMY_SPELL); return; } @@ -3979,7 +4041,7 @@ void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId) { for (AuraMap::iterator iter = m_Auras.lower_bound(spellId); iter != m_Auras.upper_bound(spellId);) { - if ((!castItem || iter->second->GetCastItemGUID()==castItem->GetGUID()) && (!iter->second->IsInUse() || !iter->second->GetRemoveMode())) + if (!castItem || iter->second->GetCastItemGUID()==castItem->GetGUID()) { RemoveAura(iter); iter = m_Auras.upper_bound(spellId); // overwrite by more appropriate @@ -3998,7 +4060,10 @@ void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura * except ++iter; if (aur != except && (!casterGUID || aur->GetCasterGUID()==casterGUID)) { + uint32 removedAuras = m_removedAuras.size(); RemoveAura(aur); + if (removedAuras+1<m_removedAuras.size()) + iter=m_modAuras[auraType].begin(); } } } @@ -4012,7 +4077,10 @@ void Unit::RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell) ++iter; if (GetDispelChance(spell, aur->GetCaster(), aur->GetId())) { + uint32 removedAuras = m_removedAuras.size(); RemoveAura(aur, AURA_REMOVE_BY_ENEMY_SPELL); + if (removedAuras+1<m_removedAuras.size()) + iter=m_modAuras[auraType].begin(); } } } @@ -4032,35 +4100,25 @@ void Unit::RemoveNotOwnSingleTargetAuras() AuraList& scAuras = GetSingleCastAuras(); for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) { - if ((*iter)->GetTarget()!=this) + Aura * aur=*iter; + ++iter; + if (aur->GetTarget()!=this) { - Aura * aur=*iter; - ++iter; + uint32 removedAuras = m_removedAuras.size(); aur->GetTarget()->RemoveAura(aur->GetId(),aur->GetCasterGUID()); + if (removedAuras+1<m_removedAuras.size()) + iter=scAuras.begin(); } - else - ++iter; } } void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) { Aura* Aur = i->second; - //aura can be during update when removing, set it to remove at next update - if (Aur->IsInUse()) - { - if (!Aur->GetRemoveMode()) - Aur->RemoveAura(mode); - i++; - return; - } - - SpellEntry const* AurSpellInfo = Aur->GetSpellProto(); // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura // remove aura from list before to prevent deleting it before m_Auras.erase(i); - ++m_removedAuras; // internal count used by unit update Aur->UnregisterSingleCastAura(); @@ -4072,71 +4130,20 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable - || (Aur->GetSpellProto()->Mechanic==MECHANIC_KNOCKOUT && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) + || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) { m_ccAuras.remove(Aur); } - // Set remove mode if mode already not set - if (!Aur->GetRemoveMode()) - Aur->SetRemoveMode(mode); - - // Statue unsummoned at aura remove - Totem* statue = NULL; - bool channeled = false; - if(Aur->GetAuraDuration() && !Aur->IsPersistent() && IsChanneledSpell(AurSpellInfo)) - { - Unit* caster = Aur->GetCaster(); - if(caster && caster->isAlive()) - { - // stop caster chanelling state - if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]) - { - // same spell - if (AurSpellInfo == caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo - //prevent recurential call - && caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) - { - if (caster==this || !IsAreaOfEffectSpell(AurSpellInfo)) - { - // remove auras only for non-aoe spells or when chanelled aura is removed - // because aoe spells don't require aura on target to continue - { - caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); - caster->m_currentSpells[CURRENT_CHANNELED_SPELL]=NULL; - } - } - - if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE) - statue = ((Totem*)caster); - } - } - - // Unsummon summon as possessed creatures on spell cancel - if(caster->GetTypeId() == TYPEID_PLAYER) - { - for(int i = 0; i < 3; ++i) - { - if(AurSpellInfo->Effect[i] == SPELL_EFFECT_SUMMON) - if(SummonPropertiesEntry const *SummonProperties = sSummonPropertiesStore.LookupEntry(AurSpellInfo->EffectMiscValueB[i])) - if(SummonProperties->Category == SUMMON_CATEGORY_POSSESSED) - { - ((Player*)caster)->StopCastingCharm(); - break; - } - } - } - } - } + Aur->SetRemoveMode(mode); sLog.outDebug("Aura %u now is remove mode %d", Aur->GetId(), mode); Aur->HandleEffects(false); - Aur->_RemoveAura(); - delete Aur; + // set aura to be removed during unit::_updatespells + m_removedAuras.push_back(Aur); - if(statue) - statue->UnSummon(); + Aur->_RemoveAura(); // only way correctly remove all auras from list i = m_Auras.begin(); @@ -4233,6 +4240,21 @@ bool Unit::HasAura(uint32 spellId, uint64 caster) const return false; } +bool Unit::HasAura(Aura * aur) const +{ + // no need to find aura + if (!aur || aur->IsRemoved()) + return false; + for(AuraMap::const_iterator iter = m_Auras.lower_bound(aur->GetId()); iter != m_Auras.upper_bound(aur->GetId());) + { + if (aur == iter->second) + return true; + else + ++iter; + } + return false; +} + bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const { if (Aura * aur = GetAura(spellId, caster)) @@ -4745,10 +4767,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 9799: case 25988: { - // prevent damage back from weapon special attacks - if (!procSpell || procSpell->DmgClass != SPELL_DAMAGE_CLASS_MAGIC ) - return false; - // return damage % to attacker but < 50% own total health basepoints0 = triggerAmount*int32(damage)/100; if(basepoints0 > GetMaxHealth()/2) @@ -5124,7 +5142,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger for(AuraMap::iterator iter = Auras.begin(); iter != Auras.end();) { SpellEntry const *spell = iter->second->GetSpellProto(); - if( GetAllSpellMechanicMask(spell) & 1<<(MECHANIC_STUN-1)) + if( GetAllSpellMechanicMask(spell) & 1<<(MECHANIC_STUN)) { pVictim->RemoveAura(iter); } @@ -5388,7 +5406,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if (!target) return false; triggered_spell_id = 54181; - basepoints0 = damage * triggerAmount / 100; + basepoints0 = damage * 15 / 100; break; } switch(dummySpell->Id) @@ -5599,14 +5617,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Leader of the Pack case 24932: { - if (triggerAmount <= 0) + if (triggerAmount <= 0) return false; basepoints0 = triggerAmount * GetMaxHealth() / 100; target = this; triggered_spell_id = 34299; if (triggeredByAura->GetCaster() != this) break; - int32 basepoints1 = triggerAmount * 2 *GetMaxPower(POWER_MANA)/100; + int32 basepoints1 = triggerAmount * 2; CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura); break; } @@ -5818,6 +5836,34 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger basepoints0 = GetAttackTime(BASE_ATTACK) * int32(ap*0.022f + 0.044f * holy) / 1000; break; } + // Light's Beacon - Beacon of Light + if ( dummySpell->Id == 53651 ) + { + if (Unit * caster = triggeredByAura->GetCaster()) + { + // do not proc when target of beacon of light is healed + if (caster == pVictim) + return false; + if (Aura * aur = caster->GetAura(53563)) + { + if (Unit * paladin = aur->GetCaster()) + { + if (paladin != this) + return false; + basepoints0 = damage; + triggered_spell_id = 53654; + target = caster; + break; + } + else + { + pVictim->RemoveAura(triggeredByAura->GetParentAura()); + return false; + } + } + } + else return false; + } // Judgements of the Wise if (dummySpell->SpellIconID == 3017) { @@ -6595,7 +6641,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig Item* castItem = triggeredByAura->GetParentAura()->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetParentAura()->GetCastItemGUID()) : NULL; - // Try handle uncnown trigger spells + // Try handle unknown trigger spells if (sSpellStore.LookupEntry(trigger_spell_id)==NULL) { switch (auraSpellInfo->SpellFamilyName) @@ -8000,7 +8046,7 @@ void Unit::SetGuardian(Guardian* guardian, bool apply) if(AddUInt64Value(UNIT_FIELD_SUMMON, guardian->GetGUID())) { - if(GetTypeId() == TYPEID_PLAYER) + if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID()) { if(guardian->isPet()) ((Player*)this)->PetSpellInitialize(); @@ -8035,12 +8081,17 @@ void Unit::SetGuardian(Guardian* guardian, bool apply) //Check if there is another guardian for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) { + if(GetCharmGUID() == (*itr)->GetGUID()) + continue; + assert((*itr)->GetOwnerGUID() == GetGUID()); + assert((*itr)->GetTypeId() == TYPEID_UNIT); if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID())) { - if(GetTypeId() == TYPEID_PLAYER) + //show another pet bar if there is no charm bar + if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID()) { - if(guardian->isPet()) + if(((Creature*)(*itr))->isPet()) ((Player*)this)->PetSpellInitialize(); else ((Player*)this)->CharmSpellInitialize(); @@ -8665,18 +8716,28 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM if (pVictim->GetTypeId() == TYPEID_PLAYER) crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); } - // scripted (increase crit chance ... against ... target by x% AuraEffectList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { if (!((*i)->isAffectedOnSpell(spellProto))) continue; + int32 modChance=0; switch((*i)->GetMiscValue()) { - case 849: if (pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) crit_chance+= 17.0f; break; //Shatter Rank 1 - case 910: if (pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) crit_chance+= 34.0f; break; //Shatter Rank 2 - case 911: if (pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) crit_chance+= 50.0f; break; //Shatter Rank 3 + // Shatter + case 911: modChance+= 16.0f; + case 910: modChance+= 17.0f; + case 849: modChance+= 17.0f; + if (!pVictim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) + break; + crit_chance+=modChance; + // Fingers of Frost + // TODO: Change this code to less hacky + if (Aura * aur = GetAura(44544)) + if (aur->DropAuraCharge()) + RemoveAura(aur); + break; case 7917: // Glyph of Shadowburn if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this)) crit_chance+=(*i)->GetAmount(); @@ -8906,6 +8967,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint // Check for table values SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id); float coeff; + bool scripted = false; if (bonus) { if (damagetype == DOT) @@ -8915,57 +8977,74 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint if (bonus->ap_bonus) DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack; } + else // scripted bonus + { + // Gift of the Naaru + if (spellProto->Id==59547) + { + scripted = true; + uint32 apBonus = GetTotalAttackPowerValue(BASE_ATTACK); + if (apBonus > DoneAdvertisedBenefit) + { + DoneTotal+=apBonus * stack; + coeff = 0.0f; + } + else + coeff = 1.0f; + } + } + // Default calculation if (DoneAdvertisedBenefit || TakenAdvertisedBenefit) { - if(!bonus) - { - // Damage Done from spell damage bonus - int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); - // Damage over Time spells bonus calculation - float DotFactor = 1.0f; - if(damagetype == DOT) + if(!bonus && !scripted) { - int32 DotDuration = GetSpellDuration(spellProto); - // 200% limit - if(DotDuration > 0) + // Damage Done from spell damage bonus + int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); + // Damage over Time spells bonus calculation + float DotFactor = 1.0f; + if(damagetype == DOT) { - if(DotDuration > 30000) DotDuration = 30000; - if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; - int x = 0; - for(int j = 0; j < 3; j++) + int32 DotDuration = GetSpellDuration(spellProto); + // 200% limit + if(DotDuration > 0) { - if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE || - spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) + if(DotDuration > 30000) DotDuration = 30000; + if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f; + int x = 0; + for(int j = 0; j < 3; j++) { - x = j; - break; + if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && ( + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE || + spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) ) + { + x = j; + break; + } + } + int32 DotTicks = 6; + if(spellProto->EffectAmplitude[x] != 0) + DotTicks = DotDuration / spellProto->EffectAmplitude[x]; + if(DotTicks) + { + DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks; + TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks; } - } - int32 DotTicks = 6; - if(spellProto->EffectAmplitude[x] != 0) - DotTicks = DotDuration / spellProto->EffectAmplitude[x]; - if(DotTicks) - { - DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks; - TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks; } } - } - // Distribute Damage over multiple effects, reduce by AoE - CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); - // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for(int j = 0; j < 3; ++j) - { - if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || - spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) + // Distribute Damage over multiple effects, reduce by AoE + CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime ); + // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing + for(int j = 0; j < 3; ++j) { - CastingTime /= 2; - break; + if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH || + spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH ) + { + CastingTime /= 2; + break; + } } - } - coeff = (CastingTime / 3500.0f) * DotFactor; + coeff = (CastingTime / 3500.0f) * DotFactor; } float coeff2 = CalculateLevelPenalty(spellProto) * 1.88f * stack; @@ -9117,12 +9196,15 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo) return true; } - SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; - for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) + if (spellInfo->Mechanic) { - if(itr->type & (1<<spellInfo->Mechanic)) + SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; + for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) { - return true; + if(itr->type == spellInfo->Mechanic) + { + return true; + } } } @@ -9153,7 +9235,7 @@ bool Unit::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) con { SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC]; for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr) - if(itr->type & 1<<(spellInfo->EffectMechanic[index])) + if(itr->type == spellInfo->EffectMechanic[index]) return true; } @@ -9457,21 +9539,7 @@ void Unit::Mount(uint32 mount) // unsummon pet if(GetTypeId() == TYPEID_PLAYER) - { - Pet* pet = ((Player*)this)->GetPet(); - if(pet) - { - if(pet->isControlled()) - { - ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); - ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - } - - ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); - } - else - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } + ((Player*)this)->UnsummonPetTemporaryIfAny(); } void Unit::Unmount() @@ -9487,14 +9555,8 @@ void Unit::Unmount() // only resummon old pet if the player is already added to a map // this prevents adding a pet to a not created map which would otherwise cause a crash // (it could probably happen when logging in after a previous crash) - if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive()) - { - Pet* NewPet = new Pet((Player*)this); - if(!NewPet->LoadPetFromDB((Player*)this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) - delete NewPet; - - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); } void Unit::SetInCombatWith(Unit* enemy) @@ -9648,7 +9710,7 @@ bool Unit::isAttackableByAOE() const if(GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster()) return false; - return !isInFlight(); + return !hasUnitState(UNIT_STAT_UNATTACKABLE); } int32 Unit::ModifyHealth(int32 dVal) @@ -10429,7 +10491,7 @@ void Unit::ModSpellCastTime(SpellEntry const* spellProto, int32 & castTime, Spel if(Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell); - if( !(spellProto->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) ) + if( !(spellProto->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) && spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spellProto->SpellFamilyName) castTime = int32( float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED)); else { @@ -10575,6 +10637,16 @@ Unit* Unit::GetUnit(WorldObject& object, uint64 guid) return ObjectAccessor::GetUnit(object,guid); } +Player* Unit::GetPlayer(uint64 guid) +{ + return ObjectAccessor::FindPlayer(guid); +} + +Creature* Unit::GetCreature(WorldObject& object, uint64 guid) +{ + return ObjectAccessor::GetCreature(object, guid); +} + bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const { return u->canSeeOrDetect(this, false, inVisibleList, false); @@ -10995,9 +11067,22 @@ uint32 Unit::GetCreatePowers( Powers power ) const return 0; } +void Unit::AddToWorld() +{ + if(!IsInWorld()) + { + WorldObject::AddToWorld(); + m_Notified = false; + m_IsInNotifyList = false; + SetToNotify(); + } +} + void Unit::RemoveFromWorld() { // cleanup + assert(GetGUID()); + if(IsInWorld()) { UnsummonAllTotems(); @@ -11015,11 +11100,12 @@ void Unit::RemoveFromWorld() void Unit::CleanupsBeforeDelete() { - assert(m_uint32Values); + assert(GetGUID()); //A unit may be in removelist and not in world, but it is still in grid //and may have some references during delete RemoveAllAuras(); + _DeleteAuras(); InterruptNonMeleeSpells(true); m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList CombatStop(); @@ -11254,34 +11340,18 @@ bool Unit::isFrozen() const struct ProcTriggeredData { - ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, AuraEffect* _triggeredByAura) - : spellProcEvent(_spellProcEvent), triggeredByAura(_triggeredByAura) - {} - SpellProcEventEntry const *spellProcEvent; - AuraEffect* triggeredByAura; -}; -struct ProcTriggerringAura -{ - ProcTriggerringAura(uint32 _spellId, uint64 _casterGUID) : spellId(_spellId), casterGUID(_casterGUID) + ProcTriggeredData(Aura* _aura) + : aura(_aura) { - triggeringAura[0]=NULL; - triggeringAura[1]=NULL; - triggeringAura[2]=NULL; - } - ProcTriggeredData * triggeringAura[3]; - uint32 spellId; - uint64 casterGUID; - ~ProcTriggerringAura() - { - for (uint8 i = 0;i<3;++i) - if (triggeringAura[i]) - delete triggeringAura[i]; + effMask = 0; + spellProcEvent = NULL; } + SpellProcEventEntry const *spellProcEvent; + Aura * aura; + uint32 effMask; }; -//typedef std::list< ProcTriggeredData > ProcTriggeredList; -typedef std::list< ProcTriggerringAura > ProcTriggeredList; -typedef std::list< uint32> RemoveSpellList; +typedef std::list< ProcTriggeredData > ProcTriggeredList; // List of auras that CAN be trigger but may not exist in spell_proc_event // in most case need for drop charges @@ -11324,6 +11394,7 @@ bool InitTriggerAuraData() isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true; + isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true; isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true; isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true; @@ -11437,69 +11508,60 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag } } - RemoveSpellList removedSpells; ProcTriggeredList procTriggered; // Fill procTriggered list for(AuraMap::const_iterator itr = GetAuras().begin(); itr!= GetAuras().end(); ++itr) { - bool first = true; - ProcTriggeredList::iterator aurItr; + ProcTriggeredData triggerData(itr->second); + + if(!IsTriggeredAtSpellProcEvent(pTarget, triggerData.aura, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), triggerData.spellProcEvent)) + continue; + for (uint8 i=0; i<MAX_SPELL_EFFECTS;++i) { if (AuraEffect * aurEff = itr->second->GetPartAura(i)) { - SpellProcEventEntry const* spellProcEvent = NULL; - if(!IsTriggeredAtSpellProcEvent(pTarget, aurEff, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent)) + // Skip this auras + if (isNonTriggerAura[aurEff->GetAuraName()]) continue; - if (first) - { - first = false; - ProcTriggerringAura procAur(itr->second->GetId(), itr->second->GetCasterGUID()); - procTriggered.push_front(procAur); - aurItr = procTriggered.begin(); - } - aurItr->triggeringAura[i] = new ProcTriggeredData(spellProcEvent, aurEff); + // If not trigger by default and spellProcEvent==NULL - skip + if (!isTriggerAura[aurEff->GetAuraName()] && triggerData.spellProcEvent==NULL) + continue; + + triggerData.effMask |= 1<<i; } } + if (triggerData.effMask) + procTriggered.push_front(triggerData); } // Nothing found if (procTriggered.empty()) return; - Aura * parentAura = NULL; // Handle effects proceed this time for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) { - // look for parent aura in auras list, it may be removed while proc even processing - parentAura = GetAura(i->spellId, i->casterGUID); - if (!parentAura) + // look for aura in auras list, it may be removed while proc event processing + if (!HasAura(i->aura)) continue; - bool inuse = parentAura->IsInUse(); - if (!inuse) - parentAura->SetInUse(true); - - bool useCharges= parentAura->GetAuraCharges()>0; + bool useCharges= i->aura->GetAuraCharges()>0; bool takeCharges = false; + SpellEntry const *spellInfo = i->aura->GetSpellProto(); + uint32 Id=i->aura->GetId(); - for (uint8 j = 0; j<MAX_SPELL_EFFECTS;++j) - { - if (!i->triggeringAura[j]) - continue; + // For players set spell cooldown if need + uint32 cooldown = 0; + if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown) + cooldown = i->spellProcEvent->cooldown; - // possible for stacked auras from same caster, skip then - if (parentAura->GetPartAura(j)!=i->triggeringAura[j]->triggeredByAura) + for (uint8 effIndex = 0; effIndex<MAX_SPELL_EFFECTS;++effIndex) + { + if (!(i->effMask & (1<<effIndex))) continue; - SpellProcEventEntry const *spellProcEvent = i->triggeringAura[j]->spellProcEvent; - AuraEffect *triggeredByAura =triggeredByAura = i->triggeringAura[j]->triggeredByAura; - - SpellEntry const *spellInfo = triggeredByAura->GetSpellProto(); - uint32 effIndex = triggeredByAura->GetEffIndex(); - // For players set spell cooldown if need - uint32 cooldown = 0; - if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown) - cooldown = spellProcEvent->cooldown; + AuraEffect *triggeredByAura = i->aura->GetPartAura(effIndex); + assert(triggeredByAura); switch(triggeredByAura->GetAuraName()) { @@ -11611,19 +11673,11 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag } takeCharges=true; } - if (!inuse) - parentAura->SetInUse(false); - - if ( !parentAura->GetAuraDuration() && !(parentAura->IsPermanent() || (parentAura->IsPassive())) ) - RemoveAura(parentAura); - else + // Remove charge (aura can be removed by triggers) + if(useCharges && takeCharges) { - // Remove charge (aura can be removed by triggers) - if(useCharges && takeCharges) - { - if (parentAura->DropAuraCharge()) - RemoveAura(parentAura->GetId(),parentAura->GetCasterGUID()); - } + if (i->aura->DropAuraCharge()) + RemoveAura(i->aura); } } } @@ -12243,20 +12297,13 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id) return pet; } -bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, AuraEffect * aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ) +bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ) { SpellEntry const* spellProto = aura->GetSpellProto (); // Get proc Event Entry spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id); - // Skip this auras - if (isNonTriggerAura[aura->GetAuraName()]) - return false; - // If not trigger by default and spellProcEvent==NULL - skip - if (!isTriggerAura[aura->GetAuraName()] && spellProcEvent==NULL) - return false; - // Get EventProcFlag uint32 EventProcFlag; if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags @@ -12362,8 +12409,6 @@ bool Unit::HandleAuraRaidProcFromChargeWithValue( AuraEffect* triggeredByAura ) else radius = GetSpellMaxRangeForTarget(triggeredByAura->GetCaster() ,sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); - //Get max possible jumps for aura to get proper charges amount for target - if(Player* caster = ((Player*)triggeredByAura->GetCaster())) { caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); @@ -12371,7 +12416,7 @@ bool Unit::HandleAuraRaidProcFromChargeWithValue( AuraEffect* triggeredByAura ) if (Unit* target= GetNextRandomRaidMemberOrPet(radius)) { CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID()); - if (Aura * aur = GetAura(spellProto->Id, caster->GetGUID())) + if (Aura * aur = target->GetAura(spellProto->Id, caster->GetGUID())) aur->SetAuraCharges(jumps); //bonus must be applied after aura cast on target @@ -12425,19 +12470,14 @@ bool Unit::HandleAuraRaidProcFromCharge( AuraEffect* triggeredByAura ) else radius = GetSpellMaxRangeForTarget(triggeredByAura->GetCaster() ,sSpellRangeStore.LookupEntry(spellProto->rangeIndex)); - //Get max possible jumps for aura to get proper charges amount for target - int32 maxJumps = spellProto->procCharges; - if(Player* caster = ((Player*)triggeredByAura->GetCaster())) { caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); - caster->ApplySpellMod(spellProto->Id, SPELLMOD_CHARGES, maxJumps, NULL); - if (Unit* target= GetNextRandomRaidMemberOrPet(radius)) { - CastSpell(this, spellProto, true,NULL,triggeredByAura,caster_guid); - if (Aura * aur = GetAura(spellProto->Id, caster->GetGUID())) + CastSpell(target, spellProto, true,NULL,triggeredByAura,caster_guid); + if (Aura * aur = target->GetAura(spellProto->Id, caster->GetGUID())) aur->SetAuraCharges(jumps); } } @@ -12796,7 +12836,7 @@ void Unit::SetCharmedOrPossessedBy(Unit* charmer, bool possess) if(this == charmer) return; - if(isInFlight()) + if(hasUnitState(UNIT_STAT_UNATTACKABLE)) return; if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport()) @@ -13107,6 +13147,8 @@ void Unit::GetPartyMember(std::list<Unit*> &TagUnitMap, float radius) void Unit::HandleAuraEffect(AuraEffect * aureff, bool apply) { + if (aureff->GetParentAura()->IsRemoved()) + return; if (apply) { m_modAuras[aureff->GetAuraName()].push_back(aureff); @@ -13145,7 +13187,7 @@ void Unit::AddAura(uint32 spellId, Unit* target) for(uint32 i = 0; i < 3; ++i) { - if(spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) + if(spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || IsAreaAuraEffect(spellInfo->Effect[i])) { if(target->IsImmunedToSpellEffect(spellInfo, i)) continue; @@ -13174,6 +13216,8 @@ Aura * Unit::AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster) if (aur) { AuraEffect *aurEffect = CreateAuraEffect(aur, effIndex, NULL, caster); + if (!aurEffect) + return aur; if (!aur->SetPartAura(aurEffect, effIndex)) delete aurEffect; } @@ -13259,6 +13303,61 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) summon->SetPhaseMask(newPhaseMask,true); } +void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) +{ + if(GetTypeId() == TYPEID_UNIT) + { + GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ); + } + else + { + float vcos, vsin; + GetSinCos(x, y, vsin, vcos); + + WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); + data.append(GetPackGUID()); + data << uint32(0); // Sequence + data << float(vcos); // x direction + data << float(vsin); // y direction + data << float(speedXY); // Horizontal speed + data << float(-speedZ); // Z Movement speed (vertical) + + ((Player*)this)->GetSession()->SendPacket(&data); + } +} + +void Unit::JumpTo(float speedXY, float speedZ, bool forward) +{ + float angle = forward ? 0 : M_PI; + if(GetTypeId() == TYPEID_UNIT) + { + GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ); + } + else + { + float vcos = cos(angle+GetOrientation()); + float vsin = sin(angle+GetOrientation()); + + WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4)); + data.append(GetPackGUID()); + data << uint32(0); // Sequence + data << float(vcos); // x direction + data << float(vsin); // y direction + data << float(speedXY); // Horizontal speed + data << float(-speedZ); // Z Movement speed (vertical) + + ((Player*)this)->GetSession()->SendPacket(&data); + } +} + +void Unit::JumpTo(WorldObject *obj, float speedZ) +{ + float x, y, z; + obj->GetContactPoint(this, x, y, z); + float speedXY = GetExactDistance2d(x, y) * 10.0f / speedZ; + GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); +} + void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ ) { if(GetTypeId() == TYPEID_PLAYER) diff --git a/src/game/Unit.h b/src/game/Unit.h index 2ab00f23407..17e5abb10a0 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -59,9 +59,9 @@ enum SpellChannelInterruptFlags enum SpellAuraInterruptFlags { - AURA_INTERRUPT_FLAG_HITBYSPELL = 0x00000001, // 0 removed when getting hit by a negative spell? + AURA_INTERRUPT_FLAG_ANY_CAST = 0x00000001, // 0 removed by any cast AURA_INTERRUPT_FLAG_DAMAGE = 0x00000002, // 1 removed by any damage - AURA_INTERRUPT_FLAG_CC = 0x00000004, // 2 crowd control + AURA_INTERRUPT_FLAG_HITBYSPELL = 0x00000004, // 2 removed when getting hit by a negative spell? aoe damage? AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning AURA_INTERRUPT_FLAG_JUMP = 0x00000020, // 5 removed by entering combat @@ -71,8 +71,8 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing AURA_INTERRUPT_FLAG_TALK = 0x00000400, // 10 talk to npc / loot? action on creature AURA_INTERRUPT_FLAG_USE = 0x00000800, // 11 mine/use/open action on gameobject - AURA_INTERRUPT_FLAG_ATTACK = 0x00001000, // 12 removed by attacking - AURA_INTERRUPT_FLAG_CAST = 0x00002000, // 13 ??? + AURA_INTERRUPT_FLAG_ATTACK = 0x00001000, // 12 removed by attacking (negative spell cast?) + AURA_INTERRUPT_FLAG_CAST = 0x00002000, // 13 cast stealth breaking spell AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14 AURA_INTERRUPT_FLAG_TRANSFORM = 0x00008000, // 15 removed by transform? AURA_INTERRUPT_FLAG_UNK16 = 0x00010000, // 16 @@ -295,6 +295,7 @@ class Pet; class Path; class PetAura; class Guardian; +class UnitAI; struct SpellImmune { @@ -328,7 +329,6 @@ enum DamageTypeToSchool enum AuraRemoveMode { - AURA_NO_REMOVE_MODE = 0, AURA_REMOVE_BY_DEFAULT, AURA_REMOVE_BY_STACK, // change stack, single aura remove, AURA_REMOVE_BY_CANCEL, @@ -422,6 +422,8 @@ enum UnitState UNIT_STAT_POSSESSED = 0x00010000, UNIT_STAT_CHARGING = 0x00020000, UNIT_STAT_JUMPING = 0x00040000, + UNIT_STAT_ONVEHICLE = 0x00080000, + UNIT_STAT_UNATTACKABLE = (UNIT_STAT_IN_FLIGHT | UNIT_STAT_ONVEHICLE), UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE), UNIT_STAT_CONTROLLED = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING), UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONTROLLED | UNIT_STAT_JUMPING | UNIT_STAT_CHARGING), @@ -857,6 +859,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject virtual ~Unit ( ); + void AddToWorld(); void RemoveFromWorld(); void CleanupsBeforeDelete(); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) @@ -1142,6 +1145,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false); + void KnockbackFrom(float x, float y, float speedXY, float speedZ); + void JumpTo(float speedXY, float speedZ, bool forward = true); + void JumpTo(WorldObject *obj, float speedZ); + void SendMonsterStop(); void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player = NULL); void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player *player = NULL); @@ -1150,8 +1157,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); - virtual void MoveOutOfRange(Player &) { }; - bool isAlive() const { return (m_deathState == ALIVE); }; bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; DeathState getDeathState() { return m_deathState; }; @@ -1395,6 +1400,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject AuraEffect* GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0); bool HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster = 0) const; bool HasAura(uint32 spellId, uint64 caster = 0) const; + bool HasAura(Aura * aur) const; bool HasAuraType(AuraType auraType) const; bool HasAuraTypeWithMiscvalue(AuraType auratype, uint32 miscvalue) const; @@ -1491,6 +1497,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void addFollower(FollowerReference* pRef) { m_FollowingRefManager.insertFirst(pRef); } void removeFollower(FollowerReference* /*pRef*/ ) { /* nothing to do yet */ } static Unit* GetUnit(WorldObject& object, uint64 guid); + static Player* GetPlayer(uint64 guid); + static Creature* GetCreature(WorldObject& object, uint64 guid); MotionMaster* GetMotionMaster() { return &i_motionMaster; } @@ -1555,6 +1563,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject UnitAI *i_AI, *i_disabledAI; void _UpdateSpells(uint32 time); + void _DeleteAuras(); void _UpdateAutoRepeatSpell(); bool m_AutoRepeatFirstCast; @@ -1576,12 +1585,12 @@ class TRINITY_DLL_SPEC Unit : public WorldObject std::list<GameObject*> m_gameObj; bool m_isSorted; uint32 m_transform; - uint32 m_removedAuras; AuraEffectList m_modAuras[TOTAL_AURAS]; AuraList m_scAuras; // casted singlecast auras AuraList m_interruptableAuras; AuraList m_ccAuras; + AuraList m_removedAuras; uint32 m_interruptMask; float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; @@ -1609,7 +1618,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SendAttackStop(Unit* victim); // only from AttackStop(Unit*) //void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*) - bool IsTriggeredAtSpellProcEvent(Unit *pVictim, AuraEffect* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ); + bool IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ); bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleObsModEnergyAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); @@ -1642,5 +1651,20 @@ class TRINITY_DLL_SPEC Unit : public WorldObject uint32 m_reducedThreatPercent; uint64 m_misdirectionTargetGUID; }; + +namespace Trinity +{ + template<class T> + void RandomResizeList(std::list<T> &_list, uint32 _size) + { + while(_list.size() > _size) + { + typename std::list<T>::iterator itr = _list.begin(); + advance(itr, urand(0, _list.size() - 1)); + _list.erase(itr); + } + } +} + #endif diff --git a/src/game/World.cpp b/src/game/World.cpp index 9105e6a8eb8..d9a22a4a4a2 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -40,6 +40,7 @@ #include "AchievementMgr.h" #include "AuctionHouseMgr.h" #include "ObjectMgr.h" +#include "CreatureEventAIMgr.h" #include "SpellMgr.h" #include "Chat.h" #include "DBCStores.h" @@ -736,7 +737,7 @@ void World::LoadConfigSettings(bool reload) { sLog.outError("StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.", m_configs[CONFIG_START_HONOR_POINTS],m_configs[CONFIG_MAX_HONOR_POINTS],0); - m_configs[CONFIG_MAX_HONOR_POINTS] = 0; + m_configs[CONFIG_START_HONOR_POINTS] = 0; } else if(m_configs[CONFIG_START_HONOR_POINTS] > m_configs[CONFIG_MAX_HONOR_POINTS]) { @@ -1371,6 +1372,7 @@ void World::SetInitialWorldSettings() sLog.outString(); achievementmgr.LoadAchievementReferenceList(); achievementmgr.LoadAchievementCriteriaList(); + achievementmgr.LoadAchievementCriteriaData(); achievementmgr.LoadRewards(); achievementmgr.LoadRewardLocales(); achievementmgr.LoadCompletedAchievements(); @@ -1447,6 +1449,15 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls objmgr.LoadDbScriptStrings(); + sLog.outString( "Loading CreatureEventAI Texts..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Texts(); + + sLog.outString( "Loading CreatureEventAI Summons..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Summons(); + + sLog.outString( "Loading CreatureEventAI Scripts..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Scripts(); + sLog.outString( "Initializing Scripts..." ); if(!LoadScriptingModule()) exit(1); @@ -3190,14 +3201,20 @@ void World::UpdateMaxSessionCounters() void World::LoadDBVersion() { QueryResult* result = WorldDatabase.Query("SELECT db_version FROM version LIMIT 1"); + //QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version FROM db_version LIMIT 1"); if(result) { Field* fields = result->Fetch(); - m_DBVersion = fields[0].GetString(); + m_DBVersion = fields[0].GetCppString(); + //m_CreatureEventAIVersion = fields[1].GetCppString(); delete result; } - else - m_DBVersion = "unknown world database"; + + if(m_DBVersion.empty()) + m_DBVersion = "Unknown world database."; + + if(m_CreatureEventAIVersion.empty()) + m_CreatureEventAIVersion = "Unknown creature EventAI."; } diff --git a/src/game/World.h b/src/game/World.h index 2f261467a6c..27075885368 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -560,6 +560,7 @@ class World //used World DB version void LoadDBVersion(); char const* GetDBVersion() { return m_DBVersion.c_str(); } + char const* GetCreatureEventAIVersion() { return m_CreatureEventAIVersion.c_str(); } //used Script version void SetScriptsVersion(char const* version) { m_ScriptsVersion = version ? version : "unknown scripting library"; } @@ -640,6 +641,7 @@ class World //used versions std::string m_DBVersion; + std::string m_CreatureEventAIVersion; std::string m_ScriptsVersion; }; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 01bda647fa4..da6837b1662 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -240,7 +240,7 @@ bool WorldSession::Update(uint32 /*diff*/) void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout - while(_player && _player->IsBeingTeleported()) + while(_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; |
