Added a new rule to flip back modal dual face card on each phase and after each action, fixed "Aladdin's Lamp" and "Turntimber Symbiosis" primitives, allowed the AI to play back side of modal dual face cards, improved the "doubleside" keyword to flip modal dual face cards, improved filters to target flipped cards using the "isflipped" keyword, fixed a crash when zone pointer was null in GameObserver::logAction method.

This commit is contained in:
Vittorio Alfieri
2021-04-28 17:03:29 +02:00
parent ac273b1947
commit 79716a4533
9 changed files with 93 additions and 13 deletions
+17 -1
View File
@@ -53,7 +53,6 @@ auto=lord(Swamp[-noactivatedability;-nomanaability;-notapability;land]|MyBattlef
auto=lord(Mountain[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{R} auto=lord(Mountain[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{R}
auto=lord(Forest[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{G} auto=lord(Forest[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{G}
#Mana Empties from manapool at the end of each phase #Mana Empties from manapool at the end of each phase
auto=@each untap:removeMana(*) auto=@each untap:removeMana(*)
auto=@each upkeep:removeMana(*) auto=@each upkeep:removeMana(*)
@@ -68,6 +67,23 @@ auto=@each secondmain:removeMana(*)
auto=@each end:removeMana(*) auto=@each end:removeMana(*)
auto=@each cleanup:removeMana(*) auto=@each cleanup:removeMana(*)
#Modal dual face card flip back rule
auto=@each untap restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each upkeep restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each draw restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each firstmain restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatbegins restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each attackers restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each blockers restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatdamage restriction{type(*[isflipped]|nonbattlezone))~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatEnds restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each secondmain restriction{type(*[isflipped]|nonbattlezone))~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each end restriction{compare(type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each cleanup restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|nonbattlezone) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|stack) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|battlefield) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
#Monarch rule #Monarch rule
auto=@each my endofturn restriction{compare(pmonarch)~morethan~0}:draw:1 auto=@each my endofturn restriction{compare(pmonarch)~morethan~0}:draw:1
+17 -2
View File
@@ -45,7 +45,6 @@ auto=sethand:7
auto=@each my draw:draw:1 auto=@each my draw:draw:1
auto=maxPlay(land)1 auto=maxPlay(land)1
#Lands Mana Rules #Lands Mana Rules
auto=lord(Plains[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{W} auto=lord(Plains[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{W}
auto=lord(Island[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{U} auto=lord(Island[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{U}
@@ -53,7 +52,6 @@ auto=lord(Swamp[-noactivatedability;-nomanaability;-notapability;land]|MyBattlef
auto=lord(Mountain[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{R} auto=lord(Mountain[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{R}
auto=lord(Forest[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{G} auto=lord(Forest[-noactivatedability;-nomanaability;-notapability;land]|MyBattlefield) {T}:Add{G}
#Mana Empties from manapool at the end of each phase #Mana Empties from manapool at the end of each phase
auto=@each untap:removeMana(*) auto=@each untap:removeMana(*)
auto=@each upkeep:removeMana(*) auto=@each upkeep:removeMana(*)
@@ -68,6 +66,23 @@ auto=@each secondmain:removeMana(*)
auto=@each end:removeMana(*) auto=@each end:removeMana(*)
auto=@each cleanup:removeMana(*) auto=@each cleanup:removeMana(*)
#Modal dual face card flip back rule
auto=@each untap restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each upkeep restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each draw restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each firstmain restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatbegins restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each attackers restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each blockers restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatdamage restriction{type(*[isflipped]|nonbattlezone))~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each combatEnds restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each secondmain restriction{type(*[isflipped]|nonbattlezone))~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each end restriction{compare(type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@each cleanup restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|nonbattlezone) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|stack) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
auto=@movedto(other *|battlefield) restriction{type(*[isflipped]|nonbattlezone)~morethan~0}:ability$!all(*[isflipped]|nonbattlezone) doubleside()!$ controller
#Monarch rule #Monarch rule
auto=@each my endofturn restriction{compare(pmonarch)~morethan~0}:draw:1 auto=@each my endofturn restriction{compare(pmonarch)~morethan~0}:draw:1
@@ -974,7 +974,7 @@ auto={6}{T}:name(X=6) name(X=6) transforms((,newability[replacedraw reveal:6 opt
auto={7}{T}:name(X=7) name(X=7) transforms((,newability[replacedraw reveal:7 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=6]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot auto={7}{T}:name(X=7) name(X=7) transforms((,newability[replacedraw reveal:7 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=6]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot
auto={8}{T}:name(X=8) name(X=8) transforms((,newability[replacedraw reveal:8 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=7]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot auto={8}{T}:name(X=8) name(X=8) transforms((,newability[replacedraw reveal:8 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=7]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot
auto={9}{T}:name(X=9) name(X=9) transforms((,newability[replacedraw reveal:9 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=8]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot auto={9}{T}:name(X=9) name(X=9) transforms((,newability[replacedraw reveal:9 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=8]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend])) ueot
auto={10}{T}:name(X=10) name(X=10) transforms((,newability[replacedraw reveal:10 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=9]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend afterreveal all(*[zpos<=10]) moveto(myhand) afterrevealend revealend])) ueot auto={10}{T}:name(X=10) name(X=10) transforms((,newability[replacedraw reveal:10 optionone name(Choose a card) target(*|reveal) moveto(myhand) and!( all(*[zpos<=9]|mylibrary) moveto(myhand) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend afterrevealed all(*[zpos<=10]) moveto(myhand) afterrevealedend revealend])) ueot
text={X}, {T}: The next time you would draw a card this turn, instead look at the top X cards of your library, put all but one of them on the bottom of your library in a random order, then draw a card. X can't be 0. text={X}, {T}: The next time you would draw a card this turn, instead look at the top X cards of your library, put all but one of them on the bottom of your library in a random order, then draw a card. X can't be 0.
mana={10} mana={10}
type=Artifact type=Artifact
@@ -59937,8 +59937,8 @@ name=Turntimber Symbiosis
restriction=compare(isflipped)~equalto~0 restriction=compare(isflipped)~equalto~0
anyzone={0}:doubleside(Turntimber, Serpentine Wood) anyzone={0}:doubleside(Turntimber, Serpentine Wood)
autohand={0}:restriction{can play land,compare(isflipped)~equalto~1} name(Turntimber, Serpentine Wood) name(Turntimber, Serpentine Wood) flip(Turntimber, Serpentine Wood) forcetype(land) autohand={0}:restriction{can play land,compare(isflipped)~equalto~1} name(Turntimber, Serpentine Wood) name(Turntimber, Serpentine Wood) flip(Turntimber, Serpentine Wood) forcetype(land)
auto=choice name(Look seven and put creature with manacost 3 or less) name(Look seven and put creature with manacost 3 or less) reveal:7 optionone name(Get Creature) target(creature[manacost<=3]|reveal) moveTo(myBattlefield) and!( counter(1/1,3) )! optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend restriction{type(creature[manacost<=3;zpos<=7]|myLibrary)~morethan~0} aicode=activate target(*[zpos=1]|mylibrary) transforms((,newability[if type(creature[zpos<=7]|mylibrary)~equalto~0 then all(*[zpos<=7]|mylibrary) moveto(myreveal) and!( bottomoflibrary )!],newability[if type(creature[zpos<=7]|mylibrary)~morethan~0 then target(creature[zpos<=7]|mylibrary) moveto(myBattlefield) and!( transforms((,newability[all(*[zpos<=7]|mylibrary) moveto(myreveal) and!( bottomoflibrary )!],newability[if cantargetcard(creature[manacost<=3]|*) then counter(1/1.3)])) oneshot )! ])) oneshot
auto=choice name(Look seven and put creature with manacost 4 or more) name(Look seven and put creature with manacost 4 or more) reveal:7 optionone name(Get Creature) target(creature[manacost>=4]|reveal) moveTo(myBattlefield) optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend restriction{type(creature[manacost>=4;zpos<=7]|myLibrary)~morethan~0} auto=name(Look seven and put creature in play) reveal:7 optionone name(Get Creature) target(<upto:1>creature|reveal) moveTo(mylibrary) and!( becomes(tobecast) ueot )! optiononeend optiontwo name(put on bottom) target(*|reveal) bottomoflibrary and!( all(*|reveal) bottomoflibrary )! optiontwoend afterrevealed all(tobecast|mylibrary) moveto(myBattlefield) and!( transforms((,newability[if cantargetcard(creature[manacost<=3]|*) then counter(1/1.3)])) oneshot )! afterrevealedend revealend
text=Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. If that card has converted mana cost 3 or less, it enters with three additional +1/+1 counters on it. Put the rest on the bottom of your library in a random order. // Turntimber, Serpentine Wood text=Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. If that card has converted mana cost 3 or less, it enters with three additional +1/+1 counters on it. Put the rest on the bottom of your library in a random order. // Turntimber, Serpentine Wood
mana={4}{G}{G}{G} mana={4}{G}{G}{G}
type=Sorcery type=Sorcery
+4 -2
View File
@@ -632,9 +632,11 @@ int OrderedAIAction::getEfficiency()
efficiency = 90; efficiency = 90;
} }
} }
else if (dynamic_cast<AATurnSide *>(a)) else if (AATurnSide * ats = dynamic_cast<AATurnSide *>(a))
{ {
efficiency = 0; // AI does not have to use the doubleside ability to avoid loops. efficiency = 0; // AI does not have to use the doubleside ability to avoid loops but it can randomly choose to flip card and cast its back side.
if(std::rand() % 2)
ats->source->isFlipped = !ats->source->isFlipped;
} }
else if (ATokenCreator * atc = dynamic_cast<ATokenCreator *>(a)) else if (ATokenCreator * atc = dynamic_cast<ATokenCreator *>(a))
{ {
+21 -4
View File
@@ -4349,12 +4349,15 @@ int AATurnSide::resolve()
if(_target->mutation && _target->parentCards.size() > 0) return 0; // Mutated down cards cannot be turned, they will follow the fate of top-card if(_target->mutation && _target->parentCards.size() > 0) return 0; // Mutated down cards cannot be turned, they will follow the fate of top-card
MTGCard * fcard; MTGCard * fcard;
MTGCardInstance* sideCard; MTGCardInstance* sideCard;
if(_target->controller()->isAI() && _target->isFlipped) _target->isFlipped = false; // If it's AI calling back we just have to reset isFLipped flag and then return.
if(!_target->isFlipped && _SideName == "") return 0; // No need to turn front if card has not been flipped before.
if(!_target->isFlipped){ if(!_target->isFlipped){
fcard = MTGCollection()->getCardByName(_SideName); fcard = MTGCollection()->getCardByName(_SideName);
if(!fcard) return 0; if(!fcard) return 0;
sideCard = NEW MTGCardInstance(fcard, _target->controller()->game); sideCard = NEW MTGCardInstance(fcard, _target->controller()->game);
_target->nameOrig = _target->name; _target->nameOrig = _target->name;
_target->name = sideCard->name; _target->name = sideCard->name;
_target->setName(sideCard->name);
if(!sideCard) return 0; if(!sideCard) return 0;
if(sideCard->getManaCost()){ if(sideCard->getManaCost()){
if(_target->getManaCost()->getAlternative()){ if(_target->getManaCost()->getAlternative()){
@@ -4367,6 +4370,7 @@ int AATurnSide::resolve()
fcard = MTGCollection()->getCardByName(_target->nameOrig); fcard = MTGCollection()->getCardByName(_target->nameOrig);
if(!fcard) return 0; if(!fcard) return 0;
_target->name = _target->nameOrig; _target->name = _target->nameOrig;
_target->setName(_target->nameOrig);
_target->nameOrig = ""; _target->nameOrig = "";
sideCard = NEW MTGCardInstance(fcard, _target->controller()->game); sideCard = NEW MTGCardInstance(fcard, _target->controller()->game);
if(!sideCard) return 0; if(!sideCard) return 0;
@@ -4375,13 +4379,26 @@ int AATurnSide::resolve()
_target->getManaCost()->copy(sideCard->getManaCost()); // Restore the original side cost mana symbols. _target->getManaCost()->copy(sideCard->getManaCost()); // Restore the original side cost mana symbols.
} }
} }
for (int i = ((int)_target->types.size())-1; i >= 0; --i) // Load all the types from the current side if(_target->owner->playMode != Player::MODE_TEST_SUITE)
_target->removeType(_target->types[i]); {
for (int i = 0; i < ((int)sideCard->types.size()); i++) _target->setMTGId(sideCard->getMTGId());
_target->addType(sideCard->types[i]); _target->setId = sideCard->setId;
}
_target->power = sideCard->power;
_target->life = sideCard->life;
_target->toughness = sideCard->toughness;
_target->origpower = sideCard->origpower;
_target->origtoughness = sideCard->origtoughness;
_target->basepower = sideCard->basepower;
_target->basetoughness = sideCard->basetoughness;
_target->types = sideCard->types;
_target->text = sideCard->text; _target->text = sideCard->text;
_target->formattedText = sideCard->formattedText; _target->formattedText = sideCard->formattedText;
_target->magicText = sideCard->magicText;
_target->colors = sideCard->colors;
_target->basicAbilities = sideCard->basicAbilities;
_target->isFlipped = !_target->isFlipped; _target->isFlipped = !_target->isFlipped;
_target->mPropertiesChangedSinceLastUpdate = true;
SAFE_DELETE(sideCard); SAFE_DELETE(sideCard);
return 1; return 1;
} }
+5
View File
@@ -281,6 +281,11 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
match = NULL; match = NULL;
} }
if (isFlipped != card->isFlipped)
{
match = NULL;
}
if ((tapped == -1 && card->isTapped()) || (tapped == 1 && !card->isTapped())) if ((tapped == -1 && card->isTapped()) || (tapped == 1 && !card->isTapped()))
{ {
match = NULL; match = NULL;
+12
View File
@@ -1544,6 +1544,18 @@ bool CardGui::FilterCard(MTGCard * _card,string filter)
cd.isToken = 1; cd.isToken = 1;
} }
} }
//Has been flipped
else if (attribute.find("isflipped") != string::npos)
{
if (minus)
{
cd.isFlipped = false;
}
else
{
cd.isFlipped = true;
}
}
//Has x in cost //Has x in cost
else if (attribute.find("hasx") != string::npos) else if (attribute.find("hasx") != string::npos)
{ {
+2 -1
View File
@@ -2125,8 +2125,9 @@ void GameObserver::logAction(Player* player, const string& s) {
void GameObserver::logAction(MTGCardInstance* card, MTGGameZone* zone, size_t index, int result) { void GameObserver::logAction(MTGCardInstance* card, MTGGameZone* zone, size_t index, int result) {
stringstream stream; stringstream stream;
if(zone == NULL) zone = card->currentZone; if(zone == NULL) zone = card->currentZone;
string zoneName = (zone != NULL)?zone->getName():"UnknownZone"; // Fixed a crash when zone pointer was null.
stream << "p" << ((card->controller()==players[0])?"1.":"2.") stream << "p" << ((card->controller()==players[0])?"1.":"2.")
<< zone->getName()<< "[" << index << "] " << zoneName << "[" << index << "] "
<< result << card->getLCName(); << result << card->getLCName();
logAction(stream.str()); logAction(stream.str());
} }
+12
View File
@@ -590,6 +590,18 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->isToken = 1; cd->isToken = 1;
} }
} }
//Has been flipped
else if (attribute.find("isflipped") != string::npos)
{
if (minus)
{
cd->isFlipped = false;
}
else
{
cd->isFlipped = true;
}
}
//Has x in cost //Has x in cost
else if (attribute.find("hasx") != string::npos) else if (attribute.find("hasx") != string::npos)
{ {