Godot Version
4.6.1
Question
Help, im really lost here. i have no idea why the queue containers wont show up
extends Control
# --- CONFIGURATION ---
@export var debug_player_weapon: Weapon
@export var debug_player_identity: Identity
@export var debug_enemy_weapon: Weapon
@export var debug_enemy_identity: Identity
@export var contract_templates: Array[BattleContract] = []
# --- STATE ---
var player_hp: int = 20
var enemy_hp: int = 20
var energy: int = 5
var player_next_roll_debuff: int = 0
var enemy_next_roll_debuff: int = 0
var waves_left: int = 0
var current_enemy_max_hp: int = 0
var current_enemy_identity: Identity
var current_enemy_weapon: Weapon
var planned_skills: Array[Skill] = []
var enemy_planned_skills: Array[Skill] = []
var player_retained_dodge: Skill = null
var enemy_retained_dodge: Skill = null
# --- UI REFERENCES ---
@onready var log_box = $BattleLog
@onready var p_hp_label = $PlayerHPLabel
@onready var e_hp_label = $EnemyHPLabel
@onready var nrg_label = $EnergyLabel
@onready var skill_container = $VBoxContainer
@onready var p_queue_ui = $QueueContainer
@onready var e_queue_ui = $EnemyQueueContainer
@onready var turn_button = $turn_button
func _ready():
randomize()
if log_box:
log_box.bbcode_enabled = true
log_box.text = ""
if turn_button:
if not turn_button.pressed.is_connected(_on_turn_button_pressed):
turn_button.pressed.connect(_on_turn_button_pressed)
_initialize_combatants()
waves_left = PlayerData.current_waves
_spawn_next_wave()
setup_battle()
func _initialize_combatants():
if PlayerData.current_identity:
player_hp = PlayerData.current_identity.base_hp
var contract = PlayerData.current_battle_contract
if contract:
current_enemy_identity = contract.enemy_identity
if current_enemy_identity:
enemy_hp = current_enemy_identity.base_hp
if contract.possible_weapons.size() > 0:
current_enemy_weapon = contract.possible_weapons.pick_random()
else:
current_enemy_weapon = debug_enemy_weapon
func setup_battle():
log_message("-------------------------", "gray")
log_message("NEW TURN", "yellow")
energy = 5
planned_skills.clear()
_clear_ui_container(p_queue_ui)
_clear_ui_container(e_queue_ui)
update_ui()
generate_skill_buttons()
generate_enemy_turn()
turn_button.disabled = false
func _spawn_next_wave():
var contract = PlayerData.current_battle_contract
if contract and contract.enemy_identity:
enemy_hp = contract.enemy_identity.base_hp
current_enemy_max_hp = enemy_hp
log_message("A new enemy appears! Waves left: " + str(waves_left))
update_ui()
func update_ui():
# is_instance_valid checks if the node actually exists in the scene
if is_instance_valid(nrg_label):
nrg_label.text = "Energy: %d/5" % energy
if is_instance_valid(p_hp_label):
p_hp_label.text = "Player: %d HP" % max(0, player_hp)
if is_instance_valid(e_hp_label):
e_hp_label.text = "Enemy: %d HP" % max(0, enemy_hp)
# If the code gets here, it means the script didn't crash!
print("UI Updated successfully")
func generate_skill_buttons():
_clear_ui_container(skill_container)
var weapon = PlayerData.current_weapon
if not weapon: return
for skill in weapon.skills:
var btn = Button.new()
var bonus = get_total_bonus(skill, true)
var bonus_text = (" + %d" % bonus) if bonus > 0 else (" - %d" % abs(bonus) if bonus < 0 else "")
btn.text = "%s (%d-%d)%s | %d EP" % [skill.name.to_upper(), skill.min_value, skill.max_value, bonus_text, skill.energy_cost]
btn.pressed.connect(_on_skill_pressed.bind(skill))
skill_container.add_child(btn)
func _on_skill_pressed(skill: Skill):
if energy >= skill.energy_cost:
energy -= skill.energy_cost
planned_skills.append(skill)
var btn = Button.new()
btn.text = "> " + skill.name.to_upper()
btn.flat = true
if p_queue_ui:
p_queue_ui.add_child(btn)
btn.pressed.connect(_revert_skill.bind(skill, btn))
update_ui()
func _revert_skill(skill: Skill, btn_reference: Button):
energy += skill.energy_cost
for i in range(planned_skills.size() - 1, -1, -1):
if planned_skills[i] == skill:
planned_skills.remove_at(i)
break
btn_reference.queue_free()
update_ui()
log_message("Reverted: " + skill.name, "gray")
func generate_enemy_turn():
enemy_planned_skills.clear()
var e_queue = get_node_or_null("EnemyQueueContainer")
if e_queue:
for child in e_queue.get_children(): child.queue_free()
var e_nrg = 5
if not current_enemy_weapon: return
while e_nrg > 0:
var affordable = current_enemy_weapon.skills.filter(func(s): return s.energy_cost <= e_nrg)
if affordable.size() == 0: break
var chosen = affordable.pick_random()
enemy_planned_skills.append(chosen)
e_nrg -= chosen.energy_cost
var label = Label.new()
label.text = "< " + chosen.name.to_upper()
if e_queue:
e_queue.add_child(label)
func get_total_bonus(skill: Skill, is_player: bool) -> int:
var total = 0
var id_res = PlayerData.current_identity if is_player else current_enemy_identity
var wp_res = PlayerData.current_weapon if is_player else current_enemy_weapon
if id_res:
if skill.type == "attack": total += id_res.atk_power
elif skill.type == "defense" or skill.type == "dodge": total += id_res.def_power
if wp_res is Weapon:
if skill.type == "attack": total += wp_res.atk_bonus
if wp_res.weapon_passive:
var p = wp_res.weapon_passive
if skill.type == "attack": total += p.flat_atk_bonus
elif skill.type == "defense" or skill.type == "dodge": total += p.flat_def_bonus
return total
func _on_turn_button_pressed():
if planned_skills.is_empty(): return
turn_button.disabled = true
var p_pointer = 0
var e_pointer = 0
while p_pointer < planned_skills.size() or e_pointer < enemy_planned_skills.size() or player_retained_dodge != null:
if e_pointer >= enemy_planned_skills.size() and player_retained_dodge != null:
player_retained_dodge = null
var using_retained = (player_retained_dodge != null)
execute_clash_pointer_step(p_pointer, e_pointer)
if not using_retained and p_pointer < planned_skills.size(): p_pointer += 1
if e_pointer < enemy_planned_skills.size(): e_pointer += 1
update_ui()
await get_tree().create_timer(0.8).timeout
if enemy_hp <= 0 or player_hp <= 0: break
_end_turn_cleanup()
func execute_clash_pointer_step(p_idx: int, e_idx: int):
var p_s = player_retained_dodge if player_retained_dodge else (planned_skills[p_idx] if p_idx < planned_skills.size() else null)
var e_s = enemy_retained_dodge if enemy_retained_dodge else (enemy_planned_skills[e_idx] if e_idx < enemy_planned_skills.size() else null)
if not p_s and not e_s: return
if p_s and not e_s:
_apply_win(p_s, null, _get_roll(p_s, true), true); return
if e_s and not p_s:
_apply_win(e_s, null, _get_roll(e_s, false), false); return
var p_v = _get_roll(p_s, true)
var e_v = _get_roll(e_s, false)
log_message("CLASH: %s (%d) vs %s (%d)" % [p_s.name, p_v, e_s.name, e_v])
if p_s.type != "attack" and e_s.type != "attack":
log_message("NEGATED: Defensive moves cancel out", "gray")
player_retained_dodge = null; enemy_retained_dodge = null; return
if p_v > e_v:
_apply_win(p_s, e_s, p_v, true)
if p_s.type == "attack": player_retained_dodge = null
elif e_v > p_v:
_apply_win(e_s, p_s, e_v, false)
player_retained_dodge = null
else:
log_message("STALEMATE", "gray")
_clear_retained()
func _get_roll(skill: Skill, is_player: bool) -> int:
var bonus = get_total_bonus(skill, is_player)
var roll = randi_range(skill.min_value, skill.max_value) + bonus
if is_player and player_next_roll_debuff > 0:
roll -= player_next_roll_debuff; player_next_roll_debuff = 0
elif not is_player and enemy_next_roll_debuff > 0:
roll -= enemy_next_roll_debuff; enemy_next_roll_debuff = 0
return max(0, roll)
func _apply_win(win_skill: Skill, lose_skill: Skill, val: int, p_win: bool):
var target_label = "Operative" if p_win else "Target"
if win_skill.type == "attack":
if p_win: enemy_hp -= val
else: player_hp -= val
log_message("%s deals %d damage!" % [target_label, val], "cyan" if p_win else "red")
var weapon = PlayerData.current_weapon if p_win else current_enemy_weapon
if weapon and weapon.weapon_passive:
var penalty = weapon.weapon_passive.next_roll_penalty
if p_win: enemy_next_roll_debuff = penalty
else: player_next_roll_debuff = penalty
elif win_skill.type == "dodge":
log_message("%s dodged with %d!" % [target_label, val], "yellow")
if p_win: player_retained_dodge = win_skill; enemy_retained_dodge = null
else: enemy_retained_dodge = win_skill; player_retained_dodge = null
func _end_turn_cleanup():
if player_hp <= 0: get_tree().change_scene_to_file("res://office.tscn")
elif enemy_hp <= 0: _on_enemy_died()
else: setup_battle()
func _on_enemy_died():
waves_left -= 1
if waves_left > 0:
await get_tree().create_timer(1.5).timeout
_spawn_next_wave()
setup_battle()
else:
PlayerData.ahn += PlayerData.current_reward
get_tree().change_scene_to_file("res://office.tscn")
func _clear_ui_container(container: Control):
if container: for child in container.get_children(): child.queue_free()
func log_message(text: String, color: String = "white"):
if log_box: log_box.append_text("[color=%s]%s[/color]\n" % [color, text])
func _clear_retained():
player_retained_dodge = null
enemy_retained_dodge = null
