From fc70d205b3f479b0a46042370b1cb2bb70906b3c Mon Sep 17 00:00:00 2001 From: istamarahsan Date: Sun, 26 Jan 2025 05:00:37 +0700 Subject: [PATCH] feat: implement support cards - insurance - absorb - tanker - lifesteal - sword mastery - invisibility - potion - all out attack --- data/cards/support/absorb.tres | 11 ++-- data/cards/support/all_out_attack.tres | 9 +-- data/cards/support/energy_booster.tres | 9 +-- data/cards/support/insurance.tres | 9 +-- data/cards/support/invisibility.tres | 9 +-- data/cards/support/lifesteal.tres | 9 +-- data/cards/support/negate.tres | 9 +-- data/cards/support/potion.tres | 11 ++-- data/cards/support/reflection.tres | 9 +-- data/cards/support/sword_mastery.tres | 9 +-- data/cards/support/tanker.tres | 9 +-- tcg/card/card.gd | 2 +- tcg/card/implemented_support_card.gd | 4 ++ tcg/card/support_card.gd | 1 - tcg/match/match_manager.gd | 88 ++++++++++++++------------ 15 files changed, 110 insertions(+), 88 deletions(-) create mode 100644 tcg/card/implemented_support_card.gd diff --git a/data/cards/support/absorb.tres b/data/cards/support/absorb.tres index 705b320..8d7403c 100644 --- a/data/cards/support/absorb.tres +++ b/data/cards/support/absorb.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://be01tdq1fxlct"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://cc0ebl4g4ffyk"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_mhxdy"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_x8k3o"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_f6hay"] [resource] -script = ExtResource("2_x8k3o") +script = ExtResource("2_f6hay") +scope = "turn" +magnitude = 0 type = "red" -priority = 0 -effects = Array[ExtResource("1_mhxdy")]([null]) +effects = Array[ExtResource("1_mhxdy")]([]) name = "Absorb" description = "Enemy damage converted to heal your Active Monster Field HP during this turn." diff --git a/data/cards/support/all_out_attack.tres b/data/cards/support/all_out_attack.tres index d69f64b..ec8850c 100644 --- a/data/cards/support/all_out_attack.tres +++ b/data/cards/support/all_out_attack.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://dgxcvdo6x6kst"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://dgxcvdo6x6kst"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_fd50n"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_1tjl7"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_61mgn"] [resource] -script = ExtResource("2_1tjl7") +script = ExtResource("2_61mgn") +scope = "instant" +magnitude = 0 type = "green" -priority = 0 effects = Array[ExtResource("1_fd50n")]([null]) name = "All-Out Attack" description = "Combine all Rock Paper Scissor during this turn, and got additional damage from the lowest Rock Paper Scissor you got." diff --git a/data/cards/support/energy_booster.tres b/data/cards/support/energy_booster.tres index c3e9de8..ea24a0b 100644 --- a/data/cards/support/energy_booster.tres +++ b/data/cards/support/energy_booster.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://c0grh1y65e0f3"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://c0grh1y65e0f3"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_pkc1x"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_qqko6"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_iq88n"] [resource] -script = ExtResource("2_qqko6") +script = ExtResource("2_iq88n") +scope = "turn" +magnitude = 0 type = "green" -priority = 0 effects = Array[ExtResource("1_pkc1x")]([null]) name = "Energy Booster" description = "Add 1 additional Energy." diff --git a/data/cards/support/insurance.tres b/data/cards/support/insurance.tres index 4f53e44..5183f9f 100644 --- a/data/cards/support/insurance.tres +++ b/data/cards/support/insurance.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://dfocg5yfh22e8"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://dfocg5yfh22e8"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_gtyqr"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_286ne"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_3ixor"] [resource] -script = ExtResource("2_286ne") +script = ExtResource("2_3ixor") +scope = "turn" +magnitude = 10 type = "red" -priority = 0 effects = Array[ExtResource("1_gtyqr")]([null]) name = "Insurance" description = "If your monster supposed to be dead in this turn, keep it alive at 10 HP." diff --git a/data/cards/support/invisibility.tres b/data/cards/support/invisibility.tres index c0a3499..2b917fb 100644 --- a/data/cards/support/invisibility.tres +++ b/data/cards/support/invisibility.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://by4yg81uqti3u"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://by4yg81uqti3u"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_5tnpm"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_hsvj6"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_6c2xo"] [resource] -script = ExtResource("2_hsvj6") +script = ExtResource("2_6c2xo") +scope = "turn" +magnitude = 0 type = "green" -priority = 0 effects = Array[ExtResource("1_5tnpm")]([null]) name = "Invisibility" description = "Ignore any damage to your monster in this turn." diff --git a/data/cards/support/lifesteal.tres b/data/cards/support/lifesteal.tres index 26aa830..726912d 100644 --- a/data/cards/support/lifesteal.tres +++ b/data/cards/support/lifesteal.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://bcrlaam8uq6xt"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://bcrlaam8uq6xt"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_b33y4"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_qww3m"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_khaf1"] [resource] -script = ExtResource("2_qww3m") +script = ExtResource("2_khaf1") +scope = "turn" +magnitude = 0 type = "green" -priority = 0 effects = Array[ExtResource("1_b33y4")]([null]) name = "Lifesteal" description = "During this turn your attack also heals your HP." diff --git a/data/cards/support/negate.tres b/data/cards/support/negate.tres index 1c634cd..38707fc 100644 --- a/data/cards/support/negate.tres +++ b/data/cards/support/negate.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://cl0jcer7o04uc"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://cl0jcer7o04uc"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_awvxv"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_v8fdj"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_tr5ug"] [resource] -script = ExtResource("2_v8fdj") +script = ExtResource("2_tr5ug") +scope = "turn" +magnitude = 0 type = "red" -priority = 1 effects = Array[ExtResource("1_awvxv")]([null]) name = "Negate" description = "Cancel 1 of the Support Card played by your opponent. This card will always be played last." diff --git a/data/cards/support/potion.tres b/data/cards/support/potion.tres index 96ed2d7..7137c77 100644 --- a/data/cards/support/potion.tres +++ b/data/cards/support/potion.tres @@ -1,9 +1,8 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=6 format=3 uid="uid://4eod3m0vc5a8"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=5 format=3 uid="uid://4eod3m0vc5a8"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_ujm0o"] [ext_resource type="Resource" uid="uid://cvu0rtt5nggf" path="res://data/support_effects/heal.tres" id="2_k1cnl"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="3_6r4k4"] -[ext_resource type="Texture2D" uid="uid://rh3aswb0p7ri" path="res://assets/energy.png" id="3_kyx3v"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="3_at5nt"] [sub_resource type="Resource" id="Resource_88lmk"] script = ExtResource("1_ujm0o") @@ -11,10 +10,10 @@ magnitude = 30 effect = ExtResource("2_k1cnl") [resource] -script = ExtResource("3_6r4k4") +script = ExtResource("3_at5nt") +scope = "turn" +magnitude = 30 type = "green" -priority = 0 effects = Array[ExtResource("1_ujm0o")]([SubResource("Resource_88lmk")]) name = "Potion" description = "Heal 30 HP" -icon = ExtResource("3_kyx3v") diff --git a/data/cards/support/reflection.tres b/data/cards/support/reflection.tres index 1833aad..b87a630 100644 --- a/data/cards/support/reflection.tres +++ b/data/cards/support/reflection.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://c1gsrru1wa6ao"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://c1gsrru1wa6ao"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_mk2or"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_fliii"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_igbok"] [resource] -script = ExtResource("2_fliii") +script = ExtResource("2_igbok") +scope = "turn" +magnitude = 0 type = "red" -priority = 0 effects = Array[ExtResource("1_mk2or")]([null]) name = "Reflection" description = "Enemy got the same amount of damage as our monster in this turn." diff --git a/data/cards/support/sword_mastery.tres b/data/cards/support/sword_mastery.tres index 77eee88..1d48401 100644 --- a/data/cards/support/sword_mastery.tres +++ b/data/cards/support/sword_mastery.tres @@ -1,8 +1,8 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=5 format=3 uid="uid://2xeb6keaoabo"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=5 format=3 uid="uid://2xeb6keaoabo"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_y6yvj"] [ext_resource type="Resource" uid="uid://bs4i85slalkgd" path="res://data/support_effects/sword_mastery.tres" id="2_omhdb"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_vp8a3"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="3_37rh4"] [sub_resource type="Resource" id="Resource_wwv02"] script = ExtResource("1_y6yvj") @@ -10,9 +10,10 @@ magnitude = 20 effect = ExtResource("2_omhdb") [resource] -script = ExtResource("2_vp8a3") +script = ExtResource("3_37rh4") +scope = "monster" +magnitude = 20 type = "green" -priority = 0 effects = Array[ExtResource("1_y6yvj")]([SubResource("Resource_wwv02")]) name = "Sword Mastery" description = "Permanently add 20 damage for all Rock Paper Scissor to 1 Active Monster." diff --git a/data/cards/support/tanker.tres b/data/cards/support/tanker.tres index c51cbf2..7a207b4 100644 --- a/data/cards/support/tanker.tres +++ b/data/cards/support/tanker.tres @@ -1,12 +1,13 @@ -[gd_resource type="Resource" script_class="SupportCard" load_steps=3 format=3 uid="uid://dsmrqyxt8mdp5"] +[gd_resource type="Resource" script_class="SimpleSupportCard" load_steps=3 format=3 uid="uid://dsmrqyxt8mdp5"] [ext_resource type="Script" path="res://tcg/card/support_card_effect_instance.gd" id="1_1fvcb"] -[ext_resource type="Script" path="res://tcg/card/support_card.gd" id="2_m4ahe"] +[ext_resource type="Script" path="res://tcg/card/implemented_support_card.gd" id="2_d0adk"] [resource] -script = ExtResource("2_m4ahe") +script = ExtResource("2_d0adk") +scope = "turn" +magnitude = 0 type = "red" -priority = 0 effects = Array[ExtResource("1_1fvcb")]([null]) name = "Tanker" description = "Add your HP with your selected (Rock Paper Scissor) during this turn, and reduce to max HP if current HP higher than max HP." diff --git a/tcg/card/card.gd b/tcg/card/card.gd index e14ff41..6fd69f3 100644 --- a/tcg/card/card.gd +++ b/tcg/card/card.gd @@ -2,7 +2,7 @@ extends Resource class_name Card @export var name: String -@export var description: String +@export_multiline var description: String @export var icon: Texture2D var id: String: diff --git a/tcg/card/implemented_support_card.gd b/tcg/card/implemented_support_card.gd new file mode 100644 index 0000000..9806f1c --- /dev/null +++ b/tcg/card/implemented_support_card.gd @@ -0,0 +1,4 @@ +extends SupportCard +class_name ImplementedSupportCard + +@export_enum("instant", "turn", "monster", "match") var scope = "instant" diff --git a/tcg/card/support_card.gd b/tcg/card/support_card.gd index 8ff5e3b..68eeba4 100644 --- a/tcg/card/support_card.gd +++ b/tcg/card/support_card.gd @@ -2,5 +2,4 @@ extends Card class_name SupportCard @export_enum("red", "green") var type = "green" -@export var priority: int = 0 @export var effects: Array[SupportCardEffectInstance] = [null] diff --git a/tcg/match/match_manager.gd b/tcg/match/match_manager.gd index 1bff5e2..1a12147 100644 --- a/tcg/match/match_manager.gd +++ b/tcg/match/match_manager.gd @@ -22,9 +22,6 @@ var player_2: MatchPlayer: return players[actual_p2_id] as MatchPlayer var phase: Match.Phase = Match.Phase.PREGAME -var support_cards_1: Dictionary = {} -var support_cards_2: Dictionary = {} - var actual_p1_id: int var actual_p2_id: int @@ -38,8 +35,7 @@ func init(decks: Dictionary, actual_p1_id: int, actual_p2_id: int): cleanup() for player_id in [PLAYER_1_ID, PLAYER_2_ID]: var deck_shuffled = decks[player_id].duplicate() as Array[Card] - - var first_monster = deck_shuffled.filter(func (card): return card is MonsterCard)[0] + var first_monster = deck_shuffled.filter(func(card): return card is MonsterCard)[0] var first_monster_idx = deck_shuffled.find(first_monster) deck_shuffled.pop_at(first_monster_idx) var zero_idx_card = deck_shuffled.pop_at(0) @@ -49,6 +45,7 @@ func init(decks: Dictionary, actual_p1_id: int, actual_p2_id: int): deck_shuffled.shuffle() players[player_id] = MatchPlayer.new(player_id, deck_shuffled) + func cleanup(): for player_id in [PLAYER_1_ID, PLAYER_2_ID]: var existing = players.get(player_id) @@ -75,8 +72,6 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: ) phase = Match.Phase.SUMMON Match.Phase.SUMMON: - support_cards_1.clear() - support_cards_2.clear() for player_id in action_by_player_id.keys(): var action = action_by_player_id[player_id] @@ -89,38 +84,48 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: if players.values().all(func(player: MatchPlayer): return player.monster): phase = Match.Phase.SUPPORT_1 Match.Phase.SUPPORT_1: - support_cards_1.clear() - support_cards_2.clear() - var support_cards = [] if player_1_action is ActionPlayCard: support_cards.append({ "player": player_1, "card": player_1_action.card }) - support_cards_1[player_1] = player_1_action.card player_1.hand.erase(player_1_action.card) if player_2_action is ActionPlayCard: support_cards.append({ "player": player_2, "card": player_2_action.card }) - support_cards_1[player_2] = player_2_action.card player_2.hand.erase(player_2_action.card) support_cards.sort_custom(func(a, b): return a.card.priority < b.card.priority) for played_card in support_cards: var player: MatchPlayer = played_card.player var card: SupportCard = played_card.card - events.append_array(_resolve_support_card_effects(player, card)) + var executed_instant_effects_events = _execute_support_card_immediate_effects(player, card) + player.active_support_cards.append(card) + events.append_array(executed_instant_effects_events) phase = Match.Phase.RPS Match.Phase.RPS: + var damage_pairs = [] var tie = player_1_action.move == player_2_action.move var player_1_win = rps_wins[player_1_action.move] == player_2_action.move var player_2_win = rps_wins[player_2_action.move] == player_1_action.move if tie or player_1_win: - player_2.monster.health_delta -= player_1.monster.card.damage[player_1_action.move] + _resolve_damage_delta(player_1) + damage_pairs.append({"from": player_1, "to": player_2}) if tie or player_2_win: - player_1.monster.health_delta -= player_2.monster.card.damage[player_2_action.move] + _resolve_damage_delta(player_2) + damage_pairs.append({"from": player_2, "to": player_1}) + for pair in damage_pairs: + var computed_damage = pair.from.monster.card.damage[pair.from.move] + if _player_has_active_support_card(pair.from, "all_out_attack"): + var rps = [pair.from.monster.card.rock, pair.from.monster.card.paper, pair.from.monster.card.scissors] + computed_damage = rps.reduce(func (a, b): return a + b, 0) + pair.from.health_delta -= rps.min() + if _player_has_active_support_card(pair.from, "sword_mastery"): + computed_damage += 20 + if _player_has_active_support_card(pair.from, "lifesteal"): + pair.from.health_delta += computed_damage + pair.to.monster.health_delta -= computed_damage + phase = Match.Phase.SUPPORT_2 Match.Phase.SUPPORT_2: var support_cards = [] @@ -129,26 +134,32 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: "player": player_1, "card": player_1_action.card }) - support_cards_2[player_1] = player_1_action.card player_1.hand.erase(player_1_action.card) if player_2_action is ActionPlayCard: support_cards.append({ "player": player_2, "card": player_2_action.card }) - support_cards_2[player_2] = player_2_action.card player_2.hand.erase(player_2_action.card) support_cards.sort_custom(func(a, b): return a.card.priority < b.card.priority) for played_card in support_cards: var player: MatchPlayer = played_card.player var card: SupportCard = played_card.card - events.append_array(_resolve_support_card_effects(player, card)) + player.active_support_cards.append(played_card) + events.append_array(_execute_support_card_immediate_effects(player, card)) for player: MatchPlayer in players.values(): + if _player_has_active_support_card(player, "absorb") and player.monster.health_delta < 0: + player.monster.health_delta = -player.monster.health_delta var monster_final_health = player.monster.health + player.monster.health_delta + if _player_has_active_support_card(player, "invisibility"): + monster_final_health = player.monster.health + if _player_has_active_support_card(player, "insurance"): + monster_final_health = max(10, monster_final_health) if monster_final_health <= 0: player.monster = null - player.active_support_cards = [] + var card_expires_with_monster = func(card): return card is ImplementedSupportCard and card.scope == 'monster' + player.active_support_cards = player.active_support_cards.filter(card_expires_with_monster) events.append(EventMonsterDied.new(player.id)) else: player.monster.health += player.monster.health_delta @@ -157,11 +168,15 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: if drawn_card: player.hand.append(drawn_card) events.append(EventCardDrawn.new(player.id, drawn_card)) - var players_without_monster = players.values().filter(func (player): return player.monster == null) + + var card_expires_this_turn = func(card): return card is ImplementedSupportCard and card.scope == 'turn' + player.active_support_cards = player.active_support_cards.filter(card_expires_this_turn) + + var players_without_monster = players.values().filter(func(player): return player.monster == null) if players_without_monster.size() == 0: phase = Match.Phase.SUPPORT_1 elif players_without_monster.all( - func (player): return player.hand.any(func (it): return it is MonsterCard and it.energy_cost <= player.energy) + func(player): return player.hand.any(func(it): return it is MonsterCard and it.energy_cost <= player.energy) ): phase = Match.Phase.SUMMON else: @@ -175,24 +190,19 @@ func resolve(action_by_player_id: Dictionary) -> PhaseTransition: func _monster_from_card(card: MonsterCard) -> MatchMonster: return MatchMonster.new(card, card.base_health, 0) -func _resolve_support_card_effects(player: MatchPlayer, card: SupportCard) -> Array[Event]: +func _execute_support_card_immediate_effects(player: MatchPlayer, card: SupportCard) -> Array[Event]: var events: Array[Event] - for effect_instance in card.effects: - var effect = effect_instance.effect - var magnitude = effect_instance.magnitude - match effect.id: - "heal": - player.monster.health_delta += magnitude - events.append(EventSupportEffectApplied.new(player.id, effect_instance)) - "sword_mastery": - player.active_support_cards.append(card) - events.append(EventSupportEffectApplied.new(player.id, effect_instance)) + if card is ImplementedSupportCard: + match card.id: + "potion": + player.monster.health_delta += card.magnitude + "energy_booster": + player.energy += card.magnitude + # events.append(Event) return events -func _resolve_damage_delta(player: MatchPlayer): - var final_delta: int = 0 - for card in player.active_support_cards: - match card.id: - "sword_mastery": - final_delta += card.magnitude - return final_delta +func _player_has_active_support_card(player: MatchPlayer, card_id: String) -> bool: + return player.active_support_cards.any(func (card): return card.id == card_id) + +func _player_opponent(player: MatchPlayer) -> MatchPlayer: + return player_2 if player.id == PLAYER_1_ID else player_1 \ No newline at end of file