class_name CombatSystem extends Node func create_proposal(attacker: Unit, defender: Unit) -> CombatProposal: var proposal := CombatProposal.new() proposal.attacker = _snapshot(attacker, defender) proposal.defender = _snapshot(defender, attacker) return proposal func _snapshot(unit: Unit, opponent: Unit) -> CombatProposal.CombatantStats: var stats := CombatProposal.CombatantStats.new() stats.unit = unit stats.hp = unit.current_stats.current_hp stats.sp = unit.current_stats.current_sp stats.hit = unit.current_stats.hit - opponent.current_stats.eva stats.atk = unit.current_stats.phys_atk stats.def = unit.current_stats.phys_def stats.spd = unit.current_stats.spd return stats func process_combat(attacker: Unit, defender: Unit) -> void: var proposal := create_proposal(attacker, defender) var atk_name := attacker.current_info.name var def_name := defender.current_info.name print("=== Combat: %s vs %s ===" % [atk_name, def_name]) print(" %s — HP:%d ATK:%d DEF:%d HIT:%d" % [atk_name, proposal.attacker.hp, proposal.attacker.atk, proposal.attacker.def, proposal.attacker.hit]) print(" %s — HP:%d ATK:%d DEF:%d HIT:%d" % [def_name, proposal.defender.hp, proposal.defender.atk, proposal.defender.def, proposal.defender.hit]) apply_proposal(proposal) print(" Result: %s HP=%d, %s HP=%d" % [atk_name, attacker.current_stats.current_hp, def_name, defender.current_stats.current_hp]) func apply_proposal(proposal: CombatProposal) -> void: var atk_stats := proposal.attacker var def_stats := proposal.defender var atk_unit := atk_stats.unit var def_unit := def_stats.unit # Attacker strikes var atk_roll := randi_range(1, 100) if atk_roll <= atk_stats.hit: var damage := maxi(atk_stats.atk - def_stats.def, 0) def_unit.current_stats.current_hp -= damage # Counterattack if defender survives if def_unit.current_stats.current_hp > 0: var def_roll := randi_range(1, 100) if def_roll <= def_stats.hit: var damage := maxi(def_stats.atk - atk_stats.def, 0) atk_unit.current_stats.current_hp -= damage