Permalink
Browse files

Move to Aura API v3

 - Auras are gone from the CardDefs.xml
 - `aura` is now a proper Card script with one or more actions
 - Selection now happens via selectors, instead of is_valid_target()
 - PlayRequirement hacks are all gone
 - Adjacent Buff handling logic is gone, we reuse selectors instead

Two points to note:
 - Currently, we expect the aura action to be a Buff() call. Anything
   else will break the aura logic.
 - Spiteful Smith is hardcoded until we revise Enrage scripts.
  • Loading branch information...
jleclanche committed Aug 5, 2015
1 parent 7df40a8 commit ce1810146d3eae90096496ff7c393e43fa2d4370
@@ -90,10 +90,14 @@ def _set_zone(self, value):
self._zone = value

if value == Zone.PLAY:
for aura in self.data.auras:
aura = Aura(aura, source=self)
aura.summon()
self._auras.append(aura)
if hasattr(self.data.scripts, "aura"):
auras = self.data.scripts.aura
if not hasattr(auras, "__iter__"):
auras = (auras, )
for aura in auras:
aura = Aura(aura, source=self)
aura.summon()
self._auras.append(aura)
else:
for aura in self._auras:
aura.destroy()
@@ -500,7 +504,6 @@ class Minion(Character):

def __init__(self, id, data):
self._enrage = None
self.adjacent_buff = False
self.always_wins_brawls = False
self.divine_shield = False
self.enrage = False
@@ -710,48 +713,30 @@ class Aura(object):
targets affected by an aura. It is only internal.
"""

def __init__(self, obj, source):
self.id = obj["id"]
def __init__(self, action, source):
self.action = action
self.selector = self.action._args[0]
self.id = self.action._args[1]
self.source = source
self.controller = source.controller
self.requirements = obj["requirements"].copy()
self._buffed = CardList()
self._buffs = CardList()
self._auraType = obj["type"]
# THIS IS A HACK
# DON'T SHOOT, IT'S TEMPORARY
self.on_enrage = self.id == "CS2_221e"

def __repr__(self):
return "<Aura (%r)>" % (self.id)

@property
def game(self):
return self.source.game

def is_valid_target(self, target):
if self._auraType == AuraType.PLAYER_AURA:
return target == self.controller
elif self._auraType == AuraType.HAND_AURA:
if target.zone != Zone.HAND:
return False
return is_valid_target(self.source, target, requirements=self.requirements)

@property
def targets(self):
if self._auraType == AuraType.PLAYER_AURA:
return [self.controller]
elif self._auraType == AuraType.HAND_AURA:
return self.controller.hand + self.controller.opponent.hand
if self.source.type == CardType.MINION and self.source.adjacent_buff:
return self.source.adjacent_minions
# XXX The targets are right but we need to get them a cleaner way.
ret = self.game.player1.field + self.game.player2.field
if self.controller.weapon:
ret.append(self.controller.weapon)
return ret
if self.on_enrage and not self.source.enraged:
return []
return self.selector.eval(self.source.game, self.source)

def summon(self):
logging.info("Summoning Aura %r", self)
self.game.auras.append(self)
self.game.refresh_auras()
self.source.game.auras.append(self)
self.source.game.refresh_auras()

def _buff(self, target):
buff = self.source.buff(target, self.id)
@@ -766,26 +751,22 @@ def _entity_buff(self, target):
return buff

def update(self):
for target in self.targets:
if target.type == CardType.ENCHANTMENT:
# HACKY: self.targets currently relies on hero entities
# This includes enchantments so we need to filter them out.
continue
if self.is_valid_target(target):
if not self._entity_buff(target):
self._buff(target)
targets = self.targets
for target in targets:
if not self._entity_buff(target):
self._buff(target)
# Make sure to copy the list as it can change during iteration
for target in self._buffed[:]:
# Remove auras no longer valid
if not self.is_valid_target(target):
if target not in targets:
buff = self._entity_buff(target)
if buff:
buff.destroy()
self._buffed.remove(target)

def destroy(self):
logging.info("Removing %r affecting %r" % (self, self._buffed))
self.game.auras.remove(self)
self.source.game.auras.remove(self)
for buff in self._buffs[:]:
buff.destroy()
del self._buffs
@@ -26,6 +26,16 @@ class DS1_070:
play = Buff(TARGET, "DS1_070o")


# Timber Wolf
class DS1_175:
aura = Buff(FRIENDLY_MINIONS + BEAST - SELF, "DS1_175o")


# Tundra Rhino
class DS1_178:
aura = Buff(FRIENDLY_MINIONS + BEAST, "DS1_178e")


# Scavenging Hyena
class EX1_531:
events = Death(FRIENDLY + BEAST).on(Buff(SELF, "EX1_531e"))
@@ -36,6 +46,11 @@ class EX1_534:
deathrattle = Summon(CONTROLLER, "EX1_534t") * 2


# Leokk
class NEW1_033:
aura = Buff(FRIENDLY_MINIONS - SELF, "NEW1_033o")


##
# Spells

@@ -33,11 +33,19 @@ class EX1_559:
events = OWN_SPELL_PLAY.on(Give(CONTROLLER, "CS2_029"))


# Sorcerer's Apprentice
class EX1_608:
aura = Buff(FRIENDLY + SPELL + IN_HAND, "EX1_608a")


# Kirin Tor Mage
class EX1_612:
play = Buff(FRIENDLY_HERO, "EX1_612o")
play = Buff(FRIENDLY_HERO, "EX1_612oa")

class EX1_612oa:
aura = Buff(FRIENDLY + SECRET + IN_HAND, "EX1_612o")

class EX1_612o:
cost = lambda self, i: 0


@@ -4,6 +4,16 @@
##
# Free basic minions

# Raid Leader
class CS2_122:
aura = Buff(FRIENDLY_MINIONS - SELF, "CS2_122e")


# Stormwind Champion
class CS2_222:
aura = Buff(FRIENDLY_MINIONS - SELF, "CS2_222o")


# Frostwolf Warlord
class CS2_226:
play = Buff(SELF, "CS2_226e") * Count(FRIENDLY_MINIONS)
@@ -29,6 +39,11 @@ class EX1_102:
events = OWN_TURN_BEGIN.on(Hit(RANDOM_ENEMY_CHARACTER, 2))


# Dire Wolf Alpha
class EX1_162:
aura = Buff(SELF_ADJACENT, "EX1_162o")


# Arathi Weaponsmith
class EX1_398:
play = Summon(CONTROLLER, "EX1_398t")
@@ -39,6 +54,11 @@ class EX1_399:
events = SELF_DAMAGE.on(Buff(SELF, "EX1_399e"))


# Grimscale Oracle
class EX1_508:
aura = Buff(ALL_MINIONS + MURLOC - SELF, "EX1_508o")


# Nightblade
class EX1_593:
play = Hit(ENEMY_HERO, 3)
@@ -102,6 +122,16 @@ class CS2_203:
play = Silence(TARGET)


# Spiteful Smith
class CS2_221:
aura = Buff(FRIENDLY_WEAPON, "CS2_221e")


# Venture Co. Mercenary
class CS2_227:
aura = Buff(FRIENDLY + MINION + IN_HAND, "CS2_227a")


# Darkscale Healer
class DS1_055:
play = Heal(FRIENDLY_CHARACTERS, 2)
@@ -11,6 +11,11 @@ class EX1_105:
cost = lambda self, i: i - (len(self.controller.hand) - 1)


# Murloc Warleader
class EX1_507:
aura = Buff(ALL_MINIONS + MURLOC - SELF, "EX1_507e")


# Faceless Manipulator
class EX1_564:
play = Morph(SELF, ExactCopy(TARGET))
@@ -47,3 +52,8 @@ class NEW1_017:
# Doomsayer
class NEW1_021:
events = OWN_TURN_BEGIN.on(Destroy(ALL_MINIONS))


# Southsea Captain
class NEW1_027:
aura = Buff(FRIENDLY_MINIONS + PIRATE - SELF, "NEW1_027e")
@@ -155,6 +155,7 @@ class NEW1_029:
play = Buff(ENEMY_HERO, "NEW1_029t")

class NEW1_029t:
aura = Buff(ENEMY + SPELL + IN_HAND, "NEW1_029ta")
events = OWN_TURN_BEGIN.on(Destroy(SELF))

class NEW1_029ta:
@@ -46,7 +46,10 @@ class EX1_059:
play = Buff(TARGET, "EX1_059e")


# Pint-Sized Summoner (Aura)
# Pint-Sized Summoner
class EX1_076:
aura = Buff(FRIENDLY + MINION + IN_HAND, "EX1_076a")

class EX1_076a:
def cost(self, i):
if not self.controller.minions_played_this_turn:
@@ -109,6 +112,11 @@ class EX1_597:
events = OWN_TURN_END.on(Hit(SELF, 1), Summon(CONTROLLER, "EX1_598"))


# Mana Wraith
class EX1_616:
aura = Buff(MINION + IN_HAND, "EX1_616a")


# Knife Juggler
class NEW1_019:
events = Summon(CONTROLLER, MINION - SELF).after(Hit(RANDOM_ENEMY_CHARACTER, 1))
@@ -37,6 +37,16 @@ class EX1_341:
events = OWN_TURN_BEGIN.on(Heal(RANDOM(FRIENDLY + DAMAGED_CHARACTERS), 3))


# Prophet Velen
class EX1_350:
aura = Buff(CONTROLLER, "EX1_350a")


# Auchenai Soulpriest
class EX1_591:
aura = Buff(CONTROLLER, "EX1_591a")


# Temple Enforcer
class EX1_623:
play = Buff(TARGET, "EX1_623e")
@@ -117,6 +117,7 @@ class EX1_145:
play = Buff(FRIENDLY_HERO, "EX1_145o")

class EX1_145o:
aura = Buff(FRIENDLY + SPELL + IN_HAND, "EX1_145oa")
events = OWN_SPELL_PLAY.on(Destroy(SELF))


@@ -28,6 +28,11 @@ class EX1_258:
events = Play(CONTROLLER, OVERLOAD).on(Buff(SELF, "EX1_258e"))


# Flametongue Totem
class EX1_565:
aura = Buff(SELF_ADJACENT, "EX1_565o")


# Mana Tide Totem
class EX1_575:
events = OWN_TURN_END.on(Draw(CONTROLLER))
@@ -56,7 +56,10 @@ class EX1_313:
play = Hit(FRIENDLY_HERO, 5)


# Summoning Portal (Virtual Aura)
# Summoning Portal
class EX1_315:
aura = Buff(FRIENDLY + MINION + IN_HAND, "EX1_315a")

class EX1_315a:
cost = lambda self, i: min(i, max(1, i - 2))

@@ -6,7 +6,6 @@
from xml.dom import minidom
from xml.etree import ElementTree
from fireplace.enums import AuraType, GameTag
import auras
import buffs
import chooseone
import enrage
@@ -23,25 +22,6 @@
]


def add_aura(card, auras):
for aura in auras:
reqs = aura.get("requirements", {})
id = aura.get("id")
type = aura.get("type", AuraType.PLAY_AURA)

e = ElementTree.Element("Aura")
e.attrib["cardID"] = id
e.attrib["type"] = str(int(type))

for requirement, param in reqs.items():
req = ElementTree.Element("ActiveRequirement")
req.attrib["reqID"] = str(int(requirement))
req.attrib["param"] = str(int(param)) if param is not True else ""
e.append(req)
card.xml.append(e)
print("%s: Adding aura data %r" % (card.name, aura))


def add_chooseone_tags(card, ids):
for id in ids:
e = ElementTree.Element("ChooseCard")
@@ -179,9 +159,6 @@ def main():
if hasattr(chooseone, id):
add_chooseone_tags(card, getattr(chooseone, id))

if hasattr(auras, id):
add_aura(card, getattr(auras, id))

if hasattr(enrage, id):
add_enrage_definition(card, getattr(enrage, id))

Oops, something went wrong.

0 comments on commit ce18101

Please sign in to comment.