Added new event handler system for creature events to allow for balancing

This commit is contained in:
2024-10-10 00:55:00 -04:00
parent cbec66031d
commit 25f74e1b5a
5 changed files with 173 additions and 93 deletions

View File

@@ -1,81 +1,50 @@
#include <functional>
#include <unordered_map>
#include <vector>
#include <memory>
#include "Creature.h"
#include "CreatureHooks.h"
#include "MpLogger.h"
void CreatureHooks::RegisterJustDied(uint32 entry, CreatureHook<Creature*, Unit*> callback) {
(*_JustDiedHandlers)[entry].push_back(callback);
}
class CreatureHooks {
private:
// Define type aliases for cleaner code
using EventCallback = std::function<void(Creature*)>;
using EventList = std::vector<EventCallback>;
using EventMap = std::unordered_map<uint32, EventList>;
void CreatureHooks::RegisterOnSpawn(uint32 entry, CreatureHook<Creature*>callback) {
(*_OnSpawnHandlers)[entry].push_back(callback);
}
// Constructor
CreatureHooks() = default;
void CreatureHooks::RegisterOnAddToInstance(uint32 entry, uint32 mapId, uint32 instanceId, CreatureHook<Creature*> callback) {
(*_OnAddToInstanceHandlers)[entry].push_back(callback);
}
// Use the type aliases for readability
std::unique_ptr<EventMap> _spawnedEvents = std::make_unique<EventMap>();
std::unique_ptr<EventMap> _isDeadEvents = std::make_unique<EventMap>();
std::unique_ptr<std::unordered_map<uint32, std::unordered_map<uint8, EventList>>> _healthPercentEvents
= std::make_unique<std::unordered_map<uint32, std::unordered_map<uint8, EventList>>>();
// Call health events if the creature's health is at or below the percentage
// void CheckHealthEvents(Creature* creature) {
// uint32 entry = creature->GetEntry();
// uint32 currentHealthPct = creature->GetHealthPct();
public:
// Singleton instance access method
static CreatureHooks* instance() {
static CreatureHooks instance;
return &instance;
}
// if (_healthPercentEvents->contains(entry)) {
// for (const auto& [percent, callbacks] : _healthPercentEvents->at(entry)) {
// if (currentHealthPct <= percent) {
// for (auto& callback : callbacks) {
// callback(creature); // Trigger custom behavior
// }
// }
// }
// }
// }
// Register events for health at a certain percentage
void RegisterHealthAtPercentHook(uint32 entry, uint8 percent, EventCallback callback) {
(*_healthPercentEvents)[entry][percent].push_back(callback);
}
void CreatureHooks::JustDied(Creature* creature, Unit* killer) {
uint32 entry = creature->GetEntry();
// Register "Is Dead" events
void RegisterIsDeadHook(uint32 entry, EventCallback callback) {
(*_isDeadEvents)[entry].push_back(callback);
}
// Register "Spawned" events
void RegisterSpawnedHook(uint32 entry, EventCallback callback) {
(*_spawnedEvents)[entry].push_back(callback);
}
// Call health events if the creature's health is at or below the percentage
void CheckHealthEvents(Creature* creature) {
uint32 entry = creature->GetEntry();
uint32 currentHealthPct = creature->GetHealthPct();
if (_healthPercentEvents->contains(entry)) {
for (const auto& [percent, callbacks] : _healthPercentEvents->at(entry)) {
if (currentHealthPct <= percent) {
for (auto& callback : callbacks) {
callback(creature); // Trigger custom behavior
}
}
}
if (_JustDiedHandlers->contains(entry)) {
for (auto& callback : _JustDiedHandlers->at(entry)) {
callback(creature, killer);
}
}
}
// Call "Is Dead" events if the creature is dead
void CheckIsDeadEvent(Creature* creature) {
uint32 entry = creature->GetEntry();
if (!creature->IsAlive() && _isDeadEvents->contains(entry)) {
for (auto& callback : _isDeadEvents->at(entry)) {
callback(creature); // Trigger custom behavior
}
void CreatureHooks::JustSpawned(Creature* creature) {
uint32 entry = creature->GetEntry();
if (_OnSpawnHandlers->contains(entry)) {
for (auto& callback : _OnSpawnHandlers->at(entry)) {
callback(creature);
}
}
// Call "Spawned" events when the creature spawns
void CheckSpawnedEvent(Creature* creature) {
uint32 entry = creature->GetEntry();
if (_spawnedEvents->contains(entry)) {
for (auto& callback : _spawnedEvents->at(entry)) {
callback(creature); // Trigger custom behavior
}
}
}
};
}

74
src/CreatureHooks.h Normal file
View File

@@ -0,0 +1,74 @@
#ifndef CREATUREHOOKS_H
#define CREATUREHOOKS_H
#include <functional>
#include <unordered_map>
#include <vector>
#include <memory>
#include "Creature.h"
#include "ObjectGuid.h"
// Struct to store the state of which handlers have been fired for a creature
struct CreatureEventState {
bool onDeathEventFired = false;
bool onSpawnEventFired = false;
bool onAddedToInstanceEventFired = false;
uint8 deaths = 0; // Count of deaths
};
// Type aliases for creature event handling
// using CreatureHook = std::function<void(Creature*)>;
// using HookList = std::vector<CreatureHook>;
// using HandlerMap = std::unordered_map<uint32, HookList>;
// Type alias for variadic event hooks
template<typename... Args>
using CreatureHook = std::function<void(Args...)>;
// Type alias for a list of hooks that take varying arguments
template<typename... Args>
using HandlersList = std::vector<CreatureHook<Args...>>;
// HandlerMap using variadic templates
template<typename... Args>
using HandlerMap = std::unordered_map<uint32, HandlersList<Args...>>;
using CreatureEventStateMap = std::map<ObjectGuid, CreatureEventState>;
class CreatureHooks {
private:
CreatureHooks() { }
~CreatureHooks() { }
// ensure we only ever have one instance of this class
CreatureHooks(const CreatureHooks&) = delete;
CreatureHooks& operator=(const CreatureHooks&) = delete;
// Data members for storing event handlers
std::unique_ptr<HandlerMap<Creature*>> _OnSpawnHandlers;
std::unique_ptr<HandlerMap<Creature*, Unit*>> _JustDiedHandlers;
std::unique_ptr<HandlerMap<Creature*>> _OnAddToInstanceHandlers;
// Tracks state to know which handlers need to be fired again
std::unique_ptr<CreatureEventStateMap> _eventStates;
public:
static CreatureHooks* instance() {
static CreatureHooks instance;
return &instance;
}
// Register events for specific actions
void RegisterJustDied(uint32 entry, CreatureHook<Creature*, Unit*> callback);
void RegisterOnSpawn(uint32 entry, CreatureHook<Creature*> callback);
void RegisterOnAddToInstance(uint32 entry, uint32 mapId, uint32 instanceId, CreatureHook<Creature*> callback);
// Event triggers
void JustDied(Creature* creature, Unit* killer);
void JustSpawned(Creature* creature);
};
#define sCreatureHooks CreatureHooks::instance()
#endif // CREATUREHOOKS_H

View File

View File

@@ -1,24 +0,0 @@
#ifndef MP_EVENT_HANDLER_H
#define MP_EVENT_HANDLER_H
#include <functional>
#include <memory>
// Template class for handling different function signatures
template<typename... Args>
class MpEventHandler
{
public:
using EventCallback = std::function<void(Args...)>;
// Constructor to initialize with a callback function
EventCallback(CallbackFunction func);
// Method to call the stored function with arguments
void Call(Args... args);
private:
CallbackFunction _func;
};
#endif // MP_EVENT_HANDLER_H

61
src/MpScriptAI.h Normal file
View File

@@ -0,0 +1,61 @@
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureHooks.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#ifdef _ELUNA_CREATURE_AI_H
#include "ElunaCreatureAI.h"
#endif
class MpScriptAI : public ScriptedAI
{
public:
MpScriptAI(Creature* creature) : ScriptedAI(creature) {
#ifdef _ELUNA_CREATURE_AI_H
// Check if Eluna is attached to the creature
if (ElunaCreatureAI* eluna = dynamic_cast<ElunaCreatureAI*>(creature->AI())) {
elunaAI = eluna; // Store a pointer to the Eluna AI
} else {
elunaAI = nullptr; // No Eluna AI attached
}
#endif
}
// Example for JustDied event
void JustDied(Unit* killer) override {
sCreatureHooks->JustDied(me, killer);
#ifdef _ELUNA_CREATURE_AI_H
// If Eluna is attached, call its JustDied event
if (elunaAI){
elunaAI->JustDied(killer);
}
else
#endif
{
// If Eluna is not installed or not attached, call the default AI handler
ScriptedAI::JustDied(killer);
}
}
void Reset() override {
#ifdef _ELUNA_CREATURE_AI_H
// If Eluna is attached, call its Reset event
if (elunaAI){
elunaAI->Reset();
}
else
#endif
{
// Call the default AI handler
ScriptedAI::Reset();
}
}
private:
#ifdef ENABLE_ELUNA
ElunaCreatureAI* elunaAI; // Store a pointer to Eluna's AI if attached
#endif
};