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:
omegablast2002@yahoo.com
2012-03-13 17:54:24 +00:00
parent b20b75df33
commit 0210ecf28c
15 changed files with 1269 additions and 126 deletions

View File

@@ -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 = ',');

View File

@@ -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

View File

@@ -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:

View File

@@ -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) :

View File

@@ -37,8 +37,6 @@ CardPrimitive::CardPrimitive()
CardPrimitive::CardPrimitive(CardPrimitive * source)
{
if(!source)
return;
if(!source)
return;
basicAbilities = source->basicAbilities;

View File

@@ -5,7 +5,7 @@
#include "Player.h"
#include "GameObserver.h"
#include "MTGDeck.h"
#include "ManaCostHybrid.h"
#include "ManacostHybrid.h"
DeckStats * DeckStats::mInstance = NULL;

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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++)
{

View File

@@ -168,7 +168,6 @@ void MTGCardInstance::initMTGCI()
flanked = 0;
target = NULL;
playerTarget = NULL;
playerTarget = NULL;
type_as_damageable = DAMAGEABLE_MTGCARDINSTANCE;
banding = NULL;
owner = NULL;

View File

@@ -123,7 +123,11 @@ const char* Constants::MTGBasicAbilities[] = {
"canattack",
"hydra",
"undying",
"poisonshroud"
"poisonshroud",
"noactivatedability",
"notapability",
"nomanaability",
"onlymanaability"
};
map<string,int> Constants::MTGBasicAbilitiesMap;

View File

@@ -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) :

View File

@@ -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++)

View File

@@ -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];

View File

@@ -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