Skip to content

Commit

Permalink
Until Fail Decorator (#296)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
RedstoneParadox authored Jan 10, 2024
1 parent b8703d7 commit c95040f
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 1 deletion.
45 changes: 45 additions & 0 deletions addons/beehave/icons/until_fail.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions addons/beehave/nodes/decorators/until_fail.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@tool
@icon("../../icons/until_fail.svg")
class_name UntilFailDecorator
extends Decorator

## The UntilFail Decorator will return `RUNNING` if its child returns
## `SUCCESS` or `RUNNING` or it will return `SUCCESS` if its child returns
## `FAILURE`

func tick(actor: Node, blackboard: Blackboard) -> int:
var c = get_child(0)

if c != running_child:
c.before_run(actor, blackboard)

var response = c.tick(actor, blackboard)
if can_send_message(blackboard):
BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)

if c is ConditionLeaf:
blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))

if response == RUNNING:
running_child = c
if c is ActionLeaf:
blackboard.set_value("running_action", c, str(actor.get_instance_id()))
return RUNNING
if response == SUCCESS:
return RUNNING

return SUCCESS

2 changes: 1 addition & 1 deletion addons/gdUnit4/GdUnitRunner.cfg
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"included":{"res://test/blackboard/blackboard_test.gd":["test_blackboard_property_shared_between_trees"]},"server_port":31002,"skipped":{},"version":"1.0"}
{"included":{"res://test/":[]},"server_port":31002,"skipped":{},"version":"1.0"}
6 changes: 6 additions & 0 deletions docs/manual/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ When first executing the `Delayer` node, it will start an internal timer and ret
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.

**Example:** A mob attacks you and has to wait before it can attack you again.

## UntilFail

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`.

**Example:** A turret fires upon any NPC in range until it does not detect any more NPCs.
44 changes: 44 additions & 0 deletions test/nodes/decorators/until_fail_test.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# GdUnit generated TestSuite
class_name UntilFailDecoratorTest
extends GdUnitTestSuite
@warning_ignore('unused_parameter')
@warning_ignore('return_value_discarded')

# TestSuite generated from
const __source = 'res://addons/beehave/nodes/decorators/until_fail.gd'
const __action = "res://test/actions/count_up_action.gd"
const __tree = "res://addons/beehave/nodes/beehave_tree.gd"
const __blackboard = "res://addons/beehave/blackboard.gd"

var tree: BeehaveTree
var action: ActionLeaf
var until_fail: UntilFailDecorator


func before_test() -> void:
tree = auto_free(load(__tree).new())
action = auto_free(load(__action).new())
until_fail = auto_free(load(__source).new())

var actor = auto_free(Node2D.new())
var blackboard = auto_free(load(__blackboard).new())

tree.add_child(until_fail)
until_fail.add_child(action)

tree.actor = actor
tree.blackboard = blackboard

func test_failure() -> void:
action.status = BeehaveNode.RUNNING

for i in range(100):
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING)

action.status = BeehaveNode.SUCCESS

for i in range(100):
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING)

action.status = BeehaveNode.FAILURE
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS)

0 comments on commit c95040f

Please sign in to comment.