From 01fd8fa406010d6f97ac073d36f282482b3ef0a8 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Wed, 13 Jul 2016 23:57:30 -0400 Subject: [PATCH 1/4] recoded cascade, the logic was incorrect. also the ability was coded incorrectly. ALL the cards get exiled, then placed on the bottom, the card that cost less is also exiled then MAY be cast otherwise its placed in the library bottom with the rest. I also now tell AI to ALWAYS use cast card if available. as the effects are always better. --- projects/mtg/src/AIPlayerBaka.cpp | 3 + projects/mtg/src/AllAbilities.cpp | 122 +++++++++++++++++------------- projects/mtg/src/ExtraCost.cpp | 2 + 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index 4262b0624..c1f792a09 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -104,6 +104,9 @@ int OrderedAIAction::getEfficiency() { target = a->source; } + + if (AACastCard * CC = dynamic_cast (a)) + return 99; switch (a->aType) { diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 0369afc0c..83056f210 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1144,75 +1144,89 @@ AACascade::AACascade(GameObserver* observer, int _id, MTGCardInstance * _source, oldOrder.clear(); newOrder.clear(); } - int AACascade::resolve() +int AACascade::resolve() +{ + Player * player = source->controller(); + if (!player) + return 0; + WParsedInt numCards(nbcardsStr, NULL, source); + MTGLibrary * library = player->game->library; + MTGRemovedFromGame * exile = player->game->exile; + MTGCardInstance * viable = NULL; + int counter = 0; + bool found = false; + for (int i = 0; i < numCards.getValue(); i++) { - Player * player = source->controller(); - if (player) + //*//*//*// + if (found) + continue; + ////////////////////////////////////////////// + if (!library->nb_cards) + continue; + ////////////////////////////////////////////// + while (library->nb_cards && !found) { - WParsedInt numCards(nbcardsStr, NULL, source); - MTGLibrary * library = player->game->library; - MTGRemovedFromGame * exile = player->game->exile; - MTGCardInstance * viable = NULL; - int counter = 0; - for (int i = 0; i < numCards.getValue(); i++) + viable = library->cards[library->nb_cards -1]; + if (!found) { - if (library->nb_cards) + if (!viable->isLand() && (viable->getManaCost()->getConvertedCost() < source->getManaCost()->getConvertedCost())) { - for(int z = library->nb_cards-1; z >= 0; z--) - { - if(!library->cards[z]->isLand() && (library->cards[z]->getManaCost()->getConvertedCost() < source->getManaCost()->getConvertedCost())) - { - viable = library->cards[z]; - player->game->putInZone(viable, library, exile); - { - for(int j=0; j < library->nb_cards; j++) - { - if(library->cards[j]->isCascaded) - { - library->cards[j]->isCascaded = false; - selectedCards.push_back(library->cards[j]); - } - } - if(selectedCards.size()) - { - std::random_shuffle ( selectedCards.begin(), selectedCards.end() ); - for(unsigned int i = 0; i < selectedCards.size();++i) - { - oldOrder = library->cards; - newOrder.push_back(selectedCards[i]); - for(unsigned int k = 0;k < oldOrder.size();++k) - { - MTGCardInstance * rearranged = oldOrder[k]; - if(rearranged != selectedCards[i]) - newOrder.push_back(rearranged); - } - library->cards = newOrder; - } - } - } - toCastCard(viable->next); - return 1; - } - else - { - library->cards[library->nb_cards - 1]->isCascaded=true; - counter++; - } - } + + toCastCard(viable); + viable = player->game->putInZone(viable, library, exile); + viable->isCascaded = true; + found = true; + } + else + { + viable = player->game->putInZone(viable, library, exile); + viable->isCascaded = true; + counter++; } } } - return 1; + + //*//*//*//* } + //////////////////////////////////////////// + for (int j = 0; j < exile->nb_cards; j++) + { + if (exile->cards[j]->isCascaded) + { + MTGCardInstance * CardToPutBack = exile->cards[j];//player->game->putInZone(exile->cards[j], exile, library); + CardToPutBack->isCascaded = false; + selectedCards.push_back(CardToPutBack); + } + } + ////////////////////////////////////////// + if (selectedCards.size()) + { + do + { + MTGCardInstance * toMove = selectedCards.back(); + if (toMove) + { + MTGAbility * a = NEW AALibraryBottom(game, game->mLayers->actionLayer()->getMaxId(), source, toMove); + a->oneShot = 1; + a->resolve(); + SAFE_DELETE(a); + selectedCards.pop_back(); + } + } while (selectedCards.size()); + } + ////////////////////////////////////// + return 1; +} void AACascade::toCastCard(MTGCardInstance * thisCard) { MTGAbility *ac = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), thisCard, thisCard,false,false,true,"","",false,false); - MayAbility *ma1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ac->clone(), thisCard,true); + MayAbility *ma1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ac->clone(), thisCard,false); MTGAbility *ga1 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), thisCard,NULL,ma1->clone()); SAFE_DELETE(ac); SAFE_DELETE(ma1); ga1->resolve(); + SAFE_DELETE(ga1); return; } @@ -7291,6 +7305,7 @@ MTGCardInstance * AACastCard::makeCard() MTGCardInstance * card = NULL; MTGCard * cardData = MTGCollection()->getCardByName(cardNamed); card = NEW MTGCardInstance(cardData, source->controller()->game); + card->owner = source->controller(); source->controller()->game->temp->addCard(card); return card; } @@ -7311,6 +7326,7 @@ int AACastCard::resolveSpell() MTGCard * cardToCopy = MTGCollection()->getCardById(_target->getId()); MTGCardInstance * myDummy = NULL; myDummy = NEW MTGCardInstance(cardToCopy, source->controller()->game); + myDummy->setObserver(source->controller()->getObserver()); source->controller()->game->garbage->addCard(myDummy); _target = myDummy; _target->isToken = 1; diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index fbae3701c..33efc8d53 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -249,6 +249,8 @@ LifeCost::LifeCost(TargetChooser *_tc) int LifeCost::canPay() { MTGCardInstance * _target = (MTGCardInstance *) target; + if (!_target) + return 0; if (_target->controller()->life <= 0 || _target->controller()->inPlay()->hasAbility(Constants::CANTCHANGELIFE) || _target->controller()->opponent()->game->battlefield->hasAbility(Constants::CANTPAYLIFE) || _target->controller()->game->battlefield->hasAbility(Constants::CANTPAYLIFE)) From e81346f8812c1003c234fe396ef8ba3a5dfaa5b5 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Thu, 14 Jul 2016 20:28:19 -0400 Subject: [PATCH 2/4] more work on cascade, I think I figured out what was causing a weird crash. --- projects/mtg/include/AllAbilities.h | 1 + projects/mtg/include/GameObserver.h | 1 + projects/mtg/include/MTGCardInstance.h | 1 + projects/mtg/src/AllAbilities.cpp | 13 +++++++++--- projects/mtg/src/GameObserver.cpp | 10 +++++++++ projects/mtg/src/MTGAbility.cpp | 28 ++++++++++++++++++++------ 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 392c89eb4..5681d7994 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -6208,6 +6208,7 @@ class AACascade: public ActivatedAbility { public: string nbcardsStr; + MTGCardInstance * castingThis; vectorselectedCards; vectoroldOrder; vectornewOrder; diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index 6b5fddb79..2f520043c 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -133,6 +133,7 @@ class GameObserver{ int isInPlay(MTGCardInstance * card); int isInGrave(MTGCardInstance * card); int isInExile(MTGCardInstance * card); + int isInHand(MTGCardInstance * card); virtual void Update(float dt); void Render(); void ButtonPressed(PlayGuiObject*); diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 4a59bb206..b06b2e656 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -92,6 +92,7 @@ public: bool isPhased; bool isCascaded; int phasedTurn; + bool handEffects; bool graveEffects; bool exileEffects; bool suspended; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 83056f210..e5ced563c 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1143,6 +1143,7 @@ AACascade::AACascade(GameObserver* observer, int _id, MTGCardInstance * _source, selectedCards.clear(); oldOrder.clear(); newOrder.clear(); + castingThis = NULL; } int AACascade::resolve() { @@ -1171,10 +1172,9 @@ int AACascade::resolve() { if (!viable->isLand() && (viable->getManaCost()->getConvertedCost() < source->getManaCost()->getConvertedCost())) { - - toCastCard(viable); viable = player->game->putInZone(viable, library, exile); viable->isCascaded = true; + castingThis = viable; found = true; } else @@ -1193,7 +1193,7 @@ int AACascade::resolve() { if (exile->cards[j]->isCascaded) { - MTGCardInstance * CardToPutBack = exile->cards[j];//player->game->putInZone(exile->cards[j], exile, library); + MTGCardInstance * CardToPutBack = exile->cards[j];; CardToPutBack->isCascaded = false; selectedCards.push_back(CardToPutBack); } @@ -1213,6 +1213,13 @@ int AACascade::resolve() selectedCards.pop_back(); } } while (selectedCards.size()); + + if (castingThis) + { + while (castingThis->next) + castingThis = castingThis->next; + toCastCard(castingThis); + } } ////////////////////////////////////// return 1; diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index faa869fdb..7cca9d03e 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -1568,7 +1568,17 @@ int GameObserver::isInExile(MTGCardInstance * card) } return 0; } +int GameObserver::isInHand(MTGCardInstance * card) +{ + for (int i = 0; i < 2; i++) + { + MTGGameZone * hand = players[i]->game->hand; + if (players[i]->game->isInZone(card, hand)) + return 1; + } + return 0; +} void GameObserver::cleanupPhase() { currentPlayer->cleanupPhase(); diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index dbd525a22..42285fc82 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -3982,13 +3982,14 @@ int AbilityFactory::getAbilities(vector * v, Spell * spell, MTGCar { card->graveEffects = false; card->exileEffects = false; - + card->handEffects = false; for (int i = 0; i < 2; ++i) { MTGPlayerCards * zones = observer->players[i]->game; if (dest == zones->hand) { magicText = card->magicTexts["hand"]; + card->handEffects = true; break; } if (dest == zones->graveyard) @@ -4891,6 +4892,8 @@ int MTGAbility::testDestroy() return 1; if (forceDestroy == -1) return 0; + if (source->handEffects && game->isInHand(source)) + return 0; if(source->graveEffects && game->isInGrave(source)) return 0; if(source->exileEffects && game->isInExile(source)) @@ -5934,13 +5937,26 @@ int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana) int result = 0; if (!mana) mana = game->currentlyActing()->getManaPool(); - if (_card == source && (!tap || !source->isTapped()) && game->currentlyActing()->game->inPlay->hasCard(source) - && (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness()) && !source->isPhased) + //please do not condense the following, I broke it apart for readability, it was far to difficult to tell what exactly happened before with it all in a single line. + //and far to prone to bugs. + if (_card == source) { - ManaCost * cost = getCost(); - if (!cost || (mana->canAfford(cost) && (!cost->extraCosts || cost->extraCosts->canPay())))/*counter cost bypass react to click*/ + if (!tap || (tap && !source->isTapped())) { - result = 1; + if (!source->hasSummoningSickness()) + { + if (game->currentlyActing()->game->inPlay->hasCard(source) && source->hasType(Subtypes::TYPE_LAND)) + { + if (!source->isPhased) + { + ManaCost * cost = getCost(); + if (!cost || (mana->canAfford(cost) && (!cost->extraCosts || cost->extraCosts->canPay())))/*counter cost bypass react to click*/ + { + result = 1; + } + } + } + } } } return result; From 9a56817bf84631b56e0ed08fcc623adc10ee5f09 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Thu, 14 Jul 2016 20:44:21 -0400 Subject: [PATCH 3/4] fixed a bug I introduced --- projects/mtg/src/MTGAbility.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 42285fc82..1262e0a36 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -5945,8 +5945,8 @@ int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana) { if (!source->hasSummoningSickness()) { - if (game->currentlyActing()->game->inPlay->hasCard(source) && source->hasType(Subtypes::TYPE_LAND)) - { + if (game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness())) + { if (!source->isPhased) { ManaCost * cost = getCost(); From 2fc52c9abd54c271329013ba1866eee502de2f51 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Thu, 14 Jul 2016 21:25:04 -0400 Subject: [PATCH 4/4] changed suspend to use castcard. --- projects/mtg/src/Counters.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/projects/mtg/src/Counters.cpp b/projects/mtg/src/Counters.cpp index b01c57644..a08c4402e 100644 --- a/projects/mtg/src/Counters.cpp +++ b/projects/mtg/src/Counters.cpp @@ -2,6 +2,7 @@ #include "Counters.h" #include "MTGCardInstance.h" +#include "AllAbilities.h" Counter::Counter(MTGCardInstance * _target, int _power, int _toughness) { @@ -187,10 +188,13 @@ int Counters::removeCounter(const char * _name, int _power, int _toughness) if (target->suspended && !target->counters->hasCounter("time",0,0)) { GameObserver * game = target->getObserver(); - MTGCardInstance * copy = target->controller()->game->putInZone(target, target->currentZone, target->controller()->game->stack); - - game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL,1, 0); - game->targetChooser = NULL; + MTGAbility *ac = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), target, target, false, false, true, "", "", false, false); + MayAbility *ma1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ac->clone(), target, true); + MTGAbility *ga1 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), target, NULL, ma1->clone()); + SAFE_DELETE(ac); + SAFE_DELETE(ma1); + ga1->resolve(); + SAFE_DELETE(ga1); } return mCount; }