Fixed some primitives from issue #1085 and from Discord channel, fixed all curses primitives and targets, added new keywords "oppotgt" and "ctrltgt" to check wich player has been targeted from a card, fixed an issue on "chooseaname" ability.

This commit is contained in:
Vittorio Alfieri
2023-07-13 17:24:11 +02:00
parent c170733af6
commit fbfcb7d3ac
9 changed files with 298 additions and 174 deletions

View File

@@ -3817,7 +3817,7 @@ GenericRollDie::~GenericRollDie()
//set die result
AASetDie::AASetDie(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, int _side, int _diefaces, string toAlter):
InstantAbility(observer, id, source),side(_side), diefaces(_diefaces), abilityToAlter(toAlter)
InstantAbility(observer, id, source), side(_side), diefaces(_diefaces), abilityToAlter(toAlter)
{
this->target = _target;
abilityAltered = NULL;
@@ -3833,12 +3833,12 @@ int AASetDie::resolve()
_target->dieNumFaces = diefaces;
WEvent * e = NEW WEventCardRollDie(_target, source->controller()->getDisplayName());
game->receiveEvent(e);
vector<string>Win = parseBetween(abilityToAlter,"winability "," winabilityend");
vector<string>Win = parseBetween(abilityToAlter, "winability ", " winabilityend");
if(Win.size())
{
abilityWin = Win[1];
}
vector<string>Lose = parseBetween(abilityToAlter,"loseability "," loseabilityend");
vector<string>Lose = parseBetween(abilityToAlter, "loseability ", " loseabilityend");
if(Lose.size())
{
abilityLose = Lose[1];
@@ -3860,14 +3860,14 @@ int AASetDie::resolve()
abilityAltered->addToGame();
}
msg << "Result is: " << roll << ". You Won The Die Roll";
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, msg.str());
MTGAbility * message = NEW MTGEventText(game, this->GetId(), source, msg.str());
message->oneShot = true;
message->addToGame();
}
else if(abilityWin.size() && !abilityLose.size())
{
msg << "Result is: " << roll << ". You Lost The Die Roll";
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, msg.str());
MTGAbility * message = NEW MTGEventText(game, this->GetId(), source, msg.str());
message->oneShot = true;
message->addToGame();
}
@@ -3886,14 +3886,14 @@ int AASetDie::resolve()
abilityAltered->addToGame();
}
msg << "Result is: " << roll << ". You Lost The Die Roll";
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, msg.str());
MTGAbility * message = NEW MTGEventText(game, this->GetId(), source, msg.str());
message->oneShot = true;
message->addToGame();
}
else if(abilityLose.size())
{
msg << "Result is: " << roll << ". You Won The Die Roll";
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, msg.str());
MTGAbility * message = NEW MTGEventText(game, this->GetId(), source, msg.str());
message->oneShot = true;
message->addToGame();
}

View File

