Skip to content

Commit

Permalink
Knights of the Frozen Throne (#495)
Browse files Browse the repository at this point in the history
* icc

* 冰封王座的骑士 所有中立卡牌

* 冰封王座的骑士 - 德鲁伊

* 冰封王座的骑士 - 猎人(parts)

* 冰封王座的骑士 - Full

* Add test for icc

* Add test for icc
  • Loading branch information
shinoi2 authored Dec 4, 2023
1 parent a5656dc commit f0dd09c
Show file tree
Hide file tree
Showing 54 changed files with 26,961 additions and 2,848 deletions.
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

0 comments on commit f0dd09c

Please sign in to comment.