Core/Scripts: Added script hook to execute actions after completing an achievement (#27718)

This commit is contained in:
Meji
2022-02-08 23:23:05 +01:00
committed by GitHub
parent 8e2d1e328e
commit 27cba3f523
7 changed files with 143 additions and 0 deletions

View 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;

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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>;

View File

@@ -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);

View File

@@ -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...");

View File

@@ -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();
}