Fixed primitives, added new macro "_TRAINING_" for new ability "Training", added new trigger "trained", added "trainer" restriction to check if player controls an attacking creature with greater power than the current one, improved "ninjutsu" ability when the targeted card is already in play (e.g. "Olivia, Crimson Bride"), improved "flip" ability in order to add the "andability" option and in ordeer to prevent flipped auras go to graveyard, improved "andability" option for "imprint", "haunt" and "conjure" ability, improved "retarget" and "newtarget" keywords with "fromplay" option (to use with flipped auras e.g. "Vengeful Strangler"), replaced old "praidcount" and "oraidcount" with new keywords "pattackedcount" and "oattackedcount".
This commit is contained in:
@@ -2262,7 +2262,6 @@ int AAImprint::resolve()
|
||||
{
|
||||
andAbilityClone->addToGame();
|
||||
}
|
||||
SAFE_DELETE(andAbility); //moved here because in destructor it can cause a crash.
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -2276,11 +2275,15 @@ const string AAImprint::getMenuText()
|
||||
|
||||
AAImprint * AAImprint::clone() const
|
||||
{
|
||||
return NEW AAImprint(*this);
|
||||
AAImprint * a = NEW AAImprint(*this);
|
||||
if(andAbility)
|
||||
a->andAbility = andAbility->clone();
|
||||
return a;
|
||||
}
|
||||
|
||||
AAImprint::~AAImprint()
|
||||
{
|
||||
SAFE_DELETE(andAbility);
|
||||
}
|
||||
|
||||
//AAHaunt
|
||||
@@ -2317,7 +2320,6 @@ int AAHaunt::resolve()
|
||||
{
|
||||
andAbilityClone->addToGame();
|
||||
}
|
||||
SAFE_DELETE(andAbility); //moved here because in destructor it can cause a crash.
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -2331,11 +2333,76 @@ const string AAHaunt::getMenuText()
|
||||
|
||||
AAHaunt * AAHaunt::clone() const
|
||||
{
|
||||
return NEW AAHaunt(*this);
|
||||
AAHaunt * a = NEW AAHaunt(*this);
|
||||
if(andAbility)
|
||||
a->andAbility = andAbility->clone();
|
||||
return a;
|
||||
}
|
||||
|
||||
AAHaunt::~AAHaunt()
|
||||
{
|
||||
SAFE_DELETE(andAbility);
|
||||
}
|
||||
|
||||
//AATrain
|
||||
AATrain::AATrain(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
|
||||
ActivatedAbility(observer, _id, _source, _cost, 0)
|
||||
{
|
||||
target = _target;
|
||||
andAbility = NULL;
|
||||
}
|
||||
|
||||
int AATrain::resolve()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
if (_target && _target->hasType(Subtypes::TYPE_CREATURE) && _target->isAttacker())
|
||||
{
|
||||
if(_target->mutation && _target->parentCards.size() > 0) return 0; // Mutated down cards cannot be trained, they will follow the fate of top-card
|
||||
|
||||
while(_target->next)
|
||||
_target = _target->next;
|
||||
|
||||
if(_target->counters)
|
||||
_target->counters->addCounter(1,1);
|
||||
|
||||
WEvent * e = NEW WEventCardTrained(_target);
|
||||
game->receiveEvent(e);
|
||||
|
||||
if(andAbility)
|
||||
{
|
||||
MTGAbility * andAbilityClone = andAbility->clone();
|
||||
andAbilityClone->target = _target;
|
||||
if(andAbility->oneShot)
|
||||
{
|
||||
andAbilityClone->resolve();
|
||||
SAFE_DELETE(andAbilityClone);
|
||||
}
|
||||
else
|
||||
{
|
||||
andAbilityClone->addToGame();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const string AATrain::getMenuText()
|
||||
{
|
||||
return "Training";
|
||||
}
|
||||
|
||||
AATrain * AATrain::clone() const
|
||||
{
|
||||
AATrain * a = NEW AATrain(*this);
|
||||
if(andAbility)
|
||||
a->andAbility = andAbility->clone();
|
||||
return a;
|
||||
}
|
||||
|
||||
AATrain::~AATrain()
|
||||
{
|
||||
SAFE_DELETE(andAbility);
|
||||
}
|
||||
|
||||
//AAConjure
|
||||
@@ -2401,7 +2468,10 @@ const string AAConjure::getMenuText()
|
||||
|
||||
AAConjure * AAConjure::clone() const
|
||||
{
|
||||
return NEW AAConjure(*this);
|
||||
AAConjure * a = NEW AAConjure(*this);
|
||||
if(andAbility)
|
||||
a->andAbility = andAbility->clone();
|
||||
return a;
|
||||
}
|
||||
|
||||
AAConjure::~AAConjure()
|
||||
@@ -4271,8 +4341,8 @@ AAFrozen * AAFrozen::clone() const
|
||||
}
|
||||
|
||||
// chose a new target for an aura or enchantment and equip it note: VERY basic right now.
|
||||
AANewTarget::AANewTarget(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target,bool retarget, ManaCost * _cost, bool reequip, bool newhook, int mutation) :
|
||||
ActivatedAbility(observer, id, card, _cost, 0),retarget(retarget),reequip(reequip),newhook(newhook),mutation(mutation)
|
||||
AANewTarget::AANewTarget(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, bool retarget, bool reequip, bool newhook, int mutation, bool fromplay) :
|
||||
ActivatedAbility(observer, id, card, _cost, 0),retarget(retarget),reequip(reequip),newhook(newhook),mutation(mutation),fromplay(fromplay)
|
||||
{
|
||||
target = _target;
|
||||
}
|
||||
@@ -4288,17 +4358,18 @@ int AANewTarget::resolve()
|
||||
if (_target && !reequip && !mutation)
|
||||
{
|
||||
while (_target->next)
|
||||
_target = _target->next;
|
||||
_target->controller()->game->putInZone(_target, _target->currentZone,
|
||||
_target->owner->game->exile);
|
||||
_target = _target->next;
|
||||
|
||||
MTGCardInstance * refreshed = source->controller()->game->putInZone(_target,_target->currentZone,source->controller()->game->battlefield);
|
||||
_target = _target->next;
|
||||
if(!fromplay){
|
||||
_target->controller()->game->putInZone(_target, _target->currentZone, _target->owner->game->exile);
|
||||
_target = _target->next;
|
||||
}
|
||||
MTGCardInstance * refreshed = source->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->battlefield);
|
||||
Spell * reUp = NEW Spell(game, refreshed);
|
||||
if(reUp->source->hasSubtype(Subtypes::TYPE_AURA))
|
||||
{
|
||||
reUp->source->target = source;
|
||||
reUp->resolve();
|
||||
if(reUp->source->spellTargetType == "") reUp->source->spellTargetType = "creature"; // Fix to prevent flipped auras go to graveyard.
|
||||
}
|
||||
if(_target->hasSubtype(Subtypes::TYPE_EQUIPMENT))
|
||||
{
|
||||
@@ -4706,6 +4777,7 @@ AAFlip::AAFlip(GameObserver* observer, int id, MTGCardInstance * card, MTGCardIn
|
||||
InstantAbility(observer, id, card, _target),flipStats(flipStats),isflipcard(isflipcard),forcedcopy(forcedcopy),forcetype(forcetype),backfromcopy(backfromcopy)
|
||||
{
|
||||
target = _target;
|
||||
andAbility = NULL;
|
||||
}
|
||||
|
||||
int AAFlip::resolve()
|
||||
@@ -4773,6 +4845,7 @@ int AAFlip::resolve()
|
||||
if(myFlip->getManaCost())
|
||||
_target->getManaCost()->copy(myFlip->getManaCost());
|
||||
}
|
||||
_target->spellTargetType = myFlip->spellTargetType; // Fix to prevent flipped auras go to graveyard.
|
||||
_target->colors = myFlip->colors;
|
||||
_target->types = myFlip->types;
|
||||
_target->text = myFlip->text;
|
||||
@@ -4931,7 +5004,20 @@ int AAFlip::resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(andAbility)
|
||||
{
|
||||
MTGAbility * andAbilityClone = andAbility->clone();
|
||||
andAbilityClone->target = _target;
|
||||
if(andAbility->oneShot)
|
||||
{
|
||||
andAbilityClone->resolve();
|
||||
SAFE_DELETE(andAbilityClone);
|
||||
}
|
||||
else
|
||||
{
|
||||
andAbilityClone->addToGame();
|
||||
}
|
||||
}
|
||||
currentAbilities.clear();
|
||||
testDestroy();
|
||||
}
|
||||
@@ -4966,9 +5052,17 @@ const string AAFlip::getMenuText()
|
||||
AAFlip * AAFlip::clone() const
|
||||
{
|
||||
AAFlip * a = NEW AAFlip(*this);
|
||||
if(andAbility)
|
||||
a->andAbility = andAbility->clone();
|
||||
a->forceDestroy = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
AAFlip::~AAFlip()
|
||||
{
|
||||
SAFE_DELETE(andAbility);
|
||||
}
|
||||
|
||||
// AADYNAMIC: dynamic ability builder
|
||||
AADynamic::AADynamic(GameObserver* observer, int id, MTGCardInstance * card, Damageable * _target,int type,int effect,int who,int amountsource,MTGAbility * storedAbility, ManaCost * _cost) :
|
||||
ActivatedAbility(observer, id, card, _cost, 0),type(type),effect(effect),who(who),amountsource(amountsource),storedAbility(storedAbility)
|
||||
|
||||
@@ -847,6 +847,20 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe
|
||||
if(!found)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("trainer"); //Player controls an attacking creature with greater power than the current one.
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(player != observer->currentPlayer || !card->isAttacker())
|
||||
return 0;
|
||||
bool found = false;
|
||||
for(unsigned int i = 0; i < observer->currentPlayer->game->inPlay->cards.size() && !found; i++){
|
||||
if(observer->currentPlayer->game->inPlay->cards[i]->hasType(Subtypes::TYPE_CREATURE) && observer->currentPlayer->game->inPlay->cards[i]->isAttacker() && observer->currentPlayer->game->inPlay->cards[i]->power > card->power){
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("can play");
|
||||
if(check != string::npos)
|
||||
{
|
||||
@@ -1274,6 +1288,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
|
||||
if (TargetChooser * tc = parseSimpleTC(s, "foretold", card))
|
||||
return NEW TrCardForetold(observer, id, card, tc, once, limitOnceATurn);
|
||||
|
||||
//Train has been performed from a card
|
||||
if (TargetChooser * tc = parseSimpleTC(s, "trained", card))
|
||||
return NEW TrCardTrained(observer, id, card, tc, once, limitOnceATurn);
|
||||
|
||||
//Scry has been performed from a card
|
||||
if (TargetChooser * tc = parseSimpleTC(s, "scryed", card))
|
||||
return NEW TrCardScryed(observer, id, card, tc, once, limitOnceATurn);
|
||||
@@ -3422,6 +3440,22 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
}
|
||||
}
|
||||
|
||||
//train a creature
|
||||
found = s.find("dotrain");
|
||||
if (found != string::npos)
|
||||
{
|
||||
MTGAbility * a = NEW AATrain(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
//andability
|
||||
if(storedAndAbility.size())
|
||||
{
|
||||
string stored = storedAndAbility;
|
||||
storedAndAbility.clear();
|
||||
((AATrain*)a)->andAbility = parseMagicLine(stored, id, spell, card);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
//Conjure a card
|
||||
found = s.find("conjure");
|
||||
if (found != string::npos)
|
||||
@@ -4638,6 +4672,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
bool backfromcopy = (s.find("undocpy") != string::npos)?true:false; // Added to undo the copy effect at end of turn (es. Scion of the Ur-Dragon).
|
||||
bool transmode = card->getdoubleFaced() == "kamiflip"?true:false;
|
||||
MTGAbility * a = NEW AAFlip(observer, id, card, target, flipStats, transmode, false, forcetype, backfromcopy);
|
||||
//andability
|
||||
if(storedAndAbility.size())
|
||||
{
|
||||
string stored = storedAndAbility;
|
||||
storedAndAbility.clear();
|
||||
((AAFlip*)a)->andAbility = parseMagicLine(stored, id, spell, card);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -4859,10 +4900,10 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return a;
|
||||
}
|
||||
|
||||
//get a new target - retarget and newtarget makes the card refreshed - from exile to play...
|
||||
//get a new target - retarget and newtarget makes the card refreshed - from exile to play (or from play to play)...
|
||||
if ((s.find("retarget") != string::npos) || s.find("newtarget") != string::npos)
|
||||
{
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card,target, (s.find("retarget") != string::npos));
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card, target, NULL, (s.find("retarget") != string::npos), false, false, 0, (s.find("fromplay") != string::npos));
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
@@ -4870,15 +4911,15 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
//get a new target for puresteel paladin...etc for equipments inplay only.. newhook & rehook supports stone hewer basic... the card is reequipped
|
||||
if ((s.find("rehook") != string::npos) || s.find("newhook") != string::npos)
|
||||
{
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card,target, false,NULL,true,(s.find("newhook") != string::npos));
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card,target, NULL, false, true, (s.find("newhook") != string::npos));
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//get a new target for muatations
|
||||
//get a new target for mutations
|
||||
if ((s.find("mutateover") != string::npos) || s.find("mutateunder") != string::npos)
|
||||
{
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card,target, false,NULL,false,false,(s.find("mutateover") != string::npos)?1:2);
|
||||
MTGAbility * a = NEW AANewTarget(observer, id, card, target, NULL, false, false, false, (s.find("mutateover") != string::npos)?1:2);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
@@ -5359,6 +5400,8 @@ int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, Targ
|
||||
return BAKA_EFFECT_GOOD;
|
||||
if (dynamic_cast<AAHaunt *> (a))
|
||||
return BAKA_EFFECT_GOOD;
|
||||
if (dynamic_cast<AATrain *> (a))
|
||||
return BAKA_EFFECT_GOOD;
|
||||
if (dynamic_cast<ABestow *> (a))
|
||||
return BAKA_EFFECT_GOOD;
|
||||
if (dynamic_cast<AExert *> (a))
|
||||
|
||||
@@ -238,7 +238,8 @@ const char* Constants::MTGBasicAbilities[] = {
|
||||
"isconspiracy", //The card is a conspiracy (e.g. "Double Stroke")
|
||||
"hasaftermath", //Flashback cost is an aftemath cost (e.g. "Claim // Fame")
|
||||
"noentertrg", //Creatures entering the battlefield don't cause abilities to trigger (e.g. "Hushbringer").
|
||||
"nodietrg" //Creatures dying don't cause abilities to trigger (e.g. "Hushbringer").
|
||||
"nodietrg", //Creatures dying don't cause abilities to trigger (e.g. "Hushbringer").
|
||||
"training" //Has training ability (e.g. "Gryff Rider")
|
||||
};
|
||||
|
||||
map<string,int> Constants::MTGBasicAbilitiesMap;
|
||||
|
||||
@@ -317,6 +317,11 @@ WEventCardForetold::WEventCardForetold(MTGCardInstance * card) :
|
||||
{
|
||||
}
|
||||
|
||||
WEventCardTrained::WEventCardTrained(MTGCardInstance * card) :
|
||||
WEventCardUpdate(card)
|
||||
{
|
||||
}
|
||||
|
||||
WEventCardScryed::WEventCardScryed(MTGCardInstance * card) :
|
||||
WEventCardUpdate(card)
|
||||
{
|
||||
@@ -573,6 +578,12 @@ Targetable * WEventCardForetold::getTarget(int target)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Targetable * WEventCardTrained::getTarget(int target)
|
||||
{
|
||||
if (target) return card;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Targetable * WEventCardScryed::getTarget(int target)
|
||||
{
|
||||
if (target) return card;
|
||||
|
||||
@@ -475,9 +475,9 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
|
||||
{
|
||||
intValue = (s == "pdevotionoffset")?card->controller()->devotionOffset:card->controller()->opponent()->devotionOffset;
|
||||
}
|
||||
else if (s == "praidcount" || s == "oraidcount")
|
||||
else if (s == "pattackedcount" || s == "oattackedcount")
|
||||
{
|
||||
intValue = (s == "praidcount")?card->controller()->raidcount:card->controller()->opponent()->raidcount;
|
||||
intValue = (s == "pattackedcount")?card->controller()->raidcount:card->controller()->opponent()->raidcount;
|
||||
}
|
||||
else if (s == "pstormcount" || s == "ostormcount")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user