Explain disabled battle action buttons
This commit is contained in:
@@ -2074,7 +2074,7 @@ func _update_hud() -> void:
|
||||
selected_label.text = "No unit selected."
|
||||
else:
|
||||
selected_label.text = _format_unit_focus_text(hovered_unit, "Hover")
|
||||
wait_button.disabled = true
|
||||
_update_wait_button({})
|
||||
_update_tactic_button({})
|
||||
_hide_tactic_menu()
|
||||
_update_item_button({})
|
||||
@@ -2084,7 +2084,7 @@ func _update_hud() -> void:
|
||||
else:
|
||||
_update_hud_unit_portrait(selected)
|
||||
selected_label.text = _format_unit_focus_text(selected, "Selected")
|
||||
wait_button.disabled = selected.get("acted", false) or not state.can_player_act() or _is_input_locked()
|
||||
_update_wait_button(selected)
|
||||
_update_tactic_button(selected)
|
||||
_update_item_button(selected)
|
||||
_update_equip_button(selected)
|
||||
@@ -2095,11 +2095,9 @@ func _update_hud() -> void:
|
||||
if equip_menu != null and equip_menu.visible:
|
||||
_rebuild_equip_menu(selected)
|
||||
|
||||
end_turn_button.disabled = not state.can_player_act() or _is_input_locked()
|
||||
_update_end_turn_button()
|
||||
restart_button.disabled = campaign_complete_screen
|
||||
if threat_button != null:
|
||||
threat_button.button_pressed = show_threat_overlay
|
||||
threat_button.disabled = not battle_started or state.battle_status != BattleState.STATUS_ACTIVE or campaign_complete_screen
|
||||
_update_threat_button()
|
||||
|
||||
|
||||
func _format_objective_hud_text() -> String:
|
||||
@@ -4887,32 +4885,118 @@ func _on_new_campaign_pressed() -> void:
|
||||
_update_hud()
|
||||
|
||||
|
||||
func _set_action_button_state(button: Button, label: String, disabled: bool, tooltip := "") -> void:
|
||||
if button == null:
|
||||
return
|
||||
button.text = label
|
||||
button.disabled = disabled
|
||||
button.tooltip_text = tooltip
|
||||
|
||||
|
||||
func _set_action_button_blocked(button: Button, base_label: String, reason_label: String, tooltip: String) -> void:
|
||||
_set_action_button_state(button, "%s - %s" % [base_label, reason_label], true, tooltip)
|
||||
|
||||
|
||||
func _action_phase_block_reason() -> Dictionary:
|
||||
if campaign_complete_screen:
|
||||
return {
|
||||
"label": "Campaign Done",
|
||||
"tooltip": "The campaign is complete."
|
||||
}
|
||||
if not battle_started:
|
||||
return {
|
||||
"label": "Start Battle",
|
||||
"tooltip": "Begin the battle before using combat actions."
|
||||
}
|
||||
if state.battle_status != BattleState.STATUS_ACTIVE:
|
||||
return {
|
||||
"label": "Battle Over",
|
||||
"tooltip": "Combat actions are unavailable after the battle ends."
|
||||
}
|
||||
if state.current_team != BattleState.TEAM_PLAYER:
|
||||
return {
|
||||
"label": "Enemy Turn",
|
||||
"tooltip": "Wait for the player phase."
|
||||
}
|
||||
if _is_input_locked():
|
||||
return {
|
||||
"label": "Busy",
|
||||
"tooltip": "Finish the current dialogue, result, or animation first."
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
func _update_wait_button(selected: Dictionary) -> void:
|
||||
if wait_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
_set_action_button_blocked(wait_button, "Wait", "Select Unit", "Select a controllable player unit before waiting.")
|
||||
return
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(wait_button, "Wait", "Done", "This unit has already acted.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(wait_button, "Wait", str(phase_block.get("label", "Busy")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
_set_action_button_state(wait_button, "Wait", false, "End this unit's action for the current turn.")
|
||||
|
||||
|
||||
func _update_end_turn_button() -> void:
|
||||
if end_turn_button == null:
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(end_turn_button, "End Turn", str(phase_block.get("label", "Busy")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
_set_action_button_state(end_turn_button, "End Turn", false, "End the player phase and let enemies act.")
|
||||
|
||||
|
||||
func _update_threat_button() -> void:
|
||||
if threat_button == null:
|
||||
return
|
||||
threat_button.button_pressed = show_threat_overlay
|
||||
if campaign_complete_screen:
|
||||
_set_action_button_blocked(threat_button, "Threat", "Campaign Done", "The campaign is complete.")
|
||||
return
|
||||
if not battle_started:
|
||||
_set_action_button_blocked(threat_button, "Threat", "Start Battle", "Begin the battle before showing enemy threat range.")
|
||||
return
|
||||
if state.battle_status != BattleState.STATUS_ACTIVE:
|
||||
_set_action_button_blocked(threat_button, "Threat", "Battle Over", "Threat range is only available during active battles.")
|
||||
return
|
||||
_set_action_button_state(threat_button, "Threat", false, "Toggle enemy attack and hostile tactic reach.")
|
||||
|
||||
|
||||
func _update_tactic_button(selected: Dictionary) -> void:
|
||||
if tactic_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
tactic_button.text = "Tactic"
|
||||
tactic_button.disabled = true
|
||||
_set_action_button_blocked(tactic_button, "Tactic", "Select Unit", "Select a controllable player unit before using tactics.")
|
||||
return
|
||||
|
||||
var skill_ids := state.get_skill_ids(selected["id"])
|
||||
if skill_ids.is_empty():
|
||||
tactic_button.text = "Tactic"
|
||||
tactic_button.disabled = true
|
||||
_set_action_button_blocked(tactic_button, "Tactic", "None", "This unit has no tactics.")
|
||||
return
|
||||
if state.is_unit_skill_sealed(selected["id"]):
|
||||
tactic_button.text = "Tactic - Sealed"
|
||||
tactic_button.disabled = true
|
||||
_set_action_button_blocked(tactic_button, "Tactic", "Sealed", "This unit is sealed and cannot use tactics.")
|
||||
return
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(tactic_button, "Tactic", "Done", "This unit has already acted.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(tactic_button, "Tactic", str(phase_block.get("label", "Busy")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
|
||||
if not selected_skill_id.is_empty():
|
||||
var skill := state.get_skill_def(selected_skill_id)
|
||||
tactic_button.text = "Tactic: %s" % str(skill.get("name", selected_skill_id))
|
||||
_set_action_button_state(tactic_button, "Tactic: %s" % str(skill.get("name", selected_skill_id)), false, "Target this tactic on the map.")
|
||||
elif tactic_menu != null and tactic_menu.visible:
|
||||
tactic_button.text = "Close Tactic"
|
||||
_set_action_button_state(tactic_button, "Close Tactic", false, "Close the tactics menu.")
|
||||
else:
|
||||
tactic_button.text = "Tactic"
|
||||
tactic_button.disabled = selected.get("acted", false) or not state.can_player_act() or _is_input_locked()
|
||||
_set_action_button_state(tactic_button, "Tactic", false, "Open tactics. %d known." % skill_ids.size())
|
||||
|
||||
|
||||
func _show_tactic_menu(selected: Dictionary) -> void:
|
||||
@@ -5066,24 +5150,28 @@ func _update_item_button(selected: Dictionary) -> void:
|
||||
if item_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
item_button.text = "Item"
|
||||
item_button.disabled = true
|
||||
_set_action_button_blocked(item_button, "Item", "Select Unit", "Select a controllable player unit before using items.")
|
||||
return
|
||||
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(item_button, "Item", "Done", "This unit has already acted.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(item_button, "Item", str(phase_block.get("label", "Busy")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
var item_ids := state.get_usable_item_ids()
|
||||
if item_ids.is_empty():
|
||||
item_button.text = "Item"
|
||||
item_button.disabled = true
|
||||
_set_action_button_blocked(item_button, "Item", "None", "No consumable items are available.")
|
||||
return
|
||||
|
||||
if not selected_item_id.is_empty():
|
||||
var item := state.get_item_def(selected_item_id)
|
||||
item_button.text = "Item: %s" % str(item.get("name", selected_item_id))
|
||||
_set_action_button_state(item_button, "Item: %s" % str(item.get("name", selected_item_id)), false, "Target this item on the map.")
|
||||
elif item_menu != null and item_menu.visible:
|
||||
item_button.text = "Close Item"
|
||||
_set_action_button_state(item_button, "Close Item", false, "Close the item menu.")
|
||||
else:
|
||||
item_button.text = "Item"
|
||||
item_button.disabled = selected.get("acted", false) or not state.can_player_act() or _is_input_locked()
|
||||
_set_action_button_state(item_button, "Item", false, "Open items. %d consumable types available." % item_ids.size())
|
||||
|
||||
|
||||
func _show_item_menu(selected: Dictionary) -> void:
|
||||
@@ -5185,15 +5273,23 @@ func _update_equip_button(selected: Dictionary) -> void:
|
||||
if equip_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
equip_button.text = "Equip"
|
||||
equip_button.disabled = true
|
||||
_set_action_button_blocked(equip_button, "Equip", "Select Unit", "Select a controllable player unit before changing equipment.")
|
||||
return
|
||||
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(equip_button, "Equip", "Done", "This unit has already acted.")
|
||||
return
|
||||
if bool(selected.get("moved", false)):
|
||||
_set_action_button_blocked(equip_button, "Equip", "Moved", "Equipment can only be changed before this unit moves.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(equip_button, "Equip", str(phase_block.get("label", "Busy")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
if equip_menu != null and equip_menu.visible:
|
||||
equip_button.text = "Close Equip"
|
||||
_set_action_button_state(equip_button, "Close Equip", false, "Close the equipment menu.")
|
||||
else:
|
||||
equip_button.text = "Equip"
|
||||
equip_button.disabled = selected.get("moved", false) or selected.get("acted", false) or not state.can_player_act() or _is_input_locked()
|
||||
_set_action_button_state(equip_button, "Equip", false, "Change weapons, armor, or accessories before moving.")
|
||||
|
||||
|
||||
func _show_equip_menu(selected: Dictionary) -> void:
|
||||
|
||||
@@ -44,6 +44,7 @@ func _init() -> void:
|
||||
_check_scene_texture_loading(failures)
|
||||
_check_hud_focus_text(failures)
|
||||
_check_hover_intent_badges(failures)
|
||||
_check_action_button_disabled_reasons(failures)
|
||||
_check_terrain_and_unit_presentation(failures)
|
||||
_check_attack_motion_profiles(failures)
|
||||
_check_attack_motion_signal(failures)
|
||||
@@ -237,6 +238,85 @@ func _check_hud_focus_text(failures: Array[String]) -> void:
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_action_button_disabled_reasons(failures: Array[String]) -> void:
|
||||
var scene = BattleSceneScript.new()
|
||||
scene.wait_button = Button.new()
|
||||
scene.tactic_button = Button.new()
|
||||
scene.item_button = Button.new()
|
||||
scene.equip_button = Button.new()
|
||||
scene.end_turn_button = Button.new()
|
||||
scene.threat_button = Button.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
failures.append("could not load battle scene state for action button reasons")
|
||||
_free_action_button_test_scene(scene)
|
||||
return
|
||||
scene.battle_started = true
|
||||
var cao_cao: Dictionary = scene.state.get_unit("cao_cao")
|
||||
|
||||
cao_cao["status_effects"] = [{
|
||||
"type": "action_lock",
|
||||
"status": "seal",
|
||||
"action": "skill",
|
||||
"remaining_phases": 2
|
||||
}]
|
||||
scene._update_tactic_button(cao_cao)
|
||||
if scene.tactic_button.text != "Tactic - Sealed" or not scene.tactic_button.tooltip_text.to_lower().contains("sealed"):
|
||||
failures.append("sealed unit should explain disabled tactic button: %s | %s" % [scene.tactic_button.text, scene.tactic_button.tooltip_text])
|
||||
cao_cao["status_effects"] = []
|
||||
|
||||
cao_cao["acted"] = true
|
||||
scene._update_wait_button(cao_cao)
|
||||
scene._update_tactic_button(cao_cao)
|
||||
scene._update_item_button(cao_cao)
|
||||
scene._update_equip_button(cao_cao)
|
||||
if not scene.wait_button.text.contains("Done"):
|
||||
failures.append("acted unit wait button should show Done: %s" % scene.wait_button.text)
|
||||
if not scene.tactic_button.text.contains("Done"):
|
||||
failures.append("acted unit tactic button should show Done: %s" % scene.tactic_button.text)
|
||||
if not scene.item_button.text.contains("Done"):
|
||||
failures.append("acted unit item button should show Done: %s" % scene.item_button.text)
|
||||
if not scene.equip_button.text.contains("Done"):
|
||||
failures.append("acted unit equip button should show Done: %s" % scene.equip_button.text)
|
||||
|
||||
cao_cao["acted"] = false
|
||||
cao_cao["moved"] = true
|
||||
scene._update_equip_button(cao_cao)
|
||||
if scene.equip_button.text != "Equip - Moved" or not scene.equip_button.tooltip_text.to_lower().contains("before"):
|
||||
failures.append("moved unit should explain disabled equip button: %s | %s" % [scene.equip_button.text, scene.equip_button.tooltip_text])
|
||||
|
||||
cao_cao["moved"] = false
|
||||
scene.state.set_inventory_snapshot({})
|
||||
scene._update_item_button(cao_cao)
|
||||
if scene.item_button.text != "Item - None" or not scene.item_button.tooltip_text.to_lower().contains("no consumable"):
|
||||
failures.append("empty inventory should explain disabled item button: %s | %s" % [scene.item_button.text, scene.item_button.tooltip_text])
|
||||
|
||||
scene.state.current_team = BattleState.TEAM_ENEMY
|
||||
scene._update_end_turn_button()
|
||||
if scene.end_turn_button.text != "End Turn - Enemy Turn" or not scene.end_turn_button.tooltip_text.to_lower().contains("player phase"):
|
||||
failures.append("enemy phase should explain disabled end turn button: %s | %s" % [scene.end_turn_button.text, scene.end_turn_button.tooltip_text])
|
||||
|
||||
scene.state.current_team = BattleState.TEAM_PLAYER
|
||||
scene.battle_started = false
|
||||
scene._update_threat_button()
|
||||
if scene.threat_button.text != "Threat - Start Battle" or not scene.threat_button.tooltip_text.to_lower().contains("begin"):
|
||||
failures.append("inactive battle should explain disabled threat button: %s | %s" % [scene.threat_button.text, scene.threat_button.tooltip_text])
|
||||
_free_action_button_test_scene(scene)
|
||||
|
||||
|
||||
func _free_action_button_test_scene(scene) -> void:
|
||||
for button in [
|
||||
scene.wait_button,
|
||||
scene.tactic_button,
|
||||
scene.item_button,
|
||||
scene.equip_button,
|
||||
scene.end_turn_button,
|
||||
scene.threat_button
|
||||
]:
|
||||
if button != null and is_instance_valid(button):
|
||||
button.free()
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_hover_intent_badges(failures: Array[String]) -> void:
|
||||
var scene = BattleSceneScript.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
|
||||
Reference in New Issue
Block a user