Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Knights of the Frozen Throne #495

Merged
merged 7 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ __pycache__
build
fireplace.egg-info
coverage.xml
venv

*.pyc
.tox
Expand Down
133 changes: 116 additions & 17 deletions fireplace/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
)

from .dsl import LazyNum, LazyValue, Selector
from .dsl.random_picker import RandomCollectible, RandomMinion
from .dsl.random_picker import RandomBeast, RandomCollectible, RandomMinion
from .entity import Entity
from .exceptions import InvalidAction
from .logging import log
from .utils import random_class
from .utils import get_script_definition, random_class


def _eval_card(source, card):
Expand Down Expand Up @@ -311,6 +311,8 @@ def do(self, source, player):
"%r cannot end turn with the open choice %r." % (player, player.choice)
)
self.broadcast(source, EventListener.ON, player)
if player.extra_end_turn_effect:
self.broadcast(source, EventListener.ON, player)
source.game._end_turn()


Expand Down Expand Up @@ -517,15 +519,17 @@ class Activate(GameAction):
PLAYER = ActionArg()
CARD = CardArg()
TARGET = ActionArg()
CHOOSE = ActionArg()

def get_args(self, source):
return (source, ) + super().get_args(source)

def do(self, source, player, heropower, target=None):
def do(self, source, player, heropower, target, choose):
player.pay_cost(heropower, heropower.cost)
self.broadcast(source, EventListener.ON, player, heropower, target)
self.broadcast(source, EventListener.ON, player, heropower, target, choose)

actions = heropower.get_actions("activate")
card = choose or heropower
actions = card.get_actions("activate")
source.game.action_start(BlockType.PLAY, heropower, 0, target)
source.game.main_power(heropower, actions, target)
source.game.action_end(BlockType.PLAY, heropower)
Expand All @@ -550,6 +554,7 @@ def do(self, source, player, amount):
log.info("%r overloads %s for %i", source, player, amount)
self.broadcast(source, EventListener.ON, player, amount)
player.overloaded += amount
player.overloaded_this_game += amount


class TargetedAction(Action):
Expand Down Expand Up @@ -592,6 +597,8 @@ def get_targets(self, source, t):
ret = t
elif isinstance(t, LazyValue):
ret = t.evaluate(source)
elif isinstance(t, str):
ret = source.controller.card(t)
else:
ret = t.eval(source.game, source)
if not ret:
Expand Down Expand Up @@ -659,21 +666,21 @@ def do(self, source, target, buff):
return buff.apply(target)


class StoringSpellBuff(TargetedAction):
class StoringBuff(TargetedAction):
TARGET = ActionArg()
BUFF = ActionArg()
SPELL = ActionArg()
CARD = ActionArg()

def get_target_args(self, source, target):
buff = self._args[1]
spell = _eval_card(source, self._args[2])[0]
card = _eval_card(source, self._args[2])[0]
buff = source.controller.card(buff)
buff.source = source
return [buff, spell]
return [buff, card]

def do(self, source, target, buff, spell):
log.info("%r store spell %r", buff, spell)
buff.store_spell = spell
def do(self, source, target, buff, card):
log.info("%r store card %r", buff, card)
buff.store_card = card
return buff.apply(target)


Expand Down Expand Up @@ -1099,10 +1106,22 @@ class Mill(TargetedAction):
Mill \a count cards from the top of the player targets' deck.
"""
TARGET = ActionArg()
AMOUNT = IntArg()
CARD = CardArg()

def get_target_args(self, source, target):
if target.deck:
card = target.deck[-1]
else:
card = None
return [card]

def do(self, source, target, card):
if card is None:
return []
card.discard()
self.broadcast(source, EventListener.ON, target, card, source)

def do(self, source, target, count):
target.mill(count)
return [card]


class Morph(TargetedAction):
Expand Down Expand Up @@ -1203,6 +1222,7 @@ def do(self, source, target, tags):
else:
for tag in tags:
target.tags[tag] = True
self.broadcast(source, EventListener.AFTER, target)


class UnsetTag(TargetedAction):
Expand Down Expand Up @@ -1533,8 +1553,11 @@ class RefreshHeroPower(TargetedAction):

def do(self, source, heropower):
log.info("Refresh Hero Power %s.", heropower)
heropower.activations_this_turn = 0
return heropower
if heropower.heropower_disabled:
return
if not heropower.exhausted:
return
heropower.additional_activations_this_turn += 1


class KazakusAction(TargetedAction):
Expand Down Expand Up @@ -1758,3 +1781,79 @@ def choose(self, card):
else:
log.info("Choose incorrectly, corrent choice is %r", self.starting_card)
self.player.choice = self.next_choice


class CreateZombeast(TargetedAction):
def init(self, source):
hunter_beast_ids = RandomBeast(
card_class=CardClass.HUNTER,
cost=list(range(0, 6))).find_cards(source)
neutral_beast_ids = RandomBeast(
card_class=CardClass.NEUTRAL,
cost=list(range(0, 6))).find_cards(source)
beast_ids = hunter_beast_ids + neutral_beast_ids
self.first_ids = []
self.second_ids = []
for id in beast_ids:
if get_script_definition(id):
self.first_ids.append(id)
else:
self.second_ids.append(id)

def do(self, source, player):
self.init(source)
self.player = player
self.next_choice = self.player.choice
self.source = source
self.min_count = 1
self.max_count = 1
self.choosed_cards = []
self.player.choice = self
self.do_step1()

def do_step1(self):
self.cards = [self.player.card(id) for id in random.sample(self.first_ids, 3)]

def do_step2(self):
self.cards = [self.player.card(id) for id in random.sample(self.second_ids, 3)]

def done(self):
zombeast = self.player.card("ICC_828t")
card1 = self.choosed_cards[0]
card2 = self.choosed_cards[1]
zombeast.tags[GameTag.CARDTEXT_ENTITY_0] = card2.data.strings[GameTag.CARDTEXT]
zombeast.tags[GameTag.CARDTEXT_ENTITY_1] = card1.data.strings[GameTag.CARDTEXT]
zombeast.data.scripts = card1.data.scripts
int_mergeable_attributes = (
"atk", "cost", "max_health", "incoming_damage_multiplier", "spellpower",
"windfury",
)
bool_mergeable_attributes = (
"has_deathrattle", "charge", "has_inspire", "stealthed", "cant_attack",
"cant_be_targeted_by_opponents", "cant_be_targeted_by_abilities",
"cant_be_targeted_by_hero_powers", "heavily_armored", "min_health",
"rush", "taunt", "poisonous", "ignore_taunt", "cannot_attack_heroes",
"unlimited_attacks", "cant_be_damaged", "lifesteal",
)
for attribute in int_mergeable_attributes:
setattr(zombeast, attribute, getattr(card1, attribute) + getattr(card2, attribute))
for attribute in bool_mergeable_attributes:
setattr(zombeast, attribute, getattr(card1, attribute) or getattr(card2, attribute))
self.player.give(zombeast)

def choose(self, card):
if card not in self.cards:
raise InvalidAction("%r is not a valid choice (one of %r)" % (card, self.cards))
else:
self.choosed_cards.append(card)
if len(self.choosed_cards) == 1:
self.do_step2()
elif len(self.choosed_cards) == 2:
self.done()
self.player.choice = self.next_choice


class LosesDivineShield(TargetedAction):
def do(self, source, target):
target.divine_shield = False
self.broadcast(source, EventListener.AFTER, target)
Loading