├── 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 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /addons/beehave/icons/blackboard.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 34 | 38 | 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 | 14 | 16 | 34 | 39 | 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 | [![tutorial-thumbnail](https://img.youtube.com/vi/AUfzET91m0s/0.jpg)](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 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /addons/beehave/icons/tree.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /addons/beehave/icons/selector.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 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 | 14 | 16 | 35 | 36 | 40 | 41 | -------------------------------------------------------------------------------- /addons/beehave/icons/action.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 34 | 38 | 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 | 13 | 15 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /addons/beehave/icons/category_leaf.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 34 | 38 | 39 | --------------------------------------------------------------------------------