Merge branch 'master' of https://github.com/azerothcore/azerothcore-wotlk into dir-restructure
This commit is contained in:
@@ -429,7 +429,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
|
||||
return false;
|
||||
}
|
||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area))
|
||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area))
|
||||
{
|
||||
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
|
||||
return false;
|
||||
|
||||
@@ -1731,7 +1731,7 @@ class SmartAIMgr
|
||||
|
||||
bool IsItemValid(SmartScriptHolder const& e, uint32 entry)
|
||||
{
|
||||
if (!sItemStore.LookupEntry(entry))
|
||||
if (!sObjectMgr->GetItemTemplate(entry))
|
||||
{
|
||||
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Item entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
||||
return false;
|
||||
|
||||
@@ -167,7 +167,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||
return true;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
|
||||
if (!GetAreaEntryByAreaID(area.id))
|
||||
if (!sAreaTableStore.LookupEntry(area.id))
|
||||
{
|
||||
sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.",
|
||||
criteria->ID, criteria->requiredType, dataType, area.id);
|
||||
@@ -358,12 +358,18 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un
|
||||
return false;
|
||||
return target->getGender() == gender.gender;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT:
|
||||
return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target));
|
||||
return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(target), criteria_id);
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY:
|
||||
{
|
||||
if (source->GetMap()->IsRaid())
|
||||
if (source->GetMap()->Is25ManRaid() != ((difficulty.difficulty & RAID_DIFFICULTY_MASK_25MAN) != 0))
|
||||
return false;
|
||||
return source->GetMap()->GetSpawnMode() >= difficulty.difficulty;
|
||||
|
||||
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id);
|
||||
uint8 spawnMode = source->GetMap()->GetSpawnMode();
|
||||
// Dungeons completed on heroic mode count towards both in general achievement, but not in statistics.
|
||||
return sAchievementMgr->IsStatisticCriteria(criteria) ? spawnMode == difficulty.difficulty : spawnMode >= difficulty.difficulty;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
|
||||
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
|
||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:
|
||||
@@ -1277,17 +1283,15 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
bool matchFound = false;
|
||||
for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
|
||||
{
|
||||
uint32 area_id = worldOverlayEntry->areatableID[j];
|
||||
if (!area_id) // array have 0 only in empty tail
|
||||
AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->areatableID[j]);
|
||||
if (!area)
|
||||
break;
|
||||
|
||||
int32 exploreFlag = GetAreaFlagByAreaID(area_id);
|
||||
if (exploreFlag < 0)
|
||||
uint32 playerIndexOffset = uint32(area->exploreFlag) / 32;
|
||||
if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||
continue;
|
||||
|
||||
uint32 playerIndexOffset = uint32(exploreFlag) / 32;
|
||||
uint32 mask = 1<< (uint32(exploreFlag) % 32);
|
||||
|
||||
uint32 mask = 1 << (uint32(area->exploreFlag) % 32);
|
||||
if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
|
||||
{
|
||||
matchFound = true;
|
||||
@@ -1661,8 +1665,14 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
|
||||
{
|
||||
// those requirements couldn't be found in the dbc
|
||||
AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
|
||||
if (!data || !data->Meets(GetPlayer(), NULL))
|
||||
continue;
|
||||
|
||||
// Check map id requirement
|
||||
if (miscValue1 == achievementCriteria->win_arena.mapID)
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
@@ -1678,7 +1688,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
break;
|
||||
// FIXME: not triggered in code as result, need to implement
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
|
||||
break; // Not implemented yet :(
|
||||
@@ -1876,6 +1885,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2163,9 +2173,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
|
||||
}
|
||||
}
|
||||
|
||||
// don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement
|
||||
// TODO: where do set this instead?
|
||||
if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
sAchievementMgr->SetRealmCompleted(achievement);
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, achievement->ID);
|
||||
@@ -2307,6 +2315,61 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const
|
||||
{
|
||||
return isStatisticAchievement(sAchievementStore.LookupEntry(achievementCriteria->referredAchievement));
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::isStatisticAchievement(AchievementEntry const* achievement) const
|
||||
{
|
||||
if (!achievement)
|
||||
return false;
|
||||
|
||||
AchievementCategoryEntry const* cat = sAchievementCategoryStore.LookupEntry(achievement->categoryId);
|
||||
do {
|
||||
switch(cat->ID) {
|
||||
case ACHIEVEMENT_CATEGORY_STATISTICS:
|
||||
return true;
|
||||
case ACHIEVEMENT_CATEOGRY_GENERAL:
|
||||
return false;
|
||||
default:
|
||||
cat = sAchievementCategoryStore.LookupEntry(cat->parentCategory);
|
||||
break;
|
||||
}
|
||||
} while (cat);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
auto itr = m_allCompletedAchievements.find(achievement->ID);
|
||||
if (itr == m_allCompletedAchievements.end())
|
||||
return false;
|
||||
|
||||
if (itr->second == std::chrono::system_clock::time_point::min())
|
||||
return false;
|
||||
|
||||
if (itr->second == std::chrono::system_clock::time_point::max())
|
||||
return true;
|
||||
|
||||
// Allow completing the realm first kill for entire minute after first person did it
|
||||
// it may allow more than one group to achieve it (highly unlikely)
|
||||
// but apparently this is how blizz handles it as well
|
||||
if (achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
|
||||
return (std::chrono::system_clock::now() - itr->second) > std::chrono::minutes(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AchievementGlobalMgr::SetRealmCompleted(AchievementEntry const* achievement)
|
||||
{
|
||||
if (IsRealmCompleted(achievement))
|
||||
return;
|
||||
|
||||
m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
void AchievementGlobalMgr::LoadAchievementCriteriaList()
|
||||
{
|
||||
@@ -2628,6 +2691,14 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
|
||||
|
||||
// Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer
|
||||
// while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added
|
||||
// instead the only potential race will happen on value associated with the key
|
||||
for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
|
||||
if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
|
||||
if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
m_allCompletedAchievements[achievement->ID] = std::chrono::system_clock::time_point::min();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 completed achievements. DB table `character_achievement` is empty.");
|
||||
@@ -2655,7 +2726,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
continue;
|
||||
}
|
||||
else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
|
||||
m_allCompletedAchievements.insert(achievementId);
|
||||
m_allCompletedAchievements[achievementId] = std::chrono::system_clock::time_point::max();
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include "Common.h"
|
||||
#include <ace/Singleton.h>
|
||||
@@ -55,9 +56,14 @@ enum AchievementCriteriaDataType
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc
|
||||
};
|
||||
|
||||
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum
|
||||
|
||||
enum AchievementCommonCategories
|
||||
{
|
||||
ACHIEVEMENT_CATEOGRY_GENERAL = -1,
|
||||
ACHIEVEMENT_CATEGORY_STATISTICS = 1
|
||||
};
|
||||
|
||||
class Player;
|
||||
class Unit;
|
||||
|
||||
@@ -294,6 +300,9 @@ class AchievementGlobalMgr
|
||||
~AchievementGlobalMgr() {}
|
||||
|
||||
public:
|
||||
bool IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const;
|
||||
bool isStatisticAchievement(AchievementEntry const* achievement) const;
|
||||
|
||||
AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const
|
||||
{
|
||||
return &m_AchievementCriteriasByType[type];
|
||||
@@ -348,15 +357,8 @@ class AchievementGlobalMgr
|
||||
return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
|
||||
}
|
||||
|
||||
bool IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
return m_allCompletedAchievements.find(achievement->ID) != m_allCompletedAchievements.end();
|
||||
}
|
||||
|
||||
void SetRealmCompleted(AchievementEntry const* achievement)
|
||||
{
|
||||
m_allCompletedAchievements.insert(achievement->ID);
|
||||
}
|
||||
bool IsRealmCompleted(AchievementEntry const* achievement) const;
|
||||
void SetRealmCompleted(AchievementEntry const* achievement);
|
||||
|
||||
void LoadAchievementCriteriaList();
|
||||
void LoadAchievementCriteriaData();
|
||||
@@ -375,7 +377,7 @@ class AchievementGlobalMgr
|
||||
// store achievements by referenced achievement id to speed up lookup
|
||||
AchievementListByReferencedId m_AchievementListByReferencedId;
|
||||
|
||||
typedef std::set<uint32> AllCompletedAchievements;
|
||||
typedef UNORDERED_MAP<uint32 /*achievementId*/, std::chrono::system_clock::time_point /*completionTime*/> AllCompletedAchievements;
|
||||
AllCompletedAchievements m_allCompletedAchievements;
|
||||
|
||||
AchievementRewards m_achievementRewards;
|
||||
|
||||
@@ -956,6 +956,8 @@ void Battleground::EndBattleground(TeamId winnerTeamId)
|
||||
// Arena lost => reset the win_rated_arena having the "no_lose" condition
|
||||
player->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE, 0);
|
||||
}
|
||||
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA, GetMapId());
|
||||
}
|
||||
|
||||
uint32 winner_kills = player->GetRandomWinner() ? BG_REWARD_WINNER_HONOR_LAST : BG_REWARD_WINNER_HONOR_FIRST;
|
||||
|
||||
@@ -111,8 +111,8 @@ set(game_STAT_SRCS
|
||||
include_directories(
|
||||
${game_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast
|
||||
${CMAKE_SOURCE_DIR}/deps/recastnavigation/Detour/Include
|
||||
${CMAKE_SOURCE_DIR}/deps/recastnavigation/Recast/Include
|
||||
${CMAKE_SOURCE_DIR}/deps/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/deps/SFMT
|
||||
${CMAKE_SOURCE_DIR}/deps/zlib
|
||||
|
||||
@@ -301,11 +301,11 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c
|
||||
uint32 areaId = player->GetAreaId();
|
||||
std::string areaName = "Unknown";
|
||||
std::string zoneName = "Unknown";
|
||||
if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId))
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||
{
|
||||
int locale = GetSessionDbcLocale();
|
||||
areaName = area->area_name[locale];
|
||||
if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone))
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))
|
||||
zoneName = zone->area_name[locale];
|
||||
}
|
||||
|
||||
|
||||
@@ -1658,7 +1658,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
|
||||
}
|
||||
case CONDITION_ZONEID:
|
||||
{
|
||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1);
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
|
||||
if (!areaEntry)
|
||||
{
|
||||
sLog->outErrorDb("ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1);
|
||||
|
||||
@@ -38,15 +38,14 @@ struct WMOAreaTableTripple
|
||||
|
||||
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
|
||||
|
||||
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
|
||||
DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);
|
||||
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
||||
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
|
||||
static AreaFlagByAreaID sAreaFlagByAreaID;
|
||||
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
|
||||
|
||||
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
|
||||
|
||||
DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt);
|
||||
DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore(AchievementCategoryfmt);
|
||||
DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore(AchievementCriteriafmt);
|
||||
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
|
||||
DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt);
|
||||
@@ -100,7 +99,6 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
|
||||
|
||||
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
|
||||
|
||||
DBCStorage <ItemEntry> sItemStore(Itemfmt);
|
||||
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
|
||||
//DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
|
||||
DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
|
||||
@@ -255,23 +253,10 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
StoreProblemList bad_dbc_files;
|
||||
uint32 availableDbcLocales = 0xFFFFFFFF;
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaStore, dbcPath, "AreaTable.dbc");
|
||||
|
||||
// must be after sAreaStore loading
|
||||
for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaStore.LookupEntry(i))
|
||||
{
|
||||
// fill AreaId->DBC records
|
||||
sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->exploreFlag));
|
||||
|
||||
// fill MapId->DBC records (skip sub zones and continents)
|
||||
if (area->zone == 0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571)
|
||||
sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid, area->exploreFlag));
|
||||
}
|
||||
}
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTableStore, dbcPath, "AreaTable.dbc");
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCategoryStore, dbcPath, "Achievement_Category.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaGroupStore, dbcPath, "AreaGroup.dbc");
|
||||
@@ -346,7 +331,6 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sHolidaysStore, dbcPath, "Holidays.dbc");
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc");
|
||||
//LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemCondExtCostsStore, dbcPath, "ItemCondExtCosts.dbc");
|
||||
@@ -626,10 +610,9 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
}
|
||||
|
||||
// Check loaded DBC files proper version
|
||||
if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a
|
||||
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
|
||||
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
|
||||
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
|
||||
!sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
|
||||
!sItemExtendedCostStore.LookupEntry(2997) || // last item extended cost added in 3.3.5a
|
||||
!sMapStore.LookupEntry(724) || // last map added in 3.3.5a
|
||||
!sSpellStore.LookupEntry(80864) ) // last client known item added in 3.3.5a
|
||||
@@ -678,50 +661,12 @@ uint32 GetTalentSpellCost(uint32 spellId)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id)
|
||||
{
|
||||
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
|
||||
if (i == sAreaFlagByAreaID.end())
|
||||
return -1;
|
||||
|
||||
return i->second;
|
||||
}
|
||||
|
||||
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
|
||||
{
|
||||
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
|
||||
if (i == sWMOAreaInfoByTripple.end())
|
||||
return NULL;
|
||||
return i->second;
|
||||
}
|
||||
|
||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
|
||||
{
|
||||
int32 areaflag = GetAreaFlagByAreaID(area_id);
|
||||
if (areaflag < 0)
|
||||
if (i == sWMOAreaInfoByTripple.end())
|
||||
return NULL;
|
||||
|
||||
return sAreaStore.LookupEntry(areaflag);
|
||||
}
|
||||
|
||||
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id)
|
||||
{
|
||||
if (area_flag)
|
||||
return sAreaStore.LookupEntry(area_flag);
|
||||
|
||||
if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id))
|
||||
return GetAreaEntryByAreaID(mapEntry->linked_zone);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 GetAreaFlagByMapId(uint32 mapid)
|
||||
{
|
||||
AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid);
|
||||
if (i == sAreaFlagByMapID.end())
|
||||
return 0;
|
||||
else
|
||||
return i->second;
|
||||
return i->second;
|
||||
}
|
||||
|
||||
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
|
||||
|
||||
@@ -20,11 +20,6 @@ char* GetPetName(uint32 petfamily, uint32 dbclang);
|
||||
uint32 GetTalentSpellCost(uint32 spellId);
|
||||
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
|
||||
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id);
|
||||
uint32 GetAreaFlagByMapId(uint32 mapid);
|
||||
|
||||
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid);
|
||||
|
||||
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
|
||||
@@ -58,7 +53,8 @@ uint32 GetDefaultMapLight(uint32 mapId);
|
||||
|
||||
extern DBCStorage <AchievementEntry> sAchievementStore;
|
||||
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
|
||||
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
|
||||
extern DBCStorage <AchievementCategoryEntry> sAchievementCategoryStore;
|
||||
extern DBCStorage <AreaTableEntry> sAreaTableStore;
|
||||
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
|
||||
extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
|
||||
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
|
||||
@@ -104,7 +100,6 @@ extern DBCStorage <GtOCTRegenHPEntry> sGtOCTRegenHPStore;
|
||||
extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
|
||||
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
|
||||
extern DBCStorage <HolidaysEntry> sHolidaysStore;
|
||||
extern DBCStorage <ItemEntry> sItemStore;
|
||||
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
|
||||
extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore;
|
||||
extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
|
||||
|
||||
@@ -46,7 +46,7 @@ struct AchievementEntry
|
||||
struct AchievementCategoryEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 parentCategory; // 1 -1 for main category
|
||||
int32 parentCategory; // 1 -1 for main category
|
||||
//char *name[16]; // 2-17
|
||||
//uint32 name_flags; // 18
|
||||
//uint32 sortOrder; // 19
|
||||
@@ -1092,18 +1092,6 @@ struct HolidaysEntry
|
||||
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
|
||||
};
|
||||
|
||||
struct ItemEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 Class; // 1
|
||||
uint32 SubClass; // 2 some items have strange subclasses
|
||||
int32 SoundOverrideSubclass; // 3
|
||||
int32 Material; // 4
|
||||
uint32 DisplayId; // 5
|
||||
uint32 InventoryType; // 6
|
||||
uint32 Sheath; // 7
|
||||
};
|
||||
|
||||
struct ItemBagFamilyEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
||||
const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
|
||||
const std::string CustomAchievementIndex = "ID";
|
||||
char const AchievementCategoryfmt[] = "nixxxxxxxxxxxxxxxxxx";
|
||||
char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix";
|
||||
char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx";
|
||||
char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx";
|
||||
char const AreaGroupEntryfmt[] = "niiiiiii";
|
||||
char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
|
||||
char const AreaTriggerEntryfmt[] = "niffffffff";
|
||||
@@ -57,7 +58,6 @@ char const GtOCTRegenHPfmt[] = "f";
|
||||
char const GtRegenHPPerSptfmt[] = "f";
|
||||
char const GtRegenMPPerSptfmt[] = "f";
|
||||
char const Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
|
||||
char const Itemfmt[] = "niiiiiii";
|
||||
char const ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx";
|
||||
char const ItemDisplayTemplateEntryfmt[] = "nxxxxsxxxxxxxxxxxxxxxxxxx";
|
||||
//char const ItemCondExtCostsEntryfmt[] = "xiii";
|
||||
|
||||
@@ -353,7 +353,7 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
|
||||
|
||||
// Load creature equipment
|
||||
if (!data || data->equipmentId == 0) // use default from the template
|
||||
LoadEquipment(GetCreatureData() ? GetOriginalEquipmentId() : 1);
|
||||
LoadEquipment();
|
||||
else if (data && data->equipmentId != 0) // override, 0 means no equipment
|
||||
{
|
||||
m_originalEquipmentId = data->equipmentId;
|
||||
|
||||
@@ -1095,9 +1095,13 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
|
||||
if (!IsInMap(obj))
|
||||
return false;
|
||||
|
||||
float ox, oy, oz;
|
||||
obj->GetPosition(ox, oy, oz);
|
||||
return IsWithinLOS(ox, oy, oz);
|
||||
float x, y, z;
|
||||
if (obj->GetTypeId() == TYPEID_PLAYER)
|
||||
obj->GetPosition(x, y, z);
|
||||
else
|
||||
obj->GetHitSpherePointFor(GetPosition(), x, y, z);
|
||||
|
||||
return IsWithinLOS(x, y, z);
|
||||
}
|
||||
|
||||
bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
|
||||
@@ -1107,11 +1111,36 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
|
||||
VMAP::IVMapManager* vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);*/
|
||||
if (IsInWorld())
|
||||
return GetMap()->isInLineOfSight(GetPositionX(), GetPositionY(), GetPositionZ()+2.f, ox, oy, oz+2.f, GetPhaseMask());
|
||||
{
|
||||
float x, y, z;
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
GetPosition(x, y, z);
|
||||
else
|
||||
GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
|
||||
|
||||
return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhaseMask());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Position WorldObject::GetHitSpherePointFor(Position const& dest) const
|
||||
{
|
||||
G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetObjectSize());
|
||||
|
||||
return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
|
||||
}
|
||||
|
||||
void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const
|
||||
{
|
||||
Position pos = GetHitSpherePointFor(dest);
|
||||
x = pos.GetPositionX();
|
||||
y = pos.GetPositionY();
|
||||
z = pos.GetPositionZ();
|
||||
}
|
||||
|
||||
bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
|
||||
{
|
||||
float dx1 = GetPositionX() - obj1->GetPositionX();
|
||||
@@ -2402,123 +2431,33 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y,
|
||||
else
|
||||
UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
/*
|
||||
// if detection disabled, return first point
|
||||
if (!sWorld->getIntConfig(CONFIG_DETECT_POS_COLLISION))
|
||||
{
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
|
||||
return;
|
||||
}
|
||||
|
||||
// or remember first point
|
||||
// return if the point is already in LoS
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
|
||||
// remember first point
|
||||
float first_x = x;
|
||||
float first_y = y;
|
||||
bool first_los_conflict = false; // first point LOS problems
|
||||
float first_z = z;
|
||||
|
||||
// prepare selector for work
|
||||
ObjectPosSelector selector(GetPositionX(), GetPositionY(), GetObjectSize(), distance2d+searcher_size);
|
||||
|
||||
// adding used positions around object
|
||||
// loop in a circle to look for a point in LoS using small steps
|
||||
for (float angle = float(M_PI) / 8; angle < float(M_PI) * 2; angle += float(M_PI) / 8)
|
||||
{
|
||||
CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.SetNoCreate();
|
||||
|
||||
Trinity::NearUsedPosDo u_do(*this, searcher, absAngle, selector);
|
||||
Trinity::WorldObjectWorker<Trinity::NearUsedPosDo> worker(this, u_do);
|
||||
|
||||
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
|
||||
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
|
||||
|
||||
CellLock<GridReadGuard> cell_lock(cell, p);
|
||||
cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap(), *this, distance2d);
|
||||
cell_lock->Visit(cell_lock, world_obj_worker, *GetMap(), *this, distance2d);
|
||||
}
|
||||
|
||||
// maybe can just place in primary position
|
||||
if (selector.CheckOriginal())
|
||||
{
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
|
||||
first_los_conflict = true; // first point have LOS problems
|
||||
}
|
||||
|
||||
float angle; // candidate of angle for free pos
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if (selector.FirstAngle(angle))
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
GetNearPoint2D(x, y, distance2d + searcher_size, absAngle + angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
UpdateAllowedPositionZ(x, y, z);
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while (selector.NextAngle(angle)) // angle for free pos
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD NEWS: not free pos (or used or have LOS problems)
|
||||
// Attempt find _used_ pos without LOS problem
|
||||
|
||||
if (!first_los_conflict)
|
||||
{
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
return;
|
||||
}
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if (selector.IsNonBalanced())
|
||||
{
|
||||
if (!selector.FirstAngle(angle)) // _used_ pos
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD BAD NEWS: all found pos (free and used) have LOS problem :(
|
||||
// still not in LoS, give up and return first position found
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
*/
|
||||
z = first_z;
|
||||
}
|
||||
|
||||
bool WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d, float angle, const WorldObject* forWho, bool force) const
|
||||
|
||||
@@ -365,6 +365,17 @@ class Object
|
||||
|
||||
struct Position
|
||||
{
|
||||
Position(float x = 0, float y = 0, float z = 0, float o = 0)
|
||||
: m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
|
||||
|
||||
Position(Position const& loc) { Relocate(loc); }
|
||||
|
||||
struct PositionXYStreamer
|
||||
{
|
||||
explicit PositionXYStreamer(Position& pos) : Pos(&pos) { }
|
||||
Position* Pos;
|
||||
};
|
||||
|
||||
struct PositionXYZStreamer
|
||||
{
|
||||
explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) {}
|
||||
@@ -382,19 +393,38 @@ struct Position
|
||||
float m_positionZ;
|
||||
float m_orientation;
|
||||
|
||||
bool operator==(Position const &a);
|
||||
|
||||
inline bool operator!=(Position const &a)
|
||||
{
|
||||
return !(operator==(a));
|
||||
}
|
||||
|
||||
void Relocate(float x, float y)
|
||||
{ m_positionX = x; m_positionY = y;}
|
||||
{
|
||||
m_positionX = x; m_positionY = y;
|
||||
}
|
||||
void Relocate(float x, float y, float z)
|
||||
{ m_positionX = x; m_positionY = y; m_positionZ = z; }
|
||||
{
|
||||
m_positionX = x; m_positionY = y; m_positionZ = z;
|
||||
}
|
||||
void Relocate(float x, float y, float z, float orientation)
|
||||
{ m_positionX = x; m_positionY = y; m_positionZ = z; m_orientation = orientation; }
|
||||
{
|
||||
m_positionX = x; m_positionY = y; m_positionZ = z; m_orientation = orientation;
|
||||
}
|
||||
void Relocate(const Position &pos)
|
||||
{ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; m_orientation = pos.m_orientation; }
|
||||
{
|
||||
m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; m_orientation = pos.m_orientation;
|
||||
}
|
||||
void Relocate(const Position* pos)
|
||||
{ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; m_orientation = pos->m_orientation; }
|
||||
{
|
||||
m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; m_orientation = pos->m_orientation;
|
||||
}
|
||||
void RelocateOffset(const Position &offset);
|
||||
void SetOrientation(float orientation)
|
||||
{ m_orientation = orientation; }
|
||||
{
|
||||
m_orientation = orientation;
|
||||
}
|
||||
|
||||
float GetPositionX() const { return m_positionX; }
|
||||
float GetPositionY() const { return m_positionY; }
|
||||
@@ -402,17 +432,26 @@ struct Position
|
||||
float GetOrientation() const { return m_orientation; }
|
||||
|
||||
void GetPosition(float &x, float &y) const
|
||||
{ x = m_positionX; y = m_positionY; }
|
||||
{
|
||||
x = m_positionX; y = m_positionY;
|
||||
}
|
||||
void GetPosition(float &x, float &y, float &z) const
|
||||
{ x = m_positionX; y = m_positionY; z = m_positionZ; }
|
||||
{
|
||||
x = m_positionX; y = m_positionY; z = m_positionZ;
|
||||
}
|
||||
void GetPosition(float &x, float &y, float &z, float &o) const
|
||||
{ x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; }
|
||||
{
|
||||
x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation;
|
||||
}
|
||||
void GetPosition(Position* pos) const
|
||||
{
|
||||
if (pos)
|
||||
pos->Relocate(m_positionX, m_positionY, m_positionZ, m_orientation);
|
||||
}
|
||||
|
||||
Position GetPosition() const { return *this; }
|
||||
|
||||
|
||||
Position::PositionXYZStreamer PositionXYZStream()
|
||||
{
|
||||
return PositionXYZStreamer(*this);
|
||||
@@ -425,39 +464,65 @@ struct Position
|
||||
bool IsPositionValid() const;
|
||||
|
||||
float GetExactDist2dSq(float x, float y) const
|
||||
{ float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; }
|
||||
{
|
||||
float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy;
|
||||
}
|
||||
float GetExactDist2d(const float x, const float y) const
|
||||
{ return sqrt(GetExactDist2dSq(x, y)); }
|
||||
{
|
||||
return sqrt(GetExactDist2dSq(x, y));
|
||||
}
|
||||
float GetExactDist2dSq(const Position* pos) const
|
||||
{ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
|
||||
{
|
||||
float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy;
|
||||
}
|
||||
float GetExactDist2d(const Position* pos) const
|
||||
{ return sqrt(GetExactDist2dSq(pos)); }
|
||||
{
|
||||
return sqrt(GetExactDist2dSq(pos));
|
||||
}
|
||||
float GetExactDistSq(float x, float y, float z) const
|
||||
{ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
|
||||
{
|
||||
float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz;
|
||||
}
|
||||
float GetExactDist(float x, float y, float z) const
|
||||
{ return sqrt(GetExactDistSq(x, y, z)); }
|
||||
{
|
||||
return sqrt(GetExactDistSq(x, y, z));
|
||||
}
|
||||
float GetExactDistSq(const Position* pos) const
|
||||
{ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; }
|
||||
{
|
||||
float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
float GetExactDist(const Position* pos) const
|
||||
{ return sqrt(GetExactDistSq(pos)); }
|
||||
{
|
||||
return sqrt(GetExactDistSq(pos));
|
||||
}
|
||||
|
||||
void GetPositionOffsetTo(const Position & endPos, Position & retOffset) const;
|
||||
|
||||
float GetAngle(const Position* pos) const;
|
||||
float GetAngle(float x, float y) const;
|
||||
float GetRelativeAngle(const Position* pos) const
|
||||
{ return GetAngle(pos) - m_orientation; }
|
||||
{
|
||||
return GetAngle(pos) - m_orientation;
|
||||
}
|
||||
float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
|
||||
void GetSinCos(float x, float y, float &vsin, float &vcos) const;
|
||||
|
||||
bool IsInDist2d(float x, float y, float dist) const
|
||||
{ return GetExactDist2dSq(x, y) < dist * dist; }
|
||||
{
|
||||
return GetExactDist2dSq(x, y) < dist * dist;
|
||||
}
|
||||
bool IsInDist2d(const Position* pos, float dist) const
|
||||
{ return GetExactDist2dSq(pos) < dist * dist; }
|
||||
{
|
||||
return GetExactDist2dSq(pos) < dist * dist;
|
||||
}
|
||||
bool IsInDist(float x, float y, float z, float dist) const
|
||||
{ return GetExactDistSq(x, y, z) < dist * dist; }
|
||||
{
|
||||
return GetExactDistSq(x, y, z) < dist * dist;
|
||||
}
|
||||
bool IsInDist(const Position* pos, float dist) const
|
||||
{ return GetExactDistSq(pos) < dist * dist; }
|
||||
{
|
||||
return GetExactDistSq(pos) < dist * dist;
|
||||
}
|
||||
|
||||
bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const;
|
||||
bool HasInArc(float arcangle, const Position* pos, float targetRadius = 0.0f) const;
|
||||
@@ -479,10 +544,13 @@ struct Position
|
||||
return fmod(o, 2.0f * static_cast<float>(M_PI));
|
||||
}
|
||||
};
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
|
||||
ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
|
||||
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
|
||||
ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
|
||||
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
|
||||
ByteBuffer& operator >> (ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
|
||||
|
||||
|
||||
struct MovementInfo
|
||||
{
|
||||
@@ -785,6 +853,8 @@ class WorldObject : public Object, public WorldLocation
|
||||
}
|
||||
bool IsWithinLOS(float x, float y, float z) const;
|
||||
bool IsWithinLOSInMap(const WorldObject* obj) const;
|
||||
Position GetHitSpherePointFor(Position const& dest) const;
|
||||
void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const;
|
||||
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
|
||||
bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
|
||||
bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
|
||||
|
||||
@@ -960,6 +960,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetCreateHealth(4 * petlevel);
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - 30 - (petlevel / 4) + m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel - 30 + (petlevel / 4) + m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f));
|
||||
SetReactState(REACT_DEFENSIVE);
|
||||
break;
|
||||
}
|
||||
case NPC_ARMY_OF_THE_DEAD:
|
||||
|
||||
@@ -2189,8 +2189,8 @@ void Player::SendTeleportAckPacket()
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options)
|
||||
{
|
||||
bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options /*= 0*/, Unit *target /*= nullptr*/)
|
||||
{
|
||||
if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
|
||||
{
|
||||
sLog->outError("TeleportTo: invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player (GUID: %u, name: %s, map: %d, X: %f, Y: %f, Z: %f, O: %f).",
|
||||
@@ -2288,6 +2288,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
if (duel && GetMapId() != mapid && GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER)))
|
||||
DuelComplete(DUEL_FLED);
|
||||
|
||||
if (!sScriptMgr->OnBeforePlayerTeleport(this, mapid, x, y, z, orientation, options, target))
|
||||
return false;
|
||||
|
||||
if (GetMapId() == mapid)
|
||||
{
|
||||
//lets reset far teleport flag if it wasn't reset during chained teleports
|
||||
@@ -3026,11 +3029,7 @@ void Player::SetGameMaster(bool on)
|
||||
else
|
||||
{
|
||||
// restore phase
|
||||
uint32 newPhase = 0;
|
||||
AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
|
||||
if (!phases.empty())
|
||||
for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
|
||||
newPhase |= (*itr)->GetMiscValue();
|
||||
uint32 newPhase = GetPhaseByAuras();
|
||||
|
||||
if (!newPhase)
|
||||
newPhase = PHASEMASK_NORMAL;
|
||||
@@ -3063,14 +3062,21 @@ void Player::SetGameMaster(bool on)
|
||||
}
|
||||
|
||||
void Player::SetGMVisible(bool on)
|
||||
{
|
||||
{
|
||||
const uint32 VISUAL_AURA = 37800;
|
||||
|
||||
if (on)
|
||||
{
|
||||
if (HasAura(VISUAL_AURA, 0))
|
||||
RemoveAurasDueToSpell(VISUAL_AURA);
|
||||
|
||||
m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag
|
||||
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddAura(VISUAL_AURA, this);
|
||||
|
||||
m_ExtraFlags |= PLAYER_EXTRA_GM_INVISIBLE; //add flag
|
||||
|
||||
SetAcceptWhispers(false);
|
||||
@@ -5286,7 +5292,7 @@ void Player::CreateCorpse()
|
||||
return;
|
||||
}
|
||||
|
||||
_uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
|
||||
_uf = getRace();
|
||||
_pb = GetUInt32Value(PLAYER_BYTES);
|
||||
_pb2 = GetUInt32Value(PLAYER_BYTES_2);
|
||||
|
||||
@@ -5577,11 +5583,11 @@ void Player::RepopAtGraveyard()
|
||||
// note: this can be called also when the player is alive
|
||||
// for example from WorldSession::HandleMovementOpcodes
|
||||
|
||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId());
|
||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
|
||||
|
||||
// Such zones are considered unreachable as a ghost and the player must be automatically revived
|
||||
// Xinef: Get Transport Check is not needed
|
||||
if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < -500.0f)
|
||||
if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
|
||||
{
|
||||
ResurrectPlayer(0.5f);
|
||||
SpawnCorpseBones();
|
||||
@@ -5618,8 +5624,10 @@ void Player::RepopAtGraveyard()
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
else if (GetPositionZ() < -500.0f)
|
||||
else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
|
||||
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
||||
|
||||
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||
}
|
||||
|
||||
bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone)
|
||||
@@ -5671,7 +5679,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
|
||||
if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
|
||||
return; // The client handles it automatically after loading, but not after teleporting
|
||||
|
||||
AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone);
|
||||
AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone);
|
||||
if (!current_zone)
|
||||
return;
|
||||
|
||||
@@ -6894,45 +6902,46 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
return;
|
||||
|
||||
bool isOutdoor = IsOutdoors();
|
||||
uint32 areaFlag = GetAreaFlagByAreaID(GetAreaId());
|
||||
|
||||
uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||
RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
|
||||
|
||||
if (areaFlag == 0xffff)
|
||||
if (!areaId)
|
||||
return;
|
||||
int offset = areaFlag / 32;
|
||||
|
||||
if (!areaEntry)
|
||||
{
|
||||
sLog->outError("Player '%s' (%u) discovered unknown area (x: %f y: %f z: %f map: %u)",
|
||||
GetName().c_str(), GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 offset = areaEntry->exploreFlag / 32;
|
||||
|
||||
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
|
||||
sLog->outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaEntry->flags, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 val = (uint32)(1 << (areaFlag % 32));
|
||||
uint32 val = (uint32)(1 << (areaEntry->exploreFlag % 32));
|
||||
uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
||||
|
||||
if (!(currFields & val))
|
||||
{
|
||||
SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, GetAreaId());
|
||||
|
||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId());
|
||||
if (!areaEntry)
|
||||
{
|
||||
sLog->outError("Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
|
||||
return;
|
||||
}
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, areaId);
|
||||
|
||||
if (areaEntry->area_level > 0)
|
||||
{
|
||||
uint32 area = areaEntry->ID;
|
||||
if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
SendExplorationExperience(area, 0);
|
||||
SendExplorationExperience(areaId, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6958,10 +6967,10 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
}
|
||||
|
||||
GiveXP(XP, NULL);
|
||||
SendExplorationExperience(area, XP);
|
||||
SendExplorationExperience(areaId, XP);
|
||||
}
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), area);
|
||||
sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), areaId);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -7528,12 +7537,14 @@ void Player::UpdateArea(uint32 newArea)
|
||||
// pussywizard: inform instance, needed for Icecrown Citadel
|
||||
if (InstanceScript* instance = GetInstanceScript())
|
||||
instance->OnPlayerAreaUpdate(this, m_areaUpdateId, newArea);
|
||||
|
||||
sScriptMgr->OnPlayerUpdateArea(this, m_areaUpdateId, newArea);
|
||||
|
||||
// FFA_PVP flags are area and not zone id dependent
|
||||
// so apply them accordingly
|
||||
m_areaUpdateId = newArea;
|
||||
|
||||
AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
|
||||
AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);
|
||||
bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
|
||||
pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
|
||||
UpdatePvPState(true);
|
||||
@@ -7568,7 +7579,7 @@ void Player::UpdateArea(uint32 newArea)
|
||||
}
|
||||
|
||||
// Xinef: area should inherit zone flags
|
||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone);
|
||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);
|
||||
uint32 areaFlags = area->flags;
|
||||
bool isSanctuary = area->IsSanctuary();
|
||||
bool isInn = area->IsInn(GetTeamId(true));
|
||||
@@ -7656,7 +7667,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
// zone changed, so area changed as well, update it
|
||||
UpdateArea(newArea);
|
||||
|
||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone);
|
||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone);
|
||||
if (!zone)
|
||||
return;
|
||||
|
||||
@@ -9258,6 +9269,12 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
|
||||
permission = OWNER_PERMISSION;
|
||||
|
||||
//Inform instance if creature is skinned.
|
||||
if (InstanceScript* mapInstance = creature->GetInstanceScript())
|
||||
{
|
||||
mapInstance->CreatureLooted(creature, LOOT_SKINNING);
|
||||
}
|
||||
|
||||
// Xinef: Set new loot recipient
|
||||
creature->SetLootRecipient(this, false);
|
||||
}
|
||||
@@ -20736,7 +20753,7 @@ void Player::Say(const std::string& text, const uint32 language)
|
||||
sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, Language(language), this, this, text);
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, Language(language), this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true);
|
||||
}
|
||||
|
||||
@@ -20746,7 +20763,7 @@ void Player::Yell(const std::string& text, const uint32 language)
|
||||
sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, Language(language), this, this, text);
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, Language(language), this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true);
|
||||
}
|
||||
|
||||
@@ -20756,7 +20773,7 @@ void Player::TextEmote(const std::string& text)
|
||||
sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, text);
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT));
|
||||
}
|
||||
|
||||
@@ -20773,14 +20790,14 @@ void Player::Whisper(const std::string& text, uint32 language, uint64 receiver)
|
||||
sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, rPlayer);
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, Language(language), this, this, text);
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, Language(language), this, this, _text);
|
||||
rPlayer->GetSession()->SendPacket(&data);
|
||||
|
||||
// rest stuff shouldn't happen in case of addon message
|
||||
if (isAddonMessage)
|
||||
return;
|
||||
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, Language(language), rPlayer, rPlayer, text);
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, Language(language), rPlayer, rPlayer, _text);
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
if (!isAcceptWhispers() && !IsGameMaster() && !rPlayer->IsGameMaster())
|
||||
@@ -22658,19 +22675,30 @@ bool Player::IsVisibleGloballyFor(Player const* u) const
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void UpdateVisibilityOf_helper(T* /*target*/, std::vector<Unit*>& /*v*/)
|
||||
inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, T* target, std::vector<Unit*>& /*v*/)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void UpdateVisibilityOf_helper(Creature* target, std::vector<Unit*>& v)
|
||||
inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, GameObject* target, std::vector<Unit*>& /*v*/)
|
||||
{
|
||||
// @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
|
||||
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
|
||||
s64.insert(target->GetGUID());
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, Creature* target, std::vector<Unit*>& v)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
v.push_back(target);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void UpdateVisibilityOf_helper(Player* target, std::vector<Unit*>& v)
|
||||
inline void UpdateVisibilityOf_helper(Player::ClientGUIDs& s64, Player* target, std::vector<Unit*>& v)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
v.push_back(target);
|
||||
}
|
||||
|
||||
@@ -22784,9 +22812,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::vector<Unit*>&
|
||||
if (CanSeeOrDetect(target, false, true))
|
||||
{
|
||||
target->BuildCreateUpdateBlockForPlayer(&data, this);
|
||||
m_clientGUIDs.insert(target->GetGUID());
|
||||
|
||||
UpdateVisibilityOf_helper(target, visibleNow);
|
||||
UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23610,8 +23636,8 @@ void Player::UpdateForQuestWorldObjects()
|
||||
GetSession()->SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Player::SummonIfPossible(bool agree)
|
||||
{
|
||||
void Player::SummonIfPossible(bool agree, uint32 summoner_guid)
|
||||
{
|
||||
if (!agree)
|
||||
{
|
||||
m_summon_expire = 0;
|
||||
@@ -23631,7 +23657,7 @@ void Player::SummonIfPossible(bool agree)
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1);
|
||||
|
||||
TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z, GetOrientation());
|
||||
TeleportTo(m_summon_mapid, m_summon_x, m_summon_y, m_summon_z, GetOrientation(), 0, ObjectAccessor::FindPlayer(summoner_guid));
|
||||
}
|
||||
|
||||
void Player::RemoveItemDurations(Item* item)
|
||||
@@ -25226,22 +25252,19 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
}
|
||||
|
||||
uint32 Player::GetPhaseMaskForSpawn() const
|
||||
{
|
||||
uint32 phase = PHASEMASK_NORMAL;
|
||||
if (!IsGameMaster())
|
||||
phase = GetPhaseMask();
|
||||
else
|
||||
{
|
||||
AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
|
||||
if (!phases.empty())
|
||||
phase = phases.front()->GetMiscValue();
|
||||
}
|
||||
{
|
||||
uint32 phase = IsGameMaster() ? GetPhaseByAuras() : GetPhaseMask();
|
||||
|
||||
if (!phase)
|
||||
phase = PHASEMASK_NORMAL;
|
||||
|
||||
|
||||
// some aura phases include 1 normal map in addition to phase itself
|
||||
if (uint32 n_phase = phase & ~PHASEMASK_NORMAL)
|
||||
uint32 n_phase = phase & ~PHASEMASK_NORMAL;
|
||||
if (n_phase > 0)
|
||||
return n_phase;
|
||||
|
||||
return PHASEMASK_NORMAL;
|
||||
return phase;
|
||||
}
|
||||
|
||||
InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const
|
||||
|
||||
@@ -1096,10 +1096,10 @@ class Player : public Unit, public GridObject<Player>
|
||||
SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH);
|
||||
}
|
||||
|
||||
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0);
|
||||
bool TeleportTo(WorldLocation const &loc, uint32 options = 0)
|
||||
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0, Unit *target = nullptr);
|
||||
bool TeleportTo(WorldLocation const &loc, uint32 options = 0, Unit *target = nullptr)
|
||||
{
|
||||
return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options);
|
||||
return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options, target);
|
||||
}
|
||||
bool TeleportToEntryPoint();
|
||||
|
||||
@@ -1114,7 +1114,7 @@ class Player : public Unit, public GridObject<Player>
|
||||
}
|
||||
bool IsSummonAsSpectator() const { return m_summon_asSpectator && m_summon_expire >= time(NULL); }
|
||||
void SetSummonAsSpectator(bool on) { m_summon_asSpectator = on; }
|
||||
void SummonIfPossible(bool agree);
|
||||
void SummonIfPossible(bool agree, uint32 summoner_guid);
|
||||
time_t GetSummonExpireTimer() const { return m_summon_expire; }
|
||||
|
||||
bool Create(uint32 guidlow, CharacterCreateInfo* createInfo);
|
||||
|
||||
@@ -3395,6 +3395,15 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Unit::CanMoveDuringChannel() const
|
||||
{
|
||||
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
|
||||
if (spell->getState() != SPELL_STATE_FINISHED)
|
||||
return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
|
||||
{
|
||||
return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
|
||||
@@ -13690,7 +13699,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
|
||||
if (!spellInfo || castTime < 0)
|
||||
return;
|
||||
|
||||
if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION))
|
||||
if (spellInfo->IsChanneled() && spellInfo->HasAura(SPELL_AURA_MOUNTED))
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
@@ -14493,7 +14502,7 @@ void CharmInfo::InitPossessCreateSpells()
|
||||
{
|
||||
uint32 spellId = _unit->ToCreature()->m_spells[i];
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
|
||||
if (spellInfo)
|
||||
{
|
||||
if (spellInfo->IsPassive())
|
||||
_unit->CastSpell(_unit, spellInfo, true);
|
||||
@@ -14523,7 +14532,7 @@ void CharmInfo::InitCharmCreateSpells()
|
||||
uint32 spellId = _unit->ToCreature()->m_spells[x];
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
|
||||
if (!spellInfo || spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
|
||||
if (!spellInfo)
|
||||
{
|
||||
_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
|
||||
continue;
|
||||
@@ -17547,6 +17556,17 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, i
|
||||
return missChance;
|
||||
}
|
||||
|
||||
uint32 Unit::GetPhaseByAuras() const
|
||||
{
|
||||
uint32 currentPhase = 0;
|
||||
AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
|
||||
if (!phases.empty())
|
||||
for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
|
||||
currentPhase |= (*itr)->GetMiscValue();
|
||||
|
||||
return currentPhase;
|
||||
}
|
||||
|
||||
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
|
||||
{
|
||||
if (newPhaseMask == GetPhaseMask())
|
||||
|
||||
@@ -2048,6 +2048,9 @@ class Unit : public WorldObject
|
||||
// delayed+channeled spells are always interrupted
|
||||
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, bool bySelf = false);
|
||||
|
||||
// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
|
||||
bool CanMoveDuringChannel() const;
|
||||
|
||||
Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
|
||||
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
|
||||
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
|
||||
@@ -2122,6 +2125,7 @@ class Unit : public WorldObject
|
||||
void SetModelVisible(bool on);
|
||||
|
||||
// common function for visibility checks for player/creatures with detection code
|
||||
uint32 GetPhaseByAuras() const;
|
||||
void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask
|
||||
void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false);
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "GameObjectAI.h"
|
||||
#include "Transport.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
bool GameEventMgr::CheckOneGameEvent(uint16 entry) const
|
||||
{
|
||||
switch (mGameEvent[entry].state)
|
||||
@@ -194,8 +196,8 @@ void GameEventMgr::LoadFromDB()
|
||||
{
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
// 1 2 3 4 5 6 7 8
|
||||
QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, description, world_event FROM game_event");
|
||||
// 1 2 3 4 5 6 7 8 9
|
||||
QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, holidayStage, description, world_event FROM game_event");
|
||||
if (!result)
|
||||
{
|
||||
mGameEvent.clear();
|
||||
@@ -225,9 +227,13 @@ void GameEventMgr::LoadFromDB()
|
||||
pGameEvent.length = fields[4].GetUInt64();
|
||||
pGameEvent.holiday_id = HolidayIds(fields[5].GetUInt32());
|
||||
|
||||
pGameEvent.state = (GameEventState)(fields[7].GetUInt8());
|
||||
pGameEvent.holidayStage = fields[6].GetUInt8();
|
||||
pGameEvent.description = fields[7].GetString();
|
||||
pGameEvent.state = (GameEventState)(fields[8].GetUInt8());
|
||||
pGameEvent.nextstart = 0;
|
||||
|
||||
++count;
|
||||
|
||||
if (pGameEvent.length == 0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check
|
||||
{
|
||||
sLog->outErrorDb("`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.", event_id);
|
||||
@@ -241,11 +247,10 @@ void GameEventMgr::LoadFromDB()
|
||||
sLog->outErrorDb("`game_event` game event id (%i) have not existed holiday id %u.", event_id, pGameEvent.holiday_id);
|
||||
pGameEvent.holiday_id = HOLIDAY_NONE;
|
||||
}
|
||||
|
||||
SetHolidayEventTime(pGameEvent);
|
||||
}
|
||||
|
||||
pGameEvent.description = fields[6].GetString();
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
@@ -951,6 +956,45 @@ void GameEventMgr::LoadFromDB()
|
||||
}
|
||||
}
|
||||
|
||||
void GameEventMgr::LoadHolidayDates()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, date_id, date_value FROM holiday_dates");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 holiday dates. DB table `holiday_dates` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 holidayId = fields[0].GetUInt32();
|
||||
HolidaysEntry* entry = const_cast<HolidaysEntry*>(sHolidaysStore.LookupEntry(holidayId));
|
||||
if (!entry)
|
||||
{
|
||||
sLog->outErrorDb("holiday_dates entry has invalid holiday id %u.", holidayId);
|
||||
continue;
|
||||
}
|
||||
uint8 dateId = fields[1].GetUInt8();
|
||||
if (dateId >= MAX_HOLIDAY_DATES)
|
||||
{
|
||||
sLog->outErrorDb("holiday_dates entry has out of range date_id %u.", dateId);
|
||||
continue;
|
||||
}
|
||||
entry->Date[dateId] = fields[2].GetUInt32();
|
||||
modifiedHolidays.insert(entry->Id);
|
||||
++count;
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u holiday dates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
uint32 GameEventMgr::GetNPCFlag(Creature* cr)
|
||||
{
|
||||
uint32 mask = 0;
|
||||
@@ -1669,6 +1713,83 @@ void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate)
|
||||
}
|
||||
}
|
||||
|
||||
void GameEventMgr::SetHolidayEventTime(GameEventData& event)
|
||||
{
|
||||
if (!event.holidayStage) // Ignore holiday
|
||||
return;
|
||||
|
||||
const HolidaysEntry* holiday = sHolidaysStore.LookupEntry(event.holiday_id);
|
||||
|
||||
if (!holiday->Date[0] || !holiday->Duration[0]) // Invalid definitions
|
||||
{
|
||||
sLog->outErrorDb("Missing date or duration for holiday %u.", event.holiday_id);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 stageIndex = event.holidayStage - 1;
|
||||
event.length = holiday->Duration[stageIndex] * HOUR / MINUTE;
|
||||
|
||||
time_t stageOffset = 0;
|
||||
for (int i = 0; i < stageIndex; ++i)
|
||||
stageOffset += holiday->Duration[i] * HOUR;
|
||||
|
||||
switch (holiday->CalendarFilterType)
|
||||
{
|
||||
case -1: // Yearly
|
||||
event.occurence = YEAR / MINUTE; // Not all too useful
|
||||
break;
|
||||
case 0: // Weekly
|
||||
event.occurence = WEEK / MINUTE;
|
||||
break;
|
||||
case 1: // Defined dates only (Darkmoon Faire)
|
||||
break;
|
||||
case 2: // Only used for looping events (Call to Arms)
|
||||
break;
|
||||
}
|
||||
|
||||
if (holiday->Looping)
|
||||
{
|
||||
event.occurence = 0;
|
||||
for (int i = 0; i < MAX_HOLIDAY_DURATIONS && holiday->Duration[i]; ++i)
|
||||
event.occurence += holiday->Duration[i] * HOUR / MINUTE;
|
||||
}
|
||||
|
||||
bool singleDate = ((holiday->Date[0] >> 24) & 0x1F) == 31; // Events with fixed date within year have - 1
|
||||
|
||||
time_t curTime = time(NULL);
|
||||
for (int i = 0; i < MAX_HOLIDAY_DATES && holiday->Date[i]; ++i)
|
||||
{
|
||||
uint32 date = holiday->Date[i];
|
||||
|
||||
tm timeInfo;
|
||||
if (singleDate)
|
||||
timeInfo.tm_year = localtime(&curTime)->tm_year - 1; // First try last year (event active through New Year)
|
||||
else
|
||||
timeInfo.tm_year = ((date >> 24) & 0x1F) + 100;
|
||||
timeInfo.tm_mon = (date >> 20) & 0xF;
|
||||
timeInfo.tm_mday = ((date >> 14) & 0x3F) + 1;
|
||||
timeInfo.tm_hour = (date >> 6) & 0x1F;
|
||||
timeInfo.tm_min = date & 0x3F;
|
||||
timeInfo.tm_sec = 0;
|
||||
timeInfo.tm_isdst = -1;
|
||||
tm tmCopy = timeInfo;
|
||||
|
||||
time_t startTime = mktime(&timeInfo);
|
||||
if (curTime < startTime + event.length * MINUTE)
|
||||
{
|
||||
event.start = startTime + stageOffset;
|
||||
return;
|
||||
}
|
||||
else if (singleDate)
|
||||
{
|
||||
tmCopy.tm_year = localtime(&curTime)->tm_year; // This year
|
||||
event.start = mktime(&tmCopy) + stageOffset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
sLog->outString("No suitable start date found for holiday %u.", event.holiday_id);
|
||||
}
|
||||
|
||||
bool IsHolidayActive(HolidayIds id)
|
||||
{
|
||||
if (id == HOLIDAY_NONE)
|
||||
|
||||
@@ -50,6 +50,7 @@ struct GameEventData
|
||||
uint32 occurence; // time between end and start
|
||||
uint32 length; // length of the event (minutes) after finishing all conditions
|
||||
HolidayIds holiday_id;
|
||||
uint8 holidayStage;
|
||||
GameEventState state; // state of the game event, these are saved into the game_event table on change!
|
||||
GameEventConditionMap conditions; // conditions to finish
|
||||
std::set<uint16 /*gameevent id*/> prerequisite_events; // events that must be completed before starting this event
|
||||
@@ -95,6 +96,7 @@ class GameEventMgr
|
||||
bool CheckOneGameEvent(uint16 entry) const;
|
||||
uint32 NextCheck(uint16 entry) const;
|
||||
void LoadFromDB();
|
||||
void LoadHolidayDates();
|
||||
uint32 Update();
|
||||
bool IsActiveEvent(uint16 event_id) { return (m_ActiveEvents.find(event_id) != m_ActiveEvents.end()); }
|
||||
uint32 StartSystem();
|
||||
@@ -128,6 +130,7 @@ class GameEventMgr
|
||||
bool hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id);
|
||||
bool hasCreatureActiveEventExcept(uint32 creature_guid, uint16 event_id);
|
||||
bool hasGameObjectActiveEventExcept(uint32 go_guid, uint16 event_id);
|
||||
void SetHolidayEventTime(GameEventData& event);
|
||||
|
||||
typedef std::list<uint32> GuidList;
|
||||
typedef std::list<uint32> IdList;
|
||||
@@ -162,6 +165,7 @@ class GameEventMgr
|
||||
public:
|
||||
GameEventGuidMap mGameEventCreatureGuids;
|
||||
GameEventGuidMap mGameEventGameobjectGuids;
|
||||
std::set<uint32> modifiedHolidays;
|
||||
};
|
||||
|
||||
#define sGameEventMgr ACE_Singleton<GameEventMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
@@ -1171,9 +1171,9 @@ void ObjectMgr::LoadEquipmentTemplates()
|
||||
if (!equipmentInfo.ItemEntry[i])
|
||||
continue;
|
||||
|
||||
ItemEntry const* dbcItem = sItemStore.LookupEntry(equipmentInfo.ItemEntry[i]);
|
||||
const ItemTemplate* item = GetItemTemplate(equipmentInfo.ItemEntry[i]);
|
||||
|
||||
if (!dbcItem)
|
||||
if (!item)
|
||||
{
|
||||
sLog->outErrorDb("Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u, forced to 0.",
|
||||
equipmentInfo.ItemEntry[i], i+1, entry);
|
||||
@@ -1181,15 +1181,15 @@ void ObjectMgr::LoadEquipmentTemplates()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dbcItem->InventoryType != INVTYPE_WEAPON &&
|
||||
dbcItem->InventoryType != INVTYPE_SHIELD &&
|
||||
dbcItem->InventoryType != INVTYPE_RANGED &&
|
||||
dbcItem->InventoryType != INVTYPE_2HWEAPON &&
|
||||
dbcItem->InventoryType != INVTYPE_WEAPONMAINHAND &&
|
||||
dbcItem->InventoryType != INVTYPE_WEAPONOFFHAND &&
|
||||
dbcItem->InventoryType != INVTYPE_HOLDABLE &&
|
||||
dbcItem->InventoryType != INVTYPE_THROWN &&
|
||||
dbcItem->InventoryType != INVTYPE_RANGEDRIGHT)
|
||||
if (item->InventoryType != INVTYPE_WEAPON &&
|
||||
item->InventoryType != INVTYPE_SHIELD &&
|
||||
item->InventoryType != INVTYPE_RANGED &&
|
||||
item->InventoryType != INVTYPE_2HWEAPON &&
|
||||
item->InventoryType != INVTYPE_WEAPONMAINHAND &&
|
||||
item->InventoryType != INVTYPE_WEAPONOFFHAND &&
|
||||
item->InventoryType != INVTYPE_HOLDABLE &&
|
||||
item->InventoryType != INVTYPE_THROWN &&
|
||||
item->InventoryType != INVTYPE_RANGEDRIGHT)
|
||||
{
|
||||
sLog->outErrorDb("Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u is not equipable in a hand, forced to 0.",
|
||||
equipmentInfo.ItemEntry[i], i+1, entry);
|
||||
@@ -2266,7 +2266,6 @@ void ObjectMgr::LoadItemTemplates()
|
||||
|
||||
_itemTemplateStore.rehash(result->GetRowCount());
|
||||
uint32 count = 0;
|
||||
bool enforceDBCAttributes = sWorld->getBoolConfig(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES);
|
||||
|
||||
do
|
||||
{
|
||||
@@ -2383,53 +2382,6 @@ void ObjectMgr::LoadItemTemplates()
|
||||
itemTemplate.FlagsCu = fields[137].GetUInt32();
|
||||
|
||||
// Checks
|
||||
|
||||
ItemEntry const* dbcitem = sItemStore.LookupEntry(entry);
|
||||
|
||||
if (dbcitem)
|
||||
{
|
||||
if (itemTemplate.Class != dbcitem->Class)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) does not have a correct class %u, must be %u .", entry, itemTemplate.Class, dbcitem->Class);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.Class = dbcitem->Class;
|
||||
}
|
||||
|
||||
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclass)
|
||||
{
|
||||
sLog->outError("Item (Entry: %u) does not have a correct SoundOverrideSubclass (%i), must be %i .", entry, itemTemplate.SoundOverrideSubclass, dbcitem->SoundOverrideSubclass);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclass;
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) does not have a correct material (%i), must be %i .", entry, itemTemplate.Material, dbcitem->Material);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.Material = dbcitem->Material;
|
||||
}
|
||||
if (itemTemplate.InventoryType != dbcitem->InventoryType)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) does not have a correct inventory type (%u), must be %u .", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.InventoryType = dbcitem->InventoryType;
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayId)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) does not have a correct display id (%u), must be %u .", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayId);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.DisplayInfoID = dbcitem->DisplayId;
|
||||
}
|
||||
if (itemTemplate.Sheath != dbcitem->Sheath)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) does not have a correct sheathid (%u), must be %u .", entry, itemTemplate.Sheath, dbcitem->Sheath);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.Sheath = dbcitem->Sheath;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
sLog->outErrorDb("Item (Entry: %u) does not exist in item.dbc! (not correct id?).", entry);
|
||||
|
||||
if (itemTemplate.Class >= MAX_ITEM_CLASS)
|
||||
{
|
||||
sLog->outErrorDb("Item (Entry: %u) has wrong Class value (%u)", entry, itemTemplate.Class);
|
||||
@@ -2720,7 +2672,7 @@ void ObjectMgr::LoadItemTemplates()
|
||||
itemTemplate.ItemSet = 0;
|
||||
}
|
||||
|
||||
if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area))
|
||||
if (itemTemplate.Area && !sAreaTableStore.LookupEntry(itemTemplate.Area))
|
||||
sLog->outErrorDb("Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area);
|
||||
|
||||
if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map))
|
||||
@@ -4022,7 +3974,7 @@ void ObjectMgr::LoadQuests()
|
||||
// client quest log visual (area case)
|
||||
if (qinfo->ZoneOrSort > 0)
|
||||
{
|
||||
if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
|
||||
if (!sAreaTableStore.LookupEntry(qinfo->ZoneOrSort))
|
||||
{
|
||||
sLog->outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
|
||||
qinfo->GetQuestId(), qinfo->ZoneOrSort);
|
||||
@@ -5845,7 +5797,7 @@ void ObjectMgr::LoadGraveyardZones()
|
||||
continue;
|
||||
}
|
||||
|
||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||
if (!areaEntry)
|
||||
{
|
||||
sLog->outErrorDb("Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId);
|
||||
@@ -7893,7 +7845,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
|
||||
uint32 entry = fields[0].GetUInt32();
|
||||
int32 skill = fields[1].GetInt16();
|
||||
|
||||
AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
|
||||
AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry);
|
||||
if (!fArea)
|
||||
{
|
||||
sLog->outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist", entry);
|
||||
|
||||
@@ -721,6 +721,7 @@ class ObjectMgr
|
||||
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
|
||||
ItemTemplate const* GetItemTemplate(uint32 entry);
|
||||
ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
|
||||
std::vector<ItemTemplate*> const* GetItemTemplateStoreFast() const { return &_itemTemplateStoreFast; }
|
||||
|
||||
ItemSetNameEntry const* GetItemSetNameEntry(uint32 itemId)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ class Player;
|
||||
|
||||
#define MAX_NUMBER_OF_GRIDS 64
|
||||
|
||||
#define SIZE_OF_GRIDS 533.33333f
|
||||
#define SIZE_OF_GRIDS 533.3333f
|
||||
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
|
||||
|
||||
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
|
||||
@@ -213,7 +213,7 @@ namespace Trinity
|
||||
|
||||
inline bool IsValidMapCoord(float x, float y, float z)
|
||||
{
|
||||
return IsValidMapCoord(x, y) && isfinite(z);
|
||||
return IsValidMapCoord(x, y) && IsValidMapCoord(z);
|
||||
}
|
||||
|
||||
inline bool IsValidMapCoord(float x, float y, float z, float o)
|
||||
|
||||
@@ -34,6 +34,7 @@ Copied events should probably have a new owner
|
||||
#include "GuildMgr.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "WorldSession.h"
|
||||
#include "GameEventMgr.h"
|
||||
|
||||
void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/)
|
||||
{
|
||||
@@ -139,11 +140,10 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/)
|
||||
data.append(dataBuffer);
|
||||
|
||||
// TODO: Fix this, how we do know how many and what holidays to send?
|
||||
uint32 holidayCount = 0;
|
||||
data << uint32(holidayCount);
|
||||
for (uint32 i = 0; i < holidayCount; ++i)
|
||||
data << uint32(sGameEventMgr->modifiedHolidays.size());
|
||||
for (uint32 entry : sGameEventMgr->modifiedHolidays)
|
||||
{
|
||||
HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(666);
|
||||
HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(entry);
|
||||
|
||||
data << uint32(holiday->Id); // m_ID
|
||||
data << uint32(holiday->Region); // m_region, might be looping
|
||||
|
||||
@@ -27,7 +27,7 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId());
|
||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
|
||||
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1979,30 +1979,50 @@ void WorldSession::HandleEquipmentSetUse(WorldPacket &recvData)
|
||||
item = _player->GetItemByGuid(itemGuid);
|
||||
|
||||
uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8);
|
||||
|
||||
InventoryResult msg;
|
||||
|
||||
if (!item)
|
||||
{
|
||||
Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
|
||||
if (!uItem)
|
||||
continue;
|
||||
|
||||
ItemPosCountVec sDest;
|
||||
InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
_player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
|
||||
_player->StoreItem(sDest, uItem, true);
|
||||
Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
|
||||
if (uItem) {
|
||||
if (uItem->IsEquipped()) {
|
||||
msg = _player->CanUnequipItem(dstpos, true);
|
||||
if (msg != EQUIP_ERR_OK) {
|
||||
_player->SendEquipError(msg, uItem, NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
_player->SendEquipError(msg, uItem, NULL);
|
||||
|
||||
continue;
|
||||
if (!item)
|
||||
{
|
||||
ItemPosCountVec sDest;
|
||||
msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
_player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
|
||||
_player->StoreItem(sDest, uItem, true);
|
||||
}
|
||||
else
|
||||
_player->SendEquipError(msg, uItem, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (item->GetPos() == dstpos)
|
||||
continue;
|
||||
if (item) {
|
||||
if (item->GetPos() == dstpos)
|
||||
continue;
|
||||
|
||||
_player->SwapItem(item->GetPos(), dstpos);
|
||||
if (!item->IsEquipped()) {
|
||||
uint16 _candidatePos;
|
||||
msg = _player->CanEquipItem(NULL_SLOT, _candidatePos, item, true);
|
||||
if (msg != EQUIP_ERR_OK) {
|
||||
_player->SendEquipError(msg, item, NULL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_player->SwapItem(item->GetPos(), dstpos);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1);
|
||||
|
||||
@@ -360,7 +360,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
|
||||
continue;
|
||||
|
||||
std::string aname;
|
||||
if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
|
||||
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
|
||||
aname = areaEntry->area_name[GetSessionDbcLocale()];
|
||||
|
||||
bool s_show = true;
|
||||
@@ -1934,7 +1934,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/)
|
||||
return;
|
||||
}
|
||||
|
||||
AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId());
|
||||
AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId());
|
||||
if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2))
|
||||
return;
|
||||
|
||||
|
||||
@@ -474,16 +474,26 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recvData)
|
||||
|
||||
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
|
||||
|
||||
if (movementInfo.pos.GetPositionZ() < -500.0f)
|
||||
if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
|
||||
if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player))
|
||||
{
|
||||
if (plrMover->IsAlive())
|
||||
{
|
||||
plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
|
||||
// player can be alive if GM
|
||||
if (plrMover->IsAlive())
|
||||
plrMover->KillPlayer();
|
||||
}
|
||||
else if (!plrMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
|
||||
{
|
||||
WorldSafeLocsEntry const* grave = sObjectMgr->GetClosestGraveyard(plrMover->GetPositionX(), plrMover->GetPositionY(), plrMover->GetPositionZ(), plrMover->GetMapId(), plrMover->GetTeamId());
|
||||
|
||||
if ( grave)
|
||||
plrMover->TeleportTo(grave->map_id, grave->x, grave->y, grave->z, plrMover->GetOrientation());
|
||||
plrMover->Relocate(grave->x, grave->y, grave->z, plrMover->GetOrientation());
|
||||
}
|
||||
|
||||
plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit
|
||||
}
|
||||
}
|
||||
@@ -711,5 +721,5 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData)
|
||||
agree = false;
|
||||
}
|
||||
_player->SetSummonAsSpectator(false);
|
||||
_player->SummonIfPossible(agree);
|
||||
_player->SummonIfPossible(agree, summoner_guid);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,9 @@ class InstanceScript : public ZoneScript
|
||||
//On load
|
||||
virtual void Load(char const* data) { LoadBossState(data); }
|
||||
|
||||
//Called when creature is Looted
|
||||
virtual void CreatureLooted(Creature* /*creature*/, LootType) {}
|
||||
|
||||
//When save is needed, this function generates the data
|
||||
virtual std::string GetSaveData() { return GetBossSaveData(); }
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class LootTemplate::LootGroup // A set of loot def
|
||||
bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry
|
||||
bool HasQuestDropForPlayer(Player const* player) const;
|
||||
// The same for active quests of the player
|
||||
void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
|
||||
void Process(Loot& loot, Player const *player, LootStore const& lootstore, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
|
||||
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
|
||||
float TotalChance() const; // Overall chance for the group
|
||||
|
||||
@@ -98,7 +98,7 @@ class LootTemplate::LootGroup // A set of loot def
|
||||
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
|
||||
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
|
||||
|
||||
LootStoreItem const* Roll(Loot& loot, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
|
||||
LootStoreItem const* Roll(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances
|
||||
|
||||
// This class must never be copied - storing pointers
|
||||
LootGroup(LootGroup const&);
|
||||
@@ -279,19 +279,23 @@ void LootStore::ReportNotExistedId(uint32 id) const
|
||||
|
||||
// Checks if the entry (quest, non-quest, reference) takes it's chance (at loot generation)
|
||||
// RATE_DROP_ITEMS is no longer used for all types of entries
|
||||
bool LootStoreItem::Roll(bool rate) const
|
||||
bool LootStoreItem::Roll(bool rate, Player const *player, Loot& loot, LootStore const& store) const
|
||||
{
|
||||
if (chance >= 100.0f)
|
||||
float _chance = chance;
|
||||
|
||||
sScriptMgr->OnItemRoll(player, this, _chance, loot, store);
|
||||
|
||||
if (_chance >= 100.0f)
|
||||
return true;
|
||||
|
||||
if (mincountOrRef < 0) // reference case
|
||||
return roll_chance_f(chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
|
||||
return roll_chance_f(_chance* (rate ? sWorld->getRate(RATE_DROP_ITEM_REFERENCED) : 1.0f));
|
||||
|
||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
|
||||
|
||||
float qualityModifier = pProto && rate ? sWorld->getRate(qualityToRate[pProto->Quality]) : 1.0f;
|
||||
|
||||
return roll_chance_f(chance*qualityModifier);
|
||||
return roll_chance_f(_chance*qualityModifier);
|
||||
}
|
||||
|
||||
// Checks correctness of values
|
||||
@@ -462,7 +466,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
|
||||
items.reserve(MAX_NR_LOOT_ITEMS);
|
||||
quest_items.reserve(MAX_NR_QUEST_ITEMS);
|
||||
|
||||
tab->Process(*this, store.IsRatesAllowed(), lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
|
||||
tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
|
||||
|
||||
// Setting access rights for group loot case
|
||||
Group* group = lootOwner->GetGroup();
|
||||
@@ -1102,7 +1106,7 @@ void LootTemplate::LootGroup::AddEntry(LootStoreItem* item)
|
||||
}
|
||||
|
||||
// Rolls an item from the group, returns NULL if all miss their chances
|
||||
LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, uint16 lootMode) const
|
||||
LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const
|
||||
{
|
||||
LootStoreItemList possibleLoot = ExplicitlyChanced;
|
||||
possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode));
|
||||
@@ -1114,10 +1118,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, uint16 lootMode)
|
||||
for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality.
|
||||
{
|
||||
LootStoreItem* item = *itr;
|
||||
if (item->chance >= 100.0f)
|
||||
float chance = item->chance;
|
||||
|
||||
sScriptMgr->OnItemRoll(player, item, chance, loot, store);
|
||||
|
||||
if (chance >= 100.0f)
|
||||
return item;
|
||||
|
||||
roll -= item->chance;
|
||||
roll -= chance;
|
||||
if (roll < 0)
|
||||
return item;
|
||||
}
|
||||
@@ -1169,9 +1177,9 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/)
|
||||
}
|
||||
|
||||
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
|
||||
void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
|
||||
void LootTemplate::LootGroup::Process(Loot& loot, Player const *player, LootStore const& store, uint16 lootMode) const
|
||||
{
|
||||
if (LootStoreItem const* item = Roll(loot, lootMode))
|
||||
if (LootStoreItem const* item = Roll(loot, player, store, lootMode))
|
||||
loot.AddItem(*item);
|
||||
}
|
||||
|
||||
@@ -1297,8 +1305,10 @@ void LootTemplate::CopyConditions(LootItem* li) const
|
||||
}
|
||||
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const* player, uint8 groupId) const
|
||||
void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId) const
|
||||
{
|
||||
bool rate = store.IsRatesAllowed();
|
||||
|
||||
if (groupId) // Group reference uses own processing of the group
|
||||
{
|
||||
if (groupId > Groups.size())
|
||||
@@ -1307,7 +1317,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
|
||||
if (!Groups[groupId - 1])
|
||||
return;
|
||||
|
||||
Groups[groupId-1]->Process(loot, lootMode);
|
||||
Groups[groupId-1]->Process(loot, player, store, lootMode);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1318,7 +1328,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
|
||||
if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
|
||||
continue;
|
||||
|
||||
if (!item->Roll(rate))
|
||||
if (!item->Roll(rate, player, loot, store))
|
||||
continue; // Bad luck for the entry
|
||||
|
||||
if (item->mincountOrRef < 0) // References processing
|
||||
@@ -1328,12 +1338,12 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
|
||||
continue; // Error message already printed at loading stage
|
||||
|
||||
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
|
||||
sScriptMgr->OnAfterRefCount(item, maxcount);
|
||||
sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, item, maxcount, store);
|
||||
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
|
||||
Referenced->Process(loot, rate, lootMode, player, item->group);
|
||||
Referenced->Process(loot, store, lootMode, player, item->group);
|
||||
} else {
|
||||
// Plain entries (not a reference, not grouped)
|
||||
sScriptMgr->OnBeforeDropAddItem(player, loot, item);
|
||||
sScriptMgr->OnBeforeDropAddItem(player, loot, rate, lootMode, item, store);
|
||||
loot.AddItem(*item); // Chance is already checked, just add
|
||||
}
|
||||
}
|
||||
@@ -1341,7 +1351,7 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, Player const*
|
||||
// Now processing groups
|
||||
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
|
||||
if (LootGroup* group = *i)
|
||||
group->Process(loot, lootMode);
|
||||
group->Process(loot, player, store, lootMode);
|
||||
}
|
||||
|
||||
// True if template includes at least 1 quest drop entry
|
||||
@@ -1598,8 +1608,8 @@ void LoadLootTemplates_Fishing()
|
||||
uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);
|
||||
|
||||
// remove real entries and check existence loot
|
||||
for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
|
||||
if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
|
||||
for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
|
||||
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i))
|
||||
if (lootIdSet.find(areaEntry->ID) != lootIdSet.end())
|
||||
lootIdSet.erase(areaEntry->ID);
|
||||
|
||||
@@ -1784,8 +1794,8 @@ void LoadLootTemplates_Mail()
|
||||
uint32 count = LootTemplates_Mail.LoadAndCollectLootIds(lootIdSet);
|
||||
|
||||
// remove real entries and check existence loot
|
||||
for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
|
||||
if (sMailTemplateStore.LookupEntry(i))
|
||||
for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
|
||||
if (sAreaTableStore.LookupEntry(i))
|
||||
if (lootIdSet.find(i) != lootIdSet.end())
|
||||
lootIdSet.erase(i);
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ enum LootSlotType
|
||||
class Player;
|
||||
class LootStore;
|
||||
class ConditionMgr;
|
||||
struct Loot;
|
||||
|
||||
struct LootStoreItem
|
||||
{
|
||||
@@ -129,7 +130,7 @@ struct LootStoreItem
|
||||
group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount)
|
||||
{}
|
||||
|
||||
bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation)
|
||||
bool Roll(bool rate, Player const *player, Loot& loot, LootStore const& store) const; // Checks if the entry takes it's chance (at loot generation)
|
||||
bool IsValid(LootStore const& store, uint32 entry) const;
|
||||
// Checks correctness of values
|
||||
};
|
||||
@@ -178,7 +179,6 @@ struct QuestItem
|
||||
: index(_index), is_looted(_islooted) {}
|
||||
};
|
||||
|
||||
struct Loot;
|
||||
class LootTemplate;
|
||||
|
||||
typedef std::vector<QuestItem> QuestItemList;
|
||||
@@ -237,7 +237,7 @@ class LootTemplate
|
||||
// Adds an entry to the group (at loading stage)
|
||||
void AddEntry(LootStoreItem* item);
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void Process(Loot& loot, bool rate, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
|
||||
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
|
||||
void CopyConditions(ConditionList conditions);
|
||||
void CopyConditions(LootItem* li) const;
|
||||
|
||||
|
||||
+136
-56
@@ -32,7 +32,7 @@ union u_map_magic
|
||||
};
|
||||
|
||||
u_map_magic MapMagic = { {'M','A','P','S'} };
|
||||
u_map_magic MapVersionMagic = { {'v','1','.','3'} };
|
||||
u_map_magic MapVersionMagic = { {'v','1','.','8'} };
|
||||
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
|
||||
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
|
||||
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
|
||||
@@ -1200,13 +1200,15 @@ GridMap::GridMap()
|
||||
_flags = 0;
|
||||
// Area data
|
||||
_gridArea = 0;
|
||||
_areaMap = NULL;
|
||||
_areaMap = nullptr;
|
||||
// Height level data
|
||||
_gridHeight = INVALID_HEIGHT;
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
_gridIntHeightMultiplier = 0;
|
||||
m_V9 = NULL;
|
||||
m_V8 = NULL;
|
||||
m_V9 = nullptr;
|
||||
m_V8 = nullptr;
|
||||
_maxHeight = nullptr;
|
||||
_minHeight = nullptr;
|
||||
// Liquid data
|
||||
_liquidType = 0;
|
||||
_liquidOffX = 0;
|
||||
@@ -1214,9 +1216,9 @@ GridMap::GridMap()
|
||||
_liquidWidth = 0;
|
||||
_liquidHeight = 0;
|
||||
_liquidLevel = INVALID_HEIGHT;
|
||||
_liquidEntry = NULL;
|
||||
_liquidFlags = NULL;
|
||||
_liquidMap = NULL;
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
}
|
||||
|
||||
GridMap::~GridMap()
|
||||
@@ -1277,15 +1279,19 @@ void GridMap::unloadData()
|
||||
delete[] _areaMap;
|
||||
delete[] m_V9;
|
||||
delete[] m_V8;
|
||||
delete[] _maxHeight;
|
||||
delete[] _minHeight;
|
||||
delete[] _liquidEntry;
|
||||
delete[] _liquidFlags;
|
||||
delete[] _liquidMap;
|
||||
_areaMap = NULL;
|
||||
m_V9 = NULL;
|
||||
m_V8 = NULL;
|
||||
_liquidEntry = NULL;
|
||||
_liquidFlags = NULL;
|
||||
_liquidMap = NULL;
|
||||
_areaMap = nullptr;
|
||||
m_V9 = nullptr;
|
||||
m_V8 = nullptr;
|
||||
_maxHeight = nullptr;
|
||||
_minHeight = nullptr;
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
}
|
||||
|
||||
@@ -1350,6 +1356,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
|
||||
}
|
||||
else
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
|
||||
if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
|
||||
{
|
||||
_maxHeight = new int16[3 * 3];
|
||||
_minHeight = new int16[3 * 3];
|
||||
if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 ||
|
||||
fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1620,6 +1636,66 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
||||
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
|
||||
}
|
||||
|
||||
float GridMap::getMinHeight(float x, float y) const
|
||||
{
|
||||
if (!_minHeight)
|
||||
return -500.0f;
|
||||
|
||||
static uint32 const indices[] =
|
||||
{
|
||||
3, 0, 4,
|
||||
0, 1, 4,
|
||||
1, 2, 4,
|
||||
2, 5, 4,
|
||||
5, 8, 4,
|
||||
8, 7, 4,
|
||||
7, 6, 4,
|
||||
6, 3, 4
|
||||
};
|
||||
|
||||
static float const boundGridCoords[] =
|
||||
{
|
||||
0.0f, 0.0f,
|
||||
0.0f, -266.66666f,
|
||||
0.0f, -533.33331f,
|
||||
-266.66666f, 0.0f,
|
||||
-266.66666f, -266.66666f,
|
||||
-266.66666f, -533.33331f,
|
||||
-533.33331f, 0.0f,
|
||||
-533.33331f, -266.66666f,
|
||||
-533.33331f, -533.33331f
|
||||
};
|
||||
|
||||
Cell cell(x, y);
|
||||
float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||
float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||
|
||||
uint32 quarterIndex = 0;
|
||||
if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2)
|
||||
{
|
||||
if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
|
||||
{
|
||||
quarterIndex = 4 + (gy > gx);
|
||||
}
|
||||
else
|
||||
quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy);
|
||||
}
|
||||
else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
|
||||
{
|
||||
quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy);
|
||||
}
|
||||
else
|
||||
quarterIndex = gx > gy;
|
||||
|
||||
quarterIndex *= 3;
|
||||
|
||||
return G3D::Plane(
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]),
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]),
|
||||
G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]])
|
||||
).distance(G3D::Vector3(gx, gy, 0.0f));
|
||||
}
|
||||
|
||||
float GridMap::getLiquidLevel(float x, float y) const
|
||||
{
|
||||
if (!_liquidMap)
|
||||
@@ -1679,12 +1755,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R
|
||||
uint32 liqTypeIdx = liquidEntry->Type;
|
||||
if (entry < 21)
|
||||
{
|
||||
if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID))
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = GetAreaEntryByAreaID(area->zone);
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
@@ -1835,7 +1911,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
||||
|
||||
// we are already under the surface or vmap height above map heigt
|
||||
// or if the distance of the vmap height is less the land height distance
|
||||
if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
|
||||
if (vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z))
|
||||
return vmapHeight;
|
||||
else
|
||||
return mapHeight; // better use .map surface height
|
||||
@@ -1847,6 +1923,15 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
||||
return mapHeight; // explicitly use map data
|
||||
}
|
||||
|
||||
float Map::GetMinHeight(float x, float y) const
|
||||
{
|
||||
if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
return grid->getMinHeight(x, y);
|
||||
|
||||
return -500.0f;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
||||
{
|
||||
bool outdoor = true;
|
||||
@@ -1887,7 +1972,7 @@ bool Map::IsOutdoors(float x, float y, float z) const
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outStaticDebug("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
||||
#endif
|
||||
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
}
|
||||
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
}
|
||||
@@ -1911,7 +1996,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
||||
uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const
|
||||
{
|
||||
uint32 mogpFlags;
|
||||
int32 adtId, rootId, groupId;
|
||||
@@ -1924,20 +2009,20 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
||||
haveAreaInfo = true;
|
||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
}
|
||||
|
||||
uint16 areaflag;
|
||||
uint16 areaId = 0;
|
||||
|
||||
if (atEntry)
|
||||
areaflag = atEntry->exploreFlag;
|
||||
areaId = atEntry->ID;
|
||||
else
|
||||
{
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
areaflag = gmap->getArea(x, y);
|
||||
areaId = gmap->getArea(x, y);
|
||||
// this used while not all *.map files generated (instances)
|
||||
else
|
||||
areaflag = GetAreaFlagByMapId(i_mapEntry->MapID);
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
}
|
||||
|
||||
if (isOutdoors)
|
||||
@@ -1947,8 +2032,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
||||
else
|
||||
*isOutdoors = true;
|
||||
}
|
||||
return areaflag;
|
||||
}
|
||||
return areaId;
|
||||
}
|
||||
|
||||
uint32 Map::GetAreaId(float x, float y, float z) const
|
||||
{
|
||||
return GetAreaId(x, y, z, nullptr);
|
||||
}
|
||||
|
||||
uint32 Map::GetZoneId(float x, float y, float z) const
|
||||
{
|
||||
uint32 areaId = GetAreaId(x, y, z);
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||
if (area->zone)
|
||||
return area->zone;
|
||||
|
||||
return areaId;
|
||||
}
|
||||
|
||||
void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||
{
|
||||
areaid = zoneid = GetAreaId(x, y, z);
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
|
||||
if (area->zone)
|
||||
zoneid = area->zone;
|
||||
}
|
||||
|
||||
uint8 Map::GetTerrainType(float x, float y) const
|
||||
{
|
||||
@@ -1986,12 +2094,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
|
||||
|
||||
if (liquid_type && liquid_type < 21)
|
||||
{
|
||||
if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId()))
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = GetAreaEntryByAreaID(area->zone);
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
}
|
||||
@@ -2053,34 +2161,6 @@ float Map::GetWaterLevel(float x, float y) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
||||
{
|
||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
||||
|
||||
if (entry)
|
||||
return entry->ID;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
||||
{
|
||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
||||
|
||||
if (entry)
|
||||
return (entry->zone != 0) ? entry->zone : entry->ID;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id)
|
||||
{
|
||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
||||
|
||||
areaid = entry ? entry->ID : 0;
|
||||
zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0;
|
||||
}
|
||||
|
||||
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
|
||||
{
|
||||
return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
|
||||
|
||||
+13
-24
@@ -85,9 +85,10 @@ struct map_areaHeader
|
||||
uint16 gridArea;
|
||||
};
|
||||
|
||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
|
||||
|
||||
struct map_heightHeader
|
||||
{
|
||||
@@ -153,6 +154,8 @@ class GridMap
|
||||
uint16* m_uint16_V8;
|
||||
uint8* m_uint8_V8;
|
||||
};
|
||||
int16* _maxHeight;
|
||||
int16* _minHeight;
|
||||
// Height level data
|
||||
float _gridHeight;
|
||||
float _gridIntHeightMultiplier;
|
||||
@@ -193,6 +196,7 @@ public:
|
||||
|
||||
uint16 getArea(float x, float y) const;
|
||||
inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
||||
float getMinHeight(float x, float y) const;
|
||||
float getLiquidLevel(float x, float y) const;
|
||||
uint8 getTerrainType(float x, float y) const;
|
||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
|
||||
@@ -327,12 +331,16 @@ class Map : public GridRefManager<NGridType>
|
||||
// some calls like isInWater should not use vmaps due to processor power
|
||||
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
float GetMinHeight(float x, float y) const;
|
||||
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = NULL);
|
||||
|
||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0) const;
|
||||
|
||||
uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const;
|
||||
bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||
uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const;
|
||||
bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||
uint32 GetAreaId(float x, float y, float z) const;
|
||||
uint32 GetZoneId(float x, float y, float z) const;
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
|
||||
|
||||
bool IsOutdoors(float x, float y, float z) const;
|
||||
|
||||
@@ -341,25 +349,6 @@ class Map : public GridRefManager<NGridType>
|
||||
bool IsInWater(float x, float y, float z, LiquidData* data = 0) const;
|
||||
bool IsUnderWater(float x, float y, float z) const;
|
||||
|
||||
static uint32 GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id);
|
||||
static uint32 GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id);
|
||||
static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id);
|
||||
|
||||
uint32 GetAreaId(float x, float y, float z) const
|
||||
{
|
||||
return GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), GetId());
|
||||
}
|
||||
|
||||
uint32 GetZoneId(float x, float y, float z) const
|
||||
{
|
||||
return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId());
|
||||
}
|
||||
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||
{
|
||||
GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId());
|
||||
}
|
||||
|
||||
void MoveAllCreaturesInMoveList();
|
||||
void MoveAllGameObjectsInMoveList();
|
||||
void MoveAllDynamicObjectsInMoveList();
|
||||
|
||||
@@ -36,22 +36,20 @@ class MapManager
|
||||
return (iter == i_maps.end() ? NULL : iter->second);
|
||||
}
|
||||
|
||||
uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const
|
||||
{
|
||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||
return m->GetAreaFlag(x, y, z);
|
||||
}
|
||||
uint32 GetAreaId(uint32 mapid, float x, float y, float z) const
|
||||
{
|
||||
return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid);
|
||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||
return m->GetAreaId(x, y, z);
|
||||
}
|
||||
uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
|
||||
{
|
||||
return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid);
|
||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||
return m->GetZoneId(x, y, z);
|
||||
}
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
|
||||
{
|
||||
Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid);
|
||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||
m->GetZoneAndAreaId(zoneid, areaid, x, y, z);
|
||||
}
|
||||
|
||||
void Initialize(void);
|
||||
|
||||
@@ -35,7 +35,7 @@ void WhoListCacheMgr::Update()
|
||||
wstrToLower(wgname);
|
||||
|
||||
std::string aname;
|
||||
if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
|
||||
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
|
||||
aname = areaEntry->area_name[sWorld->GetDefaultDbcLocale()];
|
||||
|
||||
if (itr->second->IsSpectator())
|
||||
|
||||
@@ -444,7 +444,7 @@ enum SpellAttr4
|
||||
|
||||
enum SpellAttr5
|
||||
{
|
||||
SPELL_ATTR5_UNK0 = 0x00000001, // 0
|
||||
SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING = 0x00000001, // 0
|
||||
SPELL_ATTR5_NO_REAGENT_WHILE_PREP = 0x00000002, // 1 not need reagents if UNIT_FLAG_PREPARATION
|
||||
SPELL_ATTR5_REMOVE_ON_ARENA_ENTER = 0x00000004, // 2 xinef: remove this aura on arena enter
|
||||
SPELL_ATTR5_USABLE_WHILE_STUNNED = 0x00000008, // 3 usable while stunned
|
||||
@@ -3531,7 +3531,7 @@ enum PartyResult
|
||||
};
|
||||
|
||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||
#define MMAP_VERSION 3
|
||||
#define MMAP_VERSION 8
|
||||
|
||||
struct MmapTileHeader
|
||||
{
|
||||
@@ -3539,12 +3539,23 @@ struct MmapTileHeader
|
||||
uint32 dtVersion;
|
||||
uint32 mmapVersion;
|
||||
uint32 size;
|
||||
bool usesLiquids : 1;
|
||||
char usesLiquids;
|
||||
char padding[3];
|
||||
|
||||
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() { }
|
||||
};
|
||||
|
||||
// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
|
||||
static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
|
||||
static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
|
||||
sizeof(MmapTileHeader::dtVersion) +
|
||||
sizeof(MmapTileHeader::mmapVersion) +
|
||||
sizeof(MmapTileHeader::size) +
|
||||
sizeof(MmapTileHeader::usesLiquids) +
|
||||
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
|
||||
|
||||
|
||||
enum NavTerrain
|
||||
{
|
||||
NAV_EMPTY = 0x00,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "MoveSplineInit.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "Player.h"
|
||||
#include "VMapFactory.h"
|
||||
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
@@ -32,6 +33,19 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
|
||||
if (!_getPoint(owner, x, y, z))
|
||||
return;
|
||||
|
||||
// Add LOS check for target point
|
||||
bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(owner->GetMapId(),
|
||||
owner->GetPositionX(),
|
||||
owner->GetPositionY(),
|
||||
owner->GetPositionZ() + 2.0f,
|
||||
x, y, z + 2.0f);
|
||||
|
||||
if (!isInLOS)
|
||||
{
|
||||
i_nextCheckTime.Reset(500);
|
||||
return;
|
||||
}
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
|
||||
@@ -152,9 +152,10 @@ dtPolyRef PathGenerator::GetPolyByLocation(float* point, float* distance) const
|
||||
|
||||
// still nothing ..
|
||||
// try with bigger search box
|
||||
extents[1] = 80.0f;
|
||||
result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
|
||||
if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
|
||||
// Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly)
|
||||
extents[1] = 50.0f;
|
||||
|
||||
if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
|
||||
{
|
||||
*distance = dtVdist(closestPoint, point);
|
||||
return polyRef;
|
||||
@@ -339,7 +340,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
if (startPoly != endPoly || !endInWaterFar)
|
||||
{
|
||||
float closestPoint[VERTEX_SIZE];
|
||||
if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
|
||||
if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, NULL)))
|
||||
{
|
||||
dtVcopy(endPoint, closestPoint);
|
||||
SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
|
||||
@@ -416,7 +417,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
|
||||
// we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
|
||||
float suffixEndPoint[VERTEX_SIZE];
|
||||
if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
|
||||
if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, NULL)))
|
||||
{
|
||||
// we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
|
||||
// try to recover by using prev polyref
|
||||
@@ -424,7 +425,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
if (prefixPolyLength)
|
||||
{
|
||||
suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
|
||||
if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
|
||||
if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,NULL)))
|
||||
error = true;
|
||||
}
|
||||
else
|
||||
@@ -445,7 +446,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
(int*)&suffixPolyLength,
|
||||
MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
|
||||
|
||||
if (!suffixPolyLength || dtResult != DT_SUCCESS)
|
||||
if (!_polyLength || dtStatusFailed(dtResult))
|
||||
{
|
||||
// this is probably an error state, but we'll leave it
|
||||
// and hopefully recover on the next Update
|
||||
@@ -470,7 +471,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
(int*)&_polyLength,
|
||||
MAX_PATH_LENGTH); // max number of polygons in output path
|
||||
|
||||
if (!_polyLength || dtResult != DT_SUCCESS)
|
||||
if (!_polyLength || dtStatusFailed(dtResult))
|
||||
{
|
||||
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
||||
BuildShortcut();
|
||||
@@ -499,7 +500,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
||||
(int*)&_polyLength,
|
||||
MAX_PATH_LENGTH); // max number of polygons in output path
|
||||
|
||||
if (!_polyLength || dtResult != DT_SUCCESS)
|
||||
if (!_polyLength || dtStatusFailed(dtResult))
|
||||
{
|
||||
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
||||
BuildShortcut();
|
||||
@@ -658,7 +659,7 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin
|
||||
_pointPathLimit); // maximum number of points
|
||||
}
|
||||
|
||||
if (pointCount < 2 || dtResult != DT_SUCCESS)
|
||||
if (pointCount < 2 || dtStatusFailed(dtResult))
|
||||
{
|
||||
// only happens if pass bad data to findStraightPath or navmesh is broken
|
||||
// single point paths can be generated here
|
||||
@@ -784,7 +785,7 @@ bool PathGenerator::HaveTile(const G3D::Vector3& p) const
|
||||
if (tx < 0 || ty < 0)
|
||||
return false;
|
||||
|
||||
return (_navMesh->getTileAt(tx, ty) != NULL);
|
||||
return (_navMesh->getTileAt(tx, ty, 0) != NULL);
|
||||
}
|
||||
|
||||
uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
|
||||
@@ -844,7 +845,7 @@ bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
|
||||
uint32 nsteerPath = 0;
|
||||
dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
|
||||
steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
|
||||
if (!nsteerPath || DT_SUCCESS != dtResult)
|
||||
if (!nsteerPath || dtStatusFailed(dtResult))
|
||||
return false;
|
||||
|
||||
// Find vertex far enough to steer to.
|
||||
@@ -908,7 +909,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo
|
||||
// Find movement delta.
|
||||
float delta[VERTEX_SIZE];
|
||||
dtVsub(delta, steerPos, iterPos);
|
||||
float len = dtSqrt(dtVdot(delta,delta));
|
||||
float len = dtMathSqrtf(dtVdot(delta, delta));
|
||||
// If the steer target is end of path or off-mesh link, do not move past the location.
|
||||
if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
|
||||
len = 1.0f;
|
||||
|
||||
@@ -38,7 +38,7 @@ class Unit;
|
||||
#define ALLOWED_DIST_FROM_POLY 2.5f
|
||||
#define ADDED_Z_FOR_POLY_LOOKUP 0.3f
|
||||
#define DISALLOW_TIME_AFTER_FAIL 3 // secs
|
||||
#define MAX_FIXABLE_Z_ERROR 12.0f
|
||||
#define MAX_FIXABLE_Z_ERROR 7.0f
|
||||
|
||||
#define VERTEX_SIZE 3
|
||||
#define INVALID_POLYREF 0
|
||||
|
||||
@@ -30,6 +30,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
||||
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||
return;
|
||||
|
||||
if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
bool isPlayerPet = owner->IsPet() && IS_PLAYER_GUID(owner->GetOwnerGUID());
|
||||
bool sameTransport = owner->GetTransport() && owner->GetTransport() == i_target->GetTransport();
|
||||
@@ -44,11 +47,17 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
||||
(i_target->GetTypeId() == TYPEID_PLAYER && i_target->ToPlayer()->IsGameMaster()); // for .npc follow
|
||||
bool forcePoint = ((!isPlayerPet || owner->GetMapId() == 618) && (forceDest || !useMMaps)) || sameTransport;
|
||||
|
||||
if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()) && !sameTransport && !forceDest && !forcePoint)
|
||||
return;
|
||||
|
||||
lastOwnerXYZ.Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
|
||||
lastTargetXYZ.Relocate(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ());
|
||||
|
||||
if (!i_offset)
|
||||
{
|
||||
if (i_target->IsWithinDistInMap(owner, CONTACT_DISTANCE))
|
||||
return;
|
||||
|
||||
float allowedRange = MELEE_RANGE;
|
||||
if ((!initial || (owner->movespline->Finalized() && this->GetMovementGeneratorType() == CHASE_MOTION_TYPE)) && i_target->IsWithinMeleeRange(owner, allowedRange) && i_target->IsWithinLOS(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ()))
|
||||
return;
|
||||
@@ -60,6 +69,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
||||
owner->m_targetsNotAcceptable[i_target->GetGUID()] = MMapTargetData(sWorld->GetGameTime()+DISALLOW_TIME_AFTER_FAIL, owner, i_target.getTarget());
|
||||
return;
|
||||
}
|
||||
|
||||
// to nearest contact position
|
||||
i_target->GetContactPoint(owner, x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -167,6 +179,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
||||
else
|
||||
{
|
||||
owner->m_targetsNotAcceptable.erase(i_target->GetGUID());
|
||||
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||
|
||||
init.MovebyPath(i_path->GetPath());
|
||||
if (i_angle == 0.f)
|
||||
@@ -180,6 +193,8 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
||||
// if failed to generate, just use normal MoveTo
|
||||
}
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||
|
||||
init.MoveTo(x,y,z);
|
||||
// Using the same condition for facing target as the one that is used for SetInFront on movement end
|
||||
// - applies to ChaseMovementGenerator mostly
|
||||
@@ -206,7 +221,7 @@ bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff)
|
||||
}
|
||||
|
||||
// prevent movement while casting spells with cast time or channel time
|
||||
if (owner->HasUnitState(UNIT_STATE_CASTING))
|
||||
if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
|
||||
{
|
||||
bool stop = true;
|
||||
if (Spell* spell = owner->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
||||
|
||||
@@ -1148,13 +1148,13 @@ void ScriptMgr::OnShutdown()
|
||||
FOREACH_SCRIPT(WorldScript)->OnShutdown();
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target)
|
||||
bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target, uint32 criteria_id)
|
||||
{
|
||||
ASSERT(source);
|
||||
// target can be NULL.
|
||||
|
||||
GET_SCRIPT_RET(AchievementCriteriaScript, scriptId, tmpscript, false);
|
||||
return tmpscript->OnCheck(source, target);
|
||||
return tmpscript->OnCheck(source, target, criteria_id);
|
||||
}
|
||||
|
||||
// Player
|
||||
@@ -1303,6 +1303,21 @@ void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newAre
|
||||
FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerUpdateArea(Player* player, uint32 oldArea, uint32 newArea)
|
||||
{
|
||||
FOREACH_SCRIPT(PlayerScript)->OnUpdateArea(player, oldArea, newArea);
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit *target)
|
||||
{
|
||||
bool ret=true;
|
||||
FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts
|
||||
if (!itr->second->OnBeforeTeleport(player, mapid, x, y, z, orientation, options, target))
|
||||
ret=false; // we change ret value only when scripts return false
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerUpdateFaction(Player* player)
|
||||
{
|
||||
FOREACH_SCRIPT(PlayerScript)->OnUpdateFaction(player);
|
||||
@@ -1494,14 +1509,18 @@ void ScriptMgr::OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<uint32, uint32
|
||||
FOREACH_SCRIPT(GlobalScript)->OnBeforeUpdateArenaPoints(at,ap);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnAfterRefCount(LootStoreItem* LootStoreItem, uint32 &maxcount)
|
||||
void ScriptMgr::OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32 &maxcount, LootStore const& store)
|
||||
{
|
||||
FOREACH_SCRIPT(GlobalScript)->OnAfterRefCount(LootStoreItem, maxcount);
|
||||
FOREACH_SCRIPT(GlobalScript)->OnAfterRefCount(player, LootStoreItem, loot, canRate, lootMode, maxcount, store);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnBeforeDropAddItem(Player const* player, Loot& loot, LootStoreItem* LootStoreItem)
|
||||
void ScriptMgr::OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store)
|
||||
{
|
||||
FOREACH_SCRIPT(GlobalScript)->OnBeforeDropAddItem(player, loot, LootStoreItem);
|
||||
FOREACH_SCRIPT(GlobalScript)->OnBeforeDropAddItem(player, loot, canRate, lootMode, LootStoreItem, store);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float &chance, Loot& loot, LootStore const& store) {
|
||||
FOREACH_SCRIPT(GlobalScript)->OnItemRoll(player, LootStoreItem, chance, loot, store);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData)
|
||||
|
||||
@@ -747,7 +747,11 @@ class AchievementCriteriaScript : public ScriptObject
|
||||
bool IsDatabaseBound() const { return true; }
|
||||
|
||||
// Called when an additional criteria is checked.
|
||||
virtual bool OnCheck(Player* source, Unit* target) = 0;
|
||||
virtual bool OnCheck(Player* source, Unit* target, uint32 /*criteria_id*/) {
|
||||
return OnCheck(source, target);
|
||||
}
|
||||
// deprecated/legacy
|
||||
virtual bool OnCheck(Player* /*source*/, Unit* /*target*/) { return true; };
|
||||
};
|
||||
|
||||
class PlayerScript : public ScriptObject
|
||||
@@ -838,9 +842,15 @@ class PlayerScript : public ScriptObject
|
||||
// Called when a player switches to a new zone
|
||||
virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { }
|
||||
|
||||
// Called when a player switches to a new area (more accurate than UpdateZone)
|
||||
virtual void OnUpdateArea(Player* /*player*/, uint32 /*oldArea*/, uint32 /*newArea*/) { }
|
||||
|
||||
// Called when a player changes to a new map (after moving to new map)
|
||||
virtual void OnMapChanged(Player* /*player*/) { }
|
||||
|
||||
// Called before a player is being teleported to new coords
|
||||
virtual bool OnBeforeTeleport(Player* /*player*/, uint32 /*mapid*/, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) { return true; }
|
||||
|
||||
// Called when team/faction is set on player
|
||||
virtual void OnUpdateFaction(Player* /*player*/) { }
|
||||
|
||||
@@ -994,8 +1004,11 @@ class GlobalScript : public ScriptObject
|
||||
// items
|
||||
virtual void OnItemDelFromDB(SQLTransaction& /*trans*/, uint32 /*itemGuid*/) { }
|
||||
virtual void OnMirrorImageDisplayItem(const Item* /*item*/, uint32& /*display*/) { }
|
||||
virtual void OnAfterRefCount(LootStoreItem* /*LootStoreItem*/, uint32& /*maxcount*/) { }
|
||||
virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, LootStoreItem* /*LootStoreItem*/) { }
|
||||
|
||||
// loot
|
||||
virtual void OnAfterRefCount(Player const* /*player*/, LootStoreItem* /*LootStoreItem*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, uint32& /*maxcount*/, LootStore const& /*store*/) { }
|
||||
virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* /*LootStoreItem*/, LootStore const& /*store*/) { }
|
||||
virtual void OnItemRoll(Player const* /*player*/, LootStoreItem const* /*LootStoreItem*/, float& /*chance*/, Loot& /*loot*/, LootStore const& /*store*/) { };
|
||||
|
||||
virtual void OnInitializeLockedDungeons(Player* /*player*/, uint8& /*level*/, uint32& /*lockData*/) { }
|
||||
virtual void OnAfterInitializeLockedDungeons(Player* /*player*/) { }
|
||||
@@ -1176,7 +1189,7 @@ class ScriptMgr
|
||||
|
||||
public: /* AchievementCriteriaScript */
|
||||
|
||||
bool OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target);
|
||||
bool OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target, uint32 criteria_id);
|
||||
|
||||
public: /* PlayerScript */
|
||||
|
||||
@@ -1210,6 +1223,8 @@ class ScriptMgr
|
||||
void OnPlayerDelete(uint64 guid);
|
||||
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent);
|
||||
void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea);
|
||||
void OnPlayerUpdateArea(Player* player, uint32 oldArea, uint32 newArea);
|
||||
bool OnBeforePlayerTeleport(Player* player, uint32 mapid, float x, float y, float z, float orientation, uint32 options, Unit *target);
|
||||
void OnPlayerUpdateFaction(Player* player);
|
||||
void OnPlayerAddToBattleground(Player* player, Battleground* bg);
|
||||
void OnPlayerRemoveFromBattleground(Player* player, Battleground* bg);
|
||||
@@ -1264,8 +1279,9 @@ class ScriptMgr
|
||||
void OnGlobalItemDelFromDB(SQLTransaction& trans, uint32 itemGuid);
|
||||
void OnGlobalMirrorImageDisplayItem(const Item *item, uint32 &display);
|
||||
void OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<uint32, uint32> &ap);
|
||||
void OnAfterRefCount(LootStoreItem* LootStoreItem, uint32 &maxcount);
|
||||
void OnBeforeDropAddItem(Player const* player, Loot& loot, LootStoreItem* LootStoreItem);
|
||||
void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32 &maxcount, LootStore const& store);
|
||||
void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store);
|
||||
void OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float &chance, Loot& loot, LootStore const& store);
|
||||
void OnInitializeLockedDungeons(Player* player, uint8& level, uint32& lockData);
|
||||
void OnAfterInitializeLockedDungeons(Player* player);
|
||||
|
||||
|
||||
@@ -1711,20 +1711,16 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
// no-phase is also phase state so same code for apply and remove
|
||||
uint32 newPhase = 0;
|
||||
Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE);
|
||||
if (!phases.empty())
|
||||
for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
|
||||
newPhase |= (*itr)->GetMiscValue();
|
||||
uint32 newPhase = target->GetPhaseByAuras();
|
||||
|
||||
if (Player* player = target->ToPlayer())
|
||||
{
|
||||
if (!newPhase)
|
||||
newPhase = PHASEMASK_NORMAL;
|
||||
|
||||
// GM-mode have mask 0xFFFFFFFF
|
||||
// do not change phase to GM with all phases enabled
|
||||
if (player->IsGameMaster())
|
||||
newPhase = 0xFFFFFFFF;
|
||||
newPhase = PHASEMASK_ANYWHERE;
|
||||
|
||||
player->SetPhaseMask(newPhase, false);
|
||||
player->GetSession()->SendSetPhaseShift(newPhase);
|
||||
@@ -1769,7 +1765,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
|
||||
|
||||
void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_REAL))
|
||||
if (!(mode & AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
@@ -3582,6 +3578,9 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
|
||||
|
||||
switch (GetId())
|
||||
{
|
||||
case 46924: // BladeStorm
|
||||
target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
|
||||
break;
|
||||
case 34471: // The Beast Within
|
||||
case 19574: // Bestial Wrath
|
||||
mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
|
||||
|
||||
@@ -395,7 +395,7 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne
|
||||
|
||||
Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, uint64 casterGUID) :
|
||||
m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()),
|
||||
m_castItemGuid(castItem ? castItem->GetGUID() : 0), m_applyTime(time(NULL)),
|
||||
m_castItemGuid(castItem ? castItem->GetGUID() : 0),m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(time(NULL)),
|
||||
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
|
||||
m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
|
||||
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false)
|
||||
|
||||
@@ -96,6 +96,7 @@ class Aura
|
||||
uint32 GetId() const{ return GetSpellInfo()->Id; }
|
||||
|
||||
uint64 GetCastItemGUID() const { return m_castItemGuid; }
|
||||
uint32 GetCastItemEntry() const { return m_castItemEntry; }
|
||||
uint64 GetCasterGUID() const { return m_casterGuid; }
|
||||
Unit* GetCaster() const;
|
||||
WorldObject* GetOwner() const { return m_owner; }
|
||||
@@ -235,6 +236,7 @@ class Aura
|
||||
SpellInfo const* const m_spellInfo;
|
||||
uint64 const m_casterGuid;
|
||||
uint64 const m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
|
||||
uint32 const m_castItemEntry; // when deleted, we could retrieve some information from template instead
|
||||
time_t const m_applyTime;
|
||||
WorldObject* const m_owner; //
|
||||
|
||||
|
||||
@@ -287,6 +287,16 @@ Corpse* SpellCastTargets::GetCorpseTarget() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SpellCastTargets::SetCorpseTarget(Corpse* target)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
m_objectTarget = target;
|
||||
m_objectTargetGUID = target->GetGUID();
|
||||
m_targetMask |= TARGET_FLAG_CORPSE_MASK;
|
||||
}
|
||||
|
||||
WorldObject* SpellCastTargets::GetObjectTarget() const
|
||||
{
|
||||
return m_objectTarget;
|
||||
@@ -1306,7 +1316,8 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
||||
float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
|
||||
float x, y, z, angle;
|
||||
angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
|
||||
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle);
|
||||
//m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle); this contains extra code that breaks fishing
|
||||
m_caster->GetNearPoint(m_caster, x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, m_caster->GetOrientation() + angle);
|
||||
|
||||
float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z, true, 120.0f);
|
||||
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
|
||||
@@ -2395,6 +2406,23 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
// Increase time interval for reflected spells by 1.5
|
||||
m_caster->m_Events.AddEvent(new ReflectEvent(m_caster->GetGUID(), targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay));
|
||||
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
|
||||
|
||||
// HACK: workaround check for succubus seduction case
|
||||
// TODO: seduction should be casted only on humanoids (not demons)
|
||||
if (m_caster->IsPet())
|
||||
{
|
||||
CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(m_caster->GetEntry());
|
||||
switch (ci->family)
|
||||
{
|
||||
case CREATURE_FAMILY_SUCCUBUS:
|
||||
{
|
||||
if (m_spellInfo->SpellIconID != 694) // Soothing Kiss
|
||||
cancel();
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
targetInfo.reflectResult = SPELL_MISS_NONE;
|
||||
@@ -4545,14 +4573,14 @@ void Spell::WriteAmmoToPacket(WorldPacket* data)
|
||||
{
|
||||
if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i))
|
||||
{
|
||||
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
|
||||
if (ItemTemplate const* itemEntry = sObjectMgr->GetItemTemplate(item_id))
|
||||
{
|
||||
if (itemEntry->Class == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
switch (itemEntry->SubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
ammoDisplayID = itemEntry->DisplayId;
|
||||
ammoDisplayID = itemEntry->DisplayInfoID;
|
||||
ammoInventoryType = itemEntry->InventoryType;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
@@ -5788,7 +5816,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
m_pathFinder = new PathGenerator(m_caster);
|
||||
m_pathFinder->CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ+0.15f, false);
|
||||
G3D::Vector3 endPos = m_pathFinder->GetEndPosition(); // also check distance between target and the point calculated by mmaps
|
||||
if (m_pathFinder->GetPathType()&PATHFIND_NOPATH || target->GetExactDistSq(endPos.x, endPos.y, endPos.z) > maxdist*maxdist || m_pathFinder->getPathLength() > (40.0f + (m_caster->HasAura(58097) ? 5.0f : 0.0f)))
|
||||
if (m_pathFinder->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE) || target->GetExactDistSq(endPos.x, endPos.y, endPos.z) > maxdist*maxdist || m_pathFinder->getPathLength() > (40.0f + (m_caster->HasAura(58097) ? 5.0f : 0.0f)))
|
||||
return SPELL_FAILED_NOPATH;
|
||||
}
|
||||
break;
|
||||
@@ -6200,7 +6228,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive())
|
||||
{
|
||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
|
||||
if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId()))
|
||||
if (AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))
|
||||
if ((pArea->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))
|
||||
return SPELL_FAILED_NOT_HERE;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ class SpellCastTargets
|
||||
|
||||
uint64 GetCorpseTargetGUID() const;
|
||||
Corpse* GetCorpseTarget() const;
|
||||
void SetCorpseTarget(Corpse* target);
|
||||
|
||||
WorldObject* GetObjectTarget() const;
|
||||
uint64 GetObjectTargetGUID() const;
|
||||
|
||||
@@ -3218,7 +3218,7 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
|
||||
return;
|
||||
|
||||
// xinef: Hand of Reckoning, cast before checing canhavethreatlist. fixes damage against pets
|
||||
if (m_spellInfo->Id == 62124 && unitTarget->GetVictim() != m_caster && !unitTarget->IsTotem())
|
||||
if (m_spellInfo->Id == 62124 && unitTarget->GetVictim() != m_caster)
|
||||
m_caster->CastSpell(unitTarget, 67485, true);
|
||||
|
||||
// this effect use before aura Taunt apply for prevent taunt already attacking target
|
||||
@@ -4241,14 +4241,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
|
||||
return;
|
||||
|
||||
// Players can only fight a duel in zones with this flag
|
||||
AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId());
|
||||
AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId());
|
||||
if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
||||
return;
|
||||
}
|
||||
|
||||
AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId());
|
||||
AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId());
|
||||
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
||||
|
||||
@@ -1069,7 +1069,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId());
|
||||
AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId());
|
||||
if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE))
|
||||
return false;
|
||||
if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))
|
||||
@@ -2513,7 +2513,7 @@ void SpellMgr::LoadSpellAreas()
|
||||
}
|
||||
}
|
||||
|
||||
if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
|
||||
if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
|
||||
{
|
||||
sLog->outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);
|
||||
continue;
|
||||
@@ -6243,8 +6243,8 @@ void SpellMgr::LoadDbcDataCorrections()
|
||||
}
|
||||
|
||||
// Xinef: The Veiled Sea area in outlands (Draenei zone), client blocks casting flying mounts
|
||||
for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i)
|
||||
if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaStore.LookupEntry(i)))
|
||||
for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
|
||||
if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaTableStore.LookupEntry(i)))
|
||||
{
|
||||
if (areaEntry->ID == 3479)
|
||||
areaEntry->flags |= AREA_FLAG_NO_FLY_ZONE;
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include "WhoListCache.h"
|
||||
#include "AsyncAuctionListing.h"
|
||||
#include "SavingSystem.h"
|
||||
#include <VMapManager2.h>
|
||||
|
||||
ACE_Atomic_Op<ACE_Thread_Mutex, bool> World::m_stopEvent = false;
|
||||
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
|
||||
@@ -909,6 +910,12 @@ void World::LoadConfigSettings(bool reload)
|
||||
m_int_configs[CONFIG_UPTIME_UPDATE] = 1;
|
||||
}
|
||||
|
||||
if (reload)
|
||||
{
|
||||
m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
|
||||
m_timers[WUPDATE_UPTIME].Reset();
|
||||
}
|
||||
|
||||
// log db cleanup interval
|
||||
m_int_configs[CONFIG_LOGDB_CLEARINTERVAL] = sConfigMgr->GetIntDefault("LogDB.Opt.ClearInterval", 10);
|
||||
if (int32(m_int_configs[CONFIG_LOGDB_CLEARINTERVAL]) <= 0)
|
||||
@@ -1218,9 +1225,6 @@ void World::LoadConfigSettings(bool reload)
|
||||
// Dungeon finder
|
||||
m_int_configs[CONFIG_LFG_OPTIONSMASK] = sConfigMgr->GetIntDefault("DungeonFinder.OptionsMask", 3);
|
||||
|
||||
// DBC_ItemAttributes
|
||||
m_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetBoolDefault("DBC.EnforceItemAttributes", true);
|
||||
|
||||
// Max instances per hour
|
||||
m_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetIntDefault("AccountInstancesPerHour", 5);
|
||||
|
||||
@@ -1276,6 +1280,12 @@ void World::SetInitialWorldSettings()
|
||||
sLog->outString("Initializing Scripts...");
|
||||
sScriptMgr->Initialize();
|
||||
|
||||
///- Initialize VMapManager function pointers (to untangle game/collision circular deps)
|
||||
if (VMAP::VMapManager2* vmmgr2 = dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager()))
|
||||
{
|
||||
vmmgr2->GetLiquidFlagsPtr = &GetLiquidFlags;
|
||||
}
|
||||
|
||||
///- Initialize config settings
|
||||
LoadConfigSettings();
|
||||
|
||||
@@ -1520,7 +1530,8 @@ void World::SetInitialWorldSettings()
|
||||
sPoolMgr->LoadFromDB();
|
||||
|
||||
sLog->outString("Loading Game Event Data..."); // must be after loading pools fully
|
||||
sGameEventMgr->LoadFromDB();
|
||||
sGameEventMgr->LoadHolidayDates(); // Must be after loading DBC
|
||||
sGameEventMgr->LoadFromDB(); // Must be after loading holiday dates
|
||||
|
||||
sLog->outString("Loading UNIT_NPC_FLAG_SPELLCLICK Data..."); // must be after LoadQuests
|
||||
sObjectMgr->LoadNPCSpellClickSpells();
|
||||
@@ -1752,11 +1763,16 @@ void World::SetInitialWorldSettings()
|
||||
m_gameTime = time(NULL);
|
||||
m_startTime = m_gameTime;
|
||||
|
||||
LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')",
|
||||
realmID, uint32(m_startTime), _FULLVERSION); // One-time query
|
||||
|
||||
|
||||
|
||||
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
|
||||
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
|
||||
m_timers[WUPDATE_AUCTIONS].SetCurrent(MINUTE*IN_MILLISECONDS);
|
||||
m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
|
||||
//Update "uptime" table based on configuration entry in minutes.
|
||||
|
||||
m_timers[WUPDATE_CORPSES].SetInterval(20 * MINUTE * IN_MILLISECONDS);
|
||||
//erase corpses every 20 minutes
|
||||
@@ -2077,7 +2093,25 @@ void World::Update(uint32 diff)
|
||||
|
||||
// execute callbacks from sql queries that were queued recently
|
||||
ProcessQueryCallbacks();
|
||||
|
||||
|
||||
/// <li> Update uptime table
|
||||
if (m_timers[WUPDATE_UPTIME].Passed())
|
||||
{
|
||||
uint32 tmpDiff = uint32(m_gameTime - m_startTime);
|
||||
uint32 maxOnlinePlayers = GetMaxPlayerCount();
|
||||
|
||||
m_timers[WUPDATE_UPTIME].Reset();
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_UPTIME_PLAYERS);
|
||||
|
||||
stmt->setUInt32(0, tmpDiff);
|
||||
stmt->setUInt16(1, uint16(maxOnlinePlayers));
|
||||
stmt->setUInt32(2, realmID);
|
||||
stmt->setUInt32(3, uint32(m_startTime));
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
///- Erase corpses once every 20 minutes
|
||||
if (m_timers[WUPDATE_CORPSES].Passed())
|
||||
{
|
||||
@@ -2765,6 +2799,7 @@ void World::UpdateRealmCharCount(uint32 accountId)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT);
|
||||
stmt->setUInt32(0, accountId);
|
||||
stmt->setUInt32(1, accountId);
|
||||
PreparedQueryResultFuture result = CharacterDatabase.AsyncQuery(stmt);
|
||||
m_realmCharCallbacks.insert(result);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ enum WorldTimers
|
||||
{
|
||||
WUPDATE_AUCTIONS,
|
||||
WUPDATE_WEATHERS,
|
||||
WUPDATE_UPTIME,
|
||||
WUPDATE_CORPSES,
|
||||
WUPDATE_EVENTS,
|
||||
WUPDATE_CLEANDB,
|
||||
@@ -147,7 +148,6 @@ enum WorldBoolConfigs
|
||||
CONFIG_AUTOBROADCAST,
|
||||
CONFIG_ALLOW_TICKETS,
|
||||
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
|
||||
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
|
||||
CONFIG_PRESERVE_CUSTOM_CHANNELS,
|
||||
CONFIG_WINTERGRASP_ENABLE,
|
||||
CONFIG_PDUMP_NO_PATHS,
|
||||
|
||||
Reference in New Issue
Block a user