Skip to content

Commit 247d713

Browse files
committed
Add TryActivateAbilityEffect class (resolves #8)
This commit also modifies the behavior of `Effect` to only call `Effect.start` right before ticking. This is helpful for sequential mode, because previously all effects would be started upon instantiation, which is unintuitively non-sequential.
1 parent a62d070 commit 247d713

File tree

8 files changed

+74
-7
lines changed

8 files changed

+74
-7
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ This is where the bulk of your custom game logic will go. It has access to the `
7777
* `AttributeEffect` - modifies an `Attribute`
7878
* `TagEffect` - adds or removes `Tag`s from `AbilitySystem`
7979
* `WaitEffect` - arbitrarily delays `AbilityEvent`
80+
* `TryActivateAbilityEffect` - attempts to activate an `Ability` on the `AbilitySystem`
8081

8182
### `Tag`
8283

src/ability_event.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ void AbilityEvent::_bind_methods() {
2020
void AbilityEvent::start(AbilitySystem *owner) {
2121
status = Status::READY;
2222
effect_instances.clear();
23-
for_each(this->ability->get_effects(), [this, owner](Ref<Effect> effect) {
24-
Ref<Effect> instance = effect->duplicate(true);
23+
for_each_i(this->ability->get_effects(), [this, owner](Ref<Effect> effect, int i) {
24+
Ref<Effect> instance = effect->duplicate(false);
2525
effect_instances.append(instance);
26-
instance->start(owner);
26+
// Start the first effect (when in sequential mode) or all effects (when in parallel mode)
27+
if (i == 0 || ability->effect_mode == EffectMode::PARALLEL)
28+
instance->start(owner);
2729
});
2830
status = Status::RUNNING;
2931
}
@@ -70,17 +72,24 @@ void AbilityEvent::tick_parallel(AbilitySystem *owner, float delta) {
7072
}
7173

7274
void AbilityEvent::tick_sequential(AbilitySystem *owner, float delta) {
75+
Status current_status = Status::READY;
7376
// Tick the first effect, if it exists.
7477
if (effect_instances.size()) {
7578
Ref<Effect> effect = effect_instances[0];
76-
Status effect_status = effect->tick(owner, delta);
79+
current_status = effect->tick(owner, delta);
7780
// If the first effect is finished, remove it from the list.
78-
if (effect_status == Status::FINISHED) {
81+
if (current_status == Status::FINISHED) {
7982
effect_instances.pop_front();
8083
emit_signal(as_signal::EffectFinished, effect);
8184
owner->emit_signal(as_signal::EffectsChanged);
8285
}
8386
}
87+
88+
// Start the next effect, if it exists and is not already running.
89+
if (current_status != Status::RUNNING && effect_instances.size()) {
90+
Ref<Effect> effect = effect_instances[0];
91+
effect->start(owner);
92+
}
8493
}
8594

8695
String AbilityEvent::_to_string() const {

src/effect/attribute_effect.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ int AttributeEffect::_tick(AbilitySystem *owner, float delta) {
2323
float effect = RANDF_RANGE(min_effect, max_effect);
2424
owner->modify_attribute_value(attribute, effect);
2525
} else {
26-
print_error("Searching for attribute: " + stringify_variants(attribute));
27-
print_error("Owner missing attribute! (attributes are " + stringify_variants(owner->get_attribute_dict()) + ")");
26+
print_error("Searching for attribute: " + stringify(attribute));
27+
print_error("Owner missing attribute! (attributes are " + stringify(owner->get_attribute_dict()) + ")");
2828
}
2929
return Status::FINISHED;
3030
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "try_activate_ability_effect.h"
2+
3+
#include <godot_cpp/variant/utility_functions.hpp>
4+
5+
#include "../ability_system.h"
6+
7+
void TryActivateAbilityEffect::_bind_methods() {
8+
BIND_GETSET(TryActivateAbilityEffect, ability);
9+
10+
OBJECT_PROP(Ability, ability);
11+
}
12+
13+
void TryActivateAbilityEffect::_start(AbilitySystem *owner) {
14+
if (ability.is_null()) {
15+
print_error("No ability provided!");
16+
return;
17+
}
18+
19+
if (!owner->has_ability(ability)) {
20+
String message = fmt(
21+
"Owner is missing ability {0}! Has abilities: {1}",
22+
ability->to_string(),
23+
stringify(owner->get_abilities())
24+
);
25+
print_error(message);
26+
} else if (!owner->can_activate(ability))
27+
print_error(fmt("Owner cannot activate ability {0}!", ability->to_string()));
28+
29+
owner->activate(ability);
30+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef AS_TRYACTIVATEABILITYEFFECT_HPP
2+
#define AS_TRYACTIVATEABILITYEFFECT_HPP
3+
4+
#include "../ability.hpp"
5+
#include "effect.h"
6+
7+
class TryActivateAbilityEffect : public Effect {
8+
GDCLASS(TryActivateAbilityEffect, Effect);
9+
10+
private:
11+
Ref<Ability> ability;
12+
13+
protected:
14+
static void _bind_methods();
15+
16+
public:
17+
GETSET_RESOURCE(Ref<Ability>, ability)
18+
19+
virtual void _start(AbilitySystem *owner) override;
20+
virtual int _tick(AbilitySystem *owner, float delta) override {
21+
return Status::FINISHED;
22+
}
23+
};
24+
25+
#endif

src/register_types.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "effect/attribute_effect.h"
1616
#include "effect/tag_effect.h"
1717
#include "effect/wait_effect.hpp"
18+
#include "effect/try_activate_ability_effect.h"
1819

1920
// Editor
2021
#include "editor/viewer_base.h"
@@ -45,6 +46,7 @@ void initialize_ability_system_module(ModuleInitializationLevel p_level) {
4546
ClassDB::register_class<WaitEffect>();
4647
ClassDB::register_class<AttributeEffect>();
4748
ClassDB::register_class<TagEffect>();
49+
ClassDB::register_class<TryActivateAbilityEffect>();
4850
ClassDB::register_class<AbilitySystem>();
4951

5052
// Editor

0 commit comments

Comments
 (0)