@@ -726,7 +726,6 @@ void GameObserver::gameStateBasedEffects()
for (int i = 0; i < 2; i++)
{
MTGGameZone * zone = players[i]->game->inPlay;
players[i]->curses.clear();
for (int j = zone->nb_cards - 1; j >= 0; j--)
{
MTGCardInstance * card = zone->cards[j];
@@ -843,10 +842,6 @@ void GameObserver::gameStateBasedEffects()
{
card->target->enchanted = true;
}
if (card->playerTarget && card->hasType("curse"))
{
card->playerTarget->curses.push_back(card);
}
//704.5n If an Aura is attached to an illegal object or player,
//or is not attached to an object or player, that Aura is put into its owners graveyard.

View File

@@ -2259,12 +2259,34 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return NULL;
}
if (StartsWith(s, "chooseacolor ") || StartsWith(s, "chooseatype ") || StartsWith(s, "chooseaname"))
{
MTGAbility * choose = parseChooseActionAbility(s,card,spell,target,0,id);
choose = NEW GenericActivatedAbility(observer, "","",id, card,choose,NULL);
MayAbility * mainAbility = NEW MayAbility(observer, id, choose, card,true);
if (storedAbilityString.size() && StartsWith(s, "chooseaname"))
{
bool chooseoppo = false;
vector<string> splitChoose = parseBetween(s, "chooseaname ", " chooseend", false);
if(!splitChoose.size()){
splitChoose = parseBetween(s, "chooseanameopp ", " chooseend", false);
chooseoppo = true;
}
if (splitChoose.size())
{
if(!chooseoppo)
s = "chooseaname ";
else
s = "chooseanameopp ";
s.append(storedAbilityString);
s.append(" ");
if(splitChoose[2].empty())
s.append(splitChoose[1]);
else
s.append(splitChoose[2]);
}
}
MTGAbility * choose = parseChooseActionAbility(s, card, spell, target, 0, id);
choose = NEW GenericActivatedAbility(observer, "", "", id, card, choose, NULL);
MayAbility * mainAbility = NEW MayAbility(observer, id, choose, card, true);
return mainAbility;
}
@@ -2305,6 +2327,34 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
storedPayString.clear();
}
bool chooseoppo = false;
vector<string> splitChoose = parseBetween(s, "chooseaname ", " chooseend", false);
if(!splitChoose.size()){
splitChoose = parseBetween(s, "chooseanameopp ", " chooseend", false);
chooseoppo = true;
}
if (splitChoose.size() && storedAbilityString.empty())
{
storedAbilityString = splitChoose[1];
size_t pos1 = s.find("transforms(("); // Try to handle chooseaname ability inside ability$! or transforms keywords.
size_t pos2 = s.find("ability$!");
if(pos2 == string::npos)
pos2 = s.find("winability"); // Try to handle chooseaname ability inside winability or loseability keywords.
if(pos2 == string::npos)
pos2 = s.find("loseability");
size_t pos3 = s.find(splitChoose[1]);
if((pos1 == string::npos && pos2 == string::npos) || (pos2 != string::npos && pos1 != string::npos && pos3 <= pos1 && pos3 <= pos2) ||
(pos2 == string::npos && pos1 != string::npos && pos3 <= pos1) || (pos1 == string::npos && pos2 != string::npos && pos3 <= pos2)){
s = splitChoose[0];
if(!chooseoppo)
s.append("chooseaname ");
else
s.append("chooseanameopp ");
s.append(splitChoose[2]);
} else
storedAbilityString.clear();
}
vector<string> splitGrant = parseBetween(s, "grant ", " grantend", false);
if (splitGrant.size() && storedAbilityString.empty())
{
@@ -4540,7 +4590,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
SAFE_DELETE(parser);
}
Damageable * t = spell ? spell->getNextDamageableTarget() : NULL;
MTGAbility * a = NEW AASetHand(observer, id, card, t, hand, NULL, who);
MTGAbility * a = NEW AASetHand(observer, id, card, t, hand, NULL, who);
a->oneShot = 1;
return a;
}
@@ -5751,37 +5801,38 @@ MTGAbility * AbilityFactory::parseUpkeepAbility(string s,MTGCardInstance * card,
MTGAbility * AbilityFactory::parsePhaseActionAbility(string s,MTGCardInstance * card,Spell * spell,MTGCardInstance * target, int restrictions,int id)
{
vector<string> splitActions = parseBetween(s, "[", "]");
if (!splitActions.size())
vector<string> splitActions = parseBetween(s, "[", "]");
if (!splitActions.size())
{
DebugTrace("MTGABILITY:Parsing Error " << s);
return NULL;
}
string s1 = splitActions[1];
int phase = MTG_PHASE_UPKEEP;
for (int i = 0; i < NB_MTG_PHASES; i++)
{
string phaseStr = Constants::MTGPhaseCodeNames[i];
if (s1.find(phaseStr) != string::npos)
{
DebugTrace("MTGABILITY:Parsing Error " << s);
return NULL;
}
string s1 = splitActions[1];
int phase = MTG_PHASE_UPKEEP;
for (int i = 0; i < NB_MTG_PHASES; i++)
{
string phaseStr = Constants::MTGPhaseCodeNames[i];
if (s1.find(phaseStr) != string::npos)
{
phase = PhaseRing::phaseStrToInt(phaseStr);
break;
}
phase = PhaseRing::phaseStrToInt(phaseStr);
break;
}
}
bool opponentturn = (s1.find("my") == string::npos);
bool myturn = (s1.find("opponent") == string::npos);
bool sourceinPlay = (s1.find("sourceinplay") != string::npos);
bool checkexile = (s1.find("checkex") != string::npos);
bool next = (s1.find("next") == string::npos); //Why is this one the opposite of the two others? That's completely inconsistent
bool once = (s1.find("once") != string::npos);
bool opponentturn = (s1.find("my") == string::npos);
bool myturn = (s1.find("opponent") == string::npos);
bool sourceinPlay = (s1.find("sourceinplay") != string::npos);
bool checkexile = (s1.find("checkex") != string::npos);
bool next = (s1.find("next") == string::npos); //Why is this one the opposite of the two others? That's completely inconsistent
bool once = (s1.find("once") != string::npos);
MTGCardInstance * _target = NULL;
if (spell)
_target = spell->getNextCardTarget();
if(!_target)
_target = target;
return NEW APhaseActionGeneric(observer, id, card,_target, trim(splitActions[2]), restrictions, phase,sourceinPlay,next,myturn,opponentturn,once,checkexile);
MTGCardInstance * _target = NULL;
if (spell)
_target = spell->getNextCardTarget();
if(!_target)
_target = target;
return NEW APhaseActionGeneric(observer, id, card, _target, trim(splitActions[2]), restrictions, phase, sourceinPlay, next, myturn, opponentturn, once, checkexile);
}
MTGAbility * AbilityFactory::parseChooseActionAbility(string s,MTGCardInstance * card,Spell *,MTGCardInstance * target, int, int id)

View File

@@ -2289,12 +2289,18 @@ bool TriggerTargetChooser::equals(TargetChooser * tc)
}
/*my curses */
bool myCursesChooser::canTarget(Targetable * target,bool)
bool myCursesChooser::canTarget(Targetable * target, bool)
{
for(unsigned int i = 0;i < source->controller()->curses.size();++i)
for (int j = source->controller()->game->battlefield->nb_cards - 1; j >= 0; --j)
{
MTGCardInstance * compare = source->controller()->curses[i];
if(compare == dynamic_cast<MTGCardInstance*>(target))
MTGCardInstance * compare = source->controller()->game->battlefield->cards[j];
if(compare->hasType("Curse") && compare->playerTarget == source->controller() && compare == dynamic_cast<MTGCardInstance*>(target))
return true;
}
for (int j = source->controller()->opponent()->game->battlefield->nb_cards - 1; j >= 0; --j)
{
MTGCardInstance * compare = source->controller()->opponent()->game->battlefield->cards[j];
if(compare->hasType("Curse") && compare->playerTarget == source->controller() && compare == dynamic_cast<MTGCardInstance*>(target))
return true;
}
return false;

View File

@@ -572,7 +572,19 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
}
else if (s == "targetedcurses")
{
intValue = (card->playerTarget)?card->playerTarget->curses.size():0;
intValue = 0;
for (int j = card->controller()->game->battlefield->nb_cards - 1; j >= 0; --j)
{
MTGCardInstance * curse = card->controller()->game->battlefield->cards[j];
if (curse->hasType("Curse") && curse->playerTarget == card->playerTarget)
intValue++;
}
for (int j = card->controller()->opponent()->game->battlefield->nb_cards - 1; j >= 0; --j)
{
MTGCardInstance * curse = card->controller()->opponent()->game->battlefield->cards[j];
if (curse->hasType("Curse") && curse->playerTarget == card->playerTarget)
intValue++;
}
}
else if (s == "lifetotal" || s == "opponentlifetotal")
{
@@ -820,9 +832,9 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
{
intValue = (s == "countedamount")?target->CountedObjects:target->CountedObjectsB;
}
else if (s == "kicked" || s == "handsize")
else if (s == "handsize" || s == "ohandsize")
{
intValue = (s == "kicked")?card->kicked:target->controller()->handsize;
intValue = (s == "ohandsize")?card->controller()->opponent()->handsize:target->controller()->handsize;
}
else if (s == "olandg" || s == "olandu")
{
@@ -1650,6 +1662,17 @@ void WParsedInt::extendedParse(string s, Spell * spell, MTGCardInstance * card)
{
intValue = (s == "iscommander")?card->isCommander:card->isRingBearer;
}
else if (s == "oppotgt" || s == "ctrltgt") // Return 1 if card targeted the opponent -- Return 1 if card targeted its controller
{
intValue = 0;
Player* p = (s == "oppotgt")?card->controller()->opponent():card->controller();
if(card->playerTarget == p)
intValue = 1;
}
else if (s == "kicked")
{
intValue = card->kicked;
}
else if(!intValue)//found nothing, try parsing a atoi
{
intValue = atoi(s.c_str());