Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: eventcallbacks which returns a ReturnValue #2532

Merged
33 changes: 28 additions & 5 deletions data/scripts/eventcallbacks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Event callbacks are available for several categories of game entities, such as `
### These are the functions available to use

- `(bool)` `creatureOnChangeOutfit`
- `(bool)` `creatureOnAreaCombat`
- `(bool)` `creatureOnTargetCombat`
- `(ReturnValue)` `creatureOnAreaCombat`
- `(ReturnValue)` `creatureOnTargetCombat`
- `(void)` `creatureOnHear`
- `(void)` `creatureOnDrainHealth`
- `(bool)` `partyOnJoin`
Expand Down Expand Up @@ -66,7 +66,7 @@ local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
-- custom behavior when a creature enters combat area
return true
return RETURNVALUE_NOERROR
end

callback:register()
Expand Down Expand Up @@ -131,21 +131,44 @@ Here is an example of a boolean event callback:
```lua
local callback = EventCallback()

function callback.playerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)
if item:getId() == ITEM_PARCEL then
--Custom behavior when the player moves a parcel.
return false
end
return true
end

callback:register()
```

### In this example, when a player moves an item, the function checks if the item is a parcel and apply a custom behaviour, returning false making it impossible to move, stopping the associated function on the C++ side.

## ReturnValue Event Callbacks

Some event callbacks are expected to return a enum value, in this case, the enum ReturnValue. If the return is different of RETURNVALUE_NOERROR, it will stop the execution of the next callbacks.

Here is an example of a ReturnValue event callback:

```lua
local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
-- if the creature is not aggressive, stop the execution of the C++ function
if not isAggressive then
return false
return RETURNVALUE_NOTPOSSIBLE
end

-- custom behavior when an aggressive creature enters a combat area
return true
return RETURNVALUE_NOERROR
end

callback:register()
```

### In this example, when a non-aggressive creature enters a combat area, the creatureOnAreaCombat function returns false, stopping the associated function on the C++ side.


## Multiple Callbacks for the Same Event

You can define multiple callbacks for the same event type. This allows you to encapsulate different behaviors in separate callbacks, making your code more modular and easier to manage.
Expand Down
2 changes: 1 addition & 1 deletion data/scripts/eventcallbacks/creature/on_area_combat.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local callback = EventCallback()

function callback.creatureOnAreaCombat(creature, tile, isAggressive)
return true
return RETURNVALUE_NOERROR
end

callback:register()
15 changes: 12 additions & 3 deletions src/creatures/combat/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "items/weapons/weapons.hpp"
#include "map/spectators.hpp"
#include "lib/metrics/metrics.hpp"
#include "lua/callbacks/event_callback.hpp"
#include "lua/callbacks/events_callbacks.hpp"

int32_t Combat::getLevelFormula(std::shared_ptr<Player> player, const std::shared_ptr<Spell> wheelSpell, const CombatDamage &damage) const {
if (!player) {
Expand Down Expand Up @@ -273,8 +275,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr<Creature> caster, std::shared_pt
}
}
}

return g_events().eventCreatureOnAreaCombat(caster, tile, aggressive);
ReturnValue ret = g_events().eventCreatureOnAreaCombat(caster, tile, aggressive);
if (ret == RETURNVALUE_NOERROR) {
ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnAreaCombat, caster, tile, aggressive);
}
return ret;
}

bool Combat::isInPvpZone(std::shared_ptr<Creature> attacker, std::shared_ptr<Creature> target) {
Expand Down Expand Up @@ -409,7 +414,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr<Creature> attacker, std::shared_
}
}
}
return g_events().eventCreatureOnTargetCombat(attacker, target);
ReturnValue ret = g_events().eventCreatureOnTargetCombat(attacker, target);
if (ret == RETURNVALUE_NOERROR) {
ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnTargetCombat, attacker, target);
}
return ret;
}

void Combat::setPlayerCombatValues(formulaType_t newFormulaType, double newMina, double newMinb, double newMaxa, double newMaxb) {
Expand Down
26 changes: 26 additions & 0 deletions src/lua/callbacks/events_callbacks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,32 @@ class EventsCallbacks {
}
}
}
/**
* @brief Checks if all registered callbacks of the specified event type succeed.
* @param eventType The type of event to check.
* @param callbackFunc Function pointer to the callback method.
* @param args Variadic arguments to pass to the callback function.
* @return ReturnValue enum.
*/
template <typename CallbackFunc, typename... Args>
ReturnValue checkCallbackWithReturnValue(EventCallback_t eventType, CallbackFunc callbackFunc, Args &&... args) {
ReturnValue res = RETURNVALUE_NOERROR;
for (const auto &callback : getCallbacksByType(eventType)) {
auto argsCopy = std::make_tuple(args...);
if (callback && callback->isLoadedCallback()) {
ReturnValue callbackResult = std::apply(
[&callback, &callbackFunc](auto &&... args) {
return ((*callback).*callbackFunc)(std::forward<decltype(args)>(args)...);
},
argsCopy
);
if (callbackResult != RETURNVALUE_NOERROR) {
return callbackResult;
}
}
}
return res;
}

/**
* @brief Checks if all registered callbacks of the specified event type succeed.
Expand Down
Loading