Skip to content

Commit c95040f

Browse files
Until Fail Decorator (#296)
* Create Until Fail Decorator * Create unit test for UntilFail decorator * UntilFail decorator returns SUCCESS on child FAILURE * Fixed until fail unit test * UntilFail documentation * UntilFail icon
1 parent b8703d7 commit c95040f

File tree

5 files changed

+129
-1
lines changed

5 files changed

+129
-1
lines changed
Lines changed: 45 additions & 0 deletions
Loading
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@tool
2+
@icon("../../icons/until_fail.svg")
3+
class_name UntilFailDecorator
4+
extends Decorator
5+
6+
## The UntilFail Decorator will return `RUNNING` if its child returns
7+
## `SUCCESS` or `RUNNING` or it will return `SUCCESS` if its child returns
8+
## `FAILURE`
9+
10+
func tick(actor: Node, blackboard: Blackboard) -> int:
11+
var c = get_child(0)
12+
13+
if c != running_child:
14+
c.before_run(actor, blackboard)
15+
16+
var response = c.tick(actor, blackboard)
17+
if can_send_message(blackboard):
18+
BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
19+
20+
if c is ConditionLeaf:
21+
blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
22+
blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
23+
24+
if response == RUNNING:
25+
running_child = c
26+
if c is ActionLeaf:
27+
blackboard.set_value("running_action", c, str(actor.get_instance_id()))
28+
return RUNNING
29+
if response == SUCCESS:
30+
return RUNNING
31+
32+
return SUCCESS
33+

addons/gdUnit4/GdUnitRunner.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"included":{"res://test/blackboard/blackboard_test.gd":["test_blackboard_property_shared_between_trees"]},"server_port":31002,"skipped":{},"version":"1.0"}
1+
{"included":{"res://test/":[]},"server_port":31002,"skipped":{},"version":"1.0"}

docs/manual/decorators.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ When first executing the `Delayer` node, it will start an internal timer and ret
3939
The `Cooldown` node executes its child until it either returns `SUCCESS` or `FAILURE`, after which it will start an internal timer and return `FAILURE` until the timer is complete. The cooldown is then able to execute its child again.
4040

4141
**Example:** A mob attacks you and has to wait before it can attack you again.
42+
43+
## UntilFail
44+
45+
The `UntilFail` node executes its child and returns `RUNNING` as long as it returns either `RUNNING` or `SUCCESS`. If its child returns `FAILURE`, it will instead return `SUCCESS`.
46+
47+
**Example:** A turret fires upon any NPC in range until it does not detect any more NPCs.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# GdUnit generated TestSuite
2+
class_name UntilFailDecoratorTest
3+
extends GdUnitTestSuite
4+
@warning_ignore('unused_parameter')
5+
@warning_ignore('return_value_discarded')
6+
7+
# TestSuite generated from
8+
const __source = 'res://addons/beehave/nodes/decorators/until_fail.gd'
9+
const __action = "res://test/actions/count_up_action.gd"
10+
const __tree = "res://addons/beehave/nodes/beehave_tree.gd"
11+
const __blackboard = "res://addons/beehave/blackboard.gd"
12+
13+
var tree: BeehaveTree
14+
var action: ActionLeaf
15+
var until_fail: UntilFailDecorator
16+
17+
18+
func before_test() -> void:
19+
tree = auto_free(load(__tree).new())
20+
action = auto_free(load(__action).new())
21+
until_fail = auto_free(load(__source).new())
22+
23+
var actor = auto_free(Node2D.new())
24+
var blackboard = auto_free(load(__blackboard).new())
25+
26+
tree.add_child(until_fail)
27+
until_fail.add_child(action)
28+
29+
tree.actor = actor
30+
tree.blackboard = blackboard
31+
32+
func test_failure() -> void:
33+
action.status = BeehaveNode.RUNNING
34+
35+
for i in range(100):
36+
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING)
37+
38+
action.status = BeehaveNode.SUCCESS
39+
40+
for i in range(100):
41+
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING)
42+
43+
action.status = BeehaveNode.FAILURE
44+
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS)

0 commit comments

Comments
 (0)