├── script_templates
├── .gdignore
└── BeehaveNode
│ └── default.gd
├── .gitattributes
├── assets
├── animation
│ ├── die.res
│ ├── idle.res
│ ├── walk.res
│ ├── attack1.res
│ └── attack2.res
├── models
│ ├── cloud.res
│ ├── level.glb
│ ├── slime.glb
│ ├── textures
│ │ ├── rock.png
│ │ ├── fence.png
│ │ ├── grass.png
│ │ ├── slime.png
│ │ ├── vines.png
│ │ ├── bg-trees.png
│ │ ├── rock-edge.png
│ │ ├── rock.png.import
│ │ ├── fence.png.import
│ │ ├── grass.png.import
│ │ ├── slime.png.import
│ │ ├── vines.png.import
│ │ ├── bg-trees.png.import
│ │ └── rock-edge.png.import
│ ├── gobot
│ │ ├── model
│ │ │ ├── gobot.glb
│ │ │ ├── custom
│ │ │ │ ├── hurt.res
│ │ │ │ ├── run_step.res
│ │ │ │ ├── custom_lib.res
│ │ │ │ ├── hurt.res.depren
│ │ │ │ └── custom_lib.res.depren
│ │ │ ├── gobot_gobot_diffuse.png
│ │ │ ├── gobot_gobot_normal.png
│ │ │ ├── gobot_gobot_roughness.png
│ │ │ ├── gobot_gobot_diffuse.png.import
│ │ │ ├── gobot_gobot_roughness.png.import
│ │ │ └── gobot_gobot_normal.png.import
│ │ ├── textures
│ │ │ ├── open_eye.png
│ │ │ ├── closed_eyes.png
│ │ │ ├── hurt_eyes.png
│ │ │ ├── hurt_eyes.png.import
│ │ │ ├── open_eye.png.import
│ │ │ └── closed_eyes.png.import
│ │ └── materials
│ │ │ └── eye_mat.tres
│ ├── level_bg-trees-32-1.png
│ ├── level.glb.import
│ └── level_bg-trees-32-1.png.import
├── materials
│ ├── slime.material
│ ├── slime.material.depren
│ ├── transparent.tres
│ ├── red_overlay.tres
│ ├── grass-rock-edge.tres
│ ├── fence.tres
│ ├── bg_trees-dark.tres
│ ├── bg_trees.tres
│ ├── vines.tres
│ ├── grass-32.tres
│ ├── rock-32.tres
│ └── shadow.tres
├── default_env.tres
└── shaders
│ └── crumble.gdshader
├── scripts
├── AI
│ ├── damageable_settings.gd
│ ├── enemy_agent.gd
│ ├── ActionSlots
│ │ ├── action_slot.gd
│ │ └── as_hit.gd
│ ├── ground_check.gd
│ ├── death_helper.gd
│ ├── enemy_actions.gd
│ ├── avoid_obstacle.gd
│ ├── npc_actions.gd
│ └── ai_senses.gd
├── beehave
│ ├── bh_empty.gd
│ ├── bh_fail.gd
│ ├── bh_succeed.gd
│ ├── bh_test.gd
│ ├── bh_stop_navigation.gd
│ ├── bh_set_target_enemy.gd
│ ├── bh_set_idle.gd
│ ├── bh_start_navigation.gd
│ ├── bh_stop_rotate.gd
│ ├── bh_is_there_enemy.gd
│ ├── bh_is_at_destination.gd
│ ├── bh_is_moving.gd
│ ├── bh_wait_for_destination.gd
│ ├── bh_is_action_in_progress.gd
│ ├── bh_is_obstacle_close.gd
│ ├── bh_anim_travel.gd
│ ├── bh_is_idle.gd
│ ├── bh_get_enemy.gd
│ ├── bh_wait_for_action_complete.gd
│ ├── bh_back_up.gd
│ ├── bh_get_enemy_fallback.gd
│ ├── bh_is_anim_playing.gd
│ ├── bh_new_wander_target.gd
│ ├── bh_is_in_melee_range.gd
│ ├── bh_is_enemy_in_range.gd
│ ├── bh_is_enemy_in_hitbox.gd
│ ├── bh_wait_for_melee_range.gd
│ ├── bh_face_enemy.gd
│ ├── bh_wait_for_range.gd
│ ├── bh_face_enemy_ranged.gd
│ ├── bh_counter.gd
│ ├── bh_is_enemy_distance.gd
│ ├── bh_start_cooldown.gd
│ ├── bh_is_cooldown_done.gd
│ ├── bh_set_speed.gd
│ ├── bh_distance_from_start.gd
│ └── bh_rotating_cooldown.gd
├── Damageable
│ ├── object_damageable.gd
│ ├── damageable.gd
│ ├── attack_object.gd
│ ├── damage_dealer.gd
│ └── agent_damageable.gd
└── misc
│ ├── hit_sound.gd
│ ├── hit_flash.gd
│ ├── shadow_caster.gd
│ └── camera_movement.gd
├── addons
└── beehave
│ ├── plugin.cfg
│ ├── debug
│ ├── icons
│ │ ├── port_left.svg
│ │ ├── port_bottom.svg
│ │ ├── port_right.svg
│ │ ├── port_top.svg
│ │ ├── vertical_layout.svg
│ │ ├── horizontal_layout.svg
│ │ ├── port_top.svg.import
│ │ ├── port_left.svg.import
│ │ ├── port_right.svg.import
│ │ ├── port_bottom.svg.import
│ │ ├── vertical_layout.svg.import
│ │ └── horizontal_layout.svg.import
│ ├── global_debugger.gd
│ ├── debugger_messages.gd
│ ├── frames.gd
│ ├── debugger.gd
│ └── debugger_tab.gd
│ ├── nodes
│ ├── leaves
│ │ ├── condition.gd
│ │ ├── action.gd
│ │ ├── blackboard_erase.gd
│ │ ├── blackboard_has.gd
│ │ ├── blackboard_set.gd
│ │ ├── leaf.gd
│ │ └── blackboard_compare.gd
│ ├── decorators
│ │ ├── decorator.gd
│ │ ├── until_fail.gd
│ │ ├── until_success.gd
│ │ ├── failer.gd
│ │ ├── succeeder.gd
│ │ ├── inverter.gd
│ │ ├── delayer.gd
│ │ ├── cooldown.gd
│ │ ├── repeater.gd
│ │ ├── limiter.gd
│ │ ├── for_loop.gd
│ │ ├── time_limiter.gd
│ │ └── time_limiter_succeeder.gd
│ ├── composites
│ │ ├── composite.gd
│ │ ├── selector_reactive.gd
│ │ ├── sequence_star.gd
│ │ ├── sequence_reactive.gd
│ │ ├── selector.gd
│ │ ├── selector_random.gd
│ │ ├── success_sequence.gd
│ │ ├── sequence.gd
│ │ └── sequence_random.gd
│ └── beehave_node.gd
│ ├── utils
│ └── utils.gd
│ ├── plugin.gd
│ ├── icons
│ ├── delayer.svg.import
│ ├── cooldown.svg.import
│ ├── repeater.svg.import
│ ├── until_fail.svg.import
│ ├── tree.svg.import
│ ├── action.svg.import
│ ├── failer.svg.import
│ ├── inverter.svg.import
│ ├── limiter.svg.import
│ ├── selector.svg.import
│ ├── sequence.svg.import
│ ├── condition.svg.import
│ ├── succeeder.svg.import
│ ├── blackboard.svg.import
│ ├── category_bt.svg.import
│ ├── category_leaf.svg.import
│ ├── selector_random.svg.import
│ ├── sequence_random.svg.import
│ ├── sequence_reactive.svg.import
│ ├── category_composite.svg.import
│ ├── category_decorator.svg.import
│ ├── selector_reactive.svg.import
│ ├── cooldown.svg
│ ├── blackboard.svg
│ ├── delayer.svg
│ ├── succeeder.svg
│ ├── limiter.svg
│ ├── tree.svg
│ ├── failer.svg
│ ├── inverter.svg
│ ├── sequence.svg
│ ├── selector.svg
│ ├── condition.svg
│ ├── repeater.svg
│ ├── action.svg
│ ├── selector_reactive.svg
│ ├── category_bt.svg
│ └── category_leaf.svg
│ ├── LICENSE
│ ├── metrics
│ └── beehave_global_metrics.gd
│ └── blackboard.gd
├── .gitignore
├── LICENSE
├── README.md
└── scenes
├── beehave-trees
└── SimpleWander.tscn
└── demo-level.tscn
/script_templates/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/assets/animation/die.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/animation/die.res
--------------------------------------------------------------------------------
/assets/models/cloud.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/cloud.res
--------------------------------------------------------------------------------
/assets/models/level.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/level.glb
--------------------------------------------------------------------------------
/assets/models/slime.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/slime.glb
--------------------------------------------------------------------------------
/assets/animation/idle.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/animation/idle.res
--------------------------------------------------------------------------------
/assets/animation/walk.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/animation/walk.res
--------------------------------------------------------------------------------
/assets/animation/attack1.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/animation/attack1.res
--------------------------------------------------------------------------------
/assets/animation/attack2.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/animation/attack2.res
--------------------------------------------------------------------------------
/assets/materials/slime.material:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/materials/slime.material
--------------------------------------------------------------------------------
/assets/models/textures/rock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/rock.png
--------------------------------------------------------------------------------
/assets/models/textures/fence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/fence.png
--------------------------------------------------------------------------------
/assets/models/textures/grass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/grass.png
--------------------------------------------------------------------------------
/assets/models/textures/slime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/slime.png
--------------------------------------------------------------------------------
/assets/models/textures/vines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/vines.png
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/gobot.glb
--------------------------------------------------------------------------------
/assets/models/textures/bg-trees.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/bg-trees.png
--------------------------------------------------------------------------------
/assets/models/textures/rock-edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/textures/rock-edge.png
--------------------------------------------------------------------------------
/assets/materials/slime.material.depren:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/materials/slime.material.depren
--------------------------------------------------------------------------------
/assets/models/level_bg-trees-32-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/level_bg-trees-32-1.png
--------------------------------------------------------------------------------
/assets/models/gobot/model/custom/hurt.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/custom/hurt.res
--------------------------------------------------------------------------------
/assets/models/gobot/textures/open_eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/textures/open_eye.png
--------------------------------------------------------------------------------
/scripts/AI/damageable_settings.gd:
--------------------------------------------------------------------------------
1 | extends Resource
2 | class_name DamageableSettings
3 |
4 |
5 | @export var damage_mult_in_vulnerable : float = 1
6 |
--------------------------------------------------------------------------------
/assets/models/gobot/textures/closed_eyes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/textures/closed_eyes.png
--------------------------------------------------------------------------------
/assets/models/gobot/textures/hurt_eyes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/textures/hurt_eyes.png
--------------------------------------------------------------------------------
/scripts/beehave/bh_empty.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name Empty extends ActionLeaf
3 |
4 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
5 | return SUCCESS
6 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_fail.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name Fail extends ActionLeaf
3 |
4 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
5 | return FAILURE
6 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_succeed.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name Succeed extends ActionLeaf
3 |
4 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
5 | return SUCCESS
--------------------------------------------------------------------------------
/assets/models/gobot/model/custom/run_step.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/custom/run_step.res
--------------------------------------------------------------------------------
/assets/models/gobot/model/custom/custom_lib.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/custom/custom_lib.res
--------------------------------------------------------------------------------
/assets/models/gobot/model/custom/hurt.res.depren:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/custom/hurt.res.depren
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_diffuse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/gobot_gobot_diffuse.png
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/gobot_gobot_normal.png
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_roughness.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/gobot_gobot_roughness.png
--------------------------------------------------------------------------------
/assets/models/gobot/model/custom/custom_lib.res.depren:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/taillight-games/beehave-3d-example/HEAD/assets/models/gobot/model/custom/custom_lib.res.depren
--------------------------------------------------------------------------------
/addons/beehave/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Beehave"
4 | description="🐝 Behavior Tree addon for Godot Engine"
5 | author="bitbrain"
6 | version="2.7.11"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_test.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name TestAction extends ActionLeaf
3 |
4 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
5 | print("test action fired")
6 | return SUCCESS
7 |
--------------------------------------------------------------------------------
/script_templates/BeehaveNode/default.gd:
--------------------------------------------------------------------------------
1 | # meta-name: Default
2 | # meta-default: true
3 | extends _BASE_
4 |
5 |
6 | func tick(actor: Node, blackboard: Blackboard) -> int:
7 | return SUCCESS
8 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_stop_navigation.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name StopNavigation extends ActionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | actor.toggle_navigation(false)
6 | return SUCCESS
--------------------------------------------------------------------------------
/scripts/AI/enemy_agent.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Agent
3 | class_name EnemyAgent
4 |
5 |
6 | var enemy : Node3D
7 |
8 | @export_category("Enemy Agent Settings")
9 |
10 | @export var melee_range : float = 2
11 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_set_target_enemy.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name SetTargetEnemy extends ActionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | actor.set_target(actor.enemy.global_position)
6 | return SUCCESS
7 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_set_idle.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name SetIdle extends ActionLeaf
3 |
4 | @export var idle_value := true
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | actor.is_idle = idle_value
8 | return SUCCESS
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_start_navigation.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name StartNavigation extends ActionLeaf
3 |
4 |
5 | func tick(actor:Node, _blackboard:Blackboard) -> int:
6 | actor.toggle_navigation(true)
7 | return SUCCESS
8 |
9 |
10 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_stop_rotate.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name StopFaceEnemy extends ActionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 |
6 | #actor.rotate_self = false
7 | actor.rotate_node = null
8 | return SUCCESS
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_there_enemy.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsThereEnemy extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.senses.has_enemies():
6 | return SUCCESS
7 | else:
8 | return FAILURE
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_at_destination.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsAtDestination extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.is_at_destination():
6 | return SUCCESS
7 | else:
8 | return FAILURE
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_moving.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsMoving extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.linear_velocity.length() > 0.1:
6 | return SUCCESS
7 | else:
8 | return FAILURE
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_wait_for_destination.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name WaitForDestination extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.is_at_destination():
6 | return SUCCESS
7 | else:
8 | return RUNNING
9 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_bottom.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_action_in_progress.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsActionInProgress extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.actions.is_action_in_progress():
6 | return SUCCESS
7 | else:
8 | return FAILURE
9 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_obstacle_close.gd:
--------------------------------------------------------------------------------
1 | extends ConditionLeaf
2 | class_name IsObstacleClose
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.wall_raycast_collided or actor.near_obstacle:
6 | return SUCCESS
7 | else:
8 | return FAILURE
9 |
--------------------------------------------------------------------------------
/assets/materials/transparent.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" format=3 uid="uid://cj4jr6crcu1gc"]
2 |
3 | [resource]
4 | transparency = 2
5 | alpha_scissor_threshold = 1.0
6 | alpha_antialiasing_mode = 0
7 | shading_mode = 0
8 | albedo_color = Color(1, 1, 1, 0)
9 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_anim_travel.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name AnimTravel extends ActionLeaf
3 |
4 | @export var animation_name : StringName
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 |
8 | actor.anim_travel(animation_name)
9 |
10 | return SUCCESS
11 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_idle.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsIdle extends ConditionLeaf
3 |
4 | @export var animation_name : StringName
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | if actor.is_idle:
8 | return SUCCESS
9 | else:
10 | return FAILURE
11 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_top.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/materials/red_overlay.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" format=3 uid="uid://b6ros7h2rxv3s"]
2 |
3 | [resource]
4 | render_priority = 1
5 | transparency = 1
6 | blend_mode = 1
7 | cull_mode = 2
8 | shading_mode = 0
9 | albedo_color = Color(1, 0, 0, 0.376471)
10 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_get_enemy.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name GetEnemy extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 |
6 | var _e = actor.senses.get_enemy()
7 | if _e == null:
8 | return FAILURE
9 | else:
10 | actor.enemy = _e
11 | return SUCCESS
12 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_wait_for_action_complete.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name WaitForActionComplete extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | return SUCCESS
6 | #if actor.senses.has_enemies():
7 | #return SUCCESS
8 | #else:
9 | # return FAILURE
10 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_back_up.gd:
--------------------------------------------------------------------------------
1 | extends ActionLeaf
2 | class_name SetTargetBackwards
3 |
4 | @export var distance : float = 2.0
5 |
6 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
7 |
8 | _actor.set_target(_actor.global_position + (_actor.basis.z * distance))
9 | return SUCCESS
10 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_get_enemy_fallback.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name GetEnemyFallback extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | var _e = actor.senses.get_enemy()
6 | if _e == null:
7 | return FAILURE
8 | else:
9 | actor.enemy = _e
10 | return SUCCESS
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.cfg
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | # Mono-specific ignores
13 | .mono/
14 | data_*/
15 | mono_crash.*.json
16 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_anim_playing.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsAnimPlaying extends ConditionLeaf
3 |
4 | @export var animation_name : StringName
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | if actor.anim_sm.get_current_node() == animation_name:
8 | return SUCCESS
9 | else:
10 | return FAILURE
11 |
--------------------------------------------------------------------------------
/scripts/Damageable/object_damageable.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Damageable
3 | class_name ObjectDamageable
4 |
5 | func damaged(_attack : AttackObject):
6 |
7 | if health <= 0:
8 | return
9 |
10 | on_hit.emit()
11 |
12 | health -= _attack.damage
13 |
14 | if health <= 0:
15 | die()
16 |
17 | func die():
18 | pass
19 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_new_wander_target.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name NewWanderTarget extends ActionLeaf
3 |
4 | @export var radius : float = 0
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 |
8 | if radius == 0:
9 | actor.new_wander_target()
10 | else:
11 | actor.new_wander_target(radius)
12 |
13 | return SUCCESS
14 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_in_melee_range.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsInMeleeRange extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.enemy == null:
6 | return FAILURE
7 |
8 | if actor.global_position.distance_to(actor.enemy.global_position) <= actor.melee_range:
9 | return SUCCESS
10 | else:
11 | return FAILURE
12 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_enemy_in_range.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsEnemyInRange extends ConditionLeaf
3 |
4 | @export var current_range : float = 2.0
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | if actor.enemy == null:
8 | return FAILURE
9 |
10 | if actor.global_position.distance_to(actor.enemy.global_position) <= current_range:
11 | return SUCCESS
12 | else:
13 | return FAILURE
14 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/condition.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/condition.svg")
3 | class_name ConditionLeaf extends Leaf
4 | ## Conditions are leaf nodes that either return SUCCESS or FAILURE depending on
5 | ## a single simple condition. They should never return `RUNNING`.
6 |
7 | func get_class_name() -> Array[StringName]:
8 | var classes := super()
9 | classes.push_back(&"ConditionLeaf")
10 | return classes
11 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_enemy_in_hitbox.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsEnemyInHitbox extends ConditionLeaf
3 |
4 |
5 | func tick(actor:Node, _blackboard:Blackboard) -> int:
6 | # if actor.global_positon.distance_to(actor.enemy.global_positon) <= actor.melee_range:
7 | # return SUCCESS
8 | # else:
9 | # return FAILURE
10 |
11 | if actor.actions.is_in_hitbox(actor.enemy):
12 | return SUCCESS
13 | else:
14 | return FAILURE
15 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_wait_for_melee_range.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name WaitForMeleeRange extends ConditionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.global_position.distance_to(actor.enemy.global_position) <= actor.melee_range:
6 | return SUCCESS
7 | else:
8 | return RUNNING
9 |
10 | # if actor.actions.is_in_hitbox(actor.enemy):
11 | # return SUCCESS
12 | # else:
13 | # return RUNNING
14 |
--------------------------------------------------------------------------------
/assets/materials/grass-rock-edge.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bqxdxu7vu0mg4"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://bhh4ve32ldk71" path="res://assets/models/textures/rock-edge.png" id="1_fbdhp"]
4 |
5 | [resource]
6 | shading_mode = 0
7 | vertex_color_use_as_albedo = true
8 | albedo_texture = ExtResource("1_fbdhp")
9 | uv1_world_triplanar = true
10 | texture_filter = 2
11 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_face_enemy.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name FaceEnemy extends ActionLeaf
3 | #yeas
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 | if actor.actions.is_in_hitbox(actor.enemy):
6 | #actor.rot_in_place = false
7 | actor.rotate_node = null
8 | return SUCCESS
9 | else:
10 | actor.rotate_self = true
11 | actor.rotate_target = actor.enemy.global_position
12 | actor.rotate_node = actor.enemy
13 | return RUNNING
14 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_wait_for_range.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name WaitForRange extends ConditionLeaf
3 |
4 | @export var _range : float = 2.0
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | if actor.global_position.distance_to(actor.enemy.global_position) <= _range:
8 | return SUCCESS
9 | else:
10 | return RUNNING
11 |
12 | # if actor.actions.is_in_hitbox(actor.enemy):
13 | # return SUCCESS
14 | # else:
15 | # return RUNNING
16 |
--------------------------------------------------------------------------------
/assets/models/gobot/materials/eye_mat.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://div0enqs04w5j"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dq675fmt1rg8c" path="res://assets/models/gobot/textures/open_eye.png" id="1_5dt3l"]
4 |
5 | [resource]
6 | resource_local_to_scene = true
7 | albedo_texture = ExtResource("1_5dt3l")
8 | roughness = 0.6
9 | uv1_offset = Vector3(0.1, 0, 0)
10 | texture_repeat = false
11 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_face_enemy_ranged.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name FaceEnemyRanged extends ActionLeaf
3 |
4 | func tick(actor:Node, _blackboard:Blackboard) -> int:
5 |
6 | actor.rotate_self = true
7 | actor.rotate_target = actor.enemy.global_position
8 | actor.rotate_node = actor.enemy
9 |
10 | if actor.is_rotate_complete():
11 | #actor.rot_in_place = false
12 | actor.rotate_node = null
13 | return SUCCESS
14 | else:
15 | return RUNNING
16 |
--------------------------------------------------------------------------------
/assets/materials/fence.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bk0rqjdcmjtt0"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dnnyfo1xp27s3" path="res://assets/models/textures/fence.png" id="1_ft2qa"]
4 |
5 | [resource]
6 | transparency = 2
7 | alpha_scissor_threshold = 0.535
8 | alpha_antialiasing_mode = 0
9 | cull_mode = 2
10 | shading_mode = 0
11 | albedo_texture = ExtResource("1_ft2qa")
12 | texture_filter = 0
13 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_counter.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name Counter extends ConditionLeaf
3 | ## Returns SUCCESS for max_count amount of times, the returns FAILURE once and repeats
4 |
5 |
6 | @export var max_count := 0
7 |
8 | @onready var current_count := max_count
9 |
10 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
11 | if current_count == 0:
12 | current_count = max_count
13 | return FAILURE
14 | else:
15 | current_count -= 1
16 | return SUCCESS
17 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_enemy_distance.gd:
--------------------------------------------------------------------------------
1 | class_name IsEnemyDistance extends ConditionLeaf
2 |
3 | @export var upper_range : float = 10
4 | @export var lower_range : float = 2.0
5 |
6 | func tick(actor:Node, _blackboard:Blackboard) -> int:
7 | if actor.enemy == null:
8 | return FAILURE
9 |
10 | var _p = actor.global_position.distance_to(actor.enemy.global_position)
11 |
12 | if lower_range <= _p and _p <= upper_range:
13 | return SUCCESS
14 | else:
15 | return FAILURE
16 |
--------------------------------------------------------------------------------
/assets/materials/bg_trees-dark.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://f2kijod18ox7"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dkd52dlahgxlu" path="res://assets/models/textures/bg-trees.png" id="1_lcdab"]
4 |
5 | [resource]
6 | transparency = 2
7 | alpha_scissor_threshold = 0.228
8 | alpha_antialiasing_mode = 0
9 | shading_mode = 0
10 | albedo_color = Color(0.607843, 0.607843, 0.607843, 1)
11 | albedo_texture = ExtResource("1_lcdab")
12 | texture_filter = 2
13 |
--------------------------------------------------------------------------------
/assets/materials/bg_trees.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cktpnfxywi6l3"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dkd52dlahgxlu" path="res://assets/models/textures/bg-trees.png" id="1_v8tvj"]
4 |
5 | [resource]
6 | transparency = 2
7 | alpha_scissor_threshold = 0.228
8 | alpha_antialiasing_mode = 0
9 | shading_mode = 0
10 | albedo_color = Color(0.839216, 0.839216, 0.839216, 1)
11 | albedo_texture = ExtResource("1_v8tvj")
12 | texture_filter = 2
13 |
--------------------------------------------------------------------------------
/assets/materials/vines.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://deivqr8yqilku"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dnw8444nv77cb" path="res://assets/models/textures/vines.png" id="1_r51pv"]
4 |
5 | [resource]
6 | transparency = 2
7 | alpha_scissor_threshold = 0.5
8 | alpha_antialiasing_mode = 0
9 | cull_mode = 2
10 | shading_mode = 0
11 | albedo_color = Color(0.53088, 0.4928, 0.56, 1)
12 | albedo_texture = ExtResource("1_r51pv")
13 | texture_filter = 0
14 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_start_cooldown.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name StartCooldown extends ActionLeaf
3 |
4 | enum cooldown_types
5 | {
6 | normal,
7 | secondary
8 | }
9 |
10 | @export var cooldown_type : cooldown_types = cooldown_types.normal
11 | @export var cooldown_time : float = 1
12 |
13 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
14 | if cooldown_type == cooldown_types.normal:
15 | _actor.start_cooldown(cooldown_time)
16 | else:
17 | _actor.start_secondary_cooldown(cooldown_time)
18 | return SUCCESS
19 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/action.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/action.svg")
3 | class_name ActionLeaf extends Leaf
4 | ## Actions are leaf nodes that define a task to be performed by an actor.
5 | ## Their execution can be long running, potentially being called across multiple
6 | ## frame executions. In this case, the node should return `RUNNING` until the
7 | ## action is completed.
8 |
9 | func get_class_name() -> Array[StringName]:
10 | var classes := super()
11 | classes.push_back(&"ActionLeaf")
12 | return classes
13 |
--------------------------------------------------------------------------------
/assets/materials/grass-32.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bxsrpokc2g0mm"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://blhfgvab2pqvo" path="res://assets/models/textures/grass.png" id="1_c4u5i"]
4 |
5 | [resource]
6 | shading_mode = 0
7 | vertex_color_use_as_albedo = true
8 | albedo_color = Color(0.803325, 0.803325, 0.803325, 1)
9 | albedo_texture = ExtResource("1_c4u5i")
10 | uv1_scale = Vector3(38.635, 38.635, 38.635)
11 | uv1_world_triplanar = true
12 | texture_filter = 2
13 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_is_cooldown_done.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name IsCooldownDone extends ConditionLeaf
3 |
4 | enum cooldown_types
5 | {
6 | normal,
7 | secondary
8 | }
9 |
10 | @export var cooldown_type : cooldown_types = cooldown_types.normal
11 |
12 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
13 | if cooldown_type == cooldown_types.normal:
14 | if _actor.in_cooldown:
15 | return FAILURE
16 | else:
17 | return SUCCESS
18 | else:
19 | if _actor.in_secondary_cooldown:
20 | return FAILURE
21 | else:
22 | return SUCCESS
23 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/vertical_layout.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/assets/materials/rock-32.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bd8xo0abeyq1j"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://ogf3nlwpmjvv" path="res://assets/models/textures/rock.png" id="1_8grwc"]
4 |
5 | [resource]
6 | cull_mode = 2
7 | shading_mode = 2
8 | diffuse_mode = 2
9 | specular_mode = 2
10 | vertex_color_use_as_albedo = true
11 | albedo_texture = ExtResource("1_8grwc")
12 | uv1_scale = Vector3(43.11, 43.11, 43.11)
13 | uv1_triplanar_sharpness = 8.16138
14 | uv1_world_triplanar = true
15 | texture_filter = 2
16 |
--------------------------------------------------------------------------------
/scripts/misc/hit_sound.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var sound : AudioStream
4 |
5 | @export var audio_player : AudioStreamPlayer3D
6 |
7 | # Called when the node enters the scene tree for the first time.
8 | func _ready():
9 | get_parent().on_hit.connect(play_sound)
10 |
11 |
12 | # Called every frame. 'delta' is the elapsed time since the previous frame.
13 | func play_sound():
14 | #audio_player.stream = sound
15 | if audio_player.get_stream_playback() is AudioStreamPlaybackPolyphonic:
16 | audio_player.get_stream_playback().play_stream(sound)
17 |
18 |
--------------------------------------------------------------------------------
/scripts/Damageable/damageable.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Area3D
3 | class_name Damageable
4 |
5 | @export_category("Damageable Settings")
6 |
7 | @export var max_health : int = 10
8 |
9 | @onready var health : int = max_health
10 |
11 |
12 | @export var active := true
13 |
14 | signal on_hit
15 | signal on_heal
16 | signal on_die
17 |
18 | func _ready():
19 | # set the collider so it is always on collision layer 10 and is not monitoring
20 | monitoring = false
21 | collision_layer = 512
22 | collision_mask = 512
23 |
24 | func damaged(_attack : AttackObject):
25 | pass
26 |
--------------------------------------------------------------------------------
/addons/beehave/utils/utils.gd:
--------------------------------------------------------------------------------
1 | @tool
2 |
3 | static func get_plugin() -> EditorPlugin:
4 | var tree: SceneTree = Engine.get_main_loop()
5 | return tree.get_root().get_child(0).get_node_or_null("BeehavePlugin")
6 |
7 |
8 | static func get_editor_scale() -> float:
9 | var plugin := get_plugin()
10 | if plugin:
11 | return plugin.get_editor_interface().get_editor_scale()
12 | return 1.0
13 |
14 |
15 | static func get_frames() -> RefCounted:
16 | var plugin := get_plugin()
17 | if plugin:
18 | return plugin.frames
19 | push_error("Can't find Beehave Plugin")
20 | return null
21 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/horizontal_layout.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/AI/ActionSlots/action_slot.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name ActionSlot extends Node
3 |
4 |
5 | @onready var parent : NPCActions = get_parent()
6 |
7 | @onready var agent : Agent = parent.get_parent()
8 |
9 | func _ready():
10 | pass
11 |
12 | func on_start_action():
13 | assert(false, "Error: start_action not implimented in ActionSlot extension class")
14 |
15 | func on_end_action():
16 | assert(false, "Error: end_action not implimented in ActionSlot extension class")
17 |
18 | func on_action_process():
19 | assert(false, "Error: action_process not implimented in ActionSlot extension class")
20 |
--------------------------------------------------------------------------------
/scripts/AI/ground_check.gd:
--------------------------------------------------------------------------------
1 | extends Area3D
2 |
3 | var colliding_body_count : int = 0
4 |
5 | var is_collide : bool
6 |
7 | func _ready():
8 | if !body_entered.is_connected(_on_body_entered):
9 | body_entered.connect(_on_body_entered)
10 | if !body_exited.is_connected(_on_body_exited):
11 | body_exited.connect(_on_body_exited)
12 |
13 |
14 | func _on_body_entered(_body):
15 | colliding_body_count += 1
16 |
17 |
18 | func _on_body_exited(_body):
19 | colliding_body_count -= 1
20 |
21 | func is_colliding() -> bool:
22 |
23 | if colliding_body_count != 0:
24 | return true
25 | else:
26 | return false
27 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_set_speed.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name SetSpeed extends ActionLeaf
3 |
4 | enum speed_type {
5 | normal_speed,
6 | sprint_speed,
7 | custom
8 | }
9 |
10 | @export var type : speed_type = speed_type.normal_speed
11 |
12 | @export var custom_speed : float = 1.0
13 |
14 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
15 | if type == speed_type.normal_speed:
16 | _actor.movement_speed = _actor.normal_speed
17 | elif type == speed_type.sprint_speed:
18 | _actor.movement_speed = _actor.sprint_speed
19 | elif type == speed_type.custom:
20 | _actor.movement_speed = custom_speed
21 | return SUCCESS
22 |
23 |
24 |
--------------------------------------------------------------------------------
/scripts/Damageable/attack_object.gd:
--------------------------------------------------------------------------------
1 |
2 |
3 | class_name AttackObject extends Resource
4 |
5 |
6 | enum damage_types {
7 | none,
8 | slashing,
9 | kinetic,
10 | fire,
11 | earth
12 | }
13 |
14 | @export var damage_type : damage_types = damage_types.slashing
15 |
16 | @export var damage : int = 1
17 |
18 | @export var override_knockback := false
19 |
20 | @export var knockback : float = 3
21 |
22 | func _init(_damage_type : damage_types = damage_types.slashing, _damage : int = 1, _override_knockback : bool = false, _knockback : float = 3):
23 | damage_type = _damage_type
24 | damage = _damage
25 | override_knockback = _override_knockback
26 | knockback = _knockback
27 |
28 |
--------------------------------------------------------------------------------
/assets/materials/shadow.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://mqiw67hqph8o"]
2 |
3 | [sub_resource type="Gradient" id="Gradient_eits2"]
4 | offsets = PackedFloat32Array(0.271293, 0.555205)
5 | colors = PackedColorArray(0, 0, 0, 0.360784, 0, 0, 0, 0)
6 |
7 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_j3l60"]
8 | gradient = SubResource("Gradient_eits2")
9 | width = 16
10 | height = 16
11 | fill = 1
12 | fill_from = Vector2(0.5, 0.5)
13 | fill_to = Vector2(0, 0)
14 | metadata/_snap_enabled = true
15 |
16 | [resource]
17 | transparency = 1
18 | shading_mode = 0
19 | albedo_texture = SubResource("GradientTexture2D_j3l60")
20 | texture_repeat = false
21 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_distance_from_start.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name DistanceFromStart extends ConditionLeaf
3 |
4 | @export var max_distance := 10.0
5 |
6 | @export var use_agent_max_distance := false
7 |
8 | @export_enum("Position:0", "Destination:1") var use_point : int
9 |
10 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
11 |
12 | var _md = max_distance
13 | if use_agent_max_distance: _md = _actor.max_wander_distance
14 |
15 | var start_p := Vector3.ZERO
16 | if use_point == 0:
17 | start_p = _actor.global_position
18 | else:
19 | start_p = _actor.nav_agent.target_position
20 |
21 | if start_p.distance_to(_actor.start_position) > _md:
22 | return FAILURE
23 | else:
24 | return SUCCESS
25 |
--------------------------------------------------------------------------------
/scripts/beehave/bh_rotating_cooldown.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name RotatingCooldown extends ActionLeaf
3 |
4 | enum cooldown_types
5 | {
6 | normal,
7 | secondary
8 | }
9 |
10 | @export var cooldown_type : cooldown_types = cooldown_types.normal
11 | @export var cooldown_times : Array[float]
12 |
13 | var times_cooled : int = 0
14 |
15 | func tick(_actor:Node, _blackboard:Blackboard) -> int:
16 |
17 | times_cooled = times_cooled % cooldown_times.size()
18 |
19 | var _time = cooldown_times[times_cooled]
20 |
21 | if cooldown_type == cooldown_types.normal:
22 | _actor.start_cooldown(_time)
23 | else:
24 | _actor.start_secondary_cooldown(_time)
25 |
26 | times_cooled += 1
27 |
28 | return SUCCESS
29 |
--------------------------------------------------------------------------------
/addons/beehave/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 | const BeehaveEditorDebugger := preload("debug/debugger.gd")
5 | var editor_debugger: BeehaveEditorDebugger
6 | var frames: RefCounted
7 |
8 | func _init():
9 | name = "BeehavePlugin"
10 | add_autoload_singleton("BeehaveGlobalMetrics", "metrics/beehave_global_metrics.gd")
11 | add_autoload_singleton("BeehaveGlobalDebugger", "debug/global_debugger.gd")
12 | print("Beehave initialized!")
13 |
14 | func _enter_tree() -> void:
15 | editor_debugger = BeehaveEditorDebugger.new()
16 | frames = preload("debug/frames.gd").new()
17 | add_debugger_plugin(editor_debugger)
18 |
19 |
20 | func _exit_tree() -> void:
21 | remove_debugger_plugin(editor_debugger)
22 |
--------------------------------------------------------------------------------
/scripts/AI/death_helper.gd:
--------------------------------------------------------------------------------
1 | extends Timer
2 |
3 | @export_node_path("MeshInstance3D") var mesh_path : NodePath
4 | @export var dead_material : Material
5 | @export var transparent_material : Material
6 |
7 | @onready var anim : AnimationPlayer = $AnimationPlayer
8 |
9 | @onready var mesh = get_node(mesh_path)
10 |
11 | # Called when the node enters the scene tree for the first time.
12 | func _ready():
13 | timeout.connect(end)
14 |
15 |
16 | func begin():
17 |
18 | await get_tree().create_timer(0.2).timeout
19 |
20 | mesh.material_overlay = dead_material
21 | start()
22 | anim.play("crumble")
23 |
24 | func end():
25 | get_parent().queue_free()
26 |
27 | func a_hide_main():
28 | mesh.material_override = transparent_material
29 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/blackboard_erase.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BlackboardEraseAction extends ActionLeaf
3 |
4 | ## Erases the specified key from the blackboard.
5 | ## Returns [code]FAILURE[/code] if expression execution fails, otherwise [code]SUCCESS[/code].
6 |
7 | ## Expression representing a blackboard key.
8 | @export_placeholder(EXPRESSION_PLACEHOLDER) var key: String = ""
9 |
10 | @onready var _key_expression: Expression = _parse_expression(key)
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | var key_value: Variant = _key_expression.execute([], blackboard)
15 |
16 | if _key_expression.has_execute_failed():
17 | return FAILURE
18 |
19 | blackboard.erase_value(key_value)
20 |
21 | return SUCCESS
22 |
23 |
24 | func _get_expression_sources() -> Array[String]:
25 | return [key]
26 |
--------------------------------------------------------------------------------
/assets/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=3 format=3 uid="uid://c4cxd4w3vogf"]
2 |
3 | [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_d5nml"]
4 | sun_curve = 0.113679
5 | use_debanding = false
6 |
7 | [sub_resource type="Sky" id="Sky_hvlwe"]
8 | sky_material = SubResource("ProceduralSkyMaterial_d5nml")
9 | radiance_size = 2
10 |
11 | [resource]
12 | background_mode = 2
13 | background_color = Color(1, 1, 1, 1)
14 | sky = SubResource("Sky_hvlwe")
15 | ambient_light_source = 2
16 | ambient_light_color = Color(0.631373, 0.631373, 0.631373, 1)
17 | ambient_light_energy = 1.2
18 | tonemap_mode = 3
19 | fog_light_color = Color(0.458824, 0.494118, 0.321569, 1)
20 | fog_light_energy = 0.23
21 | fog_density = 0.055
22 | adjustment_brightness = 0.01
23 | adjustment_contrast = 0.01
24 | adjustment_saturation = 0.01
25 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/blackboard_has.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BlackboardHasCondition extends ConditionLeaf
3 |
4 | ## Returns [code]FAILURE[/code] if expression execution fails or the specified key doesn't exist.
5 | ## Returns [code]SUCCESS[/code] if blackboard has the specified key.
6 |
7 | ## Expression representing a blackboard key.
8 | @export_placeholder(EXPRESSION_PLACEHOLDER) var key: String = ""
9 |
10 | @onready var _key_expression: Expression = _parse_expression(key)
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | var key_value: Variant = _key_expression.execute([], blackboard)
15 |
16 | if _key_expression.has_execute_failed():
17 | return FAILURE
18 |
19 | return SUCCESS if blackboard.has_value(key_value) else FAILURE
20 |
21 |
22 | func _get_expression_sources() -> Array[String]:
23 | return [key]
24 |
--------------------------------------------------------------------------------
/scripts/misc/hit_flash.gd:
--------------------------------------------------------------------------------
1 | extends Timer
2 |
3 | @export var models_path : Array[NodePath]
4 |
5 | @export var time := 1.0
6 |
7 | @export var flash_mat : Material
8 |
9 |
10 | var models : Array[GeometryInstance3D]
11 |
12 | func _ready():
13 |
14 | for _mp in models_path:
15 | models.append(get_node(_mp))
16 | assert(get_node(_mp) is GeometryInstance3D, "Error: hit_flash models_path must be GeometryInstance")
17 |
18 | if !timeout.is_connected(end_effect):
19 | timeout.connect(end_effect)
20 | get_parent().on_hit.connect(play_effect)
21 |
22 |
23 | func play_effect():
24 | for _m in models:
25 | _m.material_overlay = flash_mat
26 | #model.material_overlay = flash_mat
27 | wait_time = time
28 | start()
29 |
30 |
31 | func end_effect():
32 | #model.material_overlay = null
33 | for _m in models:
34 | if _m.material_overlay == flash_mat:
35 | _m.material_overlay = null
36 |
--------------------------------------------------------------------------------
/assets/models/textures/rock.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://ogf3nlwpmjvv"
6 | path="res://.godot/imported/rock.png-5b611a500258ba1f546867a879c47c59.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/rock.png"
14 | dest_files=["res://.godot/imported/rock.png-5b611a500258ba1f546867a879c47c59.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/fence.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dnnyfo1xp27s3"
6 | path="res://.godot/imported/fence.png-84fb9590bd822d9ddfd0902befb38fc0.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/fence.png"
14 | dest_files=["res://.godot/imported/fence.png-84fb9590bd822d9ddfd0902befb38fc0.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/grass.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://blhfgvab2pqvo"
6 | path="res://.godot/imported/grass.png-7db2f1a6ec9fd5bcb9ac7530f257acd8.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/grass.png"
14 | dest_files=["res://.godot/imported/grass.png-7db2f1a6ec9fd5bcb9ac7530f257acd8.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/slime.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://k4qb285xu0n6"
6 | path="res://.godot/imported/slime.png-fa8dbcb3073fae6ee4263e399fe4b328.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/slime.png"
14 | dest_files=["res://.godot/imported/slime.png-fa8dbcb3073fae6ee4263e399fe4b328.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=1
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/vines.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dnw8444nv77cb"
6 | path="res://.godot/imported/vines.png-3ac86d9dee2682aa6009524eeb351ec0.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/vines.png"
14 | dest_files=["res://.godot/imported/vines.png-3ac86d9dee2682aa6009524eeb351ec0.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/bg-trees.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dkd52dlahgxlu"
6 | path="res://.godot/imported/bg-trees.png-269043d6b04fb226c1690ea4ebdc9d7f.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/bg-trees.png"
14 | dest_files=["res://.godot/imported/bg-trees.png-269043d6b04fb226c1690ea4ebdc9d7f.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/textures/rock-edge.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bhh4ve32ldk71"
6 | path="res://.godot/imported/rock-edge.png-1bd3ec73bd684aaadd4d9fa64119a7d6.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/textures/rock-edge.png"
14 | dest_files=["res://.godot/imported/rock-edge.png-1bd3ec73bd684aaadd4d9fa64119a7d6.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=true
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/assets/models/level.glb.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="scene"
4 | importer_version=1
5 | type="PackedScene"
6 | uid="uid://d31p1dmc66x0f"
7 | path="res://.godot/imported/level.glb-cb8828e79d0109b12e7a20dc1572e2fd.scn"
8 |
9 | [deps]
10 |
11 | source_file="res://assets/models/level.glb"
12 | dest_files=["res://.godot/imported/level.glb-cb8828e79d0109b12e7a20dc1572e2fd.scn"]
13 |
14 | [params]
15 |
16 | nodes/root_type=""
17 | nodes/root_name=""
18 | nodes/apply_root_scale=true
19 | nodes/root_scale=1.0
20 | meshes/ensure_tangents=true
21 | meshes/generate_lods=true
22 | meshes/create_shadow_meshes=true
23 | meshes/light_baking=1
24 | meshes/lightmap_texel_size=0.2
25 | meshes/force_disable_compression=false
26 | skins/use_named_skins=true
27 | animation/import=true
28 | animation/fps=30
29 | animation/trimming=false
30 | animation/remove_immutable_tracks=true
31 | import_script/path=""
32 | _subresources={}
33 | gltf/naming_version=1
34 | gltf/embedded_image_handling=1
35 |
--------------------------------------------------------------------------------
/assets/models/level_bg-trees-32-1.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://v8km302ur1yc"
6 | path="res://.godot/imported/level_bg-trees-32-1.png-3a944d8edc3896d1f5d3c3cd417cd51e.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://assets/models/level_bg-trees-32-1.png"
14 | dest_files=["res://.godot/imported/level_bg-trees-32-1.png-3a944d8edc3896d1f5d3c3cd417cd51e.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=0
35 |
--------------------------------------------------------------------------------
/scripts/AI/enemy_actions.gd:
--------------------------------------------------------------------------------
1 |
2 |
3 | class_name EnemyActions extends NPCActions
4 |
5 |
6 | @export_category("Attack 1")
7 | @export var attack_1_hitbox : Area3D
8 |
9 | @export var attack_1_damage : int = 1
10 |
11 | @export var attack_1_object : AttackObject
12 |
13 | @export_category("Settings")
14 |
15 | @export var self_collider : Area3D
16 |
17 |
18 | ### ---- Animation Functions ----- ###
19 |
20 | func a_attack_1_damage():
21 | _deal_damage(attack_1_hitbox, attack_1_damage)
22 |
23 | ### ----- Internal Functions ---- ###
24 |
25 | func _deal_damage(_a : Area3D, _damage : int = 1):
26 | var _bodies = _a.get_overlapping_areas()
27 | var _ao = attack_1_object
28 | _ao.damage = _damage
29 | for _b in _bodies:
30 | if _b != self_collider and _b is Damageable:
31 | _b.damaged(_ao)
32 |
33 |
34 | func is_in_hitbox(_agent : Area3D) -> bool:
35 | var _areas = attack_1_hitbox.get_overlapping_areas()
36 | for _a in _areas:
37 | if _a == _agent:
38 | return true
39 | return false
40 |
41 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/decorator.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/category_decorator.svg")
3 | class_name Decorator extends BeehaveNode
4 | ## Decorator nodes are used to transform the result received by its child.
5 | ## Must only have one child.
6 |
7 | var running_child: BeehaveNode = null
8 |
9 |
10 | func _get_configuration_warnings() -> PackedStringArray:
11 | var warnings: PackedStringArray = super._get_configuration_warnings()
12 |
13 | if get_child_count() != 1:
14 | warnings.append("Decorator should have exactly one child node.")
15 |
16 | return warnings
17 |
18 |
19 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
20 | if running_child != null:
21 | running_child.interrupt(actor, blackboard)
22 | running_child = null
23 |
24 |
25 | func after_run(actor: Node, blackboard: Blackboard) -> void:
26 | running_child = null
27 |
28 |
29 | func get_class_name() -> Array[StringName]:
30 | var classes := super()
31 | classes.push_back(&"Decorator")
32 | return classes
33 |
--------------------------------------------------------------------------------
/scripts/AI/avoid_obstacle.gd:
--------------------------------------------------------------------------------
1 | extends RayCast3D
2 |
3 |
4 | @onready var parent = get_parent().get_parent()
5 |
6 | enum Type {
7 | left,
8 | middle,
9 | right
10 | }
11 |
12 | @export var raycastType : Type = Type.left
13 |
14 | # Called when the node enters the scene tree for the first time.
15 | func _ready():
16 | pass # Replace with function body.
17 |
18 |
19 | # Called every frame. 'delta' is the elapsed time since the previous frame.
20 | func _physics_process(_delta):
21 | if is_colliding():
22 |
23 | parent.force_avoid_obstacle()
24 | # get the distance to raycast hit and then return it as a percentage of the raycast size
25 | var _distance = global_position.distance_to(get_collision_point())
26 | _distance = inverse_lerp(-target_position.z, 0, _distance)
27 |
28 | match raycastType:
29 | Type.left: parent.obstacle_distance.x = _distance
30 | Type.middle: parent.obstacle_distance.y = _distance
31 | Type.right: parent.obstacle_distance.z = _distance
32 | # print("obstacle collision")
33 |
--------------------------------------------------------------------------------
/assets/models/gobot/textures/hurt_eyes.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://yj5yx07nva6l"
6 | path.s3tc="res://.godot/imported/hurt_eyes.png-9cfbc0da7da452578ce339ea9e562cf7.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/textures/hurt_eyes.png"
15 | dest_files=["res://.godot/imported/hurt_eyes.png-9cfbc0da7da452578ce339ea9e562cf7.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/assets/models/gobot/textures/open_eye.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dq675fmt1rg8c"
6 | path.s3tc="res://.godot/imported/open_eye.png-c420b95a0de2488d71a0d5d6ced9535b.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/textures/open_eye.png"
15 | dest_files=["res://.godot/imported/open_eye.png-c420b95a0de2488d71a0d5d6ced9535b.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_diffuse.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bt5o0sr6peltq"
6 | path="res://.godot/imported/gobot_gobot_diffuse.png-cb197b72fb26f3a9ce9537a926b87b11.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 | generator_parameters={}
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/model/gobot_gobot_diffuse.png"
15 | dest_files=["res://.godot/imported/gobot_gobot_diffuse.png-cb197b72fb26f3a9ce9537a926b87b11.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=3
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/assets/models/gobot/textures/closed_eyes.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cfdf62ci74tew"
6 | path.s3tc="res://.godot/imported/closed_eyes.png-3db4539d1a34ce3b15586911025c6960.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/textures/closed_eyes.png"
15 | dest_files=["res://.godot/imported/closed_eyes.png-3db4539d1a34ce3b15586911025c6960.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/beehave/debug/global_debugger.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var _registered_trees: Dictionary
4 | var _active_tree
5 |
6 |
7 | func _enter_tree() -> void:
8 | EngineDebugger.register_message_capture("beehave", _on_debug_message)
9 |
10 |
11 | func _on_debug_message(message: String, data: Array) -> bool:
12 | if message == "activate_tree":
13 | _set_active_tree(data[0])
14 | return true
15 | if message == "visibility_changed":
16 | if _active_tree:
17 | _active_tree._can_send_message = data[0]
18 | return true
19 | return false
20 |
21 |
22 | func _set_active_tree(tree_id: int) -> void:
23 | var tree = _registered_trees.get(tree_id, null)
24 | if not tree:
25 | return
26 |
27 | if _active_tree:
28 | _active_tree._can_send_message = false
29 | _active_tree = tree
30 | _active_tree._can_send_message = true
31 |
32 |
33 | func register_tree(tree) -> void:
34 | _registered_trees[tree.get_instance_id()] = tree
35 |
36 |
37 | func unregister_tree(tree) -> void:
38 | _registered_trees.erase(tree.get_instance_id())
39 |
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_roughness.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cgkj45d67dalm"
6 | path="res://.godot/imported/gobot_gobot_roughness.png-5af3322df24f8726044f911696b38e97.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 | generator_parameters={}
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/model/gobot_gobot_roughness.png"
15 | dest_files=["res://.godot/imported/gobot_gobot_roughness.png-5af3322df24f8726044f911696b38e97.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=3
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/beehave/icons/delayer.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dt2i5e0wi1ghb"
6 | path="res://.godot/imported/delayer.svg-6f92c97f61b1eb8679428f438e6b08c7.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/beehave/icons/delayer.svg"
14 | dest_files=["res://.godot/imported/delayer.svg-6f92c97f61b1eb8679428f438e6b08c7.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/assets/models/gobot/model/gobot_gobot_normal.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://d28w5bql3g21l"
6 | path="res://.godot/imported/gobot_gobot_normal.png-863637192050a1a25e34f54c741cd987.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 | generator_parameters={}
11 |
12 | [deps]
13 |
14 | source_file="res://assets/models/gobot/model/gobot_gobot_normal.png"
15 | dest_files=["res://.godot/imported/gobot_gobot_normal.png-863637192050a1a25e34f54c741cd987.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=3
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=1
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=1
28 | roughness/src_normal="res://gobot_gobot_normal.png"
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/beehave/icons/cooldown.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://d0thvgntqf4ql"
6 | path="res://.godot/imported/cooldown.svg-2fb8975b5974e35bedad825abb9faf66.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/beehave/icons/cooldown.svg"
14 | dest_files=["res://.godot/imported/cooldown.svg-2fb8975b5974e35bedad825abb9faf66.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/beehave/icons/repeater.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cm44w4goafgdx"
6 | path="res://.godot/imported/repeater.svg-be2d3a7f1a46d7ba1d1939553725f598.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/beehave/icons/repeater.svg"
14 | dest_files=["res://.godot/imported/repeater.svg-be2d3a7f1a46d7ba1d1939553725f598.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/composite.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/category_composite.svg")
3 | class_name Composite extends BeehaveNode
4 | ## A Composite node controls the flow of execution of its children in a specific manner.
5 |
6 | var running_child: BeehaveNode = null
7 |
8 |
9 | func _get_configuration_warnings() -> PackedStringArray:
10 | var warnings: PackedStringArray = super._get_configuration_warnings()
11 |
12 | if get_children().filter(func(x): return x is BeehaveNode).size() < 2:
13 | warnings.append("Any composite node should have at least two children. Otherwise it is not useful.")
14 |
15 | return warnings
16 |
17 |
18 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
19 | if running_child != null:
20 | running_child.interrupt(actor, blackboard)
21 | running_child = null
22 |
23 |
24 | func after_run(actor: Node, blackboard: Blackboard) -> void:
25 | running_child = null
26 |
27 |
28 | func get_class_name() -> Array[StringName]:
29 | var classes := super()
30 | classes.push_back(&"Composite")
31 | return classes
32 |
--------------------------------------------------------------------------------
/addons/beehave/debug/debugger_messages.gd:
--------------------------------------------------------------------------------
1 | class_name BeehaveDebuggerMessages
2 |
3 |
4 | static func can_send_message() -> bool:
5 | return not Engine.is_editor_hint() and OS.has_feature("editor")
6 |
7 |
8 | static func register_tree(beehave_tree: Dictionary) -> void:
9 | if can_send_message():
10 | EngineDebugger.send_message("beehave:register_tree", [beehave_tree])
11 |
12 |
13 | static func unregister_tree(instance_id: int) -> void:
14 | if can_send_message():
15 | EngineDebugger.send_message("beehave:unregister_tree", [instance_id])
16 |
17 |
18 | static func process_tick(instance_id: int, status: int) -> void:
19 | if can_send_message():
20 | EngineDebugger.send_message("beehave:process_tick", [instance_id, status])
21 |
22 |
23 | static func process_begin(instance_id: int) -> void:
24 | if can_send_message():
25 | EngineDebugger.send_message("beehave:process_begin", [instance_id])
26 |
27 |
28 | static func process_end(instance_id: int) -> void:
29 | if can_send_message():
30 | EngineDebugger.send_message("beehave:process_end", [instance_id])
31 |
32 |
--------------------------------------------------------------------------------
/addons/beehave/icons/until_fail.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://chpy50kaej7a8"
6 | path="res://.godot/imported/until_fail.svg-8015014c40e91d9c2668ec34d4118b8e.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/beehave/icons/until_fail.svg"
14 | dest_files=["res://.godot/imported/until_fail.svg-8015014c40e91d9c2668ec34d4118b8e.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/beehave/icons/tree.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://deryyg2hbmaaw"
6 | path="res://.godot/imported/tree.svg-c0b20ed88b2fe300c0296f7236049076.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/tree.svg"
15 | dest_files=["res://.godot/imported/tree.svg-c0b20ed88b2fe300c0296f7236049076.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/action.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://btrq8e0kyxthg"
6 | path="res://.godot/imported/action.svg-e8a91246d0ba9ba3cf84290d65648f06.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/action.svg"
15 | dest_files=["res://.godot/imported/action.svg-e8a91246d0ba9ba3cf84290d65648f06.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/failer.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://2fj7htaqvcud"
6 | path="res://.godot/imported/failer.svg-9a62b840e1eacc0437e7a67b14a302e4.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/failer.svg"
15 | dest_files=["res://.godot/imported/failer.svg-9a62b840e1eacc0437e7a67b14a302e4.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/inverter.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cffmoc3og8hux"
6 | path="res://.godot/imported/inverter.svg-1f1b976d95de42c4ad99a92fa9a6c5d0.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/inverter.svg"
15 | dest_files=["res://.godot/imported/inverter.svg-1f1b976d95de42c4ad99a92fa9a6c5d0.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/limiter.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c7akxvsg0f2by"
6 | path="res://.godot/imported/limiter.svg-b4c7646605c46f53c5e403fe21d8f584.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/limiter.svg"
15 | dest_files=["res://.godot/imported/limiter.svg-b4c7646605c46f53c5e403fe21d8f584.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/selector.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b2c5d20doh4sp"
6 | path="res://.godot/imported/selector.svg-78bccfc448bd1676b5a29bfde4b08e5b.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/selector.svg"
15 | dest_files=["res://.godot/imported/selector.svg-78bccfc448bd1676b5a29bfde4b08e5b.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/sequence.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c5gw354thiofm"
6 | path="res://.godot/imported/sequence.svg-76e5600611900cc81e9ec286977b8c6a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/sequence.svg"
15 | dest_files=["res://.godot/imported/sequence.svg-76e5600611900cc81e9ec286977b8c6a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/condition.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://ck4toqx0nggiu"
6 | path="res://.godot/imported/condition.svg-57892684b10a64086f68c09c388b17e5.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/condition.svg"
15 | dest_files=["res://.godot/imported/condition.svg-57892684b10a64086f68c09c388b17e5.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/succeeder.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dl6wo332kglbe"
6 | path="res://.godot/imported/succeeder.svg-e5cf6f6e04b9b862b82fd2cb479272aa.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/succeeder.svg"
15 | dest_files=["res://.godot/imported/succeeder.svg-e5cf6f6e04b9b862b82fd2cb479272aa.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/blackboard.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dw7rom0hiff6c"
6 | path="res://.godot/imported/blackboard.svg-18d4dfd4f6de558de250b67251ff1e69.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/blackboard.svg"
15 | dest_files=["res://.godot/imported/blackboard.svg-18d4dfd4f6de558de250b67251ff1e69.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_top.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bw8wmxdfom8eh"
6 | path="res://.godot/imported/port_top.svg-d1b336cdc6a0dd570305782a1e56f61d.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/port_top.svg"
15 | dest_files=["res://.godot/imported/port_top.svg-d1b336cdc6a0dd570305782a1e56f61d.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_bt.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://qpdd6ue7x82h"
6 | path="res://.godot/imported/category_bt.svg-8537bebd1c5f62dca3d7ee7f17efeed4.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/category_bt.svg"
15 | dest_files=["res://.godot/imported/category_bt.svg-8537bebd1c5f62dca3d7ee7f17efeed4.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_left.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bnufc8p6spdtn"
6 | path="res://.godot/imported/port_left.svg-69cd927c4db555f1edbb8d1f553ea2fd.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/port_left.svg"
15 | dest_files=["res://.godot/imported/port_left.svg-69cd927c4db555f1edbb8d1f553ea2fd.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_right.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bbmd6vk23ympm"
6 | path="res://.godot/imported/port_right.svg-f760bd8be2dd613d0d3848c998c92a2a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/port_right.svg"
15 | dest_files=["res://.godot/imported/port_right.svg-f760bd8be2dd613d0d3848c998c92a2a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_leaf.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://eq0sp4g3s75r"
6 | path="res://.godot/imported/category_leaf.svg-c740ecab6cfae632574ca5e39e46fd2e.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/category_leaf.svg"
15 | dest_files=["res://.godot/imported/category_leaf.svg-c740ecab6cfae632574ca5e39e46fd2e.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/until_fail.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/until_fail.svg")
3 | class_name UntilFailDecorator
4 | extends Decorator
5 | ## The UntilFail Decorator will return `RUNNING` if its child returns
6 | ## `SUCCESS` or `RUNNING` or it will return `SUCCESS` if its child returns
7 | ## `FAILURE`
8 |
9 | func tick(actor: Node, blackboard: Blackboard) -> int:
10 | var c = get_child(0)
11 |
12 | if c != running_child:
13 | c.before_run(actor, blackboard)
14 |
15 | var response = c.tick(actor, blackboard)
16 | if can_send_message(blackboard):
17 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
18 |
19 | if c is ConditionLeaf:
20 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
21 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
22 |
23 | if response == RUNNING:
24 | running_child = c
25 | if c is ActionLeaf:
26 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
27 | return RUNNING
28 | if response == SUCCESS:
29 | return RUNNING
30 |
31 | return SUCCESS
32 |
33 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/port_bottom.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://da3b236rjbqns"
6 | path="res://.godot/imported/port_bottom.svg-e5c5c61b642a79ab9c2b66ff56603d34.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/port_bottom.svg"
15 | dest_files=["res://.godot/imported/port_bottom.svg-e5c5c61b642a79ab9c2b66ff56603d34.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/until_success.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/until_fail.svg")
3 | class_name UntilSuccessDecorator
4 | extends Decorator
5 | ## The UntilFail Decorator will return `RUNNING` if its child returns
6 | ## `SUCCESS` or `RUNNING` or it will return `SUCCESS` if its child returns
7 | ## `FAILURE`
8 |
9 | func tick(actor: Node, blackboard: Blackboard) -> int:
10 | var c = get_child(0)
11 |
12 | if c != running_child:
13 | c.before_run(actor, blackboard)
14 |
15 | var response = c.tick(actor, blackboard)
16 | if can_send_message(blackboard):
17 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
18 |
19 | if c is ConditionLeaf:
20 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
21 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
22 |
23 | if response == RUNNING:
24 | running_child = c
25 | if c is ActionLeaf:
26 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
27 | return RUNNING
28 | if response == FAILURE:
29 | return RUNNING
30 |
31 | return SUCCESS
32 |
33 |
--------------------------------------------------------------------------------
/addons/beehave/icons/selector_random.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bmnkcmk7bkdjd"
6 | path="res://.godot/imported/selector_random.svg-d52fea1352c24483ecd9dc8609cf00f3.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/selector_random.svg"
15 | dest_files=["res://.godot/imported/selector_random.svg-d52fea1352c24483ecd9dc8609cf00f3.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/sequence_random.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bat8ptdw5qt1d"
6 | path="res://.godot/imported/sequence_random.svg-58cee9098c622ef87db941279206422a.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/sequence_random.svg"
15 | dest_files=["res://.godot/imported/sequence_random.svg-58cee9098c622ef87db941279206422a.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/scripts/AI/npc_actions.gd:
--------------------------------------------------------------------------------
1 |
2 |
3 | class_name NPCActions extends Node
4 |
5 |
6 | @export var default_animation_name : StringName = "idle"
7 |
8 | @export_category("Hit Action Slot")
9 |
10 | @export var enable_hit_action := true
11 |
12 | @export var hit_action_slot : ActionSlot
13 |
14 | @onready var parent : Agent = get_parent()
15 |
16 | var action_in_progress := false
17 |
18 | @onready var timer : Timer = $Timer
19 |
20 | signal action_started
21 | signal action_ended
22 | signal action_process
23 |
24 | func _ready():
25 | timer.timeout.connect(a_action_ended)
26 |
27 | func a_action_started():
28 | if action_in_progress:
29 | a_action_ended()
30 | action_in_progress = true
31 | parent.bh_tree.enabled = false
32 | parent.toggle_navigation(false)
33 |
34 | func a_action_ended():
35 | timer.stop()
36 | action_in_progress = false
37 | action_ended.emit()
38 | parent.bh_tree.enabled = true
39 | parent.toggle_navigation(true)
40 |
41 | func is_action_in_progress() -> bool:
42 | return action_in_progress
43 |
44 | func hit_action():
45 | if enable_hit_action:
46 | hit_action_slot.on_start_action()
47 |
--------------------------------------------------------------------------------
/addons/beehave/icons/sequence_reactive.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://rmiu1slwfkh7"
6 | path="res://.godot/imported/sequence_reactive.svg-7d384ca290f7934adb9e17d9e7116b6c.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/sequence_reactive.svg"
15 | dest_files=["res://.godot/imported/sequence_reactive.svg-7d384ca290f7934adb9e17d9e7116b6c.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/vertical_layout.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bpyxu6i1dx5qh"
6 | path="res://.godot/imported/vertical_layout.svg-1a08fee4b09812a05bcf3defb8afcc4c.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/vertical_layout.svg"
15 | dest_files=["res://.godot/imported/vertical_layout.svg-1a08fee4b09812a05bcf3defb8afcc4c.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_composite.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://863s568sneja"
6 | path="res://.godot/imported/category_composite.svg-43f66e63a7ccfa5ac8ec6da0583b3246.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/category_composite.svg"
15 | dest_files=["res://.godot/imported/category_composite.svg-43f66e63a7ccfa5ac8ec6da0583b3246.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_decorator.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c2ie8m4ddawlb"
6 | path="res://.godot/imported/category_decorator.svg-79d598d6456f32724156248e09d6eaf3.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/category_decorator.svg"
15 | dest_files=["res://.godot/imported/category_decorator.svg-79d598d6456f32724156248e09d6eaf3.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/selector_reactive.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://crkbov0h8sb8l"
6 | path="res://.godot/imported/selector_reactive.svg-dd3b8fb8cd2ffe331605aaad1e021cc0.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/icons/selector_reactive.svg"
15 | dest_files=["res://.godot/imported/selector_reactive.svg-dd3b8fb8cd2ffe331605aaad1e021cc0.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/failer.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/failer.svg")
3 | class_name AlwaysFailDecorator extends Decorator
4 | ## A Failer node will always return a `FAILURE` status code.
5 |
6 | func tick(actor: Node, blackboard: Blackboard) -> int:
7 | var c = get_child(0)
8 |
9 | if c != running_child:
10 | c.before_run(actor, blackboard)
11 |
12 | var response = c.tick(actor, blackboard)
13 | if can_send_message(blackboard):
14 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
15 |
16 | if c is ConditionLeaf:
17 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
18 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
19 |
20 | if response == RUNNING:
21 | running_child = c
22 | if c is ActionLeaf:
23 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
24 | return RUNNING
25 | else:
26 | c.after_run(actor, blackboard)
27 | return FAILURE
28 |
29 |
30 | func get_class_name() -> Array[StringName]:
31 | var classes := super()
32 | classes.push_back(&"AlwaysFailDecorator")
33 | return classes
34 |
--------------------------------------------------------------------------------
/addons/beehave/debug/icons/horizontal_layout.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bah77esichnyx"
6 | path="res://.godot/imported/horizontal_layout.svg-d2a7af351e44f9bf61d0c938b6f47fac.ctex"
7 | metadata={
8 | "has_editor_variant": true,
9 | "vram_texture": false
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/beehave/debug/icons/horizontal_layout.svg"
15 | dest_files=["res://.godot/imported/horizontal_layout.svg-d2a7af351e44f9bf61d0c938b6f47fac.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=0
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 | svg/scale=1.0
37 | editor/scale_with_editor_scale=true
38 | editor/convert_colors_with_editor_theme=true
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Taillight Games
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/succeeder.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/succeeder.svg")
3 | class_name AlwaysSucceedDecorator extends Decorator
4 | ## A succeeder node will always return a `SUCCESS` status code.
5 |
6 | func tick(actor: Node, blackboard: Blackboard) -> int:
7 | var c = get_child(0)
8 |
9 | if c != running_child:
10 | c.before_run(actor, blackboard)
11 |
12 | var response = c.tick(actor, blackboard)
13 | if can_send_message(blackboard):
14 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
15 |
16 | if c is ConditionLeaf:
17 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
18 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
19 |
20 | if response == RUNNING:
21 | running_child = c
22 | if c is ActionLeaf:
23 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
24 | return RUNNING
25 | else:
26 | c.after_run(actor, blackboard)
27 | return SUCCESS
28 |
29 |
30 | func get_class_name() -> Array[StringName]:
31 | var classes := super()
32 | classes.push_back(&"AlwaysSucceedDecorator")
33 | return classes
34 |
--------------------------------------------------------------------------------
/addons/beehave/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 bitbrain
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/beehave/debug/frames.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends RefCounted
3 |
4 |
5 | const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
6 |
7 |
8 | const SUCCESS_COLOR := Color("#009944c8")
9 | const NORMAL_COLOR := Color("#15181e")
10 | const FAILURE_COLOR := Color("#cf000f80")
11 | const RUNNING_COLOR := Color("#ffcc00c8")
12 |
13 | var empty: StyleBoxEmpty
14 | var normal: StyleBoxFlat
15 | var success: StyleBoxFlat
16 | var failure: StyleBoxFlat
17 | var running: StyleBoxFlat
18 |
19 |
20 | func _init() -> void:
21 | var plugin := BeehaveUtils.get_plugin()
22 | if not plugin:
23 | return
24 |
25 | var editor_scale := BeehaveUtils.get_editor_scale()
26 |
27 | empty = StyleBoxEmpty.new()
28 |
29 | normal = plugin.get_editor_interface().get_base_control().get_theme_stylebox(&"frame", &"GraphNode").duplicate()
30 |
31 | success = plugin.get_editor_interface().get_base_control().get_theme_stylebox(&"selected_frame", &"GraphNode").duplicate()
32 | failure = success.duplicate()
33 | running = success.duplicate()
34 |
35 | success.border_color = SUCCESS_COLOR
36 | failure.border_color = FAILURE_COLOR
37 | running.border_color = RUNNING_COLOR
38 |
--------------------------------------------------------------------------------
/assets/shaders/crumble.gdshader:
--------------------------------------------------------------------------------
1 | shader_type spatial;
2 | render_mode unshaded, blend_mix, cull_disabled;
3 |
4 | uniform float alpha = 0.0;
5 |
6 | uniform float alpha_clip : hint_range(0.0, 1.0, 0.01);
7 |
8 | uniform sampler2D main_tex : filter_nearest_mipmap;
9 |
10 | uniform sampler2D noise_tex : filter_nearest_mipmap;
11 |
12 | uniform sampler2D SCREEN_TEXTURE : hint_screen_texture;
13 |
14 | uniform float effect_start_time;
15 |
16 | uniform vec2 noise_uv_offset;
17 |
18 | void vertex() {
19 | // Called for every vertex the material is visible on.
20 | }
21 |
22 | void fragment() {
23 | // Called for every pixel the material is visible on.
24 |
25 | vec4 _tex = texture(main_tex, UV);
26 | vec4 a = texture(noise_tex, UV + noise_uv_offset);
27 |
28 | float _multiply_alpha;
29 |
30 | if (a.x > alpha_clip)
31 | {
32 | _multiply_alpha = 1.0;
33 | } else {
34 | _multiply_alpha = 0.0;
35 | }
36 |
37 | ALBEDO = _tex.rgb;
38 |
39 | ALPHA = _multiply_alpha;
40 |
41 | }
42 |
43 | //void light() {
44 | // Called for every pixel for every light affecting the material.
45 | // Uncomment to replace the default light processing function with this one.
46 | //}
47 |
--------------------------------------------------------------------------------
/scripts/misc/shadow_caster.gd:
--------------------------------------------------------------------------------
1 | extends RayCast3D
2 |
3 |
4 | @export var shadow_offset : float = 0.02
5 |
6 | @onready var shadow : Node3D = $shadow
7 | @onready var parent : Node3D = get_parent()
8 |
9 | # Called when the node enters the scene tree for the first time.
10 | func _ready():
11 | pass # Replace with function body.
12 |
13 |
14 | # Called every frame. 'delta' is the elapsed time since the previous frame.
15 | func _physics_process(_delta):
16 |
17 | if is_colliding():
18 | shadow.visible = true
19 | global_rotation = Vector3(0,0,0)
20 | shadow.global_position = get_collision_point() + Vector3(0, shadow_offset, 0)
21 | shadow.basis = align_up(shadow.basis, get_collision_normal())
22 | else:
23 | shadow.visible = false
24 | #shadow.rotation_degrees.y = 0
25 |
26 |
27 | func align_up(node_basis, normal):
28 | var result = Basis()
29 | #var _scale = node_basis.get_scale() # Only if your node might have a scale other than (1,1,1)
30 |
31 | result.x = normal.cross(node_basis.z)
32 | result.y = normal
33 | result.z = node_basis.x.cross(normal)
34 |
35 | result = result.orthonormalized()
36 | #result.x *= _scale.x
37 | #result.y *= _scale.y
38 | #result.z *= _scale.z
39 |
40 | return result
41 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/blackboard_set.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BlackboardSetAction extends ActionLeaf
3 |
4 | ## Sets the specified key to the specified value.
5 | ## Returns [code]FAILURE[/code] if expression execution fails, otherwise [code]SUCCESS[/code].
6 |
7 | ## Expression representing a blackboard key.
8 | @export_placeholder(EXPRESSION_PLACEHOLDER) var key: String = ""
9 | ## Expression representing a blackboard value to assign to the specified key.
10 | @export_placeholder(EXPRESSION_PLACEHOLDER) var value: String = ""
11 |
12 |
13 | @onready var _key_expression: Expression = _parse_expression(key)
14 | @onready var _value_expression: Expression = _parse_expression(value)
15 |
16 |
17 | func tick(actor: Node, blackboard: Blackboard) -> int:
18 | var key_value: Variant = _key_expression.execute([], blackboard)
19 |
20 | if _key_expression.has_execute_failed():
21 | return FAILURE
22 |
23 | var value_value: Variant = _value_expression.execute([], blackboard)
24 |
25 | if _value_expression.has_execute_failed():
26 | return FAILURE
27 |
28 | blackboard.set_value(key_value, value_value)
29 |
30 | return SUCCESS
31 |
32 |
33 | func _get_expression_sources() -> Array[String]:
34 | return [key, value]
35 |
--------------------------------------------------------------------------------
/scripts/Damageable/damage_dealer.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Area3D
3 | class_name DamageDealer
4 |
5 | @export var affect_col_mask := false
6 |
7 | @export var active := false
8 |
9 | @export var damage := 1
10 | @export var attack_object : AttackObject
11 |
12 | @export var self_collider : Area3D
13 |
14 | var collider_mask
15 |
16 | func _ready():
17 | attack_object = AttackObject.new()
18 | attack_object.damage = 1
19 | if !area_entered.is_connected(_on_area_entered):
20 | area_entered.connect(_on_area_entered)
21 | collider_mask = collision_mask
22 | if affect_col_mask:
23 | collision_mask = 0
24 |
25 | func _on_area_entered(area : Area3D):
26 | if active:
27 | if area != self_collider and area is Damageable:
28 | area.damaged(attack_object)
29 |
30 |
31 | func enable():
32 | if affect_col_mask:
33 | collision_mask = collider_mask
34 | active = true
35 |
36 | func disable():
37 | if affect_col_mask:
38 | collision_mask = 0
39 | active = false
40 |
41 | func oneshot():
42 | var _areas = get_overlapping_areas()
43 | for _a in _areas:
44 | if _a is Damageable:
45 | _a.damaged(damage)
46 |
47 |
48 | func is_in_hitbox(_agent : Area3D) -> bool:
49 | var _areas = get_overlapping_areas()
50 | for _a in _areas:
51 | if _a == _agent:
52 | return true
53 | return false
54 |
--------------------------------------------------------------------------------
/addons/beehave/metrics/beehave_global_metrics.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var _tree_count: int = 0
4 | var _active_tree_count: int = 0
5 | var _registered_trees: Array = []
6 |
7 |
8 | func _enter_tree() -> void:
9 | Performance.add_custom_monitor("beehave/total_trees", _get_total_trees)
10 | Performance.add_custom_monitor("beehave/total_enabled_trees", _get_total_enabled_trees)
11 |
12 |
13 | func register_tree(tree) -> void:
14 | if _registered_trees.has(tree):
15 | return
16 |
17 | _registered_trees.append(tree)
18 | _tree_count += 1
19 |
20 | if tree.enabled:
21 | _active_tree_count += 1
22 |
23 | tree.tree_enabled.connect(_on_tree_enabled)
24 | tree.tree_disabled.connect(_on_tree_disabled)
25 |
26 |
27 | func unregister_tree(tree) -> void:
28 | if not _registered_trees.has(tree):
29 | return
30 |
31 | _registered_trees.erase(tree)
32 | _tree_count -= 1
33 |
34 | if tree.enabled:
35 | _active_tree_count -= 1
36 |
37 | tree.tree_enabled.disconnect(_on_tree_enabled)
38 | tree.tree_disabled.disconnect(_on_tree_disabled)
39 |
40 |
41 | func _get_total_trees() -> int:
42 | return _tree_count
43 |
44 |
45 | func _get_total_enabled_trees() -> int:
46 | return _active_tree_count
47 |
48 |
49 | func _on_tree_enabled() -> void:
50 | _active_tree_count += 1
51 |
52 |
53 | func _on_tree_disabled() -> void:
54 | _active_tree_count -= 1
55 |
--------------------------------------------------------------------------------
/scripts/misc/camera_movement.gd:
--------------------------------------------------------------------------------
1 | # ----------------------------------------------------------------------------------- #
2 | # -------------- FEEL FREE TO USE IN ANY PROJECT, COMMERCIAL OR NON-COMMERCIAL ------ #
3 | # ---------------------- 3D PLATFORMER CONTROLLER BY SD STUDIOS --------------------- #
4 | # ---------------------------- ATTRIBUTION NOT REQUIRED ----------------------------- #
5 | # ----------------------------------------------------------------------------------- #
6 |
7 | extends Node3D
8 |
9 | # ---------- VARIABLES ---------- #
10 |
11 | # Control Mouse Sensitivity through inspector or from here
12 | @export var mouse_sensitivity := 0.2
13 |
14 | # Assign Camera Node here it might be named different in your Project
15 | @onready var camera = $Camera3D
16 |
17 | # ---------- FUNCTIONS ---------- #
18 |
19 | func _ready():
20 | top_level = true
21 | # Confining Mouse Cursor in the game view so it doesnt get in the way of gameplay
22 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
23 |
24 | # Handling Camera Movement
25 | func _unhandled_input(event):
26 | if event is InputEventMouseMotion:
27 | rotation_degrees.x -= event.relative.y * mouse_sensitivity
28 | rotation_degrees.x = clamp(rotation_degrees.x, -60, 60)
29 |
30 | rotation_degrees.y -= event.relative.x * mouse_sensitivity
31 | rotation_degrees.y = wrapf(rotation_degrees.y, 0, 360)
32 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/inverter.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/inverter.svg")
3 | class_name InverterDecorator extends Decorator
4 | ## An inverter will return `FAILURE` in case it's child returns a `SUCCESS` status
5 | ## code or `SUCCESS` in case its child returns a `FAILURE` status code.
6 |
7 | func tick(actor: Node, blackboard: Blackboard) -> int:
8 | var c = get_child(0)
9 |
10 | if c != running_child:
11 | c.before_run(actor, blackboard)
12 |
13 | var response = c.tick(actor, blackboard)
14 | if can_send_message(blackboard):
15 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
16 |
17 | if c is ConditionLeaf:
18 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
19 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
20 |
21 | match response:
22 | SUCCESS:
23 | c.after_run(actor, blackboard)
24 | return FAILURE
25 | FAILURE:
26 | c.after_run(actor, blackboard)
27 | return SUCCESS
28 | RUNNING:
29 | running_child = c
30 | if c is ActionLeaf:
31 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
32 | return RUNNING
33 | _:
34 | push_error("This should be unreachable")
35 | return -1
36 |
37 |
38 | func get_class_name() -> Array[StringName]:
39 | var classes := super()
40 | classes.push_back(&"InverterDecorator")
41 | return classes
42 |
--------------------------------------------------------------------------------
/scripts/Damageable/agent_damageable.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Damageable
3 | class_name AgentDamageable
4 |
5 | @export_category("Agent Settings")
6 |
7 | @export var team : int = 0
8 |
9 | @export var agent : Node
10 |
11 | @export var only_damage_in_vulnerable : bool = false
12 |
13 | @export var damage_vulnerability : AttackObject.damage_types = AttackObject.damage_types.none
14 |
15 | @export var settings : DamageableSettings
16 |
17 | var is_alive := true
18 |
19 | var vulnerable : bool = false
20 |
21 | signal on_invincible_hit
22 |
23 | func _ready():
24 |
25 | if agent == null:
26 | agent = get_parent()
27 |
28 | func damaged(_attack : AttackObject):
29 |
30 | if !active or health <= 0:
31 | print("no damage")
32 | return
33 |
34 | if only_damage_in_vulnerable and !vulnerable:
35 | if !_attack.damage_type == damage_vulnerability:
36 | on_invincible_hit.emit()
37 | return
38 |
39 |
40 | var _damage = _attack.damage
41 |
42 | if vulnerable:
43 | var _fdamage : float = _attack.damage * settings.damage_mult_in_vulnerable
44 | _damage = roundi(_fdamage)
45 |
46 | health -= _damage
47 |
48 | on_hit.emit()
49 |
50 | agent.on_hit()
51 |
52 | if health <= 0:
53 | die()
54 |
55 | func heal(i : int):
56 | health += i
57 | if health > max_health:
58 | health = max_health
59 |
60 | on_heal.emit()
61 |
62 | func die():
63 | on_die.emit()
64 | is_alive = false
65 | agent.die()
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/addons/beehave/blackboard.gd:
--------------------------------------------------------------------------------
1 | @icon("icons/blackboard.svg")
2 | class_name Blackboard extends Node
3 |
4 |
5 | const DEFAULT = "default"
6 |
7 |
8 | ## The blackboard is an object that can be used to store and access data between
9 | ## multiple nodes of the behavior tree.
10 | @export var blackboard: Dictionary = {}:
11 | set(b):
12 | blackboard = b
13 | _data[DEFAULT] = blackboard
14 |
15 |
16 | var _data:Dictionary = {}
17 |
18 |
19 | func _ready():
20 | _data[DEFAULT] = blackboard
21 |
22 |
23 | func keys() -> Array[String]:
24 | var keys: Array[String]
25 | keys.assign(_data.keys().duplicate())
26 | return keys
27 |
28 | func set_value(key: Variant, value: Variant, blackboard_name: String = DEFAULT) -> void:
29 | if not _data.has(blackboard_name):
30 | _data[blackboard_name] = {}
31 |
32 | _data[blackboard_name][key] = value
33 |
34 |
35 | func get_value(key: Variant, default_value: Variant = null, blackboard_name: String = DEFAULT) -> Variant:
36 | if has_value(key, blackboard_name):
37 | return _data[blackboard_name].get(key, default_value)
38 | return default_value
39 |
40 |
41 | func has_value(key: Variant, blackboard_name: String = DEFAULT) -> bool:
42 | return _data.has(blackboard_name) and _data[blackboard_name].has(key) and _data[blackboard_name][key] != null
43 |
44 |
45 | func erase_value(key: Variant, blackboard_name: String = DEFAULT) -> void:
46 | if _data.has(blackboard_name):
47 | _data[blackboard_name][key] = null
48 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/leaf.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/category_leaf.svg")
3 | class_name Leaf extends BeehaveNode
4 | ## Base class for all leaf nodes of the tree.
5 |
6 | const EXPRESSION_PLACEHOLDER: String = "Insert an expression..."
7 |
8 |
9 | func _get_configuration_warnings() -> PackedStringArray:
10 | var warnings: PackedStringArray = []
11 |
12 | var children: Array[Node] = get_children()
13 |
14 | if children.any(func(x): return x is BeehaveNode):
15 | warnings.append("Leaf nodes should not have any child nodes. They won't be ticked.")
16 |
17 | for source in _get_expression_sources():
18 | var error_text: String = _parse_expression(source).get_error_text()
19 | if not error_text.is_empty():
20 | warnings.append("Expression `%s` is invalid! Error text: `%s`" % [source, error_text])
21 |
22 | return warnings
23 |
24 |
25 | func _parse_expression(source: String) -> Expression:
26 | var result: Expression = Expression.new()
27 | var error: int = result.parse(source)
28 |
29 | if not Engine.is_editor_hint() and error != OK:
30 | push_error(
31 | "[Leaf] Couldn't parse expression with source: `%s` Error text: `%s`" %\
32 | [source, result.get_error_text()]
33 | )
34 |
35 | return result
36 |
37 |
38 | func _get_expression_sources() -> Array[String]: # virtual
39 | return []
40 |
41 |
42 | func get_class_name() -> Array[StringName]:
43 | var classes := super()
44 | classes.push_back(&"Leaf")
45 | return classes
46 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/beehave_node.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BeehaveNode extends Node
3 | ## A node in the behavior tree. Every node must return `SUCCESS`, `FAILURE` or
4 | ## `RUNNING` when ticked.
5 |
6 | enum {
7 | SUCCESS,
8 | FAILURE,
9 | RUNNING
10 | }
11 |
12 |
13 | func _get_configuration_warnings() -> PackedStringArray:
14 | var warnings: PackedStringArray = []
15 |
16 | if get_children().any(func(x): return not (x is BeehaveNode)):
17 | warnings.append("All children of this node should inherit from BeehaveNode class.")
18 |
19 | return warnings
20 |
21 |
22 | ## Executes this node and returns a status code.
23 | ## This method must be overwritten.
24 | func tick(actor: Node, blackboard: Blackboard) -> int:
25 | return SUCCESS
26 |
27 |
28 | ## Called when this node needs to be interrupted before it can return FAILURE or SUCCESS.
29 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
30 | pass
31 |
32 |
33 | ## Called before the first time it ticks by the parent.
34 | func before_run(actor: Node, blackboard: Blackboard) -> void:
35 | pass
36 |
37 |
38 | ## Called after the last time it ticks and returns
39 | ## [code]SUCCESS[/code] or [code]FAILURE[/code].
40 | func after_run(actor: Node, blackboard: Blackboard) -> void:
41 | pass
42 |
43 |
44 | func get_class_name() -> Array[StringName]:
45 | return [&"BeehaveNode"]
46 |
47 |
48 | func can_send_message(blackboard: Blackboard) -> bool:
49 | return blackboard.get_value("can_send_message", false)
50 |
--------------------------------------------------------------------------------
/addons/beehave/icons/cooldown.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/blackboard.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/selector_reactive.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/selector_reactive.svg")
3 | class_name SelectorReactiveComposite extends Composite
4 | ## Selector Reactive nodes will attempt to execute each of its children until one of
5 | ## them return `SUCCESS`. If all children return `FAILURE`, this node will also
6 | ## return `FAILURE`.
7 | ## If a child returns `RUNNING` it will restart.
8 |
9 | func tick(actor: Node, blackboard: Blackboard) -> int:
10 | for c in get_children():
11 | if c != running_child:
12 | c.before_run(actor, blackboard)
13 |
14 | var response = c.tick(actor, blackboard)
15 | if can_send_message(blackboard):
16 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
17 |
18 | if c is ConditionLeaf:
19 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
20 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
21 |
22 | match response:
23 | SUCCESS:
24 | # Interrupt any child that was RUNNING before.
25 | if c != running_child:
26 | interrupt(actor, blackboard)
27 | c.after_run(actor, blackboard)
28 | return SUCCESS
29 | FAILURE:
30 | c.after_run(actor, blackboard)
31 | RUNNING:
32 | if c != running_child:
33 | interrupt(actor, blackboard)
34 | running_child = c
35 | if c is ActionLeaf:
36 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
37 | return RUNNING
38 |
39 | return FAILURE
40 |
41 |
42 | func get_class_name() -> Array[StringName]:
43 | var classes := super()
44 | classes.push_back(&"SelectorReactiveComposite")
45 | return classes
46 |
--------------------------------------------------------------------------------
/addons/beehave/icons/delayer.svg:
--------------------------------------------------------------------------------
1 |
2 |
40 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/delayer.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/delayer.svg")
3 | extends Decorator
4 | class_name DelayDecorator
5 | ## The Delay Decorator will return 'RUNNING' for a set amount of time
6 | ## before executing its child.
7 | ## The timer resets when both it and its child are not `RUNNING`
8 |
9 | ## The wait time in seconds
10 | @export var wait_time: = 0.0
11 |
12 | @onready var cache_key = 'time_limiter_%s' % self.get_instance_id()
13 |
14 | func tick(actor: Node, blackboard: Blackboard) -> int:
15 | var c = get_child(0)
16 | var total_time = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
17 | var response
18 |
19 | if c != running_child:
20 | c.before_run(actor, blackboard)
21 |
22 | if total_time < wait_time:
23 | response = RUNNING
24 |
25 | total_time += get_physics_process_delta_time()
26 | blackboard.set_value(cache_key, total_time, str(actor.get_instance_id()))
27 |
28 | if can_send_message(blackboard):
29 | BeehaveDebuggerMessages.process_tick(self.get_instance_id(), response)
30 | else:
31 | response = c.tick(actor, blackboard)
32 |
33 | if can_send_message(blackboard):
34 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
35 |
36 | if c is ConditionLeaf:
37 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
38 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
39 |
40 | if response == RUNNING and c is ActionLeaf:
41 | running_child = c
42 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
43 |
44 | if response != RUNNING:
45 | blackboard.set_value(cache_key, 0.0, str(actor.get_instance_id()))
46 |
47 | return response
48 |
49 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/cooldown.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/cooldown.svg")
3 | extends Decorator
4 | class_name CooldownDecorator
5 | ## The Cooldown Decorator will return 'FAILURE' for a set amount of time
6 | ## after executing its child.
7 | ## The timer resets the next time its child is executed and it is not `RUNNING`
8 |
9 | ## The wait time in seconds
10 | @export var wait_time: = 0.0
11 |
12 | @onready var cache_key = 'cooldown_%s' % self.get_instance_id()
13 |
14 |
15 | func tick(actor: Node, blackboard: Blackboard) -> int:
16 | var c = get_child(0)
17 | var remaining_time = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
18 | var response
19 |
20 | if c != running_child:
21 | c.before_run(actor, blackboard)
22 |
23 | if remaining_time > 0:
24 | response = FAILURE
25 |
26 | remaining_time -= get_physics_process_delta_time()
27 | blackboard.set_value(cache_key, remaining_time, str(actor.get_instance_id()))
28 |
29 | if can_send_message(blackboard):
30 | BeehaveDebuggerMessages.process_tick(self.get_instance_id(), response)
31 | else:
32 | response = c.tick(actor, blackboard)
33 |
34 | if can_send_message(blackboard):
35 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
36 |
37 | if c is ConditionLeaf:
38 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
39 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
40 |
41 | if response == RUNNING and c is ActionLeaf:
42 | running_child = c
43 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
44 |
45 | if response != RUNNING:
46 | blackboard.set_value(cache_key, wait_time, str(actor.get_instance_id()))
47 |
48 | return response
49 |
50 |
51 |
--------------------------------------------------------------------------------
/scripts/AI/ai_senses.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Area3D
3 | class_name AISenses
4 |
5 | @export var self_collider : Area3D
6 |
7 | @export var current_agents : Array[Area3D] = []
8 |
9 | @export var current_enemies : Array[Area3D] = []
10 |
11 | @export var check_los : bool = false
12 |
13 | var raycast :RayCast3D
14 |
15 | # Called when the node enters the scene tree for the first time.
16 | func _ready():
17 | if check_los:
18 | raycast = $RayCast3D
19 |
20 |
21 | # Called every frame. 'delta' is the elapsed time since the previous frame.
22 | func _process(_delta):
23 | pass
24 |
25 |
26 |
27 |
28 | func _on_area_entered(area):
29 | if area is AgentDamageable and area != self_collider:
30 | if area.team != self_collider.team:
31 | current_enemies.append(area)
32 | else:
33 | current_agents.append(area)
34 |
35 |
36 | func _on_area_exited(area):
37 | current_agents.erase(area)
38 | current_enemies.erase(area)
39 |
40 |
41 | func has_enemies() -> bool:
42 | if current_enemies.size() > 0:
43 | return true
44 | else:
45 | return false
46 |
47 | func get_enemy() -> Node3D:
48 | if current_enemies.size() > 0:
49 | if check_los:
50 | if has_los(current_enemies[0].global_position):
51 | return current_enemies[0] as Node3D
52 | else:
53 | return null
54 | else:
55 | return current_enemies[0] as Node3D
56 | else:
57 | return null
58 |
59 | func has_los(target : Vector3) -> bool:
60 | raycast.enabled = true
61 | raycast.look_at_from_position(raycast.global_position, target, Vector3(0,1,0))
62 | raycast.target_position.z = -raycast.global_position.distance_to(target)
63 | raycast.force_raycast_update()
64 |
65 | if raycast.is_colliding():
66 | raycast.enabled = false
67 | return false
68 | else:
69 | raycast.enabled = false
70 | return true
71 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/repeater.gd:
--------------------------------------------------------------------------------
1 |
2 | @tool
3 | @icon("../../icons/repeater.svg")
4 | class_name RepeaterDecorator extends Decorator
5 | ## The repeater will execute its child until it returns `SUCCESS` a certain amount of times.
6 | ## When the number of maximum ticks is reached, it will return a `SUCCESS` status code.
7 | ## If the child returns `FAILURE`, the repeater will return `FAILURE` immediately.
8 |
9 | @export var repetitions: int = 1
10 | var current_count: int = 0
11 |
12 |
13 | func before_run(actor: Node, blackboard: Blackboard):
14 | current_count = 0
15 |
16 |
17 | func tick(actor: Node, blackboard: Blackboard) -> int:
18 | var child = get_child(0)
19 |
20 | if current_count < repetitions:
21 | if running_child == null:
22 | child.before_run(actor, blackboard)
23 |
24 | var response = child.tick(actor, blackboard)
25 |
26 | if can_send_message(blackboard):
27 | BeehaveDebuggerMessages.process_tick(child.get_instance_id(), response)
28 |
29 | if child is ConditionLeaf:
30 | blackboard.set_value("last_condition", child, str(actor.get_instance_id()))
31 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
32 |
33 | if response == RUNNING:
34 | running_child = child
35 | if child is ActionLeaf:
36 | blackboard.set_value("running_action", child, str(actor.get_instance_id()))
37 | return RUNNING
38 |
39 | current_count += 1
40 | child.after_run(actor, blackboard)
41 |
42 | if running_child != null:
43 | running_child = null
44 |
45 | if response == FAILURE:
46 | return FAILURE
47 |
48 | if current_count >= repetitions:
49 | return SUCCESS
50 |
51 | return RUNNING
52 | else:
53 | return SUCCESS
54 |
55 |
56 | func get_class_name() -> Array[StringName]:
57 | var classes := super()
58 | classes.push_back(&"LimiterDecorator")
59 | return classes
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BeeHave 3D Sample Project
2 |
3 | ### Tutorial and Demo
4 |
5 | In this video, I go over the contents of the repository as well as an overview of both behavior trees in general and specifically how BeeHave works.
6 |
7 | [](https://www.youtube.com/watch?v=AUfzET91m0s)
8 |
9 |
10 | ### Description
11 |
12 | BeeHave is a great asset for behavior trees in Godot, but I found it difficult to learn.
13 | Whenever I want to learn a new asset, I like to just tear apart some example projects. If that's you, this repository is for you!
14 | This is the implimentation of BeeHave in my current in-progress project: Ruins of Calica, ripped straight out of that game and put into this repository.
15 |
16 | ### Contents:
17 |
18 | - A working project with a simple character controller and a slime enemy that wanders around when idle and chases and attacks the player when in range.
19 | - Behavior trees for all the other enemies in my game. The actual enemies couldn't be included because I cannot distribute the models.
20 | - Some custom decorator nodes I found helpful, for instance: UntilSucced (the opposite of UntilFailure)
21 |
22 |
23 | ### Credits:
24 |
25 | **Character controller from: 3D-Platformer Kit by SilverDemons**
26 | https://github.com/SilverDemons-PK/3D-Platformer-Kit
27 |
28 | **BeeHave by BitBrain & Others**
29 | https://github.com/bitbrain/beehave
30 |
31 | ### Recommended Resources:
32 |
33 | https://www.gamedeveloper.com/programming/behavior-trees-for-ai-how-they-work - Behavior trees for AI: How they work
34 |
35 | https://youtu.be/PDlAlutle_c - Godot 4.1: Behavior Trees with Beehave: rant and how to start using them..
36 |
37 | https://youtu.be/YHUQY2Kea9U - Behavior Trees - Godot Game Dev (BETTER AUDIO)
38 |
39 | https://bitbra.in/beehave/#/ - BeeHave docs
40 |
41 | https://github.com/bitbrain/beehave - BeeHave Github Page
42 |
--------------------------------------------------------------------------------
/addons/beehave/icons/succeeder.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/sequence_star.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/sequence_reactive.svg")
3 | class_name SequenceStarComposite extends Composite
4 | ## Sequence Star nodes will attempt to execute all of its children and report
5 | ## `SUCCESS` in case all of the children report a `SUCCESS` status code.
6 | ## If at least one child reports a `FAILURE` status code, this node will also
7 | ## return `FAILURE` and tick again.
8 | ## In case a child returns `RUNNING` this node will tick again.
9 |
10 | var successful_index: int = 0
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | for c in get_children():
15 | if c.get_index() < successful_index:
16 | continue
17 |
18 | if c != running_child:
19 | c.before_run(actor, blackboard)
20 |
21 | var response = c.tick(actor, blackboard)
22 | if can_send_message(blackboard):
23 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
24 |
25 | if c is ConditionLeaf:
26 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
27 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
28 |
29 | match response:
30 | SUCCESS:
31 | successful_index += 1
32 | c.after_run(actor, blackboard)
33 | FAILURE:
34 | # Interrupt any child that was RUNNING before
35 | # but do not reset!
36 | super.interrupt(actor, blackboard)
37 | c.after_run(actor, blackboard)
38 | return FAILURE
39 | RUNNING:
40 | running_child = c
41 | if c is ActionLeaf:
42 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
43 | return RUNNING
44 | _reset()
45 | return SUCCESS
46 |
47 |
48 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
49 | _reset()
50 | super(actor, blackboard)
51 |
52 |
53 | func _reset() -> void:
54 | successful_index = 0
55 |
56 |
57 | func get_class_name() -> Array[StringName]:
58 | var classes := super()
59 | classes.push_back(&"SequenceStarComposite")
60 | return classes
61 |
--------------------------------------------------------------------------------
/scenes/beehave-trees/SimpleWander.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=9 format=3 uid="uid://bbjni644vcqwl"]
2 |
3 | [ext_resource type="Script" path="res://addons/beehave/nodes/beehave_tree.gd" id="1_nvhg6"]
4 | [ext_resource type="Script" path="res://addons/beehave/nodes/composites/selector.gd" id="2_swgyd"]
5 | [ext_resource type="Script" path="res://addons/beehave/nodes/decorators/inverter.gd" id="3_d727g"]
6 | [ext_resource type="Script" path="res://scripts/beehave/bh_is_at_destination.gd" id="3_iwucb"]
7 | [ext_resource type="Script" path="res://addons/beehave/nodes/composites/sequence.gd" id="4_fwm51"]
8 | [ext_resource type="Script" path="res://scripts/beehave/bh_anim_travel.gd" id="6_2kyg0"]
9 | [ext_resource type="Script" path="res://addons/beehave/nodes/decorators/delayer.gd" id="6_s56b4"]
10 | [ext_resource type="Script" path="res://scripts/beehave/bh_new_wander_target.gd" id="7_ui1mk"]
11 |
12 | [node name="SimpleWander" type="Node" node_paths=PackedStringArray("blackboard", "actor")]
13 | script = ExtResource("1_nvhg6")
14 | blackboard = NodePath("@Node@17503")
15 | actor = NodePath("")
16 |
17 | [node name="SelectorComposite2" type="Node" parent="."]
18 | script = ExtResource("2_swgyd")
19 |
20 | [node name="InverterDecorator" type="Node" parent="SelectorComposite2"]
21 | script = ExtResource("3_d727g")
22 |
23 | [node name="IsAtDestination" type="Node" parent="SelectorComposite2/InverterDecorator"]
24 | script = ExtResource("3_iwucb")
25 |
26 | [node name="SequenceComposite" type="Node" parent="SelectorComposite2"]
27 | script = ExtResource("4_fwm51")
28 |
29 | [node name="AnimTravel" type="Node" parent="SelectorComposite2/SequenceComposite"]
30 | script = ExtResource("6_2kyg0")
31 | animation_name = &"attack_1"
32 |
33 | [node name="DelayDecorator" type="Node" parent="SelectorComposite2/SequenceComposite"]
34 | script = ExtResource("6_s56b4")
35 | wait_time = 3.0
36 |
37 | [node name="NewWanderTarget" type="Node" parent="SelectorComposite2/SequenceComposite/DelayDecorator"]
38 | script = ExtResource("7_ui1mk")
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/limiter.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/tree.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/scripts/AI/ActionSlots/as_hit.gd:
--------------------------------------------------------------------------------
1 |
2 | class_name AS_Hit extends ActionSlot
3 |
4 |
5 | @export var hit_recover_time : float = 1
6 |
7 | @export var hit_recovery_i_frames := false
8 |
9 | @export var hit_knockback : float = 3
10 |
11 | @export var enable_knockback := true
12 |
13 | @export var stop_think_during_recovery := false
14 |
15 | # prevent the hit effect from stunlocking enemies
16 | # only the first hit in that period of time will play the animation
17 | @export_category("Recovery Repeat Timer")
18 | @export var enable_repeat_timer := false
19 | @export var repeat_time : float = 1.0
20 | @onready var repeat_timer : Timer = $HitRecoveryRepeatTimer
21 | var repeat_timer_in_progress := false
22 |
23 | var disable_hit_response := false
24 |
25 | func _ready():
26 | if enable_repeat_timer:
27 | repeat_timer.timeout.connect(repeat_timer_timeout)
28 |
29 | func on_start_action():
30 |
31 | # check to make sure we should actually do the hit action
32 | if disable_hit_response:
33 | return
34 | if repeat_timer_in_progress:
35 | return
36 |
37 | if stop_think_during_recovery:
38 | parent.a_action_started()
39 | # add end self to the action_ended signal
40 | parent.action_ended.connect(on_end_action)
41 |
42 | if hit_recovery_i_frames:
43 | agent.toggle_damageable(false)
44 | # play the hit animation
45 | agent.anim_sm.start("hit")
46 | # set the actions to think there's an action in progress
47 | if enable_knockback:
48 | agent.linear_velocity = agent.basis.z * hit_knockback
49 |
50 | if enable_repeat_timer:
51 | repeat_timer_start()
52 |
53 | parent.timer.start(hit_recover_time)
54 |
55 | func on_end_action():
56 | parent.action_ended.disconnect(on_end_action)
57 | agent.toggle_damageable(true)
58 |
59 | # empty function must be here to overwrite the assert in the base class.
60 | func on_action_process():
61 | pass
62 |
63 | func repeat_timer_start():
64 | repeat_timer_in_progress = true
65 | repeat_timer.start(repeat_time)
66 |
67 | func repeat_timer_timeout():
68 | repeat_timer_in_progress = false
69 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/sequence_reactive.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/sequence_reactive.svg")
3 | class_name SequenceReactiveComposite extends Composite
4 | ## Reactive Sequence nodes will attempt to execute all of its children and report
5 | ## `SUCCESS` in case all of the children report a `SUCCESS` status code.
6 | ## If at least one child reports a `FAILURE` status code, this node will also
7 | ## return `FAILURE` and restart.
8 | ## In case a child returns `RUNNING` this node will restart.
9 |
10 | var successful_index: int = 0
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | for c in get_children():
15 | if c.get_index() < successful_index:
16 | continue
17 |
18 | if c != running_child:
19 | c.before_run(actor, blackboard)
20 |
21 | var response = c.tick(actor, blackboard)
22 | if can_send_message(blackboard):
23 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
24 |
25 | if c is ConditionLeaf:
26 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
27 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
28 |
29 | match response:
30 | SUCCESS:
31 | successful_index += 1
32 | c.after_run(actor, blackboard)
33 | FAILURE:
34 | # Interrupt any child that was RUNNING before.
35 | interrupt(actor, blackboard)
36 | c.after_run(actor, blackboard)
37 | return FAILURE
38 | RUNNING:
39 | _reset()
40 | if running_child != c:
41 | interrupt(actor, blackboard)
42 | running_child = c
43 | if c is ActionLeaf:
44 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
45 | return RUNNING
46 | _reset()
47 | return SUCCESS
48 |
49 |
50 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
51 | _reset()
52 | super(actor, blackboard)
53 |
54 | func _reset() -> void:
55 | successful_index = 0
56 |
57 |
58 | func get_class_name() -> Array[StringName]:
59 | var classes := super()
60 | classes.push_back(&"SequenceReactiveComposite")
61 | return classes
62 |
--------------------------------------------------------------------------------
/addons/beehave/icons/failer.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/limiter.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/limiter.svg")
3 | class_name LimiterDecorator extends Decorator
4 | ## The limiter will execute its `RUNNING` child `x` amount of times. When the number of
5 | ## maximum ticks is reached, it will return a `FAILURE` status code.
6 | ## The count resets the next time that a child is not `RUNNING`
7 |
8 | @onready var cache_key = 'limiter_%s' % self.get_instance_id()
9 |
10 | @export var max_count : float = 0
11 |
12 | func tick(actor: Node, blackboard: Blackboard) -> int:
13 | if not get_child_count() == 1:
14 | return FAILURE
15 |
16 | var child = get_child(0)
17 | var current_count = blackboard.get_value(cache_key, 0, str(actor.get_instance_id()))
18 |
19 | if current_count < max_count:
20 | blackboard.set_value(cache_key, current_count + 1, str(actor.get_instance_id()))
21 | var response = child.tick(actor, blackboard)
22 | if can_send_message(blackboard):
23 | BeehaveDebuggerMessages.process_tick(child.get_instance_id(), response)
24 |
25 | if child is ConditionLeaf:
26 | blackboard.set_value("last_condition", child, str(actor.get_instance_id()))
27 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
28 |
29 | if child is ActionLeaf and response == RUNNING:
30 | running_child = child
31 | blackboard.set_value("running_action", child, str(actor.get_instance_id()))
32 |
33 | if response != RUNNING:
34 | child.after_run(actor, blackboard)
35 |
36 | return response
37 | else:
38 | interrupt(actor, blackboard)
39 | child.after_run(actor, blackboard)
40 | return FAILURE
41 |
42 |
43 | func before_run(actor: Node, blackboard: Blackboard) -> void:
44 | blackboard.set_value(cache_key, 0, str(actor.get_instance_id()))
45 | if get_child_count() > 0:
46 | get_child(0).before_run(actor, blackboard)
47 |
48 |
49 | func get_class_name() -> Array[StringName]:
50 | var classes := super()
51 | classes.push_back(&"LimiterDecorator")
52 | return classes
53 |
54 |
55 | func _get_configuration_warnings() -> PackedStringArray:
56 | if not get_child_count() == 1:
57 | return ["Requires exactly one child node"]
58 | return []
59 |
--------------------------------------------------------------------------------
/addons/beehave/icons/inverter.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/for_loop.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/category_decorator.svg")
3 | class_name ForLoopDecorator extends Decorator
4 | ## The limiter will execute its `RUNNING` child `x` amount of times. When the number of
5 | ## maximum ticks is reached, it will return a `FAILURE` status code.
6 | ## The count resets the next time that a child is not `RUNNING`
7 |
8 | @onready var cache_key = 'limiter_%s' % self.get_instance_id()
9 |
10 | @export var max_count : float = 0
11 |
12 | func tick(actor: Node, blackboard: Blackboard) -> int:
13 | if not get_child_count() == 1:
14 | return FAILURE
15 |
16 | var child = get_child(0)
17 | var current_count = blackboard.get_value(cache_key, 0, str(actor.get_instance_id()))
18 |
19 | if current_count < max_count:
20 | blackboard.set_value(cache_key, current_count + 1, str(actor.get_instance_id()))
21 | var response = child.tick(actor, blackboard)
22 | if can_send_message(blackboard):
23 | BeehaveDebuggerMessages.process_tick(child.get_instance_id(), response)
24 |
25 | if child is ConditionLeaf:
26 | blackboard.set_value("last_condition", child, str(actor.get_instance_id()))
27 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
28 |
29 | if child is ActionLeaf and response == RUNNING:
30 | running_child = child
31 | blackboard.set_value("running_action", child, str(actor.get_instance_id()))
32 |
33 | if response != RUNNING:
34 | child.after_run(actor, blackboard)
35 |
36 | return response
37 | else:
38 | interrupt(actor, blackboard)
39 | child.after_run(actor, blackboard)
40 | return FAILURE
41 |
42 |
43 | func before_run(actor: Node, blackboard: Blackboard) -> void:
44 | blackboard.set_value(cache_key, 0, str(actor.get_instance_id()))
45 | if get_child_count() > 0:
46 | get_child(0).before_run(actor, blackboard)
47 |
48 |
49 | func get_class_name() -> Array[StringName]:
50 | var classes := super()
51 | classes.push_back(&"LimiterDecorator")
52 | return classes
53 |
54 |
55 | func _get_configuration_warnings() -> PackedStringArray:
56 | if not get_child_count() == 1:
57 | return ["Requires exactly one child node"]
58 | return []
59 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/time_limiter.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/limiter.svg")
3 | class_name TimeLimiterDecorator extends Decorator
4 | ## The Time Limit Decorator will give its `RUNNING` child a set amount of time to finish
5 | ## before interrupting it and return a `FAILURE` status code.
6 | ## The timer resets the next time that a child is not `RUNNING`
7 |
8 | @export var wait_time: = 0.0
9 |
10 | @onready var cache_key = 'time_limiter_%s' % self.get_instance_id()
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | if not get_child_count() == 1:
15 | return FAILURE
16 |
17 | var child = self.get_child(0)
18 | var time_left = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
19 |
20 | if time_left < wait_time:
21 | time_left += get_physics_process_delta_time()
22 | blackboard.set_value(cache_key, time_left, str(actor.get_instance_id()))
23 | var response = child.tick(actor, blackboard)
24 | if can_send_message(blackboard):
25 | BeehaveDebuggerMessages.process_tick(child.get_instance_id(), response)
26 |
27 | if child is ConditionLeaf:
28 | blackboard.set_value("last_condition", child, str(actor.get_instance_id()))
29 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
30 |
31 | if response == RUNNING:
32 | running_child = child
33 | if child is ActionLeaf:
34 | blackboard.set_value("running_action", child, str(actor.get_instance_id()))
35 | else:
36 | child.after_run(actor, blackboard)
37 | return response
38 | else:
39 | interrupt(actor, blackboard)
40 | child.after_run(actor, blackboard)
41 | return FAILURE
42 |
43 |
44 | func before_run(actor: Node, blackboard: Blackboard) -> void:
45 | blackboard.set_value(cache_key, 0.0, str(actor.get_instance_id()))
46 | if get_child_count() > 0:
47 | get_child(0).before_run(actor, blackboard)
48 |
49 |
50 | func get_class_name() -> Array[StringName]:
51 | var classes := super()
52 | classes.push_back(&"TimeLimiterDecorator")
53 | return classes
54 |
55 |
56 | func _get_configuration_warnings() -> PackedStringArray:
57 | if not get_child_count() == 1:
58 | return ["Requires exactly one child node"]
59 | return []
60 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/decorators/time_limiter_succeeder.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/category_decorator.svg")
3 | class_name TimeLimiterSucceederDecorator extends Decorator
4 | ## The Time Limit Decorator will give its `RUNNING` child a set amount of time to finish
5 | ## before interrupting it and return a `SUCCESS` status code.
6 | ## The timer resets the next time that a child is not `RUNNING`
7 |
8 | @export var wait_time: = 0.0
9 |
10 | @onready var cache_key = 'time_limiter_%s' % self.get_instance_id()
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | if not get_child_count() == 1:
15 | return FAILURE
16 |
17 | var child = self.get_child(0)
18 | var time_left = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
19 |
20 | if time_left < wait_time:
21 | time_left += get_physics_process_delta_time()
22 | blackboard.set_value(cache_key, time_left, str(actor.get_instance_id()))
23 | var response = child.tick(actor, blackboard)
24 | if can_send_message(blackboard):
25 | BeehaveDebuggerMessages.process_tick(child.get_instance_id(), response)
26 |
27 | if child is ConditionLeaf:
28 | blackboard.set_value("last_condition", child, str(actor.get_instance_id()))
29 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
30 |
31 | if response == RUNNING:
32 | running_child = child
33 | if child is ActionLeaf:
34 | blackboard.set_value("running_action", child, str(actor.get_instance_id()))
35 | else:
36 | child.after_run(actor, blackboard)
37 | return response
38 | else:
39 | interrupt(actor, blackboard)
40 | child.after_run(actor, blackboard)
41 | return SUCCESS
42 |
43 |
44 | func before_run(actor: Node, blackboard: Blackboard) -> void:
45 | blackboard.set_value(cache_key, 0.0, str(actor.get_instance_id()))
46 | if get_child_count() > 0:
47 | get_child(0).before_run(actor, blackboard)
48 |
49 |
50 | func get_class_name() -> Array[StringName]:
51 | var classes := super()
52 | classes.push_back(&"TimeLimiterDecorator")
53 | return classes
54 |
55 |
56 | func _get_configuration_warnings() -> PackedStringArray:
57 | if not get_child_count() == 1:
58 | return ["Requires exactly one child node"]
59 | return []
60 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/leaves/blackboard_compare.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BlackboardCompareCondition extends ConditionLeaf
3 |
4 | ## Compares two values using the specified comparison operator.
5 | ## Returns [code]FAILURE[/code] if any of the expression fails or the
6 | ## comparison operation returns [code]false[/code], otherwise it returns [code]SUCCESS[/code].
7 |
8 | enum Operators {
9 | EQUAL,
10 | NOT_EQUAL,
11 | GREATER,
12 | LESS,
13 | GREATER_EQUAL,
14 | LESS_EQUAL,
15 | }
16 |
17 |
18 | ## Expression represetning left operand.
19 | ## This value can be any valid GDScript expression.
20 | ## In order to use the existing blackboard keys for comparison,
21 | ## use get_value("key_name") e.g. get_value("direction").length()
22 | @export_placeholder(EXPRESSION_PLACEHOLDER) var left_operand: String = ""
23 | ## Comparison operator.
24 | @export_enum("==", "!=", ">", "<", ">=", "<=") var operator: int = 0
25 | ## Expression represetning right operand.
26 | ## This value can be any valid GDScript expression.
27 | ## In order to use the existing blackboard keys for comparison,
28 | ## use get_value("key_name") e.g. get_value("direction").length()
29 | @export_placeholder(EXPRESSION_PLACEHOLDER) var right_operand: String = ""
30 |
31 |
32 | @onready var _left_expression: Expression = _parse_expression(left_operand)
33 | @onready var _right_expression: Expression = _parse_expression(right_operand)
34 |
35 |
36 | func tick(actor: Node, blackboard: Blackboard) -> int:
37 | var left: Variant = _left_expression.execute([], blackboard)
38 |
39 | if _left_expression.has_execute_failed():
40 | return FAILURE
41 |
42 | var right: Variant = _right_expression.execute([], blackboard)
43 |
44 | if _right_expression.has_execute_failed():
45 | return FAILURE
46 |
47 | var result: bool = false
48 |
49 | match operator:
50 | Operators.EQUAL: result = left == right
51 | Operators.NOT_EQUAL: result = left != right
52 | Operators.GREATER: result = left > right
53 | Operators.LESS: result = left < right
54 | Operators.GREATER_EQUAL: result = left >= right
55 | Operators.LESS_EQUAL: result = left <= right
56 |
57 | return SUCCESS if result else FAILURE
58 |
59 |
60 | func _get_expression_sources() -> Array[String]:
61 | return [left_operand, right_operand]
62 |
--------------------------------------------------------------------------------
/addons/beehave/icons/sequence.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/selector.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/selector.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/selector.svg")
3 | class_name SelectorComposite extends Composite
4 | ## Selector nodes will attempt to execute each of its children until one of
5 | ## them return `SUCCESS`. If all children return `FAILURE`, this node will also
6 | ## return `FAILURE`.
7 | ## If a child returns `RUNNING` it will tick again.
8 |
9 | var last_execution_index: int = 0
10 |
11 |
12 | func tick(actor: Node, blackboard: Blackboard) -> int:
13 | for c in get_children():
14 | if c.get_index() < last_execution_index:
15 | continue
16 |
17 | if c != running_child:
18 | c.before_run(actor, blackboard)
19 |
20 | var response = c.tick(actor, blackboard)
21 | if can_send_message(blackboard):
22 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
23 |
24 | if c is ConditionLeaf:
25 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
26 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
27 |
28 | match response:
29 | SUCCESS:
30 | _cleanup_running_task(c, actor, blackboard)
31 | c.after_run(actor, blackboard)
32 | return SUCCESS
33 | FAILURE:
34 | _cleanup_running_task(c, actor, blackboard)
35 | last_execution_index += 1
36 | c.after_run(actor, blackboard)
37 | RUNNING:
38 | running_child = c
39 | if c is ActionLeaf:
40 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
41 | return RUNNING
42 |
43 | return FAILURE
44 |
45 |
46 | func after_run(actor: Node, blackboard: Blackboard) -> void:
47 | last_execution_index = 0
48 | super(actor, blackboard)
49 |
50 |
51 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
52 | last_execution_index = 0
53 | super(actor, blackboard)
54 |
55 |
56 | ## Changes `running_action` and `running_child` after the node finishes executing.
57 | func _cleanup_running_task(finished_action: Node, actor: Node, blackboard: Blackboard):
58 | var blackboard_name = str(actor.get_instance_id())
59 | if finished_action == running_child:
60 | running_child = null
61 | if finished_action == blackboard.get_value("running_action", null, blackboard_name):
62 | blackboard.set_value("running_action", null, blackboard_name)
63 |
64 |
65 | func get_class_name() -> Array[StringName]:
66 | var classes := super()
67 | classes.push_back(&"SelectorComposite")
68 | return classes
69 |
--------------------------------------------------------------------------------
/addons/beehave/icons/condition.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/selector_random.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/selector_random.svg")
3 | class_name SelectorRandomComposite extends RandomizedComposite
4 | ## This node will attempt to execute all of its children just like a
5 | ## [code]SelectorStar[/code] would, with the exception that the children
6 | ## will be executed in a random order.
7 |
8 | ## A shuffled list of the children that will be executed in reverse order.
9 | var _children_bag: Array[Node] = []
10 | var c: Node
11 |
12 | func _ready() -> void:
13 | super()
14 | if random_seed == 0:
15 | randomize()
16 |
17 |
18 | func tick(actor: Node, blackboard: Blackboard) -> int:
19 | if _children_bag.is_empty():
20 | _reset()
21 |
22 | # We need to traverse the array in reverse since we will be manipulating it.
23 | for i in _get_reversed_indexes():
24 | c = _children_bag[i]
25 |
26 | if c != running_child:
27 | c.before_run(actor, blackboard)
28 |
29 | var response = c.tick(actor, blackboard)
30 | if can_send_message(blackboard):
31 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
32 |
33 | if c is ConditionLeaf:
34 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
35 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
36 |
37 | match response:
38 | SUCCESS:
39 | _children_bag.erase(c)
40 | c.after_run(actor, blackboard)
41 | return SUCCESS
42 | FAILURE:
43 | _children_bag.erase(c)
44 | c.after_run(actor, blackboard)
45 | RUNNING:
46 | running_child = c
47 | if c is ActionLeaf:
48 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
49 | return RUNNING
50 |
51 | return FAILURE
52 |
53 |
54 | func after_run(actor: Node, blackboard: Blackboard) -> void:
55 | _reset()
56 | super(actor, blackboard)
57 |
58 |
59 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
60 | _reset()
61 | super(actor, blackboard)
62 |
63 |
64 | func _get_reversed_indexes() -> Array[int]:
65 | var reversed: Array[int]
66 | reversed.assign(range(_children_bag.size()))
67 | reversed.reverse()
68 | return reversed
69 |
70 |
71 | func _reset() -> void:
72 | var new_order = get_shuffled_children()
73 | _children_bag = new_order.duplicate()
74 | _children_bag.reverse() # It needs to run the children in reverse order.
75 |
76 |
77 | func get_class_name() -> Array[StringName]:
78 | var classes := super()
79 | classes.push_back(&"SelectorRandomComposite")
80 | return classes
81 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/success_sequence.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/blackboard.svg")
3 | class_name ExecuteAllComposite extends Composite
4 | ## Sequence nodes will attempt to execute all of its children and report
5 | ## `SUCCESS` in case all of the children report a `SUCCESS` status code.
6 | ## If at least one child reports a `FAILURE` status code, this node will also
7 | ## return `FAILURE` and restart.
8 | ## In case a child returns `RUNNING` this node will tick again.
9 |
10 | var successful_index: int = 0
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | for c in get_children():
15 |
16 | if c.get_index() < successful_index:
17 | continue
18 |
19 | if c != running_child:
20 | c.before_run(actor, blackboard)
21 |
22 | var response = c.tick(actor, blackboard)
23 | if can_send_message(blackboard):
24 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
25 |
26 | if c is ConditionLeaf:
27 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
28 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
29 |
30 | match response:
31 | SUCCESS:
32 | _cleanup_running_task(c, actor, blackboard)
33 | successful_index += 1
34 | c.after_run(actor, blackboard)
35 | FAILURE:
36 | _cleanup_running_task(c, actor, blackboard)
37 | successful_index += 1
38 | c.after_run(actor, blackboard)
39 | RUNNING:
40 | if c != running_child:
41 | if running_child != null:
42 | running_child.interrupt(actor, blackboard)
43 | running_child = c
44 | if c is ActionLeaf:
45 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
46 | return RUNNING
47 |
48 | _reset()
49 | return SUCCESS
50 |
51 |
52 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
53 | _reset()
54 | super(actor, blackboard)
55 |
56 |
57 | func _reset() -> void:
58 | successful_index = 0
59 |
60 |
61 | ## Changes `running_action` and `running_child` after the node finishes executing.
62 | func _cleanup_running_task(finished_action: Node, actor: Node, blackboard: Blackboard):
63 | var blackboard_name = str(actor.get_instance_id())
64 | if finished_action == running_child:
65 | running_child = null
66 | if finished_action == blackboard.get_value("running_action", null, blackboard_name):
67 | blackboard.set_value("running_action", null, blackboard_name)
68 |
69 |
70 | func get_class_name() -> Array[StringName]:
71 | var classes := super()
72 | classes.push_back(&"SequenceComposite")
73 | return classes
74 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/sequence.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/sequence.svg")
3 | class_name SequenceComposite extends Composite
4 | ## Sequence nodes will attempt to execute all of its children and report
5 | ## `SUCCESS` in case all of the children report a `SUCCESS` status code.
6 | ## If at least one child reports a `FAILURE` status code, this node will also
7 | ## return `FAILURE` and restart.
8 | ## In case a child returns `RUNNING` this node will tick again.
9 |
10 | var successful_index: int = 0
11 |
12 |
13 | func tick(actor: Node, blackboard: Blackboard) -> int:
14 | for c in get_children():
15 |
16 | if c.get_index() < successful_index:
17 | continue
18 |
19 | if c != running_child:
20 | c.before_run(actor, blackboard)
21 |
22 | var response = c.tick(actor, blackboard)
23 | if can_send_message(blackboard):
24 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
25 |
26 | if c is ConditionLeaf:
27 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
28 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
29 |
30 | match response:
31 | SUCCESS:
32 | _cleanup_running_task(c, actor, blackboard)
33 | successful_index += 1
34 | c.after_run(actor, blackboard)
35 | FAILURE:
36 | _cleanup_running_task(c, actor, blackboard)
37 | # Interrupt any child that was RUNNING before.
38 | interrupt(actor, blackboard)
39 | c.after_run(actor, blackboard)
40 | return FAILURE
41 | RUNNING:
42 | if c != running_child:
43 | if running_child != null:
44 | running_child.interrupt(actor, blackboard)
45 | running_child = c
46 | if c is ActionLeaf:
47 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
48 | return RUNNING
49 |
50 | _reset()
51 | return SUCCESS
52 |
53 |
54 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
55 | _reset()
56 | super(actor, blackboard)
57 |
58 |
59 | func _reset() -> void:
60 | successful_index = 0
61 |
62 |
63 | ## Changes `running_action` and `running_child` after the node finishes executing.
64 | func _cleanup_running_task(finished_action: Node, actor: Node, blackboard: Blackboard):
65 | var blackboard_name = str(actor.get_instance_id())
66 | if finished_action == running_child:
67 | running_child = null
68 | if finished_action == blackboard.get_value("running_action", null, blackboard_name):
69 | blackboard.set_value("running_action", null, blackboard_name)
70 |
71 |
72 | func get_class_name() -> Array[StringName]:
73 | var classes := super()
74 | classes.push_back(&"SequenceComposite")
75 | return classes
76 |
--------------------------------------------------------------------------------
/addons/beehave/icons/repeater.svg:
--------------------------------------------------------------------------------
1 |
2 |
41 |
--------------------------------------------------------------------------------
/addons/beehave/icons/action.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/nodes/composites/sequence_random.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../icons/sequence_random.svg")
3 | class_name SequenceRandomComposite extends RandomizedComposite
4 | ## This node will attempt to execute all of its children just like a
5 | ## [code]SequenceStar[/code] would, with the exception that the children
6 | ## will be executed in a random order.
7 |
8 | # Emitted whenever the children are shuffled.
9 | signal reset(new_order: Array[Node])
10 |
11 | ## Whether the sequence should start where it left off after a previous failure.
12 | @export var resume_on_failure: bool = false
13 | ## Whether the sequence should start where it left off after a previous interruption.
14 | @export var resume_on_interrupt: bool = false
15 |
16 | ## A shuffled list of the children that will be executed in reverse order.
17 | var _children_bag: Array[Node] = []
18 | var c: Node
19 |
20 |
21 | func _ready() -> void:
22 | super()
23 | if random_seed == 0:
24 | randomize()
25 |
26 |
27 | func tick(actor: Node, blackboard: Blackboard) -> int:
28 | if _children_bag.is_empty():
29 | _reset()
30 |
31 | # We need to traverse the array in reverse since we will be manipulating it.
32 | for i in _get_reversed_indexes():
33 | c = _children_bag[i]
34 |
35 | if c != running_child:
36 | c.before_run(actor, blackboard)
37 |
38 | var response = c.tick(actor, blackboard)
39 | if can_send_message(blackboard):
40 | BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
41 |
42 | if c is ConditionLeaf:
43 | blackboard.set_value("last_condition", c, str(actor.get_instance_id()))
44 | blackboard.set_value("last_condition_status", response, str(actor.get_instance_id()))
45 |
46 | match response:
47 | SUCCESS:
48 | _children_bag.erase(c)
49 | c.after_run(actor, blackboard)
50 | FAILURE:
51 | _children_bag.erase(c)
52 | # Interrupt any child that was RUNNING before
53 | # but do not reset!
54 | super.interrupt(actor, blackboard)
55 | c.after_run(actor, blackboard)
56 | return FAILURE
57 | RUNNING:
58 | running_child = c
59 | if c is ActionLeaf:
60 | blackboard.set_value("running_action", c, str(actor.get_instance_id()))
61 | return RUNNING
62 |
63 | return SUCCESS
64 |
65 |
66 | func after_run(actor: Node, blackboard: Blackboard) -> void:
67 | if not resume_on_failure:
68 | _reset()
69 | super(actor, blackboard)
70 |
71 |
72 | func interrupt(actor: Node, blackboard: Blackboard) -> void:
73 | if not resume_on_interrupt:
74 | _reset()
75 | super(actor, blackboard)
76 |
77 |
78 | func _get_reversed_indexes() -> Array[int]:
79 | var reversed: Array[int]
80 | reversed.assign(range(_children_bag.size()))
81 | reversed.reverse()
82 | return reversed
83 |
84 |
85 | func _reset() -> void:
86 | var new_order = get_shuffled_children()
87 | _children_bag = new_order.duplicate()
88 | _children_bag.reverse() # It needs to run the children in reverse order.
89 | reset.emit(new_order)
90 |
91 |
92 | func get_class_name() -> Array[StringName]:
93 | var classes := super()
94 | classes.push_back(&"SequenceRandomComposite")
95 | return classes
96 |
--------------------------------------------------------------------------------
/scenes/demo-level.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=13 format=3 uid="uid://bb4fafxi72ab5"]
2 |
3 | [ext_resource type="NavigationMesh" uid="uid://bfl2doe8xpotn" path="res://assets/nav-mesh.tres" id="2_af563"]
4 | [ext_resource type="PackedScene" uid="uid://d31p1dmc66x0f" path="res://assets/models/level.glb" id="3_ncwu5"]
5 | [ext_resource type="Material" uid="uid://bxsrpokc2g0mm" path="res://assets/materials/grass-32.tres" id="4_yxhyh"]
6 | [ext_resource type="Material" uid="uid://bd8xo0abeyq1j" path="res://assets/materials/rock-32.tres" id="5_v5h6b"]
7 | [ext_resource type="Material" uid="uid://cktpnfxywi6l3" path="res://assets/materials/bg_trees.tres" id="6_k1kkm"]
8 | [ext_resource type="Material" uid="uid://bqxdxu7vu0mg4" path="res://assets/materials/grass-rock-edge.tres" id="7_s1bdv"]
9 | [ext_resource type="Material" uid="uid://f2kijod18ox7" path="res://assets/materials/bg_trees-dark.tres" id="8_3ljd5"]
10 | [ext_resource type="Material" uid="uid://deivqr8yqilku" path="res://assets/materials/vines.tres" id="9_kwn3l"]
11 | [ext_resource type="Material" uid="uid://bk0rqjdcmjtt0" path="res://assets/materials/fence.tres" id="10_rbyn3"]
12 | [ext_resource type="Environment" uid="uid://c4cxd4w3vogf" path="res://assets/default_env.tres" id="11_qpf0a"]
13 | [ext_resource type="PackedScene" uid="uid://cfedvat670073" path="res://scenes/player.tscn" id="12_vl16i"]
14 | [ext_resource type="PackedScene" uid="uid://bmpt13tisf6mq" path="res://scenes/slime_agent.tscn" id="13_qcani"]
15 |
16 | [node name="Test-level-1" type="Node3D"]
17 |
18 | [node name="NavigationRegion3D" type="NavigationRegion3D" parent="."]
19 | navigation_mesh = ExtResource("2_af563")
20 | use_edge_connections = false
21 |
22 | [node name="level" parent="NavigationRegion3D" instance=ExtResource("3_ncwu5")]
23 |
24 | [node name="main 1" parent="NavigationRegion3D/level" index="0"]
25 | surface_material_override/0 = ExtResource("4_yxhyh")
26 | surface_material_override/1 = ExtResource("5_v5h6b")
27 | surface_material_override/2 = ExtResource("6_k1kkm")
28 | surface_material_override/3 = ExtResource("7_s1bdv")
29 | surface_material_override/4 = ExtResource("8_3ljd5")
30 |
31 | [node name="edge-vines" parent="NavigationRegion3D/level" index="1"]
32 | surface_material_override/0 = ExtResource("9_kwn3l")
33 |
34 | [node name="fence-1" parent="NavigationRegion3D/level" index="2"]
35 | surface_material_override/0 = ExtResource("10_rbyn3")
36 |
37 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
38 | environment = ExtResource("11_qpf0a")
39 |
40 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
41 | transform = Transform3D(-0.420745, -0.875414, 0.237957, 0.138838, 0.197077, 0.970508, -0.896492, 0.441374, 0.0386212, 0.797561, 4.08256, -0.210869)
42 | light_energy = 0.597
43 | light_indirect_energy = 0.866
44 |
45 | [node name="Player" parent="." instance=ExtResource("12_vl16i")]
46 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -29, 0, -54)
47 |
48 | [node name="Agents" type="Node3D" parent="."]
49 |
50 | [node name="Slime-agent" parent="Agents" instance=ExtResource("13_qcani")]
51 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.23021, 3.80584e-05, -50.203)
52 |
53 | [editable path="NavigationRegion3D/level"]
54 |
--------------------------------------------------------------------------------
/addons/beehave/debug/debugger.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorDebuggerPlugin
3 |
4 | const DebuggerTab := preload("debugger_tab.gd")
5 | const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
6 |
7 | var debugger_tab := DebuggerTab.new()
8 | var floating_window: Window
9 | var session: EditorDebuggerSession
10 |
11 |
12 | func _has_capture(prefix: String) -> bool:
13 | return prefix == "beehave"
14 |
15 |
16 | func _capture(message: String, data: Array, session_id: int) -> bool:
17 | # in case the behavior tree has invalid setup this might be null
18 | if debugger_tab == null:
19 | return false
20 |
21 | if message == "beehave:register_tree":
22 | debugger_tab.register_tree(data[0])
23 | return true
24 | if message == "beehave:unregister_tree":
25 | debugger_tab.unregister_tree(data[0])
26 | return true
27 | if message == "beehave:process_tick":
28 | debugger_tab.graph.process_tick(data[0], data[1])
29 | return true
30 | if message == "beehave:process_begin":
31 | debugger_tab.graph.process_begin(data[0])
32 | return true
33 | if message == "beehave:process_end":
34 | debugger_tab.graph.process_end(data[0])
35 | return true
36 | return false
37 |
38 |
39 | func _setup_session(session_id: int) -> void:
40 | session = get_session(session_id)
41 | session.started.connect(debugger_tab.start)
42 | session.stopped.connect(debugger_tab.stop)
43 |
44 | debugger_tab.name = "🐝 Beehave"
45 | debugger_tab.make_floating.connect(_on_make_floating)
46 | debugger_tab.session = session
47 | session.add_session_tab(debugger_tab)
48 |
49 |
50 | func _on_make_floating() -> void:
51 | var plugin := BeehaveUtils.get_plugin()
52 | if not plugin:
53 | return
54 | if floating_window:
55 | _on_window_close_requested()
56 | return
57 |
58 | var border_size := Vector2(4, 4) * BeehaveUtils.get_editor_scale()
59 | var editor_interface: EditorInterface = plugin.get_editor_interface()
60 | var editor_main_screen = editor_interface.get_editor_main_screen()
61 | debugger_tab.get_parent().remove_child(debugger_tab)
62 |
63 | floating_window = Window.new()
64 |
65 | var panel := Panel.new()
66 | panel.add_theme_stylebox_override("panel", editor_interface.get_base_control().get_theme_stylebox("PanelForeground", "EditorStyles"))
67 | panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
68 | floating_window.add_child(panel)
69 |
70 | var margin := MarginContainer.new()
71 | margin.add_child(debugger_tab)
72 | margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
73 | margin.add_theme_constant_override("margin_right", border_size.x)
74 | margin.add_theme_constant_override("margin_left", border_size.x)
75 | margin.add_theme_constant_override("margin_top", border_size.y)
76 | margin.add_theme_constant_override("margin_bottom", border_size.y)
77 | panel.add_child(margin)
78 |
79 | floating_window.title = "🐝 Beehave"
80 | floating_window.wrap_controls = true
81 | floating_window.min_size = Vector2i(600, 350)
82 | floating_window.size = debugger_tab.size
83 | floating_window.position = editor_main_screen.global_position
84 | floating_window.transient = true
85 | floating_window.close_requested.connect(_on_window_close_requested)
86 | editor_interface.get_base_control().add_child(floating_window)
87 |
88 |
89 | func _on_window_close_requested() -> void:
90 | debugger_tab.get_parent().remove_child(debugger_tab)
91 | session.add_session_tab(debugger_tab)
92 | floating_window.queue_free()
93 | floating_window = null
94 |
--------------------------------------------------------------------------------
/addons/beehave/icons/selector_reactive.svg:
--------------------------------------------------------------------------------
1 |
2 |
46 |
--------------------------------------------------------------------------------
/addons/beehave/debug/debugger_tab.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name BeehaveDebuggerTab extends PanelContainer
3 |
4 |
5 | const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
6 |
7 |
8 | signal make_floating()
9 |
10 | const BeehaveGraphEdit := preload("graph_edit.gd")
11 | const TREE_ICON := preload("../icons/tree.svg")
12 |
13 | var container: HSplitContainer
14 | var item_list: ItemList
15 | var graph: BeehaveGraphEdit
16 | var message: Label
17 |
18 | var active_trees: Dictionary
19 | var active_tree_id: int = -1
20 | var session: EditorDebuggerSession
21 |
22 |
23 | func _ready() -> void:
24 | container = HSplitContainer.new()
25 | add_child(container)
26 |
27 | item_list = ItemList.new()
28 | item_list.custom_minimum_size = Vector2(200, 0)
29 | item_list.item_selected.connect(_on_item_selected)
30 | container.add_child(item_list)
31 |
32 | graph = BeehaveGraphEdit.new(BeehaveUtils.get_frames())
33 | container.add_child(graph)
34 |
35 | message = Label.new()
36 | message.text = "Run Project for debugging"
37 | message.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
38 | message.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
39 | message.set_anchors_preset(Control.PRESET_CENTER)
40 | add_child(message)
41 |
42 | var button := Button.new()
43 | button.flat = true
44 | button.name = "MakeFloatingButton"
45 | button.icon = get_theme_icon(&"ExternalLink", &"EditorIcons")
46 | button.pressed.connect(func(): make_floating.emit())
47 | button.tooltip_text = "Make floating"
48 | button.focus_mode = Control.FOCUS_NONE
49 | graph.get_menu_container().add_child(button)
50 |
51 | var toggle_button := Button.new()
52 | toggle_button.flat = true
53 | toggle_button.name = "TogglePanelButton"
54 | toggle_button.icon = get_theme_icon(&"Back", &"EditorIcons")
55 | toggle_button.pressed.connect(_on_toggle_button_pressed.bind(toggle_button))
56 | toggle_button.tooltip_text = "Toggle Panel"
57 | toggle_button.focus_mode = Control.FOCUS_NONE
58 | graph.get_menu_container().add_child(toggle_button)
59 | graph.get_menu_container().move_child(toggle_button, 0)
60 |
61 | stop()
62 | visibility_changed.connect(_on_visibility_changed)
63 |
64 |
65 | func start() -> void:
66 | container.visible = true
67 | message.visible = false
68 |
69 |
70 | func stop() -> void:
71 | container.visible = false
72 | message.visible = true
73 |
74 | active_trees.clear()
75 | item_list.clear()
76 | graph.beehave_tree = {}
77 |
78 |
79 | func register_tree(data: Dictionary) -> void:
80 | var idx := item_list.add_item(data.name, TREE_ICON)
81 | item_list.set_item_tooltip(idx, data.path)
82 | item_list.set_item_metadata(idx, data.id)
83 | active_trees[data.id] = data
84 |
85 |
86 | func unregister_tree(instance_id: int) -> void:
87 | var id := str(instance_id)
88 | for i in item_list.item_count:
89 | if item_list.get_item_metadata(i) == id:
90 | item_list.remove_item(i)
91 | break
92 |
93 | active_trees.erase(id)
94 |
95 | if graph.beehave_tree.get("id", "") == id:
96 | graph.beehave_tree = {}
97 |
98 |
99 | func _on_toggle_button_pressed(toggle_button: Button) -> void:
100 | item_list.visible = !item_list.visible
101 | toggle_button.icon = get_theme_icon(&"Back" if item_list.visible else &"Forward", &"EditorIcons")
102 |
103 |
104 | func _on_item_selected(idx: int) -> void:
105 | var id: StringName = item_list.get_item_metadata(idx)
106 | graph.beehave_tree = active_trees.get(id, {})
107 |
108 | active_tree_id = id.to_int()
109 | if session != null:
110 | session.send_message("beehave:activate_tree", [active_tree_id])
111 |
112 |
113 | func _on_visibility_changed() -> void:
114 | if session != null:
115 | session.send_message("beehave:visibility_changed", [visible and is_visible_in_tree()])
116 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_bt.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------
/addons/beehave/icons/category_leaf.svg:
--------------------------------------------------------------------------------
1 |
2 |
39 |
--------------------------------------------------------------------------------