Fixed primitives, added new ability "hasaftermath" to implement Aftermath cost with Flashback and refactored all cards with Aftermath cost (now they use a special version of Flashback but they don't count as flashback spell), added a new ability "spellmover" to implement all cards that have to target a spell on stack to move to some other zone (they are not real counters so they don't care about "nofizzle" or "nofizzlealternative" abilites of their target), fixed all primitives with "spellmover" ability, added a new keyword "storedname" to target card with a specifc previously stored name, improved "fizzleto" ability in order to allow to move the fizzled card on second place from the top or to exile and imprint the target name.

This commit is contained in:
Vittorio Alfieri
2021-10-13 23:42:45 +02:00
parent fbcb1feb88
commit 9c2eee7d7e
13 changed files with 246 additions and 120 deletions
+38 -4
View File
@@ -1356,7 +1356,7 @@ int ActionStack::garbageCollect()
}
// Fizzle action and put it in targetZone
void ActionStack::Fizzle(Interruptible * action, FizzleMode fizzleMode)
void ActionStack::Fizzle(Interruptible * action, MTGCardInstance * fizzler, FizzleMode fizzleMode)
{
if (!action)
{
@@ -1366,6 +1366,8 @@ void ActionStack::Fizzle(Interruptible * action, FizzleMode fizzleMode)
if (action->type == ACTION_SPELL)
{
Spell * spell = (Spell *) action;
MTGCardInstance * _target = NULL;
unsigned int position = 0;
switch (fizzleMode) {
case PUT_IN_GRAVEARD:
spell->source->controller()->game->putInGraveyard(spell->source);
@@ -1374,17 +1376,49 @@ void ActionStack::Fizzle(Interruptible * action, FizzleMode fizzleMode)
spell->source->controller()->game->putInHand(spell->source);
break;
case PUT_IN_EXILE:
spell->source->controller()->game->putInExile(spell->source);
case PUT_IN_EXILE_IMPRINT:
_target = spell->source->controller()->game->putInExile(spell->source);
if (_target && fizzler && fizzleMode == PUT_IN_EXILE_IMPRINT){
fizzler->imprintedCards.push_back(_target);
if (fizzler->imprintedCards.size()){
if (fizzler->imprintedCards.back()->getName().size()){
fizzler->currentimprintName = fizzler->imprintedCards.back()->getName();
fizzler->imprintedNames.push_back(fizzler->imprintedCards.back()->getName());
}
}
}
break;
case PUT_IN_LIBRARY_TOP:
case PUT_IN_LIBRARY_SECOND:
case PUT_IN_LIBRARY_BOTTOM:
MTGCardInstance * _target = spell->source->controller()->game->putInLibrary(spell->source);
_target = spell->source->controller()->game->putInLibrary(spell->source);
if (_target && fizzleMode == PUT_IN_LIBRARY_BOTTOM){
MTGLibrary * library = _target->owner->game->library;
vector<MTGCardInstance *>oldOrder = library->cards;
vector<MTGCardInstance *>newOrder;
newOrder.push_back(_target);
for(unsigned int k = 0;k < oldOrder.size();++k)
for(unsigned int k = 0 ;k < oldOrder.size(); ++k)
{
MTGCardInstance * rearranged = oldOrder[k];
if(rearranged != _target)
newOrder.push_back(rearranged);
}
library->cards = newOrder;
} else if (_target && fizzleMode == PUT_IN_LIBRARY_SECOND){
position = 2;
MTGLibrary * library = _target->owner->game->library;
vector<MTGCardInstance *>oldOrder = library->cards;
vector<MTGCardInstance *>newOrder;
if(position > oldOrder.size())
position = oldOrder.size(); //Avoid to exceed the library dimension.
for(unsigned int k = 0; k < oldOrder.size() - position; ++k)
{
MTGCardInstance * rearranged = oldOrder[k];
if(rearranged != _target)
newOrder.push_back(rearranged);
}
newOrder.push_back(_target);
for(unsigned int k = oldOrder.size() - position ; k < oldOrder.size(); ++k)
{
MTGCardInstance * rearranged = oldOrder[k];
if(rearranged != _target)
+5 -3
View File
@@ -3890,6 +3890,8 @@ ActivatedAbility(observer, _id, card, _cost, 0)
// by default we put the spell to graveyard after fizzling
fizzleMode = ActionStack::PUT_IN_GRAVEARD;
// by default fizzle is not used to put spell somewhere
spellMover = false;
}
int AAFizzler::resolve()
@@ -3910,9 +3912,9 @@ int AAFizzler::resolve()
MTGCardInstance* sCard = NULL;
if (sTarget)
sCard = sTarget->source;
if (!sCard || !sTarget || sCard->has(Constants::NOFIZZLE))
if (!sCard || !sTarget || (sCard->has(Constants::NOFIZZLE) && !spellMover))
return 0;
if (sCard->has(Constants::NOFIZZLEALTERNATIVE) && sCard->alternateCostPaid[ManaCost::MANA_PAID_WITH_ALTERNATIVE]) // No fizzle if card has been paid with alternative cost.
if (sCard->has(Constants::NOFIZZLEALTERNATIVE) && (sCard->alternateCostPaid[ManaCost::MANA_PAID_WITH_ALTERNATIVE] && !spellMover)) // No fizzle if card has been paid with alternative cost.
return 0;
if (source->alias == 111057 && sTarget)//Draining Whelk
{
@@ -3921,7 +3923,7 @@ int AAFizzler::resolve()
source->counters->addCounter(1,1);
}
}
stack->Fizzle(sTarget, fizzleMode);
stack->Fizzle(sTarget, source, fizzleMode);
if(!source->storedCard)
source->storedCard = sCard; // Store the fizzled card to retrive target information later (e.g. manacost for Reinterpret)
return 1;
+1 -1
View File
@@ -277,7 +277,7 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
match = NULL; //Some kicker costs are not a real kicker (e.g. Fuse cost).
}
if ((hasFlashbackCost == -1 && card->getManaCost()->getFlashback()) || (hasFlashbackCost == 1 && !card->getManaCost()->getFlashback()))
if ((hasFlashbackCost == -1 && (card->getManaCost()->getFlashback() && !card->has(Constants::HASAFTERMATH))) || (hasFlashbackCost == 1 && (!card->getManaCost()->getFlashback() || (card->getManaCost()->getFlashback() && card->has(Constants::HASAFTERMATH)))))
{
match = NULL;
}
+1 -1
View File
@@ -963,7 +963,7 @@ void GameStateDuel::Update(float dt)
if(game->getCurrentTargetChooser()->getNbTargets() < 1)
menu->Add(MENUITEM_TOGGLE_SELECT_ALL, "Select all Targets");
else {
menu->Add(MENUITEM_TOGGLE_SELECT_ALL, "Remove Selection");
menu->Add(MENUITEM_TOGGLE_SELECT_ALL, "Clear Selection");
menu->Add(MENUITEM_CONFIRM_SELECT_ALL, "Confirm Selection");
}
}
+11 -2
View File
@@ -2968,9 +2968,11 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a;
}
// Fizzle (counterspell...) and put to zone
// Fizzle (counterspell...) and put to zone or Move spell to zone
// This should always be above "fizzle" section
vector<string> splitFizzle = parseBetween(s, "fizzleto(", ")");
vector<string> splitFizzle = parseBetween(s, "spellmover(", ")");
if (!splitFizzle.size())
splitFizzle = parseBetween(s, "fizzleto(", ")");
if (splitFizzle.size())
{
// currently only hand, exile and library are supported
@@ -2982,9 +2984,15 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
} else if (zone == "exile")
{
fizzleMode = ActionStack::PUT_IN_EXILE;
} else if (zone == "exileimp")
{
fizzleMode = ActionStack::PUT_IN_EXILE_IMPRINT;
} else if (zone == "librarytop")
{
fizzleMode = ActionStack::PUT_IN_LIBRARY_TOP;
} else if (zone == "librarysecond")
{
fizzleMode = ActionStack::PUT_IN_LIBRARY_SECOND;
} else if (zone == "librarybottom")
{
fizzleMode = ActionStack::PUT_IN_LIBRARY_BOTTOM;
@@ -2994,6 +3002,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
starget = spell->getNextSpellTarget();
AAFizzler * a = NEW AAFizzler(observer, id, card, starget);
a->fizzleMode = fizzleMode;
a->spellMover = (s.find("spellmover(") != string::npos);
a->oneShot = 1;
return a;
}
+10
View File
@@ -197,6 +197,16 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->setFlashback(ManaCost::parseManaCost(value));
size_t name = value.find("name(");
string theName = "";
if(name != string::npos)
{
size_t endName = value.find(")",name);
theName = value.substr(name + 5,endName - name - 5);
value.erase(name, endName - name + 1);
}
if(theName.size())
cost->getFlashback()->alternativeName.append(theName);
}
}
break;
+2 -1
View File
@@ -235,7 +235,8 @@ const char* Constants::MTGBasicAbilities[] = {
"nightbound", //Card has nightbound (e.g. "Moonrage Brute")
"decayed", //Card has decayed.
"hasstrive", //Kicker cost is a strive cost (e.g. "Aerial Formation")
"isconspiracy" //The card is a conspiracy (e.g. "Double Stroke")
"isconspiracy", //The card is a conspiracy (e.g. "Double Stroke")
"hasaftermath" //Flashback cost is an aftemath cost (e.g. "Claim // Fame")
};
map<string,int> Constants::MTGBasicAbilitiesMap;
+10
View File
@@ -1076,6 +1076,16 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->nameComparisonMode = COMPARISON_EQUAL;
}
if (attribute.find("storedname") != string::npos && card->storedCard)
{
attributefound = 1;
cd->compareName = card->storedCard->getName();
if (minus)
cd->nameComparisonMode = COMPARISON_UNEQUAL;
else
cd->nameComparisonMode = COMPARISON_EQUAL;
}
if (attribute.find("preyname") != string::npos && card->hauntedCard)
{
attributefound = 1;