ok this is the last commit but i had massive issues after chopping it all up, hopefully it doesn't hilight everything that was already commited...if it does i apologize my own patch started giving me conflicts....
im like 7 tries into commiting this part....
This commit is contained in:
@@ -1004,9 +1004,10 @@ class IfThenAbility: public InstantAbility
|
||||
{
|
||||
public:
|
||||
MTGAbility * delayedAbility;
|
||||
MTGAbility * delayedElseAbility;
|
||||
int type;
|
||||
string Cond;
|
||||
IfThenAbility(GameObserver* observer, int _id,MTGAbility * delayedAbility = NULL, MTGCardInstance * _source=NULL, Targetable * target = NULL, int type = 1,string Cond = "");
|
||||
IfThenAbility(GameObserver* observer, int _id,MTGAbility * delayedAbility = NULL,MTGAbility * delayedElseAbility = NULL, MTGCardInstance * _source=NULL, Targetable * target = NULL, int type = 1,string Cond = "");
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
IfThenAbility * clone() const;
|
||||
@@ -1110,6 +1111,16 @@ public:
|
||||
|
||||
};
|
||||
|
||||
//place a card on the bottom of owners library
|
||||
class AALibraryBottom: public ActivatedAbility
|
||||
{
|
||||
public:
|
||||
AALibraryBottom(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target = NULL, ManaCost * _cost = NULL);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
AALibraryBottom * clone() const;
|
||||
};
|
||||
|
||||
//Copier. ActivatedAbility
|
||||
class AACopier: public ActivatedAbility
|
||||
{
|
||||
@@ -2659,6 +2670,11 @@ public:
|
||||
if(sabilities.find("battleready") != string::npos)
|
||||
battleReady = true;
|
||||
|
||||
if(sabilities.find("chosencolor") != string::npos)
|
||||
{
|
||||
colors.push_back(source->chooseacolor);
|
||||
}
|
||||
|
||||
for (int j = 0; j < Constants::NB_Colors; j++)
|
||||
{
|
||||
size_t found = sabilities.find(Constants::MTGColorStrings[j]);
|
||||
@@ -2674,12 +2690,21 @@ public:
|
||||
size_t found = s.find(" ");
|
||||
if (found != string::npos)
|
||||
{
|
||||
int id = MTGAllCards::findType(s.substr(0, found));
|
||||
string toCheck = s.substr(0, found);
|
||||
if(toCheck.find("chosentype") != string::npos || toCheck.find("Chosentype") != string::npos)
|
||||
{
|
||||
toCheck = source->chooseasubtype;
|
||||
}
|
||||
int id = MTGAllCards::findType(toCheck);
|
||||
types.push_back(id);
|
||||
s = s.substr(found + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(s.find("chosentype") != string::npos || s.find("Chosentype") != string::npos)
|
||||
{
|
||||
s = source->chooseasubtype;
|
||||
}
|
||||
int id = MTGAllCards::findType(s);
|
||||
types.push_back(id);
|
||||
s = "";
|
||||
@@ -3406,6 +3431,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class AAExchangeLife: public ActivatedAbilityTP
|
||||
{
|
||||
public:
|
||||
AAExchangeLife(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, ManaCost * _cost = NULL,
|
||||
int who = TargetChooser::UNSET);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
AAExchangeLife * clone() const;
|
||||
|
||||
};
|
||||
|
||||
// Add life of gives damage if a given zone has more or less than [condition] cards at the beginning of [phase]
|
||||
//Ex : the rack, ivory tower...
|
||||
class ALifeZoneLink: public MTGAbility
|
||||
@@ -4951,9 +4987,6 @@ public:
|
||||
return NEW APhaseAlter(*this);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------Addon Abra------------------
|
||||
|
||||
//Basilik --> needs to be made more generic to avoid duplicate (also something like if opponent=type then ...)
|
||||
class ABasilik: public MTGAbility
|
||||
{
|
||||
@@ -5015,6 +5048,19 @@ public:
|
||||
AADepleter * clone() const;
|
||||
};
|
||||
|
||||
//Generic skip turn/extra turn
|
||||
class AAModTurn: public ActivatedAbilityTP
|
||||
{
|
||||
public:
|
||||
string nbTurnStr;
|
||||
|
||||
AAModTurn(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbTurnStr, ManaCost * _cost = NULL,
|
||||
int who = TargetChooser::UNSET);
|
||||
int resolve();
|
||||
const char * getMenuText();
|
||||
AAModTurn * clone() const;
|
||||
};
|
||||
|
||||
//Shuffle
|
||||
class AAShuffle: public ActivatedAbilityTP
|
||||
{
|
||||
@@ -5283,6 +5329,15 @@ public:
|
||||
int resolve()
|
||||
{
|
||||
MTGCardInstance * _theftTarget = (MTGCardInstance*)target;
|
||||
bool recast = false;
|
||||
if(!_theftTarget->isInPlay(game))
|
||||
{
|
||||
recast = true;
|
||||
}
|
||||
while(_theftTarget->next)
|
||||
{
|
||||
_theftTarget= _theftTarget->next;
|
||||
}
|
||||
if(_theftTarget)
|
||||
{
|
||||
TrueController = _theftTarget->controller();
|
||||
@@ -5291,7 +5346,13 @@ public:
|
||||
target = copy;
|
||||
source->target = copy;
|
||||
copy->summoningSickness = 0;
|
||||
if(recast)
|
||||
{
|
||||
Spell * spell = NEW Spell(game, copy);
|
||||
spell->resolve();
|
||||
SAFE_DELETE(spell);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5318,6 +5379,76 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------
|
||||
class AASetColorChosen: public InstantAbility
|
||||
{
|
||||
public:
|
||||
int color;
|
||||
string abilityToAlter;
|
||||
MTGAbility * abilityAltered;
|
||||
AASetColorChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, int _color = 0 ,string toAdd = "");
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
AASetColorChosen * clone() const;
|
||||
~AASetColorChosen();
|
||||
};
|
||||
class AASetTypeChosen: public InstantAbility
|
||||
{
|
||||
public:
|
||||
int type;
|
||||
string menutext;
|
||||
string abilityToAlter;
|
||||
MTGAbility * abilityAltered;
|
||||
AASetTypeChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, int _type = 0,string menu = "error" ,string toAdd = "");
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
AASetTypeChosen * clone() const;
|
||||
~AASetTypeChosen();
|
||||
};
|
||||
class GenericChooseTypeColor: public ActivatedAbility
|
||||
{
|
||||
public:
|
||||
string baseAbility;
|
||||
bool chooseColor;
|
||||
AASetColorChosen * setColor;
|
||||
AASetTypeChosen * setType;
|
||||
bool ANonWall;
|
||||
GenericChooseTypeColor(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, string toAdd = "",bool chooseColor = false,bool nonwall = false, ManaCost * cost = NULL);
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
GenericChooseTypeColor * clone() const;
|
||||
~GenericChooseTypeColor();
|
||||
|
||||
};
|
||||
//------------------------------------------------
|
||||
//flip a coin and call it, with win or lose abilities
|
||||
class AASetCoin: public InstantAbility
|
||||
{
|
||||
public:
|
||||
int side;
|
||||
string abilityToAlter;
|
||||
string abilityWin;
|
||||
string abilityLose;
|
||||
MTGAbility * abilityAltered;
|
||||
AASetCoin(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, int side = -1,string toAdd = "");
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
AASetCoin * clone() const;
|
||||
~AASetCoin();
|
||||
};
|
||||
class GenericFlipACoin: public ActivatedAbility
|
||||
{
|
||||
public:
|
||||
string baseAbility;
|
||||
bool chooseColor;
|
||||
AASetCoin * setCoin;
|
||||
GenericFlipACoin(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, string toAdd = "", ManaCost * cost = NULL);
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
GenericFlipACoin * clone() const;
|
||||
~GenericFlipACoin();
|
||||
|
||||
};
|
||||
// utility functions
|
||||
|
||||
void PopulateColorIndexVector(list<int>& colors, const string& colorsString, char delimiter = ',');
|
||||
|
||||
@@ -212,8 +212,12 @@ class Constants
|
||||
HYDRA = 92,
|
||||
UNDYING = 93,
|
||||
POISONSHROUD = 94,
|
||||
NOACTIVATED = 95,
|
||||
NOACTIVATEDTAP = 96,
|
||||
NOMANA = 97,
|
||||
ONLYMANA = 98,
|
||||
|
||||
NB_BASIC_ABILITIES = 95,
|
||||
NB_BASIC_ABILITIES = 99,
|
||||
|
||||
|
||||
RARITY_S = 'S', //Special Rarity
|
||||
|
||||
@@ -203,6 +203,33 @@ public:
|
||||
virtual MTGAttackRule * clone() const;
|
||||
};
|
||||
|
||||
|
||||
class MTGPlaneswalkerAttackRule: public PermanentAbility, public Limitor
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool select(Target*);
|
||||
virtual bool greyout(Target*);
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
int reactToClick(MTGCardInstance * card);
|
||||
MTGPlaneswalkerAttackRule(GameObserver* observer, int _id);
|
||||
const char * getMenuText()
|
||||
{
|
||||
return "Attack Planeswalker";
|
||||
}
|
||||
virtual MTGPlaneswalkerAttackRule * clone() const;
|
||||
};
|
||||
class AAPlaneswalkerAttacked: public InstantAbility
|
||||
{
|
||||
public:
|
||||
string menuText;
|
||||
MTGCardInstance* attacker;
|
||||
AAPlaneswalkerAttacked(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target);
|
||||
int resolve();
|
||||
const char* getMenuText();
|
||||
AAPlaneswalkerAttacked * clone() const;
|
||||
~AAPlaneswalkerAttacked();
|
||||
};
|
||||
/* handles combat trigger send recieve events*/
|
||||
class MTGCombatTriggersRule: public PermanentAbility
|
||||
{
|
||||
@@ -292,7 +319,16 @@ public:
|
||||
virtual ostream& toString(ostream& out) const;
|
||||
virtual MTGPlaneWalkerRule * clone() const;
|
||||
};
|
||||
/* LifeLink */
|
||||
class MTGPlaneswalkerDamage: public PermanentAbility
|
||||
{
|
||||
public:
|
||||
MTGPlaneswalkerDamage(GameObserver* observer, int _id);
|
||||
|
||||
int receiveEvent(WEvent * event);
|
||||
|
||||
virtual MTGPlaneswalkerDamage * clone() const;
|
||||
};
|
||||
class MTGMomirRule: public PermanentAbility
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -183,6 +183,7 @@ AADamager::AADamager(GameObserver* observer, int _id, MTGCardInstance * _source,
|
||||
ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), d(d)
|
||||
{
|
||||
aType = MTGAbility::DAMAGER;
|
||||
redirected = false;
|
||||
}
|
||||
|
||||
int AADamager::resolve()
|
||||
@@ -191,6 +192,33 @@ AADamager::AADamager(GameObserver* observer, int _id, MTGCardInstance * _source,
|
||||
if (_target)
|
||||
{
|
||||
WParsedInt damage(d, NULL, (MTGCardInstance *)source);
|
||||
if(_target == game->opponent() && game->opponent()->inPlay()->hasType("planeswalker") && !redirected)
|
||||
{
|
||||
vector<MTGAbility*>selection;
|
||||
MTGCardInstance * check = NULL;
|
||||
this->redirected = true;
|
||||
MTGAbility * setPlayer = this->clone();
|
||||
selection.push_back(setPlayer);
|
||||
int checkWalkers = ((Player*)_target)->game->battlefield->cards.size();
|
||||
for(int i = 0; i < checkWalkers;++i)
|
||||
{
|
||||
check = ((Player*)_target)->game->battlefield->cards[i];
|
||||
if(check->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
MTGAbility * setWalker = this->clone();
|
||||
setWalker->oneShot = true;
|
||||
setWalker->target = check;
|
||||
selection.push_back(setWalker);
|
||||
}
|
||||
}
|
||||
if(selection.size())
|
||||
{
|
||||
MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), source, source,true,selection);
|
||||
game->mLayers->actionLayer()->currentActionCard = source;
|
||||
a1->resolve();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
game->mLayers->stackLayer()->addDamage(source, _target, damage.getValue());
|
||||
game->mLayers->stackLayer()->resolve();
|
||||
return 1;
|
||||
@@ -206,6 +234,11 @@ AADamager::AADamager(GameObserver* observer, int _id, MTGCardInstance * _source,
|
||||
|
||||
const char * AADamager::getMenuText()
|
||||
{
|
||||
MTGCardInstance * _target = dynamic_cast<MTGCardInstance*>(target);
|
||||
if(_target && _target->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
return _target->name.c_str();
|
||||
if(redirected)
|
||||
return "Damage Player";
|
||||
return "Damage";
|
||||
}
|
||||
|
||||
@@ -248,6 +281,83 @@ AADepleter * AADepleter::clone() const
|
||||
return NEW AADepleter(*this);
|
||||
}
|
||||
|
||||
//take extra turns or skip turns, values in the negitive will make you skip.
|
||||
AAModTurn::AAModTurn(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbTurnStr, ManaCost * _cost, int who) :
|
||||
ActivatedAbilityTP(observer, _id, card, _target, _cost, who),nbTurnStr(nbTurnStr)
|
||||
{
|
||||
|
||||
}
|
||||
int AAModTurn::resolve()
|
||||
{
|
||||
Player * player = getPlayerFromTarget(getTarget());
|
||||
if (player)
|
||||
{
|
||||
WParsedInt numTurns(nbTurnStr, NULL, source);
|
||||
if(numTurns.getValue() > 0)
|
||||
{
|
||||
player->extraTurn += numTurns.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
player->skippingTurn += abs(numTurns.getValue());
|
||||
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char * AAModTurn::getMenuText()
|
||||
{
|
||||
WParsedInt numTurns(nbTurnStr, NULL, source);
|
||||
if(numTurns.getValue() > 0)
|
||||
return "Take Extra Turn(s)";
|
||||
else
|
||||
return "Skip A Turn(s)";
|
||||
}
|
||||
|
||||
AAModTurn * AAModTurn::clone() const
|
||||
{
|
||||
return NEW AAModTurn(*this);
|
||||
}
|
||||
|
||||
//move target to bottom of owners library
|
||||
AALibraryBottom::AALibraryBottom(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
|
||||
ActivatedAbility(observer, _id, _source, _cost, 0)
|
||||
{
|
||||
target = _target;
|
||||
}
|
||||
|
||||
int AALibraryBottom::resolve()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
if (_target = _target->owner->game->putInLibrary(_target))
|
||||
{
|
||||
MTGLibrary * library = _target->owner->game->library;
|
||||
vector<MTGCardInstance *>oldOrder = library->cards;
|
||||
vector<MTGCardInstance *>newOrder;
|
||||
newOrder.push_back(_target);
|
||||
for(unsigned int k = 0;k < oldOrder.size();++k)
|
||||
{
|
||||
MTGCardInstance * rearranged = oldOrder[k];
|
||||
if(rearranged != _target)
|
||||
newOrder.push_back(rearranged);
|
||||
}
|
||||
library->cards = newOrder;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * AALibraryBottom::getMenuText()
|
||||
{
|
||||
return "Bottom Of Library";
|
||||
}
|
||||
|
||||
AALibraryBottom * AALibraryBottom::clone() const
|
||||
{
|
||||
return NEW AALibraryBottom(*this);
|
||||
}
|
||||
|
||||
//AACopier
|
||||
AACopier::AACopier(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
|
||||
ActivatedAbility(observer, _id, _source, _cost, 0)
|
||||
@@ -670,8 +780,318 @@ AAProliferate * AAProliferate::clone() const
|
||||
AAProliferate::~AAProliferate()
|
||||
{
|
||||
}
|
||||
//
|
||||
//choosing a type or color
|
||||
GenericChooseTypeColor::GenericChooseTypeColor(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,string _toAdd,bool chooseColor,bool nonwall, ManaCost * cost) :
|
||||
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd),chooseColor(chooseColor),ANonWall(nonwall)
|
||||
{
|
||||
this->GetId();
|
||||
setColor = NULL;
|
||||
}
|
||||
int GenericChooseTypeColor::resolve()
|
||||
{
|
||||
if (!target)
|
||||
return 0;
|
||||
vector<MTGAbility*>selection;
|
||||
if(chooseColor)
|
||||
{
|
||||
for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i)
|
||||
{
|
||||
setColor = NEW AASetColorChosen(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i, baseAbility);
|
||||
MTGAbility * set = setColor->clone();
|
||||
set->oneShot = true;
|
||||
selection.push_back(set);
|
||||
SAFE_DELETE(setColor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<string> values = MTGAllCards::getCreatureValuesById();
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
string menu = values[i];
|
||||
if(!ANonWall || (menu != "wall" && menu != "Wall"))
|
||||
{
|
||||
setType = NEW AASetTypeChosen(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i,menu,baseAbility);
|
||||
MTGAbility * set = setType->clone();
|
||||
set->oneShot = true;
|
||||
selection.push_back(set);
|
||||
SAFE_DELETE(setType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(selection.size())
|
||||
{
|
||||
MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,true,selection);
|
||||
game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
|
||||
a1->resolve();
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
const char* GenericChooseTypeColor::getMenuText()
|
||||
{
|
||||
if(chooseColor)
|
||||
return "Choose a color";
|
||||
else
|
||||
return "Choose a type";
|
||||
}
|
||||
|
||||
GenericChooseTypeColor * GenericChooseTypeColor::clone() const
|
||||
{
|
||||
GenericChooseTypeColor * a = NEW GenericChooseTypeColor(*this);
|
||||
return a;
|
||||
}
|
||||
|
||||
GenericChooseTypeColor::~GenericChooseTypeColor()
|
||||
{
|
||||
}
|
||||
|
||||
//set color choosen
|
||||
AASetColorChosen::AASetColorChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _color , string toAlter):
|
||||
InstantAbility(observer, id, source),color(_color), abilityToAlter(toAlter)
|
||||
{
|
||||
this->target = _target;
|
||||
abilityAltered = NULL;
|
||||
}
|
||||
int AASetColorChosen::resolve()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *)target;
|
||||
_target->chooseacolor = color;
|
||||
|
||||
if(abilityToAlter.size())
|
||||
{
|
||||
AbilityFactory af(game);
|
||||
abilityAltered = af.parseMagicLine(abilityToAlter, 0, NULL, _target);
|
||||
if(!abilityAltered)
|
||||
return 0;
|
||||
abilityAltered->canBeInterrupted = false;
|
||||
if(abilityAltered->oneShot)
|
||||
{
|
||||
abilityAltered->resolve();
|
||||
SAFE_DELETE(abilityAltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityAltered->target = _target;
|
||||
MayAbility * dontAdd = dynamic_cast<MayAbility*>(abilityAltered);
|
||||
if (!dontAdd)
|
||||
{
|
||||
_target->cardsAbilities.push_back(abilityAltered);
|
||||
for(unsigned int j = 0;j < _target->cardsAbilities.size();++j)
|
||||
{
|
||||
if(_target->cardsAbilities[j] == this)
|
||||
_target->cardsAbilities.erase(_target->cardsAbilities.begin() + j);
|
||||
}
|
||||
}
|
||||
abilityAltered->addToGame();
|
||||
}
|
||||
_target->skipDamageTestOnce = true;//some cards rely on this ability updating before damage test are run. otherwise they die before toughnes bonus applies.
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* AASetColorChosen::getMenuText()
|
||||
{
|
||||
return Constants::MTGColorStrings[color];
|
||||
}
|
||||
|
||||
AASetColorChosen * AASetColorChosen::clone() const
|
||||
{
|
||||
return NEW AASetColorChosen(*this);
|
||||
}
|
||||
|
||||
AASetColorChosen::~AASetColorChosen()
|
||||
{
|
||||
}
|
||||
|
||||
//set type choosen
|
||||
AASetTypeChosen::AASetTypeChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _type ,string _menu,string toAlter):
|
||||
InstantAbility(observer, id, source),type(_type), abilityToAlter(toAlter), menutext(_menu)
|
||||
{
|
||||
this->target = _target;
|
||||
abilityAltered = NULL;
|
||||
}
|
||||
int AASetTypeChosen::resolve()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *)target;
|
||||
string typeChoosen = menutext;
|
||||
_target->chooseasubtype = typeChoosen;
|
||||
|
||||
if(abilityToAlter.size())
|
||||
{
|
||||
AbilityFactory af(game);
|
||||
abilityAltered = af.parseMagicLine(abilityToAlter, 0, NULL, _target);
|
||||
if(abilityAltered->oneShot)
|
||||
{
|
||||
abilityAltered->resolve();
|
||||
SAFE_DELETE(abilityAltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityAltered->target = _target;
|
||||
MayAbility * dontAdd = dynamic_cast<MayAbility*>(abilityAltered);
|
||||
if (!dontAdd)
|
||||
{
|
||||
_target->cardsAbilities.push_back(abilityAltered);
|
||||
for(unsigned int j = 0;j < _target->cardsAbilities.size();++j)
|
||||
{
|
||||
if(_target->cardsAbilities[j] == this)
|
||||
_target->cardsAbilities.erase(_target->cardsAbilities.begin() + j);
|
||||
}
|
||||
}
|
||||
|
||||
abilityAltered->addToGame();
|
||||
}
|
||||
_target->skipDamageTestOnce = true;//some cards rely on this ability updating before damage test are run. otherwise they die before toughnes bonus applies.
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* AASetTypeChosen::getMenuText()
|
||||
{
|
||||
return menutext.c_str();
|
||||
}
|
||||
|
||||
AASetTypeChosen * AASetTypeChosen::clone() const
|
||||
{
|
||||
return NEW AASetTypeChosen(*this);
|
||||
}
|
||||
|
||||
AASetTypeChosen::~AASetTypeChosen()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//choosing a type or color
|
||||
GenericFlipACoin::GenericFlipACoin(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,string _toAdd, ManaCost * cost) :
|
||||
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd),chooseColor(chooseColor)
|
||||
{
|
||||
this->GetId();
|
||||
setCoin = NULL;
|
||||
}
|
||||
|
||||
int GenericFlipACoin::resolve()
|
||||
{
|
||||
if (!target)
|
||||
return 0;
|
||||
vector<MTGAbility*>selection;
|
||||
for (int i = 0; i <2; ++i)
|
||||
{
|
||||
setCoin = NEW AASetCoin(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i, baseAbility);
|
||||
MTGAbility * set = setCoin->clone();
|
||||
set->oneShot = true;
|
||||
selection.push_back(set);
|
||||
SAFE_DELETE(setCoin);
|
||||
}
|
||||
|
||||
if(selection.size())
|
||||
{
|
||||
MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,false,selection);
|
||||
game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
|
||||
a1->resolve();
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
const char* GenericFlipACoin::getMenuText()
|
||||
{
|
||||
return "Flip A Coin";
|
||||
}
|
||||
|
||||
GenericFlipACoin * GenericFlipACoin::clone() const
|
||||
{
|
||||
GenericFlipACoin * a = NEW GenericFlipACoin(*this);
|
||||
return a;
|
||||
}
|
||||
|
||||
GenericFlipACoin::~GenericFlipACoin()
|
||||
{
|
||||
}
|
||||
|
||||
//set color choosen
|
||||
AASetCoin::AASetCoin(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _side , string toAlter):
|
||||
InstantAbility(observer, id, source),side(_side), abilityToAlter(toAlter)
|
||||
{
|
||||
this->target = _target;
|
||||
abilityAltered = NULL;
|
||||
}
|
||||
|
||||
int AASetCoin::resolve()
|
||||
{
|
||||
MTGCardInstance * _target = (MTGCardInstance *)target;
|
||||
_target->coinSide = side;
|
||||
|
||||
int flip = game->getRandomGenerator()->random() % 2;
|
||||
vector<string>Win = parseBetween(abilityToAlter,"winability "," winabilityend");
|
||||
if(Win.size())
|
||||
{
|
||||
abilityWin = Win[1];
|
||||
}
|
||||
vector<string>Lose = parseBetween(abilityToAlter,"loseability "," loseabilityend");
|
||||
if(Lose.size())
|
||||
{
|
||||
abilityLose = Lose[1];
|
||||
}
|
||||
|
||||
if(abilityWin.size() && flip == side)
|
||||
{
|
||||
AbilityFactory af(game);
|
||||
abilityAltered = af.parseMagicLine(abilityWin, 0, NULL, _target);
|
||||
abilityAltered->canBeInterrupted = false;
|
||||
if(abilityAltered->oneShot)
|
||||
{
|
||||
abilityAltered->resolve();
|
||||
SAFE_DELETE(abilityAltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityAltered->addToGame();
|
||||
}
|
||||
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Won The Flip");
|
||||
message->oneShot = true;
|
||||
message->addToGame();
|
||||
}
|
||||
else if(abilityLose.size() && flip != side)
|
||||
{
|
||||
AbilityFactory af(game);
|
||||
abilityAltered = af.parseMagicLine(abilityLose, 0, NULL, _target);
|
||||
abilityAltered->canBeInterrupted = false;
|
||||
if(abilityAltered->oneShot)
|
||||
{
|
||||
abilityAltered->resolve();
|
||||
SAFE_DELETE(abilityAltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
abilityAltered->addToGame();
|
||||
}
|
||||
MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Lost The Flip");
|
||||
message->oneShot = true;
|
||||
message->addToGame();
|
||||
}
|
||||
_target->skipDamageTestOnce = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* AASetCoin::getMenuText()
|
||||
{
|
||||
if(side == 1)
|
||||
return "Tails";
|
||||
return "Heads";
|
||||
}
|
||||
|
||||
AASetCoin * AASetCoin::clone() const
|
||||
{
|
||||
return NEW AASetCoin(*this);
|
||||
}
|
||||
|
||||
AASetCoin::~AASetCoin()
|
||||
{
|
||||
}
|
||||
|
||||
//Reset Damage on creatures
|
||||
AAResetDamage::AAResetDamage(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, ManaCost * cost):
|
||||
@@ -2548,8 +2968,8 @@ ANewAffinity * ANewAffinity::clone() const
|
||||
}
|
||||
|
||||
//IfThenEffect
|
||||
IfThenAbility::IfThenAbility(GameObserver* observer, int _id, MTGAbility * delayedAbility, MTGCardInstance * _source, Targetable * _target, int type,string Cond) :
|
||||
InstantAbility(observer, _id, _source),delayedAbility(delayedAbility), type(type),Cond(Cond)
|
||||
IfThenAbility::IfThenAbility(GameObserver* observer, int _id, MTGAbility * delayedAbility, MTGAbility * delayedElseAbility, MTGCardInstance * _source, Targetable * _target, int type,string Cond) :
|
||||
InstantAbility(observer, _id, _source),delayedAbility(delayedAbility),delayedElseAbility(delayedElseAbility), type(type),Cond(Cond)
|
||||
{
|
||||
target = _target;
|
||||
}
|
||||
@@ -2575,15 +2995,22 @@ int IfThenAbility::resolve()
|
||||
}
|
||||
|
||||
}
|
||||
MTGAbility * a1 = NULL;
|
||||
if((checkCond && type == 1)||(!checkCond && type == 2))
|
||||
{
|
||||
MTGAbility * a1 = delayedAbility->clone();
|
||||
if (!a1)
|
||||
return 0;
|
||||
|
||||
a1 = delayedAbility->clone();
|
||||
}
|
||||
else if(delayedElseAbility)
|
||||
{
|
||||
delayedElseAbility->clone();
|
||||
}
|
||||
if (!a1)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if(a1->target && !dynamic_cast<Player *>(a1->target))
|
||||
a1->target = aTarget;
|
||||
|
||||
|
||||
if(a1->oneShot)
|
||||
{
|
||||
a1->resolve();
|
||||
@@ -2820,6 +3247,9 @@ MenuAbility::~MenuAbility()
|
||||
{
|
||||
for(int i = 0;i < int(abilities.size());i++)
|
||||
{
|
||||
AASetColorChosen * chooseA = dynamic_cast<AASetColorChosen *>(abilities[i]);
|
||||
if(chooseA && chooseA->abilityAltered)
|
||||
SAFE_DELETE(chooseA->abilityAltered);
|
||||
SAFE_DELETE(abilities[i]);
|
||||
}
|
||||
}
|
||||
@@ -3128,6 +3558,10 @@ ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * sou
|
||||
|
||||
PopulateAbilityIndexVector(abilities, sabilities);
|
||||
PopulateColorIndexVector(colors, sabilities);
|
||||
if(sabilities.find("chosencolor") != string::npos)
|
||||
{
|
||||
colors.push_back(source->chooseacolor);
|
||||
}
|
||||
|
||||
//this subkeyword adds a color without removing the existing colors.
|
||||
addNewColors = (sabilities.find("newcolors") != string::npos);
|
||||
@@ -3148,6 +3582,10 @@ ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * sou
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stypes.find("chosentype") != string::npos)
|
||||
{
|
||||
stypes = source->chooseasubtype;
|
||||
}
|
||||
PopulateSubtypesIndexVector(types, stypes);
|
||||
}
|
||||
|
||||
@@ -3520,6 +3958,68 @@ ASwapPTUEOT::~ASwapPTUEOT()
|
||||
SAFE_DELETE(ability);
|
||||
}
|
||||
|
||||
//exhange life with targetchooser
|
||||
AAExchangeLife::AAExchangeLife(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, ManaCost * _cost,
|
||||
int who) :
|
||||
ActivatedAbilityTP(observer, _id, _source, _target, _cost, who)
|
||||
{
|
||||
}
|
||||
|
||||
int AAExchangeLife::resolve()
|
||||
{
|
||||
Damageable * _target = (Damageable *) getTarget();
|
||||
if (_target)
|
||||
{
|
||||
Player *player = source->controller();
|
||||
int oldlife = player->getLife();
|
||||
int targetOldLife = _target->getLife();
|
||||
int modifier = oldlife > targetOldLife? oldlife - targetOldLife:targetOldLife - oldlife;
|
||||
if (_target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE)
|
||||
{
|
||||
int increaser = 0;
|
||||
MTGCardInstance * card = ((MTGCardInstance*)_target);
|
||||
int toughMod = 0;
|
||||
targetOldLife <= card->origtoughness?toughMod = card->origtoughness - targetOldLife: toughMod = targetOldLife - card->origtoughness;
|
||||
if(oldlife > targetOldLife)
|
||||
{
|
||||
increaser = oldlife - targetOldLife;
|
||||
player->gainOrLoseLife(modifier * -1);
|
||||
card->addToToughness(increaser+toughMod);
|
||||
}
|
||||
else
|
||||
{
|
||||
_target->life = oldlife;
|
||||
card->toughness = oldlife;
|
||||
player->gainOrLoseLife(modifier);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
Player * opponent = (Player*)_target;
|
||||
if(oldlife > targetOldLife)
|
||||
{
|
||||
player->gainOrLoseLife(modifier * -1);
|
||||
opponent->gainOrLoseLife(modifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->gainOrLoseLife(modifier);
|
||||
opponent->gainOrLoseLife(modifier * -1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * AAExchangeLife::getMenuText()
|
||||
{
|
||||
return "Exchange life";
|
||||
}
|
||||
|
||||
AAExchangeLife * AAExchangeLife::clone() const
|
||||
{
|
||||
return NEW AAExchangeLife(*this);
|
||||
}
|
||||
|
||||
//ALoseAbilities
|
||||
ALoseAbilities::ALoseAbilities(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target) :
|
||||
|
||||
@@ -37,8 +37,6 @@ CardPrimitive::CardPrimitive()
|
||||
|
||||
CardPrimitive::CardPrimitive(CardPrimitive * source)
|
||||
{
|
||||
if(!source)
|
||||
return;
|
||||
if(!source)
|
||||
return;
|
||||
basicAbilities = source->basicAbilities;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "Player.h"
|
||||
#include "GameObserver.h"
|
||||
#include "MTGDeck.h"
|
||||
#include "ManaCostHybrid.h"
|
||||
#include "ManacostHybrid.h"
|
||||
|
||||
DeckStats * DeckStats::mInstance = NULL;
|
||||
|
||||
|
||||
@@ -455,18 +455,37 @@ void GuiCombat::Render()
|
||||
(*it)->Render(step);
|
||||
if (activeAtk)
|
||||
{
|
||||
float setH = 0;
|
||||
float setW = 0;
|
||||
signed damage = activeAtk->card->stepPower(step);
|
||||
for (vector<DefenserDamaged*>::iterator q = activeAtk->blockers.begin(); q != activeAtk->blockers.end(); ++q)
|
||||
{
|
||||
(*q)->Render(step);
|
||||
damage -= (*q)->sumDamages();
|
||||
setH = (*q)->Height;
|
||||
setW = (*q)->Width;
|
||||
}
|
||||
if (damage < 0)
|
||||
damage = 0;
|
||||
if (activeAtk->card->has(Constants::TRAMPLE))
|
||||
{
|
||||
observer->opponent()->getIcon()->SetHotSpot(18, 25);
|
||||
enemy_avatar.Render(observer->opponent()->getIcon().get());
|
||||
if(activeAtk->card->isAttacking && activeAtk->card->isAttacking != observer->opponent())
|
||||
{
|
||||
JQuadPtr enemy = WResourceManager::Instance()->RetrieveCard((MTGCardInstance*)activeAtk->card->isAttacking, CACHE_THUMB);
|
||||
float oldH = enemy->mHeight;
|
||||
float oldW = enemy->mWidth;
|
||||
enemy->mHeight = setH;
|
||||
enemy->mWidth = setW;
|
||||
enemy->SetHotSpot(18, 25);
|
||||
enemy_avatar.Render(enemy.get());
|
||||
enemy->mHeight = oldH;
|
||||
enemy->mWidth = oldW;
|
||||
}
|
||||
else
|
||||
{
|
||||
observer->opponent()->getIcon()->SetHotSpot(18, 25);
|
||||
enemy_avatar.Render(observer->opponent()->getIcon().get());
|
||||
}
|
||||
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
|
||||
mFont->SetColor(ARGB(255, 255, 64, 0));
|
||||
{
|
||||
@@ -474,6 +493,7 @@ void GuiCombat::Render()
|
||||
sprintf(buf, "%i", damage);
|
||||
mFont->DrawString(buf, enemy_avatar.actX - 25, enemy_avatar.actY - 40);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (ok_tex)
|
||||
@@ -506,7 +526,8 @@ int GuiCombat::resolve() // Returns the number of damage objects dealt this turn
|
||||
}
|
||||
|
||||
if (dmg > 0 && ((!attacker->isBlocked()) || attacker->has(Constants::TRAMPLE)))
|
||||
stack->Add(NEW Damage(observer, (*it)->card, observer->opponent(), dmg, DAMAGE_COMBAT));
|
||||
stack->Add(NEW Damage(observer, (*it)->card, (Damageable*)attacker->isAttacking?(Damageable*)attacker->isAttacking:observer->opponent(), dmg, DAMAGE_COMBAT));
|
||||
|
||||
for (vector<Damage>::iterator d = (*it)->damages.begin(); d != (*it)->damages.end(); ++d)
|
||||
stack->Add(NEW Damage(*d));
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void GuiPlay::Replace()
|
||||
for (iterator it = cards.begin(); it != end_spells; ++it)
|
||||
if (!(*it)->card->target)
|
||||
{
|
||||
if(!(*it)->card->hasSubtype(Subtypes::TYPE_AURA) && !(*it)->card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
if((!(*it)->card->hasSubtype(Subtypes::TYPE_AURA)|| ((*it)->card->hasSubtype(Subtypes::TYPE_AURA) && (*it)->card->playerTarget)) && !(*it)->card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
if (observer->players[0] == (*it)->card->controller())
|
||||
++selfSpellsN;
|
||||
@@ -226,7 +226,7 @@ void GuiPlay::Replace()
|
||||
for (iterator it = cards.begin(); it != end_spells; ++it)
|
||||
if (!(*it)->card->target)
|
||||
{
|
||||
if(!(*it)->card->hasSubtype(Subtypes::TYPE_AURA) && !(*it)->card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
if((!(*it)->card->hasSubtype(Subtypes::TYPE_AURA)|| ((*it)->card->hasSubtype(Subtypes::TYPE_AURA) && (*it)->card->playerTarget)) && !(*it)->card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
if (observer->players[0] == (*it)->card->controller())
|
||||
selfSpells.Enstack(*it);
|
||||
|
||||
@@ -423,58 +423,59 @@ Counter * AbilityFactory::parseCounter(string s, MTGCardInstance * target, Spell
|
||||
int nb = 1;
|
||||
int maxNb = 0;
|
||||
string name = "";
|
||||
size_t start = 0;
|
||||
size_t end = s.length();
|
||||
size_t separator = s.find(",", start);
|
||||
if (separator == string::npos)
|
||||
separator = s.find(".", start);
|
||||
if (separator != string::npos)
|
||||
{
|
||||
size_t separator2 = s.find(",", separator + 1);
|
||||
if (separator2 == string::npos)
|
||||
separator2 = s.find(".", separator + 1);
|
||||
size_t separator3 = string::npos;
|
||||
if (separator2 != string::npos)
|
||||
{
|
||||
name = s.substr(separator2 + 1, end - separator2 - 1);
|
||||
separator3 = s.find(",", separator2 + 1);
|
||||
if (separator3 != string::npos)
|
||||
{
|
||||
name = s.substr(separator2 + 1,separator3 - separator2 - 1);
|
||||
}
|
||||
}
|
||||
string nbstr = s.substr(separator + 1, separator2 - separator - 1);
|
||||
WParsedInt * wpi;
|
||||
if (target)
|
||||
{
|
||||
wpi = NEW WParsedInt(nbstr, spell, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
wpi = NEW WParsedInt(atoi(nbstr.c_str()));
|
||||
}
|
||||
nb = wpi->getValue();
|
||||
delete (wpi);
|
||||
string maxNbstr;
|
||||
if (separator3 != string::npos)
|
||||
{
|
||||
maxNbstr = s.substr(separator3 + 1, end - separator3 - 1);
|
||||
WParsedInt * wpinb;
|
||||
if (target)
|
||||
{
|
||||
wpinb = NEW WParsedInt(maxNbstr, spell, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
wpinb = NEW WParsedInt(atoi(maxNbstr.c_str()));
|
||||
}
|
||||
maxNb = wpinb->getValue();
|
||||
delete(wpinb);
|
||||
}
|
||||
end = separator;
|
||||
}
|
||||
string nbstr = "1";
|
||||
string maxNbstr = "0";
|
||||
string spt = "";
|
||||
|
||||
vector<string>splitCounter = split(s,',');
|
||||
vector<string>splitCounterCheck = split(s,'.');
|
||||
if(splitCounter.size() < splitCounterCheck.size())
|
||||
{
|
||||
splitCounter = splitCounterCheck;//use the one with the most results.
|
||||
}
|
||||
if(!splitCounter.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if(splitCounter.size() > 0)//counter(1/1)
|
||||
{
|
||||
spt = splitCounter[0];
|
||||
}
|
||||
if(splitCounter.size() > 1)//counter(1/1,1)
|
||||
{
|
||||
nbstr = splitCounter[1];
|
||||
}
|
||||
if(splitCounter.size() > 2)//counter(0/0,1,charge)
|
||||
{
|
||||
name = splitCounter[2];
|
||||
}
|
||||
if(splitCounter.size() > 3)//counter(0/0,1,charge,2)
|
||||
{
|
||||
maxNbstr = splitCounter[3];
|
||||
}
|
||||
WParsedInt * wpi;
|
||||
if (target)
|
||||
{
|
||||
wpi = NEW WParsedInt(nbstr, spell, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
wpi = NEW WParsedInt(atoi(nbstr.c_str()));
|
||||
}
|
||||
nb = wpi->getValue();
|
||||
delete (wpi);
|
||||
WParsedInt * wpinb;
|
||||
if (target)
|
||||
{
|
||||
wpinb = NEW WParsedInt(maxNbstr, spell, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
wpinb = NEW WParsedInt(atoi(maxNbstr.c_str()));
|
||||
}
|
||||
maxNb = wpinb->getValue();
|
||||
delete(wpinb);
|
||||
|
||||
string spt = s.substr(start, end - start);
|
||||
int power, toughness;
|
||||
if (parsePowerToughness(spt, &power, &toughness))
|
||||
{
|
||||
@@ -488,22 +489,19 @@ Counter * AbilityFactory::parseCounter(string s, MTGCardInstance * target, Spell
|
||||
|
||||
int AbilityFactory::parsePowerToughness(string s, int *power, int *toughness)
|
||||
{
|
||||
size_t found = s.find("/");
|
||||
if (found != string::npos)
|
||||
vector<string>splitPT = split(s,'/');
|
||||
vector<string>splitPTCheck = split(s,'%');
|
||||
if(splitPT.size() < 2 && splitPT.size() < splitPTCheck.size())
|
||||
{
|
||||
size_t end = s.find(" ", found);
|
||||
if (end == string::npos)
|
||||
end = s.size();
|
||||
size_t start = s.find_last_of(" ", found);
|
||||
if (start == string::npos)
|
||||
start = -1;
|
||||
|
||||
*power = atoi(s.substr(start + 1, s.size() - found).c_str());
|
||||
*toughness = atoi(s.substr(found + 1, end - found - 1).c_str());
|
||||
|
||||
return 1;
|
||||
splitPT = splitPTCheck;
|
||||
}
|
||||
return 0;
|
||||
if(!splitPT.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*power = atoi(splitPT[0].c_str());
|
||||
*toughness = atoi(splitPT[1].c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
TargetChooser * AbilityFactory::parseSimpleTC(const std::string& s, const std::string& _starter, MTGCardInstance * card, bool forceNoTarget)
|
||||
@@ -551,6 +549,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int
|
||||
bool opponentPoisoned = (s.find("opponentpoisoned") != string::npos);
|
||||
bool lifelost = (s.find("foelost(") != string::npos);
|
||||
int lifeamount = lifelost ? atoi(s.substr(s.find("foelost(") + 8,')').c_str()) : 0;
|
||||
bool neverRemove = (s.find("dontremove") != string::npos);
|
||||
|
||||
//Card Changed Zone
|
||||
found = s.find("movedto(");
|
||||
@@ -602,7 +601,13 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int
|
||||
fromTc = tcf.createTargetChooser(starget, card);
|
||||
fromTc->targetter = NULL; //avoid protection from
|
||||
}
|
||||
return NEW TrCardAddedToZone(observer, id, card, (TargetZoneChooser *) toTc, toTcCard, (TargetZoneChooser *) fromTc, fromTcCard,once,sourceUntapped,isSuspended);
|
||||
TriggeredAbility * mover = NEW TrCardAddedToZone(observer, id, card, (TargetZoneChooser *) toTc, toTcCard, (TargetZoneChooser *) fromTc, fromTcCard,once,sourceUntapped,isSuspended);
|
||||
if(neverRemove)
|
||||
{
|
||||
mover->forcedAlive = 1;
|
||||
mover->forceDestroy = -1;
|
||||
}
|
||||
return mover;
|
||||
}
|
||||
|
||||
//Card unTapped
|
||||
@@ -922,6 +927,19 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
observer->addObserver(NEW MTGPlaneWalkerRule(observer, -1));
|
||||
return NULL;
|
||||
}
|
||||
found = s.find("planeswalkerdamage");
|
||||
if(found != string::npos)
|
||||
{
|
||||
observer->addObserver(NEW MTGPlaneswalkerDamage(observer, -1));
|
||||
return NULL;
|
||||
}
|
||||
found = s.find("planeswalkerattack");
|
||||
if(found != string::npos)
|
||||
{
|
||||
observer->addObserver(NEW MTGPlaneswalkerAttackRule(observer, -1));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//this handles the clean up of tokens !!MUST BE ADDED BEFORE PERSIST RULE!!
|
||||
found = s.find("tokencleanuprule");
|
||||
if(found != string::npos)
|
||||
@@ -965,10 +983,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if(strncmp(s.c_str(), "chooseacolor ", strlen("chooseacolor ")) == 0 || strncmp(s.c_str(), "chooseatype ", strlen("chooseatype ")) == 0)
|
||||
{
|
||||
MTGAbility * choose = parseChooseActionAbility(s,card,spell,target,0,id);
|
||||
choose = NEW GenericActivatedAbility(observer, "","",id, card,choose,NULL);
|
||||
MayAbility * mainAbility = NEW MayAbility(observer, id, choose, card,true);
|
||||
return mainAbility;
|
||||
}
|
||||
|
||||
//need to remove the section inside the transforms ability from the string before parsing
|
||||
//TODO: store string values of "&&" so we can remove the classes added just to add support
|
||||
//the current parser finds other abilities inside what should be nested abilities, and converts them into
|
||||
//actual abilities, this is a limitation.
|
||||
string unchangedS = "";
|
||||
unchangedS.append(s);
|
||||
found = s.find("transforms((");
|
||||
if (found != string::npos && storedString.empty())
|
||||
{
|
||||
@@ -1040,7 +1069,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
|
||||
TargetChooser * tc = NULL;
|
||||
string sWithoutTc = s;
|
||||
|
||||
string tcString = "";
|
||||
//Target Abilities - We also handle the case "notatarget" here, for things such as copy effects
|
||||
bool isTarget = true;
|
||||
vector<string> splitTarget = parseBetween(s, "notatarget(", ")");
|
||||
@@ -1053,6 +1082,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
TargetChooserFactory tcf(observer);
|
||||
tc = tcf.createTargetChooser(splitTarget[1], card);
|
||||
tcString = splitTarget[1];
|
||||
|
||||
if (!isTarget)
|
||||
tc->targetter = NULL;
|
||||
sWithoutTc = splitTarget[0];
|
||||
@@ -1139,7 +1170,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
if (tc)
|
||||
{
|
||||
tc->belongsToAbility = sWithoutTc;
|
||||
return NEW GenericTargetAbility(observer, newName,castRestriction,id, card, tc, a, cost, limit,sideEffect,usesBeforeSideEffect, restrictions, dest);
|
||||
return NEW GenericTargetAbility(observer, newName,castRestriction,id, card, tc, a, cost, limit,sideEffect,usesBeforeSideEffect, restrictions, dest,tcString);
|
||||
}
|
||||
return NEW GenericActivatedAbility(observer, newName,castRestriction,id, card, a, cost, limit,sideEffect,usesBeforeSideEffect,restrictions, dest);
|
||||
}
|
||||
@@ -1171,10 +1202,20 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
if (sWithoutTc.find(ifKeywords[i]) == 0)
|
||||
{
|
||||
string cond = sWithoutTc.substr(ifKeywords[i].length(),ifKeywords[i].length() + sWithoutTc.find(" then ")-6);
|
||||
string s1 = s.substr(s.find(" then ")+6);
|
||||
size_t foundElse = s.find(" else ");
|
||||
MTGAbility * a2 = NULL;
|
||||
if(foundElse != string::npos)
|
||||
{
|
||||
string s2 = s.substr(foundElse+6);
|
||||
if(s2.size())
|
||||
s.erase(s.find(" else ")+1);
|
||||
a2 = parseMagicLine(s2, id, spell, card);
|
||||
}
|
||||
string s1 = s.substr(foundElse+6);
|
||||
MTGAbility * a1 = parseMagicLine(s1, id, spell, card);
|
||||
|
||||
if(!a1) return NULL;
|
||||
MTGAbility * a = NEW IfThenAbility(observer, id, a1, card,(Targetable*)target,checkIf[i],cond);
|
||||
MTGAbility * a = NEW IfThenAbility(observer, id, a1,a2, card,(Targetable*)target,checkIf[i],cond);
|
||||
a->canBeInterrupted = false;
|
||||
a->oneShot = true;
|
||||
if(tc)
|
||||
@@ -1182,7 +1223,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//When...comes into play, you may...
|
||||
//When...comes into play, choose one...
|
||||
const string mayKeywords[] = {"may ", "choice "};
|
||||
@@ -1218,7 +1259,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return mainAbility;
|
||||
}
|
||||
}
|
||||
|
||||
// Generic "Until end of turn" effect
|
||||
if (s.find("ueot ") == 0)
|
||||
{
|
||||
@@ -1230,6 +1270,31 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return NEW GenericInstantAbility(observer, 1, card, (Damageable *) target, a1);
|
||||
}
|
||||
|
||||
// neverending effect
|
||||
if (s.find("emblem ") == 0)
|
||||
{
|
||||
string s1 = s.substr(7);
|
||||
MTGAbility * a1 = parseMagicLine(s1, id, spell, card);
|
||||
if (!a1)
|
||||
return NULL;
|
||||
|
||||
return NEW GenericAbilityMod(observer, 1, card,spell?spell->getNextDamageableTarget():(Damageable *) target, a1);;
|
||||
}
|
||||
|
||||
//choose a color
|
||||
vector<string> splitChooseAColor = parseBetween(s, "activatechooseacolor ", " activatechooseend");
|
||||
if (splitChooseAColor.size())
|
||||
{
|
||||
return parseChooseActionAbility(unchangedS,card,spell,target,restrictions,id);
|
||||
}
|
||||
|
||||
//choose a type
|
||||
vector<string> splitChooseAType = parseBetween(s, "activatechooseatype ", " activatechooseend");
|
||||
if (splitChooseAType.size())
|
||||
{
|
||||
return parseChooseActionAbility(unchangedS,card,spell,target,restrictions,id);
|
||||
}
|
||||
|
||||
//Upkeep Cost
|
||||
found = s.find("upcostmulti");
|
||||
if (found != string::npos)
|
||||
@@ -1249,7 +1314,10 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
found = s.find("forcedalive");
|
||||
if (found != string::npos)
|
||||
forcedalive = 1;
|
||||
|
||||
bool neverRemove = false;
|
||||
found = s.find("dontremove");
|
||||
if (found != string::npos)
|
||||
neverRemove = true;
|
||||
//rather dirty way to stop thises and lords from conflicting with each other.
|
||||
size_t lord = string::npos;
|
||||
for (size_t j = 0; j < kLordKeywordsCount; ++j)
|
||||
@@ -1343,6 +1411,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
result->oneShot = oneShot;
|
||||
a->forcedAlive = forcedalive;
|
||||
if(neverRemove)
|
||||
{
|
||||
result->forceDestroy = -1;
|
||||
result->forcedAlive = 1;
|
||||
a->forceDestroy = -1;
|
||||
a->forcedAlive = 1;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1495,6 +1571,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
result->oneShot = oneShot;
|
||||
a->forcedAlive = forcedalive;
|
||||
if(neverRemove)
|
||||
{
|
||||
result->oneShot = false;
|
||||
result->forceDestroy = -1;
|
||||
result->forcedAlive = 1;
|
||||
a->forceDestroy = -1;
|
||||
a->forcedAlive = 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1585,6 +1669,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
return parsePhaseActionAbility(s,card,spell,target,restrictions,id);
|
||||
}
|
||||
|
||||
//flip a coin
|
||||
vector<string> splitFlipCoin = parseBetween(s, "flipacoin ", " flipend");
|
||||
if (splitFlipCoin.size())
|
||||
{
|
||||
string a1 = splitFlipCoin[1];
|
||||
MTGAbility * a = NEW GenericFlipACoin(observer, id, card, target,a1);
|
||||
a->oneShot = 1;
|
||||
a->canBeInterrupted = false;
|
||||
return a;
|
||||
}
|
||||
|
||||
//Upkeep Cost
|
||||
found = s.find("upcost");
|
||||
if (found != string::npos)
|
||||
@@ -1769,6 +1865,15 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return a;
|
||||
}
|
||||
|
||||
//put a card on bottom of library
|
||||
found = s.find("bottomoflibrary");
|
||||
if (found != string::npos)
|
||||
{
|
||||
MTGAbility * a = NEW AALibraryBottom(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//Copy a target
|
||||
found = s.find("copy");
|
||||
if (found != string::npos)
|
||||
@@ -1813,6 +1918,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
MTGAbility *a = NEW AABuryCard(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
if(s.find("and(") != string::npos)
|
||||
{
|
||||
vector<string> splitAnd = parseBetween(s, "and((", " ))",false);
|
||||
if(splitAnd.size())
|
||||
{
|
||||
((AABuryCard*)a)->andAbility = parseMagicLine(splitAnd[1], id, spell, card);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1820,6 +1933,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
MTGAbility * a = NEW AADestroyCard(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
if(s.find("and(") != string::npos)
|
||||
{
|
||||
vector<string> splitAnd = parseBetween(s, "and((", " ))",false);
|
||||
if(splitAnd.size())
|
||||
{
|
||||
((AADestroyCard*)a)->andAbility = parseMagicLine(splitAnd[1], id, spell, card);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1827,6 +1948,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
MTGAbility *a = NEW AASacrificeCard(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
if(s.find("and(") != string::npos)
|
||||
{
|
||||
vector<string> splitAnd = parseBetween(s, "and((", " ))",false);
|
||||
if(splitAnd.size())
|
||||
{
|
||||
((AASacrificeCard*)a)->andAbility = parseMagicLine(splitAnd[1], id, spell, card);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1834,6 +1963,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
{
|
||||
MTGAbility *a = NEW AADiscardCard(observer, id, card, target);
|
||||
a->oneShot = 1;
|
||||
if(s.find("and(") != string::npos)
|
||||
{
|
||||
vector<string> splitAnd = parseBetween(s, "and((", " ))",false);
|
||||
if(splitAnd.size())
|
||||
{
|
||||
((AADiscardCard*)a)->andAbility = parseMagicLine(splitAnd[1], id, spell, card);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
bool oneShot = false;
|
||||
@@ -1984,6 +2121,16 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return a;
|
||||
}
|
||||
|
||||
//modify turns
|
||||
vector<string> splitModTurn = parseBetween(s, "turns:", " ", false);
|
||||
if (splitModTurn.size())
|
||||
{
|
||||
Targetable * t = spell ? spell->getNextTarget() : NULL;
|
||||
MTGAbility * a = NEW AAModTurn(observer, id, card, t , splitModTurn[1], NULL, who);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//Shuffle
|
||||
found = s.find("shuffle");
|
||||
if (found != string::npos)
|
||||
@@ -2094,6 +2241,24 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
return NULL;
|
||||
return NEW ABushidoAbility(observer, id, card,splitBushido[1]);
|
||||
}
|
||||
vector<string> splitPhaseAlter = parseBetween(s, "phasealter(", ")");
|
||||
if (splitPhaseAlter.size())
|
||||
{
|
||||
string power, toughness;
|
||||
vector<string>splitPhaseAlter2 = split(splitPhaseAlter[1],',');
|
||||
if(splitPhaseAlter2.size() < 3)
|
||||
return NULL;
|
||||
string after = "";
|
||||
if(splitPhaseAlter2.size() > 3)
|
||||
{
|
||||
vector<string> splitPhaseAlterAfter = parseBetween(splitPhaseAlter2[3], "after<", ">");
|
||||
if(splitPhaseAlterAfter.size())
|
||||
after = splitPhaseAlterAfter[1];
|
||||
}
|
||||
MTGAbility * a1 = NEW APhaseAlter(observer, id, card, target,splitPhaseAlter2[0].find("add") != string::npos, splitPhaseAlter2[1],splitPhaseAlter2[2], s.find("nextphase") != string::npos,after);
|
||||
a1->canBeInterrupted = false;
|
||||
return NEW GenericAbilityMod(observer, 1, card,spell?spell->getNextDamageableTarget():(Damageable *) target, a1);
|
||||
}
|
||||
|
||||
//loseAbilities
|
||||
if (s.find("loseabilities") != string::npos)
|
||||
@@ -2184,17 +2349,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
string newPower = "";
|
||||
string newToughness = "";
|
||||
bool ptFound = false;
|
||||
if(becomesParameters.size() >1)
|
||||
{
|
||||
vector<string> pt = split(becomesParameters[1], '/');
|
||||
newPower = pt[0];
|
||||
newToughness = pt[1];
|
||||
ptFound = true;
|
||||
}
|
||||
if(becomesParameters.size() >1)
|
||||
{
|
||||
vector<string> pt = split(becomesParameters[1], '/');
|
||||
if(pt.size() > 1)
|
||||
{
|
||||
newPower = pt[0];
|
||||
newToughness = pt[1];
|
||||
ptFound = true;
|
||||
}
|
||||
}
|
||||
string sabilities = "";
|
||||
if(becomesParameters.size() > 2)
|
||||
unsigned int becomesSize = ptFound?2:1;
|
||||
if(becomesParameters.size() > becomesSize)
|
||||
{
|
||||
for(unsigned int i = 2;i < becomesParameters.size();i++)
|
||||
for(unsigned int i = becomesSize;i < becomesParameters.size();i++)
|
||||
{
|
||||
sabilities.append(becomesParameters[i].c_str());
|
||||
if(i+1 < becomesParameters.size())
|
||||
@@ -2339,7 +2508,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
found = s.find("add");
|
||||
if (found != string::npos)
|
||||
{
|
||||
ManaCost * output = ManaCost::parseManaCost(s.substr(found));
|
||||
ManaCost * output = ManaCost::parseManaCost(s.substr(found),NULL,card);
|
||||
Targetable * t = spell ? spell->getNextTarget() : NULL;
|
||||
MTGAbility * a = NEW AManaProducer(observer, id, card, t, output, NULL, who);
|
||||
a->oneShot = 1;
|
||||
@@ -2476,7 +2645,16 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//exchange life with target; if creature then toughness is life.
|
||||
found = s.find("exchangelife");
|
||||
if (found != string::npos)
|
||||
{
|
||||
Targetable * t = spell ? spell->getNextTarget() : NULL;
|
||||
MTGAbility * a = NEW AAExchangeLife(observer, id, card, t, NULL, who);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
//Regeneration
|
||||
found = s.find("regenerate");
|
||||
if (found != string::npos)
|
||||
@@ -2645,6 +2823,50 @@ MTGAbility * AbilityFactory::parsePhaseActionAbility(string s,MTGCardInstance *
|
||||
return NEW APhaseActionGeneric(observer, id, card,_target, trim(splitActions[2]), restrictions, phase,sourceinPlay,next,myturn,opponentturn,once);
|
||||
}
|
||||
|
||||
MTGAbility * AbilityFactory::parseChooseActionAbility(string s,MTGCardInstance * card,Spell * spell,MTGCardInstance * target, int restrictions,int id)
|
||||
{
|
||||
vector<string> splitChooseAColor2 = parseBetween(s, "activatechooseacolor ", " activatechooseend");
|
||||
if (splitChooseAColor2.size())
|
||||
{
|
||||
string a1 = splitChooseAColor2[1];
|
||||
MTGAbility * a = NEW GenericChooseTypeColor(observer, id, card, target,a1,true);
|
||||
a->oneShot = 1;
|
||||
a->canBeInterrupted = false;
|
||||
return a;
|
||||
}
|
||||
//choose a type
|
||||
vector<string> splitChooseAType2 = parseBetween(s, "activatechooseatype ", " activatechooseend");
|
||||
if (splitChooseAType2.size())
|
||||
{
|
||||
string a1 = splitChooseAType2[1];
|
||||
MTGAbility * a = NEW GenericChooseTypeColor(observer, id, card, target,a1,false,s.find("nonwall")!=string::npos);
|
||||
a->oneShot = 1;
|
||||
a->canBeInterrupted = false;
|
||||
return a;
|
||||
}
|
||||
//choose a color
|
||||
vector<string> splitChooseAColor = parseBetween(s, "chooseacolor ", " chooseend");
|
||||
if (splitChooseAColor.size())
|
||||
{
|
||||
string a1 = splitChooseAColor[1];
|
||||
MTGAbility * a = NEW GenericChooseTypeColor(observer, id, card, target,a1,true);
|
||||
a->oneShot = 1;
|
||||
a->canBeInterrupted = false;
|
||||
return a;
|
||||
}
|
||||
//choose a type
|
||||
vector<string> splitChooseAType = parseBetween(s, "chooseatype ", " chooseend");
|
||||
if (splitChooseAType.size())
|
||||
{
|
||||
string a1 = splitChooseAType[1];
|
||||
MTGAbility * a = NEW GenericChooseTypeColor(observer, id, card, target,a1,false,s.find("nonwall")!=string::npos);
|
||||
a->oneShot = 1;
|
||||
a->canBeInterrupted = false;
|
||||
return a;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Tells the AI if the ability should target itself or an ennemy
|
||||
int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, TargetChooser * tc,Targetable * target)
|
||||
{
|
||||
@@ -3024,11 +3246,14 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
|
||||
else
|
||||
{
|
||||
a->addToGame();
|
||||
MayAbility * dontAdd = dynamic_cast<MayAbility*>(a);
|
||||
if(!dontAdd)
|
||||
{
|
||||
if (a->source)
|
||||
a->source->cardsAbilities.push_back(a);
|
||||
else if(spell && spell->source)
|
||||
spell->source->cardsAbilities.push_back(a);
|
||||
|
||||
}
|
||||
//keep track of abilities being added to the game on each card it belongs to, this ignores p/t bonuses given
|
||||
//from other cards, or ability bonuses, making it generally easier to strip a card of it's abilities.
|
||||
}
|
||||
@@ -3051,6 +3276,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
|
||||
zones->putInZone(card, spell->from, card->owner->game->graveyard);
|
||||
return; //fizzle
|
||||
}
|
||||
card->playerTarget = spell->getNextPlayerTarget();
|
||||
}
|
||||
_id = magicText(_id, spell);
|
||||
|
||||
@@ -3818,7 +4044,6 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
{
|
||||
if(card->isPhased)
|
||||
return 0;
|
||||
|
||||
Player * player = game->currentlyActing();
|
||||
int cPhase = game->getCurrentGamePhase();
|
||||
switch (restrictions)
|
||||
@@ -3886,7 +4111,44 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
ManaCost * cost = getCost();
|
||||
if (!cost)
|
||||
return 1;
|
||||
if(card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
for(unsigned int k = 0;k < card->cardsAbilities.size();++k)
|
||||
{
|
||||
ActivatedAbility * check = dynamic_cast<ActivatedAbility*>(card->cardsAbilities[k]);
|
||||
if(check && check->counters)
|
||||
return 0;
|
||||
}
|
||||
if (player != game->currentPlayer)
|
||||
return 0;
|
||||
if (cPhase != MTG_PHASE_FIRSTMAIN && cPhase != MTG_PHASE_SECONDMAIN)
|
||||
return 0;
|
||||
}
|
||||
if (source->has(Constants::NOACTIVATED))
|
||||
return 0;
|
||||
AbilityFactory af(game);
|
||||
MTGAbility * fmp = NULL;
|
||||
fmp = af.getCoreAbility(this);
|
||||
AManaProducer * amp = dynamic_cast<AManaProducer *> (this);
|
||||
AManaProducer * femp = dynamic_cast<AManaProducer *> (fmp);
|
||||
if (source->has(Constants::NOMANA) && (amp||femp))
|
||||
return 0;
|
||||
if(source->has(Constants::ONLYMANA) && !(amp||femp))
|
||||
return 0;
|
||||
cost->setExtraCostsAction(this, card);
|
||||
if (source->has(Constants::NOACTIVATEDTAP) && cost->extraCosts)
|
||||
{
|
||||
for(unsigned int i = 0;i < cost->extraCosts->costs.size();++i)
|
||||
{
|
||||
ExtraCost * eCost = cost->getExtraCost(i);
|
||||
if(dynamic_cast<TapCost *>(eCost))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!mana)
|
||||
mana = player->getManaPool();
|
||||
if (!mana->canAfford(cost))
|
||||
@@ -4126,9 +4388,9 @@ int TargetAbility::resolve()
|
||||
Targetable * t = tc->getNextTarget();
|
||||
if (t && ability)
|
||||
{
|
||||
source->X = 0;
|
||||
if (abilityCost)
|
||||
{
|
||||
source->X = 0;
|
||||
ManaCost * diff = abilityCost->Diff(getCost());
|
||||
source->X = diff->hasX();
|
||||
delete (diff);
|
||||
@@ -4275,20 +4537,19 @@ void InstantAbility::Update(float dt)
|
||||
|
||||
InstantAbility::InstantAbility(GameObserver* observer, int _id, MTGCardInstance * source, Targetable * _target) :
|
||||
MTGAbility(observer, _id, source, _target)
|
||||
{
|
||||
init = 0;
|
||||
}
|
||||
{
|
||||
init = 0;
|
||||
}
|
||||
|
||||
//Instant abilities last generally until the end of the turn
|
||||
int InstantAbility::testDestroy()
|
||||
{
|
||||
GamePhase newPhase = game->getCurrentGamePhase();
|
||||
if (newPhase != currentPhase && newPhase == MTG_PHASE_AFTER_EOT)
|
||||
return 1;
|
||||
currentPhase = newPhase;
|
||||
return 0;
|
||||
|
||||
}
|
||||
int InstantAbility::testDestroy()
|
||||
{
|
||||
GamePhase newPhase = game->getCurrentGamePhase();
|
||||
if (newPhase != currentPhase && newPhase == MTG_PHASE_AFTER_EOT)
|
||||
return 1;
|
||||
currentPhase = newPhase;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ostream& InstantAbility::toString(ostream& out) const
|
||||
{
|
||||
@@ -4328,9 +4589,7 @@ void ListMaintainerAbility::updateTargets()
|
||||
cards.erase(card);
|
||||
removed(card);
|
||||
}
|
||||
|
||||
temp.clear();
|
||||
|
||||
//add New valid ones
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
|
||||
@@ -168,7 +168,6 @@ void MTGCardInstance::initMTGCI()
|
||||
flanked = 0;
|
||||
target = NULL;
|
||||
playerTarget = NULL;
|
||||
playerTarget = NULL;
|
||||
type_as_damageable = DAMAGEABLE_MTGCARDINSTANCE;
|
||||
banding = NULL;
|
||||
owner = NULL;
|
||||
|
||||
@@ -123,7 +123,11 @@ const char* Constants::MTGBasicAbilities[] = {
|
||||
"canattack",
|
||||
"hydra",
|
||||
"undying",
|
||||
"poisonshroud"
|
||||
"poisonshroud",
|
||||
"noactivatedability",
|
||||
"notapability",
|
||||
"nomanaability",
|
||||
"onlymanaability"
|
||||
};
|
||||
|
||||
map<string,int> Constants::MTGBasicAbilitiesMap;
|
||||
|
||||
@@ -1190,7 +1190,7 @@ int MTGAttackRule::receiveEvent(WEvent *e)
|
||||
for (int i = 0; i < z->nb_cards; i++)
|
||||
{
|
||||
MTGCardInstance * card = z->cards[i];
|
||||
if (!card->isAttacker() && card->has(Constants::MUSTATTACK))
|
||||
if (!card->isAttacker() && !event->from->isExtra && card->has(Constants::MUSTATTACK))//cards are only required to attack in the real attack phase of a turn.
|
||||
reactToClick(card);
|
||||
if (!card->isAttacker() && card->has(Constants::TREASON) && p->isAI())
|
||||
reactToClick(card);
|
||||
@@ -1232,6 +1232,121 @@ MTGAttackRule * MTGAttackRule::clone() const
|
||||
{
|
||||
return NEW MTGAttackRule(*this);
|
||||
}
|
||||
//handling for planeswalker attacking choice
|
||||
MTGPlaneswalkerAttackRule::MTGPlaneswalkerAttackRule(GameObserver* observer, int _id) :
|
||||
PermanentAbility(observer, _id)
|
||||
{
|
||||
aType = MTGAbility::MTG_ATTACK_RULE;
|
||||
}
|
||||
|
||||
int MTGPlaneswalkerAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
|
||||
{
|
||||
if (currentPhase == MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer && card->controller() == game->currentlyActing())//on my turn and when I am the acting player.
|
||||
{
|
||||
if(!card->controller()->opponent()->game->inPlay->hasType("planeswalker"))
|
||||
return 0;
|
||||
if(card->isPhased)
|
||||
return 0;
|
||||
if (card->isAttacker())
|
||||
return 1;
|
||||
if (card->canAttack())
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MTGPlaneswalkerAttackRule::reactToClick(MTGCardInstance * card)
|
||||
{
|
||||
if (!isReactingToClick(card))
|
||||
return 0;
|
||||
//Graphically select the next card that can attack
|
||||
if (!card->isAttacker())
|
||||
{
|
||||
game->getCardSelector()->PushLimitor();
|
||||
game->getCardSelector()->Limit(this, CardView::playZone);
|
||||
game->getCardSelector()->CheckUserInput(JGE_BTN_RIGHT);
|
||||
game->getCardSelector()->Limit(NULL, CardView::playZone);
|
||||
game->getCardSelector()->PopLimitor();
|
||||
}
|
||||
|
||||
vector<MTGAbility*>selection;
|
||||
MTGCardInstance * check = NULL;
|
||||
int checkWalkers = card->controller()->opponent()->game->battlefield->cards.size();
|
||||
for(int i = 0; i < checkWalkers;++i)
|
||||
{
|
||||
check = card->controller()->opponent()->game->battlefield->cards[i];
|
||||
if(check->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
MTGAbility * setPw = NEW AAPlaneswalkerAttacked(game, game->mLayers->actionLayer()->getMaxId(), card,check);
|
||||
MTGAbility * setWalker = setPw->clone();
|
||||
setWalker->oneShot = true;
|
||||
selection.push_back(setWalker);
|
||||
SAFE_DELETE(setPw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(selection.size())
|
||||
{
|
||||
MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), card, card,false,selection);
|
||||
game->mLayers->actionLayer()->currentActionCard = card;
|
||||
a1->resolve();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
MTGPlaneswalkerAttackRule * MTGPlaneswalkerAttackRule::clone() const
|
||||
{
|
||||
return NEW MTGPlaneswalkerAttackRule(*this);
|
||||
}
|
||||
|
||||
bool MTGPlaneswalkerAttackRule::select(Target* t)
|
||||
{
|
||||
if (CardView* c = dynamic_cast<CardView*>(t))
|
||||
{
|
||||
MTGCardInstance * card = c->getCard();
|
||||
if (card->canAttack() && !card->isPhased)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool MTGPlaneswalkerAttackRule::greyout(Target* t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//setting combat against planeswalker menu handling
|
||||
AAPlaneswalkerAttacked::AAPlaneswalkerAttacked(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target):
|
||||
InstantAbility(observer, id, source)
|
||||
{
|
||||
this->target = _target;
|
||||
menuText = _target->name.c_str();
|
||||
attacker = card;
|
||||
}
|
||||
|
||||
int AAPlaneswalkerAttacked::resolve()
|
||||
{
|
||||
if(!attacker)
|
||||
return 0;
|
||||
attacker->isAttacking = this->target;
|
||||
attacker->toggleAttacker();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* AAPlaneswalkerAttacked::getMenuText()
|
||||
{
|
||||
return menuText.c_str();
|
||||
}
|
||||
|
||||
AAPlaneswalkerAttacked * AAPlaneswalkerAttacked::clone() const
|
||||
{
|
||||
return NEW AAPlaneswalkerAttacked(*this);
|
||||
}
|
||||
|
||||
AAPlaneswalkerAttacked::~AAPlaneswalkerAttacked()
|
||||
{
|
||||
}
|
||||
|
||||
//this rules handles returning cards to combat triggers for activations.
|
||||
MTGCombatTriggersRule::MTGCombatTriggersRule(GameObserver* observer, int _id) :
|
||||
@@ -2159,6 +2274,49 @@ MTGPlaneWalkerRule * MTGPlaneWalkerRule::clone() const
|
||||
{
|
||||
return NEW MTGPlaneWalkerRule(*this);
|
||||
}
|
||||
/* planeswalker damage rule */
|
||||
MTGPlaneswalkerDamage::MTGPlaneswalkerDamage(GameObserver* observer, int _id) :
|
||||
PermanentAbility(observer, _id)
|
||||
{
|
||||
}
|
||||
;
|
||||
|
||||
int MTGPlaneswalkerDamage::receiveEvent(WEvent * event)
|
||||
{
|
||||
|
||||
if (event->type == WEvent::DAMAGE)
|
||||
{
|
||||
WEventDamage * e = (WEventDamage *) event;
|
||||
Damage * d = e->damage;
|
||||
MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(e->getTarget(WEvent::TARGET_TO));
|
||||
if (d->damage > 0 && card && card->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
{
|
||||
int howMany = d->damage;
|
||||
for(int k = 0;k < howMany;k++)
|
||||
{
|
||||
card->counters->removeCounter("loyalty",0,0);
|
||||
}
|
||||
d->damage = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (WEventCounters * removel = dynamic_cast<WEventCounters*>(event))
|
||||
{
|
||||
if(removel->removed && removel->targetCard && removel->targetCard->hasType(Subtypes::TYPE_PLANESWALKER))
|
||||
if(!removel->targetCard->counters->hasCounter("loyalty",0,0))
|
||||
{
|
||||
removel->targetCard->bury();
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MTGPlaneswalkerDamage * MTGPlaneswalkerDamage::clone() const
|
||||
{
|
||||
return NEW MTGPlaneswalkerDamage(*this);
|
||||
}
|
||||
|
||||
/* Lifelink */
|
||||
MTGLifelinkRule::MTGLifelinkRule(GameObserver* observer, int _id) :
|
||||
|
||||
@@ -165,7 +165,11 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
|
||||
}
|
||||
case 'c': //Counters or cycle
|
||||
{
|
||||
if(value == "cycle")
|
||||
if(value == "chosencolor")
|
||||
{
|
||||
manaCost->add(c->chooseacolor, 1);
|
||||
}
|
||||
else if(value == "cycle")
|
||||
{
|
||||
manaCost->addExtraCost(NEW CycleCost(tc));
|
||||
}
|
||||
@@ -631,6 +635,11 @@ int ManaCost::addExtraCost(ExtraCost * _cost)
|
||||
|
||||
int ManaCost::addExtraCosts(ExtraCosts *_ecost)
|
||||
{
|
||||
if(!_ecost)
|
||||
{
|
||||
extraCosts = NULL;
|
||||
return 1;
|
||||
}
|
||||
if (!extraCosts)
|
||||
extraCosts = NEW ExtraCosts();
|
||||
for(size_t i = 0; i < _ecost->costs.size(); i++)
|
||||
|
||||
@@ -140,6 +140,7 @@ void RulesState::parsePlayerState(int playerId, string s)
|
||||
void Rules::addExtraRules(GameObserver* g)
|
||||
{
|
||||
int id = g->mLayers->actionLayer()->getMaxId();
|
||||
MTGAllCards::sortSubtypeList();
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
Player * p = g->players[i];
|
||||
|
||||
@@ -574,6 +574,29 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
cd->setColor(cid);
|
||||
}
|
||||
}
|
||||
|
||||
if (attribute.find("chosencolor") != string::npos)
|
||||
{
|
||||
attributefound = 1;
|
||||
if (minus)
|
||||
cd->SetExclusionColor(card->chooseacolor);
|
||||
else
|
||||
cd->setColor(card->chooseacolor);
|
||||
}
|
||||
|
||||
if (attribute.find("chosentype") != string::npos)
|
||||
{
|
||||
attributefound = 1;
|
||||
if (minus)
|
||||
{
|
||||
cd->setNegativeSubtype(card->chooseasubtype);
|
||||
}
|
||||
else
|
||||
{
|
||||
cd->setSubtype(card->chooseasubtype);
|
||||
}
|
||||
}
|
||||
|
||||
if (!attributefound)
|
||||
{
|
||||
//Abilities
|
||||
|
||||
Reference in New Issue
Block a user