diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 60cb22ec0..06014cd6a 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -4456,6 +4456,29 @@ public: const string getMenuText(); AAMorph * clone() const; }; + +class AAMeldFrom : public ActivatedAbility +{ +public: + string _MeldedName; + AAMeldFrom(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, string MeldedName = ""); + int resolve(); + + const string getMenuText(); + AAMeldFrom * clone() const; +}; +/* meld*/ +class AAMeld : public ActivatedAbility +{ +public: + string _MeldedName; + AAMeld(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target,string MeldedName = ""); + int resolve(); + + const string getMenuText(); + AAMeld * clone() const; +}; + /* flip*/ class AAFlip: public InstantAbility { diff --git a/projects/mtg/include/ExtraCost.h b/projects/mtg/include/ExtraCost.h index 9d3690e99..c6a8e1438 100644 --- a/projects/mtg/include/ExtraCost.h +++ b/projects/mtg/include/ExtraCost.h @@ -299,7 +299,8 @@ public: class Offering : public ExtraCost { public: - Offering(TargetChooser *_tc = NULL); + bool emerge; + Offering(TargetChooser *_tc = NULL, bool emerge = false); virtual int canPay(); virtual int isPaymentSet(); virtual int doPay(); diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index b06b2e656..356203bd0 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -89,6 +89,7 @@ public: bool turningOver; bool isMorphed; bool isFlipped; + string MeldedFrom; bool isPhased; bool isCascaded; int phasedTurn; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 4cf600791..7d2bb4d39 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -3069,6 +3069,68 @@ AAMorph * AAMorph::clone() const a->forceDestroy = 1; return a; } + +//Melded From Setter +AAMeldFrom::AAMeldFrom(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, string MeldedName) : + ActivatedAbility(observer, id, card, 0), _MeldedName(MeldedName) +{ + target = _target; + // aType = MTGAbility::Melder; +} + +int AAMeldFrom::resolve() +{ + source->MeldedFrom = _MeldedName; + return 1; +} + +const string AAMeldFrom::getMenuText() +{ + return "Melded From"; +} + +AAMeldFrom * AAMeldFrom::clone() const +{ + return NEW AAMeldFrom(*this); +} + +//Melding +AAMeld::AAMeld(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, string MeldedName) : + ActivatedAbility(observer, id, card, 0), _MeldedName(MeldedName) +{ + target = _target; + // aType = MTGAbility::Melder; +} + +int AAMeld::resolve() +{ + MTGCardInstance * _target = (MTGCardInstance *)target; + if (_target && _target->controller() == source->controller() && _target->owner == source->owner && !_target->isToken && !source->isToken) + { + source->controller()->game->putInExile(source); + _target->controller()->game->putInExile(_target); + source->next->controller()->game->putInZone(source->next, source->next->currentZone, source->next->controller()->game->temp); + _target->next->controller()->game->putInZone(_target->next, _target->next->currentZone, _target->next->controller()->game->temp); + MTGAbility *a = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), source, source, false, false, false, _MeldedName, _MeldedName, false, true); + a->oneShot = false; + a->canBeInterrupted = false; + a->addToGame(); + + return 1; + } + return 0; +} + +const string AAMeld::getMenuText() +{ + return "Meld"; +} + +AAMeld * AAMeld::clone() const +{ + return NEW AAMeld(*this); +} + // flip a card AAFlip::AAFlip(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target,string flipStats) : InstantAbility(observer, id, card, _target),flipStats(flipStats) @@ -6900,21 +6962,62 @@ void ABlink::resolveBlink() // this->forceDestroy = 1; // return; //} + if (_target->MeldedFrom.size()) + { + //cards with meld are handled very different from normal cards with this specific ability giving us about 3 of the + //core rules for the ability. below we split the card up, and we send them to garbage, move the original to temp where + //it is later moved to garbage by garbage collection. + //then we build 2 seperate blinks with the 2 parts as the targets. + vector names = split(_target->MeldedFrom, '|'); + MTGCard * cardone = MTGCollection()->getCardByName(names[0]); + MTGCardInstance * cardOne = NEW MTGCardInstance(cardone, _target->owner->game); + MTGCard * cardtwo = MTGCollection()->getCardByName(names[1]); + MTGCardInstance * cardTwo = NEW MTGCardInstance(cardtwo, _target->owner->game); + _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->temp); + _target->controller()->game->garbage->addCard(cardOne); + _target->controller()->game->garbage->addCard(cardTwo); + MTGAbility * a = NEW ABlinkGeneric(game, game->mLayers->actionLayer()->getMaxId(), source, cardOne, blinkueot, blinkForSource, blinkhand, stored); + a->target = (Targetable*)cardOne; + a->oneShot = false; + a->canBeInterrupted = false; + a->resolve(); + SAFE_DELETE(a); + + + MTGAbility * a2 = NEW ABlinkGeneric(game, game->mLayers->actionLayer()->getMaxId(), source, cardTwo, blinkueot, blinkForSource, blinkhand, stored); + a2->target = (Targetable*)cardTwo; + a2->oneShot = false; + a2->canBeInterrupted = false; + a2->resolve(); + SAFE_DELETE(a2); + this->forceDestroy = 1; + this->removeFromGame(); + return; + } + else _target->controller()->game->putInZone(_target, _target->currentZone, _target->owner->game->exile); + if (_target->MeldedFrom.size() || !_target) + { + return; + } if(_target->isToken) { //if our target is a token, we're done as soon as its sent to exile. this->forceDestroy = 1; return; } - _target = _target->next; + + if (_target && _target->next) + _target = _target->next; _target->blinked = true; Blinked = _target; - if(!blinkueot && !blinkForSource) + if (!blinkueot && !blinkForSource) { returnCardIntoPlay(_target); } + } } diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 389427db7..56a79293f 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -154,6 +154,11 @@ void CardGui::Render() quad = AlternateThumbQuad(card); float cardScale = quad ? 40 / quad->mHeight : 1; + //I want the below for melded cards but I dont know how to adjust everything else + //to look neat and clean. leaving this here incase someone else wants to pretty up the p/t box + //and line up the position. + /* if (card->MeldedFrom.size()) + cardScale = cardScale + (10 / quad->mHeight);*/ float scale = actZ * cardScale; JQuadPtr shadow; diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index 33efc8d53..98609951b 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -1128,8 +1128,8 @@ Offering * Offering::clone() const return ec; } -Offering::Offering(TargetChooser *_tc) : -ExtraCost("Select creature to offer", _tc) +Offering::Offering(TargetChooser *_tc,bool emerge) : +ExtraCost("Select creature to offer", _tc), emerge(emerge) { } @@ -1137,28 +1137,77 @@ int Offering::canPay() { if (target && target->has(Constants::CANTBESACRIFIED)) return 0; - - if (target && (!source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + if (emerge) { - tc->removeTarget(target); - target = NULL; - return 0; + if (target) + { + ManaCost * reduced = NEW ManaCost(source->getManaCost()); + reduced->remove(Constants::MTG_COLOR_ARTIFACT, target->getManaCost()->getConvertedCost()); + + if (target && (!source->controller()->getManaPool()->canAfford(reduced))) + { + tc->removeTarget(target); + target = NULL; + SAFE_DELETE(reduced); + return 0; + } + if (target && source->controller()->getManaPool()->canAfford(reduced)) + { + SAFE_DELETE(reduced); + return 1; + } + } + + } + else + { + if (target && (!source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + { + tc->removeTarget(target); + target = NULL; + return 0; + } + if (target && (source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + return 1; } - if (target && (source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) - return 1; return 0; } int Offering::isPaymentSet() { - if (target && (!source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + if (emerge) { - tc->removeTarget(target); - target = NULL; - return 0; + if (target) + { + ManaCost * reduced = NEW ManaCost(source->getManaCost()); + reduced->remove(Constants::MTG_COLOR_ARTIFACT, target->getManaCost()->getConvertedCost()); + + if (target && (!source->controller()->getManaPool()->canAfford(reduced))) + { + tc->removeTarget(target); + target = NULL; + SAFE_DELETE(reduced); + return 0; + } + if (target && source->controller()->getManaPool()->canAfford(reduced)) + { + SAFE_DELETE(reduced); + return 1; + } + } + + } + else + { + if (target && (!source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + { + tc->removeTarget(target); + target = NULL; + return 0; + } + if (target && (source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) + return 1; } - if (target && (source->controller()->getManaPool()->canAfford(source->getManaCost()->Diff(target->getManaCost())))) - return 1; return 0; } @@ -1166,6 +1215,14 @@ int Offering::doPay() { if (target) { + if (emerge) + { + ManaCost * reduced = NEW ManaCost(source->getManaCost()); + reduced->remove(Constants::MTG_COLOR_ARTIFACT, target->getManaCost()->getConvertedCost()); + target->controller()->getManaPool()->pay(reduced); + SAFE_DELETE(reduced); + } + else target->controller()->getManaPool()->pay(source->getManaCost()->Diff(target->getManaCost())); MTGCardInstance * beforeCard = target; source->storedCard = target->createSnapShot(); diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index ea7def80b..cdbfc47b0 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -3296,6 +3296,33 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } + //meld helper class + vector splitMeldFrom = parseBetween(s, "meldfrom(", ")", true); + if (splitMeldFrom.size()) + { + string splitMeldNames = ""; + if (splitMeldFrom[1].size()) + { + splitMeldNames = splitMeldFrom[1]; + } + MTGAbility * a = NEW AAMeldFrom(observer, id, card, target, splitMeldNames); + a->oneShot = true; + return a; + } + + //meld + vector splitMeld = parseBetween(s, "meld(", ")", true); + if (splitMeld.size()) + { + string splitMeldName = ""; + if (splitMeld[1].size()) + { + splitMeldName = splitMeld[1]; + } + MTGAbility * a = NEW AAMeld(observer, id, card, target, splitMeldName); + a->oneShot = true; + return a; + } //flip vector splitFlipStat = parseBetween(s, "flip(", ")", true); if(splitFlipStat.size()) diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 3daf1646d..432f8e965 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -195,6 +195,7 @@ void MTGCardInstance::initMTGCI() morphed = false; turningOver = false; isMorphed = false; + MeldedFrom = ""; isFlipped = false; isPhased = false; isCascaded = false; diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index 6ea83a866..039f43070 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -431,6 +431,34 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone return ret;//don't send event } } + //before adding card to zone, if its Melded, we break it apart + if (from == g->players[0]->game->battlefield || from == g->players[1]->game->battlefield) + { + if(to != g->players[0]->game->battlefield || to != g->players[1]->game->battlefield) + if (copy->previous && copy->previous->MeldedFrom.size()) + { + vector names = split(copy->previous->MeldedFrom, '|'); + MTGCard * cardone = MTGCollection()->getCardByName(names[0]); + MTGCardInstance * cardOne = NEW MTGCardInstance(cardone, copy->owner->game); + to->addCard(cardOne); + WEvent * e = NEW WEventZoneChange(cardOne, from, to); + g->receiveEvent(e); + MTGCard * cardtwo = MTGCollection()->getCardByName(names[1]); + MTGCardInstance * cardTwo = NEW MTGCardInstance(cardtwo, copy->owner->game); + to->addCard(cardTwo); + WEvent * e2 = NEW WEventZoneChange(cardTwo, from, to); + g->receiveEvent(e2); + + if(from == g->players[0]->game->battlefield) + g->players[0]->game->temp->addCard(copy); + if (from == g->players[1]->game->battlefield) + g->players[1]->game->temp->addCard(copy); + WEvent * e3 = NEW WEventZoneChange(copy, from, to); + g->receiveEvent(e3); + return ret; + } + + } to->addCard(copy); //The "Temp" zone are purely for code purposes, and we don't want the abilities engine to //Trigger when cards move in this zone diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index b2c1c3521..c33f1cf17 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -153,6 +153,13 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan } break; case 'e': + if (value == "emerge") + { + if (!tc) + tc = tcf.createTargetChooser("creature|mybattlefield", c); + manaCost->addExtraCost(NEW Offering(tc,true)); + } + else //Exile manaCost->addExtraCost(NEW ExileTargetCost(tc)); break;