mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Scripts: Added script hook to execute actions after completing an achievement (#27718)
This commit is contained in:
24
sql/updates/world/master/2022_02_08_00_world.sql
Normal file
24
sql/updates/world/master/2022_02_08_00_world.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
--
|
||||
-- Table structure for table `achievement_scripts`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `achievement_scripts`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `achievement_scripts` (
|
||||
`AchievementId` int NOT NULL,
|
||||
`ScriptName` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`AchievementId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `achievement_scripts`
|
||||
--
|
||||
LOCK TABLES `achievement_scripts` WRITE;
|
||||
/*!40000 ALTER TABLE `achievement_scripts` DISABLE KEYS */;
|
||||
INSERT INTO `achievement_scripts` (`AchievementId`, `ScriptName`) VALUES
|
||||
(6566,'achievement_just_a_pup'),
|
||||
(7433,'achievement_newbie');
|
||||
/*!40000 ALTER TABLE `achievement_scripts` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "RBAC.h"
|
||||
#include "StringConvert.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include <sstream>
|
||||
@@ -535,6 +536,8 @@ void PlayerAchievementMgr::CompletedAchievement(AchievementEntry const* achievem
|
||||
UpdateCriteria(CriteriaType::EarnAchievement, achievement->ID, 0, 0, nullptr, referencePlayer);
|
||||
UpdateCriteria(CriteriaType::EarnAchievementPoints, achievement->Points, 0, 0, nullptr, referencePlayer);
|
||||
|
||||
sScriptMgr->OnAchievementCompleted(referencePlayer, achievement);
|
||||
|
||||
// reward items and titles if any
|
||||
AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement);
|
||||
|
||||
@@ -985,6 +988,8 @@ void GuildAchievementMgr::CompletedAchievement(AchievementEntry const* achieveme
|
||||
|
||||
UpdateCriteria(CriteriaType::EarnAchievement, achievement->ID, 0, 0, nullptr, referencePlayer);
|
||||
UpdateCriteria(CriteriaType::EarnAchievementPoints, achievement->Points, 0, 0, nullptr, referencePlayer);
|
||||
|
||||
sScriptMgr->OnAchievementCompleted(referencePlayer, achievement);
|
||||
}
|
||||
|
||||
void GuildAchievementMgr::SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, Seconds /*timeElapsed*/, bool /*timedCompleted*/) const
|
||||
@@ -1140,6 +1145,39 @@ void AchievementGlobalMgr::LoadAchievementReferenceList()
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u achievement references in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void AchievementGlobalMgr::LoadAchievementScripts()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_achievementScripts.clear(); // need for reload case
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT AchievementId, ScriptName FROM achievement_scripts");
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 achievement scripts. DB table `achievement_scripts` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 achievementId = fields[0].GetUInt32();
|
||||
std::string scriptName = fields[1].GetString();
|
||||
|
||||
AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId);
|
||||
if (!achievement)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Table `achievement_scripts` contains non-existing Achievement (ID: %u), skipped.", achievementId);
|
||||
continue;
|
||||
}
|
||||
_achievementScripts[achievementId] = sObjectMgr->GetScriptId(scriptName);
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " achievement scripts in %u ms", _achievementScripts.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
@@ -1338,3 +1376,10 @@ void AchievementGlobalMgr::LoadRewardLocales()
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms.", uint32(_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
uint32 AchievementGlobalMgr::GetAchievementScriptId(uint32 achievementId) const
|
||||
{
|
||||
if (uint32 const* scriptId = Trinity::Containers::MapGetValuePtr(_achievementScripts, achievementId))
|
||||
return *scriptId;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -160,10 +160,13 @@ public:
|
||||
void SetRealmCompleted(AchievementEntry const* achievement);
|
||||
|
||||
void LoadAchievementReferenceList();
|
||||
void LoadAchievementScripts();
|
||||
void LoadCompletedAchievements();
|
||||
void LoadRewards();
|
||||
void LoadRewardLocales();
|
||||
|
||||
uint32 GetAchievementScriptId(uint32 achievementId) const;
|
||||
|
||||
private:
|
||||
// store achievements by referenced achievement id to speed up lookup
|
||||
std::unordered_map<uint32, std::vector<AchievementEntry const*>> _achievementListByReferencedId;
|
||||
@@ -175,6 +178,7 @@ private:
|
||||
|
||||
std::unordered_map<uint32, AchievementReward> _achievementRewards;
|
||||
std::unordered_map<uint32, AchievementRewardLocale> _achievementRewardLocales;
|
||||
std::unordered_map<uint32, uint32> _achievementScripts;
|
||||
};
|
||||
|
||||
#define sAchievementMgr AchievementGlobalMgr::Instance()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "AchievementMgr.h"
|
||||
#include "AreaTrigger.h"
|
||||
#include "AreaTriggerAI.h"
|
||||
#include "Chat.h"
|
||||
@@ -108,6 +109,10 @@ template<>
|
||||
struct is_script_database_bound<TransportScript>
|
||||
: std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_script_database_bound<AchievementScript>
|
||||
: std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_script_database_bound<AchievementCriteriaScript>
|
||||
: std::true_type { };
|
||||
@@ -1938,6 +1943,16 @@ void ScriptMgr::OnShutdown()
|
||||
FOREACH_SCRIPT(WorldScript)->OnShutdown();
|
||||
}
|
||||
|
||||
// Achievement
|
||||
void ScriptMgr::OnAchievementCompleted(Player* player, AchievementEntry const* achievement)
|
||||
{
|
||||
ASSERT(player);
|
||||
ASSERT(achievement);
|
||||
|
||||
GET_SCRIPT(AchievementScript, sAchievementMgr->GetAchievementScriptId(achievement->ID), tmpscript);
|
||||
tmpscript->OnCompleted(player, achievement);
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target)
|
||||
{
|
||||
ASSERT(source);
|
||||
@@ -2511,6 +2526,12 @@ TransportScript::TransportScript(char const* name)
|
||||
ScriptRegistry<TransportScript>::Instance()->AddScript(this);
|
||||
}
|
||||
|
||||
AchievementScript::AchievementScript(char const* name)
|
||||
: ScriptObject(name)
|
||||
{
|
||||
ScriptRegistry<AchievementScript>::Instance()->AddScript(this);
|
||||
}
|
||||
|
||||
AchievementCriteriaScript::AchievementCriteriaScript(char const* name)
|
||||
: ScriptObject(name)
|
||||
{
|
||||
@@ -2587,6 +2608,7 @@ template class TC_GAME_API ScriptRegistry<ConditionScript>;
|
||||
template class TC_GAME_API ScriptRegistry<VehicleScript>;
|
||||
template class TC_GAME_API ScriptRegistry<DynamicObjectScript>;
|
||||
template class TC_GAME_API ScriptRegistry<TransportScript>;
|
||||
template class TC_GAME_API ScriptRegistry<AchievementScript>;
|
||||
template class TC_GAME_API ScriptRegistry<AchievementCriteriaScript>;
|
||||
template class TC_GAME_API ScriptRegistry<PlayerScript>;
|
||||
template class TC_GAME_API ScriptRegistry<GuildScript>;
|
||||
|
||||
@@ -66,6 +66,7 @@ class WorldSocket;
|
||||
class WorldObject;
|
||||
class WorldSession;
|
||||
|
||||
struct AchievementEntry;
|
||||
struct AreaTriggerEntry;
|
||||
struct AuctionPosting;
|
||||
struct ConditionSourceInfo;
|
||||
@@ -622,6 +623,18 @@ class TC_GAME_API TransportScript : public ScriptObject, public UpdatableScript<
|
||||
virtual void OnRelocate(Transport* /*transport*/, uint32 /*waypointId*/, uint32 /*mapId*/, float /*x*/, float /*y*/, float /*z*/) { }
|
||||
};
|
||||
|
||||
class TC_GAME_API AchievementScript : public ScriptObject
|
||||
{
|
||||
protected:
|
||||
|
||||
AchievementScript(char const* name);
|
||||
|
||||
public:
|
||||
|
||||
// Called when an achievement is completed.
|
||||
virtual void OnCompleted(Player* /*player*/, AchievementEntry const* /*achievement*/) { }
|
||||
};
|
||||
|
||||
class TC_GAME_API AchievementCriteriaScript : public ScriptObject
|
||||
{
|
||||
protected:
|
||||
@@ -1085,6 +1098,10 @@ class TC_GAME_API ScriptMgr
|
||||
void OnTransportUpdate(Transport* transport, uint32 diff);
|
||||
void OnRelocate(Transport* transport, uint32 waypointId, uint32 mapId, float x, float y, float z);
|
||||
|
||||
public: /* AchievementScript */
|
||||
|
||||
void OnAchievementCompleted(Player* player, AchievementEntry const* achievement);
|
||||
|
||||
public: /* AchievementCriteriaScript */
|
||||
|
||||
bool OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target);
|
||||
|
||||
@@ -2149,6 +2149,8 @@ void World::SetInitialWorldSettings()
|
||||
sCriteriaMgr->LoadCriteriaData();
|
||||
TC_LOG_INFO("server.loading", "Loading Achievements...");
|
||||
sAchievementMgr->LoadAchievementReferenceList();
|
||||
TC_LOG_INFO("server.loading", "Loading Achievements Scripts...");
|
||||
sAchievementMgr->LoadAchievementScripts();
|
||||
TC_LOG_INFO("server.loading", "Loading Achievement Rewards...");
|
||||
sAchievementMgr->LoadRewards();
|
||||
TC_LOG_INFO("server.loading", "Loading Achievement Reward Locales...");
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "BattlegroundSA.h"
|
||||
#include "BattlegroundIC.h"
|
||||
#include "BattlePetMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "Player.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
class achievement_resilient_victory : public AchievementCriteriaScript
|
||||
{
|
||||
@@ -289,6 +291,31 @@ class achievement_killed_exp_or_honor_target : public AchievementCriteriaScript
|
||||
}
|
||||
};
|
||||
|
||||
// 7433 - Newbie
|
||||
class achievement_newbie : public AchievementScript
|
||||
{
|
||||
public:
|
||||
achievement_newbie() : AchievementScript("achievement_newbie") { }
|
||||
|
||||
void OnCompleted(Player* player, AchievementEntry const* /*achievement*/) override
|
||||
{
|
||||
player->GetSession()->GetBattlePetMgr()->UnlockSlot(BattlePets::BattlePetSlot::Slot1);
|
||||
// TODO: Unlock trap
|
||||
}
|
||||
};
|
||||
|
||||
// 6566 - Just a Pup
|
||||
class achievement_just_a_pup : public AchievementScript
|
||||
{
|
||||
public:
|
||||
achievement_just_a_pup() : AchievementScript("achievement_just_a_pup") { }
|
||||
|
||||
void OnCompleted(Player* player, AchievementEntry const* /*achievement*/) override
|
||||
{
|
||||
player->GetSession()->GetBattlePetMgr()->UnlockSlot(BattlePets::BattlePetSlot::Slot2);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_achievement_scripts()
|
||||
{
|
||||
new achievement_resilient_victory();
|
||||
@@ -309,4 +336,6 @@ void AddSC_achievement_scripts()
|
||||
new achievement_not_even_a_scratch();
|
||||
new achievement_flirt_with_disaster_perf_check();
|
||||
new achievement_killed_exp_or_honor_target();
|
||||
new achievement_newbie();
|
||||
new achievement_just_a_pup();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user