megapatch contents
added
"whenever a creature enters the battlefield you may pay {1}, if you do gain one life"
conditional may pay({cost}) effect
this version is a super type ability, and can only be used in certain combos.
to nest you will need to use it in its subtype pay[[{cost}]] effect
pay keyword can have sideeffects coded as follows
pay[[{1}]] life:1?life:-1
pay one mana and gain 1 life, if you dont then you lose one life. notice no space between the abilities and the question mark.
added castcard()
a method to cast a targeted card, this contains the following subkeywords which can be used in combinations
(normal)
(restricted)
(copied)
(noevent)
castcard(restricted copied noevent) for example will cast a card that is a copy or the spell without sending a cast event only when the spell is castable.
"normal" subkeyword cast the actual spell, not a copy.
extended the use of exiledeath to everyzone, any card going from any zone to graveyard is placed in exile if it has exiledeath.
limited swipe left to open hand only when hand is closed view.
"moveto(" can now be named.
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
#include <JGui.h>
|
#include <JGui.h>
|
||||||
#include <hge/hgeparticle.h>
|
#include <hge/hgeparticle.h>
|
||||||
#include "IconButton.h"
|
#include "IconButton.h"
|
||||||
|
#include "ExtraCost.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
using std::map;
|
using std::map;
|
||||||
@@ -1102,7 +1103,8 @@ public:
|
|||||||
class AAFakeAbility: public ActivatedAbility
|
class AAFakeAbility: public ActivatedAbility
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AAFakeAbility(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, ManaCost * cost = NULL);
|
string named;
|
||||||
|
AAFakeAbility(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target,string _newName, ManaCost * cost = NULL);
|
||||||
int resolve();
|
int resolve();
|
||||||
const char* getMenuText();
|
const char* getMenuText();
|
||||||
AAFakeAbility * clone() const;
|
AAFakeAbility * clone() const;
|
||||||
@@ -1157,7 +1159,6 @@ public:
|
|||||||
string Cond;
|
string Cond;
|
||||||
Player * previousInterrupter;
|
Player * previousInterrupter;
|
||||||
MTGAbility * mClone;
|
MTGAbility * mClone;
|
||||||
ManaCost * optionalCost;
|
|
||||||
|
|
||||||
MayAbility(GameObserver* observer, int _id, MTGAbility * _ability, MTGCardInstance * _source, bool must = false, string restriction = "");
|
MayAbility(GameObserver* observer, int _id, MTGAbility * _ability, MTGCardInstance * _source, bool must = false, string restriction = "");
|
||||||
|
|
||||||
@@ -1182,11 +1183,15 @@ public:
|
|||||||
int triggered;
|
int triggered;
|
||||||
bool removeMenu;
|
bool removeMenu;
|
||||||
bool must;
|
bool must;
|
||||||
|
bool processed;
|
||||||
MTGAbility * mClone;
|
MTGAbility * mClone;
|
||||||
|
ManaCost * toPay;
|
||||||
vector<MTGAbility*>abilities;
|
vector<MTGAbility*>abilities;
|
||||||
|
vector<ManaCost*>optionalCosts;
|
||||||
Player * who;
|
Player * who;
|
||||||
string newNameString;
|
string newNameString;
|
||||||
MenuAbility(GameObserver* observer, int _id, Targetable * target, MTGCardInstance * _source, bool must = false, vector<MTGAbility*>abilities = vector<MTGAbility*>(),Player * who = NULL,string _newName = "");
|
MenuAbility(GameObserver* observer, int _id, Targetable * target, MTGCardInstance * _source, bool must = false, vector<MTGAbility*>abilities = vector<MTGAbility*>(),Player * who = NULL,string _newName = "");
|
||||||
|
bool CheckUserInput(JButton key);
|
||||||
void Update(float dt);
|
void Update(float dt);
|
||||||
int resolve();
|
int resolve();
|
||||||
const char * getMenuText();
|
const char * getMenuText();
|
||||||
@@ -1194,6 +1199,7 @@ public:
|
|||||||
int isReactingToTargetClick(Targetable * card);
|
int isReactingToTargetClick(Targetable * card);
|
||||||
int reactToTargetClick(Targetable * object);
|
int reactToTargetClick(Targetable * object);
|
||||||
int reactToChoiceClick(Targetable * object,int choice,int control);
|
int reactToChoiceClick(Targetable * object,int choice,int control);
|
||||||
|
int processAbility();
|
||||||
MenuAbility * clone() const;
|
MenuAbility * clone() const;
|
||||||
~MenuAbility();
|
~MenuAbility();
|
||||||
|
|
||||||
@@ -1301,7 +1307,8 @@ class AAMover: public ActivatedAbility
|
|||||||
public:
|
public:
|
||||||
string destination;
|
string destination;
|
||||||
MTGAbility * andAbility;
|
MTGAbility * andAbility;
|
||||||
AAMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest, ManaCost * _cost = NULL);
|
string named;
|
||||||
|
AAMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest,string _name, ManaCost * _cost = NULL);
|
||||||
MTGGameZone * destinationZone(Targetable * target = NULL);
|
MTGGameZone * destinationZone(Targetable * target = NULL);
|
||||||
int resolve();
|
int resolve();
|
||||||
const char * getMenuText();
|
const char * getMenuText();
|
||||||
@@ -1331,6 +1338,7 @@ class AABuryCard: public ActivatedAbility
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MTGAbility * andAbility;
|
MTGAbility * andAbility;
|
||||||
|
string menu;
|
||||||
AABuryCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target);
|
AABuryCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target);
|
||||||
int resolve();
|
int resolve();
|
||||||
const char * getMenuText();
|
const char * getMenuText();
|
||||||
@@ -5569,6 +5577,32 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AACastCard: public MTGAbility
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MTGAbility * andAbility;
|
||||||
|
bool processed;
|
||||||
|
bool restricted;
|
||||||
|
bool asCopy;
|
||||||
|
bool normal;
|
||||||
|
string cardNamed;
|
||||||
|
string nameThis;
|
||||||
|
MTGCardInstance * theNamedCard;
|
||||||
|
bool noEvent;
|
||||||
|
AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool restricted,bool copied,bool _asNormal,string nameCard,string abilityName,bool _noEvent);
|
||||||
|
|
||||||
|
int testDestroy(){return 0;};
|
||||||
|
void Update(float dt);
|
||||||
|
const char * getMenuText();
|
||||||
|
int isReactingToTargetClick(Targetable * card);
|
||||||
|
int reactToTargetClick(Targetable * object);
|
||||||
|
MTGCardInstance * makeCard();
|
||||||
|
int resolveSpell();
|
||||||
|
|
||||||
|
AACastCard * clone() const;
|
||||||
|
~AACastCard();
|
||||||
|
};
|
||||||
|
|
||||||
//A Spirit Link Ability
|
//A Spirit Link Ability
|
||||||
class ASpiritLinkAbility: public MTGAbility
|
class ASpiritLinkAbility: public MTGAbility
|
||||||
{
|
{
|
||||||
@@ -5736,6 +5770,25 @@ public:
|
|||||||
GenericFlipACoin * clone() const;
|
GenericFlipACoin * clone() const;
|
||||||
~GenericFlipACoin();
|
~GenericFlipACoin();
|
||||||
|
|
||||||
|
};
|
||||||
|
//------------
|
||||||
|
class GenericPaidAbility: public ActivatedAbility
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MTGAbility * baseAbility;
|
||||||
|
ManaCost * optionalCost;
|
||||||
|
|
||||||
|
string newName;
|
||||||
|
string restrictions;
|
||||||
|
string baseCost;
|
||||||
|
string baseAbilityStr;
|
||||||
|
|
||||||
|
GenericPaidAbility(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,string _newName,string _castRestriction,string _mayCost, string toAdd, ManaCost * cost = NULL);
|
||||||
|
int resolve();
|
||||||
|
const char* getMenuText();
|
||||||
|
GenericPaidAbility * clone() const;
|
||||||
|
~GenericPaidAbility();
|
||||||
|
|
||||||
};
|
};
|
||||||
// utility functions
|
// utility functions
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Counters.h"
|
#include "Counters.h"
|
||||||
#include "ObjectAnalytics.h"
|
#include "ObjectAnalytics.h"
|
||||||
|
#include "ManaCost.h"
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
@@ -18,11 +19,12 @@ class ExtraCost
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TargetChooser * tc;
|
TargetChooser * tc;
|
||||||
|
ManaCost * costToPay;
|
||||||
MTGCardInstance * source;
|
MTGCardInstance * source;
|
||||||
MTGCardInstance * target;
|
MTGCardInstance * target;
|
||||||
std::string mCostRenderString;
|
std::string mCostRenderString;
|
||||||
|
|
||||||
ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL);
|
ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL,ManaCost * _costToPay = NULL);
|
||||||
virtual ~ExtraCost();
|
virtual ~ExtraCost();
|
||||||
|
|
||||||
virtual int setPayment(MTGCardInstance * card);
|
virtual int setPayment(MTGCardInstance * card);
|
||||||
@@ -58,6 +60,18 @@ public:
|
|||||||
ExtraCosts * clone() const;
|
ExtraCosts * clone() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//extraextra
|
||||||
|
class extraManaCost : public ExtraCost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
extraManaCost(ManaCost * cost = NULL);
|
||||||
|
virtual int tryToSetPayment(MTGCardInstance * card);
|
||||||
|
virtual int isPaymentSet();
|
||||||
|
virtual int canPay();
|
||||||
|
virtual int doPay();
|
||||||
|
virtual extraManaCost * clone() const;
|
||||||
|
};
|
||||||
|
|
||||||
class SacrificeCost : public ExtraCost
|
class SacrificeCost : public ExtraCost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ public:
|
|||||||
class AbilityFactory
|
class AbilityFactory
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
string storedPayString;
|
||||||
string storedString;
|
string storedString;
|
||||||
string storedAbilityString;
|
string storedAbilityString;
|
||||||
string storedAndAbility;
|
string storedAndAbility;
|
||||||
|
|||||||
@@ -115,12 +115,11 @@ public:
|
|||||||
ManaCost increasedCost;
|
ManaCost increasedCost;
|
||||||
ManaCost * getReducedManaCost();
|
ManaCost * getReducedManaCost();
|
||||||
ManaCost * getIncreasedManaCost();
|
ManaCost * getIncreasedManaCost();
|
||||||
|
|
||||||
bool matchesCastFilter(int castMethod);
|
bool matchesCastFilter(int castMethod);
|
||||||
|
|
||||||
// The recommended method to test for summoning Sickness !
|
// The recommended method to test for summoning Sickness !
|
||||||
int hasSummoningSickness();
|
int hasSummoningSickness();
|
||||||
MTGCardInstance * changeController(Player * newcontroller);
|
MTGCardInstance * changeController(Player * newcontroller,bool notZone = false);
|
||||||
Player * owner;
|
Player * owner;
|
||||||
Counters * counters;
|
Counters * counters;
|
||||||
const string getDisplayName() const;
|
const string getDisplayName() const;
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ public:
|
|||||||
MTGCardInstance * putInExile(MTGCardInstance * card);
|
MTGCardInstance * putInExile(MTGCardInstance * card);
|
||||||
MTGCardInstance * putInLibrary(MTGCardInstance * card);
|
MTGCardInstance * putInLibrary(MTGCardInstance * card);
|
||||||
MTGCardInstance * putInHand(MTGCardInstance * card);
|
MTGCardInstance * putInHand(MTGCardInstance * card);
|
||||||
MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to);
|
MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to, bool asCopy = false);
|
||||||
int isInPlay(MTGCardInstance * card);
|
int isInPlay(MTGCardInstance * card);
|
||||||
int isInGrave(MTGCardInstance * card);
|
int isInGrave(MTGCardInstance * card);
|
||||||
int isInZone(MTGCardInstance * card,MTGGameZone * zone);
|
int isInZone(MTGCardInstance * card,MTGGameZone * zone);
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public:
|
|||||||
ManaCost * Retrace;
|
ManaCost * Retrace;
|
||||||
ManaCost * morph;
|
ManaCost * morph;
|
||||||
ManaCost * suspend;
|
ManaCost * suspend;
|
||||||
|
|
||||||
|
ManaCost * manaUsedToCast;
|
||||||
|
|
||||||
string alternativeName;
|
string alternativeName;
|
||||||
bool isMulti;
|
bool isMulti;
|
||||||
static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL);
|
static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL);
|
||||||
|
|||||||
@@ -1354,7 +1354,24 @@ int AIPlayerBaka::selectHintAbility()
|
|||||||
|
|
||||||
int AIPlayerBaka::selectAbility()
|
int AIPlayerBaka::selectAbility()
|
||||||
{
|
{
|
||||||
observer->mExtraPayment = NULL;
|
if(observer->mExtraPayment && observer->mExtraPayment->source->controller() == this)
|
||||||
|
{
|
||||||
|
extraManaCost * check = NULL;
|
||||||
|
check = dynamic_cast<extraManaCost*>(observer->mExtraPayment->costs[0]);
|
||||||
|
if(check)
|
||||||
|
{
|
||||||
|
vector<MTGAbility*> CostToPay = canPayMana(observer->mExtraPayment->source,check->costToPay);
|
||||||
|
if(CostToPay.size())
|
||||||
|
{
|
||||||
|
payTheManaCost(check->costToPay,check->source,CostToPay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Try Deck hints first
|
// Try Deck hints first
|
||||||
if (selectHintAbility())
|
if (selectHintAbility())
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1479,7 +1496,11 @@ int AIPlayerBaka::effectBadOrGood(MTGCardInstance * card, int mode, TargetChoose
|
|||||||
|
|
||||||
int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCardInstance * chosenCard,bool checkOnly)
|
int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCardInstance * chosenCard,bool checkOnly)
|
||||||
{
|
{
|
||||||
|
if(observer->mExtraPayment)
|
||||||
|
{
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
observer->mExtraPayment = NULL;
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
//there should never be a case where a extra cost target selection is happening at the same time as this..
|
//there should never be a case where a extra cost target selection is happening at the same time as this..
|
||||||
//extracost uses "chooseCard()" to determine its targets.
|
//extracost uses "chooseCard()" to determine its targets.
|
||||||
vector<Targetable *> potentialTargets;
|
vector<Targetable *> potentialTargets;
|
||||||
@@ -2132,8 +2153,11 @@ int AIPlayerBaka::computeActions()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(observer->mExtraPayment)
|
if(observer->mExtraPayment)
|
||||||
|
{
|
||||||
//no extra payment should be waiting before selecting an ability.
|
//no extra payment should be waiting before selecting an ability.
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
observer->mExtraPayment = NULL;
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
//this is a fix for a rare bug that somehow ai trips over an extra payment without paying
|
//this is a fix for a rare bug that somehow ai trips over an extra payment without paying
|
||||||
//then locks in a loop of trying to choose something different to do and trying to pay the extra payment.
|
//then locks in a loop of trying to choose something different to do and trying to pay the extra payment.
|
||||||
selectAbility();
|
selectAbility();
|
||||||
@@ -2538,6 +2562,25 @@ int AIPlayerBaka::Act(float dt)
|
|||||||
{
|
{
|
||||||
if (observer->isInterrupting == this)
|
if (observer->isInterrupting == this)
|
||||||
{
|
{
|
||||||
|
if(observer->mExtraPayment && observer->mExtraPayment->source->controller() == this)
|
||||||
|
{
|
||||||
|
extraManaCost * check = NULL;
|
||||||
|
check = dynamic_cast<extraManaCost*>(observer->mExtraPayment->costs[0]);
|
||||||
|
if(check)
|
||||||
|
{
|
||||||
|
vector<MTGAbility*> CostToPay = canPayMana(observer->mExtraPayment->source,check->costToPay);
|
||||||
|
if(CostToPay.size())
|
||||||
|
{
|
||||||
|
payTheManaCost(check->costToPay,check->source,CostToPay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
observer->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption();
|
observer->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -95,6 +95,16 @@ bool ActionLayer::CheckUserInput(JButton key)
|
|||||||
{
|
{
|
||||||
if (observer->mExtraPayment && key == JGE_BTN_SEC)
|
if (observer->mExtraPayment && key == JGE_BTN_SEC)
|
||||||
{
|
{
|
||||||
|
for (size_t i = 0; i < mObjects.size(); i++)
|
||||||
|
{
|
||||||
|
if (mObjects[i] != NULL)
|
||||||
|
{
|
||||||
|
ActionElement * currentAction = (ActionElement *) mObjects[i];
|
||||||
|
currentAction->CheckUserInput(key);
|
||||||
|
//check first with a mock up to see if any abilities will care about the extra payment
|
||||||
|
//being cancelled. currently only menuability and paidability will care.
|
||||||
|
}
|
||||||
|
}
|
||||||
observer->mExtraPayment = NULL;
|
observer->mExtraPayment = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,6 +309,10 @@ int Spell::resolve()
|
|||||||
Player * p = source->controller();
|
Player * p = source->controller();
|
||||||
int castMethod = source->castMethod;
|
int castMethod = source->castMethod;
|
||||||
vector<Targetable*>backupTgt = source->backupTargets;
|
vector<Targetable*>backupTgt = source->backupTargets;
|
||||||
|
if(from != source->currentZone)
|
||||||
|
{
|
||||||
|
from = source->currentZone;//this happens when casting spells that belong to another player or casting a copy of someone elses spell.
|
||||||
|
}
|
||||||
source = p->game->putInZone(source, from, p->game->battlefield);
|
source = p->game->putInZone(source, from, p->game->battlefield);
|
||||||
|
|
||||||
// We need to get the information about the cast method on both the card in the stack AND the card in play,
|
// We need to get the information about the cast method on both the card in the stack AND the card in play,
|
||||||
@@ -326,6 +330,8 @@ int Spell::resolve()
|
|||||||
if(observer->getResourceManager())
|
if(observer->getResourceManager())
|
||||||
observer->getResourceManager()->PlaySample(source->getSample());
|
observer->getResourceManager()->PlaySample(source->getSample());
|
||||||
}
|
}
|
||||||
|
if(this->cost)
|
||||||
|
source->getManaCost()->manaUsedToCast = NEW ManaCost(this->cost);
|
||||||
AbilityFactory af(observer);
|
AbilityFactory af(observer);
|
||||||
af.addAbilities(observer->mLayers->actionLayer()->getMaxId(), this);
|
af.addAbilities(observer->mLayers->actionLayer()->getMaxId(), this);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -419,6 +425,11 @@ Interruptible(observer, id)
|
|||||||
int PutInGraveyard::resolve()
|
int PutInGraveyard::resolve()
|
||||||
{
|
{
|
||||||
MTGGameZone * zone = card->getCurrentZone();
|
MTGGameZone * zone = card->getCurrentZone();
|
||||||
|
if (card->basicAbilities[(int)Constants::EXILEDEATH])
|
||||||
|
{
|
||||||
|
card->owner->game->putInZone(card, zone, card->owner->game->exile);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (zone == observer->players[0]->game->inPlay || zone == observer->players[1]->game->inPlay)
|
if (zone == observer->players[0]->game->inPlay || zone == observer->players[1]->game->inPlay)
|
||||||
{
|
{
|
||||||
card->owner->game->putInZone(card, zone, card->owner->game->graveyard);
|
card->owner->game->putInZone(card, zone, card->owner->game->graveyard);
|
||||||
@@ -900,7 +911,7 @@ void ActionStack::Update(float dt)
|
|||||||
if (mode == ACTIONSTACK_STANDARD)
|
if (mode == ACTIONSTACK_STANDARD)
|
||||||
{
|
{
|
||||||
modal = 0;
|
modal = 0;
|
||||||
if (getLatest(NOT_RESOLVED))
|
if (getLatest(NOT_RESOLVED) && !tc)
|
||||||
{
|
{
|
||||||
Interruptible * currentSpell = (Interruptible *)getLatest(NOT_RESOLVED);
|
Interruptible * currentSpell = (Interruptible *)getLatest(NOT_RESOLVED);
|
||||||
MTGCardInstance * card = currentSpell->source;
|
MTGCardInstance * card = currentSpell->source;
|
||||||
@@ -1054,6 +1065,11 @@ bool ActionStack::CheckUserInput(JButton inputKey)
|
|||||||
{
|
{
|
||||||
if (JGE_BTN_SEC == key)
|
if (JGE_BTN_SEC == key)
|
||||||
{
|
{
|
||||||
|
if(observer->mExtraPayment)
|
||||||
|
{
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
endOfInterruption();
|
endOfInterruption();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1167,7 +1183,12 @@ void ActionStack::Render()
|
|||||||
{
|
{
|
||||||
if (!askIfWishesToInterrupt || !askIfWishesToInterrupt->displayStack())
|
if (!askIfWishesToInterrupt || !askIfWishesToInterrupt->displayStack())
|
||||||
return;
|
return;
|
||||||
|
/*observer->mExtraPayment = NULL*/;//end any payment request from extra cost as we open the stack to display items.
|
||||||
|
if(observer->mExtraPayment)
|
||||||
|
{
|
||||||
|
observer->mExtraPayment->action->CheckUserInput(JGE_BTN_SEC);
|
||||||
|
observer->mExtraPayment = NULL;
|
||||||
|
}
|
||||||
for (size_t i = 0; i < mObjects.size(); i++)
|
for (size_t i = 0; i < mObjects.size(); i++)
|
||||||
{
|
{
|
||||||
Interruptible * current = (Interruptible *) mObjects[i];
|
Interruptible * current = (Interruptible *) mObjects[i];
|
||||||
|
|||||||
@@ -544,7 +544,7 @@ AACounter * AACounter::clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//shield a card from a certain type of counter.
|
//shield a card from a certain type of counter.
|
||||||
ACounterShroud::ACounterShroud(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance *,TargetChooser * tc, Counter * counter) :
|
ACounterShroud::ACounterShroud(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target,TargetChooser * tc, Counter * counter) :
|
||||||
MTGAbility(observer, id, source),csTc(tc),counter(counter),re(NULL)
|
MTGAbility(observer, id, source),csTc(tc),counter(counter),re(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ AARemoveAllCounter * AARemoveAllCounter::clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//proliferate a target
|
//proliferate a target
|
||||||
AAProliferate::AAProliferate(GameObserver* observer, int id, MTGCardInstance * source, Targetable *,ManaCost * cost) :
|
AAProliferate::AAProliferate(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,ManaCost * cost) :
|
||||||
ActivatedAbility(observer, id, source, cost, 0)
|
ActivatedAbility(observer, id, source, cost, 0)
|
||||||
{
|
{
|
||||||
this->GetId();
|
this->GetId();
|
||||||
@@ -974,7 +974,7 @@ AASetTypeChosen::~AASetTypeChosen()
|
|||||||
//
|
//
|
||||||
//choosing a type or color
|
//choosing a type or color
|
||||||
GenericFlipACoin::GenericFlipACoin(GameObserver* observer, int id, MTGCardInstance * source, Targetable *,string _toAdd, ManaCost * cost) :
|
GenericFlipACoin::GenericFlipACoin(GameObserver* observer, int id, MTGCardInstance * source, Targetable *,string _toAdd, ManaCost * cost) :
|
||||||
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd),chooseColor(true)
|
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd),chooseColor(chooseColor)
|
||||||
{
|
{
|
||||||
this->GetId();
|
this->GetId();
|
||||||
setCoin = NULL;
|
setCoin = NULL;
|
||||||
@@ -1111,6 +1111,87 @@ AASetCoin * AASetCoin::clone() const
|
|||||||
AASetCoin::~AASetCoin()
|
AASetCoin::~AASetCoin()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
//paying for an ability as an effect but as a cost
|
||||||
|
GenericPaidAbility::GenericPaidAbility(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,string _newName,string _castRestriction,string mayCost,string _toAdd,ManaCost * cost) :
|
||||||
|
ActivatedAbility(observer, id, source, cost, 0),newName(_newName),restrictions(_castRestriction),baseCost(mayCost), baseAbilityStr(_toAdd)
|
||||||
|
{
|
||||||
|
this->GetId();
|
||||||
|
baseAbility = NULL;
|
||||||
|
optionalCost = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GenericPaidAbility::resolve()
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
if(restrictions.size())
|
||||||
|
{
|
||||||
|
AbilityFactory af(game);
|
||||||
|
int checkCond = af.parseCastRestrictions(source,source->controller(),restrictions);
|
||||||
|
if(!checkCond)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AbilityFactory Af(game);
|
||||||
|
vector<string> baseAbilityStrSplit = split(baseAbilityStr,'?');
|
||||||
|
vector<MTGAbility*>selection;
|
||||||
|
if(baseAbilityStrSplit.size() > 1)
|
||||||
|
{
|
||||||
|
baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source);
|
||||||
|
baseAbility->target = target;
|
||||||
|
optionalCost = ManaCost::parseManaCost(baseCost, NULL, source);
|
||||||
|
MTGAbility * set = baseAbility->clone();
|
||||||
|
set->oneShot = true;
|
||||||
|
selection.push_back(set);
|
||||||
|
SAFE_DELETE(baseAbility);
|
||||||
|
baseAbility = Af.parseMagicLine(baseAbilityStrSplit[1], this->GetId(), NULL, source);
|
||||||
|
baseAbility->target = target;
|
||||||
|
set = baseAbility->clone();
|
||||||
|
set->oneShot = true;
|
||||||
|
selection.push_back(set);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source);
|
||||||
|
baseAbility->target = target;
|
||||||
|
optionalCost = ManaCost::parseManaCost(baseCost, NULL, source);
|
||||||
|
MTGAbility * set = baseAbility->clone();
|
||||||
|
set->oneShot = true;
|
||||||
|
selection.push_back(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selection.size())
|
||||||
|
{
|
||||||
|
MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,baseAbilityStrSplit.size() >1?true:false,selection,NULL,newName);
|
||||||
|
dynamic_cast<MenuAbility*>(a1)->optionalCosts.push_back(NEW ManaCost(optionalCost));
|
||||||
|
game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
|
||||||
|
a1->resolve();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GenericPaidAbility::getMenuText()
|
||||||
|
{
|
||||||
|
if( newName.size())
|
||||||
|
return newName.c_str();
|
||||||
|
return "Pay For Effect";
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericPaidAbility * GenericPaidAbility::clone() const
|
||||||
|
{
|
||||||
|
GenericPaidAbility * a = NEW GenericPaidAbility(*this);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericPaidAbility::~GenericPaidAbility()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(optionalCost);
|
||||||
|
SAFE_DELETE(baseAbility);
|
||||||
|
}
|
||||||
|
|
||||||
//saves a listed mana type until end of turn.
|
//saves a listed mana type until end of turn.
|
||||||
AManaPoolSaver::AManaPoolSaver(GameObserver* observer, int id, MTGCardInstance * source,string color, bool otherPlayer) :
|
AManaPoolSaver::AManaPoolSaver(GameObserver* observer, int id, MTGCardInstance * source,string color, bool otherPlayer) :
|
||||||
@@ -1206,8 +1287,8 @@ AAResetDamage * AAResetDamage::clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ability that resolves to do nothing.
|
//ability that resolves to do nothing.
|
||||||
AAFakeAbility::AAFakeAbility(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, ManaCost * cost):
|
AAFakeAbility::AAFakeAbility(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, string _named,ManaCost * cost):
|
||||||
ActivatedAbility(observer, id, source, cost, 0)
|
ActivatedAbility(observer, id, source, cost, 0),named(_named)
|
||||||
{
|
{
|
||||||
this->target = _target;
|
this->target = _target;
|
||||||
}
|
}
|
||||||
@@ -1218,6 +1299,8 @@ int AAFakeAbility::resolve()
|
|||||||
|
|
||||||
const char* AAFakeAbility::getMenuText()
|
const char* AAFakeAbility::getMenuText()
|
||||||
{
|
{
|
||||||
|
if(named.size())
|
||||||
|
return named.c_str();
|
||||||
return "Ability";
|
return "Ability";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1249,7 +1332,9 @@ int AAFizzler::resolve()
|
|||||||
target = stack->getActionElementFromCard(cTarget);
|
target = stack->getActionElementFromCard(cTarget);
|
||||||
}
|
}
|
||||||
Spell * sTarget = (Spell *) target;
|
Spell * sTarget = (Spell *) target;
|
||||||
MTGCardInstance* sCard = sTarget->source;
|
MTGCardInstance* sCard = NULL;
|
||||||
|
if(sTarget)
|
||||||
|
sCard = sTarget->source;
|
||||||
if(!sCard || !sTarget || sCard->has(Constants::NOFIZZLE))
|
if(!sCard || !sTarget || sCard->has(Constants::NOFIZZLE))
|
||||||
return 0;
|
return 0;
|
||||||
stack->Fizzle(sTarget);
|
stack->Fizzle(sTarget);
|
||||||
@@ -1304,6 +1389,8 @@ int AABuryCard::resolve()
|
|||||||
|
|
||||||
const char * AABuryCard::getMenuText()
|
const char * AABuryCard::getMenuText()
|
||||||
{
|
{
|
||||||
|
if(menu.size())
|
||||||
|
return menu.c_str();
|
||||||
return "Bury";
|
return "Bury";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,6 +1570,9 @@ AADiscardCard::~AADiscardCard()
|
|||||||
{
|
{
|
||||||
SAFE_DELETE(andAbility);
|
SAFE_DELETE(andAbility);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
AADrawer::AADrawer(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, string nbcardsStr,
|
AADrawer::AADrawer(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, string nbcardsStr,
|
||||||
int who, bool noreplace) :
|
int who, bool noreplace) :
|
||||||
ActivatedAbilityTP(observer, _id, card, _target, _cost, who), nbcardsStr(nbcardsStr),noReplace(noreplace)
|
ActivatedAbilityTP(observer, _id, card, _target, _cost, who), nbcardsStr(nbcardsStr),noReplace(noreplace)
|
||||||
@@ -1881,23 +1971,28 @@ int AADynamic::resolve()
|
|||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_ITSELF:
|
case DYNAMIC_ABILITY_WHO_ITSELF:
|
||||||
source = ((MTGCardInstance *) _target);
|
source = ((MTGCardInstance *) _target);
|
||||||
|
_target = _target;
|
||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_TARGETCONTROLLER:
|
case DYNAMIC_ABILITY_WHO_TARGETCONTROLLER:
|
||||||
|
_target = _target;
|
||||||
secondaryTarget = ((MTGCardInstance *) _target)->controller();
|
secondaryTarget = ((MTGCardInstance *) _target)->controller();
|
||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_TARGETOPPONENT:
|
case DYNAMIC_ABILITY_WHO_TARGETOPPONENT:
|
||||||
|
_target = _target;
|
||||||
secondaryTarget = ((MTGCardInstance *) _target)->controller()->opponent();
|
secondaryTarget = ((MTGCardInstance *) _target)->controller()->opponent();
|
||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_TOSOURCE:
|
case DYNAMIC_ABILITY_WHO_TOSOURCE:
|
||||||
tosrc = true;
|
tosrc = true;
|
||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_SOURCECONTROLLER:
|
case DYNAMIC_ABILITY_WHO_SOURCECONTROLLER:
|
||||||
|
_target = _target;
|
||||||
secondaryTarget = ((MTGCardInstance *) OriginalSrc)->controller();
|
secondaryTarget = ((MTGCardInstance *) OriginalSrc)->controller();
|
||||||
break;
|
break;
|
||||||
case DYNAMIC_ABILITY_WHO_SOURCEOPPONENT:
|
case DYNAMIC_ABILITY_WHO_SOURCEOPPONENT:
|
||||||
secondaryTarget = OriginalSrc->controller()->opponent();
|
secondaryTarget = OriginalSrc->controller()->opponent();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
_target = _target;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(amountsource == DYNAMIC_MYSELF_AMOUNT)
|
if(amountsource == DYNAMIC_MYSELF_AMOUNT)
|
||||||
@@ -2530,8 +2625,8 @@ AInstantCastRestrictionUEOT::~AInstantCastRestrictionUEOT()
|
|||||||
|
|
||||||
|
|
||||||
//AAMover
|
//AAMover
|
||||||
AAMover::AAMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest, ManaCost * _cost) :
|
AAMover::AAMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest,string newName, ManaCost * _cost) :
|
||||||
ActivatedAbility(observer, _id, _source, _cost, 0), destination(dest)
|
ActivatedAbility(observer, _id, _source, _cost, 0), destination(dest),named(newName)
|
||||||
{
|
{
|
||||||
if (_target)
|
if (_target)
|
||||||
target = _target;
|
target = _target;
|
||||||
@@ -2607,11 +2702,15 @@ int AAMover::resolve()
|
|||||||
|
|
||||||
const char * AAMover::getMenuText()
|
const char * AAMover::getMenuText()
|
||||||
{
|
{
|
||||||
|
if(named.size())
|
||||||
|
return named.c_str();
|
||||||
return "Move";
|
return "Move";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * AAMover::getMenuText(TargetChooser * tc)
|
const char * AAMover::getMenuText(TargetChooser * tc)
|
||||||
{
|
{
|
||||||
|
if(named.size())
|
||||||
|
return named.c_str();
|
||||||
MTGGameZone * dest = destinationZone();
|
MTGGameZone * dest = destinationZone();
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
@@ -2862,6 +2961,7 @@ int AARemoveMana::resolve()
|
|||||||
{
|
{
|
||||||
if (player->doesntEmpty->getConvertedCost() && !player->poolDoesntEmpty->getConvertedCost())
|
if (player->doesntEmpty->getConvertedCost() && !player->poolDoesntEmpty->getConvertedCost())
|
||||||
{
|
{
|
||||||
|
ManaCost * toRemove = manaPool->Diff(player->doesntEmpty);
|
||||||
player->getManaPool()->pay(manaPool->Diff(player->doesntEmpty));
|
player->getManaPool()->pay(manaPool->Diff(player->doesntEmpty));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -3174,7 +3274,6 @@ MayAbility::MayAbility(GameObserver* observer, int _id, MTGAbility * _ability, M
|
|||||||
{
|
{
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
mClone = NULL;
|
mClone = NULL;
|
||||||
optionalCost = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MayAbility::Update(float dt)
|
void MayAbility::Update(float dt)
|
||||||
@@ -3183,8 +3282,6 @@ void MayAbility::Update(float dt)
|
|||||||
if (!triggered && !game->getCurrentTargetChooser() && (!game->mLayers->actionLayer()->menuObject||game->mLayers->actionLayer()->menuObject == source))
|
if (!triggered && !game->getCurrentTargetChooser() && (!game->mLayers->actionLayer()->menuObject||game->mLayers->actionLayer()->menuObject == source))
|
||||||
{
|
{
|
||||||
triggered = 1;
|
triggered = 1;
|
||||||
if(optionalCost && !source->controller()->getManaPool()->canAfford(optionalCost))
|
|
||||||
return;
|
|
||||||
if(Cond.size())
|
if(Cond.size())
|
||||||
{
|
{
|
||||||
AbilityFactory af(game);
|
AbilityFactory af(game);
|
||||||
@@ -3229,8 +3326,16 @@ int MayAbility::isReactingToTargetClick(Targetable * card)
|
|||||||
{
|
{
|
||||||
if (card == source)
|
if (card == source)
|
||||||
{
|
{
|
||||||
if(!optionalCost || source->controller()->getManaPool()->canAfford(optionalCost))
|
if(Cond.size())
|
||||||
return 1;
|
{
|
||||||
|
AbilityFactory af(game);
|
||||||
|
int checkCond = af.parseCastRestrictions(source,source->controller(),Cond);
|
||||||
|
if(!checkCond)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3238,12 +3343,6 @@ int MayAbility::isReactingToTargetClick(Targetable * card)
|
|||||||
int MayAbility::reactToTargetClick(Targetable * object)
|
int MayAbility::reactToTargetClick(Targetable * object)
|
||||||
{
|
{
|
||||||
mClone = ability->clone();
|
mClone = ability->clone();
|
||||||
if(optionalCost)
|
|
||||||
{
|
|
||||||
source->controller()->getManaPool()->pay(optionalCost);
|
|
||||||
optionalCost->setExtraCostsAction(this, source);
|
|
||||||
optionalCost->doPayExtra();
|
|
||||||
}
|
|
||||||
mClone->addToGame();
|
mClone->addToGame();
|
||||||
mClone->forceDestroy = 1;
|
mClone->forceDestroy = 1;
|
||||||
return mClone->reactToTargetClick(object);
|
return mClone->reactToTargetClick(object);
|
||||||
@@ -3253,18 +3352,15 @@ MayAbility * MayAbility::clone() const
|
|||||||
{
|
{
|
||||||
MayAbility * a = NEW MayAbility(*this);
|
MayAbility * a = NEW MayAbility(*this);
|
||||||
a->ability = ability->clone();
|
a->ability = ability->clone();
|
||||||
a->optionalCost = this->optionalCost;
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
MayAbility::~MayAbility()
|
MayAbility::~MayAbility()
|
||||||
{
|
{
|
||||||
SAFE_DELETE(ability);
|
SAFE_DELETE(ability);
|
||||||
SAFE_DELETE(optionalCost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Menu building ability Abilities
|
//Menu building ability Abilities
|
||||||
//this will eventaully handle choosen discards/sacrifices.
|
|
||||||
MenuAbility::MenuAbility(GameObserver* observer, int _id, Targetable * mtarget, MTGCardInstance * _source, bool must,vector<MTGAbility*>abilities,Player * who, string newName) :
|
MenuAbility::MenuAbility(GameObserver* observer, int _id, Targetable * mtarget, MTGCardInstance * _source, bool must,vector<MTGAbility*>abilities,Player * who, string newName) :
|
||||||
MayAbility(observer, _id,NULL,_source,must), must(must),abilities(abilities),who(who),newNameString(newName)
|
MayAbility(observer, _id,NULL,_source,must), must(must),abilities(abilities),who(who),newNameString(newName)
|
||||||
{
|
{
|
||||||
@@ -3272,12 +3368,46 @@ MayAbility(observer, _id,NULL,_source,must), must(must),abilities(abilities),who
|
|||||||
mClone = NULL;
|
mClone = NULL;
|
||||||
this->target = mtarget;
|
this->target = mtarget;
|
||||||
removeMenu = false;
|
removeMenu = false;
|
||||||
|
vector<ManaCost*>optionalCost = vector<ManaCost*>();
|
||||||
|
toPay = NULL;
|
||||||
|
processed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MenuAbility::CheckUserInput(JButton key)
|
||||||
|
{
|
||||||
|
if (game->mExtraPayment && key == JGE_BTN_SEC)
|
||||||
|
{
|
||||||
|
if(toPay && toPay->extraCosts == game->mExtraPayment)
|
||||||
|
{
|
||||||
|
//the user cancelled the paidability. fireAbility() on the second menu item.
|
||||||
|
//paidability will always occupy the abilities[0]; in the vector.
|
||||||
|
if(abilities.size() > 1)
|
||||||
|
{
|
||||||
|
abilities[1]->target = abilities[0]->target;
|
||||||
|
abilities[1]->fireAbility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuAbility::Update(float dt)
|
void MenuAbility::Update(float dt)
|
||||||
{
|
{
|
||||||
MTGAbility::Update(dt);
|
MTGAbility::Update(dt);
|
||||||
ActionLayer * object = game->mLayers->actionLayer();
|
ActionLayer * object = game->mLayers->actionLayer();
|
||||||
|
if(toPay && game->mExtraPayment && !processed)
|
||||||
|
{
|
||||||
|
if(game->mExtraPayment->isPaymentSet() && game->mExtraPayment->canPay() )
|
||||||
|
{
|
||||||
|
game->mExtraPayment->doPay();
|
||||||
|
game->mLayers->actionLayer()->reactToClick(game->mExtraPayment->action, game->mExtraPayment->source);
|
||||||
|
game->mExtraPayment = NULL;
|
||||||
|
processAbility();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
if (!triggered && !object->menuObject && !object->getCurrentTargetChooser())
|
if (!triggered && !object->menuObject && !object->getCurrentTargetChooser())
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -3293,7 +3423,7 @@ void MenuAbility::Update(float dt)
|
|||||||
{
|
{
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
if(triggered)
|
if(triggered && !game->mExtraPayment && !processed)
|
||||||
{
|
{
|
||||||
game->mLayers->actionLayer()->setCustomMenuObject(source, must,abilities,newNameString.size()?newNameString.c_str():"");
|
game->mLayers->actionLayer()->setCustomMenuObject(source, must,abilities,newNameString.size()?newNameString.c_str():"");
|
||||||
previousInterrupter = game->isInterrupting;
|
previousInterrupter = game->isInterrupting;
|
||||||
@@ -3317,6 +3447,8 @@ const char * MenuAbility::getMenuText()
|
|||||||
|
|
||||||
int MenuAbility::testDestroy()
|
int MenuAbility::testDestroy()
|
||||||
{
|
{
|
||||||
|
if (game->mExtraPayment)
|
||||||
|
return 0;
|
||||||
if (!removeMenu)
|
if (!removeMenu)
|
||||||
return 0;
|
return 0;
|
||||||
if (game->mLayers->actionLayer()->menuObject)
|
if (game->mLayers->actionLayer()->menuObject)
|
||||||
@@ -3327,8 +3459,38 @@ int MenuAbility::testDestroy()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MenuAbility::isReactingToTargetClick(Targetable * card){return MayAbility::isReactingToTargetClick(card);}
|
int MenuAbility::isReactingToTargetClick(Targetable * card){return 0/*MayAbility::isReactingToTargetClick(card)*/;}
|
||||||
int MenuAbility::reactToTargetClick(Targetable *){return 1;}
|
int MenuAbility::reactToTargetClick(Targetable * object){return 1;}
|
||||||
|
|
||||||
|
int MenuAbility::processAbility()
|
||||||
|
{
|
||||||
|
if(!mClone)
|
||||||
|
return 0;
|
||||||
|
if(processed)
|
||||||
|
return 0;
|
||||||
|
if(abilities[0])
|
||||||
|
mClone->target = abilities[0]->target;
|
||||||
|
if(MayAbility * toCheck = dynamic_cast<MayAbility*>(mClone))
|
||||||
|
{
|
||||||
|
toCheck->must = true;
|
||||||
|
mClone->addToGame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mClone->oneShot = true;
|
||||||
|
mClone->forceDestroy = 1;
|
||||||
|
mClone->canBeInterrupted = false;
|
||||||
|
mClone->resolve();
|
||||||
|
SAFE_DELETE(mClone);
|
||||||
|
if (source->controller() == game->isInterrupting)
|
||||||
|
game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
processed = true;
|
||||||
|
this->forceDestroy = 1;
|
||||||
|
removeMenu = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
|
int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
|
||||||
{
|
{
|
||||||
@@ -3339,12 +3501,21 @@ int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
|
|||||||
return 0;
|
return 0;
|
||||||
for(int i = 0;i < int(abilities.size());i++)
|
for(int i = 0;i < int(abilities.size());i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(choice == i)
|
if(choice == i)
|
||||||
mClone = abilities[choice]->clone();
|
mClone = abilities[choice]->clone();
|
||||||
else
|
else if(!optionalCosts.size())
|
||||||
SAFE_DELETE(abilities[i]);
|
SAFE_DELETE(abilities[i]);
|
||||||
//else
|
if (mClone && !toPay && optionalCosts.size() && i < int(optionalCosts.size()) && optionalCosts[i])//paidability only supports the first ability as paid for now.
|
||||||
// abilities[i]->clone();//all get cloned for clean up purposes. EDIT:removed, cause memleaks.
|
{
|
||||||
|
toPay = NEW ManaCost();
|
||||||
|
if(optionalCosts[i]->extraCosts)
|
||||||
|
toPay->extraCosts = optionalCosts[i]->extraCosts->clone();
|
||||||
|
toPay->addExtraCost(NEW extraManaCost(optionalCosts[i]));
|
||||||
|
toPay->setExtraCostsAction(this,source);
|
||||||
|
game->mExtraPayment = toPay->extraCosts;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!mClone)
|
if(!mClone)
|
||||||
{
|
{
|
||||||
@@ -3353,15 +3524,7 @@ int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
mClone->target = abilities[choice]->target;
|
mClone->target = abilities[choice]->target;
|
||||||
mClone->oneShot = true;
|
processAbility();
|
||||||
mClone->forceDestroy = 1;
|
|
||||||
mClone->canBeInterrupted = false;
|
|
||||||
mClone->resolve();
|
|
||||||
SAFE_DELETE(mClone);
|
|
||||||
if (source->controller() == game->isInterrupting)
|
|
||||||
game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
|
|
||||||
this->forceDestroy = 1;
|
|
||||||
removeMenu = true;
|
|
||||||
return reactToTargetClick(object);
|
return reactToTargetClick(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3374,6 +3537,7 @@ MenuAbility * MenuAbility::clone() const
|
|||||||
for(int i = 0;i < int(abilities.size());i++)
|
for(int i = 0;i < int(abilities.size());i++)
|
||||||
{
|
{
|
||||||
a->abilities.push_back(abilities[i]->clone());
|
a->abilities.push_back(abilities[i]->clone());
|
||||||
|
a->optionalCosts.push_back(NEW ManaCost(optionalCosts[i]));
|
||||||
a->abilities[i]->target = abilities[i]->target;
|
a->abilities[i]->target = abilities[i]->target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3399,6 +3563,15 @@ MenuAbility::~MenuAbility()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
SAFE_DELETE(ability);
|
SAFE_DELETE(ability);
|
||||||
|
if(optionalCosts.size())
|
||||||
|
for(int i = 0;i < int(optionalCosts.size());i++)
|
||||||
|
{
|
||||||
|
if(optionalCosts[i])
|
||||||
|
{
|
||||||
|
SAFE_DELETE(optionalCosts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
//MultiAbility : triggers several actions for a cost
|
//MultiAbility : triggers several actions for a cost
|
||||||
@@ -5148,6 +5321,211 @@ AAConnect * AAConnect::clone() const
|
|||||||
return NEW AAConnect(*this);
|
return NEW AAConnect(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// casting a card for free, or casting a copy of a card.
|
||||||
|
AACastCard::AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool _restricted,bool _copied,bool asNormal,string _namedCard,string _name,bool _noEvent) :
|
||||||
|
MTGAbility(observer, _id, _source),restricted(_restricted),asCopy(_copied),normal(asNormal),cardNamed(_namedCard),nameThis(_name),noEvent(_noEvent)
|
||||||
|
{
|
||||||
|
target = _target;
|
||||||
|
andAbility = NULL;
|
||||||
|
processed = false;
|
||||||
|
theNamedCard = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AACastCard::Update(float dt)
|
||||||
|
{
|
||||||
|
MTGAbility::Update(dt);
|
||||||
|
if (processed)
|
||||||
|
return;
|
||||||
|
if(cardNamed.size() && !theNamedCard)
|
||||||
|
{
|
||||||
|
theNamedCard = makeCard();
|
||||||
|
}
|
||||||
|
if (restricted)
|
||||||
|
{
|
||||||
|
MTGCardInstance * toCheck = (MTGCardInstance*)target;
|
||||||
|
if(theNamedCard)
|
||||||
|
toCheck = theNamedCard;
|
||||||
|
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(toCheck, source->controller()->game->stack) == PlayRestriction::CANT_PLAY)
|
||||||
|
{
|
||||||
|
processed = true;
|
||||||
|
this->forceDestroy = 1;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
if(!allowedToCast(toCheck,source->controller()))
|
||||||
|
{
|
||||||
|
processed = true;
|
||||||
|
this->forceDestroy = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!toCheck->hasType(Subtypes::TYPE_INSTANT) && !(game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
|
||||||
|
{
|
||||||
|
processed = true;
|
||||||
|
this->forceDestroy = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MTGCardInstance * toCheck = (MTGCardInstance*)target;
|
||||||
|
if(theNamedCard)
|
||||||
|
toCheck = theNamedCard;
|
||||||
|
if (Spell * checkSpell = dynamic_cast<Spell*>(target))
|
||||||
|
{
|
||||||
|
toCheck = checkSpell->source;
|
||||||
|
}
|
||||||
|
if (!game->targetListIsSet(toCheck))
|
||||||
|
{
|
||||||
|
if(game->targetChooser)
|
||||||
|
game->targetChooser->Owner = source->controller();//sources controller is the caster
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolveSpell();
|
||||||
|
this->forceDestroy = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int AACastCard::isReactingToTargetClick(Targetable * card){return 0;}
|
||||||
|
int AACastCard::reactToTargetClick(Targetable * object)
|
||||||
|
{
|
||||||
|
if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
|
||||||
|
return reactToClick(cObject);
|
||||||
|
|
||||||
|
if (waitingForAnswer)
|
||||||
|
{
|
||||||
|
if (tc->toggleTarget(object) == TARGET_OK_FULL)
|
||||||
|
{
|
||||||
|
waitingForAnswer = 0;
|
||||||
|
game->mLayers->actionLayer()->setCurrentWaitingAction(NULL);
|
||||||
|
return MTGAbility::reactToClick(source);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTGCardInstance * AACastCard::makeCard()
|
||||||
|
{
|
||||||
|
MTGCardInstance * card = NULL;
|
||||||
|
MTGCard * cardData = MTGCollection()->getCardByName(cardNamed);
|
||||||
|
card = NEW MTGCardInstance(cardData, source->controller()->game);
|
||||||
|
source->controller()->game->temp->addCard(card);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AACastCard::resolveSpell()
|
||||||
|
{
|
||||||
|
if (processed)
|
||||||
|
return 0;
|
||||||
|
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||||
|
if(theNamedCard)
|
||||||
|
_target = theNamedCard;
|
||||||
|
if (Spell * checkSpell = dynamic_cast<Spell*>(target))
|
||||||
|
{
|
||||||
|
_target = checkSpell->source;
|
||||||
|
}
|
||||||
|
if(asCopy)
|
||||||
|
{
|
||||||
|
MTGCard * cardToCopy = MTGCollection()->getCardById(_target->getId());
|
||||||
|
MTGCardInstance * myDummy = NULL;
|
||||||
|
myDummy = NEW MTGCardInstance(cardToCopy, source->controller()->game);
|
||||||
|
source->controller()->game->garbage->addCard(myDummy);
|
||||||
|
_target = myDummy;
|
||||||
|
_target->isToken = 1;
|
||||||
|
_target->changeController(source->controller(),true);
|
||||||
|
}
|
||||||
|
if (_target)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_target->isLand())
|
||||||
|
{
|
||||||
|
MTGCardInstance * copy = _target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->temp,noEvent);
|
||||||
|
copy->changeController(source->controller(),true);
|
||||||
|
Spell * spell = NEW Spell(game, 0,copy,NULL,NULL, 1);
|
||||||
|
spell->resolve();
|
||||||
|
delete spell;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Spell * spell = NULL;
|
||||||
|
MTGCardInstance * copy = NULL;
|
||||||
|
if (normal ||(!_target->hasType(Subtypes::TYPE_INSTANT) && !_target->hasType(Subtypes::TYPE_SORCERY)))
|
||||||
|
{
|
||||||
|
copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->stack,noEvent);
|
||||||
|
copy->changeController(source->controller(),true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
copy =_target->controller()->game->putInZone(_target, _target->currentZone, _target->controller()->game->stack,noEvent);
|
||||||
|
copy->changeController(source->controller(),true);
|
||||||
|
}
|
||||||
|
if (game->targetChooser)
|
||||||
|
{
|
||||||
|
game->targetChooser->Owner = source->controller();
|
||||||
|
spell = game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL, 1, 0);
|
||||||
|
game->targetChooser = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spell = game->mLayers->stackLayer()->addSpell(copy, NULL, NULL, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy->has(Constants::STORM))
|
||||||
|
{
|
||||||
|
int storm = _target->controller()->game->stack->seenThisTurn("*", Constants::CAST_ALL) + source->controller()->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL);
|
||||||
|
|
||||||
|
for (int i = storm; i > 1; i--)
|
||||||
|
{
|
||||||
|
spell = game->mLayers->stackLayer()->addSpell(copy, NULL, 0, 1, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!copy->has(Constants::STORM))
|
||||||
|
{
|
||||||
|
copy->X = 0;
|
||||||
|
copy->castX = copy->X;
|
||||||
|
}
|
||||||
|
if(andAbility)
|
||||||
|
{
|
||||||
|
MTGAbility * andAbilityClone = andAbility->clone();
|
||||||
|
andAbilityClone->target = copy;
|
||||||
|
if(andAbility->oneShot)
|
||||||
|
{
|
||||||
|
andAbilityClone->resolve();
|
||||||
|
SAFE_DELETE(andAbilityClone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
andAbilityClone->addToGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->forceDestroy = true;
|
||||||
|
processed = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * AACastCard::getMenuText()
|
||||||
|
{
|
||||||
|
if(nameThis.size())
|
||||||
|
return nameThis.c_str();
|
||||||
|
return "Cast For Free";
|
||||||
|
}
|
||||||
|
|
||||||
|
AACastCard * AACastCard::clone() const
|
||||||
|
{
|
||||||
|
AACastCard * a = NEW AACastCard(*this);
|
||||||
|
if(tc)
|
||||||
|
a->tc = tc->clone();
|
||||||
|
if(andAbility)
|
||||||
|
a->andAbility = andAbility->clone();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
AACastCard::~AACastCard()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(tc);
|
||||||
|
SAFE_DELETE(andAbility);
|
||||||
|
}
|
||||||
|
|
||||||
//Tutorial Messaging
|
//Tutorial Messaging
|
||||||
|
|
||||||
ATutorialMessage::ATutorialMessage(GameObserver* observer, MTGCardInstance * source, string message, int limit)
|
ATutorialMessage::ATutorialMessage(GameObserver* observer, MTGCardInstance * source, string message, int limit)
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ int Counters::removeCounter(const char * _name, int _power, int _toughness)
|
|||||||
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
|
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
|
||||||
g->receiveEvent(e);
|
g->receiveEvent(e);
|
||||||
//special case:if a card is suspended and no longer has a time counter when the last is removed, the card is cast.
|
//special case:if a card is suspended and no longer has a time counter when the last is removed, the card is cast.
|
||||||
|
|
||||||
if (target->suspended && !target->counters->hasCounter("time",0,0))
|
if (target->suspended && !target->counters->hasCounter("time",0,0))
|
||||||
{
|
{
|
||||||
GameObserver * game = target->getObserver();
|
GameObserver * game = target->getObserver();
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ void DeckStats::save(const std::string& filename)
|
|||||||
playerDeckMeta->setColorIndex( manaColorIndex );
|
playerDeckMeta->setColorIndex( manaColorIndex );
|
||||||
}
|
}
|
||||||
file << "MANA:" << manaColorIndex << endl;
|
file << "MANA:" << manaColorIndex << endl;
|
||||||
|
if(file)
|
||||||
for (it = stats.begin(); it != stats.end(); it++)
|
for (it = stats.begin(); it != stats.end(); it++)
|
||||||
{
|
{
|
||||||
sprintf(writer, "%s\n", it->first.c_str());
|
sprintf(writer, "%s\n", it->first.c_str());
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
SUPPORT_OBJECT_ANALYTICS(ExtraCost)
|
SUPPORT_OBJECT_ANALYTICS(ExtraCost)
|
||||||
|
|
||||||
ExtraCost::ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc)
|
ExtraCost::ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc, ManaCost * _costToPay)
|
||||||
: tc(_tc), source(NULL), target(NULL), mCostRenderString(inCostRenderString)
|
: tc(_tc),costToPay(_costToPay), source(NULL), target(NULL), mCostRenderString(inCostRenderString)
|
||||||
{
|
{
|
||||||
if (tc)
|
if (tc)
|
||||||
tc->targetter = NULL;
|
tc->targetter = NULL;
|
||||||
@@ -19,6 +19,7 @@ ExtraCost::ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc)
|
|||||||
|
|
||||||
ExtraCost::~ExtraCost()
|
ExtraCost::~ExtraCost()
|
||||||
{
|
{
|
||||||
|
SAFE_DELETE(costToPay);
|
||||||
SAFE_DELETE(tc);
|
SAFE_DELETE(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +62,56 @@ int ExtraCost::setPayment(MTGCardInstance * card)
|
|||||||
target = card;
|
target = card;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (costToPay && source->controller()->getManaPool()->canAfford(costToPay))
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
//extra added manacost, or add a manacost as the cost of extra
|
||||||
|
extraManaCost * extraManaCost::clone() const
|
||||||
|
{
|
||||||
|
extraManaCost * ec = NEW extraManaCost(*this);
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
extraManaCost::extraManaCost(ManaCost * costToPay)
|
||||||
|
: ExtraCost("Pay The Cost",NULL, costToPay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int extraManaCost::tryToSetPayment(MTGCardInstance * card)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int extraManaCost::isPaymentSet()
|
||||||
|
{
|
||||||
|
if (!source->controller()->getManaPool()->canAfford(costToPay))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int extraManaCost::canPay()
|
||||||
|
{
|
||||||
|
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||||
|
if(!source->controller()->getManaPool()->canAfford(costToPay))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int extraManaCost::doPay()
|
||||||
|
{
|
||||||
|
if (!source->controller()->getManaPool()->canAfford(costToPay))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
source->controller()->getManaPool()->pay(costToPay);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//life cost
|
//life cost
|
||||||
LifeCost * LifeCost::clone() const
|
LifeCost * LifeCost::clone() const
|
||||||
|
|||||||
@@ -564,6 +564,7 @@ void GameObserver::Update(float dt)
|
|||||||
if(getCurrentTargetChooser()->Owner != currentlyActing())
|
if(getCurrentTargetChooser()->Owner != currentlyActing())
|
||||||
{
|
{
|
||||||
player = getCurrentTargetChooser()->Owner;
|
player = getCurrentTargetChooser()->Owner;
|
||||||
|
isInterrupting = player;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentActionPlayer = player;
|
currentActionPlayer = player;
|
||||||
@@ -1273,8 +1274,12 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object, bool lo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extraManaCost * costType = NULL;
|
||||||
|
if( mExtraPayment && mExtraPayment->costs.size())
|
||||||
|
costType = dynamic_cast<extraManaCost*>(mExtraPayment->costs[0]);
|
||||||
|
|
||||||
if (WaitForExtraPayment(card)) {
|
if (WaitForExtraPayment(card) && !costType)
|
||||||
|
{
|
||||||
toReturn = 1;
|
toReturn = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1716,7 +1716,7 @@ void GameStateDuel::OnScroll(int inXVelocity, int inYVelocity)
|
|||||||
if (abs(inXVelocity) > 300)
|
if (abs(inXVelocity) > 300)
|
||||||
{
|
{
|
||||||
bool flickLeft = (inYVelocity > 0);
|
bool flickLeft = (inYVelocity > 0);
|
||||||
if(flickLeft)
|
if(flickLeft && OptionClosedHand::INVISIBLE == options[Options::CLOSEDHAND].number)
|
||||||
{
|
{
|
||||||
JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_PREV : JGE_BTN_NEXT);
|
JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_PREV : JGE_BTN_NEXT);
|
||||||
mEngine->HoldKey_NoRepeat(trigger);
|
mEngine->HoldKey_NoRepeat(trigger);
|
||||||
|
|||||||
+182
-29
@@ -337,26 +337,80 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe
|
|||||||
check = restriction[i].find("miracle");
|
check = restriction[i].find("miracle");
|
||||||
if(check != string::npos)
|
if(check != string::npos)
|
||||||
{
|
{
|
||||||
if(!card->miracle)
|
if(observer->turn < 1 && card->controller()->drawCounter < 1)
|
||||||
|
return 0;
|
||||||
|
if(card->previous && !card->previous->miracle)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
check = restriction[i].find("prowl");
|
check = restriction[i].find("prowl");
|
||||||
if(check != string::npos)
|
if(check != string::npos)
|
||||||
{
|
{
|
||||||
|
vector<string>typeToCheck = parseBetween(restriction[i],"prowl(",")");
|
||||||
bool isProwled = false;
|
bool isProwled = false;
|
||||||
for (size_t i = 0; i < card->controller()->prowledTypes.size(); ++i)
|
if(typeToCheck.size())
|
||||||
{
|
{
|
||||||
if ( card->hasSubtype( card->controller()->prowledTypes[i] ))
|
vector<string>splitTypes = split(typeToCheck[1],' ');
|
||||||
|
if(splitTypes.size())
|
||||||
{
|
{
|
||||||
isProwled = true;
|
for (size_t k = 0; k < splitTypes.size(); ++k)
|
||||||
break;
|
{
|
||||||
|
string theType = splitTypes[k];
|
||||||
|
for (size_t j = 0; j < card->controller()->prowledTypes.size(); ++j)
|
||||||
|
{
|
||||||
|
if ( card->controller()->prowledTypes[j] == splitTypes[k])
|
||||||
|
{
|
||||||
|
isProwled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < card->controller()->prowledTypes.size(); ++j)
|
||||||
|
{
|
||||||
|
if ( card->controller()->prowledTypes[j] == typeToCheck[1])
|
||||||
|
{
|
||||||
|
isProwled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < card->controller()->prowledTypes.size(); ++j)
|
||||||
|
{
|
||||||
|
if ( card->hasSubtype( card->controller()->prowledTypes[j] ))
|
||||||
|
{
|
||||||
|
isProwled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!isProwled)
|
if(!isProwled)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check = restriction[i].find("spent(");
|
||||||
|
if(check != string::npos)
|
||||||
|
{
|
||||||
|
vector<string>spentMana = parseBetween(restriction[i],"spent(",")");
|
||||||
|
if(spentMana.size())
|
||||||
|
{
|
||||||
|
ManaCost * costToCheck = ManaCost::parseManaCost(restriction[i]);
|
||||||
|
ManaCost * spent = card->getManaCost()->manaUsedToCast;
|
||||||
|
if(spent && costToCheck && !spent->canAfford(costToCheck))
|
||||||
|
{
|
||||||
|
SAFE_DELETE(costToCheck);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SAFE_DELETE(costToCheck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
check = restriction[i].find("ownerscontrol");
|
check = restriction[i].find("ownerscontrol");
|
||||||
if(check != string::npos)
|
if(check != string::npos)
|
||||||
{
|
{
|
||||||
@@ -1104,6 +1158,19 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
//actual abilities, this is a limitation.
|
//actual abilities, this is a limitation.
|
||||||
string unchangedS = "";
|
string unchangedS = "";
|
||||||
unchangedS.append(s);
|
unchangedS.append(s);
|
||||||
|
found = s.find("pay(");
|
||||||
|
if (found != string::npos && storedPayString.empty())
|
||||||
|
{
|
||||||
|
vector<string> splitMayPaystr = parseBetween(s, "pay(", ")", true);
|
||||||
|
if(splitMayPaystr.size())
|
||||||
|
{
|
||||||
|
storedPayString.append(splitMayPaystr[2]);
|
||||||
|
s = splitMayPaystr[0];
|
||||||
|
s.append("pay(");
|
||||||
|
s.append(splitMayPaystr[1]);
|
||||||
|
s.append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
found = s.find("transforms((");
|
found = s.find("transforms((");
|
||||||
if (found != string::npos && storedString.empty())
|
if (found != string::npos && storedString.empty())
|
||||||
{
|
{
|
||||||
@@ -1133,6 +1200,20 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found = s.find("pay[[");
|
||||||
|
if (found != string::npos && storedPayString.empty())
|
||||||
|
{
|
||||||
|
vector<string> splitMayPaystr = parseBetween(s, "pay[[", " ", true);
|
||||||
|
if(splitMayPaystr.size())
|
||||||
|
{
|
||||||
|
storedPayString.append(splitMayPaystr[2]);
|
||||||
|
s = splitMayPaystr[0];
|
||||||
|
s.append("pay[[");
|
||||||
|
s.append(splitMayPaystr[1]);
|
||||||
|
s.append("]]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
found = s.find("and!(");
|
found = s.find("and!(");
|
||||||
if (found != string::npos && found + 6 != ')' && storedAndAbility.empty())
|
if (found != string::npos && found + 6 != ')' && storedAndAbility.empty())
|
||||||
{
|
{
|
||||||
@@ -1377,29 +1458,26 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//may pay ability
|
||||||
|
vector<string> splitMayPay = parseBetween(s, "pay(", ")", true);
|
||||||
|
if(splitMayPay.size())
|
||||||
|
{
|
||||||
|
MTGAbility * a1 = NULL;
|
||||||
|
GenericPaidAbility * a = NEW GenericPaidAbility(observer, id, card, target,newName,castRestriction,splitMayPay[1],storedPayString);
|
||||||
|
a->oneShot = 1;
|
||||||
|
a->canBeInterrupted = false;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
//When...comes into play, you may...
|
//When...comes into play, you may...
|
||||||
//When...comes into play, choose one...
|
//When...comes into play, choose one...
|
||||||
const string mayKeywords[] = {"may ", "choice "};
|
const string mayKeywords[] = {"may ", "choice "};
|
||||||
const bool mayMust[] = { false, true };
|
const bool mayMust[] = { false, true };
|
||||||
ManaCost * mayCost = NULL;
|
|
||||||
for (size_t i =0; i < sizeof(mayMust)/sizeof(mayMust[0]); ++i)
|
for (size_t i =0; i < sizeof(mayMust)/sizeof(mayMust[0]); ++i)
|
||||||
{
|
{
|
||||||
if (sWithoutTc.find(mayKeywords[i]) == 0)
|
if (sWithoutTc.find(mayKeywords[i]) == 0)
|
||||||
{
|
{
|
||||||
string s1 = sWithoutTc.substr(mayKeywords[i].length());
|
string s1 = sWithoutTc.substr(mayKeywords[i].length());
|
||||||
MTGAbility * a1 = NULL;
|
MTGAbility * a1 = parseMagicLine(s1, id, spell, card);
|
||||||
//may pay a cost for this ability
|
|
||||||
vector<string> splitMayPay = parseBetween(s1, "pay(", ")", true);
|
|
||||||
if(splitMayPay.size())
|
|
||||||
{
|
|
||||||
a1 = parseMagicLine(splitMayPay[2], id, spell, card);
|
|
||||||
mayCost = ManaCost::parseManaCost(splitMayPay[1], NULL, card);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a1 = parseMagicLine(s1, id, spell, card);
|
|
||||||
}
|
|
||||||
if (!a1)
|
if (!a1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -1408,8 +1486,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
else
|
else
|
||||||
a1 = NEW GenericActivatedAbility(observer, newName,castRestriction,id, card, a1, NULL);
|
a1 = NEW GenericActivatedAbility(observer, newName,castRestriction,id, card, a1, NULL);
|
||||||
MayAbility * mainAbility = NEW MayAbility(observer, id, a1, card,mayMust[i],castRestriction);
|
MayAbility * mainAbility = NEW MayAbility(observer, id, a1, card,mayMust[i],castRestriction);
|
||||||
if(mayCost)
|
|
||||||
mainAbility->optionalCost = mayCost;
|
|
||||||
return mainAbility;
|
return mainAbility;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1424,6 +1500,17 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
return NEW GenericInstantAbility(observer, 1, card, (Damageable *) target, a1);
|
return NEW GenericInstantAbility(observer, 1, card, (Damageable *) target, a1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add an ability to the game, this is the "addToGame" version of the above ability.
|
||||||
|
if (s.find("activate ") == 0 || s.find(" activate ") == 0)
|
||||||
|
{
|
||||||
|
string s1 = s.substr(9);
|
||||||
|
MTGAbility * a1 = parseMagicLine(s1, id, spell, card);
|
||||||
|
if (!a1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return NEW GenericAddToGame(observer,1, card, (Damageable *) target,a1);
|
||||||
|
}
|
||||||
|
|
||||||
// neverending effect
|
// neverending effect
|
||||||
if (s.find("emblem ") == 0)
|
if (s.find("emblem ") == 0)
|
||||||
{
|
{
|
||||||
@@ -1876,7 +1963,16 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
a->canBeInterrupted = false;
|
a->canBeInterrupted = false;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
//may pay ability
|
||||||
|
vector<string> splitMayPaysub = parseBetween(s, "pay[[","]]", true);
|
||||||
|
if(splitMayPaysub.size())
|
||||||
|
{
|
||||||
|
MTGAbility * a1 = NULL;
|
||||||
|
GenericPaidAbility * a = NEW GenericPaidAbility(observer, id, card, target,newName,castRestriction,splitMayPaysub[1],storedPayString);
|
||||||
|
a->oneShot = 1;
|
||||||
|
a->canBeInterrupted = false;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
//Upkeep Cost
|
//Upkeep Cost
|
||||||
found = s.find("upcost");
|
found = s.find("upcost");
|
||||||
if (found != string::npos)
|
if (found != string::npos)
|
||||||
@@ -2058,7 +2154,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
if (card->hasType(Subtypes::TYPE_AURA))
|
if (card->hasType(Subtypes::TYPE_AURA))
|
||||||
target = card;
|
target = card;
|
||||||
|
|
||||||
MTGAbility * a = NEW AAMover(observer, id, card, target, splitMove[1]);
|
MTGAbility * a = NEW AAMover(observer, id, card, target, splitMove[1],newName);
|
||||||
a->oneShot = true;
|
a->oneShot = true;
|
||||||
if(storedAndAbility.size())
|
if(storedAndAbility.size())
|
||||||
{
|
{
|
||||||
@@ -2182,6 +2278,46 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cast a card without paying it's manacost
|
||||||
|
vector<string> splitCastCard = parseBetween(s, "castcard(", ")");
|
||||||
|
if (splitCastCard.size())
|
||||||
|
{
|
||||||
|
string builtHow = splitCastCard[1];
|
||||||
|
bool withRestrictions = splitCastCard[1].find("restricted") != string::npos;
|
||||||
|
bool asCopy = splitCastCard[1].find("copied") != string::npos;
|
||||||
|
bool asNormal = splitCastCard[1].find("normal") != string::npos;
|
||||||
|
bool sendNoEvent = splitCastCard[1].find("noevent") != string::npos;
|
||||||
|
string nameCard = "";
|
||||||
|
if(splitCastCard[1].find("named!:") != string::npos)
|
||||||
|
{
|
||||||
|
vector<string> splitCastName = parseBetween(splitCastCard[1], "named!:", ":!");
|
||||||
|
if(splitCastName.size())
|
||||||
|
{
|
||||||
|
nameCard = splitCastName[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MTGAbility *a = NEW AACastCard(observer, id, card, target,withRestrictions,asCopy,asNormal,nameCard,newName,sendNoEvent);
|
||||||
|
a->oneShot = false;
|
||||||
|
if(splitCastCard[1].find("trigger[to]") != string::npos)
|
||||||
|
{
|
||||||
|
a->setActionTC(NEW TriggerTargetChooser(observer, WEvent::TARGET_TO));
|
||||||
|
}
|
||||||
|
if(storedAndAbility.size())
|
||||||
|
{
|
||||||
|
string stored = storedAndAbility;
|
||||||
|
storedAndAbility.clear();
|
||||||
|
((AACastCard*)a)->andAbility = parseMagicLine(stored, id, spell, card);
|
||||||
|
}
|
||||||
|
MTGCardInstance * _target = NULL;
|
||||||
|
if (spell)
|
||||||
|
_target = spell->getNextCardTarget();
|
||||||
|
if(!_target)
|
||||||
|
_target = target;
|
||||||
|
a->target = _target;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
bool oneShot = false;
|
bool oneShot = false;
|
||||||
bool forceForever = false;
|
bool forceForever = false;
|
||||||
bool untilYourNextTurn = false;
|
bool untilYourNextTurn = false;
|
||||||
@@ -2244,7 +2380,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
found = s.find("donothing");
|
found = s.find("donothing");
|
||||||
if (found != string::npos)
|
if (found != string::npos)
|
||||||
{
|
{
|
||||||
MTGAbility * a = NEW AAFakeAbility(observer, id, card, target);
|
|
||||||
|
MTGAbility * a = NEW AAFakeAbility(observer, id, card, target,newName);
|
||||||
a->oneShot = 1;
|
a->oneShot = 1;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -4106,18 +4243,26 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
|
|||||||
|
|
||||||
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY))
|
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY))
|
||||||
{
|
{
|
||||||
MTGPlayerCards * zones = card->controller()->game;
|
MTGPlayerCards * zones = card->owner->game;
|
||||||
if (card->alternateCostPaid[ManaCost::MANA_PAID_WITH_BUYBACK] > 0)
|
if(card->getCurrentZone())
|
||||||
|
card->currentZone->owner->game;//grab it from where ever it is.
|
||||||
|
MTGPlayerCards * Endzones = card->owner->game;//put them in thier owners respective zones as per rules.
|
||||||
|
if (card->basicAbilities[(int)Constants::EXILEDEATH])
|
||||||
{
|
{
|
||||||
zones->putInZone(card, zones->stack, zones->hand);
|
card->owner->game->putInZone(card, card->getCurrentZone(), card->owner->game->exile);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (card->alternateCostPaid[ManaCost::MANA_PAID_WITH_BUYBACK] > 0)
|
||||||
|
{
|
||||||
|
zones->putInZone(card, zones->stack, Endzones->hand);
|
||||||
}
|
}
|
||||||
else if (card->alternateCostPaid[ManaCost::MANA_PAID_WITH_FLASHBACK] > 0)
|
else if (card->alternateCostPaid[ManaCost::MANA_PAID_WITH_FLASHBACK] > 0)
|
||||||
{
|
{
|
||||||
zones->putInZone(card, zones->stack, zones->exile);
|
zones->putInZone(card, zones->stack, Endzones->exile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zones->putInZone(card, zones->stack, zones->graveyard);
|
zones->putInZone(card, zones->stack, Endzones->graveyard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4763,6 +4908,14 @@ int TriggeredAbility::receiveEvent(WEvent * e)
|
|||||||
//that resolves instantly before the event that targetted it.
|
//that resolves instantly before the event that targetted it.
|
||||||
resolve();
|
resolve();
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
WEventZoneChange * stackCheck = dynamic_cast<WEventZoneChange*>(e);
|
||||||
|
if(stackCheck && (stackCheck->to == game->currentPlayer->game->stack||stackCheck->to == game->currentPlayer->opponent()->game->stack))
|
||||||
|
{
|
||||||
|
resolve();
|
||||||
|
return 1;
|
||||||
|
//triggers that resolve from stack events must resolve instantly or by the time they do the cards that triggered them
|
||||||
|
//have already been put in play or graveyard.
|
||||||
}
|
}
|
||||||
fireAbility();
|
fireAbility();
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -541,8 +541,13 @@ int MTGCardInstance::hasSummoningSickness()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTGCardInstance * MTGCardInstance::changeController(Player * newController)
|
MTGCardInstance * MTGCardInstance::changeController(Player * newController,bool notZone)
|
||||||
{
|
{
|
||||||
|
if(notZone)
|
||||||
|
{
|
||||||
|
lastController = newController;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
Player * originalOwner = controller();
|
Player * originalOwner = controller();
|
||||||
MTGCardInstance * copy = originalOwner->game->putInZone(this, this->currentZone, newController->game->inPlay);
|
MTGCardInstance * copy = originalOwner->game->putInZone(this, this->currentZone, newController->game->inPlay);
|
||||||
copy->summoningSickness = 1;
|
copy->summoningSickness = 1;
|
||||||
|
|||||||
@@ -222,6 +222,11 @@ void MTGPlayerCards::drawFromLibrary()
|
|||||||
}
|
}
|
||||||
MTGCardInstance * toMove = library->cards[library->nb_cards - 1];
|
MTGCardInstance * toMove = library->cards[library->nb_cards - 1];
|
||||||
library->lastCardDrawn = toMove;
|
library->lastCardDrawn = toMove;
|
||||||
|
if (!library->miracle)
|
||||||
|
{
|
||||||
|
library->miracle = true;
|
||||||
|
toMove->miracle = true;
|
||||||
|
}
|
||||||
|
|
||||||
// useability tweak - assume that the user is probably going to want to see the new card,
|
// useability tweak - assume that the user is probably going to want to see the new card,
|
||||||
// so prefetch it.
|
// so prefetch it.
|
||||||
@@ -243,12 +248,7 @@ void MTGPlayerCards::drawFromLibrary()
|
|||||||
if(putInZone(toMove, library, hand))
|
if(putInZone(toMove, library, hand))
|
||||||
{
|
{
|
||||||
toMove->currentZone = hand;
|
toMove->currentZone = hand;
|
||||||
if (!library->miracle)
|
|
||||||
{
|
|
||||||
library->miracle = true;
|
|
||||||
toMove->miracle = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTGPlayerCards::resetLibrary()
|
void MTGPlayerCards::resetLibrary()
|
||||||
@@ -285,6 +285,11 @@ void MTGPlayerCards::showHand()
|
|||||||
// Moves a card to its owner's graveyard
|
// Moves a card to its owner's graveyard
|
||||||
MTGCardInstance * MTGPlayerCards::putInGraveyard(MTGCardInstance * card)
|
MTGCardInstance * MTGPlayerCards::putInGraveyard(MTGCardInstance * card)
|
||||||
{
|
{
|
||||||
|
if (card->basicAbilities[(int)Constants::EXILEDEATH])
|
||||||
|
{
|
||||||
|
putInZone(card, card->getCurrentZone(), card->owner->game->exile);
|
||||||
|
|
||||||
|
}
|
||||||
return putInZone(card, card->currentZone, card->owner->game->graveyard);
|
return putInZone(card, card->currentZone, card->owner->game->graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +313,7 @@ MTGCardInstance * MTGPlayerCards::putInHand(MTGCardInstance * card)
|
|||||||
|
|
||||||
// Moves a card from one zone to another
|
// Moves a card from one zone to another
|
||||||
// If the card is not actually in the expected "from" zone, does nothing and returns null
|
// If the card is not actually in the expected "from" zone, does nothing and returns null
|
||||||
MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to)
|
MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to,bool asCopy)
|
||||||
{
|
{
|
||||||
MTGCardInstance * copy = NULL;
|
MTGCardInstance * copy = NULL;
|
||||||
GameObserver *g = owner->getObserver();
|
GameObserver *g = owner->getObserver();
|
||||||
@@ -325,7 +330,10 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
|
|||||||
|
|
||||||
if (!(copy = from->removeCard(card, doCopy)))
|
if (!(copy = from->removeCard(card, doCopy)))
|
||||||
return NULL; //ERROR
|
return NULL; //ERROR
|
||||||
|
if (card->miracle)
|
||||||
|
{
|
||||||
|
copy->miracle = true;
|
||||||
|
}
|
||||||
if (options[Options::SFXVOLUME].number > 0)
|
if (options[Options::SFXVOLUME].number > 0)
|
||||||
{
|
{
|
||||||
if (to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard)
|
if (to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard)
|
||||||
@@ -374,8 +382,11 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
|
|||||||
SAFE_DELETE(previous);
|
SAFE_DELETE(previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!asCopy)
|
||||||
|
{
|
||||||
WEvent * e = NEW WEventZoneChange(copy, from, to);
|
WEvent * e = NEW WEventZoneChange(copy, from, to);
|
||||||
g->receiveEvent(e);
|
g->receiveEvent(e);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -690,8 +690,8 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter
|
|||||||
|
|
||||||
assert(alternateCost);
|
assert(alternateCost);
|
||||||
if (alternateCost->isExtraPaymentSet() )
|
if (alternateCost->isExtraPaymentSet() )
|
||||||
{
|
{
|
||||||
if (!game->targetListIsSet(card))
|
if (!game->targetListIsSet(card))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2457,7 +2457,7 @@ int MTGLegendRule::canBeInList(MTGCardInstance * card)
|
|||||||
{
|
{
|
||||||
if(card->isPhased)
|
if(card->isPhased)
|
||||||
return 0;
|
return 0;
|
||||||
if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->isInPlay(card))
|
if (card->hasType(Subtypes::TYPE_LEGENDARY) && card->controller()->game->inPlay->hasCard(card))
|
||||||
{
|
{
|
||||||
if(card->has(Constants::NOLEGEND))
|
if(card->has(Constants::NOLEGEND))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2471,18 +2471,38 @@ int MTGLegendRule::added(MTGCardInstance * card)
|
|||||||
{
|
{
|
||||||
map<MTGCardInstance *, bool>::iterator it;
|
map<MTGCardInstance *, bool>::iterator it;
|
||||||
int destroy = 0;
|
int destroy = 0;
|
||||||
|
|
||||||
|
vector<MTGCardInstance*>oldCards;
|
||||||
for (it = cards.begin(); it != cards.end(); it++)
|
for (it = cards.begin(); it != cards.end(); it++)
|
||||||
{
|
{
|
||||||
MTGCardInstance * comparison = (*it).first;
|
MTGCardInstance * comparison = (*it).first;
|
||||||
if (comparison != card && !(comparison->getName().compare(card->getName())))
|
if (comparison != card && comparison->controller() == card->controller() && !(comparison->getName().compare(card->getName())))
|
||||||
{
|
{
|
||||||
comparison->controller()->game->putInGraveyard(comparison);
|
oldCards.push_back(comparison);
|
||||||
destroy = 1;
|
destroy = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (destroy)
|
if(destroy)
|
||||||
{
|
{
|
||||||
card->owner->game->putInGraveyard(card);
|
vector<MTGAbility*>selection;
|
||||||
|
MultiAbility * multi = NEW MultiAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card, NULL);
|
||||||
|
for(unsigned int i = 0;i < oldCards.size();i++)
|
||||||
|
{
|
||||||
|
AABuryCard *a = NEW AABuryCard(game, game->mLayers->actionLayer()->getMaxId(), card, oldCards[i]);
|
||||||
|
a->menu = "Keep New";
|
||||||
|
a->oneShot = true;
|
||||||
|
multi->Add(a);
|
||||||
|
}
|
||||||
|
multi->oneShot = 1;
|
||||||
|
MTGAbility * a1 = multi;
|
||||||
|
selection.push_back(a1);
|
||||||
|
AABuryCard *b = NEW AABuryCard(game, game->mLayers->actionLayer()->getMaxId(), card, card);
|
||||||
|
b->menu = "Keep Old";
|
||||||
|
b->oneShot = true;
|
||||||
|
MTGAbility * b1 = b;
|
||||||
|
selection.push_back(b1);
|
||||||
|
MTGAbility * menuChoice = NEW MenuAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card,true,selection,card->controller(),"Choose Legend");
|
||||||
|
menuChoice->addToGame();
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2517,7 +2537,7 @@ int MTGPlaneWalkerRule::canBeInList(MTGCardInstance * card)
|
|||||||
{
|
{
|
||||||
if(card->isPhased)
|
if(card->isPhased)
|
||||||
return 0;
|
return 0;
|
||||||
if (card->hasType(Subtypes::TYPE_PLANESWALKER) && game->isInPlay(card))
|
if (card->hasType(Subtypes::TYPE_PLANESWALKER) && card->controller()->game->inPlay->hasCard(card))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2528,18 +2548,38 @@ int MTGPlaneWalkerRule::added(MTGCardInstance * card)
|
|||||||
{
|
{
|
||||||
map<MTGCardInstance *, bool>::iterator it;
|
map<MTGCardInstance *, bool>::iterator it;
|
||||||
int destroy = 0;
|
int destroy = 0;
|
||||||
|
vector<MTGCardInstance*>oldCards;
|
||||||
for (it = cards.begin(); it != cards.end(); it++)
|
for (it = cards.begin(); it != cards.end(); it++)
|
||||||
{
|
{
|
||||||
MTGCardInstance * comparison = (*it).first;
|
MTGCardInstance * comparison = (*it).first;
|
||||||
if (comparison != card && comparison->types == card->types)
|
if (comparison != card && comparison->types == card->types && comparison->controller() == card->controller())
|
||||||
{
|
{
|
||||||
comparison->controller()->game->putInGraveyard(comparison);
|
oldCards.push_back(comparison);
|
||||||
destroy = 1;
|
destroy = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (destroy)
|
if (destroy)
|
||||||
{
|
{
|
||||||
card->owner->game->putInGraveyard(card);
|
vector<MTGAbility*>selection;
|
||||||
|
|
||||||
|
MultiAbility * multi = NEW MultiAbility(game,game->mLayers->actionLayer()->getMaxId(), card, card, NULL);
|
||||||
|
for(unsigned int i = 0;i < oldCards.size();i++)
|
||||||
|
{
|
||||||
|
AABuryCard *a = NEW AABuryCard(game, game->mLayers->actionLayer()->getMaxId(), card, oldCards[i]);
|
||||||
|
a->menu = "Keep New";
|
||||||
|
a->oneShot = true;
|
||||||
|
multi->Add(a);
|
||||||
|
}
|
||||||
|
multi->oneShot = 1;
|
||||||
|
MTGAbility * a1 = multi;
|
||||||
|
selection.push_back(a1);
|
||||||
|
AABuryCard *b = NEW AABuryCard(game, game->mLayers->actionLayer()->getMaxId(), card, card);
|
||||||
|
b->menu = "Keep Old";
|
||||||
|
b->oneShot = true;
|
||||||
|
MTGAbility * b1 = b;
|
||||||
|
selection.push_back(b1);
|
||||||
|
MTGAbility * menuChoice = NEW MenuAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card,true,selection,card->controller(),"Choose Planeswalker");
|
||||||
|
menuChoice->addToGame();
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
start = s.find_first_of("{");
|
start = s.find_first_of("{");
|
||||||
|
if(s.find_first_of("{") != string::npos && start > 0)
|
||||||
|
{
|
||||||
|
string value = s.substr(start -1,end);
|
||||||
|
if(value == "n{")//"restrictio n{m orbid} would read the n{m as {m} millcost
|
||||||
|
return manaCost;
|
||||||
|
}
|
||||||
if (start == string::npos)
|
if (start == string::npos)
|
||||||
{
|
{
|
||||||
return manaCost;
|
return manaCost;
|
||||||
@@ -323,6 +329,7 @@ ManaCost::ManaCost(ManaCost * manaCost)
|
|||||||
suspend = NEW ManaCost( manaCost->suspend );
|
suspend = NEW ManaCost( manaCost->suspend );
|
||||||
|
|
||||||
extraCosts = manaCost->extraCosts ? manaCost->extraCosts->clone() : NULL;
|
extraCosts = manaCost->extraCosts ? manaCost->extraCosts->clone() : NULL;
|
||||||
|
manaUsedToCast = NULL;
|
||||||
xColor = manaCost->xColor;
|
xColor = manaCost->xColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +357,7 @@ ManaCost::ManaCost(const ManaCost& manaCost)
|
|||||||
suspend = NEW ManaCost( manaCost.suspend );
|
suspend = NEW ManaCost( manaCost.suspend );
|
||||||
|
|
||||||
extraCosts = manaCost.extraCosts ? manaCost.extraCosts->clone() : NULL;
|
extraCosts = manaCost.extraCosts ? manaCost.extraCosts->clone() : NULL;
|
||||||
|
manaUsedToCast = NULL;
|
||||||
xColor = manaCost.xColor;
|
xColor = manaCost.xColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,6 +378,7 @@ ManaCost & ManaCost::operator= (const ManaCost & manaCost)
|
|||||||
FlashBack = manaCost.FlashBack;
|
FlashBack = manaCost.FlashBack;
|
||||||
morph = manaCost.morph;
|
morph = manaCost.morph;
|
||||||
suspend = manaCost.suspend;
|
suspend = manaCost.suspend;
|
||||||
|
manaUsedToCast = manaCost.manaUsedToCast;
|
||||||
xColor = manaCost.xColor;
|
xColor = manaCost.xColor;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@@ -385,6 +394,7 @@ ManaCost::~ManaCost()
|
|||||||
SAFE_DELETE(Retrace);
|
SAFE_DELETE(Retrace);
|
||||||
SAFE_DELETE(morph);
|
SAFE_DELETE(morph);
|
||||||
SAFE_DELETE(suspend);
|
SAFE_DELETE(suspend);
|
||||||
|
SAFE_DELETE(manaUsedToCast);
|
||||||
|
|
||||||
cost.erase(cost.begin() ,cost.end());
|
cost.erase(cost.begin() ,cost.end());
|
||||||
}
|
}
|
||||||
@@ -468,6 +478,7 @@ void ManaCost::init()
|
|||||||
Retrace = NULL;
|
Retrace = NULL;
|
||||||
morph = NULL;
|
morph = NULL;
|
||||||
suspend = NULL;
|
suspend = NULL;
|
||||||
|
manaUsedToCast = NULL;
|
||||||
isMulti = false;
|
isMulti = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,17 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
|||||||
if (s.length() > 7 && s.find("[") == 7)
|
if (s.length() > 7 && s.find("[") == 7)
|
||||||
{
|
{
|
||||||
string s1 = s.substr(7, s.find("]"));
|
string s1 = s.substr(7, s.find("]"));
|
||||||
if (s1.find("to") != string::npos) return NEW TriggerTargetChooser(observer, WEvent::TARGET_TO);
|
if (s1.find("to") != string::npos)
|
||||||
|
{
|
||||||
|
if(s1.find("<1>") != string::npos)
|
||||||
|
{
|
||||||
|
TriggerTargetChooser * ttc = NEW TriggerTargetChooser(observer, WEvent::TARGET_TO);
|
||||||
|
ttc->maxtargets = 1;
|
||||||
|
return ttc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NEW TriggerTargetChooser(observer, WEvent::TARGET_TO);
|
||||||
|
}
|
||||||
if (s1.find("from") != string::npos) return NEW TriggerTargetChooser(observer, WEvent::TARGET_FROM);
|
if (s1.find("from") != string::npos) return NEW TriggerTargetChooser(observer, WEvent::TARGET_FROM);
|
||||||
}
|
}
|
||||||
return NEW TriggerTargetChooser(observer, 1);
|
return NEW TriggerTargetChooser(observer, 1);
|
||||||
@@ -606,6 +616,16 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attribute.find("iscolorless") != string::npos)
|
||||||
|
{
|
||||||
|
attributefound = 1;
|
||||||
|
for (int cid = 1; cid < Constants::NB_Colors; cid++)
|
||||||
|
{
|
||||||
|
cd->SetExclusionColor(cid);
|
||||||
|
}
|
||||||
|
cd->mode = CD_OR;
|
||||||
|
}
|
||||||
|
|
||||||
if (attribute.find("chosencolor") != string::npos)
|
if (attribute.find("chosencolor") != string::npos)
|
||||||
{
|
{
|
||||||
attributefound = 1;
|
attributefound = 1;
|
||||||
@@ -688,6 +708,12 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
|||||||
{
|
{
|
||||||
return NEW CardTargetChooser(observer, card, card, zones, nbzones);
|
return NEW CardTargetChooser(observer, card, card, zones, nbzones);
|
||||||
}
|
}
|
||||||
|
else if (typeName.compare("sourcecard") == 0)
|
||||||
|
{
|
||||||
|
CardTargetChooser * ctc = NEW CardTargetChooser(observer, card, card, zones, nbzones);
|
||||||
|
ctc->setAllZones();
|
||||||
|
return ctc;
|
||||||
|
}
|
||||||
else if (typeName.compare("mystored") == 0)
|
else if (typeName.compare("mystored") == 0)
|
||||||
{
|
{
|
||||||
return NEW CardTargetChooser(observer, card->storedSourceCard, card, zones, nbzones);
|
return NEW CardTargetChooser(observer, card->storedSourceCard, card, zones, nbzones);
|
||||||
@@ -1488,6 +1514,13 @@ bool TriggerTargetChooser::targetsZone(MTGGameZone *)
|
|||||||
|
|
||||||
bool TriggerTargetChooser::canTarget(Targetable * _target,bool)
|
bool TriggerTargetChooser::canTarget(Targetable * _target,bool)
|
||||||
{
|
{
|
||||||
|
//something is wrong with trigger[to] not allowing us to target stack.
|
||||||
|
if(Spell * spell = dynamic_cast<Spell *>(_target))
|
||||||
|
{
|
||||||
|
MTGCardInstance * card = spell->source;
|
||||||
|
if(card == target)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (_target == target) return true;
|
if (_target == target) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ MTGCardInstance * TargetsList::getNextCardTarget(MTGCardInstance * previous)
|
|||||||
size_t nextIndex = iterateTarget(previous);
|
size_t nextIndex = iterateTarget(previous);
|
||||||
for (size_t i = nextIndex; i < targets.size(); ++i)
|
for (size_t i = nextIndex; i < targets.size(); ++i)
|
||||||
{
|
{
|
||||||
|
if (Spell * spell = dynamic_cast<Spell *>(targets[i]))
|
||||||
|
{
|
||||||
|
if (MTGCardInstance * c = dynamic_cast<MTGCardInstance *>(spell->source))
|
||||||
|
return c;
|
||||||
|
}
|
||||||
if (MTGCardInstance * c = dynamic_cast<MTGCardInstance *>(targets[i]))
|
if (MTGCardInstance * c = dynamic_cast<MTGCardInstance *>(targets[i]))
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user