diff --git a/src/game/BattleGround/BattleGround.h b/src/game/BattleGround/BattleGround.h index c8f0e7124..d661d8253 100644 --- a/src/game/BattleGround/BattleGround.h +++ b/src/game/BattleGround/BattleGround.h @@ -314,7 +314,17 @@ class BattleGround // Get methods: ObjectGuid GetObjectGuid() { return ObjectGuid(HIGHGUID_BATTLEGROUND, uint32(m_ArenaType), uint32(m_TypeID)); } char const* GetName() const { return m_Name; } - BattleGroundTypeId GetTypeID() const { return m_TypeID; } + /** + * @brief + * + * @return BattleGroundTypeId + */ + BattleGroundTypeId GetTypeID(bool GetRandom = false) const { return GetRandom ? m_RandomTypeID : m_TypeID; } + /** + * @brief + * + * @return BattleGroundBracketId + */ BattleGroundBracketId GetBracketId() const { return m_BracketId; } // the instanceId check is also used to determine a bg-template // that's why the m_map hack is here.. @@ -581,6 +591,7 @@ class BattleGround private: /* Battleground */ BattleGroundTypeId m_TypeID; + BattleGroundTypeId m_RandomTypeID; BattleGroundStatus m_Status; uint32 m_ClientInstanceID; // the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; diff --git a/src/game/BattleGround/BattleGroundMgr.cpp b/src/game/BattleGround/BattleGroundMgr.cpp index 0dfa27763..e9c2f79fd 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -1131,10 +1131,12 @@ void BGQueueRemoveEvent::Abort(uint64 /*e_time*/) /*** BATTLEGROUND MANAGER ***/ /*********************************************************/ -BattleGroundMgr::BattleGroundMgr() : m_ArenaTesting(false) +BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false) { for (uint8 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; ++i) + { m_BattleGrounds[i].clear(); + } m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER); m_Testing = false; } @@ -1973,6 +1975,80 @@ void BattleGroundMgr::CreateInitialBattleGrounds() sLog.outString(">> Loaded %u battlegrounds", count); } +void BattleGroundMgr::InitAutomaticArenaPointDistribution() +{ + if (sWorld.getConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS)) + { + DEBUG_LOG("Initializing Automatic Arena Point Distribution"); + QueryResult* result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables"); + if (!result) + { + DEBUG_LOG("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now."); + m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS)); + CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('" UI64FMTD "')", uint64(m_NextAutoDistributionTime)); + } + else + { + m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64()); + delete result; + } + DEBUG_LOG("Automatic Arena Point Distribution initialized."); + } +} + +/* + * there does not appear to be a way to do this in Three +void BattleGroundMgr::DistributeArenaPoints() +{ + // used to distribute arena points based on last week's stats + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START); + + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START); + + // temporary structure for storing maximum points to add values for all players + std::map PlayerPoints; + + // at first update all points for all team members + for (ObjectMgr::ArenaTeamMap::iterator team_itr = sObjectMgr.GetArenaTeamMapBegin(); team_itr != sObjectMgr.GetArenaTeamMapEnd(); ++team_itr) + { + if (ArenaTeam* at = team_itr->second) + { + at->UpdateArenaPointsHelper(PlayerPoints); + } + } + + // cycle that gives points to all players + for (std::map::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr) + { + // update to database + CharacterDatabase.PExecute("UPDATE characters SET arenaPoints = arenaPoints + '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first); + // add points if player is online + if (Player* pl = sObjectMgr.GetPlayer(ObjectGuid(HIGHGUID_PLAYER, plr_itr->first))) + pl->ModifyArenaPoints(plr_itr->second); + } + + PlayerPoints.clear(); + + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END); + + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START); + for (ObjectMgr::ArenaTeamMap::iterator titr = sObjectMgr.GetArenaTeamMapBegin(); titr != sObjectMgr.GetArenaTeamMapEnd(); ++titr) + { + if (ArenaTeam* at = titr->second) + { + at->FinishWeek(); // set played this week etc values to 0 in memory, too + at->SaveToDB(); // save changes + at->NotifyStatsChanged(); // notify the players of the changes + } + } + + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END); + + sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END); +} +*/ + + void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket* data, ObjectGuid guid, Player* plr, BattleGroundTypeId bgTypeId) { if (!plr) diff --git a/src/game/BattleGround/BattleGroundMgr.h b/src/game/BattleGround/BattleGroundMgr.h index 07de85e94..afc6df245 100644 --- a/src/game/BattleGround/BattleGroundMgr.h +++ b/src/game/BattleGround/BattleGroundMgr.h @@ -42,6 +42,7 @@ typedef UNORDERED_MAP BattleMastersMap; typedef UNORDERED_MAP CreatureBattleEventIndexesMap; typedef UNORDERED_MAP GameObjectBattleEventIndexesMap; +#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day #define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10 struct GroupQueueInfo; // type predefinition @@ -239,6 +240,8 @@ class BattleGroundMgr uint32 GetRatingDiscardTimer() const; uint32 GetPrematureFinishTime() const; + void InitAutomaticArenaPointDistribution(); + // void DistributeArenaPoints(); // there does not appear to be a way to do this in Three void ToggleArenaTesting(); void ToggleTesting(); @@ -291,6 +294,8 @@ class BattleGroundMgr typedef std::set ClientBattleGroundIdSet; ClientBattleGroundIdSet m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_BRACKETS]; // the instanceids just visible for the client uint32 m_NextRatingDiscardUpdate; + time_t m_NextAutoDistributionTime; + uint32 m_AutoDistributionTimeChecker; bool m_ArenaTesting; bool m_Testing; }; diff --git a/src/game/ChatCommands/Level3.cpp b/src/game/ChatCommands/Level3.cpp index b57504c84..79c36a8e2 100644 --- a/src/game/ChatCommands/Level3.cpp +++ b/src/game/ChatCommands/Level3.cpp @@ -4849,33 +4849,29 @@ bool ChatHandler::HandleChangeWeatherCommand(char* args) if (!ExtractUInt32(&args, type)) return false; - // 0 to 3, 0: fine, 1: rain, 2: snow, 3: sand - if (type > 3) + // see enum WeatherType + if (!Weather::IsValidWeatherType(type)) + { return false; + } float grade; if (!ExtractFloat(&args, grade)) return false; - // 0 to 1, sending -1 is instand good weather + // 0 to 1, sending -1 is instant good weather if (grade < 0.0f || grade > 1.0f) return false; Player* player = m_session->GetPlayer(); - uint32 zoneid = player->GetZoneId(); - - Weather* wth = sWorld.FindWeather(zoneid); - - if (!wth) - wth = sWorld.AddWeather(zoneid); - if (!wth) + uint32 zoneId = player->GetZoneId(); + if (!sWeatherMgr.GetWeatherChances(zoneId)) { SendSysMessage(LANG_NO_WEATHER); SetSentErrorMessage(true); - return false; } - wth->SetWeather(WeatherType(type), grade); + player->GetMap()->SetWeather(zoneId, (WeatherType)type, grade, false); return true; } diff --git a/src/game/Object/ArenaTeam.cpp b/src/game/Object/ArenaTeam.cpp index b1c09bd56..112b69f1b 100644 --- a/src/game/Object/ArenaTeam.cpp +++ b/src/game/Object/ArenaTeam.cpp @@ -558,6 +558,33 @@ ArenaType ArenaTeam::GetTypeBySlot(uint8 slot) return ArenaType(0xFF); } +uint32 ArenaTeam::GetPoints(uint32 MemberRating) +{ + // returns how many points would be awarded with this team type with this rating + float points; + + uint32 rating = MemberRating + 150 < m_stats.rating ? MemberRating : m_stats.rating; + + if (rating <= 1500) + { + // As of Season 6 and later, all teams below 1500 rating will earn points as if they were a 1500 rated team + if (sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_ID) >= 6) + rating = 1500; + + points = (float)rating * 0.22f + 14.0f; + } + else + points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating)); + + // type penalties for <5v5 teams + if (m_Type == ARENA_TYPE_2v2) + points *= 0.76f; + else if (m_Type == ARENA_TYPE_3v3) + points *= 0.88f; + + return (uint32)points; +} + bool ArenaTeam::HaveMember(ObjectGuid guid) const { for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) @@ -703,6 +730,35 @@ void ArenaTeam::MemberWon(Player* plr, uint32 againstRating) } } +void ArenaTeam::UpdateArenaPointsHelper(std::map& PlayerPoints) +{ + // called after a match has ended and the stats are already modified + // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons) + // 10 played games per week is a minimum + if (m_stats.games_week < 10) + return; + // to get points, a player has to participate in at least 30% of the matches + uint32 min_plays = (uint32)ceil(m_stats.games_week * 0.3); + for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + { + // the player participated in enough games, update his points + uint32 points_to_add = 0; + if (itr->games_week >= min_plays) + points_to_add = GetPoints(itr->personal_rating); + // OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, m_TeamId, itr->guid); + + std::map::iterator plr_itr = PlayerPoints.find(itr->guid.GetCounter()); + if (plr_itr != PlayerPoints.end()) + { + // check if there is already more points + if (plr_itr->second < points_to_add) + PlayerPoints[itr->guid.GetCounter()] = points_to_add; + } + else + PlayerPoints[itr->guid.GetCounter()] = points_to_add; + } +} + void ArenaTeam::SaveToDB() { // save team and member stats to db diff --git a/src/game/Object/ArenaTeam.h b/src/game/Object/ArenaTeam.h index 874e671f9..a774b32d0 100644 --- a/src/game/Object/ArenaTeam.h +++ b/src/game/Object/ArenaTeam.h @@ -200,6 +200,7 @@ class ArenaTeam void Stats(WorldSession* session); void InspectStats(WorldSession* session, ObjectGuid guid); + uint32 GetPoints(uint32 MemberRating); float GetChanceAgainst(uint32 own_rating, uint32 enemy_rating); int32 WonAgainst(uint32 againstRating); void MemberWon(Player* plr, uint32 againstRating); @@ -207,6 +208,8 @@ class ArenaTeam void MemberLost(Player* plr, uint32 againstRating); void OfflineMemberLost(ObjectGuid guid, uint32 againstRating); + void UpdateArenaPointsHelper(std::map & PlayerPoints); + void NotifyStatsChanged(); void FinishWeek(); diff --git a/src/game/Object/Creature.h b/src/game/Object/Creature.h index 308b79ceb..437f1c390 100644 --- a/src/game/Object/Creature.h +++ b/src/game/Object/Creature.h @@ -238,6 +238,17 @@ struct CreatureDataAddon uint32 const* auras; // loaded as char* "spell1 spell2 ... " }; +// Bases values for given Level and UnitClass +struct CreatureClassLvlStats +{ + uint32 BaseHealth; + uint32 BaseMana; + float BaseDamage; + float BaseMeleeAttackPower; + float BaseRangedAttackPower; + uint32 BaseArmor; +}; + struct CreatureModelInfo { uint32 modelid; diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index 42fea20fa..d5dc7e57b 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -868,6 +868,82 @@ void ObjectMgr::LoadCreatureAddons() sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`", addon->guidOrEntry); } +void ObjectMgr::LoadCreatureClassLvlStats() +{ + // initialize data array + memset(&m_creatureClassLvlStats, 0, sizeof(m_creatureClassLvlStats)); + + std::string queryStr = "SELECT Class, Level, BaseMana, BaseMeleeAttackPower, BaseRangedAttackPower, BaseArmor"; + + for (int i = 0; i <= MAX_EXPANSION; i++) + { + std::ostringstream str; + str << ", `BaseHealthExp" << i << "`, `BaseDamageExp" << i << "`"; + queryStr.append(str.str().c_str()); + } + + queryStr.append(" FROM `creature_template_classlevelstats` ORDER BY `Class`, `Level`"); + QueryResult* result = WorldDatabase.Query(queryStr.c_str()); + + if (!result) + { + BarGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb("DB table `creature_template_classlevelstats` is empty."); + return; + } + + BarGoLink bar(result->GetRowCount()); + uint32 DataCount = 0; + + do + { + Field* fields = result->Fetch(); + bar.step(); + + uint32 creatureClass = fields[0].GetUInt32(); + uint32 creatureLevel = fields[1].GetUInt32(); + + if (creatureLevel == 0 || creatureLevel > DEFAULT_MAX_CREATURE_LEVEL) + { + sLog.outErrorDb("Found stats for creature level [%u] with incorrect level. Skipping!", creatureLevel); + continue; + } + + if (((1 << (creatureClass - 1)) & CLASSMASK_ALL_CREATURES) == 0) + { + sLog.outErrorDb("Found stats for creature class [%u] with incorrect class. Skipping!", creatureClass); + continue; + } + + uint32 baseMana = fields[2].GetUInt32(); + float baseMeleeAttackPower = fields[3].GetFloat(); + float baseRangedAttackPower = fields[4].GetFloat(); + uint32 baseArmor = fields[5].GetUInt32(); + + for (uint8 i = 0; i <= MAX_EXPANSION; ++i) + { + CreatureClassLvlStats &cCLS = m_creatureClassLvlStats[creatureLevel][classToIndex[creatureClass]][i - 1]; // values should start from 0 + cCLS.BaseMana = baseMana; + cCLS.BaseMeleeAttackPower = baseMeleeAttackPower; + cCLS.BaseRangedAttackPower = baseRangedAttackPower; + cCLS.BaseArmor = baseArmor; + + cCLS.BaseHealth = fields[6 + (i * 2)].GetUInt32(); + cCLS.BaseDamage = fields[7 + (i * 2)].GetFloat(); + } + ++DataCount; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u creature class level stats definitions.", DataCount); +} + void ObjectMgr::LoadEquipmentTemplates() { sEquipmentStorage.Load(); @@ -6993,6 +7069,112 @@ void ObjectMgr::LoadQuestPOI() sLog.outString(">> Loaded %u quest POI definitions", count); } +void ObjectMgr::LoadDungeonFinderRequirements() +{ + uint32 count = 0; + mDungeonFinderRequirementsMap.clear(); // in case of a reload + + // 0 1 2 3 4 5 6 7 8 + QueryResult* result = WorldDatabase.Query("SELECT mapId, difficulty, min_item_level, item, item_2, alliance_quest, horde_quest, achievement, quest_incomplete_text FROM dungeonfinder_requirements"); + + if (!result) + { + BarGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 dungeon finder requirements. DB table `dungeonfinder_requirements`, is empty!"); + return; + } + + BarGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + bar.step(); + + uint32 mapId = fields[0].GetUInt32(); + uint32 difficulty = fields[1].GetUInt32(); + uint32 dungeonKey = MAKE_PAIR32(mapId, difficulty); // for unique key + + uint32 minItemLevel = fields[2].GetUInt32(); + uint32 item = fields[3].GetUInt32(); + uint32 item2 = fields[4].GetUInt32(); + uint32 allianceQuest = fields[5].GetUInt32(); + uint32 hordeQuest = fields[6].GetUInt32(); + uint32 achievement = fields[7].GetUInt32(); + const char* questText = fields[8].GetString(); + + // check that items, quests, & achievements are real + if (item) + { + ItemEntry const* dbcitem = sItemStore.LookupEntry(item); + if (!dbcitem) + { + sLog.outString(); + sLog.outErrorDb("Table `dungeonfinder_requirements` has invalid item entry %u for map %u ! Removing requirement.", item, mapId); + item = 0; + } + } + + if (item2) + { + ItemEntry const* dbcitem = sItemStore.LookupEntry(item2); + if (!dbcitem) + { + sLog.outString(); + sLog.outErrorDb("Table `dungeonfinder_requirements` has invalid item entry %u for map %u ! Removing requirement.", item2, mapId); + item2 = 0; + } + } + + if (allianceQuest) + { + QuestMap::iterator qReqItr = mQuestTemplates.find(allianceQuest); + if (qReqItr == mQuestTemplates.end()) + { + sLog.outString(); + sLog.outErrorDb("Table `dungeonfinder_requirements` has invalid quest requirement %u for map %u ! Removing requirement.", allianceQuest, mapId); + allianceQuest = 0; + } + } + + if (hordeQuest) + { + QuestMap::iterator qReqItr = mQuestTemplates.find(hordeQuest); + if (qReqItr == mQuestTemplates.end()) + { + sLog.outString(); + sLog.outErrorDb("Table `dungeonfinder_requirements` has invalid quest requirement %u for map %u ! Removing requirement.", hordeQuest, mapId); + hordeQuest = 0; + } + } + + if (achievement) + { + if (!sAchievementStore.LookupEntry(achievement)) + { + sLog.outString(); + sLog.outErrorDb("Table `dungeonfinder_requirements` has invalid achievement %u for map %u ! Removing requirement.", achievement, mapId); + achievement = 0; + } + } + + // add to map after checks + DungeonFinderRequirements requirement(minItemLevel, item, item2, allianceQuest, hordeQuest, achievement, questText); + mDungeonFinderRequirementsMap[dungeonKey] = requirement; + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u Dungeon Finder Requirements", count); +} + void ObjectMgr::LoadNPCSpellClickSpells() { uint32 count = 0; @@ -7100,68 +7282,57 @@ void ObjectMgr::GetConditions(uint32 conditionId, std::vector { - uint32 count = 0; - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult* result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); - - if (!result) + template + void default_fill(uint32 field_pos, S src, D& dst) { - BarGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); - return; + if (field_pos == LOADED_SPELLDBC_FIELD_POS_EQUIPPED_ITEM_CLASS) + dst = D(-1); + else + dst = D(src); } - BarGoLink bar(result->GetRowCount()); - - do + void default_fill_to_str(uint32 field_pos, char const* /*src*/, char * & dst) { - Field* fields = result->Fetch(); - bar.step(); - - uint32 zone_id = fields[0].GetUInt32(); - - WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; - - for (int season = 0; season < WEATHER_SEASONS; ++season) + if (field_pos == LOADED_SPELLDBC_FIELD_POS_SPELLNAME_0) { - wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE - 1) + 1].GetUInt32(); - wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE - 1) + 2].GetUInt32(); - wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE - 1) + 3].GetUInt32(); - - if (wzc.data[season].rainChance > 100) - { - wzc.data[season].rainChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%", zone_id, season); - } - - if (wzc.data[season].snowChance > 100) - { - wzc.data[season].snowChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%", zone_id, season); - } - - if (wzc.data[season].stormChance > 100) - { - wzc.data[season].stormChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%", zone_id, season); - } + dst = SERVER_SIDE_SPELL; + } + else + { + dst = new char[1]; + *dst = 0; } - - ++count; } - while (result->NextRow()); +}; - delete result; +void ObjectMgr::LoadSpellTemplate() +{ + SQLSpellLoader loader; + loader.Load(sSpellTemplate); + sLog.outString(">> Loaded %u spell definitions", sSpellTemplate.GetRecordCount()); sLog.outString(); - sLog.outString(">> Loaded %u weather definitions", count); + + for (uint32 i = 1; i < sSpellTemplate.GetMaxEntry(); ++i) + { + // check data correctness + SpellEntry const* spellEntry = sSpellTemplate.LookupEntry(i); + if (!spellEntry) + continue; + + // insert serverside spell data + if (sSpellStore.GetNumRows() <= i) + { + sLog.outErrorDb("Loading Spell Template for spell %u, index out of bounds (max = %u)", i, sSpellStore.GetNumRows()); + continue; + } + else + sSpellStore.InsertEntry(const_cast(spellEntry), i); + } } void ObjectMgr::DeleteCreatureData(uint32 guid) @@ -7737,7 +7908,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min { data.SoundId = fields[10].GetUInt32(); data.Type = fields[11].GetUInt32(); - data.Language = fields[12].GetUInt32(); + data.LanguageId = (Language)fields[12].GetUInt32(); data.Emote = fields[13].GetUInt32(); if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId)) @@ -7746,10 +7917,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min data.SoundId = 0; } - if (!GetLanguageDescByID(data.Language)) + if (!GetLanguageDescByID(data.LanguageId)) { - _DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.Language); - data.Language = LANG_UNIVERSAL; + _DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.LanguageId); + data.LanguageId = LANG_UNIVERSAL; } if (data.Type > CHAT_TYPE_ZONE_YELL) @@ -10107,10 +10278,10 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL* switch (data->Type) { case CHAT_TYPE_SAY: - source->MonsterSay(entry, data->Language, target); + source->MonsterSay(entry, data->LanguageId, target); break; case CHAT_TYPE_YELL: - source->MonsterYell(entry, data->Language, target); + source->MonsterYell(entry, data->LanguageId, target); break; case CHAT_TYPE_TEXT_EMOTE: source->MonsterTextEmote(entry, target); @@ -10141,7 +10312,7 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL* break; } case CHAT_TYPE_ZONE_YELL: - source->MonsterYellToZone(entry, data->Language, target); + source->MonsterYellToZone(entry, data->LanguageId, target); break; } diff --git a/src/game/Object/ObjectMgr.h b/src/game/Object/ObjectMgr.h index 235798837..ae20aa7b9 100644 --- a/src/game/Object/ObjectMgr.h +++ b/src/game/Object/ObjectMgr.h @@ -141,12 +141,12 @@ static_assert(MAX_DB_SCRIPT_STRING_ID < ACE_INT32_MAX, "Must scope with int32 ra struct MangosStringLocale { - MangosStringLocale() : SoundId(0), Type(0), Language(0), Emote(0) { } + MangosStringLocale() : SoundId(0), Type(0), LanguageId(LANG_UNIVERSAL), Emote(0) { } std::vector Content; // 0 -> default, i -> i-1 locale index uint32 SoundId; uint8 Type; - uint32 Language; + Language LanguageId; uint32 Emote; // 0 -> default, i -> i-1 locale index }; @@ -333,19 +333,6 @@ struct QuestPOI typedef std::vector QuestPOIVector; typedef UNORDERED_MAP QuestPOIMap; -#define WEATHER_SEASONS 4 -struct WeatherSeasonChances -{ - uint32 rainChance; - uint32 snowChance; - uint32 stormChance; -}; - -struct WeatherZoneChances -{ - WeatherSeasonChances data[WEATHER_SEASONS]; -}; - struct DungeonEncounter { DungeonEncounter(DungeonEncounterEntry const* _dbcEntry, EncounterCreditType _creditType, uint32 _creditEntry, uint32 _lastEncounterDungeon) @@ -359,6 +346,51 @@ struct DungeonEncounter typedef std::multimap DungeonEncounterMap; typedef std::pair DungeonEncounterMapBounds; +struct DungeonFinderRequirements +{ + uint32 minItemLevel; + uint32 item; + uint32 item2; + uint32 allianceQuestId; + uint32 hordeQuestId; + uint32 achievement; + const char* questIncompleteText; + + DungeonFinderRequirements() + : minItemLevel(0), item(0), item2(0), allianceQuestId(0), hordeQuestId(0), achievement(0) {} + DungeonFinderRequirements(uint32 MinItemLevel, uint32 Item, uint32 Item2, uint32 AllianceQuestId, + uint32 HordeQuestId, uint32 Achievement, const char* QuestIncompleteText) + : minItemLevel(MinItemLevel), item(Item), item2(Item2), allianceQuestId(AllianceQuestId), + hordeQuestId(HordeQuestId), achievement(Achievement), questIncompleteText(QuestIncompleteText) {} +}; + +struct DungeonFinderRewards +{ + uint32 baseXPReward; + int32 baseMonetaryReward; + + DungeonFinderRewards() : baseXPReward(0), baseMonetaryReward(0) {} + DungeonFinderRewards(uint32 BaseXPReward, int32 BaseMonetaryReward) : baseXPReward(BaseXPReward), baseMonetaryReward(BaseMonetaryReward) {} +}; + +struct DungeonFinderItems +{ + // sorted by auto-incrementing id + uint32 minLevel; + uint32 maxLevel; + uint32 itemReward; + uint32 itemAmount; + uint32 dungeonType; + + DungeonFinderItems() : minLevel(0), maxLevel(0), itemReward(0), itemAmount(0), dungeonType(0) {} + DungeonFinderItems(uint32 MinLevel, uint32 MaxLevel, uint32 ItemReward, uint32 ItemAmount, uint32 DungeonType) + : minLevel(MinLevel), maxLevel(MaxLevel), itemReward(ItemReward), itemAmount(ItemAmount), dungeonType(DungeonType) {} +}; + +typedef UNORDERED_MAP DungeonFinderRequirementsMap; +typedef UNORDERED_MAP DungeonFinderRewardsMap; +typedef UNORDERED_MAP DungeonFinderItemsMap; + struct GraveYardData { uint32 safeLocId; @@ -548,8 +580,6 @@ class ObjectMgr typedef UNORDERED_MAP PointOfInterestMap; - typedef UNORDERED_MAP WeatherZoneMap; - void LoadGameobjectInfo(); void AddGameobjectInfo(GameObjectInfo* goinfo); @@ -713,6 +743,7 @@ class ObjectMgr void LoadCreatureTemplates(); void LoadCreatures(); void LoadCreatureAddons(); + void LoadCreatureClassLvlStats(); void LoadCreatureModelInfo(); void LoadCreatureModelRace(); void LoadEquipmentTemplates(); @@ -759,10 +790,14 @@ class ObjectMgr void LoadPointsOfInterest(); void LoadQuestPOI(); + void LoadDungeonFinderRequirements(); + void LoadDungeonFinderRewards(); + void LoadDungeonFinderItems(); + void LoadNPCSpellClickSpells(); + void LoadSpellTemplate(); void LoadCreatureTemplateSpells(); - void LoadWeatherZoneChances(); void LoadGameTele(); void LoadNpcGossips(); @@ -826,15 +861,6 @@ class ObjectMgr return NULL; } - WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const - { - WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); - if (itr != mWeatherZoneMap.end()) - return &itr->second; - else - return NULL; - } - CreatureDataPair const* GetCreatureDataPair(uint32 guid) const { CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid); @@ -1217,7 +1243,9 @@ class ObjectMgr QuestPOIMap mQuestPOIMap; - WeatherZoneMap mWeatherZoneMap; + DungeonFinderRequirementsMap mDungeonFinderRequirementsMap; + DungeonFinderRewardsMap mDungeonFinderRewardsMap; + DungeonFinderItemsMap mDungeonFinderItemsMap; // character reserved names typedef std::set ReservedNamesMap; @@ -1277,6 +1305,9 @@ class ObjectMgr HalfNameMap PetHalfName0; HalfNameMap PetHalfName1; + // Array to store creature stats, Max creature level + 1 (for data alignement with in game level) + CreatureClassLvlStats m_creatureClassLvlStats[DEFAULT_MAX_CREATURE_LEVEL + 1][MAX_CREATURE_CLASS][MAX_EXPANSION + 1]; + MapObjectGuids mMapObjectGuids; CreatureDataMap mCreatureDataMap; CreatureLocaleMap mCreatureLocaleMap; diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index b8f85cdf7..85f5aebf4 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -74,6 +74,9 @@ #include "Vehicle.h" #include "Calendar.h" #include "PhaseMgr.h" +#ifdef ENABLE_ELUNA +#include "LuaEngine.h" +#endif /*ENABLE_ELUNA*/ #include @@ -1944,6 +1947,13 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return true; } +void Player::SetRandomWinner(bool isWinner) +{ + m_IsBGRandomWinner = isWinner; + if (m_IsBGRandomWinner) + CharacterDatabase.PExecute("INSERT INTO character_battleground_random (guid) VALUES ('%u')", GetGUIDLow()); +} + bool Player::TeleportToBGEntryPoint() { ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); @@ -6898,8 +6908,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (!zone) return; - phaseMgr->AddUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); - if (m_zoneUpdateId != newZone) { // handle outdoor pvp zones @@ -6910,17 +6918,16 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (sWorld.getConfig(CONFIG_BOOL_WEATHER)) { - if (Weather* wth = sWorld.FindWeather(zone->ID)) - wth->SendWeatherUpdateToPlayer(this); - else if (!sWorld.AddWeather(zone->ID)) - { - // send fine weather packet to remove old zone's weather - Weather::SendFineWeatherUpdateToPlayer(this); - } + Weather* wth = GetMap()->GetWeatherSystem()->FindOrCreateWeather(newZone); + wth->SendWeatherUpdateToPlayer(this); } } - m_zoneUpdateId = newZone; +#ifdef ENABLE_ELUNA + sEluna->OnUpdateZone(this, newZone, newArea); +#endif + + m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; // zone changed, so area changed as well, update it @@ -6930,19 +6937,19 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // in PvE, only opposition team capital switch (zone->team) { - case AREATEAM_ALLY: - pvpInfo.inHostileArea = GetTeam() != ALLIANCE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); - break; - case AREATEAM_HORDE: - pvpInfo.inHostileArea = GetTeam() != HORDE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); - break; - case AREATEAM_NONE: - // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this - pvpInfo.inHostileArea = sWorld.IsPvPRealm() || InBattleGround(); - break; - default: // 6 in fact - pvpInfo.inHostileArea = false; - break; + case AREATEAM_ALLY: + pvpInfo.inHostileArea = GetTeam() != ALLIANCE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); + break; + case AREATEAM_HORDE: + pvpInfo.inHostileArea = GetTeam() != HORDE && (sWorld.IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); + break; + case AREATEAM_NONE: + // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this + pvpInfo.inHostileArea = sWorld.IsPvPRealm() || InBattleGround(); + break; + default: // 6 in fact + pvpInfo.inHostileArea = false; + break; } if (pvpInfo.inHostileArea) // in hostile area @@ -6990,8 +6997,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateZoneDependentAuras(); UpdateZoneDependentPets(); - - phaseMgr->RemoveUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); } // If players are too far way of duel flag... then player loose the duel @@ -14056,18 +14061,6 @@ void Player::CompleteQuest(uint32 quest_id) } } -void Player::IncompleteQuest(uint32 quest_id) -{ - if (quest_id) - { - SetQuestStatus(quest_id, QUEST_STATUS_INCOMPLETE); - - uint16 log_slot = FindQuestSlot(quest_id); - if (log_slot < MAX_QUEST_LOG_SIZE) - RemoveQuestSlotState(log_slot, QUEST_STATE_COMPLETE); - } -} - void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, bool announce) { uint32 quest_id = pQuest->GetQuestId(); @@ -14075,7 +14068,9 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { if (pQuest->ReqItemId[i]) + { DestroyItemCount(pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); + } } for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) @@ -14088,18 +14083,13 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, } } - // take currency - for (uint32 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i) - { - if (pQuest->ReqCurrencyId[i]) - ModifyCurrencyCount(pQuest->ReqCurrencyId[i], -int32(pQuest->ReqCurrencyCount[i] * GetCurrencyPrecision(pQuest->ReqCurrencyId[i]))); - } - RemoveTimedQuest(quest_id); if (BattleGround* bg = GetBattleGround()) - if (bg->GetTypeID() == BATTLEGROUND_AV) + if (bg->GetTypeID(true) == BATTLEGROUND_AV) + { ((BattleGroundAV*)bg)->HandleQuestComplete(pQuest->GetQuestId(), this); + } if (pQuest->GetRewChoiceItemsCount() > 0) { @@ -14134,7 +14124,9 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, uint16 log_slot = FindQuestSlot(quest_id); if (log_slot < MAX_QUEST_LOG_SIZE) + { SetQuestSlot(log_slot, 0); + } QuestStatusData& q_status = mQuestStatus[quest_id]; @@ -14143,7 +14135,7 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, if (getLevel() < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)) { - GiveXP(xp , NULL); + GiveXP(xp, NULL); // Give player extra money (for max level already included in pQuest->GetRewMoneyMaxLevel()) if (pQuest->GetRewOrReqMoney() > 0) @@ -14155,10 +14147,10 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, else { // reward money for max level already included in pQuest->GetRewMoneyMaxLevel() - uint64 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY)); + uint32 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY)); // reward money used if > xp replacement money - if (pQuest->GetRewOrReqMoney() > int64(money)) + if (pQuest->GetRewOrReqMoney() > int32(money)) money = pQuest->GetRewOrReqMoney(); ModifyMoney(money); @@ -14169,16 +14161,9 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, if (pQuest->GetRewOrReqMoney() < 0) ModifyMoney(pQuest->GetRewOrReqMoney()); - // reward currency - for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i) - { - if (pQuest->RewCurrencyId[i]) - ModifyCurrencyCount(pQuest->RewCurrencyId[i], int32(pQuest->RewCurrencyCount[i] * GetCurrencyPrecision(pQuest->RewCurrencyId[i]))); - } - - // reward skill - if (uint32 skill = pQuest->GetRewSkill()) - UpdateSkill(skill, pQuest->GetRewSkillValue()); + // honor reward + if (uint32 honor = pQuest->CalculateRewardHonor(getLevel())) + RewardHonor(NULL, 0, honor); // title reward if (pQuest->GetCharTitleId()) @@ -14219,18 +14204,18 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, q_status.uState = QUEST_CHANGED; if (announce) - SendQuestReward(pQuest, xp, questGiver); + SendQuestReward(pQuest, xp); bool handled = false; switch (questGiver->GetTypeId()) { - case TYPEID_UNIT: - handled = sScriptMgr.OnQuestRewarded(this, (Creature*)questGiver, pQuest); - break; - case TYPEID_GAMEOBJECT: - handled = sScriptMgr.OnQuestRewarded(this, (GameObject*)questGiver, pQuest); - break; + case TYPEID_UNIT: + handled = sScriptMgr.OnQuestRewarded(this, reinterpret_cast(questGiver), pQuest, reward); + break; + case TYPEID_GAMEOBJECT: + handled = sScriptMgr.OnQuestRewarded(this, reinterpret_cast(questGiver), pQuest, reward); + break; } if (!handled && pQuest->GetQuestCompleteScript() != 0) @@ -14248,8 +14233,6 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, pQuest->GetQuestId()); - UpdateForQuestWorldObjects(); - // remove auras from spells with quest reward state limitations // Some spells applied at quest reward uint32 zone, area; @@ -14266,11 +14249,18 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, saBounds = sSpellMgr.GetSpellAreaForAreaMapBounds(0); for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) itr->second->ApplyOrRemoveSpellIfCan(this, zone, area, false); +} - PhaseUpdateData phaseUdateData; - phaseUdateData.AddQuestUpdate(quest_id); +void Player::IncompleteQuest(uint32 quest_id) +{ + if (quest_id) + { + SetQuestStatus(quest_id, QUEST_STATUS_INCOMPLETE); - phaseMgr->NotifyConditionChanged(phaseUdateData); + uint16 log_slot = FindQuestSlot(quest_id); + if (log_slot < MAX_QUEST_LOG_SIZE) + RemoveQuestSlotState(log_slot, QUEST_STATE_COMPLETE); + } } void Player::FailQuest(uint32 questId) @@ -15418,7 +15408,34 @@ void Player::SendQuestCompleteEvent(uint32 quest_id) } } -void Player::SendQuestReward(Quest const* pQuest, uint32 XP, Object* /*questGiver*/) +void Player::SendQuestReward(Quest const* pQuest, uint32 XP) +{ + uint32 questid = pQuest->GetQuestId(); + DEBUG_LOG("WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid); + WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4 + 4 + 4 + 4 + 4)); + data << uint32(questid); + + if (getLevel() < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)) + { + data << uint32(XP); + data << uint32(pQuest->GetRewOrReqMoney()); + } + else + { + data << uint32(0); + data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY))); + } + + data << uint32(10 * MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorAddition())); + data << uint32(pQuest->GetBonusTalents()); // bonus talents + data << uint32(0); // arena points + GetSession()->SendPacket(&data); +} + +// Delete this if the above works +// the above was added for deve21 (chucky) +//void Player::SendQuestReward(Quest const* pQuest, uint32 XP, Object* /*questGiver*/) +/* { uint32 questid = pQuest->GetQuestId(); DEBUG_LOG("WORLD: Sent SMSG_QUESTGIVER_QUEST_COMPLETE quest = %u", questid); @@ -15436,7 +15453,6 @@ void Player::SendQuestReward(Quest const* pQuest, uint32 XP, Object* /*questGive data << uint32(pQuest->GetRewOrReqMoney() + int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY))); data << uint32(0); } - data << uint32(questid); data << uint32(pQuest->GetRewSkill()); @@ -15445,6 +15461,7 @@ void Player::SendQuestReward(Quest const* pQuest, uint32 XP, Object* /*questGive GetSession()->SendPacket(&data); } +*/ void Player::SendQuestFailed(uint32 quest_id, InventoryResult reason) { diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index 724f44b39..16c8d1f57 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -1047,6 +1047,8 @@ class Player : public Unit bool TeleportToBGEntryPoint(); + void SetRandomWinner(bool isWinner); + void SetSummonPoint(uint32 mapid, float x, float y, float z) { m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; @@ -1364,7 +1366,7 @@ class Player : public Unit void AddQuest(Quest const* pQuest, Object* questGiver); void CompleteQuest(uint32 quest_id); void IncompleteQuest(uint32 quest_id); - void RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, bool announce = true); + void RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, bool announce); void FailQuest(uint32 quest_id); bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const; @@ -1449,7 +1451,8 @@ class Player : public Unit bool CanShareQuest(uint32 quest_id) const; void SendQuestCompleteEvent(uint32 quest_id); - void SendQuestReward(Quest const* pQuest, uint32 XP, Object* questGiver); + void SendQuestReward(Quest const* pQuest, uint32 XP); + // void SendQuestReward(Quest const* pQuest, uint32 XP, Object* questGiver); // delete this if the above works (chucky) void SendQuestFailed(uint32 quest_id, InventoryResult reason = EQUIP_ERR_OK); void SendQuestTimerFailed(uint32 quest_id); void SendCanTakeQuestResponse(uint32 msg) const; @@ -2192,6 +2195,8 @@ class Player : public Unit // returns true if the player is in active state for capture point capturing bool CanUseCapturePoint(); + bool m_IsBGRandomWinner; + /*********************************************************/ /*** REST SYSTEM ***/ /*********************************************************/ diff --git a/src/game/Object/UpdateFields.h b/src/game/Object/UpdateFields.h index 6dc4d254f..ed01df82a 100644 --- a/src/game/Object/UpdateFields.h +++ b/src/game/Object/UpdateFields.h @@ -129,7 +129,7 @@ enum EUnitFields UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x87, UNIT_FIELD_MAXITEMLEVEL = OBJECT_END + 0x88, UNIT_FIELD_PADDING = OBJECT_END + 0x89, - UNIT_END = OBJECT_END + 0x8A + UNIT_END = OBJECT_END + 0x008E, }; enum EItemFields diff --git a/src/game/Server/DBCStructure.h b/src/game/Server/DBCStructure.h index e58d579ab..e03f3e6a5 100644 --- a/src/game/Server/DBCStructure.h +++ b/src/game/Server/DBCStructure.h @@ -2095,6 +2095,11 @@ struct SpellEntry bool IsFitToFamilyMask(SpellFamily family, T t) const; }; +// A few fields which are required for automated convertion +// NOTE that these fields are count by _skipping_ the fields that are unused! +#define LOADED_SPELLDBC_FIELD_POS_EQUIPPED_ITEM_CLASS 65 // Must be converted to -1 +#define LOADED_SPELLDBC_FIELD_POS_SPELLNAME_0 132 // Links to "MaNGOS server-side spell" + struct SpellCastTimesEntry { uint32 ID; // 0 m_ID diff --git a/src/game/Server/SQLStorages.cpp b/src/game/Server/SQLStorages.cpp index e6616fd36..058404a36 100644 --- a/src/game/Server/SQLStorages.cpp +++ b/src/game/Server/SQLStorages.cpp @@ -42,6 +42,9 @@ const char WorldTemplatesrcfmt[] = "is"; const char WorldTemplatedstfmt[] = "ii"; const char ConditionsSrcFmt[] = "iiii"; const char ConditionsDstFmt[] = "iiii"; +const char SpellTemplatesrcfmt[] = "iiiiiiiiiiiiiiiix"; +// 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 185 +const char SpellTemplatedstfmt[] = "ixxxiiiixxxxxxxxxxxxxxxxxxxxxxxxiixxxxixxxxxxFxxxxxxxxxxxxxxxxxxxxxxixxxxxFFFxxxxxxixxixxixxixxxxxFFFxxxxxxixxixxixxFFFxxxxxxxxxxxxxppppppppppppppppppppppppppppppppxxxxxxxxxxxFFFxxxxxx"; const char VehicleAccessorySrcFmt[] = "iiix"; const char VehicleAccessoryDstFmt[] = "iii"; const char CreatureTemplateSpellsFmt[] = "iiiiiiiiiii"; @@ -60,6 +63,7 @@ SQLStorage sConditionStorage(ConditionsSrcFmt, ConditionsDstFmt, "condition_entr SQLHashStorage sGameObjectDataAddonStorage(GameObjectInfoAddonInfofmt, "guid", "gameobject_addon"); SQLHashStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry", "gameobject_template"); +SQLHashStorage sSpellTemplate(SpellTemplatesrcfmt, SpellTemplatedstfmt, "id", "spell_template"); SQLHashStorage sCreatureTemplateSpellsStorage(CreatureTemplateSpellsFmt, "entry", "creature_template_spells"); SQLMultiStorage sVehicleAccessoryStorage(VehicleAccessorySrcFmt, VehicleAccessoryDstFmt, "vehicle_entry", "vehicle_accessory"); diff --git a/src/game/Server/SQLStorages.h b/src/game/Server/SQLStorages.h index 9b13343b5..36b7b8e4a 100644 --- a/src/game/Server/SQLStorages.h +++ b/src/game/Server/SQLStorages.h @@ -39,6 +39,7 @@ extern SQLStorage sInstanceTemplate; extern SQLStorage sWorldTemplate; extern SQLStorage sConditionStorage; +extern SQLHashStorage sSpellTemplate; extern SQLHashStorage sGOStorage; extern SQLHashStorage sGameObjectDataAddonStorage; extern SQLHashStorage sCreatureTemplateSpellsStorage; diff --git a/src/game/Server/SharedDefines.h b/src/game/Server/SharedDefines.h index 31bcedbcc..ac37b250c 100644 --- a/src/game/Server/SharedDefines.h +++ b/src/game/Server/SharedDefines.h @@ -113,6 +113,11 @@ enum Classes (1<<(CLASS_DEATH_KNIGHT-1)) ) #define CLASSMASK_ALL_CREATURES ((1<<(CLASS_WARRIOR-1)) | (1<<(CLASS_PALADIN-1)) | (1<<(CLASS_ROGUE-1)) | (1<<(CLASS_MAGE-1)) ) +#define MAX_CREATURE_CLASS 4 + +// array index could be used to store class data only Warrior, Paladin, Rogue and Mage are indexed for creature +// W P R M +static const uint8 classToIndex[MAX_CLASSES] = { 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0 }; #define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1))) @@ -3774,7 +3779,16 @@ enum MaxLevel static const MaxLevel maxLevelForExpansion[MAX_EXPANSION + 1] = { MAX_LEVEL_CLASSIC, MAX_LEVEL_TBC, MAX_LEVEL_WOTLK, MAX_LEVEL_CATACLYSM }; +// Max creature level (included some bosses and elite) +#define DEFAULT_MAX_CREATURE_LEVEL 85 + // This spell is used for general boarding serverside #define SPELL_RIDE_VEHICLE_HARDCODED 46598 +enum TeleportLocation +{ + TELEPORT_LOCATION_HOMEBIND = 0, + TELEPORT_LOCATION_BG_ENTRY_POINT = 1, +}; + #endif diff --git a/src/game/Tools/Language.h b/src/game/Tools/Language.h index e0dac7fad..f4dc37368 100644 --- a/src/game/Tools/Language.h +++ b/src/game/Tools/Language.h @@ -742,12 +742,13 @@ enum MangosStrings LANG_DEBUG_ARENA_OFF = 738, LANG_DEBUG_BG_ON = 739, LANG_DEBUG_BG_OFF = 740, -// = 741, not used -// = 742, not used -// = 743, not used -// = 744, not used -// = 745, not used -// = 746, not used + + LANG_DIST_ARENA_POINTS_START = 741, + LANG_DIST_ARENA_POINTS_ONLINE_START = 742, + LANG_DIST_ARENA_POINTS_ONLINE_END = 743, + LANG_DIST_ARENA_POINTS_TEAM_START = 744, + LANG_DIST_ARENA_POINTS_TEAM_END = 745, + LANG_DIST_ARENA_POINTS_END = 746, // = 747, not used // = 748, not used // = 749, not used diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index fb013f96c..c17d56fb9 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -45,16 +45,27 @@ #include "BattleGround/BattleGroundMgr.h" #include "Weather.h" #include "Calendar.h" +#ifdef ENABLE_ELUNA +#include "LuaEngine.h" +#endif /* ENABLE_ELUNA */ Map::~Map() { +#ifdef ENABLE_ELUNA + sEluna->OnDestroy(this); +#endif /* ENABLE_ELUNA */ + UnloadAll(true); if (!m_scriptSchedule.empty()) + { sScriptMgr.DecreaseScheduledScriptCount(m_scriptSchedule.size()); + } if (m_persistentState) - m_persistentState->SetUsedByMapState(NULL); // field pointer can be deleted after this + { + m_persistentState->SetUsedByMapState(NULL); + } // field pointer can be deleted after this delete i_data; i_data = NULL; @@ -64,7 +75,12 @@ Map::~Map() // release reference count if (m_TerrainData->Release()) + { sTerrainMgr.UnloadTerrain(m_TerrainData->GetMapId()); + } + + delete m_weatherSystem; + m_weatherSystem = NULL; } void Map::LoadMapAndVMap(int gx, int gy) @@ -667,8 +683,7 @@ Map::Remove(T* obj, bool remove) } } -void -Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation) +void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation) { MANGOS_ASSERT(player); @@ -788,7 +803,9 @@ bool Map::UnloadGrid(const uint32& x, const uint32& y, bool pForce) { if (!pForce && ActiveObjectsNearGrid(x, y)) + { return false; + } DEBUG_FILTER_LOG(LOG_FILTER_MAP_LOADING, "Unloading grid[%u,%u] for map %u", x, y, i_id); ObjectGridUnloader unloader(*grid); @@ -1927,7 +1944,7 @@ class StaticMonsterChatBuilder * @param language language of the text * @param target, can be NULL */ -void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit const* target) const +void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, Language language, Unit const* target) const { if (guid.IsAnyTypeCreature()) { @@ -1958,14 +1975,16 @@ void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit * @param senderLowGuid provide way proper show yell for near spawned creature with known lowguid, * 0 accepted by client else if this not important */ -void Map::MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid /*= 0*/) const +void Map::MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, Language language, Unit const* target, uint32 senderLowGuid /*= 0*/) const { StaticMonsterChatBuilder say_build(cinfo, CHAT_MSG_MONSTER_YELL, textId, language, target, senderLowGuid); MaNGOS::LocalizedPacketDo say_do(say_build); Map::PlayerList const& pList = GetPlayers(); for (PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) + { say_do(itr->getSource()); + } } /** diff --git a/src/game/WorldHandlers/Map.h b/src/game/WorldHandlers/Map.h index 2a999dddc..ddfbd2490 100644 --- a/src/game/WorldHandlers/Map.h +++ b/src/game/WorldHandlers/Map.h @@ -102,197 +102,217 @@ enum LevelRequirementVsMode class Map : public GridRefManager { - friend class MapReference; - friend class ObjectGridLoader; - friend class ObjectWorldLoader; + friend class MapReference; + friend class ObjectGridLoader; + friend class ObjectWorldLoader; - protected: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); +protected: + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); - public: - virtual ~Map(); +public: + virtual ~Map(); - // currently unused for normal maps - bool CanUnload(uint32 diff) - { - if (!m_unloadTimer) return false; - if (m_unloadTimer <= diff) return true; - m_unloadTimer -= diff; - return false; - } + // currently unused for normal maps + bool CanUnload(uint32 diff) + { + if (!m_unloadTimer) { return false; } + if (m_unloadTimer <= diff) { return true; } + m_unloadTimer -= diff; + return false; + } - virtual bool Add(Player*); - virtual void Remove(Player*, bool); - template void Add(T*); - template void Remove(T*, bool); + virtual bool Add(Player*); + virtual void Remove(Player*, bool); + template void Add(T*); + template void Remove(T*, bool); - static void DeleteFromWorld(Player* player); // player object will deleted at call + static void DeleteFromWorld(Player* player); // player object will deleted at call - virtual void Update(const uint32&); + virtual void Update(const uint32&); - void MessageBroadcast(Player const*, WorldPacket*, bool to_self); - void MessageBroadcast(WorldObject const*, WorldPacket*); - void MessageDistBroadcast(Player const*, WorldPacket*, float dist, bool to_self, bool own_team_only = false); - void MessageDistBroadcast(WorldObject const*, WorldPacket*, float dist); + void MessageBroadcast(Player const*, WorldPacket*, bool to_self); + void MessageBroadcast(WorldObject const*, WorldPacket*); + void MessageDistBroadcast(Player const*, WorldPacket*, float dist, bool to_self, bool own_team_only = false); + void MessageDistBroadcast(WorldObject const*, WorldPacket*, float dist); - float GetVisibilityDistance() const { return m_VisibleDistance; } - // function for setting up visibility distance for maps on per-type/per-Id basis - virtual void InitVisibilityDistance(); + float GetVisibilityDistance() const { return m_VisibleDistance; } + // function for setting up visibility distance for maps on per-type/per-Id basis + virtual void InitVisibilityDistance(); - void PlayerRelocation(Player*, float x, float y, float z, float angl); - void CreatureRelocation(Creature* creature, float x, float y, float z, float orientation); + void PlayerRelocation(Player*, float x, float y, float z, float angl); + void CreatureRelocation(Creature* creature, float x, float y, float z, float orientation); - template void Visit(const Cell& cell, TypeContainerVisitor &visitor); + template void Visit(const Cell& cell, TypeContainerVisitor& visitor); - bool IsRemovalGrid(float x, float y) const - { - GridPair p = MaNGOS::ComputeGridPair(x, y); - return (!getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL); - } + bool IsRemovalGrid(float x, float y) const + { + GridPair p = MaNGOS::ComputeGridPair(x, y); + return(!getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL); + } - bool IsLoaded(float x, float y) const - { - GridPair p = MaNGOS::ComputeGridPair(x, y); - return loaded(p); - } + bool IsLoaded(float x, float y) const + { + GridPair p = MaNGOS::ComputeGridPair(x, y); + return loaded(p); + } - bool GetUnloadLock(const GridPair& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } - void SetUnloadLock(const GridPair& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } - void LoadGrid(const Cell& cell, bool no_unload = false); - bool UnloadGrid(const uint32& x, const uint32& y, bool pForce); - virtual void UnloadAll(bool pForce); + bool GetUnloadLock(const GridPair& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } + void SetUnloadLock(const GridPair& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } + void LoadGrid(const Cell& cell, bool no_unload = false); + bool UnloadGrid(const uint32& x, const uint32& y, bool pForce); + virtual void UnloadAll(bool pForce); - void ResetGridExpiry(NGridType& grid, float factor = 1) const - { - grid.ResetTimeTracker((time_t)((float)i_gridExpiry * factor)); - } + void ResetGridExpiry(NGridType& grid, float factor = 1) const + { + grid.ResetTimeTracker((time_t)((float)i_gridExpiry * factor)); + } - time_t GetGridExpiry(void) const { return i_gridExpiry; } - uint32 GetId(void) const { return i_id; } + time_t GetGridExpiry(void) const { return i_gridExpiry; } + uint32 GetId(void) const { return i_id; } - // 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 + // 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 - virtual void RemoveAllObjectsInRemoveList(); + virtual void RemoveAllObjectsInRemoveList(); - bool CreatureRespawnRelocation(Creature* c); // used only in CreatureRelocation and ObjectGridUnloader + bool CreatureRespawnRelocation(Creature* c); // used only in CreatureRelocation and ObjectGridUnloader - bool CheckGridIntegrity(Creature* c, bool moved) const; + bool CheckGridIntegrity(Creature* c, bool moved) const; - uint32 GetInstanceId() const { return i_InstanceId; } - virtual bool CanEnter(Player* player); - const char* GetMapName() const; + uint32 GetInstanceId() const { return i_InstanceId; } + virtual bool CanEnter(Player* player); + const char* GetMapName() const; - // have meaning only for instanced map (that have set real difficulty), NOT USE its for BaseMap - // _currently_ spawnmode == difficulty, but this can be changes later, so use appropriate spawnmode/difficult functions - // for simplify later code support - // regular difficulty = continent/dungeon normal/first raid normal difficulty - uint8 GetSpawnMode() const { return (i_spawnMode); } - Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } - bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } - uint32 GetMaxPlayers() const; // dependent from map difficulty - uint32 GetMaxResetDelay() const; // dependent from map difficulty - MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty + // have meaning only for instanced map (that have set real difficulty), NOT USE its for BaseMap + // _currently_ spawnmode == difficulty, but this can be changes later, so use appropriate spawnmode/difficult functions + // for simplify later code support + // regular difficulty = continent/dungeon normal/first raid normal difficulty + uint8 GetSpawnMode() const { return (i_spawnMode); } + Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } + bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } + uint32 GetMaxPlayers() const; // dependent from map difficulty + uint32 GetMaxResetDelay() const; // dependent from map difficulty + MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty - bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } - // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable - bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } - bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } - bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } - bool IsRaidOrHeroicDungeon() const { return IsRaid() || GetDifficulty() > DUNGEON_DIFFICULTY_NORMAL; } - bool IsHeroic() const { return IsRaid() || i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } - bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } - bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } - bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } + bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } + // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable + bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } + bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } + bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } + bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } + bool IsRaidOrHeroicDungeon() const { return IsRaid() || GetDifficulty() > DUNGEON_DIFFICULTY_NORMAL; } + bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } + bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } + bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } - // can't be NULL for loaded map - MapPersistentState* GetPersistentState() const { return m_persistentState; } + // can't be NULL for loaded map + MapPersistentState* GetPersistentState() const { return m_persistentState; } - void AddObjectToRemoveList(WorldObject* obj); + void AddObjectToRemoveList(WorldObject* obj); - void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); + void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); - void resetMarkedCells() { marked_cells.reset(); } - bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } - void markCell(uint32 pCellId) { marked_cells.set(pCellId); } + void resetMarkedCells() { marked_cells.reset(); } + bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } + void markCell(uint32 pCellId) { marked_cells.set(pCellId); } - bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } - uint32 GetPlayersCountExceptGMs() const; - bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; + bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } + uint32 GetPlayersCountExceptGMs() const; + bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; - void SendToPlayers(WorldPacket const* data) const; - bool SendToPlayersInZone(WorldPacket const* data, uint32 zoneId) const; + /// Send a Packet to all players on a map + void SendToPlayers(WorldPacket const* data) const; + /// Send a Packet to all players in a zone. Return false if no player found + bool SendToPlayersInZone(WorldPacket const* data, uint32 zoneId) const; - typedef MapRefManager PlayerList; - PlayerList const& GetPlayers() const { return m_mapRefManager; } + typedef MapRefManager PlayerList; + PlayerList const& GetPlayers() const { return m_mapRefManager; } - // per-map script storage - enum ScriptExecutionParam - { - SCRIPT_EXEC_PARAM_NONE = 0x00, // Start regardless if already started - SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE = 0x01, // Start Script only if not yet started (uniqueness identified by id and source) - SCRIPT_EXEC_PARAM_UNIQUE_BY_TARGET = 0x02, // Start Script only if not yet started (uniqueness identified by id and target) - SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE_TARGET = 0x03, // Start Script only if not yet started (uniqueness identified by id, source and target) - }; - bool ScriptsStart(ScriptMapMapName const& scripts, uint32 id, Object* source, Object* target, ScriptExecutionParam execParams = SCRIPT_EXEC_PARAM_NONE); - void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); + // per-map script storage + enum ScriptExecutionParam + { + SCRIPT_EXEC_PARAM_NONE = 0x00, // Start regardless if already started + SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE = 0x01, // Start Script only if not yet started (uniqueness identified by id and source) + SCRIPT_EXEC_PARAM_UNIQUE_BY_TARGET = 0x02, // Start Script only if not yet started (uniqueness identified by id and target) + SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE_TARGET = 0x03, // Start Script only if not yet started (uniqueness identified by id, source and target) + }; + bool ScriptsStart(ScriptMapMapName const& scripts, uint32 id, Object* source, Object* target, ScriptExecutionParam execParams = SCRIPT_EXEC_PARAM_NONE); + void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); - // must called with AddToWorld - void AddToActive(WorldObject* obj); - // must called with RemoveFromWorld - void RemoveFromActive(WorldObject* obj); + // must called with AddToWorld + void AddToActive(WorldObject* obj); + // must called with RemoveFromWorld + void RemoveFromActive(WorldObject* obj); - Player* GetPlayer(ObjectGuid guid); - Creature* GetCreature(ObjectGuid guid); - Pet* GetPet(ObjectGuid guid); - Creature* GetAnyTypeCreature(ObjectGuid guid); // normal creature or pet or vehicle - GameObject* GetGameObject(ObjectGuid guid); - DynamicObject* GetDynamicObject(ObjectGuid guid); - Corpse* GetCorpse(ObjectGuid guid); // !!! find corpse can be not in world - Unit* GetUnit(ObjectGuid guid); // only use if sure that need objects at current map, specially for player case - WorldObject* GetWorldObject(ObjectGuid guid); // only use if sure that need objects at current map, specially for player case + Player* GetPlayer(ObjectGuid guid); + Creature* GetCreature(ObjectGuid guid); + Pet* GetPet(ObjectGuid guid); + Creature* GetAnyTypeCreature(ObjectGuid guid); // normal creature or pet or vehicle + GameObject* GetGameObject(ObjectGuid guid); + DynamicObject* GetDynamicObject(ObjectGuid guid); + Corpse* GetCorpse(ObjectGuid guid); // !!! find corpse can be not in world + Unit* GetUnit(ObjectGuid guid); // only use if sure that need objects at current map, specially for player case + WorldObject* GetWorldObject(ObjectGuid guid); // only use if sure that need objects at current map, specially for player case - typedef TypeUnorderedMapContainer MapStoredObjectTypesContainer; - MapStoredObjectTypesContainer& GetObjectsStore() { return m_objectsStore; } + typedef TypeUnorderedMapContainer MapStoredObjectTypesContainer; + MapStoredObjectTypesContainer& GetObjectsStore() { return m_objectsStore; } - void AddUpdateObject(Object* obj) - { - i_objectsToClientUpdate.insert(obj); - } + void AddUpdateObject(Object* obj) + { + i_objectsToClientUpdate.insert(obj); + } - void RemoveUpdateObject(Object* obj) - { - i_objectsToClientUpdate.erase(obj); - } + void RemoveUpdateObject(Object* obj) + { + i_objectsToClientUpdate.erase(obj); + } - // DynObjects currently - uint32 GenerateLocalLowGuid(HighGuid guidhigh); + // DynObjects currently + uint32 GenerateLocalLowGuid(HighGuid guidhigh); - // get corresponding TerrainData object for this particular map - const TerrainInfo* GetTerrain() const { return m_TerrainData; } + // get corresponding TerrainData object for this particular map + const TerrainInfo* GetTerrain() const { return m_TerrainData; } - void CreateInstanceData(bool load); - InstanceData* GetInstanceData() const { return i_data; } - uint32 GetScriptId() const { return i_script_id; } + void CreateInstanceData(bool load); + InstanceData* GetInstanceData() const { return i_data; } + virtual uint32 GetScriptId() const { return sScriptMgr.GetBoundScriptId(SCRIPTED_MAP, GetId()); } - void MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit const* target) const; - void MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0) const; - void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0) const; + void MonsterYellToMap(ObjectGuid guid, int32 textId, Language language, Unit const* target) const; + void MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, Language language, Unit const* target, uint32 senderLowGuid = 0) const; + void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0) const; - // Dynamic VMaps - float GetHeight(uint32 phasemask, float x, float y, float z) const; - bool IsInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const; - bool GetHitPosition(float srcX, float srcY, float srcZ, float& destX, float& destY, float& destZ, uint32 phasemask, float modifyDist) const; + // Dynamic VMaps + float GetHeight(uint32 phasemask, float x, float y, float z) const; + bool GetHeightInRange(uint32 phasemask, float x, float y, float& z, float maxSearchDist = 4.0f) const; + bool IsInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const; + bool GetHitPosition(float srcX, float srcY, float srcZ, float& destX, float& destY, float& destZ, uint32 phasemask, float modifyDist) const; - // Object Model insertion/remove/test for dynamic vmaps use - void InsertGameObjectModel(const GameObjectModel& mdl); - void RemoveGameObjectModel(const GameObjectModel& mdl); - bool ContainsGameObjectModel(const GameObjectModel& mdl) const; + // Object Model insertion/remove/test for dynamic vmaps use + void InsertGameObjectModel(const GameObjectModel& mdl); + void RemoveGameObjectModel(const GameObjectModel& mdl); + bool ContainsGameObjectModel(const GameObjectModel& mdl) const; - // Get Holder for Creature Linking - CreatureLinkingHolder* GetCreatureLinkingHolder() { return &m_creatureLinkingHolder; } + // Get Holder for Creature Linking + CreatureLinkingHolder* GetCreatureLinkingHolder() { return &m_creatureLinkingHolder; } - void SetWeather(uint32 zoneId, WeatherType type, float grade, bool permanently); + // Teleport all players in that map to choosed location + void TeleportAllPlayersTo(TeleportLocation loc); + + // WeatherSystem + WeatherSystem* GetWeatherSystem() const { return m_weatherSystem; } + /** Set the weather in a zone on this map + * @param zoneId set the weather for which zone + * @param type What weather to set + * @param grade how strong the weather should be + * @param permanently set the weather permanently? + */ + void SetWeather(uint32 zoneId, WeatherType type, float grade, bool permanently); + + // Random on map generation + bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius); + bool GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius); + bool GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius); + bool GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status); private: void LoadMapAndVMap(int gx, int gy); @@ -392,72 +412,76 @@ class Map : public GridRefManager WeatherSystem* m_weatherSystem; }; -class WorldMap : public Map +class WorldMap : public Map { - private: - using Map::GetPersistentState; // hide in subclass for overwrite - public: - WorldMap(uint32 id, time_t expiry) : Map(id, expiry, 0, REGULAR_DIFFICULTY) {} - ~WorldMap() {} +private: + using Map::GetPersistentState; // hide in subclass for overwrite +public: + WorldMap(uint32 id, time_t expiry) : Map(id, expiry, 0, REGULAR_DIFFICULTY) {} + ~WorldMap() {} - // can't be NULL for loaded map - WorldPersistentState* GetPersistanceState() const; + // can't be NULL for loaded map + WorldPersistentState* GetPersistanceState() const; }; -class DungeonMap : public Map +class DungeonMap : public Map { - private: - using Map::GetPersistentState; // hide in subclass for overwrite - public: - DungeonMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); - ~DungeonMap(); - bool Add(Player*) override; - void Remove(Player*, bool) override; - void Update(const uint32&) override; - bool Reset(InstanceResetMethod method); - void PermBindAllPlayers(Player* player); - void UnloadAll(bool pForce) override; - void SendResetWarnings(uint32 timeLeft) const; - void SetResetSchedule(bool on); +private: + using Map::GetPersistentState; // hide in subclass for overwrite +public: + DungeonMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); + ~DungeonMap(); + bool Add(Player*) override; + void Remove(Player*, bool) override; + void Update(const uint32&) override; + bool Reset(InstanceResetMethod method); + void PermBindAllPlayers(Player* player); + void UnloadAll(bool pForce) override; + void SendResetWarnings(uint32 timeLeft) const; + void SetResetSchedule(bool on); - // can't be NULL for loaded map - DungeonPersistentState* GetPersistanceState() const; + uint32 GetScriptId() const override { return sScriptMgr.GetBoundScriptId(SCRIPTED_INSTANCE, GetId()); } - virtual void InitVisibilityDistance() override; - private: - bool m_resetAfterUnload; - bool m_unloadWhenEmpty; + // can't be NULL for loaded map + DungeonPersistentState* GetPersistanceState() const; + + virtual void InitVisibilityDistance() override; +private: + bool m_resetAfterUnload; + bool m_unloadWhenEmpty; }; -class BattleGroundMap : public Map +class BattleGroundMap : public Map { - private: - using Map::GetPersistentState; // hide in subclass for overwrite - public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId, uint8 spawnMode); - ~BattleGroundMap(); +private: + using Map::GetPersistentState; // hide in subclass for overwrite +public: + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, uint8 spawnMode); + ~BattleGroundMap(); - void Update(const uint32&) override; - bool Add(Player*) override; - void Remove(Player*, bool) override; - bool CanEnter(Player* player) override; - void SetUnload(); - void UnloadAll(bool pForce) override; + void Update(const uint32&) override; + bool Add(Player*) override; + void Remove(Player*, bool) override; + bool CanEnter(Player* player) override; + void SetUnload(); + void UnloadAll(bool pForce) override; - virtual void InitVisibilityDistance() override; - BattleGround* GetBG() { return m_bg; } - void SetBG(BattleGround* bg) { m_bg = bg; } + virtual void InitVisibilityDistance() override; + BattleGround* GetBG() { return m_bg; } + void SetBG(BattleGround* bg) { m_bg = bg; } - // can't be NULL for loaded map - BattleGroundPersistentState* GetPersistanceState() const; + uint32 GetScriptId() const override { return sScriptMgr.GetBoundScriptId(SCRIPTED_BATTLEGROUND, GetId()); } //TODO bind BG scripts through script_binding, now these are broken! - private: - BattleGround* m_bg; + // can't be NULL for loaded map + BattleGroundPersistentState* GetPersistanceState() const; + +private: + BattleGround* m_bg; }; template inline void -Map::Visit(const Cell& cell, TypeContainerVisitor &visitor) +Map::Visit(const Cell& cell, TypeContainerVisitor& visitor) { const uint32 x = cell.GridX(); const uint32 y = cell.GridY(); @@ -470,4 +494,4 @@ Map::Visit(const Cell& cell, TypeContainerVisitor &visitor) getNGrid(x, y)->Visit(cell_x, cell_y, visitor); } } -#endif +#endif \ No newline at end of file diff --git a/src/game/WorldHandlers/QuestHandler.cpp b/src/game/WorldHandlers/QuestHandler.cpp index 45c7378fc..91899f1e0 100644 --- a/src/game/WorldHandlers/QuestHandler.cpp +++ b/src/game/WorldHandlers/QuestHandler.cpp @@ -265,7 +265,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recv_data) { if (_player->CanRewardQuest(pQuest, reward, true)) { - _player->RewardQuest(pQuest, reward, pObject); + _player->RewardQuest(pQuest, reward, pObject, false); // Send next quest if (Quest const* nextquest = _player->GetNextQuest(guid, pQuest)) diff --git a/src/game/WorldHandlers/ScriptMgr.cpp b/src/game/WorldHandlers/ScriptMgr.cpp index 1d8885d00..260fe1503 100644 --- a/src/game/WorldHandlers/ScriptMgr.cpp +++ b/src/game/WorldHandlers/ScriptMgr.cpp @@ -38,6 +38,15 @@ #include "OutdoorPvP/OutdoorPvP.h" #include "WaypointMovementGenerator.h" +#ifdef ENABLE_ELUNA +#include "LuaEngine.h" +#endif /* ENABLE_ELUNA */ +#ifdef ENABLE_SD3 +#include "system/ScriptDevMgr.h" +#endif + +#include /* std::strcmp */ + #include "revision.h" ScriptMapMapName sQuestEndScripts; @@ -53,44 +62,12 @@ ScriptMapMapName sCreatureMovementScripts; INSTANTIATE_SINGLETON_1(ScriptMgr); ScriptMgr::ScriptMgr() : - m_hScriptLib(NULL), - m_scheduledScripts(0), - - m_pOnInitScriptLibrary(NULL), - m_pOnFreeScriptLibrary(NULL), - m_pGetScriptLibraryVersion(NULL), - - m_pGetCreatureAI(NULL), - m_pCreateInstanceData(NULL), - - m_pOnGossipHello(NULL), - m_pOnGOGossipHello(NULL), - m_pOnGossipSelect(NULL), - m_pOnGOGossipSelect(NULL), - m_pOnGossipSelectWithCode(NULL), - m_pOnGOGossipSelectWithCode(NULL), - m_pOnQuestAccept(NULL), - m_pOnGOQuestAccept(NULL), - m_pOnItemQuestAccept(NULL), - m_pOnQuestRewarded(NULL), - m_pOnGOQuestRewarded(NULL), - m_pGetNPCDialogStatus(NULL), - m_pGetGODialogStatus(NULL), - m_pOnGOUse(NULL), - m_pOnItemUse(NULL), - m_pOnAreaTrigger(NULL), - m_pOnProcessEvent(NULL), - m_pOnEffectDummyCreature(NULL), - m_pOnEffectDummyGO(NULL), - m_pOnEffectDummyItem(NULL), - m_pOnEffectScriptEffectCreature(NULL), - m_pOnAuraDummy(NULL) + m_scheduledScripts(0) { } ScriptMgr::~ScriptMgr() { - UnloadScriptLibrary(); } // ///////////////////////////////////////////////////////// @@ -1807,25 +1784,28 @@ bool ScriptAction::HandleScriptStep() // Scripting Library Hooks // ///////////////////////////////////////////////////////// -void ScriptMgr::LoadAreaTriggerScripts() +void ScriptMgr::LoadScriptBinding() { - m_AreaTriggerScripts.clear(); // need for reload case - QueryResult* result = WorldDatabase.Query("SELECT entry, ScriptName FROM scripted_areatrigger"); +#ifdef ENABLE_SD3 + for (int i = 0; i < SCRIPTED_MAX_TYPE; ++i) + m_scriptBind[i].clear(); + QueryResult* result = WorldDatabase.PQuery("SELECT type, bind, ScriptName, data FROM script_binding"); uint32 count = 0; if (!result) { BarGoLink bar(1); bar.step(); - + sLog.outString(">> Loaded no script binding."); sLog.outString(); - sLog.outString(">> Loaded %u scripted areatrigger", count); return; } - BarGoLink bar(result->GetRowCount()); + std::set eventIds; // Store possible event ids, for checking + CollectPossibleEventIds(eventIds); + BarGoLink bar(result->GetRowCount()); do { ++count; @@ -1833,96 +1813,107 @@ void ScriptMgr::LoadAreaTriggerScripts() Field* fields = result->Fetch(); - uint32 triggerId = fields[0].GetUInt32(); - const char* scriptName = fields[1].GetString(); + uint8 type = fields[0].GetUInt8(); + int32 id = fields[1].GetInt32(); + const char* scriptName = fields[2].GetString(); + uint8 data = fields[3].GetUInt8(); - if (!sAreaTriggerStore.LookupEntry(triggerId)) + if (type >= SCRIPTED_MAX_TYPE) { - sLog.outErrorDb("Table `scripted_areatrigger` has area trigger (ID: %u) not listed in `AreaTrigger.dbc`.", triggerId); + sLog.outErrorScriptLib("script_binding table contains a script for non-existent type %u (bind %d), ignoring.", type, id); + continue; + } + uint32 scriptId = GetScriptId(scriptName); + if (!scriptId) //this should never happen! the script names are initialized from the same table + { + sLog.outErrorScriptLib("something is very bad with your script_binding table!"); continue; } - m_AreaTriggerScripts[triggerId] = GetScriptId(scriptName); - } - while (result->NextRow()); + // checking if the scripted object actually exists + bool exists = false; + switch (type) + { + case SCRIPTED_UNIT: + exists = id > 0 ? bool(sCreatureStorage.LookupEntry(uint32(id))) : bool(sObjectMgr.GetCreatureData(uint32(-id))); + break; + case SCRIPTED_GAMEOBJECT: + exists = id > 0 ? bool(sGOStorage.LookupEntry(uint32(id))) : bool(sObjectMgr.GetGOData(uint32(-id))); + break; + case SCRIPTED_ITEM: + exists = bool(sItemStorage.LookupEntry(uint32(id))); + break; + case SCRIPTED_AREATRIGGER: + exists = bool(sAreaTriggerStore.LookupEntry(uint32(id))); + break; + case SCRIPTED_SPELL: + case SCRIPTED_AURASPELL: + exists = bool(sSpellStore.LookupEntry(uint32(id))); + break; + case SCRIPTED_MAPEVENT: + exists = eventIds.count(uint32(id)); + break; + case SCRIPTED_MAP: + exists = bool(sMapStore.LookupEntry(uint32(id))); + break; + case SCRIPTED_PVP_ZONE: // for now, no check on special zones + exists = bool(sAreaStore.LookupEntry(uint32(id))); + break; + case SCRIPTED_BATTLEGROUND: + if (MapEntry const* mapEntry = sMapStore.LookupEntry(uint32(id))) + exists = mapEntry->IsBattleGround(); + break; + case SCRIPTED_INSTANCE: + if (MapEntry const* mapEntry = sMapStore.LookupEntry(uint32(id))) + exists = mapEntry->IsDungeon(); + break; + case SCRIPTED_CONDITION: + exists = sConditionStorage.LookupEntry(uint32(id)); + break; + case SCRIPTED_ACHIEVEMENT: + break; + } + + if (!exists) + { + sLog.outErrorScriptLib("script type %u (%s) is bound to non-existing entry %d, ignoring.", type, scriptName, id); + continue; + } + + if (type == SCRIPTED_SPELL || type == SCRIPTED_AURASPELL) + id |= uint32(data) << 24; //incorporate spell effect number into the key + + m_scriptBind[type][id] = scriptId; + } while (result->NextRow()); delete result; + sLog.outString("Of the total %u script bindings, loaded succesfully:", count); + for (uint8 i = 0; i < SCRIPTED_MAX_TYPE; ++i) + { + if (m_scriptBind[i].size()) //ignore missing script types to shorten the log + { + sLog.outString(".. type %u: %u binds", i, uint32(m_scriptBind[i].size())); + count -= m_scriptBind[i].size(); + } + } + sLog.outString("Thus, %u script binds are found bad.", count); sLog.outString(); - sLog.outString(">> Loaded %u areatrigger scripts", count); -} - -void ScriptMgr::LoadEventIdScripts() -{ - m_EventIdScripts.clear(); // need for reload case - QueryResult* result = WorldDatabase.Query("SELECT id, ScriptName FROM scripted_event"); - - uint32 count = 0; - - if (!result) - { - BarGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u scripted event id", count); - return; - } - - BarGoLink bar(result->GetRowCount()); - - std::set eventIds; // Store possible event ids - CollectPossibleEventIds(eventIds); - - do - { - ++count; - bar.step(); - - Field* fields = result->Fetch(); - - uint32 eventId = fields[0].GetUInt32(); - const char* scriptName = fields[1].GetString(); - - std::set::const_iterator itr = eventIds.find(eventId); - if (itr == eventIds.end()) - sLog.outErrorDb("Table `scripted_event` has id %u not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field, type 29 or any spell effect %u or path taxi node data", - eventId, SPELL_EFFECT_SEND_EVENT); - - m_EventIdScripts[eventId] = GetScriptId(scriptName); - } - while (result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u scripted event id", count); +#endif /* ENABLE_SD3 */ + return; } void ScriptMgr::LoadScriptNames() { m_scriptNames.push_back(""); - QueryResult* result = WorldDatabase.Query( - "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM scripted_areatrigger WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM scripted_event WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM instance_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM world_template WHERE ScriptName <> ''"); + QueryResult* result = WorldDatabase.Query("SELECT DISTINCT(ScriptName) FROM script_binding"); if (!result) { BarGoLink bar(1); bar.step(); - sLog.outString(); sLog.outErrorDb(">> Loaded empty set of Script Names!"); + sLog.outString(); return; } @@ -1934,13 +1925,13 @@ void ScriptMgr::LoadScriptNames() bar.step(); m_scriptNames.push_back((*result)[0].GetString()); ++count; - } - while (result->NextRow()); + } while (result->NextRow()); delete result; std::sort(m_scriptNames.begin(), m_scriptNames.end()); + + sLog.outString(">> Loaded %d unique Script Names", count); sLog.outString(); - sLog.outString(">> Loaded %d Script Names", count); } uint32 ScriptMgr::GetScriptId(const char* name) const @@ -1948,281 +1939,410 @@ uint32 ScriptMgr::GetScriptId(const char* name) const // use binary search to find the script name in the sorted vector // assume "" is the first element if (!name) + { return 0; + } ScriptNameMap::const_iterator itr = std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name); if (itr == m_scriptNames.end() || *itr != name) + { return 0; + } return uint32(itr - m_scriptNames.begin()); } -uint32 ScriptMgr::GetAreaTriggerScriptId(uint32 triggerId) const -{ - AreaTriggerScriptMap::const_iterator itr = m_AreaTriggerScripts.find(triggerId); - if (itr != m_AreaTriggerScripts.end()) - return itr->second; - - return 0; -} - -uint32 ScriptMgr::GetEventIdScriptId(uint32 eventId) const -{ - EventIdScriptMap::const_iterator itr = m_EventIdScripts.find(eventId); - if (itr != m_EventIdScripts.end()) - return itr->second; - - return 0; -} - char const* ScriptMgr::GetScriptLibraryVersion() const { - if (!m_pGetScriptLibraryVersion) - return ""; +#ifdef ENABLE_SD3 + return SD3::GetScriptLibraryVersion(); +#else + return NULL; +#endif +} - return m_pGetScriptLibraryVersion(); +uint32 ScriptMgr::GetBoundScriptId(ScriptedObjectType entity, int32 entry) +{ + uint32 id = 0; + if (entity < SCRIPTED_MAX_TYPE) + { + EntryToScriptIdMap::const_iterator it = m_scriptBind[entity].find(entry); + if (it != m_scriptBind[entity].end()) + id = it->second; + } + else + sLog.outErrorScriptLib("asking a script for non-existing entity type %u!", entity); + + return id; } CreatureAI* ScriptMgr::GetCreatureAI(Creature* pCreature) { - if (!m_pGetCreatureAI) - return NULL; + // Used by Eluna +#ifdef ENABLE_ELUNA + if (CreatureAI* luaAI = sEluna->GetAI(pCreature)) + return luaAI; +#endif /* ENABLE_ELUNA */ - return m_pGetCreatureAI(pCreature); +#ifdef ENABLE_SD3 + return SD3::GetCreatureAI(pCreature); +#else + return NULL; +#endif } InstanceData* ScriptMgr::CreateInstanceData(Map* pMap) { - if (!m_pCreateInstanceData) - return NULL; - - return m_pCreateInstanceData(pMap); +#ifdef ENABLE_SD3 + return SD3::CreateInstanceData(pMap); +#else + return NULL; +#endif } bool ScriptMgr::OnGossipHello(Player* pPlayer, Creature* pCreature) { - return m_pOnGossipHello != NULL && m_pOnGossipHello(pPlayer, pCreature); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnGossipHello(pPlayer, pCreature)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::GossipHello(pPlayer, pCreature); +#else + return false; +#endif } bool ScriptMgr::OnGossipHello(Player* pPlayer, GameObject* pGameObject) { - return m_pOnGOGossipHello != NULL && m_pOnGOGossipHello(pPlayer, pGameObject); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnGossipHello(pPlayer, pGameObject)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::GOGossipHello(pPlayer, pGameObject); +#else + return false; +#endif } bool ScriptMgr::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) { +#ifdef ENABLE_ELUNA if (code) - return m_pOnGossipSelectWithCode != NULL && m_pOnGossipSelectWithCode(pPlayer, pCreature, sender, action, code); + { + // Used by Eluna + if (sEluna->OnGossipSelectCode(pPlayer, pCreature, sender, action, code)) + return true; + } else - return m_pOnGossipSelect != NULL && m_pOnGossipSelect(pPlayer, pCreature, sender, action); + { + // Used by Eluna + if (sEluna->OnGossipSelect(pPlayer, pCreature, sender, action)) + return true; + } +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + if (code) + { + return SD3::GossipSelectWithCode(pPlayer, pCreature, sender, action, code); + } + else + { + return SD3::GossipSelect(pPlayer, pCreature, sender, action); + } +#else + return false; +#endif } bool ScriptMgr::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) { + // Used by Eluna +#ifdef ENABLE_ELUNA if (code) - return m_pOnGOGossipSelectWithCode != NULL && m_pOnGOGossipSelectWithCode(pPlayer, pGameObject, sender, action, code); + { + if (sEluna->OnGossipSelectCode(pPlayer, pGameObject, sender, action, code)) + return true; + } else - return m_pOnGOGossipSelect != NULL && m_pOnGOGossipSelect(pPlayer, pGameObject, sender, action); + { + if (sEluna->OnGossipSelect(pPlayer, pGameObject, sender, action)) + return true; + } +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + if (code) + { + return SD3::GOGossipSelectWithCode(pPlayer, pGameObject, sender, action, code); + } + else + { + return SD3::GOGossipSelect(pPlayer, pGameObject, sender, action); + } +#else + return false; +#endif } bool ScriptMgr::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) { - return m_pOnQuestAccept != NULL && m_pOnQuestAccept(pPlayer, pCreature, pQuest); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnQuestAccept(pPlayer, pCreature, pQuest)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::QuestAccept(pPlayer, pCreature, pQuest); +#else + return false; +#endif } bool ScriptMgr::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) { - return m_pOnGOQuestAccept != NULL && m_pOnGOQuestAccept(pPlayer, pGameObject, pQuest); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnQuestAccept(pPlayer, pGameObject, pQuest)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::GOQuestAccept(pPlayer, pGameObject, pQuest); +#else + return false; +#endif } bool ScriptMgr::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) { - return m_pOnItemQuestAccept != NULL && m_pOnItemQuestAccept(pPlayer, pItem, pQuest); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnQuestAccept(pPlayer, pItem, pQuest)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::ItemQuestAccept(pPlayer, pItem, pQuest); +#else + return false; +#endif } -bool ScriptMgr::OnQuestRewarded(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnQuestRewarded(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 reward) { - return m_pOnQuestRewarded != NULL && m_pOnQuestRewarded(pPlayer, pCreature, pQuest); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnQuestReward(pPlayer, pCreature, pQuest, reward)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::QuestRewarded(pPlayer, pCreature, pQuest); +#else + return false; +#endif } -bool ScriptMgr::OnQuestRewarded(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) +bool ScriptMgr::OnQuestRewarded(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 reward) { - return m_pOnGOQuestRewarded != NULL && m_pOnGOQuestRewarded(pPlayer, pGameObject, pQuest); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnQuestReward(pPlayer, pGameObject, pQuest, reward)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::GOQuestRewarded(pPlayer, pGameObject, pQuest); +#else + return false; +#endif } uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, Creature* pCreature) { - if (!m_pGetNPCDialogStatus) - return DIALOG_STATUS_UNDEFINED; + // Used by Eluna +#ifdef ENABLE_ELUNA + if (uint32 dialogId = sEluna->GetDialogStatus(pPlayer, pCreature)) + return dialogId; +#endif /* ENABLE_ELUNA */ - return m_pGetNPCDialogStatus(pPlayer, pCreature); +#ifdef ENABLE_SD3 + return SD3::GetNPCDialogStatus(pPlayer, pCreature); +#else + return DIALOG_STATUS_UNDEFINED; +#endif } uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) { - if (!m_pGetGODialogStatus) - return DIALOG_STATUS_UNDEFINED; + // Used by Eluna +#ifdef ENABLE_ELUNA + if (uint32 dialogId = sEluna->GetDialogStatus(pPlayer, pGameObject)) + return dialogId; +#endif /* ENABLE_ELUNA */ - return m_pGetGODialogStatus(pPlayer, pGameObject); +#ifdef ENABLE_SD3 + return SD3::GetGODialogStatus(pPlayer, pGameObject); +#else + return DIALOG_STATUS_UNDEFINED; +#endif } bool ScriptMgr::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) { - return m_pOnGOUse != NULL && m_pOnGOUse(pPlayer, pGameObject); +#ifdef ENABLE_ELUNA + if (sEluna->OnGameObjectUse(pPlayer, pGameObject)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::GOUse(pPlayer, pGameObject); +#else + return false; +#endif } bool ScriptMgr::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) { - return m_pOnItemUse != NULL && m_pOnItemUse(pPlayer, pItem, targets); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (!sEluna->OnUse(pPlayer, pItem, targets)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::ItemUse(pPlayer, pItem, targets); +#else + return false; +#endif } bool ScriptMgr::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) { - return m_pOnAreaTrigger != NULL && m_pOnAreaTrigger(pPlayer, atEntry); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnAreaTrigger(pPlayer, atEntry)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::AreaTrigger(pPlayer, atEntry); +#else + return false; +#endif +} + +bool ScriptMgr::OnNpcSpellClick(Player* pPlayer, Creature* pClickedCreature, uint32 spellId) +{ +#ifdef ENABLE_SD3 + return SD3::NpcSpellClick(pPlayer, pClickedCreature, spellId); +#else + return false; +#endif } bool ScriptMgr::OnProcessEvent(uint32 eventId, Object* pSource, Object* pTarget, bool isStart) { - return m_pOnProcessEvent != NULL && m_pOnProcessEvent(eventId, pSource, pTarget, isStart); +#ifdef ENABLE_SD3 + return SD3::ProcessEvent(eventId, pSource, pTarget, isStart); +#else + return false; +#endif } bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) { - return m_pOnEffectDummyCreature != NULL && m_pOnEffectDummyCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnDummyEffect(pCaster, spellId, effIndex, pTarget)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::EffectDummyCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +#else + return false; +#endif } bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid) { - return m_pOnEffectDummyGO != NULL && m_pOnEffectDummyGO(pCaster, spellId, effIndex, pTarget, originalCasterGuid); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnDummyEffect(pCaster, spellId, effIndex, pTarget)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::EffectDummyGameObject(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +#else + return false; +#endif } bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget, ObjectGuid originalCasterGuid) { - return m_pOnEffectDummyItem != NULL && m_pOnEffectDummyItem(pCaster, spellId, effIndex, pTarget, originalCasterGuid); + // Used by Eluna +#ifdef ENABLE_ELUNA + if (sEluna->OnDummyEffect(pCaster, spellId, effIndex, pTarget)) + return true; +#endif /* ENABLE_ELUNA */ + +#ifdef ENABLE_SD3 + return SD3::EffectDummyItem(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +#else + return false; +#endif } bool ScriptMgr::OnEffectScriptEffect(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) { - return m_pOnEffectScriptEffectCreature != NULL && m_pOnEffectScriptEffectCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +#ifdef ENABLE_SD3 + return SD3::EffectScriptEffectCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +#else + return false; +#endif } bool ScriptMgr::OnAuraDummy(Aura const* pAura, bool apply) { - return m_pOnAuraDummy != NULL && m_pOnAuraDummy(pAura, apply); +#ifdef ENABLE_SD3 + return SD3::AuraDummy(pAura, apply); +#else + return false; +#endif } ScriptLoadResult ScriptMgr::LoadScriptLibrary(const char* libName) { - UnloadScriptLibrary(); - - std::string name = libName; - name = MANGOS_SCRIPT_PREFIX + name + MANGOS_SCRIPT_SUFFIX; - - m_hScriptLib = MANGOS_LOAD_LIBRARY(name.c_str()); - - if (!m_hScriptLib) - return SCRIPT_LOAD_ERR_NOT_FOUND; - -# define GET_SCRIPT_HOOK_PTR(P,N) \ - GetScriptHookPtr((P), (N)); \ - if (!(P)) \ - { \ - /* prevent call before init */ \ - m_pOnFreeScriptLibrary = NULL; \ - UnloadScriptLibrary(); \ - return SCRIPT_LOAD_ERR_WRONG_API; \ - } - - // let check used mangosd revision for build library (unsafe use with different revision because changes in inline functions, define and etc) - char const* (MANGOS_IMPORT * pGetMangosRevStr)(); - - GET_SCRIPT_HOOK_PTR(pGetMangosRevStr, "GetMangosRevStr"); - - GET_SCRIPT_HOOK_PTR(m_pOnInitScriptLibrary, "InitScriptLibrary"); - GET_SCRIPT_HOOK_PTR(m_pOnFreeScriptLibrary, "FreeScriptLibrary"); - GET_SCRIPT_HOOK_PTR(m_pGetScriptLibraryVersion, "GetScriptLibraryVersion"); - - GET_SCRIPT_HOOK_PTR(m_pGetCreatureAI, "GetCreatureAI"); - GET_SCRIPT_HOOK_PTR(m_pCreateInstanceData, "CreateInstanceData"); - - GET_SCRIPT_HOOK_PTR(m_pOnGossipHello, "GossipHello"); - GET_SCRIPT_HOOK_PTR(m_pOnGOGossipHello, "GOGossipHello"); - GET_SCRIPT_HOOK_PTR(m_pOnGossipSelect, "GossipSelect"); - GET_SCRIPT_HOOK_PTR(m_pOnGOGossipSelect, "GOGossipSelect"); - GET_SCRIPT_HOOK_PTR(m_pOnGossipSelectWithCode, "GossipSelectWithCode"); - GET_SCRIPT_HOOK_PTR(m_pOnGOGossipSelectWithCode, "GOGossipSelectWithCode"); - GET_SCRIPT_HOOK_PTR(m_pOnQuestAccept, "QuestAccept"); - GET_SCRIPT_HOOK_PTR(m_pOnGOQuestAccept, "GOQuestAccept"); - GET_SCRIPT_HOOK_PTR(m_pOnItemQuestAccept, "ItemQuestAccept"); - GET_SCRIPT_HOOK_PTR(m_pOnQuestRewarded, "QuestRewarded"); - GET_SCRIPT_HOOK_PTR(m_pOnGOQuestRewarded, "GOQuestRewarded"); - GET_SCRIPT_HOOK_PTR(m_pGetNPCDialogStatus, "GetNPCDialogStatus"); - GET_SCRIPT_HOOK_PTR(m_pGetGODialogStatus, "GetGODialogStatus"); - GET_SCRIPT_HOOK_PTR(m_pOnGOUse, "GOUse"); - GET_SCRIPT_HOOK_PTR(m_pOnItemUse, "ItemUse"); - GET_SCRIPT_HOOK_PTR(m_pOnAreaTrigger, "AreaTrigger"); - GET_SCRIPT_HOOK_PTR(m_pOnProcessEvent, "ProcessEvent"); - GET_SCRIPT_HOOK_PTR(m_pOnEffectDummyCreature, "EffectDummyCreature"); - GET_SCRIPT_HOOK_PTR(m_pOnEffectDummyGO, "EffectDummyGameObject"); - GET_SCRIPT_HOOK_PTR(m_pOnEffectDummyItem, "EffectDummyItem"); - GET_SCRIPT_HOOK_PTR(m_pOnEffectScriptEffectCreature, "EffectScriptEffectCreature"); - GET_SCRIPT_HOOK_PTR(m_pOnAuraDummy, "AuraDummy"); - -# undef GET_SCRIPT_HOOK_PTR - - if (strcmp(pGetMangosRevStr(), REVISION_NR) != 0) +#ifdef ENABLE_SD3 + if (std::strcmp(libName, MANGOS_SCRIPT_NAME) == 0) { - m_pOnFreeScriptLibrary = NULL; // prevent call before init - UnloadScriptLibrary(); - return SCRIPT_LOAD_ERR_OUTDATED; + SD3::FreeScriptLibrary(); + SD3::InitScriptLibrary(); + return SCRIPT_LOAD_OK; } - - m_pOnInitScriptLibrary(); - return SCRIPT_LOAD_OK; +#endif + return SCRIPT_LOAD_ERR_NOT_FOUND; } void ScriptMgr::UnloadScriptLibrary() { - if (!m_hScriptLib) - return; - - if (m_pOnFreeScriptLibrary) - m_pOnFreeScriptLibrary(); - - MANGOS_CLOSE_LIBRARY(m_hScriptLib); - m_hScriptLib = NULL; - - m_pOnInitScriptLibrary = NULL; - m_pOnFreeScriptLibrary = NULL; - m_pGetScriptLibraryVersion = NULL; - - m_pGetCreatureAI = NULL; - m_pCreateInstanceData = NULL; - - m_pOnGossipHello = NULL; - m_pOnGOGossipHello = NULL; - m_pOnGossipSelect = NULL; - m_pOnGOGossipSelect = NULL; - m_pOnGossipSelectWithCode = NULL; - m_pOnGOGossipSelectWithCode = NULL; - m_pOnQuestAccept = NULL; - m_pOnGOQuestAccept = NULL; - m_pOnItemQuestAccept = NULL; - m_pOnQuestRewarded = NULL; - m_pOnGOQuestRewarded = NULL; - m_pGetNPCDialogStatus = NULL; - m_pGetGODialogStatus = NULL; - m_pOnGOUse = NULL; - m_pOnItemUse = NULL; - m_pOnAreaTrigger = NULL; - m_pOnProcessEvent = NULL; - m_pOnEffectDummyCreature = NULL; - m_pOnEffectDummyGO = NULL; - m_pOnEffectDummyItem = NULL; - m_pOnEffectScriptEffectCreature = NULL; - m_pOnAuraDummy = NULL; +#ifdef ENABLE_SD3 + SD3::FreeScriptLibrary(); +#else + return; +#endif } void ScriptMgr::CollectPossibleEventIds(std::set& eventIds) diff --git a/src/game/WorldHandlers/ScriptMgr.h b/src/game/WorldHandlers/ScriptMgr.h index eb5104a54..c3a8656bf 100644 --- a/src/game/WorldHandlers/ScriptMgr.h +++ b/src/game/WorldHandlers/ScriptMgr.h @@ -47,6 +47,24 @@ class SpellCastTargets; class Unit; class WorldObject; +enum ScriptedObjectType +{ + SCRIPTED_UNIT = 0, //CreatureScript + SCRIPTED_GAMEOBJECT = 1, //GameObjectScript + SCRIPTED_ITEM = 2, //ItemScript + SCRIPTED_AREATRIGGER = 3, //AreaTriggerScript + SCRIPTED_SPELL = 4, //SpellScript + SCRIPTED_AURASPELL = 5, //AuraScript + SCRIPTED_MAPEVENT = 6, //MapEventScript + SCRIPTED_MAP = 7, //ZoneScript + SCRIPTED_BATTLEGROUND = 8, //BattleGroundScript + SCRIPTED_PVP_ZONE = 9, //OutdoorPvPScript + SCRIPTED_INSTANCE = 10, //InstanceScript + SCRIPTED_CONDITION = 11, //ConditionScript + SCRIPTED_ACHIEVEMENT = 12, //AchievementScript + SCRIPTED_MAX_TYPE +}; + enum ScriptCommand // resSource, resTarget are the resulting Source/ Target after buddy search is done { SCRIPT_COMMAND_TALK = 0, // resSource = WorldObject, resTarget = Unit/none @@ -477,24 +495,50 @@ class ScriptMgr void LoadDbScriptStrings(); void LoadScriptNames(); - void LoadAreaTriggerScripts(); - void LoadEventIdScripts(); + void LoadScriptBinding(); uint32 GetAreaTriggerScriptId(uint32 triggerId) const; uint32 GetEventIdScriptId(uint32 eventId) const; - const char* GetScriptName(uint32 id) const { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; } + uint32 GetBoundScriptId(ScriptedObjectType entity, int32 entry); + + const char* GetScriptName(uint32 id) const + { + return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; + } uint32 GetScriptId(const char* name) const; - uint32 GetScriptIdsCount() const { return m_scriptNames.size(); } + uint32 GetScriptIdsCount() const + { + return m_scriptNames.size(); + } ScriptLoadResult LoadScriptLibrary(const char* libName); void UnloadScriptLibrary(); - bool IsScriptLibraryLoaded() const { return m_hScriptLib != NULL; } + bool IsScriptLibraryLoaded() const + { + #ifdef ENABLE_SD3 + return true; + #else + return false; + #endif + } - uint32 IncreaseScheduledScriptsCount() { return (uint32)++m_scheduledScripts; } - uint32 DecreaseScheduledScriptCount() { return (uint32)--m_scheduledScripts; } - uint32 DecreaseScheduledScriptCount(size_t count) { return (uint32)(m_scheduledScripts -= count); } - bool IsScriptScheduled() const { return m_scheduledScripts > 0; } + uint32 IncreaseScheduledScriptsCount() + { + return (uint32)++m_scheduledScripts; + } + uint32 DecreaseScheduledScriptCount() + { + return (uint32)--m_scheduledScripts; + } + uint32 DecreaseScheduledScriptCount(size_t count) + { + return (uint32)(m_scheduledScripts -= count); + } + bool IsScriptScheduled() const + { + return m_scheduledScripts > 0; + } static bool CanSpellEffectStartDBScript(SpellEntry const* spellinfo, SpellEffectIndex effIdx); CreatureAI* GetCreatureAI(Creature* pCreature); @@ -508,13 +552,14 @@ class ScriptMgr bool OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest); bool OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest); bool OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest); - bool OnQuestRewarded(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool OnQuestRewarded(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest); + bool OnQuestRewarded(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 reward); + bool OnQuestRewarded(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 reward); uint32 GetDialogStatus(Player* pPlayer, Creature* pCreature); uint32 GetDialogStatus(Player* pPlayer, GameObject* pGameObject); bool OnGameObjectUse(Player* pPlayer, GameObject* pGameObject); bool OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); bool OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry); + bool OnNpcSpellClick(Player* pPlayer, Creature* pClickedCreature, uint32 spellId); bool OnProcessEvent(uint32 eventId, Object* pSource, Object* pTarget, bool isStart); bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid); bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid); @@ -527,54 +572,15 @@ class ScriptMgr void LoadScripts(ScriptMapMapName& scripts, const char* tablename); void CheckScriptTexts(ScriptMapMapName const& scripts, std::set& ids); - template - void GetScriptHookPtr(T& ptr, const char* name) - { - ptr = (T)MANGOS_GET_PROC_ADDR(m_hScriptLib, name); - } - typedef std::vector ScriptNameMap; - typedef UNORDERED_MAP AreaTriggerScriptMap; - typedef UNORDERED_MAP EventIdScriptMap; + typedef UNORDERED_MAP EntryToScriptIdMap; - AreaTriggerScriptMap m_AreaTriggerScripts; - EventIdScriptMap m_EventIdScripts; + EntryToScriptIdMap m_scriptBind[SCRIPTED_MAX_TYPE]; ScriptNameMap m_scriptNames; - MANGOS_LIBRARY_HANDLE m_hScriptLib; // atomic op counter for active scripts amount ACE_Atomic_Op m_scheduledScripts; - - void (MANGOS_IMPORT* m_pOnInitScriptLibrary)(); - void (MANGOS_IMPORT* m_pOnFreeScriptLibrary)(); - const char* (MANGOS_IMPORT* m_pGetScriptLibraryVersion)(); - - CreatureAI* (MANGOS_IMPORT* m_pGetCreatureAI)(Creature*); - InstanceData* (MANGOS_IMPORT* m_pCreateInstanceData)(Map*); - - bool (MANGOS_IMPORT* m_pOnGossipHello)(Player*, Creature*); - bool (MANGOS_IMPORT* m_pOnGOGossipHello)(Player*, GameObject*); - bool (MANGOS_IMPORT* m_pOnGossipSelect)(Player*, Creature*, uint32, uint32); - bool (MANGOS_IMPORT* m_pOnGOGossipSelect)(Player*, GameObject*, uint32, uint32); - bool (MANGOS_IMPORT* m_pOnGossipSelectWithCode)(Player*, Creature*, uint32, uint32, const char*); - bool (MANGOS_IMPORT* m_pOnGOGossipSelectWithCode)(Player*, GameObject*, uint32, uint32, const char*); - bool (MANGOS_IMPORT* m_pOnQuestAccept)(Player*, Creature*, Quest const*); - bool (MANGOS_IMPORT* m_pOnGOQuestAccept)(Player*, GameObject*, Quest const*); - bool (MANGOS_IMPORT* m_pOnItemQuestAccept)(Player*, Item*, Quest const*); - bool (MANGOS_IMPORT* m_pOnQuestRewarded)(Player*, Creature*, Quest const*); - bool (MANGOS_IMPORT* m_pOnGOQuestRewarded)(Player*, GameObject*, Quest const*); - uint32(MANGOS_IMPORT* m_pGetNPCDialogStatus)(Player*, Creature*); - uint32(MANGOS_IMPORT* m_pGetGODialogStatus)(Player*, GameObject*); - bool (MANGOS_IMPORT* m_pOnGOUse)(Player*, GameObject*); - bool (MANGOS_IMPORT* m_pOnItemUse)(Player*, Item*, SpellCastTargets const&); - bool (MANGOS_IMPORT* m_pOnAreaTrigger)(Player*, AreaTriggerEntry const*); - bool (MANGOS_IMPORT* m_pOnProcessEvent)(uint32, Object*, Object*, bool); - bool (MANGOS_IMPORT* m_pOnEffectDummyCreature)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid); - bool (MANGOS_IMPORT* m_pOnEffectDummyGO)(Unit*, uint32, SpellEffectIndex, GameObject*, ObjectGuid); - bool (MANGOS_IMPORT* m_pOnEffectDummyItem)(Unit*, uint32, SpellEffectIndex, Item*, ObjectGuid); - bool (MANGOS_IMPORT* m_pOnEffectScriptEffectCreature)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid); - bool (MANGOS_IMPORT* m_pOnAuraDummy)(Aura const*, bool); }; // Starters for events diff --git a/src/game/WorldHandlers/Weather.cpp b/src/game/WorldHandlers/Weather.cpp index 850eb183f..87c7c6c6e 100644 --- a/src/game/WorldHandlers/Weather.cpp +++ b/src/game/WorldHandlers/Weather.cpp @@ -29,52 +29,56 @@ #include "Weather.h" #include "WorldPacket.h" #include "Player.h" +#include "Map.h" #include "World.h" #include "Log.h" -#include "ObjectMgr.h" +// #include "ObjectMgr.h" // chucky delete ? #include "Util.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ /// Create the Weather object -Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone(zone), m_weatherChances(weatherChances) +Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : + m_zone(zone), + m_type(WEATHER_TYPE_FINE), + m_grade(0.0f), + m_weatherChances(weatherChances), + m_isPermanentWeather(false) { m_timer.SetInterval(sWorld.getConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER)); - m_type = WEATHER_TYPE_FINE; - m_grade = 0; - DETAIL_FILTER_LOG(LOG_FILTER_WEATHER, "WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (m_timer.GetInterval() / (MINUTE * IN_MILLISECONDS))); } /// Launch a weather update -bool Weather::Update(time_t diff) +bool Weather::Update(uint32 diff, Map const* _map) { m_timer.Update(diff); - - ///- If the timer has passed, ReGenerate the weather - if (m_timer.Passed()) + if (ReGenerate()) { - m_timer.Reset(); - // update only if Regenerate has changed the weather - if (ReGenerate()) - { - ///- Weather will be removed if not updated (no players in zone anymore) - if (!UpdateWeather()) - return false; - } + ///- Weather will be removed if not updated (no players in zone anymore) + if (!SendWeatherForPlayersInZone(_map)) + return false; } return true; } -/// Calculate the new weather +/// Calculate the new weather, returns true if and only if the weather changed bool Weather::ReGenerate() { + if (m_isPermanentWeather) + return false; + + // remember old values + WeatherType old_type = m_type; + float old_grade = m_grade; + if (!m_weatherChances) { m_type = WEATHER_TYPE_FINE; m_grade = 0.0f; - return false; + // No chanced calculation for this zone + return old_type != m_type || old_grade != m_grade; } /// Weather statistics: @@ -85,11 +89,9 @@ bool Weather::ReGenerate() uint32 u = urand(0, 99); if (u < 30) + { return false; - - // remember old values - WeatherType old_type = m_type; - float old_grade = m_grade; + } // 78 days between January 1st and March 20nd; 365/4=91 days by season // season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html @@ -149,19 +151,27 @@ bool Weather::ReGenerate() } // At this point, only weather that isn't doing anything remains but that have weather data - uint32 chance1 = m_weatherChances->data[season].rainChance; + uint32 chance1 = m_weatherChances->data[season].rainChance; uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance; uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance; uint32 rnd = urand(0, 99); if (rnd <= chance1) + { m_type = WEATHER_TYPE_RAIN; + } else if (rnd <= chance2) + { m_type = WEATHER_TYPE_SNOW; + } else if (rnd <= chance3) + { m_type = WEATHER_TYPE_STORM; + } else + { m_type = WEATHER_TYPE_FINE; + } /// New weather statistics (if not fine): ///- 85% light @@ -182,20 +192,28 @@ bool Weather::ReGenerate() // Severe change, but how severe? rnd = urand(0, 99); if (rnd < 50) + { m_grade = rand_norm_f() * 0.3333f + 0.3334f; + } else + { m_grade = rand_norm_f() * 0.3333f + 0.6667f; + } } + NormalizeGrade(); + // return true only in case weather changes return m_type != old_type || m_grade != old_grade; } void Weather::SendWeatherUpdateToPlayer(Player* player) { - WorldPacket data(SMSG_WEATHER, (4 + 4 + 1)); + NormalizeGrade(); + WorldPacket data(SMSG_WEATHER, (4 + 4 + 1)); data << uint32(GetWeatherState()) << (float)m_grade << uint8(0); + player->GetSession()->SendPacket(&data); } @@ -206,10 +224,9 @@ bool Weather::SendWeatherForPlayersInZone(Map const* _map) WeatherState state = GetWeatherState(); + // To be sent packet WorldPacket data(SMSG_WEATHER, 4 + 4 + 1); - data << uint32(state); - data << float(m_grade); - data << uint8(0); // 1 = instant change, 0 = smooth change + data << uint32(state) << (float)m_grade << uint8(0); ///- Send the weather packet to all players in this zone if (!_map->SendToPlayersInZone(&data, m_zone)) @@ -224,15 +241,7 @@ bool Weather::SendWeatherForPlayersInZone(Map const* _map) return true; } -void Weather::SendFineWeatherUpdateToPlayer(Player* player) -{ - WorldPacket data(SMSG_WEATHER, (4 + 4 + 1)); - - data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0); // no sound - player->GetSession()->SendPacket(&data); -} - -/// Send the new weather to all players in the zone +/* bool Weather::UpdateWeather() { Player* player = sWorld.FindPlayerInZone(m_zone); @@ -297,7 +306,7 @@ bool Weather::UpdateWeather() DETAIL_FILTER_LOG(LOG_FILTER_WEATHER, "Change the weather of zone %u to %s.", m_zone, wthstr); return true; -} +} */ // Set the weather void Weather::SetWeather(WeatherType type, float grade, Map const* _map, bool isPermanent) @@ -312,18 +321,6 @@ void Weather::SetWeather(WeatherType type, float grade, Map const* _map, bool is SendWeatherForPlayersInZone(_map); } -/// Set the weather -// pre Dev21 version - delete if not required ? -void Weather::SetWeather(WeatherType type, float grade) -{ - if (m_type == type && m_grade == grade) - return; - - m_type = type; - m_grade = grade; - UpdateWeather(); -} - /// Get the sound number associated with the current weather WeatherState Weather::GetWeatherState() const { @@ -421,5 +418,115 @@ void Weather::LogWeatherState(WeatherState state) const } DETAIL_FILTER_LOG(LOG_FILTER_WEATHER, "Change the weather of zone %u (type %u, grade %f) to state %s.", m_zone, m_type, m_grade, wthstr); + } +// --------------------------------------------------------- +// Weather System +// --------------------------------------------------------- + +WeatherSystem::WeatherSystem(Map const* _map) : m_map(_map) +{} + +WeatherSystem::~WeatherSystem() +{ + ///- Empty the WeatherMap + for (WeatherMap::const_iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr) + delete itr->second; + + m_weathers.clear(); +} + +/// Find or Create a Weather object by the given zoneid +Weather* WeatherSystem::FindOrCreateWeather(uint32 zoneId) +{ + WeatherMap::const_iterator itr = m_weathers.find(zoneId); + // Return if found + if (itr != m_weathers.end()) + return itr->second; + // Create + Weather* w = new Weather(zoneId, sWeatherMgr.GetWeatherChances(zoneId)); + m_weathers[zoneId] = w; + return w; +} + + +/// Update Weathers for the different zones +void WeatherSystem::UpdateWeathers(uint32 diff) +{ + ///- Send an update signal to Weather objects + for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end();) + { + ///- and remove Weather objects for zones with no player + // As interval > WorldTick + if (!itr->second->Update(diff, m_map)) + { + delete itr->second; + m_weathers.erase(itr++); + } + else + ++itr; + } +} + +/// Load Weather chanced from table game_weather +void WeatherMgr::LoadWeatherZoneChances() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + QueryResult* result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); + + if (!result) + { + BarGoLink bar(1); + bar.step(); + sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); + sLog.outString(); + return; + } + + BarGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + bar.step(); + + uint32 zone_id = fields[0].GetUInt32(); + + WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; + + for (int season = 0; season < WEATHER_SEASONS; ++season) + { + wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE - 1) + 1].GetUInt32(); + wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE - 1) + 2].GetUInt32(); + wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE - 1) + 3].GetUInt32(); + + if (wzc.data[season].rainChance > 100) + { + wzc.data[season].rainChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%", zone_id, season); + } + + if (wzc.data[season].snowChance > 100) + { + wzc.data[season].snowChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%", zone_id, season); + } + + if (wzc.data[season].stormChance > 100) + { + wzc.data[season].stormChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%", zone_id, season); + } + } + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(">> Loaded %u weather definitions", count); + sLog.outString(); +} diff --git a/src/game/WorldHandlers/Weather.h b/src/game/WorldHandlers/Weather.h index e4e75ea57..05821caae 100644 --- a/src/game/WorldHandlers/Weather.h +++ b/src/game/WorldHandlers/Weather.h @@ -58,18 +58,15 @@ class Weather { public: Weather(uint32 zone, WeatherZoneChances const* weatherChances); - ~Weather() { }; + ~Weather() {}; - bool ReGenerate(); - bool UpdateWeather(); + /// Send Weather to one player void SendWeatherUpdateToPlayer(Player* player); - bool SendWeatherForPlayersInZone(Map const* _map); - static void SendFineWeatherUpdateToPlayer(Player* player); + /// Set the weather void SetWeather(WeatherType type, float grade, Map const* _map, bool isPermanent); - void SetWeather(WeatherType type, float grade); - /// For which zone is this weather? - uint32 GetZone() { return m_zone; }; - bool Update(time_t diff); + /// Update the weather in this zone, when the timer is expired the weather will be rolled again + bool Update(uint32 diff, Map const* _map); + /// Check if a type is valid static bool IsValidWeatherType(uint32 type) { switch (type) @@ -85,14 +82,17 @@ class Weather return false; } } - private: + /// Send SMSG_WEATHER to all players in the zone + bool SendWeatherForPlayersInZone(Map const* _map); + /// Calculate new weather + bool ReGenerate(); + /// Calculate state based on type and grade + WeatherState GetWeatherState() const; // Helper to get the grade between 0..1 void NormalizeGrade(); // Helper to log recent state void LogWeatherState(WeatherState state) const; - - WeatherState GetWeatherState() const; uint32 m_zone; WeatherType m_type; float m_grade; @@ -108,17 +108,59 @@ class Weather /// Weathers for one map class WeatherSystem { -public: - WeatherSystem(Map const* _map); - ~WeatherSystem(); + public: + WeatherSystem(Map const* _map); + ~WeatherSystem(); - Weather* FindOrCreateWeather(uint32 zoneId); - void UpdateWeathers(uint32 diff); + Weather* FindOrCreateWeather(uint32 zoneId); + void UpdateWeathers(uint32 diff); -private: - Map const* const m_map; + private: + Map const* const m_map; - typedef UNORDERED_MAP WeatherMap; - WeatherMap m_weathers; + typedef UNORDERED_MAP WeatherMap; + WeatherMap m_weathers; }; + +// --------------------------------------------------------- +// Global Weather Information +// --------------------------------------------------------- + +#define WEATHER_SEASONS 4 +struct WeatherSeasonChances +{ + uint32 rainChance; + uint32 snowChance; + uint32 stormChance; +}; + +struct WeatherZoneChances +{ + WeatherSeasonChances data[WEATHER_SEASONS]; +}; + +class WeatherMgr +{ + public: + WeatherMgr() {}; + ~WeatherMgr() {}; + + void LoadWeatherZoneChances(); + + WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const + { + WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); + if (itr != mWeatherZoneMap.end()) + return &itr->second; + else + return NULL; + } + + private: + typedef UNORDERED_MAP WeatherZoneMap; + WeatherZoneMap mWeatherZoneMap; +}; + +#define sWeatherMgr MaNGOS::Singleton::Instance() + #endif diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 2420bda38..06dea53ca 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -76,6 +76,9 @@ #include "CreatureLinkingMgr.h" #include "Calendar.h" #include "PhaseMgr.h" +#ifdef ENABLE_ELUNA +#include "LuaEngine.h" +#endif /*ENABLE_ELUNA*/ INSTANTIATE_SINGLETON_1(World); @@ -428,6 +431,9 @@ void World::RemoveWeather(uint32 id) } /// Add a Weather object to the list +/* + * chucky - delete this? + * this is not in Two Weather* World::AddWeather(uint32 zone_id) { WeatherZoneChances const* weatherChances = sObjectMgr.GetWeatherChances(zone_id); @@ -442,6 +448,7 @@ Weather* World::AddWeather(uint32 zone_id) w->UpdateWeather(); return w; } +*/ /// Initialize config values void World::LoadConfigSettings(bool reload) @@ -958,16 +965,16 @@ void World::SetInitialWorldSettings() ///- Check the existence of the map files for all races start areas. if (!MapManager::ExistMapAndVMap(0, -6240.32f, 331.033f) || // Dwarf/ Gnome - !MapManager::ExistMapAndVMap(0, -8949.95f, -132.493f) || // Human - !MapManager::ExistMapAndVMap(1, -618.518f, -4251.67f) || // Orc - !MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f) || // Scourge - !MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f) || // NightElf - !MapManager::ExistMapAndVMap(1, -2917.58f, -257.98f) || // Tauren - (m_configUint32Values[CONFIG_UINT32_EXPANSION] >= EXPANSION_TBC && - (!MapManager::ExistMapAndVMap(530, 10349.6f, -6357.29f) || // BloodElf - !MapManager::ExistMapAndVMap(530, -3961.64f, -13931.2f))) || // Draenei - (m_configUint32Values[CONFIG_UINT32_EXPANSION] >= EXPANSION_WOTLK && - !MapManager::ExistMapAndVMap(609, 2355.84f, -5664.77f))) // Death Knight + !MapManager::ExistMapAndVMap(0, -8949.95f, -132.493f) || // Human + !MapManager::ExistMapAndVMap(1, -618.518f, -4251.67f) || // Orc + !MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f) || // Scourge + !MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f) || // NightElf + !MapManager::ExistMapAndVMap(1, -2917.58f, -257.98f) || // Tauren + (m_configUint32Values[CONFIG_UINT32_EXPANSION] >= EXPANSION_TBC && + (!MapManager::ExistMapAndVMap(530, 10349.6f, -6357.29f) || // BloodElf + !MapManager::ExistMapAndVMap(530, -3961.64f, -13931.2f))) || // Draenei + (m_configUint32Values[CONFIG_UINT32_EXPANSION] >= EXPANSION_WOTLK && + !MapManager::ExistMapAndVMap(609, 2355.84f, -5664.77f))) // Death Knight { sLog.outError("Correct *.map files not found in path '%smaps' or *.vmtree/*.vmtile files in '%svmaps'. Please place *.map and vmap files in appropriate directories or correct the DataDir value in the mangosd.conf file.", m_dataPath.c_str(), m_dataPath.c_str()); Log::WaitBeforeContinueIfNeed(); @@ -997,16 +1004,15 @@ void World::SetInitialWorldSettings() ///- Load the DBC files sLog.outString("Initialize data stores..."); LoadDBCStores(m_dataPath); - LoadDB2Stores(m_dataPath); DetectDBCLang(); sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) + sLog.outString("Loading SpellTemplate..."); + sObjectMgr.LoadSpellTemplate(); + sLog.outString("Loading Script Names..."); sScriptMgr.LoadScriptNames(); - sLog.outString("Loading WorldTemplate..."); - sObjectMgr.LoadWorldTemplate(); - sLog.outString("Loading InstanceTemplate..."); sObjectMgr.LoadInstanceTemplate(); @@ -1030,6 +1036,12 @@ void World::SetInitialWorldSettings() sObjectMgr.SetHighestGuids(); // must be after PackInstances() and PackGroupIds() sLog.outString(); +#ifdef ENABLE_ELUNA + ///- Initialize Lua Engine + sLog.outString("Initialize Eluna Lua Engine..."); + Eluna::Initialize(); +#endif /* ENABLE_ELUNA */ + sLog.outString("Loading Page Texts..."); sObjectMgr.LoadPageTexts(); @@ -1084,6 +1096,9 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Equipment templates..."); sObjectMgr.LoadEquipmentTemplates(); + sLog.outString("Loading Creature Stats..."); + sObjectMgr.LoadCreatureClassLvlStats(); + sLog.outString("Loading Creature templates..."); sObjectMgr.LoadCreatureTemplates(); @@ -1142,7 +1157,7 @@ void World::SetInitialWorldSettings() sPoolMgr.LoadFromDB(); sLog.outString("Loading Weather Data..."); - sObjectMgr.LoadWeatherZoneChances(); + sWeatherMgr.LoadWeatherZoneChances(); sLog.outString("Loading Quests..."); sObjectMgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables @@ -1166,12 +1181,6 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Conditions..."); sObjectMgr.LoadConditions(); - sLog.outString("Loading Phase definitions..."); - sObjectMgr.LoadPhaseDefinitions(); - - sLog.outString("Loading Spell Phase Dbc Info..."); - sObjectMgr.LoadSpellPhaseInfo(); - sLog.outString("Creating map persistent states for non-instanceable maps..."); // must be after PackInstances(), LoadCreatures(), sPoolMgr.LoadFromDB(), sGameEventMgr.LoadFromDB(); sMapPersistentStateMgr.InitWorldMaps(); @@ -1196,11 +1205,10 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Tavern Area Triggers..."); sObjectMgr.LoadTavernAreaTriggers(); - sLog.outString("Loading AreaTrigger script names..."); - sScriptMgr.LoadAreaTriggerScripts(); - - sLog.outString("Loading event id script names..."); - sScriptMgr.LoadEventIdScripts(); +#ifdef ENABLE_SD3 + sLog.outString("Loading all script bindings..."); + sScriptMgr.LoadScriptBinding(); +#endif /* ENABLE_SD3 */ sLog.outString("Loading Graveyard-zone links..."); sObjectMgr.LoadGraveyardZones(); @@ -1339,8 +1347,14 @@ void World::SetInitialWorldSettings() sLog.outString("Loading GM tickets..."); sTicketMgr.LoadGMTickets(); - sLog.outString("Loading hotfix data..."); - sObjectMgr.LoadHotfixData(); + sLog.outString("Loading Dungeon Finder Requirements..."); + sObjectMgr.LoadDungeonFinderRequirements(); + + sLog.outString("Loading Dungeon Finder Rewards..."); + sObjectMgr.LoadDungeonFinderRewards(); + + sLog.outString("Loading Dungeon Finder Items..."); + sObjectMgr.LoadDungeonFinderItems(); ///- Handle outdated emails (delete/return) sLog.outString("Returning old mails..."); @@ -1372,21 +1386,25 @@ void World::SetInitialWorldSettings() sEventAIMgr.LoadCreatureEventAI_Scripts(); sLog.outString("Initializing Scripts..."); +#ifdef ENABLE_SD3 switch (sScriptMgr.LoadScriptLibrary(MANGOS_SCRIPT_NAME)) { - case SCRIPT_LOAD_OK: - sLog.outString("Scripting library loaded."); - break; - case SCRIPT_LOAD_ERR_NOT_FOUND: - sLog.outError("Scripting library not found or not accessible."); - break; - case SCRIPT_LOAD_ERR_WRONG_API: - sLog.outError("Scripting library has wrong list functions (outdated?)."); - break; - case SCRIPT_LOAD_ERR_OUTDATED: - sLog.outError("Scripting library build for old mangosd revision. You need rebuild it."); - break; + case SCRIPT_LOAD_OK: + sLog.outString("Scripting library loaded."); + break; + case SCRIPT_LOAD_ERR_NOT_FOUND: + sLog.outError("Scripting library not found or not accessible."); + break; + case SCRIPT_LOAD_ERR_WRONG_API: + sLog.outError("Scripting library has wrong list functions (outdated?)."); + break; + case SCRIPT_LOAD_ERR_OUTDATED: + sLog.outError("Scripting library build for old mangosd revision. You need rebuild it."); + break; } +#else /* ENABLE_SD3 */ + sLog.outError("SD3 was not included in compilation, not using it."); +#endif /* ENABLE_SD3 */ ///- Initialize game time and timers sLog.outString("DEBUG:: Initialize game time and timers"); @@ -1399,12 +1417,11 @@ void World::SetInitialWorldSettings() local = *(localtime(&curr)); // dereference and assign char isoDate[128]; sprintf(isoDate, "%04d-%02d-%02d %02d:%02d:%02d", - local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); + local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)", - realmID, uint64(m_startTime), isoDate); + realmID, uint64(m_startTime), isoDate); - m_timers[WUPDATE_WEATHERS].SetInterval(1 * IN_MILLISECONDS); m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE * IN_MILLISECONDS); m_timers[WUPDATE_UPTIME].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE)*MINUTE * IN_MILLISECONDS); // Update "uptime" table based on configuration entry in minutes. @@ -1414,6 +1431,9 @@ void World::SetInitialWorldSettings() // for AhBot m_timers[WUPDATE_AHBOT].SetInterval(20 * IN_MILLISECONDS); // every 20 sec + // for Dungeon Finder + m_timers[WUPDATE_LFGMGR].SetInterval(30 * IN_MILLISECONDS); // every 30 sec + // to set mailtimer to return mails every day between 4 and 5 am // mailtimer is increased when updating auctions // one second is 1000 -(tested on win system) @@ -1433,6 +1453,7 @@ void World::SetInitialWorldSettings() ///- Initialize Battlegrounds sLog.outString("Starting BattleGround System"); sBattleGroundMgr.CreateInitialBattleGrounds(); + sBattleGroundMgr.InitAutomaticArenaPointDistribution(); ///- Initialize Outdoor PvP sLog.outString("Starting Outdoor PvP System"); @@ -1442,13 +1463,19 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Transports..."); sMapMgr.LoadTransports(); + // Initialize Warden + sLog.outString("Loading Warden Checks..."); + sWardenCheckMgr->LoadWardenChecks(); + sLog.outString(); + + sLog.outString("Loading Warden Action Overrides..."); + sWardenCheckMgr->LoadWardenOverrides(); + sLog.outString(); + sLog.outString("Deleting expired bans..."); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - sLog.outString("Calculate next currency reset time..."); - InitCurrencyResetTime(); - - sLog.outString("Calculate next daily quest reset time..."); + sLog.outString("Calculate next daily quest and dungeon reset time..."); InitDailyQuestResetTime(); sLog.outString("Calculate next weekly quest reset time..."); @@ -1457,6 +1484,9 @@ void World::SetInitialWorldSettings() sLog.outString("Calculate next monthly quest reset time..."); SetMonthlyQuestResetTime(); + sLog.outString("Calculate random battleground reset time..."); + InitRandomBGResetTime(); + sLog.outString("Starting Game Event system..."); uint32 nextGameEvent = sGameEventMgr.Initialize(); m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); // depend on next event @@ -1467,6 +1497,13 @@ void World::SetInitialWorldSettings() sLog.outString("Initialize AuctionHouseBot..."); sAuctionBot.Initialize(); +#ifdef ENABLE_ELUNA + ///- Run eluna scripts. + // in multithread foreach: run scripts + sEluna->RunScripts(); + sEluna->OnConfigLoad(false); // Must be done after Eluna is initialized and scripts have run. +#endif + sLog.outString("WORLD: World initialized"); uint32 uStartInterval = WorldTimer::getMSTimeDiff(uStartTime, WorldTimer::getMSTime()); @@ -1526,9 +1563,13 @@ void World::Update(uint32 diff) for (int i = 0; i < WUPDATE_COUNT; ++i) { if (m_timers[i].GetCurrent() >= 0) + { m_timers[i].Update(diff); + } else + { m_timers[i].SetCurrent(0); + } } ///- Update the game time and check for shutdown time @@ -1537,9 +1578,12 @@ void World::Update(uint32 diff) ///-Update mass mailer tasks if any sMassMailMgr.Update(); - /// Handle daily quests reset time + /// Handle daily quests and dungeon reset time if (m_gameTime > m_NextDailyQuestReset) + { ResetDailyQuests(); + sLFGMgr.ResetDailyRecords(); + } /// Handle weekly quests reset time if (m_gameTime > m_NextWeeklyQuestReset) @@ -1549,9 +1593,9 @@ void World::Update(uint32 diff) if (m_gameTime > m_NextMonthlyQuestReset) ResetMonthlyQuests(); - /// Handle monthly quests reset time - if (m_gameTime > m_NextCurrencyReset) - ResetCurrencyWeekCounts(); + /// Handle random battlegrounds reset time + if (m_gameTime > m_NextRandomBGReset) + ResetRandomBG(); ///
  • Handle auctions when the timer has passed if (m_timers[WUPDATE_AUCTIONS].Passed()) @@ -1577,28 +1621,16 @@ void World::Update(uint32 diff) m_timers[WUPDATE_AHBOT].Reset(); } + ///
  • Update Dungeon Finder + if (m_timers[WUPDATE_LFGMGR].Passed()) + { + sLFGMgr.Update(); + m_timers[WUPDATE_LFGMGR].Reset(); + } + ///
  • Handle session updates UpdateSessions(diff); - ///
  • Handle weather updates when the timer has passed - if (m_timers[WUPDATE_WEATHERS].Passed()) - { - ///- Send an update signal to Weather objects - for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end();) - { - ///- and remove Weather objects for zones with no player - // As interval > WorldTick - if (!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval())) - { - delete itr->second; - m_weathers.erase(itr++); - } - else - ++itr; - } - - m_timers[WUPDATE_WEATHERS].SetCurrent(0); - } ///
  • Update uptime table if (m_timers[WUPDATE_UPTIME].Passed()) { @@ -1615,6 +1647,11 @@ void World::Update(uint32 diff) sBattleGroundMgr.Update(diff); sOutdoorPvPMgr.Update(diff); + ///- Used by Eluna +#ifdef ENABLE_ELUNA + sEluna->OnWorldUpdate(diff); +#endif + ///- Delete all characters which have been deleted X days before if (m_timers[WUPDATE_DELETECHARS].Passed()) { @@ -1652,6 +1689,11 @@ void World::Update(uint32 diff) // And last, but not least handle the issued cli commands ProcessCliCommands(); + ///- Used by Eluna +#ifdef ENABLE_ELUNA + sEluna->OnWorldUpdate(diff); +#endif /* ENABLE_ELUNA */ + // cleanup unused GridMap objects as well as VMaps sTerrainMgr.Update(diff); } @@ -2241,6 +2283,18 @@ void World::ResetDailyQuests() CharacterDatabase.PExecute("UPDATE saved_variables SET NextDailyQuestResetTime = '" UI64FMTD "'", uint64(m_NextDailyQuestReset)); } +void World::ResetRandomBG() +{ + sLog.outDetail("Random BG status reset for all characters."); + CharacterDatabase.Execute("DELETE FROM character_battleground_random"); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if (itr->second->GetPlayer()) + itr->second->GetPlayer()->SetRandomWinner(false); + + m_NextRandomBGReset = time_t(m_NextRandomBGReset + DAY); + CharacterDatabase.PExecute("UPDATE saved_variables SET NextRandomBGResetTime = '" UI64FMTD "'", uint64(m_NextRandomBGReset)); +} + void World::ResetWeeklyQuests() { DETAIL_LOG("Weekly quests reset for all characters."); diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index 8d873f0c9..5a7dcc653 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -78,13 +78,14 @@ enum ShutdownExitCode enum WorldTimers { WUPDATE_AUCTIONS = 0, - WUPDATE_WEATHERS = 1, - WUPDATE_UPTIME = 2, - WUPDATE_CORPSES = 3, - WUPDATE_EVENTS = 4, - WUPDATE_DELETECHARS = 5, - WUPDATE_AHBOT = 6, - WUPDATE_COUNT = 7 + WUPDATE_UPTIME = 1, + WUPDATE_CORPSES = 2, + WUPDATE_EVENTS = 3, + WUPDATE_DELETECHARS = 4, + WUPDATE_AHBOT = 5, + WUPDATE_LFGMGR = 6, + WUPDATE_WEATHERS = 7, + WUPDATE_COUNT = 8 }; /// Configuration elements @@ -126,6 +127,11 @@ enum eConfigUInt32Values CONFIG_UINT32_MAX_PLAYER_LEVEL, CONFIG_UINT32_START_PLAYER_LEVEL, CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, + CONFIG_UINT32_START_PLAYER_MONEY, + CONFIG_UINT32_MAX_HONOR_POINTS, + CONFIG_UINT32_START_HONOR_POINTS, + CONFIG_UINT32_MAX_ARENA_POINTS, + CONFIG_UINT32_START_ARENA_POINTS, CONFIG_UINT32_CURRENCY_START_HONOR_POINTS, CONFIG_UINT32_CURRENCY_START_CONQUEST_POINTS, CONFIG_UINT32_CURRENCY_CONQUEST_POINTS_DEFAULT_WEEK_CAP, @@ -190,6 +196,7 @@ enum eConfigUInt32Values CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE, CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER, + CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS, CONFIG_UINT32_ARENA_SEASON_ID, CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID, CONFIG_UINT32_CLIENTCACHE_VERSION, @@ -347,6 +354,7 @@ enum eConfigBoolValues CONFIG_BOOL_SKILL_FAIL_POSSIBLE_FISHINGPOOL, CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, + CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_JOIN, CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_EXIT, CONFIG_BOOL_OUTDOORPVP_SI_ENABLED, @@ -636,6 +644,7 @@ class World void SetMonthlyQuestResetTime(bool initialize = true); void ResetCurrencyWeekCounts(); void ResetDailyQuests(); + void ResetRandomBG(); void ResetWeeklyQuests(); void ResetMonthlyQuests(); @@ -714,7 +723,10 @@ class World time_t m_NextCurrencyReset; time_t m_NextDailyQuestReset; time_t m_NextWeeklyQuestReset; - time_t m_NextMonthlyQuestReset; + time_t m_NextMonthlyQuestReset; + + // next daily quests reset time + time_t m_NextRandomBGReset; // Player Queue Queue m_QueuedSessions; diff --git a/src/modules/Eluna/PlayerMethods.h b/src/modules/Eluna/PlayerMethods.h index b2540f742..59baad765 100644 --- a/src/modules/Eluna/PlayerMethods.h +++ b/src/modules/Eluna/PlayerMethods.h @@ -2104,7 +2104,7 @@ namespace LuaPlayer if (!quest || player->GetQuestStatus(entry) != QUEST_STATUS_COMPLETE) return 0; - player->RewardQuest(quest, 0, player); + player->RewardQuest(quest, 0, player, false); return 0; } diff --git a/src/modules/SD2/system/ScriptDevMgr.cpp b/src/modules/SD2/system/ScriptDevMgr.cpp index 222d121ae..3f585df48 100644 --- a/src/modules/SD2/system/ScriptDevMgr.cpp +++ b/src/modules/SD2/system/ScriptDevMgr.cpp @@ -148,7 +148,7 @@ void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* } debug_log("SD2: DoOrSimulateScriptTextForMap: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", - iTextEntry, pData->SoundId, pData->Type, pData->Language, pData->Emote); + iTextEntry, pData->SoundId, pData->Type, pData->LanguageId, pData->Emote); if (pData->Type != CHAT_TYPE_ZONE_YELL) { @@ -163,11 +163,11 @@ void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* if (pCreatureSource) // If provided pointer for sayer, use direct version { - pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->Language, pTarget); + pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->LanguageId, pTarget); } else // Simulate yell { - pMap->MonsterYellToMap(pInfo, iTextEntry, pData->Language, pTarget); + pMap->MonsterYellToMap(pInfo, iTextEntry, pData->LanguageId, pTarget); } }