added "colors" to word variables
========================================
added a function to return the action element id by mtgcardinstance.
=======================================
refactored all 5 combat triggers to be handled in a single class, this change helps reduce the "bits and pieces" of trigger restrictions which some did support while others didnt, it also allows for easier editing and debugging if future code needs to be added to it.
refactored the parsing for the combat triggers also, so that a combat trigger can be built from a single object if it only contains "or"...amongst other reasons.
the new syntax is auto=@combat(blocking,attacking,turnlimited,once) source(TC) from(TC):effect...all the same words are still used, except they are now all included inside the combat(-----) this includes restrictions for the triggers. if a card still needs multiple triggers from some reason...it is still 100% allowed to have as many as you want, with whatever you want inside them...check updated primitive for examples.
the required sections are auto=@combat(atleast one trigger) source(TC):effect.
=========================================
moved the limitsperturn "limit:" from genericactivatedability up to its parent class activatedability, did this for the following reason
first rules correction, the previous method tracked uses on resolve, which is incorrect, it should count as the ability is fired and placed on the stack.
second, it keeps all the actiavted ability restrictions in the same place, this is the location we are checking summoning sickness, actived restrictions such as "myturnonly" ect. makes sense to handle it in the parent.
third, it allow any and all future activated abilities easy access to "limit:" if needed, it would only require adding a limit string to pass on construction to the child classes instead of recoding the same exact checks as genericactivated.
=======================================================
reworked "name(" so that it no longer is required to be used inside a "&&" ability, also it no longer will create a MTGAbility object with a false return. that was just dirty of me :/
enabled "name(" to replace the menutext of alternative cost.
"other={cost} name(holy cow)"
will display "holy cow" instead of "pay alternative cost", this change is nice because we ended up using "other" cost for WAY more then originally planned...now we can label it exactly what it should say when you click it.
======================================================
added a subtype keyword for powertoughnessmodifier so that you can basically switch on non-static variables for it...lifetotal/lifetotal nonstatic...PT can now except all word variables as i added reparsing of the ints, had to maintain old methods as ai needs them to decide what to do with them.
======================================================
removed the following extremely redundant classes
both ABecomes classes---atransformer has become far superior to it, i kept the "becomes(" parsing tho, and it will act exactly as it use to, except now it has access to most of the subkeywords of transforms...it also now allows word variables. and excepts "forever" as a tag. added "newcolor" subkeyword to transforms to create the "becomes(" adding a color without removing colors effect. "becomes(" now returns a constructor for ATransformer that emulates becomes( exactly as it worked before.
both forevertransformer classes, the only difference between the 2 was one subkeyword, and "forever" did not return a "destroy()"...i recreated this in less then 4 lines and a bool. that was sloppy of me :( i guess we learn and improve.
============================================================================
i removed the parsing of card casting restriction from the first pass when cards load, instead of making it a cardprimitive object, i now simply pass the string through the card and build the restrictions when theyre actually needed and checked.
this change allowed for alot of clean up, removing enum and dependancy on cardprimitive, and combining both allowedAltCast and allowedtocast functions checks through a new function "parseCastRestrictions"...this change keeps all the cast resrictions in a single place, which makes it easier to debug or add if needed, and while i was at it, i enabled it so cards can now contain as many restrictions as you want *of the available ones*
added "turn:" as a restriction to make it so "fourth turn" could actually be ANY turn you list, this allowed me to remove a dirty line of code which was checking if a card was o converted cost but had a suspend...lotus bloom...which can not be cast normally..for cards like this now you can use restriction=turn:200 or otherrestriction=turn:200....
=========================================================================
added Phyrexian Mana...svntax {p(r)} ....this will always be payable with 2 life, but if you have a red mana for this example, it will charge you the red mana instead...you can have any combination of P mana you want in any of the games manacost.
===================================================
reworked a bit of the ai logic i added, it now has true interrupting and can now correctly target for fizzles, Ai will go into full out counterspell wars with you now...
===================================================
added a ingame reward system with fancy flying text animations, they reward the player with actual credits, but are extremely hard to trigger off, theyre not meant to be something you see every 5 secs, but something that when you see them trigger you go "damn that was cool"
the triggers and effects are as follows
first the combo system:
you have to chain cast 5 or more card, without tapping or being interupted, tiny bonus for this..chain is broken as soon as you or your opponent tap something.
next combo level is
Abundant Resources - chain 10 or more spells same condition
then
killer - chain 15 or more same condition
this will include a flying text render once a chain is successfully started (5+ cast)
this bonus can be triggered multiple times in a match
the next bonus is
+ //creatures entering play consecutively will allow you a chance
+ //to gain a bonus for maintaining force sizes, it will trigger every 10th
+ //creature which enters play consecutively.
this is restarted every time a noncreature enters play.
the levels are as follows,
Deadly Force Bonus! -10 creatures enter play consecutively
Extreme Infantry Bonus! - 10 creatures enter play consecutively and you maintain a force size of 20+
Malignant Conqueror Bonus! -10 creatures enter play consecutively and you maintain a force size of 40+
this can only be triggered once per level per match.
next bonus is given for having alot of a specific type come into play under your control during a match, this bonus only triggers once per match.
the levels are:
Toy Collector!
Beast Tamer!
Vampire King!
Lord of Swarms!
Master of Elements!
Zombie Apocalypse!
Sword And Shield!
Medic!
The Promenade!
Heavenly Host!
Teeth And Scales!
its pretty easy to figure out what each requires to trigger, teeth and scales for example is dragons, wurms, drakes, and snakes.
the final bonus is deal 100 damage from a single source in a single damage event, this one triggers only once per match.
============================================================
fixed the following bugs::::
regenerate was not working for non-creature regeneration ie:welding jar
ai would sometime get stuck in a infinate loop tho extremely rarely while deciding what to do, the cause
if (clickstream.empty())
computeActions();
is NOT enough...ai should NEVER be computing actions (finding a card or ability to play) when it is NOT the active player..meaning, it does not have priority.
g->currentlyActing() is the player that has priority.
if (clickstream.empty() && g->currentlyActing() == this)...loop fixed :)
dynamicability had a couple weird results, from sources which dont have an amount to return, i now check this and if non, the amount is 0.
transformer will no longer add the same types a card already has..
removed an unneeded
if (!activated) ....oris bug seems to be corrected with this change.
wrapped limitsperturn checks in a conditional to skip it if there is no limit string.
added safer method to get the target of the combat trigger. the previous could potentially cause a crash if you interrupted the ability while the combat trigger was on the stack, it would do a call to "getnextopponent" and return a null pointer. i now send the opponent with the event.
fixed a crash that would happen when a card did not have a type= line. having a type or subtype line is now optional. and highly recommended to avoid using "type=nothing"
moved a function call in buyback isreactingtoclick so that it checks if its in the hand before parsing the restrictions for it.
removed allowedtocast function calls from the alternative payment types, they are only supposed to check allowedtocast if it is something like "buyback" and kicker...not "you may pay this instead"....
corrected an issue with type: variable where it would add the amount depending on the activeplayer. to correct i added a method to call TargetZoneChooser::targetsZone( with a mSource...so that you can set the source card for the scan.
note: all test pass.
This commit is contained in:
@@ -213,6 +213,7 @@ public:
|
||||
|
||||
int setIsInterrupting(Player * player);
|
||||
int count( int type = 0 , int state = 0 , int display = -1);
|
||||
int getActionElementFromCard(MTGCardInstance * card);
|
||||
Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1);
|
||||
int getPreviousIndex(Interruptible * next, int type = 0, int state = 0 , int display = -1);
|
||||
Interruptible * getNext(Interruptible * previous, int type = 0, int state = 0 , int display = -1);
|
||||
|
||||
@@ -75,6 +75,10 @@ public:
|
||||
{
|
||||
intValue = target->equipment;
|
||||
}
|
||||
else if (s == "colors")
|
||||
{
|
||||
intValue = target->countColors();
|
||||
}
|
||||
else if (s == "auras")
|
||||
{
|
||||
intValue = target->auras;
|
||||
@@ -106,6 +110,7 @@ public:
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
MTGGameZone * zone = zones[k];
|
||||
if(tc->targetsZone(zone,target))
|
||||
intValue += zone->countByCanTarget(tc);
|
||||
}
|
||||
}
|
||||
@@ -368,182 +373,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TrCardAttackedNotBlocked: public TriggeredAbility
|
||||
class TrCombatTrigger: public TriggeredAbility
|
||||
{
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TrCardAttackedNotBlocked(int id, MTGCardInstance * source, TargetChooser * tc) :
|
||||
TriggeredAbility(id, source), tc(tc)
|
||||
{
|
||||
}
|
||||
|
||||
int resolve()
|
||||
{
|
||||
return 0; //This is a trigger, this function should not be called
|
||||
}
|
||||
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventCardAttackedNotBlocked * e = dynamic_cast<WEventCardAttackedNotBlocked *> (event);
|
||||
if (!e) return 0;
|
||||
if (e->card->didattacked < 1) return 0;
|
||||
if (e->card->blocked) return 0;
|
||||
if (!tc->canTarget(e->card)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
~TrCardAttackedNotBlocked()
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
}
|
||||
|
||||
TrCardAttackedNotBlocked * clone() const
|
||||
{
|
||||
TrCardAttackedNotBlocked * a = NEW TrCardAttackedNotBlocked(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
class TrCardAttackedBlocked: public TriggeredAbility
|
||||
{
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TargetChooser * fromTc;
|
||||
bool limitOnceATurn;
|
||||
int triggeredTurn;
|
||||
TrCardAttackedBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL,bool limitOnceATurn = false) :
|
||||
TriggeredAbility(id, source), tc(tc), fromTc(fromTc),limitOnceATurn(limitOnceATurn)
|
||||
{
|
||||
triggeredTurn = -1;
|
||||
}
|
||||
|
||||
int resolve()
|
||||
{
|
||||
return 0; //This is a trigger, this function should not be called
|
||||
}
|
||||
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventCardAttackedBlocked * e = dynamic_cast<WEventCardAttackedBlocked *> (event);
|
||||
if (!e) return 0;
|
||||
GameObserver * g = GameObserver::GetInstance();
|
||||
if (limitOnceATurn && triggeredTurn == g->turn)
|
||||
return 0;
|
||||
if (e->card->didattacked < 1) return 0;
|
||||
if (!e->card->blocked) return 0;
|
||||
if (fromTc && !fromTc->canTarget(e->card->getNextOpponent())) return 0;
|
||||
if (!tc->canTarget(e->card)) return 0;
|
||||
triggeredTurn = g->turn;
|
||||
return 1;
|
||||
}
|
||||
|
||||
~TrCardAttackedBlocked()
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
SAFE_DELETE(fromTc);
|
||||
}
|
||||
|
||||
TrCardAttackedBlocked * clone() const
|
||||
{
|
||||
TrCardAttackedBlocked * a = NEW TrCardAttackedBlocked(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
class TrCardAttacked: public TriggeredAbility
|
||||
{
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TargetChooser * tc;//source(card)
|
||||
TargetChooser * fromTc;//from(card)
|
||||
bool once;//can only activate one time ever.
|
||||
bool activeTrigger;
|
||||
bool limitOnceATurn;//can activate one time per turn
|
||||
int triggeredTurn;//the turn it last activated
|
||||
bool sourceUntapped;
|
||||
bool opponentPoisoned;
|
||||
TrCardAttacked(int id, MTGCardInstance * source, TargetChooser * tc,bool sourceUntapped,bool opponentPoisoned) :
|
||||
TriggeredAbility(id, source), tc(tc), sourceUntapped(sourceUntapped),opponentPoisoned(opponentPoisoned)
|
||||
{
|
||||
}
|
||||
|
||||
int resolve()
|
||||
{
|
||||
return 0; //This is a trigger, this function should not be called
|
||||
}
|
||||
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventCardAttacked * e = dynamic_cast<WEventCardAttacked *> (event);
|
||||
if (!e) return 0;
|
||||
if (sourceUntapped && source->isTapped() == 1)
|
||||
return 0;
|
||||
if (e->card->didattacked < 1) return 0;
|
||||
if (!tc->canTarget(e->card)) return 0;
|
||||
if (opponentPoisoned && !source->controller()->opponent()->isPoisoned) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
~TrCardAttacked()
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
}
|
||||
|
||||
TrCardAttacked * clone() const
|
||||
{
|
||||
TrCardAttacked * a = NEW TrCardAttacked(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
class TrCardAttackedAlone: public TriggeredAbility
|
||||
{
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TrCardAttackedAlone(int id, MTGCardInstance * source, TargetChooser * tc) :
|
||||
TriggeredAbility(id, source), tc(tc)
|
||||
{
|
||||
}
|
||||
|
||||
int resolve()
|
||||
{
|
||||
return 0; //This is a trigger, this function should not be called
|
||||
}
|
||||
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventCardAttackedAlone * e = dynamic_cast<WEventCardAttackedAlone *> (event);
|
||||
if (!e) return 0;
|
||||
if (e->card->didattacked < 1) return 0;
|
||||
if (!tc->canTarget(e->card)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
~TrCardAttackedAlone()
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
}
|
||||
|
||||
TrCardAttackedAlone * clone() const
|
||||
{
|
||||
TrCardAttackedAlone * a = NEW TrCardAttackedAlone(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
class TrCardBlocked: public TriggeredAbility
|
||||
{
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TargetChooser * fromTc;
|
||||
bool once;
|
||||
bool activeTrigger;
|
||||
bool limitOnceATurn;
|
||||
int triggeredTurn;
|
||||
TrCardBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL,bool once = false,bool limitOnceATurn = false) :
|
||||
TriggeredAbility(id, source), tc(tc), fromTc(fromTc), once(once),limitOnceATurn(limitOnceATurn)
|
||||
//trigger types
|
||||
bool attackingTrigger;
|
||||
bool attackedAloneTrigger;
|
||||
bool notBlockedTrigger;
|
||||
bool attackBlockedTrigger;
|
||||
bool blockingTrigger;
|
||||
TrCombatTrigger(int id, MTGCardInstance * source, TargetChooser * tc,TargetChooser * fromTc = NULL,
|
||||
bool once = false,bool limitOnceATurn = false,bool sourceUntapped = false,bool opponentPoisoned = false,
|
||||
bool attackingTrigger = false,bool attackedAloneTrigger = false,bool notBlockedTrigger = false,bool attackBlockedTrigger = false,bool blockingTrigger = false) :
|
||||
TriggeredAbility(id, source),tc(tc), fromTc(fromTc), once(once),limitOnceATurn(limitOnceATurn),sourceUntapped(sourceUntapped),opponentPoisoned(opponentPoisoned),
|
||||
attackingTrigger(attackingTrigger),attackedAloneTrigger(attackedAloneTrigger),notBlockedTrigger(notBlockedTrigger),
|
||||
attackBlockedTrigger(attackBlockedTrigger),blockingTrigger(blockingTrigger)
|
||||
{
|
||||
activeTrigger = true;
|
||||
triggeredTurn = -1;
|
||||
@@ -556,31 +408,103 @@ public:
|
||||
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventCardBlocked * e = dynamic_cast<WEventCardBlocked *> (event);
|
||||
if (!e) return 0;
|
||||
//general restrictions
|
||||
if(source->isPhased)
|
||||
return 0;
|
||||
if (opponentPoisoned && !source->controller()->opponent()->isPoisoned)
|
||||
return 0;
|
||||
if (sourceUntapped && source->isTapped() == 1)
|
||||
return 0;
|
||||
if (limitOnceATurn && triggeredTurn == game->turn)
|
||||
return 0;
|
||||
if(activeTrigger == false)
|
||||
return 0;
|
||||
GameObserver * g = GameObserver::GetInstance();
|
||||
if (limitOnceATurn && triggeredTurn == g->turn)
|
||||
return 0;
|
||||
if (fromTc && !fromTc->canTarget(e->card->getNextOpponent())) return 0;
|
||||
if (!tc->canTarget(e->card)) return 0;
|
||||
if(once && activeTrigger )
|
||||
//the follow cases are not "else'd" on purpose, triggers which are conjoined such as
|
||||
//"whenever this card attacks, or attacks and is not blocked, are supposed to gernerally
|
||||
//trigger only once MTG rule 509.a-d, from either/or..not else'ing the statements and
|
||||
//listing them in order allows just that, a return on an event before hitting the
|
||||
//next trigger condiational.
|
||||
//when triggers are not conjoined you can simply add another combat trigger to the card as normal.
|
||||
//an attacking creature can not also be a blocking creature.
|
||||
WEventCardAttacked * attacked = dynamic_cast<WEventCardAttacked *> (event);
|
||||
//event when a card was declared an attacker.
|
||||
if (attacked && attackingTrigger && !attacked->card->didblocked)
|
||||
{
|
||||
if (!attacked->card->didattacked)
|
||||
return 0;
|
||||
if (!tc->canTarget(attacked->card))
|
||||
return 0;
|
||||
return returnResult();
|
||||
}
|
||||
WEventCardAttackedAlone * attackedAlone = dynamic_cast<WEventCardAttackedAlone *> (event);
|
||||
//event when a card was declared an attacker, and attacked alone.
|
||||
if (attackedAlone && attackedAloneTrigger && !attackedAlone->card->didblocked)
|
||||
{
|
||||
if (!attackedAlone->card->didattacked)
|
||||
return 0;
|
||||
if (!tc->canTarget(attackedAlone->card))
|
||||
return 0;
|
||||
return returnResult();
|
||||
}
|
||||
WEventCardBlocked * blocked = dynamic_cast<WEventCardBlocked *> (event);
|
||||
//event when a card was declared a blocker.
|
||||
if (blocked && blockingTrigger && !blocked->card->didattacked)
|
||||
{
|
||||
if(!blocked->card->didblocked)
|
||||
return 0;
|
||||
if (fromTc && !fromTc->canTarget(blocked->opponent))
|
||||
return 0;
|
||||
if (!tc->canTarget(blocked->card))
|
||||
return 0;
|
||||
return returnResult();
|
||||
}
|
||||
WEventCardAttackedNotBlocked * notblocked = dynamic_cast<WEventCardAttackedNotBlocked *> (event);
|
||||
//event when a card was declared an attacker, but the attack was not blocked.
|
||||
if (notblocked && notBlockedTrigger && !notblocked->card->didblocked)
|
||||
{
|
||||
if (!notblocked->card->didattacked)
|
||||
return 0;
|
||||
if (notblocked->card->blocked)
|
||||
return 0;
|
||||
if (!tc->canTarget(notblocked->card))
|
||||
return 0;
|
||||
return returnResult();
|
||||
}
|
||||
WEventCardAttackedBlocked * attackblocked = dynamic_cast<WEventCardAttackedBlocked *> (event);
|
||||
//event when a card was declared an attacker, then it became "blocked".
|
||||
if (attackblocked && attackBlockedTrigger && !attackblocked->card->didblocked)
|
||||
{
|
||||
if (!attackblocked->card->didattacked)
|
||||
return 0;
|
||||
if (!attackblocked->card->blocked)
|
||||
return 0;
|
||||
if (fromTc && !fromTc->canTarget(attackblocked->opponent))
|
||||
return 0;
|
||||
if (!tc->canTarget(attackblocked->card))
|
||||
return 0;
|
||||
return returnResult();
|
||||
}
|
||||
//default return is 0 || not triggered.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int returnResult()
|
||||
{
|
||||
if(once && activeTrigger )
|
||||
activeTrigger = false;
|
||||
triggeredTurn = g->turn;
|
||||
triggeredTurn = game->turn;
|
||||
return 1;
|
||||
}
|
||||
|
||||
~TrCardBlocked()
|
||||
|
||||
~TrCombatTrigger()
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
SAFE_DELETE(fromTc);
|
||||
}
|
||||
|
||||
TrCardBlocked * clone() const
|
||||
TrCombatTrigger * clone() const
|
||||
{
|
||||
TrCardBlocked * a = NEW TrCardBlocked(*this);
|
||||
TrCombatTrigger * a = NEW TrCombatTrigger(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
@@ -1027,12 +951,10 @@ public:
|
||||
class GenericActivatedAbility: public ActivatedAbility, public NestedAbility
|
||||
{
|
||||
public:
|
||||
int limitPerTurn;
|
||||
string limit;
|
||||
int counters;
|
||||
MTGGameZone * activeZone;
|
||||
string newName;
|
||||
|
||||
GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, string limit = "",
|
||||
GenericActivatedAbility(string newName,int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, string limit = "",
|
||||
int restrictions = 0, MTGGameZone * dest = NULL);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
@@ -1158,8 +1080,9 @@ public:
|
||||
string limit;
|
||||
int counters;
|
||||
MTGGameZone * activeZone;
|
||||
string newName;
|
||||
|
||||
GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost = NULL,
|
||||
GenericTargetAbility(string newName,int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost = NULL,
|
||||
int _tap = 0, string limit = "", int restrictions = 0, MTGGameZone * dest = NULL);
|
||||
const char * getMenuText();
|
||||
~GenericTargetAbility();
|
||||
@@ -1357,45 +1280,6 @@ public:
|
||||
AAWinGame * clone() const;
|
||||
};
|
||||
|
||||
|
||||
//naming an ability line-------------------------------------------------------------------------
|
||||
class ANamer: public ActivatedAbility
|
||||
{
|
||||
public:
|
||||
string name;
|
||||
ANamer(int _id, MTGCardInstance * _source, ManaCost * _cost, string sname, int _doTap) :
|
||||
ActivatedAbility(_id, _source, _cost, 0, _doTap)
|
||||
{
|
||||
name = sname;
|
||||
}
|
||||
int resolve()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const char * getMenuText()
|
||||
{
|
||||
sprintf(menuText, "%s", name.c_str());
|
||||
return menuText;
|
||||
}
|
||||
virtual ostream& toString(ostream& out) const
|
||||
{
|
||||
out << "ANamer ::: name" << name << " (";
|
||||
return ActivatedAbility::toString(out) << ")";
|
||||
}
|
||||
ANamer * clone() const
|
||||
{
|
||||
ANamer * a = NEW ANamer(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
~ANamer()
|
||||
{
|
||||
if (!isClone)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*Changes one of the basic abilities of target
|
||||
source : spell
|
||||
target : spell target (creature)
|
||||
@@ -1901,12 +1785,30 @@ class APowerToughnessModifier: public MTGAbility
|
||||
{
|
||||
public:
|
||||
WParsedPT * wppt;
|
||||
APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, WParsedPT * wppt) :
|
||||
MTGAbility(id, _source, _target), wppt(wppt)
|
||||
string PT;
|
||||
bool nonstatic;
|
||||
APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, WParsedPT * wppt,string PT,bool nonstatic) :
|
||||
MTGAbility(id, _source, _target), wppt(wppt),PT(PT),nonstatic(nonstatic)
|
||||
{
|
||||
aType = MTGAbility::STANDARD_PUMP;
|
||||
}
|
||||
|
||||
|
||||
void Update(float dt)
|
||||
{
|
||||
if(!nonstatic)
|
||||
return;
|
||||
((MTGCardInstance *) target)->power -= wppt->power.getValue();
|
||||
((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue());
|
||||
if(PT.size())
|
||||
{
|
||||
SAFE_DELETE(wppt);
|
||||
wppt = NEW WParsedPT(PT,NULL,(MTGCardInstance *) target);
|
||||
}
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
_target->power += wppt->power.getValue();
|
||||
_target->addToToughness(wppt->toughness.getValue());
|
||||
}
|
||||
|
||||
int addToGame()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
@@ -3932,7 +3834,10 @@ public:
|
||||
list<int> colors;
|
||||
list<int> oldcolors;
|
||||
list<int> oldtypes;
|
||||
vector<int> dontremove;
|
||||
bool addNewColors;
|
||||
bool remove;
|
||||
bool removeTypes;
|
||||
string menu;
|
||||
string newpower;
|
||||
bool newpowerfound;
|
||||
@@ -3943,9 +3848,9 @@ public:
|
||||
map<Damageable *, vector<MTGAbility *> > newAbilities;
|
||||
vector<string> newAbilitiesList;
|
||||
bool newAbilityFound;
|
||||
bool aForever;
|
||||
|
||||
|
||||
ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound = false);
|
||||
ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound = false,bool aForever = false);
|
||||
int addToGame();
|
||||
int destroy();
|
||||
const char * getMenuText();
|
||||
@@ -3953,34 +3858,8 @@ public:
|
||||
~ATransformer();
|
||||
};
|
||||
|
||||
//transforms forever class
|
||||
class AForeverTransformer: public MTGAbility
|
||||
{
|
||||
public:
|
||||
list<int> abilities;
|
||||
list<int> types;
|
||||
list<int> colors;
|
||||
string menu;
|
||||
string newpower;
|
||||
bool newpowerfound;
|
||||
int oldpower;
|
||||
string newtoughness;
|
||||
bool newtoughnessfound;
|
||||
int oldtoughness;
|
||||
bool remove;
|
||||
vector<string> newAbilitiesList;
|
||||
map<Damageable *, vector<MTGAbility *> > newAbilities;
|
||||
bool newAbilityFound;
|
||||
|
||||
AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vector<string>newAbilitiesList = vector<string>(),bool newAbilityFound = false);
|
||||
int addToGame();
|
||||
const char * getMenuText();
|
||||
AForeverTransformer * clone() const;
|
||||
~AForeverTransformer();
|
||||
};
|
||||
|
||||
//Adds types/abilities/changes color to a card (until end of turn)
|
||||
class ATransformerUEOT: public InstantAbility
|
||||
//Adds types/abilities/changes color to a card (generally until end of turn)
|
||||
class ATransformerInstant: public InstantAbility
|
||||
{
|
||||
public:
|
||||
ATransformer * ability;
|
||||
@@ -3991,32 +3870,13 @@ public:
|
||||
vector<string> newAbilitiesList;
|
||||
map<Damageable *, vector<MTGAbility *> > newAbilities;
|
||||
bool newAbilityFound;
|
||||
bool aForever;
|
||||
|
||||
ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types = "", string abilities = "",string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vector<string>newAbilitiesList = vector<string>(),bool newAbilityFound = false);
|
||||
ATransformerInstant(int id, MTGCardInstance * source, MTGCardInstance * target, string types = "", string abilities = "",string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vector<string>newAbilitiesList = vector<string>(),bool newAbilityFound = false,bool aForever = false);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
ATransformerUEOT * clone() const;
|
||||
~ATransformerUEOT();
|
||||
};
|
||||
|
||||
//transforms forever
|
||||
class ATransformerFOREVER: public InstantAbility
|
||||
{
|
||||
public:
|
||||
AForeverTransformer * ability;
|
||||
string newpower;
|
||||
bool newpowerfound;
|
||||
string newtoughness;
|
||||
bool newtoughnessfound;
|
||||
vector<string> newAbilitiesList;
|
||||
map<Damageable *, vector<MTGAbility *> > newAbilities;
|
||||
bool newAbilityFound;
|
||||
|
||||
ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vector<string>newAbilitiesList = vector<string>(),bool newAbilityFound = false);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
ATransformerFOREVER * clone() const;
|
||||
~ATransformerFOREVER();
|
||||
ATransformerInstant * clone() const;
|
||||
~ATransformerInstant();
|
||||
};
|
||||
|
||||
//switch p/t ueot
|
||||
@@ -4031,38 +3891,6 @@ public:
|
||||
~ASwapPTUEOT();
|
||||
};
|
||||
|
||||
//becomes ability
|
||||
//Adds types/abilities/P/T to a card (aura)
|
||||
class ABecomes: public MTGAbility
|
||||
{
|
||||
public:
|
||||
list<int> abilities;
|
||||
list<int> types;
|
||||
list<int> colors;
|
||||
WParsedPT * wppt;
|
||||
string menu;
|
||||
ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, WParsedPT * wppt, string sabilities);
|
||||
int addToGame();
|
||||
int destroy();
|
||||
const char * getMenuText();
|
||||
ABecomes * clone() const;
|
||||
~ABecomes();
|
||||
|
||||
};
|
||||
|
||||
//Adds types/abilities/P/T to a card (until end of turn)
|
||||
class ABecomesUEOT: public InstantAbility
|
||||
{
|
||||
public:
|
||||
ABecomes * ability;
|
||||
ABecomesUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, WParsedPT * wpt, string abilities);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
ABecomesUEOT * clone() const;
|
||||
~ABecomesUEOT();
|
||||
|
||||
};
|
||||
|
||||
class APreventDamageTypes: public MTGAbility
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -17,70 +17,6 @@ class CardPrimitive {
|
||||
ManaCost manaCost;
|
||||
|
||||
public:
|
||||
enum {
|
||||
NO_RESTRICTION = 0,
|
||||
PLAYER_TURN_ONLY = 1,
|
||||
AS_SORCERY = 2,
|
||||
MY_BEFORE_BEGIN = 3,
|
||||
MY_UNTAP = 4,
|
||||
MY_UPKEEP = 5,
|
||||
MY_DRAW = 6,
|
||||
MY_FIRSTMAIN = 7,
|
||||
MY_COMBATBEGIN = 8,
|
||||
MY_COMBATATTACKERS = 9,
|
||||
MY_COMBATBLOCKERS = 10,
|
||||
MY_COMBATDAMAGE = 11,
|
||||
MY_COMBATEND = 12,
|
||||
MY_SECONDMAIN = 13,
|
||||
MY_ENDOFTURN = 14,
|
||||
MY_EOT = 15,
|
||||
MY_CLEANUP = 16,
|
||||
MY_AFTER_EOT = 17,
|
||||
|
||||
OPPONENT_BEFORE_BEGIN = 23,
|
||||
OPPONENT_UNTAP = 24,
|
||||
OPPONENT_UPKEEP = 25,
|
||||
OPPONENT_DRAW = 26,
|
||||
OPPONENT_FIRSTMAIN = 27,
|
||||
OPPONENT_COMBATBEGIN = 28,
|
||||
OPPONENT_COMBATATTACKERS = 29,
|
||||
OPPONENT_COMBATBLOCKERS = 30,
|
||||
OPPONENT_COMBATDAMAGE = 31,
|
||||
OPPONENT_COMBATEND = 32,
|
||||
OPPONENT_SECONDMAIN = 33,
|
||||
OPPONENT_ENDOFTURN = 34,
|
||||
OPPONENT_EOT = 35,
|
||||
OPPONENT_CLEANUP = 36,
|
||||
OPPONENT_AFTER_EOT = 37,
|
||||
|
||||
BEFORE_BEGIN = 43,
|
||||
UNTAP = 44,
|
||||
UPKEEP = 45,
|
||||
DRAW = 46,
|
||||
FIRSTMAIN = 47,
|
||||
COMBATBEGIN = 48,
|
||||
COMBATATTACKERS = 49,
|
||||
COMBATBLOCKERS = 50,
|
||||
COMBATDAMAGE = 51,
|
||||
COMBATEND = 52,
|
||||
SECONDMAIN = 53,
|
||||
ENDOFTURN = 54,
|
||||
EOT = 55,
|
||||
CLEANUP = 56,
|
||||
AFTER_EOT = 57,
|
||||
|
||||
VAMPIRES = 60,
|
||||
LESS_CREATURES = 61,
|
||||
SNOW_LAND_INPLAY =62,
|
||||
CASTED_A_SPELL = 63,
|
||||
ONE_OF_AKIND = 64,
|
||||
FOURTHTURN = 65,
|
||||
BEFORECOMBATDAMAGE = 66,
|
||||
AFTERCOMBAT = 67,
|
||||
DURINGCOMBAT = 68,
|
||||
OPPONENT_TURN_ONLY = 69,
|
||||
|
||||
};
|
||||
string text;
|
||||
string name;
|
||||
int init();
|
||||
@@ -94,7 +30,7 @@ class CardPrimitive {
|
||||
int power;
|
||||
int toughness;
|
||||
bool hasRestriction;
|
||||
int restriction;
|
||||
string restriction;
|
||||
string otherrestriction;
|
||||
int suspendedTime;
|
||||
|
||||
@@ -143,8 +79,8 @@ class CardPrimitive {
|
||||
int getPower();
|
||||
void setToughness(int _toughness);
|
||||
int getToughness();
|
||||
void setRestrictions(int _restriction);
|
||||
int getRestrictions();
|
||||
void setRestrictions(string _restriction);
|
||||
void getRestrictions();
|
||||
void setOtherRestrictions(string _restriction);
|
||||
void getOtherRestrictions();
|
||||
const vector<string>& formattedText();
|
||||
|
||||
@@ -61,7 +61,14 @@ public:
|
||||
virtual int doPay();
|
||||
virtual LifeCost * clone() const;
|
||||
};
|
||||
|
||||
//pyrhaixa mana
|
||||
class LifeorManaCost: public ExtraCost{
|
||||
public:
|
||||
LifeorManaCost(TargetChooser *_tc = NULL,string manaType = "");
|
||||
string manaType;
|
||||
virtual int doPay();
|
||||
virtual LifeorManaCost * clone() const;
|
||||
};
|
||||
//Discard a random card cost
|
||||
class DiscardRandomCost: public ExtraCost{
|
||||
public:
|
||||
|
||||
@@ -98,17 +98,10 @@ class MTGAbility: public ActionElement{
|
||||
CLEANUP = 56,
|
||||
AFTER_EOT = 57,
|
||||
|
||||
VAMPIRES = 60,
|
||||
LESS_CREATURES = 61,
|
||||
SNOW_LAND_INPLAY =62,
|
||||
CASTED_A_SPELL = 63,
|
||||
ONE_OF_AKIND = 64,
|
||||
FOURTHTURN = 65,
|
||||
BEFORECOMBATDAMAGE = 66,
|
||||
AFTERCOMBAT = 67,
|
||||
DURINGCOMBAT = 68,
|
||||
OPPONENT_TURN_ONLY = 69,
|
||||
OPPONENT_TURN_ONLY = 60,
|
||||
|
||||
};
|
||||
int parseCastRestrictions(MTGCardInstance * card,Player * player,string restrictions,string otherRestrictions);
|
||||
int allowedToCast(MTGCardInstance * card,Player * player);
|
||||
int allowedToAltCast(MTGCardInstance * card,Player * player);
|
||||
int oneShot;
|
||||
@@ -260,9 +253,20 @@ class ActivatedAbility:public MTGAbility{
|
||||
};
|
||||
ManaCost * abilityCost;
|
||||
int restrictions;
|
||||
int limitPerTurn;
|
||||
string limit;
|
||||
int counters;
|
||||
int needsTapping;
|
||||
ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1);
|
||||
ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1,string limit = "");
|
||||
virtual ~ActivatedAbility();
|
||||
virtual void Update(float dt)
|
||||
{
|
||||
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT)
|
||||
{
|
||||
counters = 0;
|
||||
}
|
||||
return MTGAbility::Update(dt);
|
||||
}
|
||||
virtual int reactToClick(MTGCardInstance * card);
|
||||
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
virtual int reactToTargetClick(Targetable * object);
|
||||
@@ -371,11 +375,11 @@ class AbilityFactory{
|
||||
string storedString;
|
||||
int countCards(TargetChooser * tc, Player * player = NULL, int option = 0);
|
||||
TriggeredAbility * parseTrigger(string s, string magicText, int id, Spell * spell, MTGCardInstance *card, Targetable * target);
|
||||
int parseRestriction(string s);
|
||||
MTGAbility * getAlternateCost( string s, int id, Spell *spell, MTGCardInstance *card );
|
||||
MTGAbility * getManaReduxAbility(string s, int id, Spell *spell, MTGCardInstance *card, MTGCardInstance *target);
|
||||
|
||||
public:
|
||||
int parseRestriction(string s);
|
||||
Counter * parseCounter(string s, MTGCardInstance * target, Spell * spell = NULL);
|
||||
int parsePowerToughness(string s, int *power, int *toughness);
|
||||
int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL);
|
||||
@@ -421,10 +425,10 @@ class AManaProducer: public ActivatedAbilityTP{
|
||||
protected:
|
||||
|
||||
|
||||
string menutext;
|
||||
Player * controller;
|
||||
|
||||
public:
|
||||
string menutext;
|
||||
ManaCost * output;
|
||||
int tap;
|
||||
AManaProducer(int id, MTGCardInstance * card, Targetable * t, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 0, int who = TargetChooser::UNSET );
|
||||
|
||||
@@ -185,8 +185,8 @@ class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable {
|
||||
void eventattacked();
|
||||
void eventattackedAlone();
|
||||
void eventattackednotblocked();
|
||||
void eventattackedblocked();
|
||||
void eventblocked();
|
||||
void eventattackedblocked(MTGCardInstance * opponent);
|
||||
void eventblocked(MTGCardInstance * opponent);
|
||||
|
||||
int isInPlay();
|
||||
JSample * getSample();
|
||||
|
||||
@@ -18,6 +18,50 @@ public:
|
||||
OtherAbilitiesEventReceiver(int _id);
|
||||
OtherAbilitiesEventReceiver * clone() const;
|
||||
};
|
||||
|
||||
class MTGEventBonus: public MTGAbility
|
||||
{
|
||||
public:
|
||||
int textAlpha;
|
||||
string text;
|
||||
int army[2];
|
||||
bool army1[2];
|
||||
bool army2[2];
|
||||
bool army3[2];
|
||||
int toys[2];
|
||||
bool toybonusgranted[2];
|
||||
int chain[2];
|
||||
int highestChain[2];
|
||||
bool beastbonusgranted[2];
|
||||
int beast[2];
|
||||
bool zombiebonusgranted[2];
|
||||
int zombie[2];
|
||||
bool knightbonusgranted[2];
|
||||
int knight[2];
|
||||
bool insectbonusgranted[2];
|
||||
int insect[2];
|
||||
bool elementalbonusgranted[2];
|
||||
int elemental[2];
|
||||
bool vampirebonusgranted[2];
|
||||
int vampire[2];
|
||||
bool clericbonusgranted[2];
|
||||
int cleric[2];
|
||||
bool elfbonusgranted[2];
|
||||
int elf[2];
|
||||
bool Angelbonusgranted[2];
|
||||
int Angel[2];
|
||||
bool dragonbonusgranted[2];
|
||||
int dragon[2];
|
||||
|
||||
int receiveEvent(WEvent * event);
|
||||
void grantAward(string awardName,int amount);
|
||||
int testDestroy();
|
||||
void Update(float dt);
|
||||
void Render();
|
||||
MTGEventBonus(int _id);
|
||||
virtual MTGEventBonus * clone() const;
|
||||
};
|
||||
|
||||
class MTGPutInPlayRule: public MTGAbility
|
||||
{
|
||||
public:
|
||||
@@ -38,7 +82,7 @@ class MTGAlternativeCostRule: public MTGAbility
|
||||
protected:
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana, ManaCost *alternateManaCost);
|
||||
int reactToClick(MTGCardInstance * card, ManaCost * alternateManaCost, int paymentType = ManaCost::MANA_PAID);
|
||||
|
||||
string alternativeName;
|
||||
public:
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
int reactToClick(MTGCardInstance * card);
|
||||
@@ -48,6 +92,8 @@ public:
|
||||
MTGAlternativeCostRule(int _id);
|
||||
const char * getMenuText()
|
||||
{
|
||||
if(alternativeName.size())
|
||||
return alternativeName.c_str();
|
||||
return "Pay Alternative Cost";
|
||||
}
|
||||
virtual MTGAlternativeCostRule * clone() const;
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
ManaCost * Retrace;
|
||||
ManaCost * morph;
|
||||
ManaCost * suspend;
|
||||
string alternativeName;
|
||||
static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL);
|
||||
virtual void init();
|
||||
void x();
|
||||
|
||||
@@ -34,7 +34,6 @@ public:
|
||||
string deckFileSmall;
|
||||
string deckName;
|
||||
string phaseRing;
|
||||
|
||||
Player(string deckFile, string deckFileSmall, MTGDeck * deck = NULL);
|
||||
virtual ~Player();
|
||||
|
||||
|
||||
@@ -51,6 +51,10 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
;
|
||||
int ForceTargetListReady();
|
||||
int targetsReadyCheck();
|
||||
@@ -100,6 +104,7 @@ public:
|
||||
int nbzones;
|
||||
int init(int * _zones, int _nbzones);
|
||||
bool targetsZone(MTGGameZone * z);
|
||||
bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource);
|
||||
bool withoutProtections;
|
||||
TargetZoneChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false);
|
||||
TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false);
|
||||
|
||||
@@ -145,13 +145,15 @@ struct WEventCardAttackedNotBlocked : public WEventCardUpdate {
|
||||
|
||||
//event when card attacks but is blocked.
|
||||
struct WEventCardAttackedBlocked : public WEventCardUpdate {
|
||||
WEventCardAttackedBlocked(MTGCardInstance * card);
|
||||
WEventCardAttackedBlocked(MTGCardInstance * card,MTGCardInstance * opponent);
|
||||
MTGCardInstance * opponent;
|
||||
virtual Targetable * getTarget(int target);
|
||||
};
|
||||
|
||||
//event when card blocked.
|
||||
struct WEventCardBlocked : public WEventCardUpdate {
|
||||
WEventCardBlocked(MTGCardInstance * card);
|
||||
WEventCardBlocked(MTGCardInstance * card,MTGCardInstance * opponent);
|
||||
MTGCardInstance * opponent;
|
||||
virtual Targetable * getTarget(int target);
|
||||
};
|
||||
|
||||
|
||||
@@ -1296,6 +1296,7 @@ int AIPlayerBaka::computeActions()
|
||||
{
|
||||
GameObserver * g = GameObserver::GetInstance();
|
||||
Player * p = g->currentPlayer;
|
||||
Player * currentP = g->currentlyActing();
|
||||
if (!(g->currentlyActing() == this))
|
||||
return 0;
|
||||
if (g->mLayers->actionLayer()->menuObject)
|
||||
@@ -1315,7 +1316,19 @@ int AIPlayerBaka::computeActions()
|
||||
{//is already looking kick me out of this function!
|
||||
return 0;
|
||||
}
|
||||
if ((interruptIfICan() || g->isInterrupting == this) && p != this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 1)
|
||||
Interruptible * action = g->mLayers->stackLayer()->getAt(-1);
|
||||
Spell * spell = (Spell *) action;
|
||||
Player * lastStackActionController = NULL;
|
||||
if(spell && spell->type == ACTION_SPELL)
|
||||
lastStackActionController = spell->source->controller();
|
||||
if ((interruptIfICan() || g->isInterrupting == this)
|
||||
//i can interupt or am interupting
|
||||
&& p != this
|
||||
//and its not my turn
|
||||
&& this == currentP
|
||||
//and i am the currentlyActivePlayer
|
||||
&& ((lastStackActionController && lastStackActionController != this) || (g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)))
|
||||
//am im not interupting my own spell, or the stack contains nothing.
|
||||
{
|
||||
findingCard = true;
|
||||
CardDescriptor cd;
|
||||
@@ -1504,7 +1517,7 @@ int AIPlayerBaka::Act(float dt)
|
||||
DebugTrace("Cannot interrupt");
|
||||
return 0;
|
||||
}
|
||||
if (clickstream.empty())
|
||||
if (clickstream.empty() && g->currentlyActing() == this)//computeActions only when i have priority
|
||||
computeActions();
|
||||
if (clickstream.empty())
|
||||
{
|
||||
|
||||
@@ -772,6 +772,19 @@ int ActionStack::count(int type, int state, int display)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
int ActionStack::getActionElementFromCard(MTGCardInstance * card)
|
||||
{
|
||||
|
||||
for (int i = 0; i < mCount; i++)
|
||||
{
|
||||
Interruptible * current = (Interruptible *) mObjects[i];
|
||||
if (current->source == card)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Interruptible * ActionStack::getNext(Interruptible * previous, int type, int state, int display)
|
||||
{
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
//Activated Abilities
|
||||
|
||||
//Generic Activated Abilities
|
||||
GenericActivatedAbility::GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap,
|
||||
GenericActivatedAbility::GenericActivatedAbility(string newName,int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap,
|
||||
string limit, int restrictions, MTGGameZone * dest) :
|
||||
ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), limit(limit), activeZone(dest)
|
||||
ActivatedAbility(_id, card, _cost, restrictions, _tap,limit), NestedAbility(a), activeZone(dest),newName(newName)
|
||||
{
|
||||
counters = 0;
|
||||
target = ability->target;
|
||||
@@ -14,7 +14,6 @@ GenericActivatedAbility::GenericActivatedAbility(int _id, MTGCardInstance * card
|
||||
|
||||
int GenericActivatedAbility::resolve()
|
||||
{
|
||||
counters++;
|
||||
ManaCost * diff = abilityCost->Diff(cost);
|
||||
source->X = diff->hasX();
|
||||
source->XX = source->X/2;
|
||||
@@ -28,6 +27,8 @@ int GenericActivatedAbility::resolve()
|
||||
|
||||
const char * GenericActivatedAbility::getMenuText()
|
||||
{
|
||||
if(newName.size())
|
||||
return newName.c_str();
|
||||
if (ability)
|
||||
return ability->getMenuText();
|
||||
return "Error";
|
||||
@@ -37,24 +38,11 @@ int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost
|
||||
{
|
||||
if (dynamic_cast<AAMorph*> (ability) && !card->isMorphed && !card->morphed && card->turningOver)
|
||||
return 0;
|
||||
limitPerTurn = 0;
|
||||
if(limit.size())
|
||||
{
|
||||
WParsedInt * value = NEW WParsedInt(limit.c_str(),NULL,source);
|
||||
limitPerTurn = value->getValue();
|
||||
delete value;
|
||||
}
|
||||
if (limitPerTurn && counters >= limitPerTurn)
|
||||
return 0;
|
||||
return ActivatedAbility::isReactingToClick(card, mana);
|
||||
}
|
||||
|
||||
void GenericActivatedAbility::Update(float dt)
|
||||
{
|
||||
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT)
|
||||
{
|
||||
counters = 0;
|
||||
}
|
||||
ActivatedAbility::Update(dt);
|
||||
}
|
||||
|
||||
@@ -486,15 +474,12 @@ int AAFizzler::resolve()
|
||||
if(!target && !_target)
|
||||
{
|
||||
//if we hit this condiational its because Ai was targetting.
|
||||
target = source->target;
|
||||
Interruptible * laststackitem = game->mLayers->stackLayer()->getAt(-2);
|
||||
//fizzle the spell that was played directly before this counterspell
|
||||
//ai will tend to respond to you extremely quick.
|
||||
if (laststackitem && laststackitem->type == ACTION_SPELL)
|
||||
{
|
||||
Spell * spell = (Spell*) laststackitem;
|
||||
_target = spell;
|
||||
}
|
||||
Interruptible * targetCard = game->mLayers->stackLayer()->getAt(game->mLayers->stackLayer()->getActionElementFromCard(source->target));
|
||||
if (source->target && source->target->has(Constants::NOFIZZLE))
|
||||
return 0;
|
||||
_target = (Spell *) targetCard;
|
||||
game->mLayers->stackLayer()->Fizzle(_target);
|
||||
return 1;
|
||||
}
|
||||
if (target && _target->source->has(Constants::NOFIZZLE))
|
||||
return 0;
|
||||
@@ -1065,7 +1050,12 @@ int AADynamic::resolve()
|
||||
{
|
||||
while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next)
|
||||
_target = ((MTGCardInstance *)_target)->next;
|
||||
|
||||
if(sourceamount < 0)
|
||||
sourceamount = 0;
|
||||
if(targetamount < 0)
|
||||
targetamount = 0;
|
||||
//set values less then 0 to 0, it was reported that negitive numbers such as a creature who get -3/-3 having the power become
|
||||
//negitive, if then used as the amount, would cuase weird side effects on resolves.
|
||||
switch(effect)
|
||||
{
|
||||
case 0://deal damage
|
||||
@@ -1469,8 +1459,6 @@ AACloner::~AACloner()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Cast/Play Restriction modifier
|
||||
ACastRestriction::ACastRestriction(int _id, MTGCardInstance * card, Targetable * _target, TargetChooser * _restrictionsScope, WParsedInt * _value, bool _modifyExisting, int _zoneId, int who) :
|
||||
AbilityTP(_id, card, _target, who), restrictionsScope(_restrictionsScope), value(_value), modifyExisting(_modifyExisting),zoneId(_zoneId)
|
||||
@@ -2012,9 +2000,9 @@ MultiAbility::~MultiAbility()
|
||||
}
|
||||
|
||||
//Generic Target Ability
|
||||
GenericTargetAbility::GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a,
|
||||
GenericTargetAbility::GenericTargetAbility(string newName,int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a,
|
||||
ManaCost * _cost, int _tap, string limit, int restrictions, MTGGameZone * dest) :
|
||||
TargetAbility(_id, _source, _tc, _cost, restrictions, _tap), limit(limit), activeZone(dest)
|
||||
TargetAbility(_id, _source, _tc, _cost, restrictions, _tap), limit(limit), activeZone(dest),newName(newName)
|
||||
{
|
||||
ability = a;
|
||||
MTGAbility * core = AbilityFactory::getCoreAbility(a);
|
||||
@@ -2027,6 +2015,8 @@ const char * GenericTargetAbility::getMenuText()
|
||||
{
|
||||
if (!ability)
|
||||
return "Error";
|
||||
if (newName.size())
|
||||
return newName.c_str();
|
||||
|
||||
MTGAbility * core = AbilityFactory::getCoreAbility(ability);
|
||||
if (AAMover * move = dynamic_cast<AAMover *>(core))
|
||||
@@ -2229,16 +2219,23 @@ AAlterCost::~AAlterCost()
|
||||
}
|
||||
|
||||
// ATransformer
|
||||
ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound) :
|
||||
MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound)
|
||||
ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound,bool aForever) :
|
||||
MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever)
|
||||
{
|
||||
|
||||
PopulateAbilityIndexVector(abilities, sabilities);
|
||||
PopulateColorIndexVector(colors, sabilities);
|
||||
|
||||
|
||||
addNewColors = false;
|
||||
if(sabilities.find("newcolors") != string::npos)
|
||||
addNewColors = true;
|
||||
//this subkeyword adds a color without removing the existing colors.
|
||||
remove = false;
|
||||
if (stypes == "removesubtypes")
|
||||
remove = true;
|
||||
removeTypes = false;
|
||||
if (stypes == "removetypes")
|
||||
removeTypes = true;
|
||||
if (stypes == "allsubtypes" || stypes == "removesubtypes")
|
||||
{
|
||||
for (int i = Subtypes::LAST_TYPE + 1;; i++)
|
||||
@@ -2272,7 +2269,20 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t
|
||||
|
||||
int ATransformer::addToGame()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
MTGCardInstance * _target = NULL;
|
||||
Interruptible * action = (Interruptible *) target;
|
||||
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
|
||||
{
|
||||
Spell * spell = (Spell *) action;
|
||||
_target = spell->source;
|
||||
aForever = true;
|
||||
//when targeting the stack, set the effect to forever, incase the person does not use it
|
||||
//otherwise we will end up with a null pointer on the destroy.
|
||||
}
|
||||
else
|
||||
{
|
||||
_target = (MTGCardInstance *) target;
|
||||
}
|
||||
if (_target)
|
||||
{
|
||||
while (_target->next)
|
||||
@@ -2297,18 +2307,43 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t
|
||||
list<int>::iterator it;
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
_target->setColor(0, 1);
|
||||
if(!addNewColors)
|
||||
_target->setColor(0, 1);
|
||||
}
|
||||
|
||||
for (it = types.begin(); it != types.end(); it++)
|
||||
{
|
||||
if (remove )
|
||||
if (removeTypes)
|
||||
{
|
||||
//remove the main types from a card, ie: hidden enchantment cycle.
|
||||
_target->removeType(0,1);
|
||||
_target->removeType(1,1);
|
||||
_target->removeType(2,1);
|
||||
_target->removeType(3,1);
|
||||
_target->removeType(4,1);
|
||||
_target->removeType(5,1);
|
||||
_target->removeType(6,1);
|
||||
_target->removeType(7,1);
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
_target->removeType(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
_target->addType(*it);
|
||||
if(_target->hasSubtype(*it))
|
||||
{
|
||||
//we generally don't want to give a creature type creature again
|
||||
//all it does is create a sloppy mess of the subtype line on alternative quads
|
||||
//also creates instances where a card gained a type from an ability like this one
|
||||
//then loses the type through another ability, when this effect is destroyed the creature regains
|
||||
//the type, which is wrong.
|
||||
dontremove.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
_target->addType(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
@@ -2372,15 +2407,17 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t
|
||||
oldtoughness = _target->toughness;
|
||||
_target->addToToughness(val->getValue());
|
||||
_target->addToToughness(-oldtoughness);
|
||||
_target->life = _target->toughness;
|
||||
delete val;
|
||||
}
|
||||
|
||||
}
|
||||
return MTGAbility::addToGame();
|
||||
}
|
||||
|
||||
int ATransformer::destroy()
|
||||
{
|
||||
if(aForever)
|
||||
return 0;
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
if (_target)
|
||||
{
|
||||
@@ -2389,8 +2426,18 @@ int ATransformer::destroy()
|
||||
list<int>::iterator it;
|
||||
for (it = types.begin(); it != types.end(); it++)
|
||||
{
|
||||
if (remove == false)
|
||||
_target->removeType(*it);
|
||||
if (!remove)
|
||||
{
|
||||
bool removing = true;
|
||||
for(unsigned int k = 0;k < dontremove.size();k++)
|
||||
{
|
||||
if(dontremove[k] == *it)
|
||||
removing = false;
|
||||
}
|
||||
if(removing)
|
||||
_target->removeType(*it);
|
||||
}
|
||||
//iterators annoy me :/
|
||||
}
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
@@ -2404,7 +2451,7 @@ int ATransformer::destroy()
|
||||
{
|
||||
_target->setColor(*it);
|
||||
}
|
||||
if (remove )
|
||||
if (remove)
|
||||
{
|
||||
for (it = oldtypes.begin(); it != oldtypes.end(); it++)
|
||||
{
|
||||
@@ -2453,196 +2500,35 @@ ATransformer::~ATransformer()
|
||||
{
|
||||
}
|
||||
|
||||
// AForeverTransformer
|
||||
AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes,
|
||||
string sabilities,string newpower,bool newpowerfound, string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound) :
|
||||
MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound)
|
||||
//ATransformerInstant
|
||||
ATransformerInstant::ATransformerInstant(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string>newAbilitiesList,bool newAbilityFound,bool aForever) :
|
||||
InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever)
|
||||
{
|
||||
aType = MTGAbility::STANDARD_BECOMES;
|
||||
|
||||
PopulateAbilityIndexVector(abilities, sabilities);
|
||||
PopulateColorIndexVector(colors, sabilities);
|
||||
PopulateSubtypesIndexVector(types, stypes);
|
||||
menu = stypes;
|
||||
|
||||
remove = false;
|
||||
if (stypes == "removetypes")
|
||||
remove = true;
|
||||
}
|
||||
|
||||
int AForeverTransformer::addToGame()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
if (_target)
|
||||
{
|
||||
while (_target->next)
|
||||
_target = _target->next;
|
||||
list<int>::iterator it;
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
_target->setColor(0, 1);
|
||||
}
|
||||
for (it = types.begin(); it != types.end(); it++)
|
||||
{
|
||||
if(remove)
|
||||
{
|
||||
_target->removeType(0,1);
|
||||
_target->removeType(1,1);
|
||||
_target->removeType(2,1);
|
||||
_target->removeType(3,1);
|
||||
_target->removeType(4,1);
|
||||
_target->removeType(5,1);
|
||||
_target->removeType(6,1);
|
||||
_target->removeType(7,1);
|
||||
}
|
||||
else
|
||||
_target->addType(*it);
|
||||
}
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
_target->setColor(*it);
|
||||
}
|
||||
for (it = abilities.begin(); it != abilities.end(); it++)
|
||||
{
|
||||
_target->basicAbilities[*it]++;
|
||||
}
|
||||
if (newAbilityFound)
|
||||
{
|
||||
for (unsigned int k = 0 ; k < newAbilitiesList.size();k++)
|
||||
{
|
||||
AbilityFactory af;
|
||||
MTGAbility * aNew = af.parseMagicLine(newAbilitiesList[k], 0, NULL, _target);
|
||||
aNew->isClone = 1;
|
||||
|
||||
GenericTargetAbility * gta = dynamic_cast<GenericTargetAbility*> (aNew);
|
||||
if (gta)
|
||||
{
|
||||
((GenericTargetAbility *)aNew)->source = _target;
|
||||
((GenericTargetAbility *)aNew)->ability->source = _target;
|
||||
}
|
||||
GenericActivatedAbility * gaa = dynamic_cast<GenericActivatedAbility*> (aNew);
|
||||
if (gaa)
|
||||
{
|
||||
((GenericActivatedAbility *)aNew)->source = _target;
|
||||
((GenericActivatedAbility *)aNew)->ability->source = _target;
|
||||
}
|
||||
if (MultiAbility * abi = dynamic_cast<MultiAbility*>(aNew))
|
||||
{
|
||||
((MultiAbility *)aNew)->source = _target;
|
||||
((MultiAbility *)aNew)->abilities[0]->source = _target;
|
||||
}
|
||||
aNew->target = _target;
|
||||
aNew->source = (MTGCardInstance *) _target;
|
||||
if(aNew->oneShot)
|
||||
{
|
||||
aNew->resolve();
|
||||
delete aNew;
|
||||
}
|
||||
else
|
||||
aNew->addToGame();
|
||||
newAbilities[_target].push_back(aNew);
|
||||
}
|
||||
}
|
||||
if(newpowerfound )
|
||||
{
|
||||
WParsedInt * val = NEW WParsedInt(newpower,NULL, source);
|
||||
oldpower = _target->power -= oldpower;
|
||||
_target->power += val->getValue();
|
||||
_target->power -= oldpower;
|
||||
delete val;
|
||||
}
|
||||
if(newtoughnessfound )
|
||||
{
|
||||
WParsedInt * val = NEW WParsedInt(newtoughness,NULL, source);
|
||||
oldtoughness = _target->toughness;
|
||||
_target->addToToughness(val->getValue());
|
||||
_target->addToToughness(-oldtoughness);
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
return MTGAbility::addToGame();
|
||||
}
|
||||
|
||||
const char * AForeverTransformer::getMenuText()
|
||||
{
|
||||
string s = menu;
|
||||
sprintf(menuText, "Becomes %s", s.c_str());
|
||||
return menuText;
|
||||
}
|
||||
|
||||
AForeverTransformer * AForeverTransformer::clone() const
|
||||
{
|
||||
AForeverTransformer * a = NEW AForeverTransformer(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
AForeverTransformer::~AForeverTransformer()
|
||||
{
|
||||
}
|
||||
|
||||
//ATransformerUEOT
|
||||
ATransformerUEOT::ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string>newAbilitiesList,bool newAbilityFound) :
|
||||
InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound)
|
||||
{
|
||||
ability = NEW ATransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound);
|
||||
ability = NEW ATransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,aForever);
|
||||
aType = MTGAbility::STANDARD_BECOMES;
|
||||
}
|
||||
|
||||
int ATransformerUEOT::resolve()
|
||||
int ATransformerInstant::resolve()
|
||||
{
|
||||
ATransformer * a = ability->clone();
|
||||
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
|
||||
wrapper->addToGame();
|
||||
return 1;
|
||||
}
|
||||
const char * ATransformerUEOT::getMenuText()
|
||||
const char * ATransformerInstant::getMenuText()
|
||||
{
|
||||
return ability->getMenuText();
|
||||
}
|
||||
|
||||
ATransformerUEOT * ATransformerUEOT::clone() const
|
||||
ATransformerInstant * ATransformerInstant::clone() const
|
||||
{
|
||||
ATransformerUEOT * a = NEW ATransformerUEOT(*this);
|
||||
ATransformerInstant * a = NEW ATransformerInstant(*this);
|
||||
a->ability = this->ability->clone();
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
ATransformerUEOT::~ATransformerUEOT()
|
||||
{
|
||||
SAFE_DELETE(ability);
|
||||
}
|
||||
|
||||
// ATransformerFOREVER
|
||||
ATransformerFOREVER::ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string>newAbilitiesList,bool newAbilityFound) :
|
||||
InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound)
|
||||
{
|
||||
ability = NEW AForeverTransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound);
|
||||
aType = MTGAbility::STANDARD_BECOMES;
|
||||
}
|
||||
|
||||
int ATransformerFOREVER::resolve()
|
||||
{
|
||||
AForeverTransformer * a = ability->clone();
|
||||
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
|
||||
wrapper->addToGame();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char * ATransformerFOREVER::getMenuText()
|
||||
{
|
||||
return ability->getMenuText();
|
||||
}
|
||||
|
||||
ATransformerFOREVER * ATransformerFOREVER::clone() const
|
||||
{
|
||||
ATransformerFOREVER * a = NEW ATransformerFOREVER(*this);
|
||||
a->ability = this->ability->clone();
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
ATransformerFOREVER::~ATransformerFOREVER()
|
||||
ATransformerInstant::~ATransformerInstant()
|
||||
{
|
||||
SAFE_DELETE(ability);
|
||||
}
|
||||
@@ -2680,122 +2566,6 @@ ASwapPTUEOT::~ASwapPTUEOT()
|
||||
SAFE_DELETE(ability);
|
||||
}
|
||||
|
||||
// ABecomes
|
||||
ABecomes::ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, WParsedPT * wppt, string sabilities) :
|
||||
MTGAbility(id, source, target), wppt(wppt)
|
||||
{
|
||||
|
||||
aType = MTGAbility::STANDARD_BECOMES;
|
||||
|
||||
PopulateAbilityIndexVector(abilities, sabilities);
|
||||
PopulateColorIndexVector(colors, sabilities);
|
||||
PopulateSubtypesIndexVector(types, stypes);
|
||||
menu = stypes;
|
||||
|
||||
}
|
||||
int ABecomes::addToGame()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
list<int>::iterator it;
|
||||
for (it = types.begin(); it != types.end(); it++)
|
||||
{
|
||||
_target->addType(*it);
|
||||
}
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
_target->setColor(*it);
|
||||
}
|
||||
for (it = abilities.begin(); it != abilities.end(); it++)
|
||||
{
|
||||
_target->basicAbilities[*it]++;
|
||||
}
|
||||
|
||||
if (wppt)
|
||||
{
|
||||
_target->power = wppt->power.getValue();
|
||||
_target->toughness = wppt->toughness.getValue();
|
||||
_target->life = _target->toughness;
|
||||
}
|
||||
return MTGAbility::addToGame();
|
||||
}
|
||||
|
||||
int ABecomes::destroy()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
list<int>::iterator it;
|
||||
for (it = types.begin(); it != types.end(); it++)
|
||||
{
|
||||
_target->removeType(*it);
|
||||
}
|
||||
for (it = colors.begin(); it != colors.end(); it++)
|
||||
{
|
||||
_target->removeColor(*it);
|
||||
}
|
||||
for (it = abilities.begin(); it != abilities.end(); it++)
|
||||
{
|
||||
_target->basicAbilities[*it]--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char * ABecomes::getMenuText()
|
||||
{
|
||||
string s = menu;
|
||||
sprintf(menuText, "Becomes %s", s.c_str());
|
||||
return menuText;
|
||||
}
|
||||
|
||||
ABecomes * ABecomes::clone() const
|
||||
{
|
||||
ABecomes * a = NEW ABecomes(*this);
|
||||
if (a->wppt)
|
||||
a->wppt = NEW WParsedPT(*(a->wppt));
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
ABecomes::~ABecomes()
|
||||
{
|
||||
SAFE_DELETE (wppt);
|
||||
}
|
||||
|
||||
// ABecomes
|
||||
|
||||
// ABecomesUEOT
|
||||
ABecomesUEOT::ABecomesUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, WParsedPT * wpt,
|
||||
string abilities) :
|
||||
InstantAbility(id, source, target)
|
||||
{
|
||||
ability = NEW ABecomes(id, source, target, types, wpt, abilities);
|
||||
aType = MTGAbility::STANDARD_BECOMES;
|
||||
}
|
||||
|
||||
int ABecomesUEOT::resolve()
|
||||
{
|
||||
ABecomes * a = ability->clone();
|
||||
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
|
||||
wrapper->addToGame();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char * ABecomesUEOT::getMenuText()
|
||||
{
|
||||
return ability->getMenuText();
|
||||
}
|
||||
|
||||
ABecomesUEOT * ABecomesUEOT::clone() const
|
||||
{
|
||||
ABecomesUEOT * a = NEW ABecomesUEOT(*this);
|
||||
a->ability = this->ability->clone();
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
ABecomesUEOT::~ABecomesUEOT()
|
||||
{
|
||||
SAFE_DELETE(ability);
|
||||
}
|
||||
|
||||
//APreventDamageTypes
|
||||
APreventDamageTypes::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) :
|
||||
MTGAbility(id, source), to(to), from(from), type(type)
|
||||
|
||||
@@ -246,7 +246,6 @@ void CardGui::Render()
|
||||
mFont->SetScale(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (tc && !tc->canTarget(card))
|
||||
{
|
||||
if (!shadow)
|
||||
|
||||
@@ -23,6 +23,8 @@ CardPrimitive::CardPrimitive(CardPrimitive * source)
|
||||
for (int i = 0; i < Constants::MTG_NB_COLORS; ++i)
|
||||
colors[i] = source->colors[i];
|
||||
manaCost.copy(source->getManaCost());
|
||||
if(source->getManaCost()->alternative)
|
||||
manaCost.alternative->alternativeName = source->getManaCost()->alternative->alternativeName;
|
||||
|
||||
text = source->text;
|
||||
setName(source->name);
|
||||
@@ -87,13 +89,13 @@ bool CardPrimitive::isSpell()
|
||||
return (!isCreature() && !isLand());
|
||||
}
|
||||
|
||||
void CardPrimitive::setRestrictions(int _restriction)
|
||||
void CardPrimitive::setRestrictions(string _restriction)
|
||||
{
|
||||
restriction = _restriction;
|
||||
}
|
||||
int CardPrimitive::getRestrictions()
|
||||
void CardPrimitive::getRestrictions()
|
||||
{
|
||||
return restriction;
|
||||
restriction;
|
||||
}
|
||||
|
||||
void CardPrimitive::setOtherRestrictions(string _restriction)
|
||||
|
||||
@@ -23,6 +23,7 @@ void DuelLayers::init()
|
||||
action = NEW ActionLayer();
|
||||
action->Add(NEW MTGGamePhase(action->getMaxId()));
|
||||
//Add Magic Specific Rules
|
||||
action->Add(NEW MTGEventBonus(-1));
|
||||
action->Add(NEW MTGPutInPlayRule(-1));
|
||||
action->Add(NEW MTGAlternativeCostRule(-1));
|
||||
action->Add(NEW MTGBuyBackRule(-1));
|
||||
|
||||
@@ -87,7 +87,44 @@ int LifeCost::doPay()
|
||||
tc->initTargets();
|
||||
return 1;
|
||||
}
|
||||
//life or Mana cost
|
||||
LifeorManaCost * LifeorManaCost::clone() const
|
||||
{
|
||||
LifeorManaCost * ec = NEW LifeorManaCost(*this);
|
||||
if (tc)
|
||||
ec->tc = tc->clone();
|
||||
return ec;
|
||||
}
|
||||
|
||||
LifeorManaCost::LifeorManaCost(TargetChooser *_tc,string manaType) :
|
||||
ExtraCost("Phyrexian Mana", _tc),manaType(manaType)
|
||||
{
|
||||
}
|
||||
|
||||
int LifeorManaCost::doPay()
|
||||
{
|
||||
if (!target)
|
||||
return 0;
|
||||
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
string buildType ="{";
|
||||
buildType.append(manaType);
|
||||
buildType.append("}");
|
||||
ManaCost * newCost = ManaCost::parseManaCost(buildType);
|
||||
if(_target->controller()->getManaPool()->canAfford(newCost))
|
||||
{
|
||||
_target->controller()->getManaPool()->pay(newCost);
|
||||
}
|
||||
else
|
||||
{
|
||||
_target->controller()->loseLife(2);
|
||||
}
|
||||
SAFE_DELETE(newCost);
|
||||
target = NULL;
|
||||
if (tc)
|
||||
tc->initTargets();
|
||||
return 1;
|
||||
}
|
||||
//discard a card at random as a cost
|
||||
//DiscardRandom cost
|
||||
DiscardRandomCost * DiscardRandomCost::clone() const
|
||||
|
||||
@@ -22,165 +22,189 @@ const string kMaxCastKeywords[] = { "maxplay(", "maxcast("};
|
||||
const int kMaxCastZones[] = { MTGGameZone::BATTLEFIELD, MTGGameZone::STACK};
|
||||
const size_t kMaxCastKeywordsCount = 2;
|
||||
|
||||
int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player)
|
||||
int MTGAbility::parseCastRestrictions(MTGCardInstance * card,Player * player,string restrictions,string otherRestrictions)
|
||||
{
|
||||
restrictions.append(otherRestrictions);
|
||||
//we can do this becuase the function calls send them seperately, so one will always be empty
|
||||
vector <string> restriction = split(restrictions, ',');
|
||||
AbilityFactory af;
|
||||
int cPhase = game->getCurrentGamePhase();
|
||||
int restrictions = 0;
|
||||
restrictions = card->getRestrictions();
|
||||
|
||||
int vamps = 0;
|
||||
int playercreatures = 0;
|
||||
int opponentcreatures = 0;
|
||||
|
||||
switch (restrictions)
|
||||
for(unsigned int i = 0;i < restriction.size();i++)
|
||||
{
|
||||
case PLAYER_TURN_ONLY:
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
break;
|
||||
case OPPONENT_TURN_ONLY:
|
||||
if (player == game->currentPlayer)
|
||||
return 0;
|
||||
break;
|
||||
case AS_SORCERY:
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN)
|
||||
return 0;
|
||||
break;
|
||||
case VAMPIRES:
|
||||
vamps = player->game->inPlay->countByType("vampire");
|
||||
if(vamps < 2)
|
||||
return 0;
|
||||
break;
|
||||
case LESS_CREATURES:
|
||||
int checkPhaseBased = af.parseRestriction(restriction[i]);
|
||||
switch (checkPhaseBased)
|
||||
{
|
||||
case PLAYER_TURN_ONLY:
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
break;
|
||||
case OPPONENT_TURN_ONLY:
|
||||
if (player == game->currentPlayer)
|
||||
return 0;
|
||||
break;
|
||||
case AS_SORCERY:
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
if (checkPhaseBased >= MY_BEFORE_BEGIN && checkPhaseBased <= MY_AFTER_EOT)
|
||||
{
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != checkPhaseBased - MY_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
if (checkPhaseBased >= OPPONENT_BEFORE_BEGIN && checkPhaseBased <= OPPONENT_AFTER_EOT)
|
||||
{
|
||||
if (player == game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != checkPhaseBased - OPPONENT_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
if (checkPhaseBased >= BEFORE_BEGIN && checkPhaseBased <= AFTER_EOT)
|
||||
{
|
||||
if (cPhase != checkPhaseBased - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
size_t typeRelated = restriction[i].find("typemin:");
|
||||
size_t check = NULL;
|
||||
if(typeRelated != string::npos)
|
||||
{
|
||||
bool less = false;
|
||||
bool more = false;
|
||||
int mytypemin = 0;
|
||||
int opponenttypemin = 0;
|
||||
int min = 0;
|
||||
int opponentmin = 0;
|
||||
string type = "*";
|
||||
string opponenttype = "*";
|
||||
|
||||
playercreatures = player->game->inPlay->countByType("creature");
|
||||
opponentcreatures = player->opponent()->game->inPlay->countByType("creature");
|
||||
if(playercreatures > opponentcreatures)
|
||||
return 0;
|
||||
break;
|
||||
case SNOW_LAND_INPLAY:
|
||||
if(!player->game->inPlay->hasPrimaryType("snow","land"))
|
||||
return 0;
|
||||
break;
|
||||
case CASTED_A_SPELL:
|
||||
if(player->game->stack->seenThisTurn("*", Constants::CAST_ALL) < 1)
|
||||
return 0;
|
||||
break;
|
||||
case ONE_OF_AKIND:
|
||||
if(player->game->inPlay->hasName(card->name))
|
||||
return 0;
|
||||
break;
|
||||
case FOURTHTURN:
|
||||
if(game->turn <= 7)
|
||||
return 0;
|
||||
break;
|
||||
case BEFORECOMBATDAMAGE:
|
||||
if(cPhase > Constants::MTG_PHASE_COMBATBLOCKERS)
|
||||
return 0;
|
||||
break;
|
||||
case AFTERCOMBAT:
|
||||
if(cPhase < Constants::MTG_PHASE_COMBATBLOCKERS)
|
||||
return 0;
|
||||
break;
|
||||
case DURINGCOMBAT:
|
||||
if(cPhase < Constants::MTG_PHASE_COMBATBEGIN ||cPhase > Constants::MTG_PHASE_COMBATEND )
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
check = restriction[i].find("mytypemin:");
|
||||
if( check != string::npos)
|
||||
{
|
||||
size_t start = restriction[i].find(":", check);
|
||||
size_t end = restriction[i].find(" ", check);
|
||||
size_t lesser = restriction[i].find(":less",check);
|
||||
size_t morer = restriction[i].find(":more",check);
|
||||
if(lesser != string::npos)
|
||||
{
|
||||
less = true;
|
||||
}
|
||||
else if(morer != string::npos)
|
||||
{
|
||||
more = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
min = atoi(restriction[i].substr(start + 1, end - start - 1).c_str());
|
||||
}
|
||||
size_t found = restriction[i].find("type(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
end = restriction[i].find(")", found);
|
||||
type = restriction[i].substr(found + 5, end - found - 5).c_str();
|
||||
}
|
||||
mytypemin = card->controller()->game->inPlay->countByType(type.c_str());
|
||||
if(mytypemin < min && less == false && more == false)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("opponenttypemin:");
|
||||
if( check != string::npos)
|
||||
{
|
||||
size_t start = restriction[i].find(":", check);
|
||||
size_t end = restriction[i].find(" ", check);
|
||||
opponentmin = atoi(restriction[i].substr(start + 1, end - start - 1).c_str());
|
||||
|
||||
if (restrictions >= MY_BEFORE_BEGIN && restrictions <= MY_AFTER_EOT)
|
||||
{
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != restrictions - MY_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (restrictions >= OPPONENT_BEFORE_BEGIN && restrictions <= OPPONENT_AFTER_EOT)
|
||||
{
|
||||
if (player == game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != restrictions - OPPONENT_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (restrictions >= BEFORE_BEGIN && restrictions <= AFTER_EOT)
|
||||
{
|
||||
if (cPhase != restrictions - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
size_t found = restriction[i].find("opponenttype(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
end = restriction[i].find(")", found);
|
||||
opponenttype = restriction[i].substr(found + 13, end - found - 13).c_str();
|
||||
}
|
||||
opponenttypemin = card->controller()->opponent()->game->inPlay->countByType(opponenttype.c_str());
|
||||
if(opponenttypemin < opponentmin && less == false && more == false)
|
||||
return 0;
|
||||
}
|
||||
if(less && more == false && opponenttypemin <= mytypemin)
|
||||
return 0;
|
||||
if(less == false && more && opponenttypemin >= mytypemin)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("turn:");
|
||||
if(check != string::npos)
|
||||
{
|
||||
int Turn = 0;
|
||||
size_t start = restriction[i].find(":", check);
|
||||
size_t end = restriction[i].find(" ", check);
|
||||
Turn = atoi(restriction[i].substr(start + 1, end - start - 1).c_str());
|
||||
if(game->turn < Turn)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("casted a spell");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(player->game->stack->seenThisTurn("*", Constants::CAST_ALL) < 1)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("one of a kind");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(player->game->inPlay->hasName(card->name))
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("before battle damage");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(cPhase > Constants::MTG_PHASE_COMBATBLOCKERS)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("after battle");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(cPhase < Constants::MTG_PHASE_COMBATBLOCKERS)
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("during battle");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(cPhase < Constants::MTG_PHASE_COMBATBEGIN ||cPhase > Constants::MTG_PHASE_COMBATEND )
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("control snow land");
|
||||
if(check != string::npos)
|
||||
{
|
||||
if(!player->game->inPlay->hasPrimaryType("snow","land"))
|
||||
return 0;
|
||||
}
|
||||
check = restriction[i].find("control two or more vampires");
|
||||
if(check != string::npos)
|
||||
{
|
||||
restriction.push_back("mytypemin:2 type(vampire)");
|
||||
}
|
||||
check = restriction[i].find("control less creatures");
|
||||
if(check != string::npos)
|
||||
{
|
||||
restriction.push_back("mytypemin:less type(creature)");
|
||||
}
|
||||
check = restriction[i].find("fourth turn");
|
||||
if(check != string::npos)
|
||||
{
|
||||
restriction.push_back("turn:4");
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player)
|
||||
{
|
||||
return parseCastRestrictions(card,player,card->restriction,"");
|
||||
}
|
||||
|
||||
int MTGAbility::allowedToAltCast(MTGCardInstance * card,Player * player)
|
||||
{
|
||||
int cPhase = game->getCurrentGamePhase();
|
||||
string restrictions = "";
|
||||
restrictions = card->otherrestriction;
|
||||
static bool less = false;
|
||||
static bool more = false;
|
||||
int mytypemin = 0;
|
||||
int opponenttypemin = 0;
|
||||
int min = 0;
|
||||
int opponentmin = 0;
|
||||
string type = "*";
|
||||
string opponenttype = "*";
|
||||
|
||||
size_t check = restrictions.find("mytypemin:");
|
||||
if( check != string::npos)
|
||||
{
|
||||
size_t start = restrictions.find(":", check);
|
||||
size_t end = restrictions.find(" ", check);
|
||||
size_t lesser = restrictions.find(":less",check);
|
||||
size_t morer = restrictions.find(":more",check);
|
||||
if(lesser != string::npos)
|
||||
{
|
||||
less = true;
|
||||
}
|
||||
else if(morer != string::npos)
|
||||
{
|
||||
more = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
min = atoi(restrictions.substr(start + 1, end - start - 1).c_str());
|
||||
}
|
||||
|
||||
|
||||
size_t found = restrictions.find("type(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
end = restrictions.find(")", found);
|
||||
type = restrictions.substr(found + 5, end - found - 5).c_str();
|
||||
}
|
||||
mytypemin = card->controller()->game->inPlay->countByType(type.c_str());
|
||||
if(mytypemin < min && less == false && more == false)
|
||||
return 0;
|
||||
}
|
||||
check = restrictions.find("opponenttypemin:");
|
||||
if( check != string::npos)
|
||||
{
|
||||
size_t start = restrictions.find(":", check);
|
||||
size_t end = restrictions.find(" ", check);
|
||||
opponentmin = atoi(restrictions.substr(start + 1, end - start - 1).c_str());
|
||||
|
||||
size_t found = restrictions.find("opponenttype(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
end = restrictions.find(")", found);
|
||||
opponenttype = restrictions.substr(found + 13, end - found - 13).c_str();
|
||||
}
|
||||
opponenttypemin = card->controller()->opponent()->game->inPlay->countByType(opponenttype.c_str());
|
||||
if(opponenttypemin < opponentmin && less == false && more == false)
|
||||
return 0;
|
||||
}
|
||||
if(less && more == false && opponenttypemin <= mytypemin)
|
||||
return 0;
|
||||
if(less == false && more && opponenttypemin >= mytypemin)
|
||||
return 0;
|
||||
return 1;
|
||||
return parseCastRestrictions(card,player,"",card->otherrestriction);
|
||||
}
|
||||
|
||||
int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option)
|
||||
@@ -447,89 +471,61 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int
|
||||
|
||||
return NEW TrCardTappedformana(id, card, tc, true);
|
||||
}
|
||||
|
||||
//Card is attacking
|
||||
found = s.find("attacking(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")");
|
||||
string starget = s.substr(found + 10, end - found - 10);
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser *tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
|
||||
return NEW TrCardAttacked(id, card, tc,sourceUntapped,opponentPoisoned);
|
||||
}
|
||||
//Card is attacking alone
|
||||
found = s.find("attackedalone(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")");
|
||||
string starget = s.substr(found + 14, end - found - 14);
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser *tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
|
||||
return NEW TrCardAttackedAlone(id, card, tc);
|
||||
}
|
||||
|
||||
//Card card attacked and is not blocked
|
||||
found = s.find("notblocked(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")");
|
||||
string starget = s.substr(found + 11, end - found - 11);
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser *tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
|
||||
return NEW TrCardAttackedNotBlocked(id, card, tc);
|
||||
}
|
||||
|
||||
|
||||
//CombatTrigger
|
||||
//Card card attacked and is blocked
|
||||
found = s.find("blocked(");
|
||||
found = s.find("combat(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")");
|
||||
string starget = s.substr(found + 8, end - found - 8);
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser *tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
found = s.find("from(");
|
||||
|
||||
size_t end = s.find(")",found);
|
||||
string combatTrigger = s.substr(found + 7, end - found - 7);
|
||||
//find combat traits, only trigger types, the general restrictions are found earlier.
|
||||
bool attackingTrigger = false;
|
||||
bool attackedAloneTrigger = false;
|
||||
bool notBlockedTrigger = false;
|
||||
bool attackBlockedTrigger = false;
|
||||
bool blockingTrigger = false;
|
||||
vector <string> combatTriggerVector = split(combatTrigger, ',');
|
||||
for (unsigned int i = 0 ; i < combatTriggerVector.size() ; i++)
|
||||
{
|
||||
if(combatTriggerVector[i] == "attacking")
|
||||
attackingTrigger = true;
|
||||
if(combatTriggerVector[i] == "attackedalone")
|
||||
attackedAloneTrigger = true;
|
||||
if(combatTriggerVector[i] == "notblocked")
|
||||
notBlockedTrigger = true;
|
||||
if(combatTriggerVector[i] == "blocked")
|
||||
attackBlockedTrigger = true;
|
||||
if(combatTriggerVector[i] == "blocking")
|
||||
blockingTrigger = true;
|
||||
}
|
||||
//build triggers TCs
|
||||
TargetChooser *tc = NULL;
|
||||
TargetChooser *fromTc = NULL;
|
||||
if (found != string::npos)
|
||||
TargetChooserFactory tcf;
|
||||
string starget;
|
||||
string ftarget;
|
||||
size_t sourceCard = s.find("source(");
|
||||
if (sourceCard != string::npos)
|
||||
{
|
||||
end = s.find(")", found);
|
||||
starget = s.substr(found + 5, end - found - 5);
|
||||
fromTc = tcf.createTargetChooser(starget, card);
|
||||
size_t sEnd = s.find(")",sourceCard);
|
||||
starget = s.substr(sourceCard + 7, sEnd - sourceCard - 7);
|
||||
tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
}
|
||||
size_t From = s.find("from(");
|
||||
if (From != string::npos)
|
||||
{
|
||||
size_t fromEnd = s.find(")", From);
|
||||
ftarget = s.substr(From + 5, fromEnd - From - 5);
|
||||
fromTc = tcf.createTargetChooser(ftarget, card);
|
||||
fromTc->targetter = NULL;
|
||||
}
|
||||
|
||||
return NEW TrCardAttackedBlocked(id, card, tc, fromTc,limitOnceATurn);
|
||||
}
|
||||
|
||||
//Card card is a blocker
|
||||
found = s.find("blocking(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")");
|
||||
string starget = s.substr(found + 9, end - found - 9);
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser *tc = tcf.createTargetChooser(starget, card);
|
||||
tc->targetter = NULL;
|
||||
found = s.find("from(");
|
||||
|
||||
TargetChooser *fromTc = NULL;
|
||||
if (found != string::npos)
|
||||
{
|
||||
end = s.find(")", found);
|
||||
starget = s.substr(found + 5, end - found - 5);
|
||||
fromTc = tcf.createTargetChooser(starget, card);
|
||||
fromTc->targetter = NULL;
|
||||
}
|
||||
|
||||
return NEW TrCardBlocked(id, card, tc, fromTc,once,limitOnceATurn);
|
||||
if(tc)//a source( is required, from( is optional.
|
||||
return NEW TrCombatTrigger(id, card, tc, fromTc,once,limitOnceATurn,sourceUntapped,opponentPoisoned,
|
||||
attackingTrigger,attackedAloneTrigger,notBlockedTrigger,attackBlockedTrigger,blockingTrigger);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Card card is drawn
|
||||
@@ -884,6 +880,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
|
||||
TargetChooser * tc = NULL;
|
||||
string sWithoutTc = s;
|
||||
string newName = "";
|
||||
found = sWithoutTc.find("name(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = sWithoutTc.find(")", found);
|
||||
newName = sWithoutTc.substr(found + 5, end - found - 5);
|
||||
}
|
||||
//Target Abilities
|
||||
found = s.find("target(");
|
||||
if (found != string::npos)
|
||||
@@ -950,8 +953,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return ae;
|
||||
}
|
||||
if (tc)
|
||||
return NEW GenericTargetAbility(id, card, tc, a, cost, doTap, limit, restrictions, dest);
|
||||
return NEW GenericActivatedAbility(id, card, a, cost, doTap, limit, restrictions, dest);
|
||||
return NEW GenericTargetAbility(newName,id, card, tc, a, cost, doTap, limit, restrictions, dest);
|
||||
return NEW GenericActivatedAbility(newName,id, card, a, cost, doTap, limit, restrictions, dest);
|
||||
}
|
||||
SAFE_DELETE(cost);
|
||||
}
|
||||
@@ -1011,11 +1014,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return NULL;
|
||||
|
||||
if (tc)
|
||||
a1 = NEW GenericTargetAbility(id, card, tc, a1);
|
||||
a1 = NEW GenericTargetAbility(newName,id, card, tc, a1);
|
||||
else
|
||||
a1 = NEW GenericActivatedAbility(id, card, a1, NULL);
|
||||
a1 = NEW GenericActivatedAbility(newName,id, card, a1, NULL);
|
||||
return NEW MayAbility(id, a1, card);
|
||||
}
|
||||
|
||||
//When...comes into play, choose one...
|
||||
found = s.find("choice ");
|
||||
if (found == 0)
|
||||
@@ -1026,9 +1030,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return NULL;
|
||||
|
||||
if (tc)
|
||||
a1 = NEW GenericTargetAbility(id, card, tc, a1);
|
||||
a1 = NEW GenericTargetAbility(newName,id, card, tc, a1);
|
||||
else
|
||||
a1 = NEW GenericActivatedAbility(id, card, a1, NULL);
|
||||
a1 = NEW GenericActivatedAbility(newName,id, card, a1, NULL);
|
||||
return NEW MayAbility(id, a1, card, true);
|
||||
}
|
||||
|
||||
@@ -1386,7 +1390,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
DebugTrace("ABILITYFACTORY Error parsing: " << s);
|
||||
return NULL;
|
||||
}
|
||||
a = NEW GenericTargetAbility(id, card, tc, a);
|
||||
a = NEW GenericTargetAbility(newName,id, card, tc, a);
|
||||
return NEW MayAbility(id, a, card, true);
|
||||
}
|
||||
|
||||
@@ -1831,18 +1835,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return tok;
|
||||
}
|
||||
|
||||
//name an ability line
|
||||
found = s.find("name(");
|
||||
if (found != string::npos)
|
||||
{
|
||||
size_t end = s.find(")", found);
|
||||
string sname = s.substr(found + 5, end - found - 5);
|
||||
|
||||
ANamer * tok = NEW ANamer(id, card, NULL, sname, 0);
|
||||
return tok;
|
||||
}
|
||||
//living weapon
|
||||
|
||||
//Equipment
|
||||
found = s.find("equip");
|
||||
if (found != string::npos)
|
||||
@@ -2298,15 +2290,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
Targetable * t = NULL;
|
||||
if (spell)
|
||||
t = spell->getNextTarget();
|
||||
if (!activated)
|
||||
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT)
|
||||
{
|
||||
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT)
|
||||
{
|
||||
return NEW AInstantCastRestrictionUEOT(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who);
|
||||
}
|
||||
return NEW ACastRestriction(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who);
|
||||
return NEW AInstantCastRestrictionUEOT(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who);
|
||||
}
|
||||
return NULL; //TODO NEW ACastRestrictionUntilEndOfTurn(id, card, t, value, modifyExisting, kMaxCastZones[i], who);
|
||||
return NEW ACastRestriction(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who);
|
||||
//TODO NEW ACastRestrictionUntilEndOfTurn(id, card, t, value, modifyExisting, kMaxCastZones[i], who);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2437,6 +2426,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
string stypes = s.substr(found + 8, end - found - 8);
|
||||
WParsedPT * pt = NULL;
|
||||
string sabilities;
|
||||
string newPower = "";
|
||||
string newToughness = "";
|
||||
if (end != real_end)
|
||||
{
|
||||
int previous = end + 1;
|
||||
@@ -2444,27 +2435,41 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
if (end == string::npos)
|
||||
end = real_end;
|
||||
string temp = s.substr(previous, end - previous);
|
||||
pt = NEW WParsedPT(temp, spell, card);
|
||||
if (!pt->ok)
|
||||
size_t seperator = temp.find("/");
|
||||
if(seperator != string::npos)
|
||||
{
|
||||
newPower = temp.substr(0,seperator);
|
||||
newToughness = temp.substr(seperator + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_DELETE(pt);
|
||||
sabilities = temp;
|
||||
}
|
||||
}
|
||||
if (pt && end != real_end)
|
||||
if ((newPower.length() || newToughness.length()) && end != real_end)
|
||||
{
|
||||
sabilities = s.substr(end + 1, real_end - end - 1);
|
||||
}
|
||||
MTGAbility * ab;
|
||||
if (forceUEOT)
|
||||
bool foreverEffect = false;
|
||||
if (forceFOREVER)
|
||||
{
|
||||
ab = NEW ABecomesUEOT(id, card, target, stypes, pt, sabilities);
|
||||
foreverEffect = true;
|
||||
}
|
||||
if (oneShot || forceUEOT)
|
||||
{
|
||||
ab = NEW ATransformerInstant(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector<string>(),false,foreverEffect);
|
||||
}
|
||||
else if(foreverEffect)
|
||||
{
|
||||
ab = NEW ATransformerInstant(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector<string>(),false,foreverEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
ab = NEW ABecomes(id, card, target, stypes, pt, sabilities);
|
||||
ab = NEW ATransformer(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector<string>(),false,foreverEffect);
|
||||
}
|
||||
return ab;
|
||||
|
||||
}
|
||||
|
||||
//bloodthirst
|
||||
@@ -2587,13 +2592,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
}
|
||||
}
|
||||
MTGAbility * a;
|
||||
bool foreverEffect = false;
|
||||
if (forceFOREVER)
|
||||
{
|
||||
a = NEW ATransformerFOREVER(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound);
|
||||
foreverEffect = true;
|
||||
}
|
||||
else if (forceUEOT)
|
||||
if (oneShot || forceUEOT)
|
||||
{
|
||||
a = NEW ATransformerUEOT(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound);
|
||||
a = NEW ATransformerInstant(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,foreverEffect);
|
||||
}
|
||||
else if(foreverEffect)
|
||||
{
|
||||
a = NEW ATransformerInstant(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,foreverEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2604,15 +2614,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
|
||||
//Change Power/Toughness
|
||||
WParsedPT * wppt = NEW WParsedPT(s, spell, card);
|
||||
bool nonstatic = false;
|
||||
if (wppt->ok)
|
||||
{
|
||||
if(s.find("nonstatic") != string::npos)
|
||||
nonstatic = true;
|
||||
if (!activated)
|
||||
{
|
||||
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT)
|
||||
{
|
||||
return NEW AInstantPowerToughnessModifierUntilEOT(id, card, target, wppt);
|
||||
}
|
||||
return NEW APowerToughnessModifier(id, card, target, wppt);
|
||||
return NEW APowerToughnessModifier(id, card, target, wppt,s,nonstatic);
|
||||
}
|
||||
return NEW APowerToughnessModifierUntilEndOfTurn(id, card, target, wppt);
|
||||
}
|
||||
@@ -2631,6 +2644,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
t = spell->getNextTarget();
|
||||
MTGAbility * a = NEW AManaProducer(id, card, t, output, NULL, doTap, who);
|
||||
a->oneShot = 1;
|
||||
if(newName.size())
|
||||
((AManaProducer*)a)->menutext = newName;
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -3941,9 +3956,10 @@ NestedAbility::NestedAbility(MTGAbility * _ability)
|
||||
|
||||
//
|
||||
|
||||
ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions, int tap) :
|
||||
MTGAbility(id, card), restrictions(restrictions), needsTapping(tap)
|
||||
ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions, int tap,string limit) :
|
||||
MTGAbility(id, card), restrictions(restrictions), needsTapping(tap),limit(limit)
|
||||
{
|
||||
counters = 0;
|
||||
cost = _cost;
|
||||
abilityCost = 0;
|
||||
}
|
||||
@@ -3951,7 +3967,8 @@ ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _c
|
||||
int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
{
|
||||
if(card->isPhased)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
Player * player = game->currentlyActing();
|
||||
int cPhase = game->getCurrentGamePhase();
|
||||
switch (restrictions)
|
||||
@@ -3992,7 +4009,20 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
if (cPhase != restrictions - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN)
|
||||
return 0;
|
||||
}
|
||||
|
||||
limitPerTurn = 0;
|
||||
if(limit.size())
|
||||
{
|
||||
WParsedInt * value = NEW WParsedInt(limit.c_str(),NULL,source);
|
||||
limitPerTurn = value->getValue();
|
||||
delete value;
|
||||
//only run this check if we have a valid limit string.
|
||||
//limits on uses are based on when the ability is used, not when it is resolved
|
||||
//incrementing of counters directly after the fireability()
|
||||
//as ability limits are supposed to count the use regaurdless of the ability actually
|
||||
//resolving. this check was previously located in genericactivated, and incrementing was handled in the resolve.
|
||||
if (limitPerTurn && counters >= limitPerTurn)
|
||||
return 0;
|
||||
}
|
||||
if (card == source && source->controller() == player && (!needsTapping || (!source->isTapped()
|
||||
&& !source->hasSummoningSickness())))
|
||||
{
|
||||
@@ -4032,7 +4062,7 @@ int ActivatedAbility::reactToClick(MTGCardInstance * card)
|
||||
if (needsTapping && source->isInPlay())
|
||||
source->tap();
|
||||
fireAbility();
|
||||
|
||||
counters++;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -360,19 +360,19 @@ void MTGCardInstance::eventattackednotblocked()
|
||||
}
|
||||
|
||||
//sets card as attacked and sends events
|
||||
void MTGCardInstance::eventattackedblocked()
|
||||
void MTGCardInstance::eventattackedblocked(MTGCardInstance * opponent)
|
||||
{
|
||||
didattacked = 1;
|
||||
WEvent * e = NEW WEventCardAttackedBlocked(this);
|
||||
WEvent * e = NEW WEventCardAttackedBlocked(this,opponent);
|
||||
GameObserver * game = GameObserver::GetInstance();
|
||||
game->receiveEvent(e);
|
||||
}
|
||||
|
||||
//sets card as blocking and sends events
|
||||
void MTGCardInstance::eventblocked()
|
||||
void MTGCardInstance::eventblocked(MTGCardInstance * opponent)
|
||||
{
|
||||
didblocked = 1;
|
||||
WEvent * e = NEW WEventCardBlocked(this);
|
||||
WEvent * e = NEW WEventCardBlocked(this,opponent);
|
||||
GameObserver * game = GameObserver::GetInstance();
|
||||
game->receiveEvent(e);
|
||||
}
|
||||
@@ -439,10 +439,13 @@ int MTGCardInstance::triggerRegenerate()
|
||||
return 0;
|
||||
regenerateTokens--;
|
||||
tap();
|
||||
life = toughness;
|
||||
initAttackersDefensers();
|
||||
if (life < 1)
|
||||
return 0; //regeneration didn't work (wither ?)
|
||||
if(isCreature())
|
||||
{
|
||||
life = toughness;
|
||||
initAttackersDefensers();
|
||||
if (life < 1)
|
||||
return 0; //regeneration didn't work (wither ?)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -452,7 +455,7 @@ int MTGCardInstance::initAttackersDefensers()
|
||||
setDefenser(NULL);
|
||||
banding = NULL;
|
||||
blockers.clear();
|
||||
blocked = false;
|
||||
blocked = 0;
|
||||
didattacked = 0;
|
||||
didblocked = 0;
|
||||
return 1;
|
||||
@@ -1049,8 +1052,11 @@ JSample * MTGCardInstance::getSample()
|
||||
}
|
||||
}
|
||||
|
||||
string type = Subtypes::subtypesList->find(types[0]);
|
||||
type = type + ".wav";
|
||||
string type = "";
|
||||
if(!types.size())
|
||||
return NULL;
|
||||
type = Subtypes::subtypesList->find(types[0]);
|
||||
type.append(".wav");
|
||||
js = WResourceManager::Instance()->RetrieveSample(type);
|
||||
if (js)
|
||||
{
|
||||
|
||||
@@ -141,7 +141,6 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
|
||||
{
|
||||
string value = val;
|
||||
primitive->setOtherRestrictions(value);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -150,6 +149,12 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
|
||||
string value = val;
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
cost->alternative = ManaCost::parseManaCost(value);
|
||||
size_t name = value.find("name(");
|
||||
if(name != string::npos)
|
||||
{
|
||||
size_t endName = value.find(")",name);
|
||||
cost->alternative->alternativeName = value.substr(name + 5,endName - name - 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -222,55 +227,8 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
|
||||
{
|
||||
if (!primitive) primitive = NEW CardPrimitive();
|
||||
string value = val;
|
||||
primitive->setRestrictions(CardPrimitive::NO_RESTRICTION);
|
||||
primitive->hasRestriction = false;
|
||||
if (value.find("control two or more vampires") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::VAMPIRES);
|
||||
if (value.find("control less creatures") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::LESS_CREATURES);
|
||||
if (value.find("control snow land") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::SNOW_LAND_INPLAY);
|
||||
if (value.find("casted a spell") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::CASTED_A_SPELL);
|
||||
if (value.find("one of a kind") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::ONE_OF_AKIND);
|
||||
if (value.find("fourth turn") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::FOURTHTURN);
|
||||
if (value.find("before battle damage") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::BEFORECOMBATDAMAGE);
|
||||
if (value.find("after battle") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::AFTERCOMBAT);
|
||||
if (value.find("during battle") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::DURINGCOMBAT);
|
||||
if (value.find("myturnonly") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::PLAYER_TURN_ONLY);
|
||||
if (value.find("opponentturnonly") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::OPPONENT_TURN_ONLY);
|
||||
if (value.find("assorcery") != string::npos)
|
||||
primitive->setRestrictions(CardPrimitive::AS_SORCERY);
|
||||
string types[] = { "my", "opponent", "" };
|
||||
int starts[] = { CardPrimitive::MY_BEFORE_BEGIN, CardPrimitive::OPPONENT_BEFORE_BEGIN, CardPrimitive::BEFORE_BEGIN };
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
size_t found = value.find(types[j]);
|
||||
if (found != string::npos)
|
||||
{
|
||||
for (int i = 0; i < Constants::NB_MTG_PHASES; i++)
|
||||
{
|
||||
string toFind = types[j];
|
||||
toFind.append(Constants::MTGPhaseCodeNames[i]).append("only");
|
||||
found = value.find(toFind);
|
||||
if (found != string::npos)
|
||||
{
|
||||
if(primitive->hasRestriction == false)
|
||||
{
|
||||
primitive->setRestrictions(starts[j] + i);
|
||||
primitive->hasRestriction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
primitive->setRestrictions(value);
|
||||
primitive->hasRestriction = true;
|
||||
}
|
||||
else if ('e' == key[1] && 't' == key[2])
|
||||
{ //retrace
|
||||
|
||||
@@ -5,7 +5,284 @@
|
||||
#include "Translate.h"
|
||||
#include "Subtypes.h"
|
||||
#include "GameOptions.h"
|
||||
#include "Credits.h"
|
||||
|
||||
MTGEventBonus::MTGEventBonus(int _id) :
|
||||
MTGAbility(_id,NULL)
|
||||
{
|
||||
textAlpha = 0;
|
||||
text = "";
|
||||
for(int i = 0;i < 2;i++)
|
||||
{
|
||||
chain[i] = 0;
|
||||
highestChain[i] = 0;
|
||||
//-----------
|
||||
army[i] = 0;
|
||||
army1[i] = false;
|
||||
army2[i] = false;
|
||||
army3[i] = false;
|
||||
//--------
|
||||
|
||||
toybonusgranted[i] = false;
|
||||
toys[i] = 0;
|
||||
beastbonusgranted[i] = false;
|
||||
beast[i] = 0;
|
||||
zombiebonusgranted[i] = false;
|
||||
zombie[i] = 0;
|
||||
knightbonusgranted[i] = false;
|
||||
knight[i] = 0;
|
||||
insectbonusgranted[i] = false;
|
||||
insect[i] = 0;
|
||||
elementalbonusgranted[i] = false;
|
||||
elemental[i] = 0;
|
||||
vampirebonusgranted[i] = false;
|
||||
vampire[i] = 0;
|
||||
clericbonusgranted[i] = false;
|
||||
cleric[i] = 0;
|
||||
elfbonusgranted[i] = false;
|
||||
elf[i] = 0;
|
||||
Angelbonusgranted[i] = false;
|
||||
Angel[i] = 0;
|
||||
dragonbonusgranted[i] = false;
|
||||
dragon[i] = 0;
|
||||
|
||||
}
|
||||
}
|
||||
int MTGEventBonus::receiveEvent(WEvent * event)
|
||||
{
|
||||
Player * player = game->currentlyActing();
|
||||
Player * currentPlayer = game->currentPlayer;
|
||||
//bonus for chain chain casting without tapping for mana or being interupted;
|
||||
//note gaining mana from other sources is still possible.
|
||||
//only spells going to the stack are counted.
|
||||
if (WEventCardTappedForMana* e = dynamic_cast<WEventCardTappedForMana*>(event))
|
||||
{
|
||||
if(e)
|
||||
{
|
||||
if(chain[currentPlayer->getId()]/5 > 0)
|
||||
{
|
||||
text = "Chain Broken!";
|
||||
textAlpha = 255;
|
||||
}
|
||||
chain[currentPlayer->getId()] = 0;
|
||||
}
|
||||
}
|
||||
if (event->type == WEvent::CHANGE_ZONE && !currentPlayer->isAI())
|
||||
{
|
||||
WEventZoneChange * e = (WEventZoneChange *) event;
|
||||
if (e->to == currentPlayer->game->stack)
|
||||
{
|
||||
chain[currentPlayer->getId()]++;
|
||||
if(chain[currentPlayer->getId()] > highestChain[currentPlayer->getId()])
|
||||
highestChain[currentPlayer->getId()] = chain[currentPlayer->getId()];
|
||||
if(chain[currentPlayer->getId()] > 4)
|
||||
{
|
||||
|
||||
if(highestChain[currentPlayer->getId()] > 14)
|
||||
{
|
||||
char buffer3[20];
|
||||
sprintf(buffer3,"Killer!-Combo %i",chain[currentPlayer->getId()]);
|
||||
grantAward(buffer3,100);
|
||||
//increase the chains bonus by 100 for every card after playing a chain of 15 in a match.
|
||||
//this is almost impossible would require superior draw and mana production.
|
||||
}
|
||||
else if(highestChain[currentPlayer->getId()] > 9)
|
||||
{
|
||||
char buffer2[30];
|
||||
sprintf(buffer2,"Abundant Resources-Combo %i",chain[currentPlayer->getId()]);
|
||||
grantAward(buffer2,50);
|
||||
//increase the chains bonus by 50 for every card after playing a chain of 10 in a match.
|
||||
//this is extremely hard to do. would require a very well built deck an an abundence of mana
|
||||
//to spend in a single go combined with decent card drawing.
|
||||
}
|
||||
else if(highestChain[currentPlayer->getId()] > 4)
|
||||
{
|
||||
char buffer[20];
|
||||
sprintf(buffer,"Chained-Combo %i",chain[currentPlayer->getId()]);
|
||||
grantAward(buffer,chain[currentPlayer->getId()]);
|
||||
//gain credits for every card played after you played a chain of 5
|
||||
//during the match. this would require a very decent hand to do
|
||||
//and good mana production.
|
||||
}
|
||||
}
|
||||
}
|
||||
//end of chain bonuses
|
||||
//==========================
|
||||
//creatures entering play consecutively will allow you a chance
|
||||
//to gain a bonus for maintaining force sizes, it will trigger every 10th
|
||||
//creature which enters play consecutively.
|
||||
if (e->to == currentPlayer->game->inPlay && !currentPlayer->isAI())
|
||||
{
|
||||
if(e->card->hasType(Subtypes::TYPE_CREATURE))
|
||||
army[currentPlayer->getId()]++;
|
||||
else
|
||||
army[currentPlayer->getId()] = 0;
|
||||
if(army[currentPlayer->getId()] > 9)
|
||||
{
|
||||
//this might seem easy at first glance, but you have to both maintain a high
|
||||
//creature count, and triggers when 10 or more enter consecutively. if any thing else
|
||||
//enters play the count is reset.
|
||||
army[currentPlayer->getId()] = 0;
|
||||
int forceSize = currentPlayer->inPlay()->countByType("creature");
|
||||
if(forceSize > 40 && !army3[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Malignant Conqueror Bonus!",1000);
|
||||
army3[currentPlayer->getId()] = true;
|
||||
}
|
||||
else if(forceSize > 19 && !army2[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Extreme Infantry Bonus!",500);
|
||||
army2[currentPlayer->getId()] = true;
|
||||
}
|
||||
else if(forceSize > 9 && !army1[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Deadly Force Bonus!",250);
|
||||
army1[currentPlayer->getId()] = true;
|
||||
}
|
||||
}
|
||||
//////bonus for having a LOT of specific type.
|
||||
//not else'd becuase it is possible for a card to contain
|
||||
//more then one of the types, and for more then one to trigger.
|
||||
if(e->card->hasType(Subtypes::TYPE_ARTIFACT))
|
||||
toys[currentPlayer->getId()]++;
|
||||
if(e->card->isCreature())
|
||||
{
|
||||
if(e->card->hasType("beast"))
|
||||
beast[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("vampire"))
|
||||
vampire[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("insect"))
|
||||
insect[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("elemental"))
|
||||
elemental[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("zombie"))
|
||||
zombie[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("soldier")||e->card->hasType("knight")||e->card->hasType("warrior"))
|
||||
knight[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("cleric")||e->card->hasType("shaman")||e->card->hasType("druid"))
|
||||
cleric[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("elf"))
|
||||
elf[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("angel")||e->card->hasType("spirit"))
|
||||
Angel[currentPlayer->getId()]++;
|
||||
if(e->card->hasType("dragon")||e->card->hasType("wurm")||e->card->hasType("drake")||e->card->hasType("snake")||e->card->hasType("hydra"))
|
||||
dragon[currentPlayer->getId()]++;
|
||||
}
|
||||
if(toys[currentPlayer->getId()] > 30 && !toybonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Toy Collector!",300);
|
||||
toybonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(beast[currentPlayer->getId()] > 30 && !beastbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Beast Tamer!",300);
|
||||
beastbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(vampire[currentPlayer->getId()] > 30 && !vampirebonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Vampire King!",300);
|
||||
vampirebonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(insect[currentPlayer->getId()] > 30 && !insectbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Lord of Swarms!",300);
|
||||
insectbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(elemental[currentPlayer->getId()] > 30 && !elementalbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Master of Elements!",300);
|
||||
elementalbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(zombie[currentPlayer->getId()] > 30 && !zombiebonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Zombie Apocalypse!",300);
|
||||
zombiebonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(knight[currentPlayer->getId()] > 30 && !knightbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Sword And Shield!",300);
|
||||
knightbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(cleric[currentPlayer->getId()] > 30 && !clericbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Medic!",300);
|
||||
clericbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
|
||||
if(elf[currentPlayer->getId()] > 30 && !elfbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("The Promenade!",300);
|
||||
elfbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(Angel[currentPlayer->getId()] > 30 && !Angelbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Heavenly Host!",300);
|
||||
Angelbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
if(dragon[currentPlayer->getId()] > 30 && !dragonbonusgranted[currentPlayer->getId()])
|
||||
{
|
||||
grantAward("Teeth And Scales!",300);
|
||||
dragonbonusgranted[currentPlayer->getId()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//bonus for dealing 100+ damage from a single source
|
||||
WEventDamage * damageEvent = dynamic_cast<WEventDamage *> (event);
|
||||
if(damageEvent && !currentPlayer->isAI())
|
||||
{
|
||||
MTGCardInstance * damageSource = (MTGCardInstance*)damageEvent->getTarget(damageEvent->TARGET_FROM);
|
||||
if(damageSource && damageSource->controller() == currentPlayer && damageEvent->damage->damage > 99)
|
||||
grantAward("Overkill!",500);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MTGEventBonus::grantAward(string awardName,int amount)
|
||||
{
|
||||
JSample * sample = WResourceManager::Instance()->RetrieveSample("bonus.wav");
|
||||
if (sample)
|
||||
{
|
||||
JSoundSystem::GetInstance()->PlaySample(sample);
|
||||
}
|
||||
text = awardName;
|
||||
textAlpha = 255;
|
||||
Credits::addCreditBonus(amount);
|
||||
}
|
||||
|
||||
int MTGEventBonus::testDestroy()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MTGEventBonus::Update(float dt)
|
||||
{
|
||||
if (textAlpha)
|
||||
{
|
||||
textAlpha -= static_cast<int> (200 * dt);
|
||||
if (textAlpha < 0)
|
||||
textAlpha = 0;
|
||||
}
|
||||
MTGAbility::Update(dt);
|
||||
}
|
||||
|
||||
void MTGEventBonus::Render()
|
||||
{
|
||||
if (!textAlpha)
|
||||
return;
|
||||
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::OPTION_FONT/*MENU_FONT*/);
|
||||
mFont->SetScale(2 - (float) textAlpha / 130);
|
||||
mFont->SetColor(ARGB(255,255,255,255));
|
||||
mFont->DrawString(text.c_str(), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, JGETEXT_CENTER);
|
||||
}
|
||||
|
||||
MTGEventBonus * MTGEventBonus::clone() const
|
||||
{
|
||||
MTGEventBonus * a = NEW MTGEventBonus(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//
|
||||
MTGPutInPlayRule::MTGPutInPlayRule(int _id) :
|
||||
MTGAbility(_id, NULL)
|
||||
{
|
||||
@@ -64,8 +341,6 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
#ifdef WIN32
|
||||
cost->Dump();
|
||||
#endif
|
||||
if(!cost->getConvertedCost() && card->getManaCost()->suspend)
|
||||
return 0;
|
||||
//cost of card.
|
||||
if (playerMana->canAfford(cost))
|
||||
{
|
||||
@@ -218,11 +493,11 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *
|
||||
|
||||
if (!alternateManaCost)
|
||||
return 0;
|
||||
|
||||
if(!allowedToCast(card,player))
|
||||
return 0;
|
||||
if(!allowedToAltCast(card,player))
|
||||
return 0;
|
||||
card->getManaCost()->alternativeName;
|
||||
if(card->model->data->getManaCost()->alternative && card->model->data->getManaCost()->alternative->alternativeName.size())
|
||||
alternativeName = card->model->data->getManaCost()->alternative->alternativeName;
|
||||
|
||||
if (card->isLand())
|
||||
{
|
||||
@@ -368,10 +643,10 @@ MTGAlternativeCostRule(_id)
|
||||
int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
{
|
||||
Player * player = game->currentlyActing();
|
||||
if(!allowedToCast(card,player))
|
||||
return 0;
|
||||
if (!player->game->hand->hasCard(card))
|
||||
return 0;
|
||||
if(!allowedToCast(card,player))
|
||||
return 0;
|
||||
return MTGAlternativeCostRule::isReactingToClick( card, mana, card->getManaCost()->BuyBack );
|
||||
}
|
||||
|
||||
@@ -637,8 +912,6 @@ int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
return 0;
|
||||
if (!card->getManaCost()->morph)
|
||||
return 0;
|
||||
if(!allowedToCast(card,player))
|
||||
return 0;
|
||||
if(!allowedToAltCast(card,player))
|
||||
return 0;
|
||||
//note lands can morph too, this is different from other cost types.
|
||||
@@ -919,6 +1192,15 @@ int MTGCombatTriggersRule::receiveEvent(WEvent *e)
|
||||
}
|
||||
if (dynamic_cast<WEventBlockersChosen*>(e))
|
||||
{
|
||||
MTGGameZone* opponentZone = game->currentPlayer->opponent()->game->inPlay;
|
||||
for (int i = 0; i < opponentZone->nb_cards; i++)
|
||||
{
|
||||
MTGCardInstance* card = opponentZone->cards[i];
|
||||
if (card && card->didblocked)
|
||||
{
|
||||
card->eventblocked(card->getNextOpponent());
|
||||
}
|
||||
}
|
||||
Player * p = game->currentPlayer;
|
||||
MTGGameZone * z = p->game->inPlay;
|
||||
for (int i = 0; i < z->nb_cards; i++)
|
||||
@@ -927,21 +1209,18 @@ int MTGCombatTriggersRule::receiveEvent(WEvent *e)
|
||||
if (card && card->isAttacker() && !card->blocked)
|
||||
{
|
||||
card->eventattackednotblocked();
|
||||
card->notblocked += 1;
|
||||
card->notblocked = 1;
|
||||
}
|
||||
if (card && card->isAttacker() && card->blocked)
|
||||
{
|
||||
card->eventattackedblocked();
|
||||
}
|
||||
}
|
||||
|
||||
MTGGameZone* opponentZone = game->currentPlayer->opponent()->game->inPlay;
|
||||
for (int i = 0; i < opponentZone->nb_cards; i++)
|
||||
{
|
||||
MTGCardInstance* card = opponentZone->cards[i];
|
||||
if (card && card->didblocked > 0)
|
||||
{
|
||||
card->eventblocked();
|
||||
MTGCardInstance * opponent = card->getNextOpponent();
|
||||
while (opponent)
|
||||
{
|
||||
card->eventattackedblocked(opponent);
|
||||
opponent = card->getNextOpponent(opponent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,15 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
|
||||
tc = tcf.createTargetChooser("creature|myBattlefield", c);
|
||||
manaCost->addExtraCost(NEW Ninja(tc));
|
||||
break;
|
||||
case 'p' :
|
||||
{
|
||||
SAFE_DELETE(tc);
|
||||
size_t start = value.find("(");
|
||||
size_t end = value.rfind(")");
|
||||
string manaType = value.substr(start + 1, end - start - 1);
|
||||
manaCost->addExtraCost(NEW LifeorManaCost(NULL,manaType));
|
||||
break;
|
||||
}
|
||||
case 'c': //Counters
|
||||
{
|
||||
size_t counter_start = value.find("(");
|
||||
|
||||
@@ -486,7 +486,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
size_t start = attribute.find("share!");
|
||||
size_t end = attribute.rfind("!");
|
||||
string CDtype = attribute.substr(start + 6,end - start);
|
||||
if(card->isSpell() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION)
|
||||
if( card && card->isSpell() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION)
|
||||
{
|
||||
//spells always store their targets in :targets[]
|
||||
//however they are all erased as the spell resolves
|
||||
@@ -518,7 +518,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
}
|
||||
else if( CDtype.find("types") != string::npos )
|
||||
{
|
||||
if(card->target)
|
||||
if(card && card->target)
|
||||
{
|
||||
cd->types = card->target->types;
|
||||
//remove main types because we only care about subtypes here.
|
||||
@@ -1138,6 +1138,14 @@ bool TargetZoneChooser::targetsZone(MTGGameZone * z)
|
||||
if (MTGGameZone::intToZone(zones[i], source) == z) return true;
|
||||
return false;
|
||||
}
|
||||
bool TargetZoneChooser::targetsZone(MTGGameZone * z,MTGCardInstance * mSource)
|
||||
{
|
||||
if(mSource)
|
||||
source = mSource;
|
||||
for (int i = 0; i < nbzones; i++)
|
||||
if (MTGGameZone::intToZone(zones[i], source) == z) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TargetZoneChooser * TargetZoneChooser::clone() const
|
||||
{
|
||||
|
||||
@@ -67,13 +67,13 @@ WEventCardAttackedNotBlocked::WEventCardAttackedNotBlocked(MTGCardInstance * car
|
||||
{
|
||||
}
|
||||
|
||||
WEventCardAttackedBlocked::WEventCardAttackedBlocked(MTGCardInstance * card) :
|
||||
WEventCardUpdate(card)
|
||||
WEventCardAttackedBlocked::WEventCardAttackedBlocked(MTGCardInstance * card,MTGCardInstance * opponent) :
|
||||
WEventCardUpdate(card),opponent(opponent)
|
||||
{
|
||||
}
|
||||
|
||||
WEventCardBlocked::WEventCardBlocked(MTGCardInstance * card) :
|
||||
WEventCardUpdate(card)
|
||||
WEventCardBlocked::WEventCardBlocked(MTGCardInstance * card,MTGCardInstance * opponent) :
|
||||
WEventCardUpdate(card),opponent(opponent)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ Targetable * WEventCardAttackedBlocked::getTarget(int target)
|
||||
case TARGET_TO:
|
||||
return card;
|
||||
case TARGET_FROM:
|
||||
return card->getNextOpponent();
|
||||
return opponent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -247,7 +247,7 @@ Targetable * WEventCardBlocked::getTarget(int target)
|
||||
case TARGET_TO:
|
||||
return card;
|
||||
case TARGET_FROM:
|
||||
return card->getNextOpponent();
|
||||
return opponent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user