RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
battle_manager.gd
Go to the documentation of this file.
1extends RefCounted
2
3
9
10var active := false
11var player_card := {}
12var opponent_card := {}
13var player_hp := 0
14var opponent_hp := 0
15var player_turn := true
16var reward := 0
17var log := []
18var last_event := {}
19
20
21
22func battle(player_card:Dictionary, opponent_card:Dictionary, reward:int = 100) -> Dictionary:
23 if player_card.is_empty() or opponent_card.is_empty():
24 return {"winner": "none", "log": ["No battle could be started."], "reward": 0}
25
26 var player = player_card.duplicate(true)
27 var opponent = opponent_card.duplicate(true)
28 var player_hp = int(player.get("health", 1))
29 var opponent_hp = int(opponent.get("health", 1))
30 var player_turn = randi_range(0, 1) == 0
31 var log = [
32 "%s faces %s." % [player.get("name", "Player"), opponent.get("name", "Opponent")]
33 ]
34
35 while player_hp > 0 and opponent_hp > 0:
36 if player_turn:
37 var damage = _roll_damage(player, opponent)
38 opponent_hp -= damage
39 log.append("%s hits for %d." % [player.get("name", "Player"), damage])
40 else:
41 var damage = _roll_damage(opponent, player)
42 player_hp -= damage
43 log.append("%s hits for %d." % [opponent.get("name", "Opponent"), damage])
44 player_turn = not player_turn
45
46 var player_won = player_hp > 0
47 log.append("%s wins." % [player.get("name", "Player") if player_won else opponent.get("name", "Opponent")])
48 return {
49 "winner": "player" if player_won else "opponent",
50 "reward": reward if player_won else 0,
51 "log": log
52 }
53
54
55func _roll_damage(attacker:Dictionary, defender:Dictionary) -> int:
56 return max(1, int(attacker.get("attack", 1)) + randi_range(1, 6) - int(defender.get("defense", 0)))
57
58
59
61func start_battle(selected_player_card:Dictionary, selected_opponent_card:Dictionary, battle_reward:int = 100, starting_opponent_hp:int = -1) -> Dictionary:
62 player_card = selected_player_card.duplicate(true)
63 opponent_card = selected_opponent_card.duplicate(true)
64 player_hp = int(player_card.get("health", 1))
65 opponent_hp = starting_opponent_hp if starting_opponent_hp > 0 else int(opponent_card.get("health", 1))
66 player_turn = randi_range(0, 1) == 0
67 reward = battle_reward
68 active = not player_card.is_empty() and not opponent_card.is_empty()
69 log = []
70 last_event = {}
71 if active:
72 log.append("%s faces %s." % [player_card.get("name", "Player"), opponent_card.get("name", "Opponent")])
73 log.append("%s has initiative." % [player_card.get("name", "Player") if player_turn else opponent_card.get("name", "Opponent")])
74 else:
75 log.append("No battle could be started.")
76 return get_state()
77
78
79
80func clear_opponent() -> void:
81 active = false
82 player_card = {}
83 opponent_card = {}
84 player_hp = 0
85 opponent_hp = 0
86 log = []
87 last_event = {}
88
89
90
91func take_turn() -> Dictionary:
92 if not active:
93 last_event = {}
94 return get_state()
95
96 if player_turn:
97 var player_roll = randi_range(1, 6)
98 var player_damage = _calculate_damage(player_card, opponent_card, player_roll)
99 opponent_hp -= player_damage
100 log.append("%s rolls %d and deals %d damage." % [player_card.get("name", "Player"), player_roll, player_damage])
101 last_event = _make_turn_event("player", "opponent", player_card, opponent_card, player_roll, player_damage, max(0, opponent_hp))
102 else:
103 var opponent_roll = randi_range(1, 6)
104 var opponent_damage = _calculate_damage(opponent_card, player_card, opponent_roll)
105 player_hp -= opponent_damage
106 log.append("%s rolls %d and deals %d damage." % [opponent_card.get("name", "Opponent"), opponent_roll, opponent_damage])
107 last_event = _make_turn_event("opponent", "player", opponent_card, player_card, opponent_roll, opponent_damage, max(0, player_hp))
108
109 if player_hp <= 0 or opponent_hp <= 0:
110 active = false
111 last_event["defeated"] = true
112 last_event["winner"] = get_winner()
113 log.append("%s wins." % [player_card.get("name", "Player") if player_hp > 0 else opponent_card.get("name", "Opponent")])
114 else:
115 player_turn = not player_turn
116
117 return get_state()
118
119
120
121func get_state() -> Dictionary:
122 return {
123 "active": active,
124 "player_card": player_card,
125 "opponent_card": opponent_card,
126 "player_hp": max(0, player_hp),
127 "opponent_hp": max(0, opponent_hp),
128 "player_turn": player_turn,
129 "winner": get_winner(),
130 "reward": reward if get_winner() == "player" else 0,
131 "log": log.duplicate(),
132 "last_event": last_event.duplicate(true)
133 }
134
135
136
137func get_winner() -> String:
138 if active:
139 return ""
140 if player_card.is_empty() or opponent_card.is_empty():
141 return "none"
142 return "player" if player_hp > 0 else "opponent"
143
144
145func _calculate_damage(attacker:Dictionary, defender:Dictionary, roll:int) -> int:
146 return max(1, int(attacker.get("attack", 1)) + roll - int(defender.get("defense", 0)))
147
148
149func _make_turn_event(attacker_side:String, defender_side:String, attacker:Dictionary, defender:Dictionary, roll:int, damage:int, defender_hp:int) -> Dictionary:
150 return {
151 "type": "damage",
152 "attacker": attacker_side,
153 "defender": defender_side,
154 "attacker_id": str(attacker.get("id", attacker.get("base_id", ""))),
155 "defender_id": str(defender.get("id", defender.get("base_id", ""))),
156 "attacker_name": str(attacker.get("name", "Attacker")),
157 "defender_name": str(defender.get("name", "Defender")),
158 "roll": roll,
159 "damage": damage,
160 "hp_after": defender_hp,
161 "defeated": defender_hp <= 0
162 }
int
Run a complete battle immediately and return winner/reward/log state.