extends KinematicBody2D export var swim_length = 150 export var swim_cooldown = 1 var casual = false # True prevents restarting from beginning after dying var destination # The position the fish will move to _on_SwimTimer_timeout() var pellets_consumed = 0 # Tracks the number of clean pellets eaten var invincible = false # Used during cutscenes such as returning home, etc var poisoned = false # Used in Hazards/Poison/Poison.gd to determine if fish is dying of poison var poison_mutating = false # Used in poison mutation cutscene var poison_mutation = false # True when fish can eat and shoot poison pellets var dash_mutation = false var pellets = 0 # Tracks the number of poison pellets eaten but not shot yet var do_not_rotate = false # Used in Fork.tscn cutscene to stop fish from auto-rotating onready var mouth = $Positions/Mouth.position # Used for eating and shooting poison pellets onready var mouth_inhale = $Positions/MouthInhale.position # Used for eating poison pellets onready var tail = $Positions/Tail.position # Used for shooting poison pellets onready var house = get_node("/root/Tank/House") onready var house_eyes = get_node("/root/Tank/House/HouseEyes") onready var house_left = get_node("/root/Tank/House/HouseLeft") onready var house_right = get_node("/root/Tank/House/HouseRight") onready var house_left_entrance = get_node("/root/Tank/House/LeftEntrance") onready var house_right_entrance = get_node("/root/Tank/House/RightEntrance") func _ready(): $SwimTimer.wait_time = swim_cooldown $HungerTimer.start() func _on_SwimTimer_timeout() -> void: # Swim toward mouse if not invincible: var new_y = clamp(move_toward(position.y, get_global_mouse_position().y, swim_length), 110, 1040) #destination = Vector2(move_toward(position.x, get_global_mouse_position().x, swim_length), move_toward(position.y, get_global_mouse_position().y, swim_length)) destination = Vector2(move_toward(position.x, get_global_mouse_position().x, swim_length), new_y) $TweenSwim.interpolate_property(self, "position", position, destination, 1, Tween.TRANS_CUBIC, Tween.EASE_IN_OUT) $TweenSwim.start() else: if poison_mutating: destination.x = house_right_entrance.get_global_position().x destination.y = house_right_entrance.get_global_position().y + 100 func _process(delta: float) -> void: if destination and not do_not_rotate: var v if invincible: # Smoothly rotate fish to face destination v = destination - global_position else: # Smoothly rotate fish to face mouse v = get_global_mouse_position() - global_position var angle = v.angle() + deg2rad(270) # if global_position.x < get_global_mouse_position().x: # $AnimatedSprite.flip_v = false # else: # $AnimatedSprite.flip_v = true if rad2deg(angle) < 180 or rad2deg(angle) > 360: $AnimatedSprite.flip_v = true else: $AnimatedSprite.flip_v = false var rotation_speed = PI * 0.75 # PI = 180 degrees var angle_delta = rotation_speed * delta angle = lerp_angle(global_rotation, angle + 1.57, 1.0) angle = clamp(angle, global_rotation - angle_delta, global_rotation + angle_delta) global_rotation = angle $ThoughtBubble.global_rotation = 0 func fire_pellet() -> void: var velocity = 4 #pellets = 1 # This is just hax so we don't have to eat pellets first to fire them if pellets > 0: # But usually we require fish to eat pellets before he shoots them var poison_scene = load("res://Hazards/Poison/Poison.tscn") var poison = poison_scene.instance() poison.projectile = true # This will prevent the fish from auto-eating it the second it spawns get_parent().add_child(poison) # We add this projectile to the /tank/ so they don't move with the fish poison.position = $Positions/Tail.get_global_position() # 'position' returns the local position, but we need where it's at in relation to the tank poison.apply_central_impulse(velocity * ($Positions/Tail.get_global_position() - $Positions/Mouth.get_global_position())) pellets -= 1 func dash() -> void: $SwimTimer.stop() if invincible and get_parent().phase == get_parent().Phase.KNIFE and get_node_or_null("/root/Tank/Fork"): get_node("/root/Tank/FishFork").visible = false destination = Vector2(position.x - (swim_length*3.5), position.y) invincible = false if get_node_or_null("/root/Tank/Fork"): get_node("/root/Tank/Fork").retract() get_parent().get_node("SurviveTimer").start() do_not_rotate = false else: var new_y = clamp(move_toward(position.y, get_global_mouse_position().y, swim_length*3), 110, 1040) destination = Vector2(move_toward(position.x, get_global_mouse_position().x, swim_length*3), new_y) $TweenSwim.interpolate_property(self, "position", position, destination, 1, Tween.TRANS_CUBIC, Tween.EASE_IN_OUT) $TweenSwim.start() $SwimTimer.start() func go_inside() -> void: invincible = true destination = house_left_entrance.get_global_position() $TweenSwim.stop_all() $TweenHome.interpolate_property(self, "position", position, destination, 1.5, Tween.TRANS_SINE, Tween.EASE_OUT, 1.5) $TweenHome.start() yield($TweenHome, "tween_completed") house_right.z_index = 1 destination = house_right_entrance.get_global_position() $TweenInside.interpolate_property(self, "position", position, destination, 1.5, Tween.TRANS_SINE, Tween.EASE_OUT) $TweenInside.start() yield($TweenInside, "tween_completed") visible = false house_eyes.visible = true $TweenSleep.interpolate_property(get_parent(), "modulate", get_parent().modulate, Color(0,0,0,1), 2, Tween.TRANS_LINEAR, Tween.EASE_IN) $TweenSleep.start() yield($TweenSleep, "tween_completed") func reset_hunger() -> void: if get_parent().phase == get_parent().Phase.CLEAN: $HungerTimer.start() pellets_consumed += 1 if pellets_consumed > 5: get_parent().blackout() func belly_up(_cause: String) -> void: print("You died on account of " + _cause + ". :(") # flip fish upside-down # modulate tank red if not casual: get_parent().phase = get_parent().Phase.START get_tree().reload_current_scene() func _on_HungerTimer_timeout() -> void: if get_parent().phase == get_parent().Phase.CLEAN: belly_up("starvation") else: $HungerTimer.stop() func _on_ThoughtTimer_timeout() -> void: $ThoughtBubble.visible = false