From b021417324a6bbbc698d023d7682082a93d87183 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew@gmail.com" Date: Wed, 2 Mar 2011 13:41:24 +0000 Subject: [PATCH] Erwan -fix for issue 604 (Land play limitation should not apply in all cases) -- this adds a "castMehod" variable to MTGCardInstance. IF this variable is 0, the card was not "cast" (or for lands, "put into play" as part of the lands rule), but "added" to the battlefield with some other effect. On the other hand, if this variable is set, it means the card was cast -- as we discussed, I did not touch the "alternateCostPaid" variable, as I'm still not really sure these two concepts are actually the same --- projects/mtg/bin/Res/test/_tests.txt | 1 + .../bin/Res/test/misty_rainforest_i604.txt | 21 +++++++++++++++++ projects/mtg/include/AllAbilities.h | 4 ++-- projects/mtg/include/MTGCardInstance.h | 4 ++++ projects/mtg/include/MTGDefinitions.h | 17 ++++++++++++++ projects/mtg/include/MTGGameZones.h | 4 ++-- projects/mtg/src/ActionStack.cpp | 23 +++++++++++++++++++ projects/mtg/src/MTGAbility.cpp | 2 +- projects/mtg/src/MTGCardInstance.cpp | 15 +++++++++++- projects/mtg/src/MTGGameZones.cpp | 9 ++++---- projects/mtg/src/MTGRules.cpp | 8 +++---- projects/mtg/src/PlayRestrictions.cpp | 2 +- 12 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 projects/mtg/bin/Res/test/misty_rainforest_i604.txt diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 599c06209..45832aff8 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -392,6 +392,7 @@ Mimics#2.txt mirri_the_cursed.txt mirri_the_cursed2_i284.txt misc01.txt +misty_rainforest_i604.txt moat.txt mobile_fort.txt Morph#1.txt diff --git a/projects/mtg/bin/Res/test/misty_rainforest_i604.txt b/projects/mtg/bin/Res/test/misty_rainforest_i604.txt new file mode 100644 index 000000000..7261334a8 --- /dev/null +++ b/projects/mtg/bin/Res/test/misty_rainforest_i604.txt @@ -0,0 +1,21 @@ +#Bug: Misty Rainforst triggers the "one land per turn" limit +# see http://code.google.com/p/wagic/issues/detail?id=604 +[INIT] +FIRSTMAIN +[PLAYER1] +inplay:misty rainforest +library:island +hand:forest +[PLAYER2] +[DO] +misty rainforest +island +forest +[ASSERT] +FIRSTMAIN +[PLAYER1] +life:19 +graveyard:misty rainforest +inplay:island,forest +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 9e8bddd18..bbbbbe428 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -4746,7 +4746,7 @@ public: { counter = NEW TypeTargetChooser("land"); - landsPlayedThisTurn = source->controller()->game->inPlay->seenThisTurn(counter); + landsPlayedThisTurn = source->controller()->game->inPlay->seenThisTurn(counter, Constants::CAST_ALL); PlayRestrictions * restrictions = source->controller()->game->playRestrictions; landsRestriction = restrictions->getMaxPerTurnRestrictionByTargetChooser(counter); restrictions->removeRestriction(landsRestriction); @@ -4764,7 +4764,7 @@ public: int trigger() { - int landsPlayedThisTurnUpdated = source->controller()->game->inPlay->seenThisTurn(counter); + int landsPlayedThisTurnUpdated = source->controller()->game->inPlay->seenThisTurn(counter, Constants::CAST_ALL); if (landsPlayedThisTurnUpdated > 1 && landsPlayedThisTurnUpdated > landsPlayedThisTurn) { landsPlayedThisTurn = landsPlayedThisTurnUpdated; diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 5156e489c..4dfa934e3 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -46,6 +46,7 @@ class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable { int XX; int alternateCostPaid[ManaCost::MANA_PAID_WITH_RETRACE + 1]; int paymenttype; + int castMethod; /* Tells if the card reached its current zone by being cast or not (brought into the zone by an effect). non 0 == cast, 0 == not cast */ int frozen; int sunburst; int equipment; @@ -94,6 +95,9 @@ class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable { MTGCardInstance * next; int doDamageTest; int summoningSickness; + + bool matchesCastFilter(int castMethod); + // The recommended method to test for summoning Sickness ! int hasSummoningSickness(); MTGCardInstance * changeController(Player * newcontroller); diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index 8429645c4..05bc2623b 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -228,6 +228,23 @@ SNOWSWAMPWALK = 90, }; + enum{ + NOT_CAST = 0, + CAST_NORMALLY = 1, + CAST_WITH_KICKER = 2, + CAST_WITH_ALTERNATIVE = 3, + CAST_WITH_BUYBACK = 4, + CAST_WITH_FLASHBACK = 5, + CAST_WITH_RETRACE = 6, + CAST_WITH_MORPH = 7, + CAST_WITH_SUSPEND = 8, + + CAST_ALTERNATE = -1, //matches all alternate costs, including itself + CAST_ALL = -2, // matches everything except NOT_CAST + CAST_DONT_CARE = -3 //matches everything + + }; + static char MTGColorChars[]; static const char* MTGColorStrings[]; static int _r[], _g[], _b[]; diff --git a/projects/mtg/include/MTGGameZones.h b/projects/mtg/include/MTGGameZones.h index 32fb74c66..d92fd11cf 100644 --- a/projects/mtg/include/MTGGameZones.h +++ b/projects/mtg/include/MTGGameZones.h @@ -99,8 +99,8 @@ class MTGGameZone { int hasX(); //How many cards matching a TargetChooser have been put in this zone during the turn - int seenThisTurn(TargetChooser * tc); - int seenThisTurn(string s); + int seenThisTurn(TargetChooser * tc, int castFilter = Constants::CAST_DONT_CARE); + int seenThisTurn(string s, int castFilter = Constants::CAST_DONT_CARE); void setOwner(Player * player); MTGCardInstance * lastCardDrawn; diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 310dba2fd..27bbb2e65 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -201,11 +201,14 @@ Interruptible(0) cost = NEW ManaCost(); tc = NULL; from = _source->getCurrentZone(); + payResult = ManaCost::MANA_UNPAID; + source->castMethod = Constants::NOT_CAST; } Spell::Spell(int id, MTGCardInstance * _source, TargetChooser * tc, ManaCost * _cost, int payResult) : Interruptible(id), tc(tc), cost(_cost), payResult(payResult) { + if (!cost) cost = NEW ManaCost(); source = _source; mHeight = 40; type = ACTION_SPELL; @@ -215,6 +218,20 @@ Interruptible(id), tc(tc), cost(_cost), payResult(payResult) if(tc && tc->targets[i] != NULL) _source->backupTargets[i] = tc->targets[i]; } + + // fill information on how the card came into this zone. Right now the quickest way is to do it here, based on how the mana was paid... + switch(payResult) { + case ManaCost::MANA_UNPAID: + source->castMethod = Constants::NOT_CAST; + break; + case ManaCost::MANA_PAID: + case ManaCost::MANA_PAID_WITH_KICKER: + source->castMethod = Constants::CAST_NORMALLY; + break; + default: + source->castMethod = Constants::CAST_ALTERNATE; + break; + } } int Spell::computeX(MTGCardInstance * card) @@ -275,7 +292,13 @@ int Spell::resolve() if (!source->hasType("instant") && !source->hasType("sorcery")) { Player * p = source->controller(); + int castMethod = source->castMethod; source = p->game->putInZone(source, from, p->game->battlefield); + + // We need to get the information about the cast method on both the card in the stack AND the card in play, + //so we copy it from the previous card (in the stack) to the new one (in play). + source->castMethod = castMethod; + from = p->game->battlefield; } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 8d6de9f5c..bee45b62e 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -65,7 +65,7 @@ int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player) return 0; break; case CASTED_A_SPELL: - if(player->game->stack->seenThisTurn("*") < 1) + if(player->game->stack->seenThisTurn("*", Constants::CAST_ALL) < 1) return 0; break; case ONE_OF_AKIND: diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 791333333..bfe6e7abc 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -43,6 +43,7 @@ MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to life = toughness; preventable = 0; flanked = 0; + castMethod = Constants::NOT_CAST; } void MTGCardInstance::copy(MTGCardInstance * card) @@ -146,6 +147,8 @@ void MTGCardInstance::initMTGCI() damageToController = false; wasDealtDamage = false; suspended = false; + castMethod = Constants::NOT_CAST; + for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++) alternateCostPaid[i] = 0; @@ -883,7 +886,7 @@ int MTGCardInstance::toggleDefenser(MTGCardInstance * opponent) { if(opponent->view != NULL) { - //todo: qoute wololo "change this into a cool blinking effects when opposing creature has cursor focus." + //todo: quote wololo "change this into a cool blinking effects when opposing creature has cursor focus." opponent->view->actZ += .8f; opponent->view->actT -= .2f; } @@ -896,6 +899,16 @@ int MTGCardInstance::toggleDefenser(MTGCardInstance * opponent) return 0; } +bool MTGCardInstance::matchesCastFilter(int castFilter) { + if(castFilter == Constants::CAST_DONT_CARE) + return true; //everything + if(castFilter == Constants::CAST_ALL) + return (castMethod != Constants::NOT_CAST); //everything except "not cast" + if (castFilter == Constants::CAST_ALTERNATE && castMethod > Constants::CAST_NORMALLY) + return true; //all alternate casts + return (castFilter == castMethod); +}; + int MTGCardInstance::addProtection(TargetChooser * tc) { tc->targetter = NULL; diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index 5c15934b5..34d83eebb 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -608,7 +608,7 @@ int MTGGameZone::hasAbility(int ability) return 0; } -int MTGGameZone::seenThisTurn(TargetChooser * tc) +int MTGGameZone::seenThisTurn(TargetChooser * tc, int castMethod) { //The following 2 lines modify the passed TargetChooser. Call this function with care :/ tc->setAllZones(); // This is to allow targetting cards without caring about the actual zone @@ -617,17 +617,18 @@ int MTGGameZone::seenThisTurn(TargetChooser * tc) int count = 0; for (vector::iterator iter = cardsSeenThisTurn.begin(); iter != cardsSeenThisTurn.end(); ++iter) { - if (tc->canTarget(*iter)) + MTGCardInstance * c = (*iter); + if (c->matchesCastFilter(castMethod) && tc->canTarget(c)) count++; } return count; } -int MTGGameZone::seenThisTurn(string targetChooserDefinition) +int MTGGameZone::seenThisTurn(string targetChooserDefinition, int castMethod) { TargetChooserFactory tcf; TargetChooser *tc = tcf.createTargetChooser(targetChooserDefinition, NULL); - int result = seenThisTurn(tc); + int result = seenThisTurn(tc, castMethod); delete(tc); return result; } diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index e8668035f..a515631a7 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -130,7 +130,7 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card) if (card->hasType("land")) { MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp); - Spell * spell = NEW Spell(copy); + Spell * spell = NEW Spell(0,copy,NULL,NULL, payResult); spell->resolve(); delete spellCost; delete spell; @@ -151,7 +151,7 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card) if (card->has(Constants::STORM)) { - int storm = player->game->stack->seenThisTurn("*") + player->opponent()->game->stack->seenThisTurn("*"); + int storm = player->game->stack->seenThisTurn("*", Constants::CAST_ALL) + player->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL); ManaCost * spellCost = player->getManaPool(); for (int i = storm; i > 1; i--) { @@ -298,7 +298,7 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter if (card->hasType("land")) { MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->temp); - Spell * spell = NEW Spell(copy); + Spell * spell = NEW Spell(0,copy,NULL,NULL, alternateCostType); copy->alternateCostPaid[alternateCostType] = 1; spell->resolve(); SAFE_DELETE(spell); @@ -316,7 +316,7 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter if (card->has(Constants::STORM)) { - int storm = player->game->stack->seenThisTurn("*") + player->opponent()->game->stack->seenThisTurn("*"); + int storm = player->game->stack->seenThisTurn("*", Constants::CAST_ALL) + player->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL); for (int i = storm; i > 1; i--) { game->mLayers->stackLayer()->addSpell(copy, NULL, playerMana, alternateCostType, 1); diff --git a/projects/mtg/src/PlayRestrictions.cpp b/projects/mtg/src/PlayRestrictions.cpp index 63beb3d17..fd9f113ac 100644 --- a/projects/mtg/src/PlayRestrictions.cpp +++ b/projects/mtg/src/PlayRestrictions.cpp @@ -31,7 +31,7 @@ int MaxPerTurnRestriction::canPutIntoZone(MTGCardInstance * card, MTGGameZone * if (maxPerTurn == NO_MAX) return PlayRestriction::CAN_PLAY; - if (zone->seenThisTurn(tc) >= maxPerTurn) + if (zone->seenThisTurn(tc, Constants::CAST_ALL) >= maxPerTurn) return PlayRestriction::CANT_PLAY; return PlayRestriction::CAN_PLAY;