From d03ebdace8eb7f6fa156c3b3de96a49b9bc544ac Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Wed, 18 Jan 2017 22:13:51 +0800 Subject: [PATCH] Support for KLD and AER Kaladesh & Aether Revolt --- projects/mtg/include/AllAbilities.h | 21 ++++++ projects/mtg/include/ExtraCost.h | 23 +++++++ projects/mtg/include/MTGDefinitions.h | 4 +- projects/mtg/include/Player.h | 1 + projects/mtg/src/AIPlayerBaka.cpp | 7 ++ projects/mtg/src/AllAbilities.cpp | 70 +++++++++++++++---- projects/mtg/src/CardGui.cpp | 9 +++ projects/mtg/src/ExtraCost.cpp | 99 +++++++++++++++++++++++++++ projects/mtg/src/GuiStatic.cpp | 26 +++++-- projects/mtg/src/MTGAbility.cpp | 42 ++++++++++++ projects/mtg/src/MTGDefinitions.cpp | 4 +- projects/mtg/src/ManaCost.cpp | 18 ++++- projects/mtg/src/Player.cpp | 1 + projects/mtg/src/Rules.cpp | 1 + 14 files changed, 306 insertions(+), 20 deletions(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 6bd22aace..7dc230333 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -560,6 +560,14 @@ private: { intValue = card->controller()->opponent()->raidcount; } + else if (s == "pstormcount") + { + intValue = card->controller()->game->stack->seenThisTurn("*", Constants::CAST_ALL); + } + else if (s == "ostormcount") + { + intValue = card->controller()->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL); + } else if (s == "countallspell") { intValue = card->controller()->game->stack->seenThisTurn("*", Constants::CAST_ALL) + card->controller()->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL); @@ -4514,6 +4522,19 @@ public: AAAlterPoison * clone() const; ~AAAlterPoison(); }; +//Energy Counter +class AAAlterEnergy: public ActivatedAbilityTP +{ +public: + int energy; + + AAAlterEnergy(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int energy, ManaCost * _cost = NULL, + int who = TargetChooser::UNSET); + int resolve(); + const string getMenuText(); + AAAlterEnergy * clone() const; + ~AAAlterEnergy(); +}; /* Standard Damager, can choose a NEW target each time the price is paid */ class TADamager: public TargetAbility { diff --git a/projects/mtg/include/ExtraCost.h b/projects/mtg/include/ExtraCost.h index c6a8e1438..6eca8f69e 100644 --- a/projects/mtg/include/ExtraCost.h +++ b/projects/mtg/include/ExtraCost.h @@ -216,6 +216,19 @@ public: virtual SnowCost * clone() const; }; +//Energy cost +class EnergyCost : public ExtraCost +{ +private: + int enc; + +public: + EnergyCost(int enc = 0); + virtual int canPay(); + virtual int doPay(); + virtual EnergyCost * clone() const; +}; + //untap cost class UnTapCost : public ExtraCost { @@ -295,6 +308,16 @@ public: virtual int doPay(); virtual Delve * clone() const; }; +//improvise +class Improvise : public ExtraCost +{ +public: + Improvise(TargetChooser *_tc = NULL); + virtual int canPay(); + virtual int isPaymentSet(); + virtual int doPay(); + virtual Improvise * clone() const; +}; //offering cost class Offering : public ExtraCost { diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index f218bc8b6..31521b878 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -262,7 +262,9 @@ class Constants CONDUITED = 140, CANBLOCKTAPPED = 141, OPPNOMAXHAND = 142, - NB_BASIC_ABILITIES = 143, + CANTCREW = 143, + HIDDENFACE = 144, + NB_BASIC_ABILITIES = 145, RARITY_S = 'S', //Special Rarity RARITY_M = 'M', //Mythics diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index e63862e78..6ba887610 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -42,6 +42,7 @@ public: int skippingTurn; int extraTurn; int drawCounter; + int energyCount; int epic; int forcefield; int initLife; diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index d02f991ad..f0ce55514 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -595,6 +595,13 @@ int OrderedAIAction::getEfficiency() efficiency = 90; } } + else if (dynamic_cast(a)) + { + if (playerAbilityTarget && playerAbilityTarget == p) + { + efficiency = 90; + } + } else if (ATokenCreator * atc = dynamic_cast(a)) { efficiency = 80; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index d1097855c..5fb08a1e2 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1010,6 +1010,40 @@ AAAlterPoison::~AAAlterPoison() { } +//AA Energy Counters +AAAlterEnergy::AAAlterEnergy(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int energy, ManaCost * _cost, + int who) : + ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), energy(energy) +{ +} + +int AAAlterEnergy::resolve() +{ + Damageable * _target = (Damageable *) getTarget(); + if (_target) + { + Player * pTarget = (Player*)_target; + if(pTarget) + pTarget->energyCount += energy; + } + return 0; +} + +const string AAAlterEnergy::getMenuText() +{ + WParsedInt parsedNum(energy); + return _(parsedNum.getStringValue() + " Energy ").c_str(); +} + +AAAlterEnergy * AAAlterEnergy::clone() const +{ + return NEW AAAlterEnergy(*this); +} + +AAAlterEnergy::~AAAlterEnergy() +{ +} + //Damage Prevent AADamagePrevent::AADamagePrevent(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int preventing, ManaCost * _cost, int who) : @@ -2011,6 +2045,12 @@ int AAProliferate::resolve() a->oneShot = true; pcounters.push_back(a); } + else if(pTarget && pTarget->energyCount && pTarget == source->controller()) + { + MTGAbility * a = NEW AAAlterEnergy(game, game->mLayers->actionLayer()->getMaxId(), source, target, 1, NULL); + a->oneShot = true; + pcounters.push_back(a); + } else if (cTarget && cTarget->counters) { Counters * counters = cTarget->counters; @@ -7909,17 +7949,9 @@ int AACastCard::resolveSpell() } if (_target) { - if (_target->isLand()) - { - MTGCardInstance * copy = _target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->temp,noEvent); - copy->changeController(source->controller(),true); - Spell * spell = NEW Spell(game, 0,copy,NULL,NULL, 1); - spell->resolve(); - delete spell; - } - else - { + putinplay = true; + Spell * spell = NULL; MTGCardInstance * copy = NULL; if ((normal || asNormalMadness)||(!_target->hasType(Subtypes::TYPE_INSTANT) && !_target->hasType(Subtypes::TYPE_SORCERY))) @@ -7943,12 +7975,24 @@ int AACastCard::resolveSpell() if (game->targetChooser) { game->targetChooser->Owner = source->controller(); - spell = game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL, 1, 0); + if(putinplay) + { + spell = NEW Spell(game, 0,copy,game->targetChooser,NULL, 1); + spell->resolve(); + } + else + spell = game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL, 1, 0); game->targetChooser = NULL; } else { - spell = game->mLayers->stackLayer()->addSpell(copy, NULL, NULL, 1, 0); + if(putinplay) + { + spell = NEW Spell(game, 0,copy,NULL,NULL, 1); + spell->resolve(); + } + else + spell = game->mLayers->stackLayer()->addSpell(copy, NULL, NULL, 1, 0); } if (copy->has(Constants::STORM)) @@ -7980,7 +8024,7 @@ int AACastCard::resolveSpell() andAbilityClone->addToGame(); } } - } + this->forceDestroy = true; processed = true; return 1; diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 6fc544d15..bd5cb850b 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -533,6 +533,7 @@ void CardGui::AlternateRender(MTGCard * card, const Pos& pos) // Draw the "unknown" card model JRenderer * renderer = JRenderer::GetInstance(); JQuadPtr q; + MTGCardInstance * thiscard = dynamic_cast (card); float x = pos.actX; @@ -553,6 +554,14 @@ void CardGui::AlternateRender(MTGCard * card, const Pos& pos) items.clear(); if (q.get() && q->mTex) { + //test + //draw black border ingame only + if(thiscard && thiscard->getObserver()) + { + renderer->FillRoundRect((pos.actX - (pos.actZ * 84.f))-11.5f,(pos.actY - (pos.actZ * 119.7f))-14.f,pos.actZ * 168.f + 6.5f,pos.actZ * 239.4f + 12.f,8.f,ARGB(255,5,5,5)); + renderer->DrawRoundRect((pos.actX - (pos.actZ * 84.f))-11.5f,(pos.actY - (pos.actZ * 119.7f))-14.f,pos.actZ * 168.f + 6.5f,pos.actZ * 239.4f + 12.f,8.f,ARGB(50,240,240,240)); + } + q->SetHotSpot(static_cast (q->mTex->mWidth / 2), static_cast (q->mTex->mHeight / 2)); float scale = pos.actZ * 250 / q->mHeight; diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index a1ee9b63b..8b43bd422 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -232,6 +232,37 @@ int SnowCost::doPay() return 0; } +//Energy Cost +EnergyCost * EnergyCost::clone() const +{ + EnergyCost * ec = NEW EnergyCost(*this); + return ec; +} + +EnergyCost::EnergyCost(int enc) : +ExtraCost("Energy Cost"),enc(enc) +{ +} + +int EnergyCost::canPay() +{ + if(source->controller()->energyCount >= enc) + { + return 1; + } + return 0; +} + +int EnergyCost::doPay() +{ + if(source->controller()->energyCount) + { + source->controller()->energyCount -= enc; + return 1; + } + return 0; +} + //life cost LifeCost * LifeCost::clone() const { @@ -1118,6 +1149,74 @@ int Delve::doPay() return 0; } +//IMPROVISE +Improvise * Improvise::clone() const +{ + Improvise * ec = NEW Improvise(*this); + if (tc) + ec->tc = tc->clone(); + return ec; +} + +Improvise::Improvise(TargetChooser *_tc) : + ExtraCost("Select Artifacts To Tap", _tc) +{ +} + +int Improvise::canPay() +{ + return isPaymentSet(); +} + +int Improvise::isPaymentSet() +{ + ManaCost * toReduce = NEW ManaCost(source->getManaCost()); + tc->maxtargets = source->getManaCost()->getCost(Constants::MTG_COLOR_ARTIFACT); + if (tc->getNbTargets()) + { + toReduce->remove(Constants::MTG_COLOR_ARTIFACT, tc->getNbTargets()); + } + if (target && (!source->controller()->getManaPool()->canAfford(toReduce))) + { + target = NULL; + SAFE_DELETE(toReduce); + return 0; + } + if (target && (source->controller()->getManaPool()->canAfford(toReduce))) + { + /*if (target->getObserver()->guiOpenDisplay) + target->getObserver()->ButtonPressed(target->getObserver()->guiOpenDisplay);*/ + SAFE_DELETE(toReduce); + return 1; + } + SAFE_DELETE(toReduce); + return 0; +} + +int Improvise::doPay() +{ + if (target && tc->getNbTargets()) + { + ManaCost * toReduce = NEW ManaCost(source->getManaCost()); + + toReduce->remove(Constants::MTG_COLOR_ARTIFACT, tc->getNbTargets()); + + target->controller()->getManaPool()->pay(toReduce); + SAFE_DELETE(toReduce); + vectortargetlist = tc->getTargetsFrom(); + for (vector::iterator it = targetlist.begin(); it != targetlist.end(); it++) + { + MTGCardInstance * targetCard = dynamic_cast(*it); + source->storedCard = targetCard->createSnapShot(); + targetCard->tap(); + } + if (tc) + tc->initTargets(); + return 1; + } + return 0; +} + /////////////// //Sacrifice target as cost for Offering Offering * Offering::clone() const diff --git a/projects/mtg/src/GuiStatic.cpp b/projects/mtg/src/GuiStatic.cpp index baa30379a..97ab1cf4a 100644 --- a/projects/mtg/src/GuiStatic.cpp +++ b/projects/mtg/src/GuiStatic.cpp @@ -31,6 +31,7 @@ void GuiAvatar::Render() JRenderer * r = JRenderer::GetInstance(); int life = player->life; int poisonCount = player->poisonCount; + int energyCount = player->energyCount; WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); //Avatar @@ -108,10 +109,10 @@ void GuiAvatar::Render() { case TOP_LEFT: mFont->SetColor(ARGB((int)actA / 4, 0, 0, 0)); - mFont->DrawString(buffer, actX + 2, actY + 2); + mFont->DrawString(buffer, actX + 2, actY - 2); mFont->SetScale(1.3f); mFont->SetColor(ARGB((int)actA, lx, ly, lz)); - mFont->DrawString(buffer, actX + 1, actY + 1); + mFont->DrawString(buffer, actX + 1, actY - 1); mFont->SetScale(1); break; case BOTTOM_RIGHT: @@ -122,8 +123,8 @@ void GuiAvatar::Render() break; } //poison - char poison[5]; - if (poisonCount > 0) + char poison[10]; + if (poisonCount >= 0) { sprintf(poison, "%i", poisonCount); switch (corner) @@ -138,6 +139,23 @@ void GuiAvatar::Render() break; } } + //energy + char energy[15]; + if (energyCount >= 0) + { + sprintf(energy, "%i", energyCount); + switch (corner) + { + case TOP_LEFT: + mFont->SetColor(ARGB((int)actA / 1, 255, 255, 0)); + mFont->DrawString(energy, actX + 2, actY + 17); + break; + case BOTTOM_RIGHT: + mFont->SetColor(ARGB((int)actA / 1 ,255, 255, 0)); + mFont->DrawString(energy, actX, actY - 27, JGETEXT_RIGHT); + break; + } + } PlayGuiObject::Render(); } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 81be0636c..cb39af59d 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -329,6 +329,37 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe if(!count) return 0; } + check = restriction[i].find("revolt"); + if(check != string::npos) + { + int count = 0; + for(unsigned int k = 0; k < player->game->hand->cardsSeenThisTurn.size(); k++) + { + MTGCardInstance * tCard = player->game->hand->cardsSeenThisTurn[k]; + if(tCard && tCard->previousZone == card->controller()->game->battlefield) + count++; + } + for(unsigned int k = 0; k < player->game->exile->cardsSeenThisTurn.size(); k++) + { + MTGCardInstance * tCard = player->game->exile->cardsSeenThisTurn[k]; + if(tCard && tCard->previousZone == card->controller()->game->battlefield) + count++; + } + for(unsigned int k = 0; k < player->game->library->cardsSeenThisTurn.size(); k++) + { + MTGCardInstance * tCard = player->game->library->cardsSeenThisTurn[k]; + if(tCard && tCard->previousZone == card->controller()->game->battlefield) + count++; + } + for(unsigned int k = 0; k < player->game->graveyard->cardsSeenThisTurn.size(); k++) + { + MTGCardInstance * tCard = player->game->graveyard->cardsSeenThisTurn[k]; + if(tCard && tCard->previousZone == card->controller()->game->battlefield) + count++; + } + if(!count) + return 0; + } check = restriction[i].find("morbid"); if(check != string::npos) { @@ -2949,6 +2980,17 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } + //alter energy + vector splitEnergy = parseBetween(s, "alterenergy:", " ", false); + if (splitEnergy.size()) + { + int energy = atoi(splitEnergy[1].c_str()); + Targetable * t = spell ? spell->getNextTarget() : NULL; + MTGAbility * a = NEW AAAlterEnergy(observer, id, card, t, energy, NULL, who); + a->oneShot = 1; + return a; + } + //prevent next damage vector splitPrevent = parseBetween(s, "prevent:", " ", false); if (splitPrevent.size()) diff --git a/projects/mtg/src/MTGDefinitions.cpp b/projects/mtg/src/MTGDefinitions.cpp index 8087fcb11..363f1a6e7 100644 --- a/projects/mtg/src/MTGDefinitions.cpp +++ b/projects/mtg/src/MTGDefinitions.cpp @@ -173,7 +173,9 @@ const char* Constants::MTGBasicAbilities[] = { "asflash", "conduited", "canblocktapped", - "oppnomaxhand" + "oppnomaxhand", + "cantcrew", + "hiddenface"//test for facedown }; map Constants::MTGBasicAbilitiesMap; diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index 77f67eb65..289c1351f 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -159,6 +159,15 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan tc = tcf.createTargetChooser("creature|mybattlefield", c); manaCost->addExtraCost(NEW Offering(tc,true)); } + else if(value.substr(0,2) == "e:") + {//Energy Cost + vectorvalSplit = parseBetween(value,"e:"," ",false); + if (valSplit.size()) { + WParsedInt* energytopay = NEW WParsedInt(valSplit[1], NULL, c); + manaCost->addExtraCost(NEW EnergyCost(energytopay->getValue())); + SAFE_DELETE(energytopay); + } + } else //Exile manaCost->addExtraCost(NEW ExileTargetCost(tc)); @@ -248,12 +257,19 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan break; } case 'i' : + if(value == "improvise") + { + if(!tc) + tc = tcf.createTargetChooser("artifact[-tapped]|myBattlefield", c); + manaCost->addExtraCost(NEW Improvise(tc)); + } + else { SAFE_DELETE(tc); manaCost->add(0,1); manaCost->addExtraCost(NEW SnowCost); - break; } + break; case 'q': if(value == "q") { diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 6fcb9b0fd..6a95ca748 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -34,6 +34,7 @@ Player::Player(GameObserver *observer, string file, string fileSmall, MTGDeck * skippingTurn = 0; extraTurn = 0; drawCounter = 0; + energyCount = 0; epic = 0; forcefield = 0; raidcount = 0; diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 5bf16d833..fc4681608 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -409,6 +409,7 @@ void Rules::initGame(GameObserver *g, bool currentPlayerSet) p->poisonCount = initState.playerData[i].player->poisonCount; p->damageCount = initState.playerData[i].player->damageCount; p->preventable = initState.playerData[i].player->preventable; + p->energyCount = initState.playerData[i].player->energyCount; if (initState.playerData[i].player->mAvatarName.size()) { p->mAvatarName = initState.playerData[i].player->mAvatarName;