2023-10-11 05:23:48 -04:00
|
|
|
class_name Fabio
|
2023-10-10 12:56:34 -04:00
|
|
|
extends CharacterBody2D
|
2023-10-10 10:22:04 -04:00
|
|
|
|
2023-10-11 11:34:37 -04:00
|
|
|
const FREE_EXP_RATE = 12
|
|
|
|
var freeXpStack = 0
|
|
|
|
|
2023-10-10 12:56:34 -04:00
|
|
|
@onready var levelup = [300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000]
|
|
|
|
|
|
|
|
@onready var is_facing_left: bool = false
|
|
|
|
@onready var is_attacking: bool = false
|
|
|
|
@onready var is_dying: bool = false
|
|
|
|
|
2023-10-10 17:13:43 -04:00
|
|
|
@export var level: int = 1
|
2023-10-11 12:05:50 -04:00
|
|
|
@export var hp: int = 125
|
|
|
|
@export var maxhp: int = 125
|
2023-10-10 13:34:26 -04:00
|
|
|
@export var maxvel: float = 2
|
2023-10-10 12:56:34 -04:00
|
|
|
@export var experience: int = 0
|
|
|
|
@export var state: String = "Idle"
|
2023-10-10 14:54:21 -04:00
|
|
|
@export var damage: int = 5
|
2023-10-10 17:03:49 -04:00
|
|
|
@export var maxAtks: int = 1
|
2023-10-11 09:36:16 -04:00
|
|
|
@export var maxcooldown: float = 0.75
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-11 00:03:05 -04:00
|
|
|
@onready var currentcooldown: float = 0
|
2023-10-10 22:31:20 -04:00
|
|
|
@onready var killcount: int = 0
|
2023-10-10 17:03:49 -04:00
|
|
|
@onready var currAtks: int = 0
|
2023-10-10 12:56:34 -04:00
|
|
|
@onready var anim: Node = get_node("Sprite")
|
|
|
|
@onready var cooldown: Node = get_node("Atk_cooldown")
|
|
|
|
@onready var lvlanim: Node = get_node("LvlUp")
|
2023-10-10 13:34:26 -04:00
|
|
|
@onready var lvlsnd: Node = get_node("LvlUpSnd")
|
2023-10-10 14:24:19 -04:00
|
|
|
@onready var hitanim: Node = get_node("Hit")
|
2023-10-10 22:45:27 -04:00
|
|
|
@onready var atk1l: Node = get_node("AttackArea/Attack1CollisionR")
|
|
|
|
@onready var atk1r: Node = get_node("AttackArea/Attack1CollisionL")
|
2023-10-10 22:31:20 -04:00
|
|
|
@onready var atk2l: Node = get_node("AttackArea/Attack2CollisionR")
|
|
|
|
@onready var atk2r: Node = get_node("AttackArea/Attack2CollisionL")
|
2023-10-10 10:22:04 -04:00
|
|
|
|
2023-10-10 17:20:44 -04:00
|
|
|
@onready var atkL: Node = atk1l
|
|
|
|
@onready var atkR: Node = atk1r
|
|
|
|
@onready var atk: String = "Attack"
|
2023-10-11 04:21:07 -04:00
|
|
|
@onready var is_dead: bool = false
|
2023-10-10 17:20:44 -04:00
|
|
|
|
2023-10-10 16:49:30 -04:00
|
|
|
@onready var list: Array = []
|
|
|
|
|
2023-10-11 05:23:48 -04:00
|
|
|
signal exp_gained(current, min, max, level)
|
|
|
|
signal hp_changed(current, max)
|
|
|
|
|
2023-10-10 16:49:30 -04:00
|
|
|
func add_foe(foe):
|
|
|
|
list.append(foe)
|
|
|
|
|
|
|
|
func remove_foe(foe):
|
2023-10-10 22:31:20 -04:00
|
|
|
receive_exp(foe.expReward)
|
2023-10-10 16:49:30 -04:00
|
|
|
list.erase(foe)
|
2023-10-10 22:31:20 -04:00
|
|
|
killcount += 1
|
2023-10-10 16:49:30 -04:00
|
|
|
|
2023-10-10 10:22:04 -04:00
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
|
|
func _ready():
|
2023-10-11 04:21:07 -04:00
|
|
|
#setLevel(2)
|
2023-10-10 17:26:13 -04:00
|
|
|
atk1l.set_disabled(true)
|
|
|
|
atk1r.set_disabled(true)
|
|
|
|
atk2l.set_disabled(true)
|
|
|
|
atk2r.set_disabled(true)
|
2023-10-11 05:23:48 -04:00
|
|
|
hp_changed.emit(hp, maxhp)
|
|
|
|
exp_gained.emit(experience, 0 if level == 1 else levelup[level - 2] ,levelup[level - 1], level)
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-10 10:22:04 -04:00
|
|
|
|
|
|
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
|
|
func _process(delta):
|
2023-10-11 04:21:07 -04:00
|
|
|
if is_dead:
|
|
|
|
pass
|
|
|
|
|
2023-10-10 21:46:15 -04:00
|
|
|
if hp <= 0 && !is_dying:
|
2023-10-11 12:05:50 -04:00
|
|
|
is_dead = true
|
2023-10-10 21:46:15 -04:00
|
|
|
$Death.start()
|
|
|
|
$Atk_cooldown.stop()
|
|
|
|
setAnimState("Die")
|
|
|
|
is_attacking = false
|
|
|
|
is_dying = true
|
2023-10-11 00:03:05 -04:00
|
|
|
$DeathSnd.play()
|
|
|
|
|
2023-10-10 22:31:20 -04:00
|
|
|
if abs(velocity.x) < 1 && abs(velocity.y) < 1 && !is_attacking:
|
2023-10-10 12:56:34 -04:00
|
|
|
setAnimState("Idle")
|
|
|
|
elif !is_attacking:
|
|
|
|
setAnimState("Run")
|
|
|
|
|
2023-10-10 17:07:02 -04:00
|
|
|
if state != "Attack" && state != "Attack2":
|
2023-10-10 18:00:02 -04:00
|
|
|
is_facing_left = velocity.x > 0 && !(velocity.x < 0)
|
2023-10-11 04:21:07 -04:00
|
|
|
|
2023-10-10 23:04:25 -04:00
|
|
|
if currentcooldown > 0.:
|
|
|
|
currentcooldown -= delta
|
2023-10-10 12:56:34 -04:00
|
|
|
# AI STUFF
|
2023-10-10 19:27:17 -04:00
|
|
|
velocity += processAI(list) * delta
|
|
|
|
|
|
|
|
while velocity.length() > 100:
|
|
|
|
velocity.x *= 0.99
|
|
|
|
velocity.y *= 0.99
|
2023-10-10 22:31:20 -04:00
|
|
|
velocity.x *= 0.97
|
|
|
|
velocity.y *= 0.97
|
2023-10-10 13:34:26 -04:00
|
|
|
|
2023-10-10 16:32:28 -04:00
|
|
|
if !hitanim.is_emitting():
|
2023-10-10 17:03:49 -04:00
|
|
|
anim.modulate.a = 1
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-11 11:34:37 -04:00
|
|
|
if freeXpStack >= 1:
|
|
|
|
receive_exp(floor(freeXpStack))
|
|
|
|
freeXpStack -= floor(freeXpStack)
|
|
|
|
freeXpStack += FREE_EXP_RATE * level * delta
|
2023-10-10 14:54:21 -04:00
|
|
|
move_and_slide()
|
2023-10-10 12:56:34 -04:00
|
|
|
|
|
|
|
|
2023-10-10 19:27:17 -04:00
|
|
|
func processAI(objs):
|
2023-10-10 13:34:26 -04:00
|
|
|
var vec: Vector2 = Vector2(0,0)
|
2023-10-11 09:36:16 -04:00
|
|
|
var skel = false
|
2023-10-10 19:27:17 -04:00
|
|
|
var weight: int = 0
|
2023-10-10 21:46:15 -04:00
|
|
|
if hp <= 0:
|
|
|
|
return vec
|
2023-10-10 13:34:26 -04:00
|
|
|
for obj in objs:
|
2023-10-10 19:33:00 -04:00
|
|
|
if !obj || !obj.isAlive:
|
|
|
|
continue
|
2023-10-11 09:36:16 -04:00
|
|
|
if position.distance_to(obj.position) < 25:
|
|
|
|
if obj.priority == 10:
|
|
|
|
vec += position.direction_to(obj.position) * 30
|
|
|
|
if currentcooldown <= 0:
|
|
|
|
attack()
|
|
|
|
currentcooldown = maxcooldown
|
|
|
|
weight = obj.priority * position.distance_to(obj.position) * ((maxhp + 1) / hp) * 1.25
|
2023-10-10 21:46:15 -04:00
|
|
|
vec = weight * -position.direction_to(obj.position)
|
2023-10-10 23:04:25 -04:00
|
|
|
if currentcooldown <= 0:
|
|
|
|
attack()
|
|
|
|
currentcooldown = maxcooldown
|
2023-10-11 09:36:16 -04:00
|
|
|
else:
|
|
|
|
if obj.priority == 10:
|
|
|
|
skel = true
|
|
|
|
vec = position.direction_to(obj.position) * 10
|
|
|
|
if currentcooldown <= 0:
|
|
|
|
attack()
|
|
|
|
currentcooldown = maxcooldown
|
|
|
|
break
|
|
|
|
weight = abs(obj.priority) * position.distance_to(obj.position)
|
|
|
|
vec += weight * position.direction_to(obj.position)
|
|
|
|
|
2023-10-10 19:27:17 -04:00
|
|
|
|
2023-10-11 09:36:16 -04:00
|
|
|
if vec.length() < 5 && objs.size() > 1 && !skel:
|
2023-10-10 19:27:17 -04:00
|
|
|
vec.y *= 3
|
|
|
|
|
2023-10-11 09:36:16 -04:00
|
|
|
if velocity.length() < 95 && objs.size() > 1 && !skel:
|
2023-10-10 19:27:17 -04:00
|
|
|
vec.y += 10
|
2023-10-10 22:45:27 -04:00
|
|
|
vec.x += 5
|
2023-10-10 19:27:17 -04:00
|
|
|
|
2023-10-11 10:44:11 -04:00
|
|
|
return vec.normalized() * 2000
|
2023-10-10 13:34:26 -04:00
|
|
|
|
|
|
|
|
2023-10-10 12:56:34 -04:00
|
|
|
func attack():
|
|
|
|
is_attacking = true
|
2023-10-11 00:03:05 -04:00
|
|
|
$AtkSnd.play()
|
2023-10-10 17:20:44 -04:00
|
|
|
|
|
|
|
setAnimState(atk)
|
|
|
|
if is_facing_left:
|
|
|
|
atkL.set_disabled(false)
|
2023-10-10 12:56:34 -04:00
|
|
|
else:
|
2023-10-10 17:20:44 -04:00
|
|
|
atkR.set_disabled(false)
|
|
|
|
|
2023-10-10 10:22:04 -04:00
|
|
|
|
2023-10-10 12:56:34 -04:00
|
|
|
func stop_attack():
|
|
|
|
is_attacking = false
|
2023-10-10 17:20:44 -04:00
|
|
|
atkL.set_disabled(true)
|
|
|
|
atkR.set_disabled(true)
|
2023-10-10 12:56:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
func setAnimState(newstate):
|
|
|
|
anim.animation = newstate
|
|
|
|
anim.flip_h = !is_facing_left
|
|
|
|
state = newstate
|
|
|
|
|
|
|
|
|
|
|
|
func receive_damage(dmg):
|
2023-10-11 12:05:50 -04:00
|
|
|
if is_dying || is_dead:
|
|
|
|
return
|
2023-10-11 00:03:05 -04:00
|
|
|
$HitSnd.play()
|
2023-10-10 14:24:19 -04:00
|
|
|
if hitanim.is_emitting():
|
|
|
|
pass
|
2023-10-10 12:56:34 -04:00
|
|
|
hp -= dmg
|
2023-10-10 14:24:19 -04:00
|
|
|
hitanim.restart()
|
2023-10-10 17:03:49 -04:00
|
|
|
anim.modulate.a = 0.5
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-11 05:23:48 -04:00
|
|
|
hp_changed.emit(hp, maxhp)
|
|
|
|
|
2023-10-10 12:56:34 -04:00
|
|
|
|
|
|
|
func receive_exp(x):
|
|
|
|
experience += x
|
2023-10-11 11:09:24 -04:00
|
|
|
while experience > levelup[level - 1] && level <= 8:
|
2023-10-10 12:56:34 -04:00
|
|
|
setLevel(level + 1)
|
|
|
|
|
2023-10-11 05:23:48 -04:00
|
|
|
exp_gained.emit(experience, 0 if level == 1 else levelup[level - 2] ,levelup[level - 1], level)
|
|
|
|
|
2023-10-10 12:56:34 -04:00
|
|
|
|
|
|
|
func setLevel(lvl):
|
|
|
|
level = lvl
|
|
|
|
lvlanim.restart()
|
2023-10-10 13:34:26 -04:00
|
|
|
lvlsnd.play()
|
2023-10-10 22:45:27 -04:00
|
|
|
stop_attack()
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-11 11:34:37 -04:00
|
|
|
if level > 2:
|
|
|
|
damage = 7
|
|
|
|
|
2023-10-10 17:20:44 -04:00
|
|
|
if level > 3:
|
|
|
|
atk = "Attack2"
|
|
|
|
atkL = atk2l
|
|
|
|
atkR = atk2r
|
2023-10-11 11:34:37 -04:00
|
|
|
damage = 14
|
2023-10-10 17:03:49 -04:00
|
|
|
|
2023-10-10 17:20:44 -04:00
|
|
|
if level > 4:
|
|
|
|
cooldown.wait_time = 1
|
|
|
|
|
2023-10-10 17:03:49 -04:00
|
|
|
if level > 5:
|
2023-10-11 11:34:37 -04:00
|
|
|
damage = 21
|
2023-10-10 17:03:49 -04:00
|
|
|
|
|
|
|
if level > 7:
|
|
|
|
maxAtks = 2
|
|
|
|
|
2023-10-11 11:34:37 -04:00
|
|
|
maxhp += 10
|
|
|
|
hp += 10 * level + 5
|
2023-10-10 17:13:43 -04:00
|
|
|
|
|
|
|
if hp > maxhp:
|
|
|
|
hp = maxhp
|
2023-10-10 12:56:34 -04:00
|
|
|
|
2023-10-11 05:23:48 -04:00
|
|
|
hp_changed.emit(hp, maxhp)
|
|
|
|
|
2023-10-10 10:22:04 -04:00
|
|
|
|
|
|
|
func _on_atk_cooldown_timeout():
|
2023-10-10 17:03:49 -04:00
|
|
|
currAtks = maxAtks
|
2023-10-11 04:21:07 -04:00
|
|
|
if !list.is_empty():
|
|
|
|
attack()
|
2023-10-10 12:56:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
func _on_sprite_animation_looped():
|
|
|
|
if is_attacking:
|
2023-10-10 17:03:49 -04:00
|
|
|
currAtks -= 1
|
2023-10-10 12:56:34 -04:00
|
|
|
stop_attack()
|
2023-10-10 17:03:49 -04:00
|
|
|
if currAtks > 0:
|
|
|
|
is_facing_left = !is_facing_left
|
|
|
|
attack()
|
2023-10-10 17:13:43 -04:00
|
|
|
else:
|
|
|
|
currAtks = maxAtks
|
2023-10-10 21:46:15 -04:00
|
|
|
is_dying = false
|
2023-10-10 13:34:26 -04:00
|
|
|
|
2023-10-10 14:54:21 -04:00
|
|
|
|
|
|
|
func _on_attack_area_body_entered(body):
|
2023-10-11 12:05:50 -04:00
|
|
|
if is_dead || is_dying:
|
|
|
|
return
|
2023-10-10 14:54:21 -04:00
|
|
|
if typeof(body) == typeof(TemplateSpawnable):
|
|
|
|
body.receive_damage(damage)
|
2023-10-11 00:03:05 -04:00
|
|
|
|
2023-10-10 21:46:15 -04:00
|
|
|
|
|
|
|
func _on_death_timeout():
|
|
|
|
$"..".win_screen()
|
|
|
|
queue_free()
|
2023-10-11 04:21:07 -04:00
|
|
|
|
|
|
|
func _on_sprite_animation_finished():
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-10-10 21:46:15 -04:00
|
|
|
|
2023-10-11 04:21:07 -04:00
|
|
|
func _on_death_snd_finished():
|
|
|
|
$DeathSnd.stop()
|