Stamina (variable) value drain function goes erratic when hitting clamp limits

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By SnapCracklins

I am making a 2D horror game where you move right to left and am using a clamp function to avoid having to make simple collision for each map. I have two concurrent state machines handling player states (idle, walk, run) and stamina meter states (empty, charging, full with a slower recovery when emptying). All my scripts are working and the debugger’s not throwing any errors but for some reason when i hit my clamp limits when running, the variable for stamina starts doing strange things (going back up, not recharging fully, etc). Any help appreciated.

extends KinematicBody2D


const spdDefault = 150
const maxStamina = 300
export var speed = 150
export var runSpeed = 300
export var stamina = 300
export var burnRate = 2
export var chargeRate = 1
export var breatherTime = 2
export var deepBreath = 5
export var marg = 50
var direction = Vector2.ZERO
onready var sprite = $AnimatedSprite
var screen_size

enum STATE {IDLE, WALKING, RUNNING}
enum CHARGESTATE {EMPTY, CHARGING, FULL}
var playerState
var staminaState


func _ready():
	stamina = maxStamina
	playerState = STATE.IDLE
	staminaState = CHARGESTATE.FULL
	screen_size = get_viewport_rect().size


func _input(_event):
	if Input.is_action_pressed("ui_left") or Input.is_action_pressed("ui_right"):
		playerState = STATE.WALKING
		if Input.is_action_pressed("run") and staminaState != CHARGESTATE.EMPTY:
			playerState = STATE.RUNNING
			if staminaState == CHARGESTATE.EMPTY:
				playerState = STATE.WALKING
	else:
		playerState = STATE.IDLE
	
	if Input.is_action_just_released("run"):
		playerState = STATE.WALKING
	
	if Input.is_action_just_pressed("debug"):
		debugCommand()


func _process(delta):		
	match playerState:
		STATE.IDLE:
			sprite.play('idle')
		STATE.WALKING:
			walking(delta)
			speed = spdDefault
		STATE.RUNNING:
			running(delta)
	
	match staminaState:
		CHARGESTATE.EMPTY:
			recharging()
		CHARGESTATE.CHARGING:
			idle_charging()
		CHARGESTATE.FULL:
			pass	

	stamDebug()


func walking(delta):
	direction.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
	anim_controller()
	
	if direction.x == 0:
		playerState = STATE.IDLE
		
	var movement = direction * speed * delta
	move_and_collide(movement)
	
	var x_limit_l = (0 - ((screen_size.x/2)-marg))
	var x_limit_r = ((screen_size.x/2)-marg)
	position.x = clamp(position.x, x_limit_l, x_limit_r)


func running(delta):
		walking(delta)
		speed = runSpeed
		while stamina > 0 and staminaState != CHARGESTATE.EMPTY and Input.is_action_pressed("run"):
			stamina = stamina-burnRate
			var burn = Timer.new()
			add_child(burn)
			burn.set_wait_time(burnRate)
			burn.start()
			yield(burn,"timeout")
			if stamina < 1:
				playerState = STATE.WALKING
				break
		


func stamDebug():
	match stamina:
		maxStamina:
			staminaState = CHARGESTATE.FULL
		0:
			staminaState = CHARGESTATE.EMPTY
			
	if stamina != maxStamina and staminaState != CHARGESTATE.EMPTY:
		staminaState = CHARGESTATE.CHARGING
	
	if stamina >= maxStamina:
		stamina = maxStamina
	if stamina < 1:
		stamina = 0

	

func anim_controller():
	match playerState:
		STATE.WALKING:
			sprite.play('walk')
		STATE.RUNNING:
			sprite.play('run')
		STATE.IDLE:
			sprite.play('idle')

	
	if direction.x < 0:
		sprite.flip_h = true
	if direction.x > 0:
		sprite.flip_h = false


func recharging():
	var breather = Timer.new()
	add_child(breather)
	breather.set_wait_time(deepBreath)
	breather.start()
	yield(breather,"timeout")
	staminaUp()
	breather.queue_free()
	

func idle_charging():
	var idleT = Timer.new()
	add_child(idleT)
	idleT.set_wait_time(breatherTime)
	idleT.start()
	yield(idleT,"timeout")
	staminaUp()
	idleT.queue_free()


func staminaUp():
	var sT = Timer.new()
	add_child(sT)
	sT.set_wait_time(chargeRate)
	while stamina < maxStamina:
		sT.start()
		stamina = stamina+chargeRate
		yield(sT,"timeout")
		if stamina >= maxStamina:
			staminaState = CHARGESTATE.FULL
			sT.queue_free()
			break



func chargeCheck():
	if stamina >= maxStamina:
		staminaState = CHARGESTATE.FULL
		stamina = maxStamina
	if stamina != maxStamina:
		staminaState = CHARGESTATE.CHARGING
	if stamina < 1:
		stamina = 0
		staminaState = CHARGESTATE.EMPTY


func debugCommand():
	print("Player state: " + str(playerState))
	print("Charge state: " + str(staminaState))
	print("Stamina level: " + str(stamina))