From 76d386be06d4415f9c95efd69f8b62e5e91f39f6 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew@gmail.com" Date: Sat, 25 Jul 2009 14:57:27 +0000 Subject: [PATCH] Erwan - fixed a bug with bottle gnomes (would give life to opponent even if you steal control) - huge update for abilities life,draw,damage,deplete,discard in the parser. This breaks some cards (so we need to fix them) but allows more flexibility in the future. See my post on the forum --- projects/mtg/bin/Res/sets/ICE/_cards.dat | 10 +- projects/mtg/bin/Res/sets/MIR/_cards.dat | 2 +- projects/mtg/bin/Res/test/_tests.txt | 1 + projects/mtg/bin/Res/test/bottle_gnomes2.txt | 21 ++++ projects/mtg/include/AllAbilities.h | 113 +++++++++++++------ projects/mtg/include/TargetChooser.h | 8 ++ projects/mtg/src/MTGAbility.cpp | 32 ++++-- projects/mtg/src/MTGGameZones.cpp | 16 ++- 8 files changed, 147 insertions(+), 56 deletions(-) create mode 100644 projects/mtg/bin/Res/test/bottle_gnomes2.txt diff --git a/projects/mtg/bin/Res/sets/ICE/_cards.dat b/projects/mtg/bin/Res/sets/ICE/_cards.dat index 95dcfc6d5..7f0d6a230 100644 --- a/projects/mtg/bin/Res/sets/ICE/_cards.dat +++ b/projects/mtg/bin/Res/sets/ICE/_cards.dat @@ -374,7 +374,7 @@ text=Flare deals 1 damage to target creature or player. Draw a card at the begin id=2621 target=creature,player auto=damage:1 -auto=@next upkeep:draw:1 +auto=@next upkeep:draw:1 controller name=Flare rarity=C type=Instant @@ -835,7 +835,7 @@ text=Target player discards a card. Draw a card at the beginning of the next id=2471 target=player auto=discard:1 -auto=@next upkeep:draw:1 +auto=@next upkeep:draw:1 controller name=Mind Ravel rarity=C type=Sorcery @@ -1096,7 +1096,7 @@ text=Target player puts the top card of his or her library into his or her grave id=2529 target=player auto=deplete:1 -auto=@next upkeep:draw:1 +auto=@next upkeep:draw:1 controller name=Ray of Erasure rarity=C type=Instant @@ -1434,8 +1434,8 @@ id=2491 name=Touch of Death target=player auto=damage:1 -auto=@next upkeep:draw:1 -auto=life:1 +auto=@next upkeep:draw:1 controller +auto=life:1 controller rarity=C type=Sorcery mana={2}{B} diff --git a/projects/mtg/bin/Res/sets/MIR/_cards.dat b/projects/mtg/bin/Res/sets/MIR/_cards.dat index 155afdf8c..61c3a1b2e 100644 --- a/projects/mtg/bin/Res/sets/MIR/_cards.dat +++ b/projects/mtg/bin/Res/sets/MIR/_cards.dat @@ -1111,7 +1111,7 @@ text=Flare deals 1 damage to target creature or player. Draw a card at the begi id=3447 name=Flare auto=damage:1 target(creature,player) -auto=@next upkeep:draw:1 +auto=@next upkeep:draw:1 controller type=Instant mana={2}{R} rarity=C diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 562eea015..58aaf49b8 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -45,6 +45,7 @@ blessed_wine.txt #blinking_spirit.txt bloodfire_colossus.txt bottle_gnomes.txt +bottle_gnomes2.txt boggart_arsonists.txt brass_man.txt castle.txt diff --git a/projects/mtg/bin/Res/test/bottle_gnomes2.txt b/projects/mtg/bin/Res/test/bottle_gnomes2.txt new file mode 100644 index 000000000..0ad4b00bd --- /dev/null +++ b/projects/mtg/bin/Res/test/bottle_gnomes2.txt @@ -0,0 +1,21 @@ +#Bug: Bug: taking control of bottle gnomes, then sacrificing them: opponent gets life +[INIT] +FIRSTMAIN +[PLAYER1] +hand:persuasion +manapool:{3}{U}{U} +[PLAYER2] +inplay:bottle gnomes +[DO] +persuasion +bottle gnomes +bottle gnomes +[ASSERT] +FIRSTMAIN +[PLAYER1] +graveyard:persuasion +manapool:{0} +life:23 +[PLAYER2] +graveyard:bottle gnomes +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 8fc246127..d3fc40ddd 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -307,18 +307,50 @@ public: }; +class ActivatedAbilityTP:public ActivatedAbility{ +public: + int who; + ActivatedAbilityTP(int id, MTGCardInstance * card, Targetable * _target = NULL, ManaCost * cost=NULL, int doTap = 0, int who = TargetChooser::UNSET):ActivatedAbility(id,card,cost,0,doTap),who(who){ + if (_target) target = _target; + } + + Targetable * getTarget(){ + switch(who){ + case TargetChooser::TARGET_CONTROLLER: + if (target) return ((MTGCardInstance *)target)->controller(); + return NULL; + case TargetChooser::CONTROLLER: + return source->controller(); + case TargetChooser::OPPONENT: + return source->controller()->opponent(); + default: + return target; + } + return NULL; + } +}; + //Drawer, allows to draw a card for a cost: -class AADrawer:public ActivatedAbility{ +class AADrawer:public ActivatedAbilityTP{ public: int nbcards; - AADrawer(int _id, MTGCardInstance * card,ManaCost * _cost, int _nbcards = 1, int _tap = 0):ActivatedAbility(_id, card,_cost,0,_tap),nbcards(_nbcards){ + AADrawer(int _id, MTGCardInstance * card,Targetable * _target,ManaCost * _cost, int _nbcards = 1, int _tap = 0, int who=TargetChooser::UNSET):ActivatedAbilityTP(_id, card,_target,_cost,_tap,who),nbcards(_nbcards){ } int resolve(){ - game->mLayers->stackLayer()->addDraw(source->controller(),nbcards); - game->mLayers->stackLayer()->resolve(); + Targetable * _target = getTarget(); + Player * player; + if (_target){ + if (_target->typeAsTarget() == TARGET_CARD){ + player = ((MTGCardInstance *)_target)->controller(); + }else{ + player = (Player *) _target; + } + game->mLayers->stackLayer()->addDraw(player,nbcards); + game->mLayers->stackLayer()->resolve(); + } return 1; } @@ -335,16 +367,20 @@ class AADrawer:public ActivatedAbility{ }; /*Gives life to target controller*/ -class AALifer:public ActivatedAbility{ +class AALifer:public ActivatedAbilityTP{ public: int life; - AALifer(int _id, MTGCardInstance * card, MTGCardInstance * _target, int life, ManaCost * _cost = NULL, int _tap = 0):ActivatedAbility(_id, card,_cost,0,_tap),life(life){ - target = _target; + AALifer(int _id, MTGCardInstance * card, Targetable * _target, int life, ManaCost * _cost = NULL, int _tap = 0, int who = TargetChooser::UNSET):ActivatedAbilityTP(_id, card,_target,_cost,_tap,who),life(life){ } int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - _target->controller()->life+=life; + Damageable * _target = (Damageable *) getTarget(); + if (_target){ + if (_target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE){ + _target = ((MTGCardInstance *)_target)->controller(); + } + _target->life+=life; + } return 1; } @@ -1615,21 +1651,18 @@ class AForeach:public ListMaintainerAbility{ }; -class AADamager:public ActivatedAbility{ + + +class AADamager:public ActivatedAbilityTP{ public: int damage; - int who; -AADamager(int _id, MTGCardInstance * _source, Damageable * _target, int _damage = 0, ManaCost * _cost=NULL, int who=0):ActivatedAbility(_id,_source,_cost),damage(_damage),who(who){ - if (_target) target = _target; +AADamager(int _id, MTGCardInstance * _source, Targetable * _target, int _damage = 0, ManaCost * _cost=NULL, int doTap = 0, int who = TargetChooser::UNSET):ActivatedAbilityTP(_id,_source,_target,_cost,doTap,who),damage(_damage){ aType = MTGAbility::DAMAGER; } int resolve(){ if(target){ - Damageable * _target = (Damageable *)target; - if (who ==1){ - _target = ((MTGCardInstance *) target)->controller(); - } + Damageable * _target = (Damageable *) getTarget(); game->mLayers->stackLayer()->addDamage(source,_target, damage); game->mLayers->stackLayer()->resolve(); return 1; @@ -3678,19 +3711,25 @@ ALavaborn * clone() const{ //Generic Millstone -class AADepleter:public ActivatedAbility{ +class AADepleter:public ActivatedAbilityTP{ public: int nbcards; - AADepleter(int _id, MTGCardInstance * card, Player * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 0):ActivatedAbility(_id,card, _cost,0,_tap),nbcards(nbcards){ - target = _target; + AADepleter(int _id, MTGCardInstance * card, Targetable * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 0, int who = TargetChooser::UNSET):ActivatedAbilityTP(_id,card, _target,_cost,_tap,who),nbcards(nbcards){ } int resolve(){ - Player * player = (Player *) target; - if (!player) return 0; - MTGLibrary * library = player->game->library; - for (int i = 0; i < nbcards; i++){ - if (library->nb_cards) - player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); + Targetable * _target = getTarget(); + Player * player; + if (_target){ + if (_target->typeAsTarget() == TARGET_CARD){ + player = ((MTGCardInstance *)_target)->controller(); + }else{ + player = (Player *) _target; + } + MTGLibrary * library = player->game->library; + for (int i = 0; i < nbcards; i++){ + if (library->nb_cards) + player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); + } } return 1; } @@ -3708,18 +3747,24 @@ class AADepleter:public ActivatedAbility{ //Random Discard -class AARandomDiscarder:public ActivatedAbility{ +class AARandomDiscarder:public ActivatedAbilityTP{ public: int nbcards; - AARandomDiscarder(int _id, MTGCardInstance * card, Player * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 0):ActivatedAbility(_id,card, _cost,0,_tap),nbcards(nbcards){ - target = _target; + AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 0,int who=TargetChooser::UNSET):ActivatedAbilityTP(_id,card, _target,_cost,_tap,who),nbcards(nbcards){ } int resolve(){ - Player * player = (Player *) target; - if (!player) return 0; - for (int i = 0; i < nbcards; i++){ - player->game->discardRandom(player->game->hand); - } + Targetable * _target = getTarget(); + Player * player; + if (_target){ + if (_target->typeAsTarget() == TARGET_CARD){ + player = ((MTGCardInstance *)_target)->controller(); + }else{ + player = (Player *) _target; + } + for (int i = 0; i < nbcards; i++){ + player->game->discardRandom(player->game->hand); + } + } return 1; } diff --git a/projects/mtg/include/TargetChooser.h b/projects/mtg/include/TargetChooser.h index e2cd76a74..27b76ca3c 100644 --- a/projects/mtg/include/TargetChooser.h +++ b/projects/mtg/include/TargetChooser.h @@ -27,6 +27,14 @@ class TargetChooser: public TargetsList { int forceTargetListReady; public: + enum{ + UNSET = 0, + OPPONENT = -1, + CONTROLLER = 1, + TARGET_CONTROLLER = 2 + }; + + TargetChooser(MTGCardInstance * card = NULL, int _maxtargets = -1); MTGCardInstance * source; diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 13cd3688c..96bd46896 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -377,6 +377,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG } } + + int who = TargetChooser::UNSET; + if (s.find(" controller") != string::npos) who=TargetChooser::CONTROLLER; + if (s.find(" opponent") != string::npos) who=TargetChooser::OPPONENT; + if (s.find(" targetcontroller") != string::npos) who=TargetChooser::TARGET_CONTROLLER; + //Damage found = s.find("damage"); if (found != string::npos){ @@ -392,9 +398,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG Damageable * d = NULL; if (spell) d = spell->getNextDamageableTarget(); - int who = 0; - if (s.find("controller") != string::npos) who=1; - MTGAbility * a = NEW AADamager(id,card,d, damage, NULL, who); + MTGAbility * a = NEW AADamager(id,card,d, damage, NULL, 0, who); a->oneShot = 1; return a; } @@ -412,7 +416,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG life = atoi(s.substr(start+1).c_str()); } - MTGAbility * a = NEW AALifer(id,card,card,life); + Damageable * d = NULL; + if (spell) d = spell->getNextPlayerTarget(); + MTGAbility * a = NEW AALifer(id,card,d,life,NULL,0,who); a->oneShot = 1; return a; } @@ -429,7 +435,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG nbcards = atoi(s.substr(start+1).c_str()); } - MTGAbility * a = NEW AADrawer(id,card,NULL,nbcards); + Targetable * t = NULL; + if (spell) t = spell->getNextPlayerTarget(); + MTGAbility * a = NEW AADrawer(id,card,t,NULL,nbcards,0,who); a->oneShot = 1; return a; } @@ -445,9 +453,10 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG }else{ nbcards = atoi(s.substr(start+1).c_str()); } - Player * player = NULL; - if (spell) player = spell->getNextPlayerTarget(); - MTGAbility * a = NEW AADepleter(id,card,player,nbcards); + + Targetable * t = NULL; + if (spell) t = spell->getNextPlayerTarget(); + MTGAbility * a = NEW AADepleter(id,card,t,nbcards,NULL,0,who); a->oneShot = 1; return a; } @@ -477,10 +486,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG nbcards = atoi(s.substr(start+1).c_str()); } - Player * player = NULL; - if (spell) player = spell->getNextPlayerTarget(); - if (!player) player = GameObserver::GetInstance()->currentlyActing(); - MTGAbility * a = NEW AARandomDiscarder (id, card, player,nbcards); + Targetable * t = NULL; + if (spell) t = spell->getNextPlayerTarget(); + MTGAbility * a = NEW AARandomDiscarder (id, card, t,nbcards,NULL,0,who); a->oneShot = 1; return a; } diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index 2b377db7f..88ebc9ca4 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -59,6 +59,12 @@ MTGPlayerCards::~MTGPlayerCards(){ void MTGPlayerCards::setOwner(Player * player){ library->setOwner(player); + graveyard->setOwner(player); + hand->setOwner(player); + inPlay->setOwner(player); + removedFromGame->setOwner(player); + stack->setOwner(player); + garbage->setOwner(player); } void MTGPlayerCards::initGame(int shuffle, int draw){ @@ -122,12 +128,13 @@ MTGCardInstance * MTGPlayerCards::putInPlay(MTGCardInstance * card){ MTGCardInstance * MTGPlayerCards::putInGraveyard(MTGCardInstance * card){ MTGCardInstance * copy = NULL; + MTGGraveyard * grave = card->owner->game->graveyard; if (inPlay->hasCard(card)){ - copy = putInZone(card,inPlay, graveyard); + copy = putInZone(card,inPlay, grave); }else if (stack->hasCard(card)){ - copy = putInZone(card,stack, graveyard); + copy = putInZone(card,stack, grave); }else{ - copy = putInZone(card,hand, graveyard); + copy = putInZone(card,hand, grave); } return copy; @@ -223,7 +230,7 @@ MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy if (card->isToken){ //TODO better than this ? return card; } - card->lastController = card->controller(); + //card->lastController = card->controller(); if (createCopy) { copy = NEW MTGCardInstance(card->model,card->owner->game); copy->previous = card; @@ -285,6 +292,7 @@ void MTGGameZone::addCard(MTGCardInstance * card){ cards.push_back(card); nb_cards++; cardsMap[card] = 1; + card->lastController = this->owner; }