extends Node3D @export var grapple_distance: float = 10 @export var grapple_speed: float = 10 @export var fire_distance: float = 100 @export var fire_rate: float = 0.1 enum State { NO_GRAPPLE, FREE, GRAPPLING } var current_state: State = State.FREE var grapple_target: Vector3 = Vector3.ZERO var bullet_inst = preload("res://prefabs/bullet.tscn") var ammo: int = 100 var fire_timer: float = fire_rate var interactable: Node3D = null # Called when the node enters the scene tree for the first time. func _ready() -> void: pass # Replace with function body. func do_grapple() -> void: if Input.is_action_just_pressed("attack") and current_state == State.FREE: var space_state = get_world_3d().direct_space_state var starting_pos = global_position var ending_pos = starting_pos + grapple_distance * -global_transform.basis.z var query = PhysicsRayQueryParameters3D.create(starting_pos, ending_pos) query.collision_mask = 0x2 var result = space_state.intersect_ray(query) if result: grapple_target = result.position + global_transform.basis.z current_state = State.GRAPPLING if Input.is_action_just_released("attack") and current_state == State.GRAPPLING: current_state = State.FREE grapple_target = Vector3.ZERO #print("State ", current_state, " ", grapple_target) if current_state == State.GRAPPLING: var dir_to_target = (grapple_target - global_position).normalized() get_parent().local_velocity = dir_to_target * grapple_speed func fire_weapon(delta: float) -> void: if Input.is_action_pressed("attack") and ammo > 0 and fire_timer >= fire_rate: var space_state = get_world_3d().direct_space_state var starting_pos = global_position var ending_pos = starting_pos + fire_distance * -global_transform.basis.z var query = PhysicsRayQueryParameters3D.create(starting_pos, ending_pos) var result = space_state.intersect_ray(query) var end = ending_pos if result: print("Hit! ") if result.collider.has_method("on_hit"): result.collider.on_hit(result.position) end = result.position else: print("Miss") var bullet: Node3D = bullet_inst.instantiate() bullet.position = starting_pos bullet.target = end get_tree().get_root().add_child(bullet) var up = Vector3.UP if abs(global_transform.basis.z.y) > 0.99: up = Vector3(0, 0, 1) bullet.look_at(end, up) ammo -= 1 print("Ammo: ", ammo) fire_timer = 0 else: fire_timer += delta func do_interact() -> void: if Input.is_action_just_pressed("interact") and interactable != null: if interactable.has_method("get_contents"): var contents = interactable.get_contents() if contents > 0: ammo += contents print("Got ", contents, " ammo!") else: print("Empty container") func _physics_process(delta: float) -> void: do_grapple() do_interact() fire_weapon(delta) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta: float) -> void: pass func _on_interactable_enter(body: Node3D) -> void: interactable = body print("Got interactable") func _on_interactable_exit(body: Node3D) -> void: if interactable == body: interactable = null