186 lines
6.5 KiB
GDScript
186 lines
6.5 KiB
GDScript
extends Node
|
|
class_name MatchManager
|
|
|
|
signal match_begun
|
|
signal state_transitioned(transition: PhaseTransition)
|
|
|
|
const PLAYER_1_ID: int = 0
|
|
const PLAYER_2_ID: int = 1
|
|
|
|
var rps_wins = {
|
|
"rock": "scissors",
|
|
"scissors": "paper",
|
|
"paper": "rock"
|
|
}
|
|
|
|
var players: Dictionary
|
|
var player_1: MatchPlayer:
|
|
get:
|
|
return players[actual_p1_id] as MatchPlayer
|
|
var player_2: MatchPlayer:
|
|
get:
|
|
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
|
|
|
|
func _ready() -> void:
|
|
cleanup()
|
|
|
|
func init(decks: Dictionary, actual_p1_id: int, actual_p2_id: int):
|
|
self.actual_p1_id = actual_p1_id
|
|
self.actual_p2_id = actual_p2_id
|
|
|
|
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_idx = deck_shuffled.find(first_monster)
|
|
deck_shuffled.pop_at(first_monster_idx)
|
|
var zero_idx_card = deck_shuffled.pop_at(0)
|
|
deck_shuffled.insert(0, first_monster)
|
|
deck_shuffled.insert(first_monster_idx, zero_idx_card)
|
|
|
|
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)
|
|
if existing:
|
|
existing.free()
|
|
phase = Match.Phase.PREGAME
|
|
|
|
func resolve(action_by_player_id: Dictionary) -> PhaseTransition:
|
|
var initial_phase = phase
|
|
var events = [] as Array[Event]
|
|
var player_1_action = action_by_player_id.get(actual_p1_id) as Action
|
|
var player_2_action = action_by_player_id.get(actual_p2_id) as Action
|
|
match phase:
|
|
Match.Phase.PREGAME:
|
|
var CARDS_TO_DRAW: int = 3
|
|
for player: MatchPlayer in [player_1, player_2]:
|
|
var n_cards_to_draw = min(player.deck.size(), CARDS_TO_DRAW)
|
|
var drawn_cards = range(n_cards_to_draw).map(func(_i): return player.deck.pop_back()) as Array[Card]
|
|
for card in drawn_cards:
|
|
player.hand.push_back(card)
|
|
var drawn_card_events = drawn_cards.map(func(card): return EventCardDrawn.new(player.id, card))
|
|
events.append_array(
|
|
drawn_card_events
|
|
)
|
|
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]
|
|
if action is ActionPlayCard:
|
|
var card = action.card
|
|
if card is MonsterCard:
|
|
players[player_id].monster = _monster_from_card(card)
|
|
players[player_id].hand = players[player_id].hand.filter(func(card_in_hand): return card.id != card_in_hand.id)
|
|
events.append(EventMonsterSummoned.new(card))
|
|
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))
|
|
phase = Match.Phase.RPS
|
|
Match.Phase.RPS:
|
|
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]
|
|
if tie or player_2_win:
|
|
player_1.monster.health_delta -= player_2.monster.card.damage[player_2_action.move]
|
|
phase = Match.Phase.SUPPORT_2
|
|
Match.Phase.SUPPORT_2:
|
|
var support_cards = []
|
|
if player_1_action is ActionPlayCard:
|
|
support_cards.append({
|
|
"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))
|
|
|
|
for player: MatchPlayer in players.values():
|
|
var monster_final_health = player.monster.health + player.monster.health_delta
|
|
if monster_final_health <= 0:
|
|
player.monster = null
|
|
events.append(EventMonsterDied.new(player.id))
|
|
else:
|
|
player.monster.health += player.monster.health_delta
|
|
player.monster.health_delta = 0
|
|
var drawn_card = player.deck.pop_back()
|
|
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)
|
|
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)
|
|
):
|
|
phase = Match.Phase.SUMMON
|
|
else:
|
|
phase = Match.Phase.END
|
|
_:
|
|
pass
|
|
var transition = PhaseTransition.new(events, initial_phase, phase)
|
|
state_transitioned.emit(transition)
|
|
return transition
|
|
|
|
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]:
|
|
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))
|
|
return events
|