Giter Site home page Giter Site logo

fireplace's Issues

ValueError: list.remove(x): x not in list

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 527, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 497, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 150, in DoMove
    minion.attack(minion.targets[move[3]])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 368, in attack
    self.game.attack(self, target)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 72, in attack
    return self.queueActions(source, [Attack(source, target)])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 136, in queueActions
    self._processDeaths()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 119, in _processDeaths
    self.queueActions(self, actions)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 132, in queueActions
    ret.append(action.trigger(source, self))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 87, in trigger
    self.do(source, game, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 139, in do
    target.zone = Zone.GRAVEYARD
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 75, in zone
    self._setZone(value)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 518, in _setZone
    super()._setZone(value)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 363, in _setZone
    super()._setZone(zone)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 181, in _setZone
    super()._setZone(zone)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 97, in _setZone
    aura.destroy()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 736, in destroy
    self.game.auras.remove(self)
ValueError: list.remove(x): x not in list
INFO:root:two ends turn 2
INFO:root:one begins turn 3
INFO:root:one is now at 11 mana crystals
INFO:root:Player(name='one', hero=<Hero ('Jaina Proudmoore')>) triggering <TargetedAction: Draw()> targeting [Player(name='one', hero=<Hero ('Jaina Proudmoore')>)]
INFO:root:one draws <Minion ('Bluegill Warrior')>
DEBUG:root:<Minion ('Bluegill Warrior')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:<Minion ('Raid Leader')> attacks <Minion ('Faerie Dragon')>
INFO:root:<Minion ('Raid Leader')> triggering <TargetedAction: Damage(amount=3)> targeting [<Minion ('Faerie Dragon')>]
INFO:root:<Minion ('Faerie Dragon')> damaged for 3 health
INFO:root:<Minion ('Faerie Dragon')> triggering <TargetedAction: Damage(amount=3)> targeting [<Minion ('Raid Leader')>]
INFO:root:<Minion ('Raid Leader')> damaged for 3 health
INFO:root:Destroying buff <Enchantment ('Enhanced')> from <Minion ('Raid Leader')>
DEBUG:root:<Enchantment ('Enhanced')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:<Minion ('Raid Leader')> is removed from the field
INFO:root:<Minion ('Raid Leader')> healed for 3 health
DEBUG:root:<Minion ('Raid Leader')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:Removing <Aura ('CS2_122e')> affecting [<Minion ('Gurubashi Berserker')>, <Minion ('Frostwolf Warlord')>]

card played error

Hi,

Running a test with secretkeeper and seems to run into a CARD_PLAYED error:

    game = prepare_game()
    secretkeeper = game.player1.give("EX1_080")
    secretkeeper.play()
    mirror = game.player2.give("CS2_027")
    mirror.play()

TypeError: CARD_PLAYED() takes 2 positional arguments but 3 were given.

Jaraxxus + Commanding Shout + Wisp

Commanding shout is an aura. Need to check if it's on the hero.

[13:09:01] <jleclanche> cho on the board
[13:09:16] <jleclanche> opponent warrior plays commanding shout
[13:09:25] <jleclanche> then millhouse
[13:09:32] <jleclanche> you (warlock) play jaraxxus, commanding shout, wisp

TypeError: unsupported operand type(s) for *=: 'int' and 'Minion'

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 527, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 497, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 145, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 283, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 178, in play
    return self.game.queueActions(self, [Play(card, target, choose)])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 132, in queueActions
    ret.append(action.trigger(source, self))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 87, in trigger
    self.do(source, game, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 190, in do
    source._play(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 196, in _play
    self.summon(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 174, in summon
    self.game.queueActions(self, [Summon(self, card)])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 132, in queueActions
    ret.append(action.trigger(source, self))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 235, in trigger
    ret.append(self.do(source, game, *extra_args))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 512, in do
    card.summon()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 580, in summon
    super().summon()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 371, in summon
    super().summon()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 188, in summon
    self.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 214, in action
    self.game.queueActions(self, actions)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 132, in queueActions
    ret.append(action.trigger(source, self))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 235, in trigger
    ret.append(self.do(source, game, *extra_args))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 317, in do
    target.draw(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 121, in draw
    ret = self.game.queueActions(self, [Draw(self) * count])[0]
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\actions.py", line 38, in __mul__
    self.times *= value
TypeError: unsupported operand type(s) for *=: 'int' and 'Minion'
INFO:root:one begins turn 11
INFO:root:one is now at 6 mana crystals
INFO:root:Player(name='one', hero=<Hero ('Jaina Proudmoore')>) triggering <TargetedAction: Draw()> targeting [Player(name='one', hero=<Hero ('Jaina Proudmoore')>)]
INFO:root:one draws <Minion ('Gurubashi Berserker')>
DEBUG:root:<Minion ('Gurubashi Berserker')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:one plays <Minion ('Goldshire Footman')> from their hand
INFO:root:Player(name='one', hero=<Hero ('Jaina Proudmoore')>) triggering <TargetedAction: Summon(card=<Minion ('Goldshire Footman')>)> targeting [Player(name='one', hero=<Hero ('Jaina Proudmoore')>)]
INFO:root:one summons <Minion ('Goldshire Footman')>
INFO:root:Summoning <Minion ('Goldshire Footman')>
DEBUG:root:<Minion ('Goldshire Footman')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
DEBUG:root:<Enchantment ('Enhanced')> moves from <Zone.INVALID: 0> to <Zone.SETASIDE: 6>
INFO:root:Applying <Enchantment ('Enhanced')> to <Minion ('Goldshire Footman')>
DEBUG:root:<Enchantment ('Enhanced')> moves from <Zone.SETASIDE: 6> to <Zone.PLAY: 1>
INFO:root:<Minion ('Raid Leader')> attacks <Hero ('Valeera Sanguinar')>
INFO:root:<Minion ('Raid Leader')> triggering <TargetedAction: Damage(amount=2)> targeting [<Hero ('Valeera Sanguinar')>]
INFO:root:<Hero ('Valeera Sanguinar')> damaged for 2 health
INFO:root:one plays <Minion ('Kobold Geomancer')> from their hand
INFO:root:Player(name='one', hero=<Hero ('Jaina Proudmoore')>) triggering <TargetedAction: Summon(card=<Minion ('Kobold Geomancer')>)> targeting [Player(name='one', hero=<Hero ('Jaina Proudmoore')>)]
INFO:root:one summons <Minion ('Kobold Geomancer')>
INFO:root:Summoning <Minion ('Kobold Geomancer')>
DEBUG:root:<Minion ('Kobold Geomancer')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
DEBUG:root:<Enchantment ('Enhanced')> moves from <Zone.INVALID: 0> to <Zone.SETASIDE: 6>
INFO:root:Applying <Enchantment ('Enhanced')> to <Minion ('Kobold Geomancer')>
DEBUG:root:<Enchantment ('Enhanced')> moves from <Zone.SETASIDE: 6> to <Zone.PLAY: 1>
INFO:root:one plays hero power <HeroPower ('Fireblast')>
INFO:root:<HeroPower ('Fireblast')> triggering <TargetedAction: Hit(amount=1)> targeting [<Hero ('Jaina Proudmoore')>]
INFO:root:<HeroPower ('Fireblast')> triggering <TargetedAction: Damage(amount=1)> targeting [<Hero ('Jaina Proudmoore')>]
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 1 health
INFO:root:one ends turn 11
INFO:root:two begins turn 12
INFO:root:two is now at 6 mana crystals
INFO:root:Player(name='two', hero=<Hero ('Valeera Sanguinar')>) triggering <TargetedAction: Draw()> targeting [Player(name='two', hero=<Hero ('Valeera Sanguinar')>)]
INFO:root:two draws <Minion ('Magma Rager')>
DEBUG:root:<Minion ('Magma Rager')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two plays <Minion ('Piloted Shredder')> from their hand
INFO:root:Player(name='two', hero=<Hero ('Valeera Sanguinar')>) triggering <TargetedAction: Summon(card=<Minion ('Piloted Shredder')>)> targeting [Player(name='two', hero=<Hero ('Valeera Sanguinar')>)]
INFO:root:two summons <Minion ('Piloted Shredder')>
INFO:root:Summoning <Minion ('Piloted Shredder')>
DEBUG:root:<Minion ('Piloted Shredder')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Minion ("Captain's Parrot")> from their hand
INFO:root:Player(name='two', hero=<Hero ('Valeera Sanguinar')>) triggering <TargetedAction: Summon(card=<Minion ("Captain's Parrot")>)> targeting [Player(name='two', hero=<Hero ('Valeera Sanguinar')>)]
INFO:root:two summons <Minion ("Captain's Parrot")>
INFO:root:Summoning <Minion ("Captain's Parrot")>
DEBUG:root:<Minion ("Captain's Parrot")> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Minion ("Captain's Parrot")> action targeting None
INFO:root:<Minion ("Captain's Parrot")> triggering <TargetedAction: ForceDraw(cards=<Selector: DECK FRIENDLY and PIRATE and>)> targeting [Player(name='two', hero=<Hero ('Valeera Sanguinar')>)]

Implement Weapon sheathing

Hi,

I ran the following test:

    game = prepare_game()
    waraxe = game.player1.give("CS2_106")
    waraxe.play()
    game.endTurn()
    tinker = game.player2.give("GVG_102")
    print(tinker.health)
    tinker.attack(game.player1.hero)
    print(tinker.health)

tinker health is 3 and then 0. It should be 3 and then 3 as player2's minion should not receive damage from player1s weapon. However, the weapon correctly does not lose durability due to the tinker's attack.

felcannon

Hey,

I think the felcannon has a 2 hit left out.

# Fel Cannon
class GVG_020:
    OWN_TURN_END = [Hit(RANDOM_MINION - MECH)]

Thanks!

'Spell' object has no attribute 'race'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['EX1_009', 'CS2_226', 'GVG_064', 'EX1_556', 'CS2_118', 'EX1_586', 'EX1_572', 'NEW1_016', 'EX1_507', 'GVG_111', 'NEW1_040', 'GVG_092', 'EX1_128', 'EX1_561', 'CS2_120', 'NEW1_025', 'GVG_013', 'EX1_015', 'GVG_098', 'CS2_155', 'NEW1_029', 'CS2_181', 'GVG_112', 'GVG_013', 'GVG_107', 'CS2_196', 'EX1_021', 'EX1_043', 'CS2_189', 'GVG_093']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 527, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 497, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 145, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 245, in _play
    card.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 219, in action
    func(self, **kwargs)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\neutral_epic.py", line 39, in action
    pirates = self.controller.deck.filter(race=Race.PIRATE)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\utils.py", line 35, in filter
    return self.__class__(e for k, v in kwargs.items() for e in self if getattr(e, k) == v)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\deck.py", line 15, in __init__
    super().__init__(cards or [])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\utils.py", line 35, in <genexpr>
    return self.__class__(e for k, v in kwargs.items() for e in self if getattr(e, k) == v)
AttributeError: 'Spell' object has no attribute 'race'
INFO:root:two begins turn 12
INFO:root:two is now at 6 mana crystals
DEBUG:root:<Minion ('Gnomish Experimenter')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two draws <Minion ('Gnomish Experimenter')>
INFO:root:two plays <Minion ('Enhance-o Mechano')> from their hand
DEBUG:root:two summons <Minion ('Enhance-o Mechano')>
INFO:root:Summoning <Minion ('Enhance-o Mechano')>
DEBUG:root:<Minion ('Enhance-o Mechano')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:<Minion ('Harvest Golem')> attacks <Hero ('Jaina Proudmoore')>
INFO:root:<Minion ('Harvest Golem')> hits <Hero ('Jaina Proudmoore')> for 2
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 2 health
INFO:root:two plays <Minion ("Captain's Parrot")> from their hand
DEBUG:root:two summons <Minion ("Captain's Parrot")>
INFO:root:Summoning <Minion ("Captain's Parrot")>
DEBUG:root:<Minion ("Captain's Parrot")> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Minion ("Captain's Parrot")> action targeting None

infinite loop

Hey,

Was able to create an infinite loop case using reversing switch and printing attack. Here's the test case:

    GOLDSHIRE = "CS1_042"
    REVERSE = "PART_006"
    game = prepare_game()
    minion1 = game.player1.give(GOLDSHIRE)
    spell1 = game.player1.give(REVERSE)
    minion1.play()
    spell1.play(minion1)
    print(minion1.atk)

webspinner deathrattle issue

Webspinner FP1_011 in the enUS.xml does not contain an entourage list for its deathrattle, so the random summon will error out on selecting random from an empty list. I think the webspinner needs to generate a list of "collectible" beasts instead.

knife juggler issue

Knife juggler should not hit when it is summoned. In addition, the potential targets has a typo

# Knife Juggler
class NEW1_019:
    def OWN_MINION_SUMMON(self, minion):
        if minion is not self :
            self.hit(random.choice(self.controller.getTargets(TARGET_ENEMY_CHARACTERS)), 1)

On the same note, mass dispell also has a typo

# Mass Dispel
class EX1_626:
    def action(self):
        for target in self.controller.getTargets(TARGET_ENEMY_MINIONS):
            target.silence()
        self.controller.draw()

floating watcher issue

Hey,

I was testing floating watcher and hit the following error using this test case:

TypeError: <lambda>() takes 3 positional arguments but 4 were given

WATCHER = "GVG_100"
def test_watcher() :
        game = prepare_game(WARLOCK,WARLOCK)
        watcher = game.player1.give(WATCHER)
        watcher.play()
        game.endTurn();game.endTurn()
        assert(watcher.atk==4)
        game.player1.hero.power.play()
        assert(watcher.atk==6)
        assert(watcher.atk==6)

I think the lambda function requires 4 arguments (aka lambda self, target, amount, source:). Thanks!

battlecry with empty targets

Minions with battlecries that target minions can be played without a target if none are present.

def test_empty_shattered() :
    game = prepare_game()
    shattered = game.player1.give("EX1_019")
    shattered.play()
    game.endTurn()

However, the following test leads to the error:

AttributeError: 'NoneType' object has no attribute 'buffs'

I think having a target == None check in the utils.py for buffTarget would enable these battlecry minions to be played with an empty target.

druid morph issues

Hey,

I was seeing some issues with druid choice cards such as Druid of the Claw (EX1_165). It looks like once you make the choice to like EX1_165b which is a Spell card, you then call MORPH on the spell card. However, Spells do not have the morph attribute only Minions do. I encountered this issue on an earlier commit but I think it should still happen on the latest build. Let me know thanks!

Missing Auras

Hi,

I think there may be a few auras that are not implemented yet (not sure if it was intentional). I ran the following code to check for cards with AURA=1 without an associated aura card.

    import fireplace.cards
    game = prepare_game()
    for cardid in fireplace.cards.filter(collectible=True) :
        if Card(cardid).aura and not Card(cardid).data.auras:
            card = Card(cardid)
            print(cardid)   

It looks like most are there except for the following :

GVG_095 = Goblin Sapper
EX1_591 = Auchenai Soulpriest
GVG_024 = Cogmaster's Wrench
GVG_122 = Wee Spellstopper
GVG_013 = Cogmaster

It seems like the Soulpriest aura may require some work to rebroadcast DAMAGE instead of HEAL (i.e., infinite death combo with soulpriest + mistress of pain). In addition, "+ spell damage" appears to boost the heal "damage" when this aura is active.

'Weapon' object has no attribute 'race'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['GVG_097', 'FP1_024', 'EX1_522', 'EX1_021', 'EX1_067', 'GVG_111', 'EX1_080', 'CS2_222', 'FP1_005', 'EX1_002', 'EX1_009', 'NEW1_041', 'EX1_577', 'CS2_162', 'EX1_089', 'EX1_032', 'CS2_151', 'BRM_007', 'EX1_508', 'EX1_028', 'GVG_095', 'CS2_127', 'GVG_070', 'CS2_151', 'NEW1_017', 'EX1_563', 'EX1_019', 'EX1_110', 'EX1_586', 'EX1_017']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 532, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 502, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 146, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 230, in _play
    self.summon(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 208, in summon
    card.summon()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 593, in summon
    self.game.broadcast("MINION_SUMMON", self.controller, self)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 31, in broadcast
    self.broadcast("UPDATE")
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 181, in UPDATE
    aura.update()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 733, in update
    if self.isValidTarget(target):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 695, in isValidTarget
    return targeting.isValidTarget(self.source, target, requirements=self.requirements)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\targeting.py", line 83, in isValidTarget
    if target.race != param:
AttributeError: 'Weapon' object has no attribute 'race'
DEBUG:root:two summons <Enchantment ('Might of Stormwind')>
INFO:root:Summoning <Enchantment ('Might of Stormwind')>
DEBUG:root:<Enchantment ('Might of Stormwind')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:Applying <Enchantment ('Might of Stormwind')> to <Minion ('Sunwalker')>
INFO:root:<Minion ('Stormwind Champion')> attacks <Hero ('Jaina Proudmoore')>
INFO:root:<Minion ('Stormwind Champion')> hits <Hero ('Jaina Proudmoore')> for 6
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 6 health
INFO:root:<Minion ('Goblin Sapper')> attacks <Hero ('Jaina Proudmoore')>
INFO:root:<Minion ('Goblin Sapper')> hits <Hero ('Jaina Proudmoore')> for 3
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 3 health
INFO:root:two plays <Minion ('Grimscale Oracle')> from their hand
DEBUG:root:two summons <Minion ('Grimscale Oracle')>
INFO:root:Summoning <Minion ('Grimscale Oracle')>
DEBUG:root:<Minion ('Grimscale Oracle')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Summoning Aura <fireplace.card.Aura object at 0x0000000004D319B0>
DEBUG:root:two summons <Enchantment ('Might of Stormwind')>
INFO:root:Summoning <Enchantment ('Might of Stormwind')>
DEBUG:root:<Enchantment ('Might of Stormwind')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:Applying <Enchantment ('Might of Stormwind')> to <Minion ('Grimscale Oracle')>

lightwell

Lightwell needs a targets empty check so that you do not random.choice with none.

# Lightwell
class EX1_341:
    def OWN_TURN_BEGIN(self):
        targets = [t for t in self.controller.getTargets(TARGET_FRIENDLY_CHARACTERS) if t.damage]
        if targets :
            self.heal(random.choice(targets), 3)

buff() missing 1 required positional argument: 'buff'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['EX1_412', 'GVG_089', 'GVG_074', 'GVG_117', 'EX1_004', 'GVG_121', 'GVG_110', 'GVG_079', 'CS2_117', 'EX1_145', 'BRM_030', 'EX1_043', 'EX1_390', 'CS2_213', 'GVG_022', 'EX1_004', 'GVG_090', 'EX1_043', 'CS2_227', 'EX1_005', 'EX1_562', 'GVG_109', 'EX1_032', 'GVG_090', 'EX1_028', 'FP1_008', 'CS2_146', 'GVG_084', 'EX1_007', 'CS2_197']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 537, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 507, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 142, in DoMove
    self.game.endTurn()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 153, in endTurn
    self.broadcast("TURN_END", self.currentPlayer)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 211, in TURN_END
    player.broadcast("OWN_TURN_END")
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 265, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 60, in <lambda>
    _func = lambda *args: func(self, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\neutral_rare.py", line 16, in OWN_TURN_END
    target.buff("EX1_004e")
TypeError: buff() missing 1 required positional argument: 'buff'

'Aura' object has no attribute '_buffed'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['EX1_399', 'EX1_506', 'EX1_508', 'CS2_075', 'NEW1_017', 'EX1_562', 'EX1_112', 'BRM_008', 'CS2_146', 'GVG_102', 'CS2_221', 'CS2_077', 'NEW1_024', 'EX1_509', 'GVG_078', 'EX1_004', 'EX1_405', 'CS2_182', 'GVG_090', 'GVG_081', 'EX1_144', 'GVG_044', 'EX1_522', 'EX1_405', 'GVG_006', 'GVG_023', 'GVG_082', 'GVG_095', 'EX1_595', 'CS2_182']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 527, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 497, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 147, in DoMove
    card.play(target=card.targets[move[3]])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 245, in _play
    card.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 219, in action
    func(self, **kwargs)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\utils.py", line 35, in <lambda>
    bounceTarget = lambda self, target: target.bounce()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 544, in bounce
    self.zone = Zone.HAND
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 87, in zone
    self._setZone(value)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 530, in _setZone
    aura.destroy()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 747, in destroy
    logging.info("Removing %r affecting %r" % (self, self._buffed))
AttributeError: 'Aura' object has no attribute '_buffed'
INFO:root:two begins turn 20
INFO:root:two is now at 10 mana crystals
DEBUG:root:<Minion ('Madder Bomber')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two draws <Minion ('Madder Bomber')>
INFO:root:two plays <Minion ('Grimscale Oracle')> from their hand
DEBUG:root:two summons <Minion ('Grimscale Oracle')>
INFO:root:Summoning <Minion ('Grimscale Oracle')>
DEBUG:root:<Minion ('Grimscale Oracle')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Summoning Aura <fireplace.card.Aura object at 0x00000000047ADDD8>
INFO:root:two plays hero power <HeroPower ('Dagger Mastery')>
INFO:root:Activating <HeroPower ('Dagger Mastery')> action targeting None
DEBUG:root:two summons <Weapon ('Wicked Knife')>
INFO:root:Summoning <Weapon ('Wicked Knife')>
DEBUG:root:<Weapon ('Wicked Knife')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:two plays <Minion ('Madder Bomber')> from their hand
DEBUG:root:two summons <Minion ('Madder Bomber')>
INFO:root:Summoning <Minion ('Madder Bomber')>
DEBUG:root:<Minion ('Madder Bomber')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:<Minion ('Southsea Deckhand')> attacks <Minion ('Booty Bay Bodyguard')>
INFO:root:<Minion ('Southsea Deckhand')> hits <Minion ('Booty Bay Bodyguard')> for 2
INFO:root:<Minion ('Booty Bay Bodyguard')> damaged for 2 health
INFO:root:<Minion ('Booty Bay Bodyguard')> hits <Minion ('Southsea Deckhand')> for 5
INFO:root:<Minion ('Southsea Deckhand')> damaged for 5 health
INFO:root:<Minion ('Booty Bay Bodyguard')> dies
INFO:root:<Minion ('Booty Bay Bodyguard')> is removed from the field
INFO:root:<Minion ('Booty Bay Bodyguard')> healed for 4 health
DEBUG:root:<Minion ('Booty Bay Bodyguard')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:<Minion ('Southsea Deckhand')> dies
INFO:root:<Minion ('Southsea Deckhand')> is removed from the field
INFO:root:<Minion ('Southsea Deckhand')> healed for 5 health
DEBUG:root:<Minion ('Southsea Deckhand')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:two plays <Minion ('Patient Assassin')> from their hand
DEBUG:root:two summons <Minion ('Patient Assassin')>
INFO:root:Summoning <Minion ('Patient Assassin')>
DEBUG:root:<Minion ('Patient Assassin')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Spell ('Time Rewinder')> from their hand
DEBUG:root:two summons <Spell ('Time Rewinder')>
INFO:root:Summoning <Spell ('Time Rewinder')>
DEBUG:root:<Spell ('Time Rewinder')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Spell ('Time Rewinder')> action targeting <Minion ('Grimscale Oracle')>
INFO:root:<Minion ('Grimscale Oracle')> is bounced back to two's hand
INFO:root:<Minion ('Grimscale Oracle')> is removed from the field

issue with enrage mechanic

Hi, I am new to your code but I am having some issues getting the attack from enrages from showing up. For example, I was creating an Amani Berserker (CardID=EX1_393) for player1 and player2 and having one attack the other.

    game = prepare_game(WARLOCK, WARLOCK)
    amani1 = game.currentPlayer.give("EX1_393")
    amani1.play()
    game.currentPlayer.field.append(amani1)
    game.endTurn()

    amani2 = game.currentPlayer.give("EX1_393")
    amani2.play()
    game.currentPlayer.field.append(amani2)
    game.endTurn()        

    print(amani2.atk,amani2.extraAtk,amani2.health)
>> 2 0 3
    amani1.attack(amani2)
    print(amani2.atk,amani2.extraAtk,amani2.health)
>> 2 0 1
    print(amani2.slots)
>> [<Enrage ('Enrage Buff')>]

    game.endTurn()

I would have expected the amani2.extraAtk to pick up the Atk=3 in the Enrage class.

aura destroy issues

Hi,

I am currently running the following test case as I was hitting some issues with aura removes. In the test case, I created two Timber Wolfs for player1 and had player2 moonfire both.

    game = prepare_game()
    timber1 = game.player1.give("DS1_175")
    timber2 = game.player1.give("DS1_175")
    timber1.play()
    timber2.play()
    game.endTurn();
    moonfire1 = game.player2.give("CS2_008") 
    moonfire2 = game.player2.give("CS2_008")
    print([card.atk for card in game.player1.field])
    moonfire1.play(timber1)
    print([card.atk for card in game.player1.field])
    moonfire2.play(timber2)

During the second moonfire, I get a ValueError during the aura destroy. Currently trying to see if I can characterize the error further. Let me know if you need more information or if I may have set up the test case incorrectly. Thanks!

tests/full_game.py doesn't run

  1. Import errors:
./full_game.py
Traceback (most recent call last):
  File "./full_game.py", line 48, in <module>
    main()
  File "./full_game.py", line 11, in main
    deck1 = randomDraft(hero=fireplace.heroes.MAGE)
AttributeError: 'module' object has no attribute 'heroes'
  1. line 17: 'game' variable shadows the module name
  2. lines 13,14: Player constructor doesn't accept a deck

I'm submitting a pull request that fixes these problems. The test now runs for 5 turns before throwing this exception. (I'm brand new to the codebase - haven't dug deeper.)

Traceback (most recent call last):
  File "full_game.py", line 53, in <module>
    main()
  File "full_game.py", line 49, in main
    gm.endTurn()
  File "../fireplace/game.py", line 186, in endTurn
    self.broadcast("TURN_END", self.currentPlayer)
  File "../fireplace/game.py", line 209, in broadcast
    super().broadcast(event, *args)
  File "../fireplace/entity.py", line 24, in broadcast
    f(*args)
  File "../fireplace/game.py", line 231, in TURN_END
    player.broadcast("OWN_TURN_END")
  File "../fireplace/player.py", line 260, in broadcast
    super().broadcast(event, *args)
  File "../fireplace/entity.py", line 24, in broadcast
    f(*args)
  File "../fireplace/card.py", line 66, in _func
    self.game.queueActions(self, actions)
  File "../fireplace/game.py", line 138, in queueActions
    action.trigger(source, self)
  File "../fireplace/actions.py", line 31, in trigger
    targets = self.eval(self.target, source, game)
  File "../fireplace/actions.py", line 28, in eval
    return selector.eval(game, source)
  File "../fireplace/targeting.py", line 156, in eval
    result += [e for e in entities if self.test(e, source)]
  File "../fireplace/targeting.py", line 156, in <listcomp>
    result += [e for e in entities if self.test(e, source)]
  File "../fireplace/targeting.py", line 202, in test
    op(self, stack)
  File "../fireplace/targeting.py", line 211, in _and
    b = stack.pop()
IndexError: pop from empty list

'NoneType' object has no attribute 'type'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['NEW1_022', 'EX1_616', 'EX1_170', 'CS2_119', 'EX1_144', 'GVG_093', 'FP1_001', 'EX1_025', 'GVG_090', 'NEW1_019', 'EX1_507', 'BRM_008', 'GVG_079', 'EX1_131', 'FP1_017', 'GVG_115', 'CS2_186', 'BRM_008', 'CS2_141', 'CS2_221', 'FP1_009', 'EX1_066', 'CS2_142', 'CS2_186', 'CS2_074', 'GVG_075', 'BRM_025', 'EX1_283', 'CS2_131', 'EX1_509']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 530, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 500, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 144, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 274, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 204, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 237, in _play
    card.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 219, in action
    func(self, **kwargs)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\rogue.py", line 52, in action
    self.buff(self.controller.weapon, "CS2_074e")
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 148, in buff
    ret.apply(target)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 651, in apply
    if target.type == CardType.WEAPON and getattr(self, "durability", 0):
AttributeError: 'NoneType' object has no attribute 'type'

KeyError: <GameTag.Collectible: 321>

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['CS2_187', 'PRO_001', 'NEW1_037', 'EX1_043', 'EX1_009', 'EX1_283', 'GVG_091', 'CS2_173', 'EX1_096', 'NEW1_027', 'EX1_020', 'CS2_125', 'FP1_007', 'EX1_103', 'EX1_562', 'FP1_009', 'EX1_062', 'CS2_161', 'GVG_109', 'FP1_003', 'GVG_084', 'BRM_007', 'CS2_233', 'EX1_032', 'EX1_506', 'GVG_024', 'EX1_616', 'GVG_104', 'BRM_022', 'EX1_508']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 527, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 497, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 135, in DoMove
    self.game.endTurn()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 153, in endTurn
    self.broadcast("TURN_END", self.currentPlayer)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 211, in TURN_END
    player.broadcast("OWN_TURN_END")
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 273, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 60, in <lambda>
    _func = lambda *args: func(self, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\neutral_rare.py", line 186, in OWN_TURN_END
    self.buff(target, "NEW1_037e")
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 147, in buff
    ret = self.controller.summon(buff)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 205, in summon
    card = self.game.card(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 100, in card
    card = Card(id)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 29, in Card
    return subclass(id, data)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 640, in __init__
    super().__init__(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 51, in __init__
    self.tags.update(data.tags)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\managers.py", line 32, in update
    if self.map[k]:
KeyError: <GameTag.Collectible: 321>
DEBUG:root:two summons <Minion ('Nerubian Egg')>
INFO:root:Summoning <Minion ('Nerubian Egg')>
DEBUG:root:<Minion ('Nerubian Egg')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Minion ('Loot Hoarder')> from their hand
DEBUG:root:two summons <Minion ('Loot Hoarder')>
INFO:root:Summoning <Minion ('Loot Hoarder')>
DEBUG:root:<Minion ('Loot Hoarder')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Minion ('Twilight Drake')> from their hand
DEBUG:root:two summons <Minion ('Twilight Drake')>
INFO:root:Summoning <Minion ('Twilight Drake')>
DEBUG:root:<Minion ('Twilight Drake')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Minion ('Twilight Drake')> action targeting None
DEBUG:root:two summons <Enchantment ('Hour of Twilight')>
INFO:root:Summoning <Enchantment ('Hour of Twilight')>
DEBUG:root:<Enchantment ('Hour of Twilight')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:Applying <Enchantment ('Hour of Twilight')> to <Minion ('Twilight Drake')>
DEBUG:root:two summons <Enchantment ('Hour of Twilight')>
INFO:root:Summoning <Enchantment ('Hour of Twilight')>
DEBUG:root:<Enchantment ('Hour of Twilight')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:Applying <Enchantment ('Hour of Twilight')> to <Minion ('Twilight Drake')>
DEBUG:root:two summons <Enchantment ('Hour of Twilight')>
INFO:root:Summoning <Enchantment ('Hour of Twilight')>
DEBUG:root:<Enchantment ('Hour of Twilight')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:Applying <Enchantment ('Hour of Twilight')> to <Minion ('Twilight Drake')>
INFO:root:two plays <Minion ('Master Swordsmith')> from their hand
DEBUG:root:two summons <Minion ('Master Swordsmith')>
INFO:root:Summoning <Minion ('Master Swordsmith')>
DEBUG:root:<Minion ('Master Swordsmith')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:<Minion ('Flying Machine')> attacks <Hero ('Jaina Proudmoore')>
INFO:root:<Minion ('Flying Machine')> hits <Hero ('Jaina Proudmoore')> for 1
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 1 health
INFO:root:two ends turn

animal companion entourage issue

Hey,

I get the following error playing Animal Companion (NEW1_031):

  File "C:\Python34\lib\site-packages\fireplace-0.1-py3.4.egg\fireplace\cards\classic\hunter.py", line 120, in action
    self.controller.summon(random.choice(self.entourage))
AttributeError: 'Spell' object has no attribute 'entourage'

Seems like entourage cards are there in the xml files.

'int' object is not callable

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['NEW1_004', 'EX1_033', 'CS2_147', 'GVG_091', 'EX1_096', 'EX1_126', 'PRO_001', 'NEW1_041', 'EX1_085', 'GVG_108', 'EX1_396', 'EX1_562', 'GVG_113', 'EX1_025', 'BRM_019', 'GVG_047', 'EX1_059', 'EX1_009', 'FP1_028', 'CS2_155', 'EX1_581', 'GVG_024', 'GVG_084', 'EX1_059', 'EX1_393', 'GVG_097', 'EX1_067', 'tt_004', 'NEW1_021', 'EX1_009']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 538, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 508, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 155, in DoMove
    card.play(target=card.targets[move[3]])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 245, in _play
    card.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 219, in action
    func(self, **kwargs)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\neutral_legendary.py", line 222, in action
    target.damage(4)
TypeError: 'int' object is not callable
INFO:root:two begins turn 16
INFO:root:two is now at 8 mana crystals
DEBUG:root:<Minion ('Doomsayer')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two draws <Minion ('Doomsayer')>
INFO:root:two plays <Minion ('Arcane Nullifier X-21')> from their hand
DEBUG:root:two summons <Minion ('Arcane Nullifier X-21')>
INFO:root:Summoning <Minion ('Arcane Nullifier X-21')>
DEBUG:root:<Minion ('Arcane Nullifier X-21')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Spell ('Rogues Do It...')> from their hand
DEBUG:root:two summons <Spell ('Rogues Do It...')>
INFO:root:Summoning <Spell ('Rogues Do It...')>
DEBUG:root:<Spell ('Rogues Do It...')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Spell ('Rogues Do It...')> action targeting <Hero ('Jaina Proudmoore')>

unsupported operand type(s) for -=: 'Minion' and 'int'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['FP1_031', 'CS2_171', 'EX1_093', 'FP1_007', 'NEW1_016', 'EX1_017', 'EX1_283', 'GVG_093', 'GVG_094', 'GVG_108', 'tt_004', 'CS2_118', 'CS2_146', 'FP1_024', 'CS2_072', 'FP1_014', 'GVG_116', 'EX1_562', 'BRM_026', 'CS2_222', 'CS2_227', 'GVG_025', 'EX1_062', 'EX1_014', 'GVG_099', 'GVG_097', 'CS2_169', 'BRM_025', 'EX1_023', 'EX1_043']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 532, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 502, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 146, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 204, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 237, in _play
    card.action()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 219, in action
    func(self, **kwargs)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\classic\neutral_epic.py", line 41, in action
    self.controller.draw(random.choice(pirates))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 149, in draw
    count -= 1
TypeError: unsupported operand type(s) for -=: 'Minion' and 'int'
DEBUG:root:two summons <Weapon ('Wicked Knife')>
INFO:root:Summoning <Weapon ('Wicked Knife')>
DEBUG:root:<Weapon ('Wicked Knife')> moves from <Zone.INVALID: 0> to <Zone.PLAY: 1>
INFO:root:<Weapon ('Wicked Knife')> dies
DEBUG:root:<Weapon ('Wicked Knife')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:<Hero ('Valeera Sanguinar')> attacks <Hero ('Jaina Proudmoore')>
INFO:root:<Weapon ('Wicked Knife')> loses 1 point of durability
INFO:root:<Hero ('Valeera Sanguinar')> hits <Hero ('Jaina Proudmoore')> for 1
INFO:root:<Hero ('Jaina Proudmoore')> damaged for 1 health
INFO:root:two plays <Minion ('Jeeves')> from their hand
DEBUG:root:two summons <Minion ('Jeeves')>
INFO:root:Summoning <Minion ('Jeeves')>
DEBUG:root:<Minion ('Jeeves')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:two plays <Minion ("Captain's Parrot")> from their hand
DEBUG:root:two summons <Minion ("Captain's Parrot")>
INFO:root:Summoning <Minion ("Captain's Parrot")>
DEBUG:root:<Minion ("Captain's Parrot")> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>
INFO:root:Activating <Minion ("Captain's Parrot")> action targeting None
DEBUG:root:<Minion ('Southsea Deckhand')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two draws <Minion ('Southsea Deckhand')>

issue with adjacent minions

Hey,

I'll look into joining the irc channel. I was running the following test and hit "AssertionError: Zone.GRAVEYARD". The error looks like it has to do with the zone assertion in the adjacentMinions function.

    game = prepare_game()
    dire1 = game.player1.give("EX1_162")
    dire2 = game.player1.give("EX1_162")
    dire1.play()
    dire2.play()
    game.endTurn();
    yeti = game.player2.give("GVG_078")
    yeti.play()
    yeti.attack(dire2)

Interestingly enough, if the yeti attack dire1, the assert is not triggered.

OWN_MINION_SUMMON() missing 1 required positional argument: 'minion'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['CS2_182', 'CS2_118', 'GVG_067', 'GVG_071', 'CS2_119', 'EX1_509', 'BRM_007', 'GVG_025', 'EX1_008', 'BRM_028', 'EX1_059', 'GVG_013', 'EX1_009', 'EX1_134', 'EX1_021', 'NEW1_004', 'GVG_084', 'GVG_013', 'EX1_563', 'EX1_080', 'GVG_103', 'NEW1_040', 'GVG_082', 'CS2_131', 'CS2_161', 'EX1_067', 'CS2_226', 'EX1_017', 'GVG_089', 'GVG_016']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 530, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 500, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 145, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 230, in _play
    self.summon(card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 208, in summon
    card.summon()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 593, in summon
    self.game.broadcast("MINION_SUMMON", self.controller, self)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 342, in MINION_SUMMON
    minion.controller.broadcast("OWN_MINION_SUMMON", minion)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 273, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 60, in <lambda>
    _func = lambda *args: func(self, *args)
TypeError: OWN_MINION_SUMMON() missing 1 required positional argument: 'minion'
INFO:root:two begins turn 12
INFO:root:two is now at 6 mana crystals
DEBUG:root:<Minion ('Cogmaster')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:two draws <Minion ('Cogmaster')>
INFO:root:<Minion ('Frostwolf Warlord')> attacks <Minion ('Raid Leader')>
INFO:root:<Minion ('Frostwolf Warlord')> hits <Minion ('Raid Leader')> for 6
INFO:root:<Minion ('Raid Leader')> damaged for 6 health
INFO:root:<Minion ('Raid Leader')> hits <Minion ('Frostwolf Warlord')> for 2
INFO:root:<Minion ('Frostwolf Warlord')> damaged for 2 health
INFO:root:<Minion ('Raid Leader')> dies
INFO:root:<Minion ('Raid Leader')> is removed from the field
INFO:root:Removing <fireplace.card.Aura object at 0x00000000065E4080> affecting [<Minion ('Darkscale Healer')>]
INFO:root:Destroying buff <Enchantment ('Enhanced')> from <Minion ('Darkscale Healer')>
INFO:root:<Minion ('Raid Leader')> healed for 6 health
DEBUG:root:<Minion ('Raid Leader')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:two plays <Minion ('One-eyed Cheat')> from their hand
DEBUG:root:two summons <Minion ('One-eyed Cheat')>
INFO:root:Summoning <Minion ('One-eyed Cheat')>
DEBUG:root:<Minion ('One-eyed Cheat')> moves from <Zone.HAND: 3> to <Zone.PLAY: 1>

buff() missing 1 required positional argument: 'buff'

Deck 1: ['EX1_508', 'CS2_226', 'CS2_142', 'EX1_011', 'CS1_042', 'EX1_011', 'CS2_197', 'EX1_399', 'CS2_173', 'CS2_023', 'CS1_042', 'CS2_122', 'CS2_120', 'DS1_055', 'CS2_162', 'CS2_187', 'CS2_120', 'CS2_141', 'DS1_055', 'CS2_032', 'CS2_127', 'CS2_029', 'CS2_173', 'EX1_399', 'EX1_066', 'EX1_508', 'CS2_026', 'CS2_122', 'CS2_171', 'CS2_187']

Deck 2: ['CS2_074', 'NEW1_023', 'EX1_059', 'CS2_117', 'CS2_189', 'FP1_008', 'EX1_564', 'EX1_128', 'EX1_126', 'CS2_120', 'GVG_013', 'CS2_169', 'GVG_067', 'EX1_145', 'CS2_073', 'EX1_561', 'CS2_161', 'CS2_169', 'FP1_016', 'EX1_048', 'CS2_124', 'CS2_196', 'BRM_019', 'CS2_161', 'FP1_024', 'GVG_102', 'FP1_001', 'EX1_100', 'CS2_172', 'EX1_029']

Traceback (most recent call last):
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 530, in UCTPlayGame
    m = UCT(rootstate = state, seconds = 10, verbose = False)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 500, in UCT
    state.DoMove(random.choice(state.GetMoves()))
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\mcts\uct.py", line 145, in DoMove
    card.play()
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 277, in play
    self.controller.play(self, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 212, in play
    self.game.action(PowSubType.PLAY, self, card, target, choose)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 54, in action
    args[0]._play(*args[1:])
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\player.py", line 220, in _play
    self.game.broadcast("CARD_PLAYED", self, card)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\game.py", line 177, in broadcast
    super().broadcast(event, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\entity.py", line 24, in broadcast
    f(*args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\card.py", line 60, in <lambda>
    _func = lambda *args: func(self, *args)
  File "C:\Users\Ragowit\Documents\GitHub\fireplace\fireplace\cards\gvg\neutral_common.py", line 19, in CARD_PLAYED
    self.buff("GVG_067a")
TypeError: buff() missing 1 required positional argument: 'buff'
INFO:root:one begins turn 25
INFO:root:one is now at 11 mana crystals
DEBUG:root:<Spell ('Frost Nova')> moves from <Zone.DECK: 2> to <Zone.HAND: 3>
INFO:root:one draws <Spell ('Frost Nova')>
INFO:root:one plays hero power <HeroPower ('Fireblast')>
INFO:root:Activating <HeroPower ('Fireblast')> action targeting <Minion ('Alexstrasza')>
INFO:root:<HeroPower ('Fireblast')> hits <Minion ('Alexstrasza')> for 1
INFO:root:<Minion ('Alexstrasza')> damaged for 1 health
INFO:root:<Minion ('Voodoo Doctor')> attacks <Minion ('Alexstrasza')>
INFO:root:<Minion ('Voodoo Doctor')> hits <Minion ('Alexstrasza')> for 2
INFO:root:<Minion ('Alexstrasza')> damaged for 2 health
INFO:root:<Minion ('Alexstrasza')> hits <Minion ('Voodoo Doctor')> for 8
INFO:root:<Minion ('Voodoo Doctor')> damaged for 8 health
INFO:root:<Minion ('Voodoo Doctor')> dies
INFO:root:<Minion ('Voodoo Doctor')> is removed from the field
INFO:root:<Minion ('Voodoo Doctor')> healed for 8 health
DEBUG:root:<Minion ('Voodoo Doctor')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:<Minion ('Alexstrasza')> dies
INFO:root:<Minion ('Alexstrasza')> is removed from the field
INFO:root:<Minion ('Alexstrasza')> healed for 10 health
DEBUG:root:<Minion ('Alexstrasza')> moves from <Zone.PLAY: 1> to <Zone.GRAVEYARD: 4>
INFO:root:one plays <Spell ('Frost Nova')> from their hand

Crazed Alchemist + Damage + silence

[16:33:53] Xinhuan: did u remember the thread about how silence works on a minion that had been crazed alchemist and took damage?
[16:34:03] Xinhuan: and how the current HP gets adjusted
[16:35:15] Xinhuan: for example, a 2/5 gets swapped to a 5/2, takes 1 damage becomes a 5/1, if its silenced then, it becomes a 2/4

some minor issues

Hey,

The new tag push seems to be pretty good although I hit a few minor issues during my testing. Below, I posted some quick fixes that seemed to make my code work again as a couple of the attributes seem to be missing in the latest commit:

  1. In card.py, the Character class should probably be initialized with self.numAttacks = 0 (hit a few errors not finding that attribute during Minion attacks). The BaseCard class should probably have self.secret = False (secretkeeper will error when a non-secret was played)

  2. In player.py the Player class should probably be initialized with self.usedMana = 0, self.combo = False, self.minionsPlayedThisTurn = 0.

  3. In targeting.py, I was hitting an issue where a weapon's race was being checked so maybe checking that the 'race' attribute is available or the target is a Minion before checking for race is needed.

  4. In cards/utils.py, healHero(amount) should be applied to self.controller.hero rather than hero.

  5. In cards/classic/druid.py, the buffSelf(self, "**") should be changed to buffSelf("**") for Claw and Bite; and replace character to target in self.hit(target,5) in Starfire.

  6. In cards/classic/warrior.py, the Frothing Beserker action should be OWN_DAMAGE not DAMAGE

  7. In cards/gvg/hunter.py, metaltooth leaper is buffing all entities, should only do mechs

    def action(self) :
        for minion in self.controller.field:
            if minion is not self and minion.race == Race.MECHANICAL :
                self.buff(minion, "GVG_048e")

I also implemented a few cards (probably not in the most ideal way), so if you would like to use them as a starting point, please feel free:

  1. In cards/classic/paladin.py, the repentance enchantment was missing
# Repentance
class EX1_379e:
       HEALTH = lambda i: 1
  1. In cards/gvg/hunter.py, maybe you can add Call Pet. It also required an enchantment (similar to Summoning Portal that is in the extras/missing_cards.py) to reduce cost by 4 on the beast draw.
# Call Pet
class GVG_017:
    def action(self):
        card = self.controller.draw()
            if card.type == CardType.MINION and card.race == Race.BEAST :
                self.buff(card, "GVG_017e")

Missing buff for call pet

GVG_017e = {
    GameTag.CARDNAME: "Call Pet Buff",
    GameTag.CARDTYPE: CardType.ENCHANTMENT,
    GameTag.COST: -4,
}
  1. In cards/gvg/neutral_common.py, maybe you can add tinkertown technician.
# Tinkertown Technician
class GVG_102:
    def action(self):
        if self.poweredUp:
            self.buff(self, "GVG_102e")
            self.controller.give(random.choice(self.data.entourage))
  1. Added a few gvg rogue card implementations
from ..utils import *


##
# Minions

# Goblin Auto-Barber
class GVG_023:
    def action(self):
        if self.controller.hero.weapon:
            self.buff(self.controller.hero.weapon, "GVG_023a")

# One-eyed Cheat
class GVG_025:
    def OWN_MINION_SUMMON(self, minion):
        if minion.race == Race.PIRATE:
            self.stealthed = True

# Iron Sensei
class GVG_027:
    def OWN_TURN_END(self):
        own_mechs = [minion for minion in self.controller.field if minion.race == Race.MECHANICAL] 
        if own_mechs :
            self.buff(random.choice(own_mechs),"GVG_027e")


# Trade Prince Gallywix
class GVG_028:
    def CARD_PLAYED(self, player, card):
        if player == self.controller.opponent and card.type == CardType.SPELL:
            self.controller.give(card.id)
            player.give("GVG_028t")

# Gallywix's Coin
class GVG_028t:
    def action(self):
        self.controller.tempMana += 1

##
# Spells

# Sabotage
class GVG_047:
    def action(self):
        if self.controller.opponent.field :
            random.choice(self.controller.opponent.field).destroy()
    def combo(self):
        if self.controller.opponent.field :
            random.choice(self.controller.opponent.field).destroy()
        if self.controller.opponent.hero.weapon:
            self.controller.opponent.hero.weapon.destroy()


# Tinker's Sharpsword Oil
class GVG_022:
    def action(self):
        if self.controller.hero.weapon :
            self.buff(self.controller.hero.weapon, "GVG_022a")
    def combo(self):
        if self.controller.hero.weapon :
            self.buff(self.controller.hero.weapon, "GVG_022a")
        if self.controller.field :
            self.buff(random.choice(self.controller.field), "GVG_022b")

which required these additions in buffs.py

# Iron Sensei
GVG_027e = {
    GameTag.ATK: 2,
    GameTag.HEALTH: 2
}

# Tinker's Sharpsword Oil
GVG_022a = buff(atk=3)
GVG_022b = buff(atk=3)

# Goblin Auto-Barber
GVG_023a = buff(atk=1)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.