added abilities:
proliferate
ProliferateChooser:new targetchooser for cards with counter and poison counters "proliferation".

MenuAbility:new internal ability to create custom menus of abilities which can be activated in sequence one after another.

multikicker, syntax kicker=multi{b}
works with variable word "kicked", the amount of times it was kicked.

target=<number>tc,target=<upto:>tc,target=<anyamount>tc,target(<number>tc),target(<upto:>tc),target(<anynumber>tc);
multitarget is now supported with the exception of "devided any way you choose" which can not be supported becuase we allow detoggling of targeted cards with a "second" click....so you can not click the same card 2 times to add it to the targets list twice for example.
this is minor, as the bulk of multitarget is not "devided"
removed 's' parsing for multitarget, added a limit of 1000 to "unlimited" for easier handling; we currently can't handle activation of an ability on a 1000 cards very well on any platform(infact i don't suggest it)

Countershroud(counterstring), this MTGAbility allows you to denote that a card can not have counters of the type "counterstring" put on it.
"any" is for no counters allowed at all. this is a replacement effect. cards state that they can still be the targets of counter effects, however on resolve nothing is placed on them instead.

@counteradded(counterstring) from(target):,@counterremoved(counterstring) from(target):: these are triggers for cards which state "whenever you add a counter of "counterstring" to "target"; added counterEvents struct; 

other changes:
added support for ai handling of multitargeted spells.

changed a few of delete( into SAFE_DELETE(, safed up a couple areas where they did not seem safe to me;

added better handling of menus presented to ai, it will try to select the best based on eff returns.

added varible lastactioncontroller for ai use, it keeps it truely from ever tripping over itself and brings ai more inline with MTG rules.

converted TC into a protected member.
added "abilitybelongsto" string to tc, and set "owner" of the tc. a tc should never belong to "no one" it should always have a owner.
abilitybelongs to string is solely for easier debugging, i found it was a pain to never know what ability created a tc while i coded multitarget. the owner of the tc is the only one that should be using it, if an ability needs to declare the opponent as the owner (choose discard which is currently unsupported for example) this will allow us to better handle that situation by setting the tc owner in the ability which called it.

rewrote the logic of "checkonly" in ai choose targets, the only time it is "checkonly" is when it is trying to see if it had a target for a spell before it cast it, i now set this in the actual function call instead, the old method was far to error prone.

wrote logic for ai checking of menu objects presented to it,
ai will now make better choices when a menu is presented to it based on what it already knows. this changes it from it's old method of "just click the first option".

taught ai how to use multi-mana producers such as birds and duel lands by adding a method for it to find it's mana for a payment. it can effectively use cards like birds of paradise and sol ring(without locking up). It's primary method of pMana searching was maintain for performance(no need to deep search if we have it in pMana).

added a vector to actionlayer to store mana abilities for pMana. this provides us with a dramatic improvement when mana lords are present by reducing the amount of objects that need checking when ai checks pMana.
with 80 mana objects and a ton of lords one instance i checked went from 8000ish checks down to 80<===big difference.

added "tapped" green coloring(sorry i missed that!)...added red coloring to current actionLayers current action card (usually the source).

changed "type(" restrictions second amount from atoi into wparsedint for more flexiable coding.

add "&" parsing to CD targetchooser, removed "iscolorandcolor" variables and functions becuase they were a hack the real fix was this.
cretaure[dragon&black&blue] a creature that is a dragon, and black and also blue.

changed some of the ai computeactions and
removed unneeded gaurds in ai chooseblockers, they did more harm then good.
This commit is contained in:
omegablast2002@yahoo.com
2011-09-01 20:03:26 +00:00
parent 67bbaa8f06
commit 6399917d25
44 changed files with 2176 additions and 618 deletions
+26 -5
View File
@@ -34,22 +34,37 @@ public:
int id; int id;
MTGCardInstance * click; MTGCardInstance * click;
MTGCardInstance * target; // TODO Improve MTGCardInstance * target; // TODO Improve
vector<Targetable*>mAbilityTargets;
Targetable * playerAbilityTarget;
//player targeting through abilities is handled completely seperate from spell targeting.
AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL) AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL)
: efficiency(-1), ability(a), player(NULL), click(c), target(t) : efficiency(-1), ability(a), player(NULL), click(c), target(t),playerAbilityTarget(NULL)
{ {
id = currentId++; id = currentId++;
}; };
AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL); AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL);
AIAction(Player * p) AIAction(Player * p)//player targeting through spells
: efficiency(-1), ability(NULL), player(p), click(NULL), target(NULL) : efficiency(-1), ability(NULL), player(p), click(NULL), target(NULL),playerAbilityTarget(NULL)
{ {
}; };
AIAction(MTGAbility * a, MTGCardInstance * c, vector<Targetable*>targetCards)
: efficiency(-1), ability(a), player(NULL), click(c), mAbilityTargets(targetCards),playerAbilityTarget(NULL)
{
id = currentId++;
};
AIAction(MTGAbility * a, Player * p, MTGCardInstance * c)//player targeting through abilities.
: efficiency(-1), ability(a), click(c),target(NULL), playerAbilityTarget(p)
{
id = currentId++;
};
int getEfficiency(); int getEfficiency();
int Act(); int Act();
int clickMultiAct(vector<Targetable*>&actionTargets);
}; };
// compares Abilities efficiency // compares Abilities efficiency
@@ -75,7 +90,7 @@ protected:
MTGCardInstance * nextCardToPlay; MTGCardInstance * nextCardToPlay;
AIHints * hints; AIHints * hints;
queue<AIAction *> clickstream; queue<AIAction *> clickstream;
bool tapLandsForMana(ManaCost * cost, MTGCardInstance * card = NULL); bool payTheManaCost(ManaCost * cost, MTGCardInstance * card = NULL,vector<MTGAbility*> gotPayment = vector<MTGAbility*>());
int orderBlockers(); int orderBlockers();
int combatDamages(); int combatDamages();
int interruptIfICan(); int interruptIfICan();
@@ -101,10 +116,15 @@ public:
int receiveEvent(WEvent * event); int receiveEvent(WEvent * event);
void Render(); void Render();
ManaCost * getPotentialMana(MTGCardInstance * card = NULL); ManaCost * getPotentialMana(MTGCardInstance * card = NULL);
vector<MTGAbility*> canPayMana(MTGCardInstance * card = NULL,ManaCost * mCost = NULL);
vector<MTGAbility*> canPaySunBurst(ManaCost * mCost = NULL);
AIPlayer(string deckFile, string deckFileSmall, MTGDeck * deck = NULL); AIPlayer(string deckFile, string deckFileSmall, MTGDeck * deck = NULL);
virtual ~AIPlayer(); virtual ~AIPlayer();
virtual MTGCardInstance * chooseCard(TargetChooser * tc, MTGCardInstance * source, int random = 0); virtual MTGCardInstance * chooseCard(TargetChooser * tc, MTGCardInstance * source, int random = 0);
virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget =NULL,MTGCardInstance * Choosencard = NULL); virtual int selectMenuOption();
virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget =NULL,MTGCardInstance * Choosencard = NULL,bool checkonly = false);
virtual int clickMultiTarget(TargetChooser * tc,vector<Targetable*>&potentialTargets);
virtual int clickSingleTarget(TargetChooser * tc,vector<Targetable*>&potentialTargets,int nbtargets = 0,MTGCardInstance * Choosencard = NULL);
virtual int Act(float dt); virtual int Act(float dt);
virtual int affectCombatDamages(CombatStep); virtual int affectCombatDamages(CombatStep);
int isAI(){return 1;}; int isAI(){return 1;};
@@ -123,6 +143,7 @@ class AIPlayerBaka: public AIPlayer{
float timer; float timer;
MTGCardInstance * FindCardToPlay(ManaCost * potentialMana, const char * type); MTGCardInstance * FindCardToPlay(ManaCost * potentialMana, const char * type);
public: public:
vector<MTGAbility*>gotPayments;
int deckId; int deckId;
AIPlayerBaka(string deckFile, string deckfileSmall, string avatarFile, MTGDeck * deck = NULL); AIPlayerBaka(string deckFile, string deckfileSmall, string avatarFile, MTGDeck * deck = NULL);
virtual int Act(float dt); virtual int Act(float dt);
+7 -1
View File
@@ -22,8 +22,8 @@ class ActionElement: public JGuiObject
{ {
protected: protected:
int activeState; int activeState;
public:
TargetChooser * tc; TargetChooser * tc;
public:
int currentPhase; int currentPhase;
int newPhase; int newPhase;
int modal; int modal;
@@ -48,9 +48,15 @@ public:
; ;
ActionElement(int id); ActionElement(int id);
ActionElement(const ActionElement& copyFromMe); ActionElement(const ActionElement& copyFromMe);
TargetChooser * getActionTc(){return tc;}
virtual void setActionTC(TargetChooser * newTc = NULL){this->tc = newTc;}
virtual ~ActionElement(); virtual ~ActionElement();
virtual int isReactingToTargetClick(Targetable * card); virtual int isReactingToTargetClick(Targetable * card);
virtual int reactToTargetClick(Targetable * card); virtual int reactToTargetClick(Targetable * card);
virtual int reactToChoiceClick(Targetable * card,int choice = 0,int controlid = 0)
{
return 0;
}
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * man = NULL) virtual int isReactingToClick(MTGCardInstance * card, ManaCost * man = NULL)
{ {
return 0; return 0;
+5
View File
@@ -24,6 +24,7 @@ public:
vector<ActionElement *> garbage; vector<ActionElement *> garbage;
Targetable * menuObject; Targetable * menuObject;
SimpleMenu * abilitiesMenu; SimpleMenu * abilitiesMenu;
MTGCardInstance * currentActionCard;
int stuffHappened; int stuffHappened;
virtual void Render(); virtual void Render();
virtual void Update(float dt); virtual void Update(float dt);
@@ -41,11 +42,15 @@ public:
int reactToTargetClick(ActionElement * ability, Targetable * card); int reactToTargetClick(ActionElement * ability, Targetable * card);
int stillInUse(MTGCardInstance * card); int stillInUse(MTGCardInstance * card);
void setMenuObject(Targetable * object, bool must = false); void setMenuObject(Targetable * object, bool must = false);
void setCustomMenuObject(Targetable * object, bool must = false,vector<MTGAbility*>abilities = vector<MTGAbility*>());
void ButtonPressed(int controllerid, int controlid); void ButtonPressed(int controllerid, int controlid);
void doMultipleChoice(int choice = -1);
void ButtonPressedOnMultipleChoice(int choice = -1);
void doReactTo(int menuIndex); void doReactTo(int menuIndex);
TargetChooser * getCurrentTargetChooser(); TargetChooser * getCurrentTargetChooser();
void setCurrentWaitingAction(ActionElement * ae); void setCurrentWaitingAction(ActionElement * ae);
MTGAbility * getAbility(int type); MTGAbility * getAbility(int type);
int checkCantCancel(){return cantCancel;};
//Removes from game but does not move the element to garbage. The caller must take care of deleting the element. //Removes from game but does not move the element to garbage. The caller must take care of deleting the element.
int removeFromGame(ActionElement * e); int removeFromGame(ActionElement * e);
+1 -1
View File
@@ -207,7 +207,7 @@ public:
DONT_INTERRUPT = 1, DONT_INTERRUPT = 1,
DONT_INTERRUPT_ALL = 2, DONT_INTERRUPT_ALL = 2,
}; };
Player * lastActionController;
int setIsInterrupting(Player * player); int setIsInterrupting(Player * player);
int count( int type = 0 , int state = 0 , int display = -1); int count( int type = 0 , int state = 0 , int display = -1);
int getActionElementFromCard(MTGCardInstance * card); int getActionElementFromCard(MTGCardInstance * card);
+96 -4
View File
@@ -44,6 +44,8 @@ public:
WParsedInt(string s, Spell * spell, MTGCardInstance * card) WParsedInt(string s, Spell * spell, MTGCardInstance * card)
{ {
if(!card)
return;
MTGCardInstance * target = card->target; MTGCardInstance * target = card->target;
intValue = 0; intValue = 0;
bool halfup = false; bool halfup = false;
@@ -185,6 +187,10 @@ public:
else if (s == "t" || s == "toughness") else if (s == "t" || s == "toughness")
{ {
intValue = target->getToughness(); intValue = target->getToughness();
}
else if (s == "kicked")
{
intValue = target->kicked;
} }
else if (s == "handsize") else if (s == "handsize")
{ {
@@ -698,6 +704,40 @@ public:
} }
}; };
//targetted trigger
class TrCounter: public Trigger
{
public:
Counter * counter;
int type;
TrCounter(int id, MTGCardInstance * source, Counter * counter, TargetChooser * tc, int type = 0,bool once = false) :
Trigger(id, source, once, tc),counter(counter), type(type)
{
}
int triggerOnEventImpl(WEvent * event)
{
WEventCounters * e = dynamic_cast<WEventCounters *> (event);
if (!e) return 0;
if (type == 0 && !e->removed) return 0;
if (type == 1 && !e->added) return 0;
if (!(e->power == counter->power && e->toughness == counter->toughness && e->name == counter->name)) return 0;
if (tc && !tc->canTarget(e->targetCard)) return 0;
return 1;
}
~TrCounter()
{
SAFE_DELETE(counter);
}
TrCounter * clone() const
{
TrCounter * mClone = NEW TrCounter(*this);
mClone->counter = NEW Counter(*this->counter);
return mClone;
}
};
//Tutorial Messaging //Tutorial Messaging
class ATutorialMessage: public MTGAbility, public IconButtonsController class ATutorialMessage: public MTGAbility, public IconButtonsController
@@ -796,13 +836,14 @@ public:
class IfThenAbility: public MTGAbility class IfThenAbility: public MTGAbility
{ {
public: public:
string delayAbility; MTGAbility * delayedAbility;
int type; int type;
string Cond; string Cond;
IfThenAbility(int _id,string delayAbility = "", MTGCardInstance * _source=NULL, int type = 1,string Cond = ""); IfThenAbility(int _id,MTGAbility * delayedAbility = NULL, MTGCardInstance * _source=NULL, int type = 1,string Cond = "");
int resolve(); int resolve();
const char * getMenuText(); const char * getMenuText();
IfThenAbility * clone() const; IfThenAbility * clone() const;
~IfThenAbility();
}; };
//MayAbility: May do ... //MayAbility: May do ...
@@ -830,6 +871,39 @@ public:
}; };
//MayAbility with custom menues.
class MenuAbility: public MayAbility
{
public:
int triggered;
bool removeMenu;
bool must;
MTGAbility * mClone;
vector<MTGAbility*>abilities;
Player * who;
MenuAbility(int _id, Targetable * target, MTGCardInstance * _source, bool must = false, vector<MTGAbility*>abilities = vector<MTGAbility*>(),Player * who = NULL);
void Update(float dt);
int resolve();
const char * getMenuText();
int testDestroy();
int isReactingToTargetClick(Targetable * card);
int reactToTargetClick(Targetable * object);
int reactToChoiceClick(Targetable * object,int choice,int control);
MenuAbility * clone() const;
~MenuAbility();
};
class AAProliferate: public ActivatedAbility
{
public:
AAProliferate(int id, MTGCardInstance * source, Targetable * target,ManaCost * cost = NULL);
int resolve();
const char* getMenuText();
AAProliferate * clone() const;
~AAProliferate();
};
//MultiAbility : triggers several actions for a cost //MultiAbility : triggers several actions for a cost
class MultiAbility: public ActivatedAbility class MultiAbility: public ActivatedAbility
{ {
@@ -2531,7 +2605,7 @@ public:
void livingWeaponToken(MTGCardInstance * card) void livingWeaponToken(MTGCardInstance * card)
{ {
GameObserver * g = g->GetInstance(); GameObserver * g = GameObserver::GetInstance();
for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); i++) for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); i++)
{ {
MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]);
@@ -2660,6 +2734,13 @@ public:
return 1; return 1;
} }
int checkActivation()
{
checkCards.clear();
checkTargets();
return checkCards.size();
}
~AForeach() ~AForeach()
{ {
SAFE_DELETE(ability); SAFE_DELETE(ability);
@@ -3424,7 +3505,18 @@ public:
APreventDamageTypes * clone() const; APreventDamageTypes * clone() const;
~APreventDamageTypes(); ~APreventDamageTypes();
}; };
//prevent counters
class ACounterShroud: public MTGAbility
{
public:
Counter * counter;
RECountersPrevention * re;
ACounterShroud(int id, MTGCardInstance * source, MTGCardInstance * target, Counter * counter = NULL);
int addToGame();
int destroy();
ACounterShroud * clone() const;
~ACounterShroud();
};
//Remove all abilities from target //Remove all abilities from target
class ALoseAbilities: public MTGAbility class ALoseAbilities: public MTGAbility
{ {
-6
View File
@@ -43,12 +43,6 @@ class CardDescriptor: public MTGCardInstance
void unsecureSetTapped(int i); void unsecureSetTapped(int i);
void unsecuresetfresh(int k); void unsecuresetfresh(int k);
void setisMultiColored(int w); void setisMultiColored(int w);
void setisBlackAndWhite(int w);
void setisRedAndBlue(int w);
void setisBlackAndGreen(int w);
void setisBlueAndGreen(int w);
void setisRedAndWhite(int w);
void setNegativeSubtype( string value); void setNegativeSubtype( string value);
int counterPower; int counterPower;
int counterToughness; int counterToughness;
+1
View File
@@ -79,6 +79,7 @@ class GameObserver{
bool removeObserver(ActionElement * observer); bool removeObserver(ActionElement * observer);
void startGame(Rules * rules); void startGame(Rules * rules);
void untapPhase(); void untapPhase();
MTGCardInstance * isCardWaiting(){ return cardWaitingForTargets; }
int isInPlay(MTGCardInstance * card); int isInPlay(MTGCardInstance * card);
int isInGrave(MTGCardInstance * card); int isInGrave(MTGCardInstance * card);
int isInExile(MTGCardInstance * card); int isInExile(MTGCardInstance * card);
+1
View File
@@ -19,6 +19,7 @@ protected:
public: public:
int mCurr; int mCurr;
vector<JGuiObject *> mObjects; vector<JGuiObject *> mObjects;
vector<JGuiObject *> manaObjects;
void Add(JGuiObject * object); void Add(JGuiObject * object);
int Remove(JGuiObject * object); int Remove(JGuiObject * object);
int modal; int modal;
+2 -1
View File
@@ -394,6 +394,7 @@ class ListMaintainerAbility:public MTGAbility
{ {
public: public:
map<MTGCardInstance *,bool> cards; map<MTGCardInstance *,bool> cards;
map<MTGCardInstance *,bool> checkCards;
map<Player *,bool> players; map<Player *,bool> players;
ListMaintainerAbility(int _id) ListMaintainerAbility(int _id)
: MTGAbility(_id, NULL) : MTGAbility(_id, NULL)
@@ -412,6 +413,7 @@ public:
virtual void Update(float dt); virtual void Update(float dt);
void updateTargets(); void updateTargets();
void checkTargets();
virtual bool canTarget(MTGGameZone * zone); virtual bool canTarget(MTGGameZone * zone);
virtual int canBeInList(MTGCardInstance * card) = 0; virtual int canBeInList(MTGCardInstance * card) = 0;
virtual int added(MTGCardInstance * card) = 0; virtual int added(MTGCardInstance * card) = 0;
@@ -506,7 +508,6 @@ public:
int parsePowerToughness(string s, int *power, int *toughness); int parsePowerToughness(string s, int *power, int *toughness);
int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0, MTGGameZone * dest = NULL); int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0, MTGGameZone * dest = NULL);
MTGAbility* parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, bool activated = false, bool forceUEOT = false, MTGGameZone * dest = NULL); MTGAbility* parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, bool activated = false, bool forceUEOT = false, MTGGameZone * dest = NULL);
int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY, TargetChooser * tc = NULL,Targetable * target = NULL); int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY, TargetChooser * tc = NULL,Targetable * target = NULL);
int magicText(int id, Spell * spell, MTGCardInstance * card = NULL, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL, MTGGameZone * dest = NULL); int magicText(int id, Spell * spell, MTGCardInstance * card = NULL, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL, MTGGameZone * dest = NULL);
static int computeX(Spell * spell, MTGCardInstance * card); static int computeX(Spell * spell, MTGCardInstance * card);
+1 -5
View File
@@ -66,11 +66,6 @@ public:
int origpower; int origpower;
int origtoughness; int origtoughness;
int isMultiColored; int isMultiColored;
int isBlackAndWhite;
int isRedAndBlue;
int isBlackAndGreen;
int isBlueAndGreen;
int isRedAndWhite;
int isLeveler; int isLeveler;
bool enchanted; bool enchanted;
int CDenchanted; int CDenchanted;
@@ -92,6 +87,7 @@ public:
int notblocked; int notblocked;
int fresh; int fresh;
int MaxLevelUp; int MaxLevelUp;
int kicked;
Player * lastController; Player * lastController;
MTGGameZone * getCurrentZone(); MTGGameZone * getCurrentZone();
MTGGameZone * previousZone; MTGGameZone * previousZone;
+2 -4
View File
@@ -177,11 +177,9 @@ class Constants
SNOWISLANDWALK = 89, SNOWISLANDWALK = 89,
SNOWSWAMPWALK = 90, SNOWSWAMPWALK = 90,
CANATTACK = 91, CANATTACK = 91,
HYDRA = 92,
NB_BASIC_ABILITIES = 93,
NB_BASIC_ABILITIES = 92,
RARITY_S = 'S', //Special Rarity RARITY_S = 'S', //Special Rarity
+1
View File
@@ -50,6 +50,7 @@ public:
ManaCost * morph; ManaCost * morph;
ManaCost * suspend; ManaCost * suspend;
string alternativeName; string alternativeName;
bool isMulti;
static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL); static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL);
virtual void init(); virtual void init();
virtual void reinit(); virtual void reinit();
+14
View File
@@ -5,6 +5,7 @@
using namespace std; using namespace std;
#include "Damage.h" #include "Damage.h"
#include "WEvent.h" #include "WEvent.h"
#include "Counters.h"
class TargetChooser; class TargetChooser;
class MTGAbility; class MTGAbility;
@@ -35,6 +36,19 @@ public:
~REDamagePrevention(); ~REDamagePrevention();
}; };
class RECountersPrevention: public ReplacementEffect
{
protected:
MTGAbility * source;
MTGCardInstance * cardSource;
MTGCardInstance * cardTarget;
Counter * counter;
public:
RECountersPrevention(MTGAbility * _source,MTGCardInstance * cardSource = NULL,MTGCardInstance * cardTarget = NULL,Counter * counter = NULL);
WEvent * replace(WEvent *e);
~RECountersPrevention();
};
class ReplacementEffects class ReplacementEffects
{ {
protected: protected:
+2
View File
@@ -37,11 +37,13 @@ private:
public: public:
bool autoTranslate; bool autoTranslate;
bool isMultipleChoice;
SimpleMenu(int id, JGuiListener* listener, int fontId, float x, float y, const char * _title = "", int _maxItems = 7, bool centerHorizontal = true, bool centerVertical = true); SimpleMenu(int id, JGuiListener* listener, int fontId, float x, float y, const char * _title = "", int _maxItems = 7, bool centerHorizontal = true, bool centerVertical = true);
virtual ~SimpleMenu(); virtual ~SimpleMenu();
void Render(); void Render();
void Update(float dt); void Update(float dt);
void Add(int id, const char * Text, string desc = "", bool forceFocus = false); void Add(int id, const char * Text, string desc = "", bool forceFocus = false);
int getmCurr(){return mCurr;}
void Close(); void Close();
void RecenterMenu(); void RecenterMenu();
+45 -24
View File
@@ -24,8 +24,8 @@ class TargetChooser: public TargetsList
{ {
protected: protected:
int forceTargetListReady; int forceTargetListReady;
public: public:
const static int UNLITMITED_TARGETS = 1000;
enum enum
{ {
UNSET = 0, UNSET = 0,
@@ -36,13 +36,16 @@ public:
}; };
bool other; bool other;
bool withoutProtections; bool withoutProtections;
TargetChooser(MTGCardInstance * card = NULL, int _maxtargets = -1, bool other = false); TargetChooser(MTGCardInstance * card = NULL, int _maxtargets = UNLITMITED_TARGETS, bool other = false, bool targetMin = false);
Player * Owner;
MTGCardInstance * source; MTGCardInstance * source;
MTGCardInstance * targetter; //Optional, usually equals source, used for protection from... MTGCardInstance * targetter; //Optional, usually equals source, used for protection from...
int maxtargets;
int maxtargets; //Set to -1 for "unlimited" bool done;
bool validTargetsExist(); bool targetMin;
bool validTargetsExist(int maxTarget = 1);
int attemptsToFill;
string belongsToAbility;
int countValidTargets(); int countValidTargets();
virtual int setAllZones() virtual int setAllZones()
{ {
@@ -68,7 +71,7 @@ public:
virtual int full() virtual int full()
{ {
if (maxtargets != -1 && ((int) (targets.size())) >= maxtargets) if ( (maxtargets != UNLITMITED_TARGETS && (int(targets.size())) >= maxtargets) || done)
{ {
return 1; return 1;
} }
@@ -107,8 +110,8 @@ public:
bool targetsZone(MTGGameZone * z); bool targetsZone(MTGGameZone * z);
bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource); bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource);
bool withoutProtections; bool withoutProtections;
TargetZoneChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); TargetZoneChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false);
TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false);
virtual bool canTarget(Targetable * _card,bool withoutProtections = false); virtual bool canTarget(Targetable * _card,bool withoutProtections = false);
int setAllZones(); int setAllZones();
virtual TargetZoneChooser * clone() const; virtual TargetZoneChooser * clone() const;
@@ -133,8 +136,8 @@ public:
int nbtypes; int nbtypes;
int types[10]; int types[10];
bool withoutProtections; bool withoutProtections;
TypeTargetChooser(const char * _type, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); TypeTargetChooser(const char * _type, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false);
TypeTargetChooser(const char * _type, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); TypeTargetChooser(const char * _type, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false);
void addType(int type); void addType(int type);
void addType(const char * type); void addType(const char * type);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target,bool withoutProtections = false);
@@ -146,13 +149,13 @@ class DamageableTargetChooser: public TypeTargetChooser
{ {
public: public:
bool withoutProtections; bool withoutProtections;
DamageableTargetChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false) : DamageableTargetChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false) :
TypeTargetChooser("creature",_zones, _nbzones, card, _maxtargets, other) TypeTargetChooser("creature",_zones, _nbzones, card, _maxtargets, other, targetMin)
{ {
} }
; ;
DamageableTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false) : DamageableTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false) :
TypeTargetChooser("creature", card, _maxtargets, other) TypeTargetChooser("creature", card, _maxtargets, other, targetMin)
{ {
} }
; ;
@@ -168,7 +171,7 @@ protected:
public: public:
bool withoutProtections; bool withoutProtections;
PlayerTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, Player *_p = NULL); PlayerTargetChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, Player *_p = NULL);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target, bool withoutProtections = false);
virtual PlayerTargetChooser * clone() const; virtual PlayerTargetChooser * clone() const;
virtual bool equals(TargetChooser * tc); virtual bool equals(TargetChooser * tc);
}; };
@@ -178,8 +181,8 @@ class DescriptorTargetChooser: public TargetZoneChooser
public: public:
CardDescriptor * cd; CardDescriptor * cd;
bool withoutProtections; bool withoutProtections;
DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false,bool targetMin = false);
DescriptorTargetChooser(CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); DescriptorTargetChooser(CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false,bool targetMin = false);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target,bool withoutProtections = false);
~DescriptorTargetChooser(); ~DescriptorTargetChooser();
virtual DescriptorTargetChooser * clone() const; virtual DescriptorTargetChooser * clone() const;
@@ -191,8 +194,8 @@ class SpellTargetChooser: public TargetChooser
public: public:
int color; int color;
bool withoutProtections; bool withoutProtections;
SpellTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, bool other = false); SpellTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, bool other = false, bool targetMin = false);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target, bool withoutProtections = false);
virtual SpellTargetChooser * clone() const; virtual SpellTargetChooser * clone() const;
virtual bool equals(TargetChooser * tc); virtual bool equals(TargetChooser * tc);
}; };
@@ -202,8 +205,8 @@ class SpellOrPermanentTargetChooser: public TargetZoneChooser
public: public:
int color; int color;
bool withoutProtections; bool withoutProtections;
SpellOrPermanentTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, bool other = false); SpellOrPermanentTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, bool other = false, bool targetMin = false);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target, bool withoutProtections = false);
virtual SpellOrPermanentTargetChooser * clone() const; virtual SpellOrPermanentTargetChooser * clone() const;
virtual bool equals(TargetChooser * tc); virtual bool equals(TargetChooser * tc);
}; };
@@ -215,7 +218,7 @@ public:
int state; int state;
bool withoutProtections; bool withoutProtections;
DamageTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, int state = NOT_RESOLVED); DamageTargetChooser(MTGCardInstance * card = NULL, int _color = -1, int _maxtargets = 1, int state = NOT_RESOLVED);
virtual bool canTarget(Targetable * target,bool withoutProtections = false); virtual bool canTarget(Targetable * target, bool withoutProtections = false);
virtual DamageTargetChooser * clone() const; virtual DamageTargetChooser * clone() const;
virtual bool equals(TargetChooser * tc); virtual bool equals(TargetChooser * tc);
}; };
@@ -229,9 +232,27 @@ public:
bool withoutProtections; bool withoutProtections;
TriggerTargetChooser(int _triggerTarget); TriggerTargetChooser(int _triggerTarget);
virtual bool targetsZone(MTGGameZone * z); virtual bool targetsZone(MTGGameZone * z);
virtual bool canTarget(Targetable * _target,bool withoutProtections = false); virtual bool canTarget(Targetable * _target, bool withoutProtections = false);
virtual TriggerTargetChooser * clone() const; virtual TriggerTargetChooser * clone() const;
virtual bool equals(TargetChooser * tc); virtual bool equals(TargetChooser * tc);
}; };
class ProliferateChooser: public TypeTargetChooser
{
public:
bool withoutProtections;
ProliferateChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false, bool targetMin = false) :
TypeTargetChooser("*",_zones, _nbzones, card, _maxtargets, other, targetMin)
{
}
;
ProliferateChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false,bool targetMin = false) :
TypeTargetChooser("*", card, _maxtargets, other,targetMin)
{
}
;
virtual bool canTarget(Targetable * target, bool withoutProtections = false);
virtual ProliferateChooser * clone() const;
virtual bool equals(TargetChooser * tc);
};
#endif #endif
+14
View File
@@ -10,6 +10,8 @@ class Damage;
class Phase; class Phase;
class Targetable; class Targetable;
class ManaPool; class ManaPool;
class AACounter;
class Counters;
class WEvent { class WEvent {
public: public:
@@ -51,6 +53,18 @@ struct WEventDamage : public WEvent {
virtual Targetable * getTarget(int target); virtual Targetable * getTarget(int target);
}; };
struct WEventCounters : public WEvent {
MTGCardInstance * targetCard;
Counters * counter;
string name;
int power;
int toughness;
bool added;
bool removed;
WEventCounters(Counters *counter,string name,int power, int toughness,bool added = false, bool removed = false);
virtual Targetable * getTarget();
};
struct WEventLife : public WEvent { struct WEventLife : public WEvent {
Player * player; Player * player;
int amount; int amount;
+1 -1
View File
@@ -60,7 +60,7 @@ int AIMomirPlayer::momir()
MTGCardInstance * card = game->hand->cards[0]; MTGCardInstance * card = game->hand->cards[0];
if (ability->isReactingToClick(card, cost)) if (ability->isReactingToClick(card, cost))
{ {
tapLandsForMana(cost); payTheManaCost(cost);
AIAction * a = NEW AIAction(ability, card); AIAction * a = NEW AIAction(ability, card);
clickstream.push(a); clickstream.push(a);
result = 1; result = 1;
File diff suppressed because it is too large Load Diff
-1
View File
@@ -29,7 +29,6 @@ ActionElement::ActionElement(const ActionElement& a): JGuiObject(a)
ActionElement::~ActionElement() ActionElement::~ActionElement()
{ {
SAFE_DELETE(tc); SAFE_DELETE(tc);
} }
int ActionElement::getActivity() int ActionElement::getActivity()
+112 -7
View File
@@ -4,6 +4,7 @@
#include "GameObserver.h" #include "GameObserver.h"
#include "Targetable.h" #include "Targetable.h"
#include "WEvent.h" #include "WEvent.h"
#include "AllAbilities.h"
MTGAbility* ActionLayer::getAbility(int type) MTGAbility* ActionLayer::getAbility(int type)
{ {
@@ -27,12 +28,21 @@ int ActionLayer::removeFromGame(ActionElement * e)
if (isWaitingForAnswer() == e) if (isWaitingForAnswer() == e)
setCurrentWaitingAction(NULL); setCurrentWaitingAction(NULL);
assert(e);
e->destroy(); e->destroy();
i = getIndexOf(e); //the destroy event might have changed the contents of mObjects, so we get the index again i = getIndexOf(e); //the destroy event might have changed the contents of mObjects, so we get the index again
if (i == -1) if (i == -1)
return 0; //Should not happen, it means we deleted thesame object twice? return 0; //Should not happen, it means we deleted thesame object twice?
AManaProducer * manaObject = dynamic_cast<AManaProducer*>(e);
if(manaObject)
{
for (size_t i = 0; i < manaObjects.size(); i++)
if (manaObjects[i] == e)
{
manaObjects.erase(manaObjects.begin() + i);
}
}
mObjects.erase(mObjects.begin() + i); mObjects.erase(mObjects.begin() + i);
return 1; return 1;
@@ -140,10 +150,32 @@ void ActionLayer::Update(float dt)
if (cantCancel) if (cantCancel)
{ {
ActionElement * ae = isWaitingForAnswer(); ActionElement * ae = isWaitingForAnswer();
if (ae && !ae->tc->validTargetsExist()) int countTargets = 0;
int maxTargets = 0;
if(ae && ae->getActionTc())
{ {
cantCancel = 0; if (!ae->getActionTc()->validTargetsExist())
cancelCurrentAction(); {
cantCancel = 0;
cancelCurrentAction();
return;
}
countTargets = ae->getActionTc()->countValidTargets();
maxTargets = ae->getActionTc()->maxtargets;
if (countTargets < maxTargets)
{
/*
@movedto(this|mygraveyard) from(mybattlefield):moveto(mybattlefield)
target(<2>creature[elf]|opponentgraveyard)
and there were 3 in the grave, you have the valid amount needed, this function should not trigger
...however if you had only 1 in the grave, then the max targets is reset to the maximum you CAN
use this effect on...in line with "up to" wording found on the cards with such abilities.
without this, the game locks into a freeze state while you try to select the targets and dont have enough to
fill the maxtargets list.
*/
if(int(ae->getActionTc()->targets.size()) == countTargets-1)
ae->getActionTc()->done = true;
}
} }
} }
} }
@@ -155,6 +187,7 @@ void ActionLayer::Render()
abilitiesMenu->Render(); abilitiesMenu->Render();
return; return;
} }
currentActionCard = NULL;
for (size_t i = 0; i < mObjects.size(); i++) for (size_t i = 0; i < mObjects.size(); i++)
{ {
if (mObjects[i] != NULL) if (mObjects[i] != NULL)
@@ -176,7 +209,7 @@ void ActionLayer::setCurrentWaitingAction(ActionElement * ae)
TargetChooser * ActionLayer::getCurrentTargetChooser() TargetChooser * ActionLayer::getCurrentTargetChooser()
{ {
if (currentWaitingAction && currentWaitingAction->waitingForAnswer) if (currentWaitingAction && currentWaitingAction->waitingForAnswer)
return currentWaitingAction->tc; return currentWaitingAction->getActionTc();
return NULL; return NULL;
} }
@@ -185,7 +218,7 @@ int ActionLayer::cancelCurrentAction()
ActionElement * ae = isWaitingForAnswer(); ActionElement * ae = isWaitingForAnswer();
if (!ae) if (!ae)
return 0; return 0;
if (cantCancel && ae->tc->validTargetsExist()) if (cantCancel && ae->getActionTc()->validTargetsExist())
return 0; return 0;
ae->waitingForAnswer = 0; //TODO MOVE THIS IN ActionElement ae->waitingForAnswer = 0; //TODO MOVE THIS IN ActionElement
setCurrentWaitingAction(NULL); setCurrentWaitingAction(NULL);
@@ -312,7 +345,7 @@ void ActionLayer::setMenuObject(Targetable * object, bool must)
SAFE_DELETE(abilitiesMenu); SAFE_DELETE(abilitiesMenu);
abilitiesMenu = NEW SimpleMenu(10, this, Fonts::MAIN_FONT, 100, 100, object->getDisplayName().c_str()); abilitiesMenu = NEW SimpleMenu(10, this, Fonts::MAIN_FONT, 100, 100, object->getDisplayName().c_str());
currentActionCard = NULL;
for (size_t i = 0; i < mObjects.size(); i++) for (size_t i = 0; i < mObjects.size(); i++)
{ {
ActionElement * currentAction = (ActionElement *) mObjects[i]; ActionElement * currentAction = (ActionElement *) mObjects[i];
@@ -328,6 +361,36 @@ void ActionLayer::setMenuObject(Targetable * object, bool must)
modal = 1; modal = 1;
} }
void ActionLayer::setCustomMenuObject(Targetable * object, bool must,vector<MTGAbility*>abilities)
{
if (!object)
{
DebugTrace("FATAL: ActionLayer::setCustomMenuObject");
return;
}
menuObject = object;
SAFE_DELETE(abilitiesMenu);
abilitiesMenu = NEW SimpleMenu(10, this, Fonts::MAIN_FONT, 100, 100, object->getDisplayName().c_str());
currentActionCard = NULL;
abilitiesMenu->isMultipleChoice = false;
if(abilities.size())
{
abilitiesMenu->isMultipleChoice = true;
ActionElement * currentAction = NULL;
for(int w = 0; w < int(abilities.size());w++)
{
currentAction = (ActionElement*)abilities[w];
currentActionCard = (MTGCardInstance*)abilities[0]->target;
abilitiesMenu->Add(mObjects.size()-1, currentAction->getMenuText(),"",false);
}
}
if (!must)
abilitiesMenu->Add(kCancelMenuID, "Cancel");
else
cantCancel = 1;
modal = 1;
}
void ActionLayer::doReactTo(int menuIndex) void ActionLayer::doReactTo(int menuIndex)
{ {
@@ -339,8 +402,21 @@ void ActionLayer::doReactTo(int menuIndex)
} }
} }
void ActionLayer::doMultipleChoice(int choice)
{
if (menuObject)
{
DebugTrace("ActionLayer::doReactToChoice " << choice);
ButtonPressedOnMultipleChoice(choice);
}
}
void ActionLayer::ButtonPressed(int controllerid, int controlid) void ActionLayer::ButtonPressed(int controllerid, int controlid)
{ {
if(this->abilitiesMenu && this->abilitiesMenu->isMultipleChoice)
{
return ButtonPressedOnMultipleChoice();
}
if (controlid >= 0 && controlid < static_cast<int>(mObjects.size())) if (controlid >= 0 && controlid < static_cast<int>(mObjects.size()))
{ {
ActionElement * currentAction = (ActionElement *) mObjects[controlid]; ActionElement * currentAction = (ActionElement *) mObjects[controlid];
@@ -359,6 +435,35 @@ void ActionLayer::ButtonPressed(int controllerid, int controlid)
} }
} }
void ActionLayer::ButtonPressedOnMultipleChoice(int choice)
{
int currentMenuObject = -1;
for(int i = int(mObjects.size()-1);i > 0;i--)
{
//the currently displayed menu is not always the currently listenning action object
//find the menu which is displayed.
MenuAbility * ma = dynamic_cast<MenuAbility *>(mObjects[i]);//find the active menu
if(ma && ma->triggered)
{
currentMenuObject = i;
break;
}
}
if (currentMenuObject >= 0 && currentMenuObject < static_cast<int>(mObjects.size()))
{
ActionElement * currentAction = (ActionElement *) mObjects[currentMenuObject];
currentAction->reactToChoiceClick(menuObject,choice > -1?choice:this->abilitiesMenu->getmCurr(),currentMenuObject);
MenuAbility * ma = dynamic_cast<MenuAbility *>(mObjects[currentMenuObject]);
if(ma)
ma->removeMenu = true;//we clicked something, close menu now.
}
else if (currentMenuObject == kCancelMenuID)
{
GameObserver::GetInstance()->mLayers->stackLayer()->endOfInterruption();
}
menuObject = 0;
}
ActionLayer::ActionLayer() ActionLayer::ActionLayer()
{ {
menuObject = NULL; menuObject = NULL;
+11 -4
View File
@@ -146,9 +146,9 @@ void StackAbility::Render()
string alt1 = source->getName(); string alt1 = source->getName();
Targetable * _target = ability->target; Targetable * _target = ability->target;
if (ability->tc) if (ability->getActionTc())
{ {
Targetable * t = ability->tc->getNextTarget(); Targetable * t = ability->getActionTc()->getNextTarget();
if (t) if (t)
_target = t; _target = t;
} }
@@ -243,7 +243,8 @@ Interruptible(id), tc(tc), cost(_cost), payResult(payResult)
int Spell::computeX(MTGCardInstance * card) int Spell::computeX(MTGCardInstance * card)
{ {
ManaCost * c = cost->Diff(card->getManaCost()); ManaCost * c = NULL;
cost? c = cost->Diff(card->getManaCost()) : c = card->controller()->getManaPool()->Diff(card->getManaCost());
int x = c->getCost(Constants::MTG_NB_COLORS); int x = c->getCost(Constants::MTG_NB_COLORS);
delete c; delete c;
return x; return x;
@@ -598,6 +599,7 @@ int ActionStack::addAction(Interruptible * action)
interruptDecision[i] = 0; interruptDecision[i] = 0;
} }
Add(action); Add(action);
lastActionController = game->currentlyActing();
DebugTrace("Action added to stack: " << action->getDisplayName()); DebugTrace("Action added to stack: " << action->getDisplayName());
return 1; return 1;
@@ -705,7 +707,7 @@ int ActionStack::resolve()
interruptDecision[i] = 0; interruptDecision[i] = 0;
} }
} }
lastActionController = NULL;
return 1; return 1;
} }
@@ -1061,6 +1063,11 @@ int ActionStack::garbageCollect()
Interruptible * current = ((Interruptible *) *iter); Interruptible * current = ((Interruptible *) *iter);
if (current->state != NOT_RESOLVED) if (current->state != NOT_RESOLVED)
{ {
AManaProducer * amp = dynamic_cast<AManaProducer*>(current);
if(amp)
{
manaObjects.erase(iter);
}
iter = mObjects.erase(iter); iter = mObjects.erase(iter);
SAFE_DELETE(current); SAFE_DELETE(current);
} }
+271 -21
View File
@@ -254,7 +254,7 @@ AAPhaseOut::AAPhaseOut(int _id, MTGCardInstance * _source, MTGCardInstance * _ta
} }
int AAPhaseOut::resolve() int AAPhaseOut::resolve()
{GameObserver * g = g->GetInstance(); {GameObserver * g = GameObserver::GetInstance();
MTGCardInstance * _target = (MTGCardInstance *) target; MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target) if (_target)
{ {
@@ -299,9 +299,12 @@ AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target,
{ {
MTGCardInstance * _target = (MTGCardInstance *) target; MTGCardInstance * _target = (MTGCardInstance *) target;
AbilityFactory af; AbilityFactory af;
if(counterstring.size())
{
Counter * checkcounter = af.parseCounter(counterstring, source, NULL); Counter * checkcounter = af.parseCounter(counterstring, source, NULL);
nb = checkcounter->nb; nb = checkcounter->nb;
delete checkcounter; delete checkcounter;
}
if (nb > 0) if (nb > 0)
{ {
for (int i = 0; i < nb; i++) for (int i = 0; i < nb; i++)
@@ -317,7 +320,9 @@ AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target,
currentAmount = targetCounter->nb; currentAmount = targetCounter->nb;
} }
if(!maxNb || (maxNb && currentAmount < maxNb)) if(!maxNb || (maxNb && currentAmount < maxNb))
{
_target->counters->addCounter(name.c_str(), power, toughness); _target->counters->addCounter(name.c_str(), power, toughness);
}
} }
} }
else else
@@ -373,7 +378,45 @@ AACounter * AACounter::clone() const
return NEW AACounter(*this); return NEW AACounter(*this);
} }
//Counters //sheild a card from a certain type of counter.
ACounterShroud::ACounterShroud(int id, MTGCardInstance * source, MTGCardInstance * target, Counter * counter) :
MTGAbility(id, source),counter(counter),re(NULL)
{
}
int ACounterShroud::addToGame()
{
SAFE_DELETE(re);
re = NEW RECountersPrevention(this,source,(MTGCardInstance*)target,counter);
if (re)
{
game->replacementEffects->add(re);
return MTGAbility::addToGame();
}
return 0;
}
int ACounterShroud::destroy()
{
game->replacementEffects->remove(re);
SAFE_DELETE(re);
return 1;
}
ACounterShroud * ACounterShroud::clone() const
{
ACounterShroud * a = NEW ACounterShroud(*this);
a->re = NULL;
return a;
}
ACounterShroud::~ACounterShroud()
{
SAFE_DELETE(re);
SAFE_DELETE(counter);
}
//removeall counters of a certain type or all.
AARemoveAllCounter::AARemoveAllCounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, AARemoveAllCounter::AARemoveAllCounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness,
int nb,bool all, ManaCost * cost) : int nb,bool all, ManaCost * cost) :
ActivatedAbility(id, source, cost, 0), nb(nb), power(power), toughness(toughness), name(_name),all(all) ActivatedAbility(id, source, cost, 0), nb(nb), power(power), toughness(toughness), name(_name),all(all)
@@ -453,6 +496,62 @@ AARemoveAllCounter * AARemoveAllCounter::clone() const
return NEW AARemoveAllCounter(*this); return NEW AARemoveAllCounter(*this);
} }
//proliferate a target
AAProliferate::AAProliferate(int id, MTGCardInstance * source, Targetable * target,ManaCost * cost) :
ActivatedAbility(id, source, cost, 0)
{
}
int AAProliferate::resolve()
{
if (target)
{
vector<MTGAbility*>pcounters = vector<MTGAbility*>();
if(target->typeAsTarget() == TARGET_PLAYER && ((Player*)target)->poisonCount && target != source->controller())
{
MTGAbility * a = NEW AAAlterPoison(game->mLayers->actionLayer()->getMaxId(), source,(Player*)target,1,NULL);
a->target = (Player*)target;
a->oneShot = true;
pcounters.push_back(a);
}
else if (target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance*)target)->counters)
{
Counter * targetCounter = NULL;
for(unsigned int i = 0; i < ((MTGCardInstance*)target)->counters->counters.size();i++)
{
MTGAbility * a = NEW AACounter(game->mLayers->actionLayer()->getMaxId(), source, (MTGCardInstance*)target,"", ((MTGCardInstance*)target)->counters->counters[i]->name.c_str(), ((MTGCardInstance*)target)->counters->counters[i]->power, ((MTGCardInstance*)target)->counters->counters[i]->toughness, 1,0);
a->target = (MTGCardInstance*)target;
a->oneShot = true;
pcounters.push_back(a);
}
}
if(pcounters.size())
{
MTGAbility * a = NEW MenuAbility(/*int(game->mLayers->actionLayer()->getMaxId())*/this->GetId(),(MTGCardInstance*)target, source,false,pcounters);
a->target = (MTGCardInstance*)target;
a->resolve();
}
return 1;
}
return 0;
}
const char* AAProliferate::getMenuText()
{
return "Proliferate";
}
AAProliferate * AAProliferate::clone() const
{
return NEW AAProliferate(*this);
}
AAProliferate::~AAProliferate()
{
}
//
//Reset Damage on creatures //Reset Damage on creatures
AAResetDamage::AAResetDamage(int id, MTGCardInstance * source, MTGCardInstance * _target, ManaCost * cost): AAResetDamage::AAResetDamage(int id, MTGCardInstance * source, MTGCardInstance * _target, ManaCost * cost):
ActivatedAbility(id, source, cost, 0) ActivatedAbility(id, source, cost, 0)
@@ -750,7 +849,7 @@ int AANewTarget::resolve()
if(_target->hasSubtype(Subtypes::TYPE_EQUIPMENT)) if(_target->hasSubtype(Subtypes::TYPE_EQUIPMENT))
{ {
reUp->resolve(); reUp->resolve();
GameObserver * g = g->GetInstance(); GameObserver * g = GameObserver::GetInstance();
for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); i++) for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); i++)
{ {
MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]);
@@ -814,7 +913,7 @@ int AAMorph::resolve()
if( a && dynamic_cast<AAMorph *> (a)) if( a && dynamic_cast<AAMorph *> (a))
{ {
a->removeFromGame(); a->removeFromGame();
GameObserver * g = g->GetInstance(); GameObserver * g = GameObserver::GetInstance();
g->removeObserver(a); g->removeObserver(a);
} }
if (a) if (a)
@@ -843,7 +942,7 @@ int AAMorph::testDestroy()
{ {
if(_target->turningOver && !_target->isMorphed && !_target->morphed) if(_target->turningOver && !_target->isMorphed && !_target->morphed)
{ {
GameObserver * g = g->GetInstance(); GameObserver * g = GameObserver::GetInstance();
g->removeObserver(this); g->removeObserver(this);
return 1; return 1;
} }
@@ -2012,8 +2111,8 @@ AAWinGame * AAWinGame::clone() const
//IfThenEffect //IfThenEffect
IfThenAbility::IfThenAbility(int _id, string delayAbility, MTGCardInstance * _source, int type,string Cond) : IfThenAbility::IfThenAbility(int _id, MTGAbility * delayedAbility, MTGCardInstance * _source, int type,string Cond) :
MTGAbility(_id, _source),delayAbility(delayAbility), type(type),Cond(Cond) MTGAbility(_id, _source),delayedAbility(delayedAbility), type(type),Cond(Cond)
{ {
} }
@@ -2022,11 +2121,30 @@ int IfThenAbility::resolve()
MTGCardInstance * card = (MTGCardInstance*)source; MTGCardInstance * card = (MTGCardInstance*)source;
AbilityFactory af; AbilityFactory af;
int checkCond = af.parseCastRestrictions(card,card->controller(),Cond); int checkCond = af.parseCastRestrictions(card,card->controller(),Cond);
if(Cond.find("cantargetcard(") != string::npos)
{
TargetChooser * condTc = NULL;
vector<string>splitTarget = parseBetween(Cond, "card(", ")");
if (splitTarget.size())
{
TargetChooserFactory tcf;
condTc = tcf.createTargetChooser(splitTarget[1], source);
condTc->targetter = NULL;
if(source->target)
checkCond = condTc->canTarget(source->target);
SAFE_DELETE(condTc);
}
}
if((checkCond && type == 1)||(!checkCond && type == 2)) if((checkCond && type == 1)||(!checkCond && type == 2))
{ {
MTGAbility * a1 = af.parseMagicLine(delayAbility, this->GetId(), NULL, card); MTGAbility * a1 = delayedAbility->clone();
if (!a1) if (!a1)
return 0; return 0;
if(target)
a1->target = target;
if(!a1->target)
a1->target = source->target;
if(a1->oneShot) if(a1->oneShot)
{ {
a1->resolve(); a1->resolve();
@@ -2046,7 +2164,14 @@ const char * IfThenAbility::getMenuText()
IfThenAbility * IfThenAbility::clone() const IfThenAbility * IfThenAbility::clone() const
{ {
return NEW IfThenAbility(*this); IfThenAbility * a = NEW IfThenAbility(*this);
a->delayedAbility = delayedAbility->clone();
return a;
}
IfThenAbility::~IfThenAbility()
{
SAFE_DELETE(delayedAbility);
} }
// //
@@ -2060,13 +2185,14 @@ MayAbility::MayAbility(int _id, MTGAbility * _ability, MTGCardInstance * _source
void MayAbility::Update(float dt) void MayAbility::Update(float dt)
{ {
GameObserver * gameObs = GameObserver::GetInstance();
MTGAbility::Update(dt); MTGAbility::Update(dt);
if (!triggered) if (!triggered && !gameObs->getCurrentTargetChooser())
{ {
triggered = 1; triggered = 1;
if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability)) if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability))
{ {
if (!ta->tc->validTargetsExist()) if (!ta->getActionTc()->validTargetsExist())
return; return;
} }
game->mLayers->actionLayer()->setMenuObject(source, must); game->mLayers->actionLayer()->setMenuObject(source, must);
@@ -2122,6 +2248,130 @@ MayAbility::~MayAbility()
SAFE_DELETE(ability); SAFE_DELETE(ability);
} }
//Menu building ability Abilities
//this will eventaully handle choosen discards/sacrifices.
MenuAbility::MenuAbility(int _id, Targetable * mtarget, MTGCardInstance * _source, bool must,vector<MTGAbility*>abilities,Player * who) :
MayAbility(_id,NULL,_source,must), must(must),abilities(abilities),who(who)
{
triggered = 0;
mClone = NULL;
this->target = mtarget;
removeMenu = false;
}
void MenuAbility::Update(float dt)
{
MTGAbility::Update(dt);
ActionLayer * object = game->mLayers->actionLayer();
if (!triggered && !object->menuObject)
{
triggered = 1;
if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability))
{
if (!ta->getActionTc()->validTargetsExist())
return;
}
}
if(object->currentActionCard && this->target != object->currentActionCard)
{
triggered = 0;
}
if(triggered)
{
game->mLayers->actionLayer()->setCustomMenuObject(source, must,abilities);
previousInterrupter = game->isInterrupting;
game->mLayers->stackLayer()->setIsInterrupting(source->controller());
}
}
int MenuAbility::resolve()
{
this->triggered = 1;
MTGAbility * a = this;
a->target = this->target;
return a->addToGame();
}
const char * MenuAbility::getMenuText()
{
if(abilities.size())
return "choose one";
return ability->getMenuText();
}
int MenuAbility::testDestroy()
{
if (!removeMenu)
return 0;
if (game->mLayers->actionLayer()->menuObject)
return 0;
if (game->mLayers->actionLayer()->getIndexOf(mClone) != -1)
return 0;
return 1;
}
int MenuAbility::isReactingToTargetClick(Targetable * card){return MayAbility::isReactingToTargetClick(card);}
int MenuAbility::reactToTargetClick(Targetable * object){return 1;}
int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
{
ActionElement * currentAction = (ActionElement *) game->mLayers->actionLayer()->mObjects[control];
if(currentAction != (ActionElement*)this)
return 0;
if(!abilities.size()||!triggered)
return 0;
for(int i = 0;i < int(abilities.size());i++)
{
if(choice == i)
mClone = abilities[choice]->clone();
else
abilities[i]->clone();//all get cloned for clean up purposes.
}
if(!mClone)
return 0;
mClone->target = abilities[choice]->target;
mClone->oneShot = true;
mClone->forceDestroy = 1;
mClone->resolve();
SAFE_DELETE(mClone);
if (source->controller() == game->isInterrupting)
game->mLayers->stackLayer()->cancelInterruptOffer();
this->forceDestroy = 1;
removeMenu = true;
return reactToTargetClick(object);
}
MenuAbility * MenuAbility::clone() const
{
MenuAbility * a = NEW MenuAbility(*this);
a->canBeInterrupted = false;
if(abilities.size())
{
for(int i = 0;i < int(abilities.size());i++)
{
a->abilities.push_back(abilities[i]->clone());
a->abilities[i]->target = abilities[i]->target;
}
}
else
a->ability = ability->clone();
return a;
}
MenuAbility::~MenuAbility()
{
if(abilities.size())
{
for(int i = 0;i < int(abilities.size());i++)
{
SAFE_DELETE(abilities[i]);
}
}
else
SAFE_DELETE(ability);
}
///
//MultiAbility : triggers several actions for a cost //MultiAbility : triggers several actions for a cost
MultiAbility::MultiAbility(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost) : MultiAbility::MultiAbility(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost) :
ActivatedAbility(_id, card, _cost, 0) ActivatedAbility(_id, card, _cost, 0)
@@ -3381,8 +3631,8 @@ void ABlink::Update(float dt)
if(!tc->validTargetsExist()) if(!tc->validTargetsExist())
{ {
spell->source->owner->game->putInExile(spell->source); spell->source->owner->game->putInExile(spell->source);
delete spell; SAFE_DELETE(spell);
delete tc; SAFE_DELETE(tc);
this->forceDestroy = 1; this->forceDestroy = 1;
return; return;
} }
@@ -3397,8 +3647,8 @@ void ABlink::Update(float dt)
spell->getNextCardTarget(); spell->getNextCardTarget();
spell->resolve(); spell->resolve();
delete spell; SAFE_DELETE(spell);
delete tc; SAFE_DELETE(tc);
this->forceDestroy = 1; this->forceDestroy = 1;
return; return;
} }
@@ -3480,8 +3730,8 @@ void ABlink::resolveBlink()
if(!tc->validTargetsExist()) if(!tc->validTargetsExist())
{ {
spell->source->owner->game->putInExile(spell->source); spell->source->owner->game->putInExile(spell->source);
delete spell; SAFE_DELETE(spell);
delete tc; SAFE_DELETE(tc);
this->forceDestroy = 1; this->forceDestroy = 1;
return; return;
} }
@@ -3495,8 +3745,8 @@ void ABlink::resolveBlink()
spell->source->target = inplay->cards[i]; spell->source->target = inplay->cards[i];
spell->getNextCardTarget(); spell->getNextCardTarget();
spell->resolve(); spell->resolve();
delete spell; SAFE_DELETE(spell);
delete tc; SAFE_DELETE(tc);
this->forceDestroy = 1; this->forceDestroy = 1;
return; return;
} }
@@ -3519,8 +3769,8 @@ void ABlink::resolveBlink()
clonedStored->addToGame(); clonedStored->addToGame();
} }
} }
delete tc; SAFE_DELETE(spell);
delete spell; SAFE_DELETE(tc);
this->forceDestroy = 1; this->forceDestroy = 1;
if(stored) if(stored)
delete(stored); delete(stored);
-41
View File
@@ -53,27 +53,6 @@ void CardDescriptor::setisMultiColored(int w)
isMultiColored = w; isMultiColored = w;
} }
void CardDescriptor::setisBlackAndWhite(int w)
{
isBlackAndWhite = w;
}
void CardDescriptor::setisRedAndBlue(int w)
{
isRedAndBlue = w;
}
void CardDescriptor::setisBlackAndGreen(int w)
{
isBlackAndGreen = w;
}
void CardDescriptor::setisBlueAndGreen(int w)
{
isBlueAndGreen = w;
}
void CardDescriptor::setisRedAndWhite(int w)
{
isRedAndWhite = w;
}
void CardDescriptor::setNegativeSubtype(string value) void CardDescriptor::setNegativeSubtype(string value)
{ {
int id = Subtypes::subtypesList->find(value); int id = Subtypes::subtypesList->find(value);
@@ -234,26 +213,6 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
{ {
match = NULL; match = NULL;
} }
if ((isBlackAndWhite == -1 && card->isBlackAndWhite) || (isBlackAndWhite == 1 && !card->isBlackAndWhite))
{
match = NULL;
}
if ((isRedAndBlue == -1 && card->isRedAndBlue) || (isRedAndBlue == 1 && !card->isRedAndBlue))
{
match = NULL;
}
if ((isBlackAndGreen == -1 && card->isBlackAndGreen) || (isBlackAndGreen == 1 && !card->isBlackAndGreen))
{
match = NULL;
}
if ((isBlueAndGreen == -1 && card->isBlueAndGreen) || (isBlueAndGreen == 1 && !card->isBlueAndGreen))
{
match = NULL;
}
if ((isRedAndWhite == -1 && card->isRedAndWhite) || (isRedAndWhite == 1 && !card->isRedAndWhite))
{
match = NULL;
}
if ((isLeveler == -1 && card->isLeveler) || (isLeveler == 1 && !card->isLeveler)) if ((isLeveler == -1 && card->isLeveler) || (isLeveler == 1 && !card->isLeveler))
{ {
match = NULL; match = NULL;
+16 -4
View File
@@ -253,7 +253,7 @@ void CardGui::Render()
if (mask && quad) if (mask && quad)
JRenderer::GetInstance()->FillRect(actX - (scale * quad->mWidth / 2),actY - (scale * quad->mHeight / 2), scale * quad->mWidth, scale* quad->mHeight, mask); JRenderer::GetInstance()->FillRect(actX - (scale * quad->mWidth / 2),actY - (scale * quad->mHeight / 2), scale * quad->mWidth, scale* quad->mHeight, mask);
if (tc && tc->alreadyHasTarget(card))//paint targets red. if ((tc && tc->alreadyHasTarget(card)) || card == game->mLayers->actionLayer()->currentActionCard)//paint targets red.
{ {
if (card->isTapped()) if (card->isTapped())
{ {
@@ -264,8 +264,17 @@ void CardGui::Render()
renderer->FillRect(actX - (scale * quad->mWidth / 2),actY - (scale * quad->mHeight / 2), scale * quad->mWidth, scale* quad->mHeight, ARGB(128,255,0,0)); renderer->FillRect(actX - (scale * quad->mWidth / 2),actY - (scale * quad->mHeight / 2), scale * quad->mWidth, scale* quad->mHeight, ARGB(128,255,0,0));
} }
} }
if(tc && tc->source && tc->source->view->actZ >= 1.3)//paint the source green while infocus. if(tc && tc->source && tc->source->view && tc->source->view->actZ >= 1.3 && card == tc->source)//paint the source green while infocus.
renderer->FillRect(tc->source->view->actX - (scale * quad->mWidth / 2),tc->source->view->actY - (scale * quad->mHeight / 2), scale*quad->mWidth, scale*quad->mHeight, ARGB(128,0,255,0)); {
if (tc->source->isTapped())
{
renderer->FillRect(actX - (scale * quad->mWidth / 2)-7,actY - (scale * quad->mHeight / 2)+7,scale* quad->mHeight,scale * quad->mWidth, ARGB(128,0,255,0));
}
else
{
renderer->FillRect(tc->source->view->actX - (scale * quad->mWidth / 2),tc->source->view->actY - (scale * quad->mHeight / 2), scale*quad->mWidth, scale*quad->mHeight, ARGB(128,0,255,0));
}
}
PlayGuiObject::Render(); PlayGuiObject::Render();
} }
@@ -779,7 +788,10 @@ void CardGui::TinyCropRender(MTGCard * card, const Pos& pos, JQuad * quad)
void CardGui::RenderBig(MTGCard* card, const Pos& pos) void CardGui::RenderBig(MTGCard* card, const Pos& pos)
{ {
JRenderer * renderer = JRenderer::GetInstance(); JRenderer * renderer = JRenderer::GetInstance();
//GameObserver * game = GameObserver::GetInstance();
//if((MTGCard*)game->mLayers->actionLayer()->currentActionCard != NULL)
// card = (MTGCard*)game->mLayers->actionLayer()->currentActionCard;
//i want this but ai targets cards so quickly that it can crash the game.
float x = pos.actX; float x = pos.actX;
JQuadPtr quad = WResourceManager::Instance()->RetrieveCard(card); JQuadPtr quad = WResourceManager::Instance()->RetrieveCard(card);
+39 -17
View File
@@ -72,29 +72,47 @@ Counters::~Counters()
int Counters::addCounter(const char * _name, int _power, int _toughness) int Counters::addCounter(const char * _name, int _power, int _toughness)
{ {
/*420.5n If a permanent has both a +1/+1 counter and a -1/-1 counter on it, N +1/+1 and N -1/-1 counters are removed from it, where N is the smaller of the number of +1/+1 and -1/-1 counters on it.*/ /*420.5n If a permanent has both a +1/+1 counter and a -1/-1 counter on it, N +1/+1 and N -1/-1 counters are removed from it, where N is the smaller of the number of +1/+1 and -1/-1 counters on it.*/
for (int i = 0; i < mCount; i++) GameObserver *g = GameObserver::GetInstance();
WEvent * e = NEW WEventCounters(this,_name,_power,_toughness);
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
if (e == g->replacementEffects->replace(e))
{ {
if (counters[i]->cancels(_power, _toughness) && !counters[i]->name.size() && counters[i]->nb > 0) for (int i = 0; i < mCount; i++)
{ {
counters[i]->removed(); if (counters[i]->cancels(_power, _toughness) && !counters[i]->name.size() && counters[i]->nb > 0)
counters[i]->nb--; {
return mCount; counters[i]->removed();
counters[i]->nb--;
WEvent * t = NEW WEventCounters(this,_name,_power*-1,_toughness*-1,false,true);
dynamic_cast<WEventCounters*>(t)->targetCard = this->target;
g->receiveEvent(t);
delete(e);
return mCount;
}
} }
} for (int i = 0; i < mCount; i++)
for (int i = 0; i < mCount; i++)
{
if (counters[i]->sameAs(_name, _power, _toughness))
{ {
counters[i]->added(); if (counters[i]->sameAs(_name, _power, _toughness))
counters[i]->nb++; {
return mCount; counters[i]->added();
counters[i]->nb++;
WEvent * j = NEW WEventCounters(this,_name,_power,_toughness,true,false);
dynamic_cast<WEventCounters*>(j)->targetCard = this->target;
g->receiveEvent(j);
delete(e);
return mCount;
}
} }
Counter * counter = NEW Counter(target, _name, _power, _toughness);
counters.push_back(counter);
counter->added();
WEvent * w = NEW WEventCounters(this,_name,_power,_toughness,true,false);
dynamic_cast<WEventCounters*>(w)->targetCard = this->target;
g->receiveEvent(w);
mCount++;
} }
Counter * counter = NEW Counter(target, _name, _power, _toughness); delete(e);
counters.push_back(counter);
counter->added();
mCount++;
return mCount; return mCount;
} }
@@ -126,6 +144,10 @@ int Counters::removeCounter(const char * _name, int _power, int _toughness)
return 0; return 0;
counters[i]->removed(); counters[i]->removed();
counters[i]->nb--; counters[i]->nb--;
GameObserver *g = GameObserver::GetInstance();
WEvent * e = NEW WEventCounters(this,_name,_power,_toughness,false,true);
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
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))
{ {
+9 -2
View File
@@ -114,6 +114,14 @@ int Damage::resolve()
} }
damage = 0; damage = 0;
} }
if ((_target)->has(Constants::HYDRA))
{
for (int j = damage; j > 0; j--)
{
(_target)->counters->removeCounter(1, 1);
}
damage = 0;
}
if (!damage) if (!damage)
{ {
state = RESOLVED_NOK; state = RESOLVED_NOK;
@@ -136,14 +144,13 @@ int Damage::resolve()
} }
if(_target->toughness <= 0 && _target->has(Constants::INDESTRUCTIBLE)) if(_target->toughness <= 0 && _target->has(Constants::INDESTRUCTIBLE))
_target->controller()->game->putInGraveyard(_target); _target->controller()->game->putInGraveyard(_target);
} }
else if (target->type_as_damageable == DAMAGEABLE_PLAYER && source->has(Constants::INFECT)) else if (target->type_as_damageable == DAMAGEABLE_PLAYER && source->has(Constants::INFECT))
{ {
// Poison on player // Poison on player
Player * _target = (Player *) target; Player * _target = (Player *) target;
_target->poisonCount += damage;//this will be changed to poison counters. _target->poisonCount += damage;//this will be changed to poison counters.
target->damageCount += damage; _target->damageCount += damage;
} }
else if (target->type_as_damageable == DAMAGEABLE_PLAYER && (source->has(Constants::POISONTOXIC) || else if (target->type_as_damageable == DAMAGEABLE_PLAYER && (source->has(Constants::POISONTOXIC) ||
source->has(Constants::POISONTWOTOXIC) || source->has(Constants::POISONTHREETOXIC))) source->has(Constants::POISONTWOTOXIC) || source->has(Constants::POISONTHREETOXIC)))
+1 -1
View File
@@ -142,7 +142,7 @@ DuelLayers::~DuelLayers()
{ {
if (objects[i] != mCardSelector) if (objects[i] != mCardSelector)
{ {
delete objects[i]; SAFE_DELETE(objects[i]);
objects[i] = NULL; objects[i] = NULL;
} }
} }
+9
View File
@@ -643,6 +643,9 @@ int CounterCost::doPay()
{ {
target->counters->addCounter(counter->name.c_str(), counter->power, counter->toughness); target->counters->addCounter(counter->name.c_str(), counter->power, counter->toughness);
} }
if (tc)
tc->initTargets();
target = NULL;
return 1; return 1;
} }
@@ -654,8 +657,14 @@ int CounterCost::doPay()
target->counters->removeCounter(counter->name.c_str(), counter->power, counter->toughness); target->counters->removeCounter(counter->name.c_str(), counter->power, counter->toughness);
} }
hasCounters = 0; hasCounters = 0;
if (tc)
tc->initTargets();
target = NULL;
return 1; return 1;
} }
if (tc)
tc->initTargets();
target = NULL;
return 0; return 0;
} }
+21 -29
View File
@@ -192,6 +192,12 @@ void GameObserver::nextCombatStep()
void GameObserver::userRequestNextGamePhase() void GameObserver::userRequestNextGamePhase()
{ {
if(getCurrentTargetChooser() && getCurrentTargetChooser()->maxtargets == 1000)
{
getCurrentTargetChooser()->done = true;
if(getCurrentTargetChooser()->source)
cardClick(getCurrentTargetChooser()->source);
}
if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED))
return; return;
if (getCurrentTargetChooser()) if (getCurrentTargetChooser())
@@ -312,7 +318,6 @@ bool GameObserver::removeObserver(ActionElement * observer)
{ {
if (!observer) if (!observer)
return false; return false;
return mLayers->actionLayer()->moveToGarbage(observer); return mLayers->actionLayer()->moveToGarbage(observer);
} }
@@ -334,15 +339,21 @@ GameObserver::~GameObserver()
void GameObserver::Update(float dt) void GameObserver::Update(float dt)
{ {
Player * player = currentPlayer; Player * player = currentPlayer;
if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep)
player = player->opponent(); {
player = player->opponent();
}
if(getCurrentTargetChooser() && getCurrentTargetChooser()->Owner && player != getCurrentTargetChooser()->Owner)
{
if(getCurrentTargetChooser()->Owner != currentlyActing())
{
player = getCurrentTargetChooser()->Owner;
}
}
currentActionPlayer = player; currentActionPlayer = player;
if (isInterrupting) if (isInterrupting)
player = isInterrupting; player = isInterrupting;
mLayers->Update(dt, player); mLayers->Update(dt, player);
while (mLayers->actionLayer()->stuffHappened) while (mLayers->actionLayer()->stuffHappened)
{ {
mLayers->actionLayer()->Update(0); mLayers->actionLayer()->Update(0);
@@ -357,15 +368,15 @@ void GameObserver::Update(float dt)
//Handles game state based effects //Handles game state based effects
void GameObserver::gameStateBasedEffects() void GameObserver::gameStateBasedEffects()
{ {
//check land playability at start; as we want this effect to happen reguardless of unresolved if(getCurrentTargetChooser() && int(getCurrentTargetChooser()->targets.size()) == getCurrentTargetChooser()->maxtargets)
//effects or menus actions getCurrentTargetChooser()->done = true;
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
players[i]->isPoisoned = (players[i]->poisonCount > 0); players[i]->isPoisoned = (players[i]->poisonCount > 0);
if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0) if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0)
return; return;
if (mLayers->actionLayer()->menuObject) if (mLayers->actionLayer()->menuObject)
return; return;
if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) if (getCurrentTargetChooser() || mLayers->actionLayer()->isWaitingForAnswer())
return; return;
//////////////////////// ////////////////////////
@@ -585,27 +596,6 @@ void GameObserver::gameStateBasedEffects()
++colored; ++colored;
} }
z->cards[w]->isMultiColored = (colored > 1) ? 1 : 0; z->cards[w]->isMultiColored = (colored > 1) ? 1 : 0;
if(z->cards[w]->hasColor(Constants::MTG_COLOR_WHITE) && z->cards[w]->hasColor(Constants::MTG_COLOR_BLACK))
z->cards[w]->isBlackAndWhite = 1;
else
z->cards[w]->isBlackAndWhite = 0;
if(z->cards[w]->hasColor(Constants::MTG_COLOR_RED) && z->cards[w]->hasColor(Constants::MTG_COLOR_BLUE))
z->cards[w]->isRedAndBlue = 1;
else
z->cards[w]->isRedAndBlue = 0;
if(z->cards[w]->hasColor(Constants::MTG_COLOR_GREEN) && z->cards[w]->hasColor(Constants::MTG_COLOR_BLACK))
z->cards[w]->isBlackAndGreen = 1;
else
z->cards[w]->isBlackAndGreen = 0;
if(z->cards[w]->hasColor(Constants::MTG_COLOR_BLUE) && z->cards[w]->hasColor(Constants::MTG_COLOR_GREEN))
z->cards[w]->isBlueAndGreen = 1;
else
z->cards[w]->isBlueAndGreen = 0;
if(z->cards[w]->hasColor(Constants::MTG_COLOR_RED) && z->cards[w]->hasColor(Constants::MTG_COLOR_WHITE))
z->cards[w]->isRedAndWhite = 1;
else
z->cards[w]->isRedAndWhite = 0;
} }
} }
/////////////////////////////////// ///////////////////////////////////
@@ -879,6 +869,8 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
if (card == cardWaitingForTargets) if (card == cardWaitingForTargets)
{ {
int _result = targetChooser->ForceTargetListReady(); int _result = targetChooser->ForceTargetListReady();
if(targetChooser->targetMin && int(targetChooser->targets.size()) < targetChooser->maxtargets)
_result = 0;
if (_result) if (_result)
{ {
result = TARGET_OK_FULL; result = TARGET_OK_FULL;
+12
View File
@@ -19,10 +19,22 @@ GuiLayer::~GuiLayer()
void GuiLayer::Add(JGuiObject *object) void GuiLayer::Add(JGuiObject *object)
{ {
mObjects.push_back(object); mObjects.push_back(object);
AManaProducer * manaObject = dynamic_cast<AManaProducer*>(object);
if(manaObject)
manaObjects.push_back(object);
} }
int GuiLayer::Remove(JGuiObject *object) int GuiLayer::Remove(JGuiObject *object)
{ {
AManaProducer * manaObject = dynamic_cast<AManaProducer*>(object);
if(manaObject)
{
for (size_t i = 0; i < manaObjects.size(); i++)
if (manaObjects[i] == object)
{
manaObjects.erase(manaObjects.begin() + i);
}
}
for (size_t i = 0; i < mObjects.size(); i++) for (size_t i = 0; i < mObjects.size(); i++)
if (mObjects[i] == object) if (mObjects[i] == object)
{ {
+1 -1
View File
@@ -138,7 +138,7 @@ void GuiPhaseBar::Render()
currentP = _("opponent's turn"); currentP = _("opponent's turn");
} }
font->SetColor(ARGB(255, 255, 255, 255)); font->SetColor(ARGB(255, 255, 255, 255));
if (g->currentlyActing()->isAI()) if (g->currentlyActing() && g->currentlyActing()->isAI())
{ {
font->SetColor(ARGB(255, 128, 128, 128)); font->SetColor(ARGB(255, 128, 128, 128));
} }
+188 -31
View File
@@ -166,7 +166,11 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card,Player * player
} }
} }
else if (i == 2) else if (i == 2)
secondAmount = atoi(comparasion[2].c_str()); {
WParsedInt * secondA = NEW WParsedInt(comparasion[2].c_str(),(Spell*)card,card);
secondAmount = secondA->getValue();
SAFE_DELETE(secondA);
}
} }
if(firstAmount < secondAmount && !less && !more && !equal) if(firstAmount < secondAmount && !less && !more && !equal)
return 0; return 0;
@@ -600,6 +604,22 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int
return NEW TrTargeted(id, card, tc, fromTc, 0,once); return NEW TrTargeted(id, card, tc, fromTc, 0,once);
} }
if (s.find("counteradded(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"counteradded(",")");
Counter * counter = parseCounter(splitCounter[1],card,NULL);
TargetChooser * tc = parseSimpleTC(s, "from", card);
return NEW TrCounter(id, card, counter, tc, 1,once);
}
if (s.find("counterremoved(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"counterremoved(",")");
Counter * counter = parseCounter(splitCounter[1],card,NULL);
TargetChooser * tc = parseSimpleTC(s, "from", card);
return NEW TrCounter(id, card, counter, tc, 0,once);
}
int who = 0; int who = 0;
if (s.find("my") != string::npos) if (s.find("my") != string::npos)
who = 1; who = 1;
@@ -699,7 +719,8 @@ MTGAbility * AbilityFactory::getCoreAbility(MTGAbility * a)
//only atempt to return a nestedability if it contains a valid ability. example where this causes a bug otherwise. AEquip is considered nested, but contains no ability. //only atempt to return a nestedability if it contains a valid ability. example where this causes a bug otherwise. AEquip is considered nested, but contains no ability.
return getCoreAbility(na->ability); return getCoreAbility(na->ability);
} }
if (MenuAbility * ma = dynamic_cast<MenuAbility*>(a))
return ma->abilities[0];
return a; return a;
} }
@@ -878,11 +899,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
TargetChooserFactory tcf; TargetChooserFactory tcf;
tc = tcf.createTargetChooser("creature|mybattlefield", card); tc = tcf.createTargetChooser("creature|mybattlefield", card);
} }
ae->tc = tc; ae->setActionTC(tc);
return ae; return ae;
} }
if (tc) if (tc)
{
tc->belongsToAbility = sWithoutTc;
return NEW GenericTargetAbility(newName,id, card, tc, a, cost, limit,sideEffect,usesBeforeSideEffect, restrictions, dest); return NEW GenericTargetAbility(newName,id, card, tc, a, cost, limit,sideEffect,usesBeforeSideEffect, restrictions, dest);
}
return NEW GenericActivatedAbility(newName,id, card, a, cost, limit,sideEffect,usesBeforeSideEffect,restrictions, dest); return NEW GenericActivatedAbility(newName,id, card, a, cost, limit,sideEffect,usesBeforeSideEffect,restrictions, dest);
} }
SAFE_DELETE(cost); SAFE_DELETE(cost);
@@ -915,7 +939,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
{ {
string cond = sWithoutTc.substr(ifKeywords[i].length(),ifKeywords[i].length() + sWithoutTc.find(" then ")-6); string cond = sWithoutTc.substr(ifKeywords[i].length(),ifKeywords[i].length() + sWithoutTc.find(" then ")-6);
string s1 = s.substr(s.find(" then ")+6); string s1 = s.substr(s.find(" then ")+6);
MTGAbility * a = NEW IfThenAbility(id, s1, card,checkIf[i],cond); MTGAbility * a1 = parseMagicLine(s1, id, spell, card);
MTGAbility * a = NEW IfThenAbility(id, a1, card,checkIf[i],cond);
a->canBeInterrupted = false; a->canBeInterrupted = false;
a->oneShot = true; a->oneShot = true;
if(tc) if(tc)
@@ -1978,6 +2003,29 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a; return a;
} }
//no counters on target of optional type
vector<string> splitCounterShroud = parseBetween(s, "countershroud(", ")");
if (splitCounterShroud.size())
{
string counterShroudString = splitCounterShroud[1];
Counter * counter = NULL;
if(splitCounterShroud[1] == "any")
{
counter = NULL;
}
else
{
counter = parseCounter(counterShroudString, target, spell);
if (!counter)
{
DebugTrace("MTGAbility: can't parse counter:" << s);
return NULL;
}
}
MTGAbility * a = NEW ACounterShroud(id, card, target,counter);
return a;
}
//removes all counters of the specifified type. //removes all counters of the specifified type.
vector<string> splitRemoveCounter = parseBetween(s, "removeallcounters(", ")"); vector<string> splitRemoveCounter = parseBetween(s, "removeallcounters(", ")");
if (splitRemoveCounter.size()) if (splitRemoveCounter.size())
@@ -2226,6 +2274,16 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return NULL; //TODO return NULL; //TODO
} }
//proliferate
found = s.find("proliferate");
if (found != string::npos)
{
MTGAbility * a = NEW AAProliferate(id, card, target);
a->oneShot = 1;
a->canBeInterrupted = false;
return a;
}
//frozen, next untap this does not untap. //frozen, next untap this does not untap.
found = s.find("frozen"); found = s.find("frozen");
if (found != string::npos) if (found != string::npos)
@@ -2340,7 +2398,7 @@ int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, Targ
{ {
if (mode == MODE_PUTINTOPLAY) if (mode == MODE_PUTINTOPLAY)
return BAKA_EFFECT_GOOD; return BAKA_EFFECT_GOOD;
return abilityEfficiency(abi->ability, p, mode, abi->tc); return abilityEfficiency(abi->ability, p, mode, abi->getActionTc());
} }
if (GenericActivatedAbility * abi = dynamic_cast<GenericActivatedAbility*>(a)) if (GenericActivatedAbility * abi = dynamic_cast<GenericActivatedAbility*>(a))
{ {
@@ -2354,8 +2412,8 @@ int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, Targ
return abilityEfficiency(abi->ability, p, mode, tc); return abilityEfficiency(abi->ability, p, mode, tc);
if (ALord * abi = dynamic_cast<ALord *>(a)) if (ALord * abi = dynamic_cast<ALord *>(a))
{ {
int myCards = countCards(abi->tc, p); int myCards = countCards(abi->getActionTc(), p);
int theirCards = countCards(abi->tc, p->opponent()); int theirCards = countCards(abi->getActionTc(), p->opponent());
int efficiency = abilityEfficiency(abi->ability, p, mode, tc); int efficiency = abilityEfficiency(abi->ability, p, mode, tc);
if ( ((myCards < theirCards) && efficiency == BAKA_EFFECT_GOOD) || ((myCards > theirCards) && efficiency == BAKA_EFFECT_BAD) ) if ( ((myCards < theirCards) && efficiency == BAKA_EFFECT_GOOD) || ((myCards > theirCards) && efficiency == BAKA_EFFECT_BAD) )
return efficiency; return efficiency;
@@ -2379,6 +2437,8 @@ int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, Targ
return BAKA_EFFECT_GOOD; return BAKA_EFFECT_GOOD;
if (dynamic_cast<AATapper *> (a)) if (dynamic_cast<AATapper *> (a))
return BAKA_EFFECT_BAD; return BAKA_EFFECT_BAD;
if (dynamic_cast<AManaProducer *> (a))
return BAKA_EFFECT_GOOD;
if (AACounter * ac = dynamic_cast<AACounter *>(a)) if (AACounter * ac = dynamic_cast<AACounter *>(a))
{ {
bool negative_effect = ac->power < 0 || ac->toughness < 0; bool negative_effect = ac->power < 0 || ac->toughness < 0;
@@ -2634,6 +2694,12 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
for (size_t i = 0; i < v.size(); ++i) for (size_t i = 0; i < v.size(); ++i)
{ {
MTGAbility * a = v[i]; MTGAbility * a = v[i];
if (!a)
{
DebugTrace("ABILITYFACTORY ERROR: Parser returned NULL");
return 0;
}
if (dryMode) if (dryMode)
{ {
result = abilityEfficiency(a, card->controller(), mode, tc); result = abilityEfficiency(a, card->controller(), mode, tc);
@@ -2641,8 +2707,44 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
SAFE_DELETE(v[i]); SAFE_DELETE(v[i]);
return result; return result;
} }
if(spell && spell->tc && spell->tc->targets.size() > 1 && spell->getNextTarget())
if (a) a->target = spell->getNextTarget();
if(a && a->target && spell && spell->tc && spell->tc->targets.size() > 1)
{
while(a && a->target)
{
if(a->oneShot)
{
a->resolve();
}
else if(!dynamic_cast<MayAbility*>(a))
{
MTGAbility * mClone = a->clone();
mClone->target = a->target;
MTGAbility * core = getCoreAbility(mClone);
if (dynamic_cast<AManaProducer*> (core))
mClone->canBeInterrupted = false;
mClone->addToGame();
}
else if(dynamic_cast<MayAbility*>(a) && a->target == spell->tc->targets[0])
{
//only add may/choice/target( menu ability for the first card,
//no point in adding "discard" 3 times to a menu, as you can only choose the effect once
MTGAbility * mClone = a->clone();
mClone->target = a->target;
MTGAbility * core = getCoreAbility(mClone);
if (dynamic_cast<AManaProducer*> (core))
mClone->canBeInterrupted = false;
mClone->addToGame();
}
a->target = spell->getNextTarget(a->target);
if(!a->target)
{
SAFE_DELETE(a);
}
}
}
else
{ {
if (a->oneShot) if (a->oneShot)
{ {
@@ -2651,18 +2753,9 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
} }
else else
{ {
// Anything involving Mana Producing abilities cannot be interrupted
MTGAbility * core = getCoreAbility(a);
if (dynamic_cast<AManaProducer*> (core))
a->canBeInterrupted = false;
a->addToGame(); a->addToGame();
} }
} }
else
{
DebugTrace("ABILITYFACTORY ERROR: Parser returned NULL");
}
} }
return result; return result;
@@ -3045,13 +3138,6 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
} }
break; break;
} }
case 1480: //Energy Tap
{
card->target->tap();
int mana = card->target->getManaCost()->getConvertedCost();
game->currentlyActing()->getManaPool()->add(Constants::MTG_COLOR_ARTIFACT, mana);
}
//Addons ICE-AGE Cards //Addons ICE-AGE Cards
case 2474: //Minion of Leshrac case 2474: //Minion of Leshrac
@@ -3771,9 +3857,28 @@ int TargetAbility::resolve()
if (t->typeAsTarget() == TARGET_CARD && ((MTGCardInstance*)t)->isPhased) if (t->typeAsTarget() == TARGET_CARD && ((MTGCardInstance*)t)->isPhased)
return 0; return 0;
if (ability->oneShot) if (ability->oneShot)
return ability->resolve(); {
MTGAbility * a = ability->clone(); while(t)
return a->addToGame(); {
ability->resolve();
t = tc->getNextTarget(t);
ability->target = t;
}
tc->targets.clear();
return 1;
}
else
{
while(t)
{
MTGAbility * a = ability->clone();
a->addToGame();
t = tc->getNextTarget(t);
ability->target = t;
}
tc->targets.clear();
return 1;
}
} }
return 0; return 0;
} }
@@ -3984,6 +4089,58 @@ void ListMaintainerAbility::updateTargets()
} }
void ListMaintainerAbility::checkTargets()
{
//remove invalid ones
map<MTGCardInstance *, bool> tempCheck;
for (map<MTGCardInstance *, bool>::iterator it = checkCards.begin(); it != checkCards.end(); ++it)
{
MTGCardInstance * card = (*it).first;
if (!canBeInList(card) || card->mPropertiesChangedSinceLastUpdate)
{
tempCheck[card] = true;
}
}
for (map<MTGCardInstance *, bool>::iterator it = tempCheck.begin(); it != tempCheck.end(); ++it)
{
MTGCardInstance * card = (*it).first;
checkCards.erase(card);
}
tempCheck.clear();
//add New valid ones
for (int i = 0; i < 2; i++)
{
Player * p = game->players[i];
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library };
for (int k = 0; k < 4; k++)
{
MTGGameZone * zone = zones[k];
if (canTarget(zone))
{
for (int j = 0; j < zone->nb_cards; j++)
{
MTGCardInstance * card = zone->cards[j];
if (canBeInList(card))
{
if (checkCards.find(card) == checkCards.end())
{
tempCheck[card] = true;
}
}
}
}
}
}
for (map<MTGCardInstance *, bool>::iterator it = tempCheck.begin(); it != tempCheck.end(); ++it)
{
MTGCardInstance * card = (*it).first;
checkCards[card] = true;
}
}
void ListMaintainerAbility::Update(float dt) void ListMaintainerAbility::Update(float dt)
{ {
updateTargets(); updateTargets();
@@ -4142,7 +4299,7 @@ int GenericTriggeredAbility::triggerOnEvent(WEvent * e)
Targetable * GenericTriggeredAbility::getTriggerTarget(WEvent * e, MTGAbility * a) Targetable * GenericTriggeredAbility::getTriggerTarget(WEvent * e, MTGAbility * a)
{ {
TriggerTargetChooser * ttc = dynamic_cast<TriggerTargetChooser *> (a->tc); TriggerTargetChooser * ttc = dynamic_cast<TriggerTargetChooser *> (a->getActionTc());
if (ttc) if (ttc)
return e->getTarget(ttc->triggerTarget); return e->getTarget(ttc->triggerTarget);
@@ -4164,7 +4321,7 @@ Targetable * GenericTriggeredAbility::getTriggerTarget(WEvent * e, MTGAbility *
void GenericTriggeredAbility::setTriggerTargets(Targetable * ta, MTGAbility * a) void GenericTriggeredAbility::setTriggerTargets(Targetable * ta, MTGAbility * a)
{ {
TriggerTargetChooser * ttc = dynamic_cast<TriggerTargetChooser *> (a->tc); TriggerTargetChooser * ttc = dynamic_cast<TriggerTargetChooser *> (a->getActionTc());
if (ttc) if (ttc)
{ {
a->target = ta; a->target = ta;
@@ -4266,7 +4423,7 @@ int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana)
&& (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness()) && !source->isPhased) && (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness()) && !source->isPhased)
{ {
ManaCost * cost = getCost(); ManaCost * cost = getCost();
if (!cost || mana->canAfford(cost)) if (!cost || (mana->canAfford(cost) && (!cost->extraCosts || cost->extraCosts->canPay())))/*counter cost bypass react to click*/
{ {
result = 1; result = 1;
} }
+1 -16
View File
@@ -118,11 +118,6 @@ void MTGCardInstance::initMTGCI()
frozen = 0; frozen = 0;
fresh = 0; fresh = 0;
isMultiColored = 0; isMultiColored = 0;
isBlackAndWhite = 0;
isRedAndBlue = 0;
isBlackAndGreen = 0;
isBlueAndGreen = 0;
isRedAndWhite = 0;
isLeveler = 0; isLeveler = 0;
enchanted = false; enchanted = false;
CDenchanted = 0; CDenchanted = 0;
@@ -146,6 +141,7 @@ void MTGCardInstance::initMTGCI()
suspended = false; suspended = false;
castMethod = Constants::NOT_CAST; castMethod = Constants::NOT_CAST;
mPropertiesChangedSinceLastUpdate = false; mPropertiesChangedSinceLastUpdate = false;
kicked = 0;
for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++) for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++)
@@ -194,17 +190,6 @@ void MTGCardInstance::initMTGCI()
if (colored > 1) if (colored > 1)
{ {
isMultiColored = 1; isMultiColored = 1;
if(this->hasColor(Constants::MTG_COLOR_WHITE) && this->hasColor(Constants::MTG_COLOR_BLACK))
isBlackAndWhite = 1;
if(this->hasColor(Constants::MTG_COLOR_RED) && this->hasColor(Constants::MTG_COLOR_BLUE))
isRedAndBlue = 1;
if(this->hasColor(Constants::MTG_COLOR_GREEN) && this->hasColor(Constants::MTG_COLOR_BLACK))
isBlackAndGreen = 1;
if(this->hasColor(Constants::MTG_COLOR_BLUE) && this->hasColor(Constants::MTG_COLOR_GREEN))
isBlueAndGreen = 1;
if(this->hasColor(Constants::MTG_COLOR_RED) && this->hasColor(Constants::MTG_COLOR_WHITE))
isRedAndWhite = 1;
} }
if(previous && previous->morphed && !turningOver) if(previous && previous->morphed && !turningOver)
+9
View File
@@ -155,7 +155,16 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
{ {
string value = val; string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower); std::transform(value.begin(), value.end(), value.begin(), ::tolower);
size_t multikick = value.find("multi");
bool isMultikicker = false;
if(multikick != string::npos)
{
size_t endK = value.find("{",multikick);
value.erase(multikick, endK - multikick);
isMultikicker = true;
}
cost->kicker = ManaCost::parseManaCost(value); cost->kicker = ManaCost::parseManaCost(value);
cost->kicker->isMulti = isMultikicker;
} }
break; break;
+2 -1
View File
@@ -118,7 +118,8 @@ const char* Constants::MTGBasicAbilities[] = {
"snowmountainlandwalk", "snowmountainlandwalk",
"snowislandlandwalk", "snowislandlandwalk",
"snowswamplandwalk", "snowswamplandwalk",
"canattack" "canattack",
"hydra"
}; };
map<string,int> Constants::MTGBasicAbilitiesMap; map<string,int> Constants::MTGBasicAbilitiesMap;
+2 -2
View File
@@ -10,7 +10,6 @@
#if defined (WIN32) || defined (LINUX) #if defined (WIN32) || defined (LINUX)
#include <time.h> #include <time.h>
#endif #endif
//------------------------------ //------------------------------
//Players Game //Players Game
//------------------------------ //------------------------------
@@ -467,6 +466,7 @@ MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy
copy->view = card->view; copy->view = card->view;
copy->isToken = card->isToken; copy->isToken = card->isToken;
copy->X = card->X; copy->X = card->X;
copy->kicked = card->kicked;
//stupid bug with tokens... //stupid bug with tokens...
if (card->model == card) if (card->model == card)
@@ -524,7 +524,7 @@ MTGCardInstance * MTGGameZone::findByName(string name)
{ {
for (int i = 0; i < (nb_cards); i++) for (int i = 0; i < (nb_cards); i++)
{ {
if (cards[i]->name == name) if (cards[i]->name == name || cards[i]->getLCName()/*tokens*/ == name)
{ {
return cards[i]; return cards[i];
} }
+32 -12
View File
@@ -240,11 +240,6 @@ int MTGEventBonus::receiveEvent(WEvent * event)
void MTGEventBonus::grantAward(string awardName,int amount) void MTGEventBonus::grantAward(string awardName,int amount)
{ {
JSample * sample = WResourceManager::Instance()->RetrieveSample("bonus.wav");
if (sample)
{
JSoundSystem::GetInstance()->PlaySample(sample);
}
text = awardName; text = awardName;
textAlpha = 255; textAlpha = 255;
Credits::addCreditBonus(amount); Credits::addCreditBonus(amount);
@@ -397,11 +392,22 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card)
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool()); ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
int payResult = player->getManaPool()->pay(card->getManaCost()); int payResult = player->getManaPool()->pay(card->getManaCost());
if (card->getManaCost()->kicker && OptionKicker::KICKER_ALWAYS == options[Options::KICKERPAYMENT].number) if (card->getManaCost()->kicker && (OptionKicker::KICKER_ALWAYS == options[Options::KICKERPAYMENT].number || card->controller()->isAI()))
{ {
ManaCost * withKickerCost= NEW ManaCost(card->getManaCost()); ManaCost * withKickerCost= NEW ManaCost(card->getManaCost());
withKickerCost->add(withKickerCost->kicker); withKickerCost->add(withKickerCost->kicker);
if (previousManaPool->canAfford(withKickerCost)) if (card->getManaCost()->kicker->isMulti)
{
while(previousManaPool->canAfford(withKickerCost))
{
withKickerCost->add(withKickerCost->kicker);
card->kicked += 1;
}
for(int i = 0;i < card->kicked;i++)
player->getManaPool()->pay(card->getManaCost()->kicker);
payResult = ManaCost::MANA_PAID_WITH_KICKER;
}
else if (previousManaPool->canAfford(withKickerCost))
{ {
player->getManaPool()->pay(card->getManaCost()->kicker); player->getManaPool()->pay(card->getManaCost()->kicker);
payResult = ManaCost::MANA_PAID_WITH_KICKER; payResult = ManaCost::MANA_PAID_WITH_KICKER;
@@ -511,8 +517,23 @@ int MTGKickerRule::reactToClick(MTGCardInstance * card)
Player * player = game->currentlyActing(); Player * player = game->currentlyActing();
ManaCost * withKickerCost= NEW ManaCost(card->getManaCost());//using pointers here alters the real cost of the card. ManaCost * withKickerCost= NEW ManaCost(card->getManaCost());//using pointers here alters the real cost of the card.
withKickerCost->add(withKickerCost->kicker); if (card->getManaCost()->kicker->isMulti)
card->paymenttype = MTGAbility::PUT_INTO_PLAY_WITH_KICKER; {
while(player->getManaPool()->canAfford(withKickerCost))
{
withKickerCost->add(withKickerCost->kicker);
card->kicked += 1;
}
card->kicked -= 1;
//for(int i = 0;i < card->kicked;i++)
//player->getManaPool()->pay(card->getManaCost()->kicker);
card->paymenttype = MTGAbility::PUT_INTO_PLAY_WITH_KICKER;
}
else
{
withKickerCost->add(withKickerCost->kicker);
card->paymenttype = MTGAbility::PUT_INTO_PLAY_WITH_KICKER;
}
if (withKickerCost->isExtraPaymentSet()) if (withKickerCost->isExtraPaymentSet())
{ {
if (!game->targetListIsSet(card)) if (!game->targetListIsSet(card))
@@ -1163,7 +1184,7 @@ MTGAbility(_id, NULL)
int MTGAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) int MTGAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{ {
if (currentPhase == Constants::MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer) if (currentPhase == Constants::MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer && card->controller() == game->currentlyActing())//on my turn and when I am the acting player.
{ {
if(card->isPhased) if(card->isPhased)
return 0; return 0;
@@ -1205,7 +1226,6 @@ int MTGAttackRule::reactToClick(MTGCardInstance * card)
{ {
if (!isReactingToClick(card)) if (!isReactingToClick(card))
return 0; return 0;
//Graphically select the next card that can attack //Graphically select the next card that can attack
if (!card->isAttacker()) if (!card->isAttacker())
{ {
@@ -1399,7 +1419,7 @@ MTGAbility(_id, NULL)
int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{ {
if (currentPhase == Constants::MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting if (currentPhase == Constants::MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting
&& card->controller() == game->currentlyActing() && card->controller() != game->currentPlayer
) )
{ {
if (card->canBlock() && !card->isPhased) if (card->canBlock() && !card->isPhased)
+10 -3
View File
@@ -172,15 +172,15 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
size_t separator2 = string::npos; size_t separator2 = string::npos;
if (separator != string::npos) if (separator != string::npos)
{ {
separator2 = value.find(",", separator + 1); separator2 = value.find(",", counter_end + 1);
} }
SAFE_DELETE(tc); SAFE_DELETE(tc);
size_t target_start = string::npos; size_t target_start = string::npos;
if (separator2 != string::npos) if (separator2 != string::npos)
{ {
target_start = value.find(",", separator2 + 1); target_start = value.find(",", counter_end + 1);
} }
size_t target_end = counter_end; size_t target_end = value.length();
if (target_start != string::npos && target_end != string::npos) if (target_start != string::npos && target_end != string::npos)
{ {
string target = value.substr(target_start + 1, target_end - 1 - target_start); string target = value.substr(target_start + 1, target_end - 1 - target_start);
@@ -267,6 +267,8 @@ ManaCost::ManaCost(ManaCost * manaCost)
hybrids = manaCost->hybrids; hybrids = manaCost->hybrids;
kicker = NEW ManaCost( manaCost->kicker ); kicker = NEW ManaCost( manaCost->kicker );
if(kicker)
kicker->isMulti = manaCost->isMulti;
Retrace = NEW ManaCost( manaCost->Retrace ); Retrace = NEW ManaCost( manaCost->Retrace );
BuyBack = NEW ManaCost( manaCost->BuyBack ); BuyBack = NEW ManaCost( manaCost->BuyBack );
alternative = NEW ManaCost( manaCost->alternative ); alternative = NEW ManaCost( manaCost->alternative );
@@ -361,6 +363,7 @@ void ManaCost::init()
Retrace = NULL; Retrace = NULL;
morph = NULL; morph = NULL;
suspend = NULL; suspend = NULL;
isMulti = false;
} }
void ManaCost::reinit() void ManaCost::reinit()
@@ -402,6 +405,7 @@ void ManaCost::copy(ManaCost * _manaCost)
{ {
kicker = NEW ManaCost(); kicker = NEW ManaCost();
kicker->copy(_manaCost->kicker); kicker->copy(_manaCost->kicker);
kicker->isMulti = _manaCost->kicker->isMulti;
} }
SAFE_DELETE(alternative); SAFE_DELETE(alternative);
if (_manaCost->alternative) if (_manaCost->alternative)
@@ -753,9 +757,12 @@ string ManaCost::toString()
#ifdef WIN32 #ifdef WIN32
void ManaCost::Dump() void ManaCost::Dump()
{ {
//if(this->getConvertedCost())//uncomment when this is far too loud and clutters your output making other traces pointless.
//{
DebugTrace( "\n===ManaCost===" ); DebugTrace( "\n===ManaCost===" );
DebugTrace( this->toString() ); DebugTrace( this->toString() );
DebugTrace( "\n=============" ); DebugTrace( "\n=============" );
//}
} }
#endif #endif
+28
View File
@@ -3,6 +3,7 @@
#include "ReplacementEffects.h" #include "ReplacementEffects.h"
#include "MTGCardInstance.h" #include "MTGCardInstance.h"
#include "TargetChooser.h" #include "TargetChooser.h"
#include "AllAbilities.h"
REDamagePrevention::REDamagePrevention(MTGAbility * source, TargetChooser *tcSource, TargetChooser *tcTarget, int damage, REDamagePrevention::REDamagePrevention(MTGAbility * source, TargetChooser *tcSource, TargetChooser *tcTarget, int damage,
bool oneShot, int typeOfDamage) : bool oneShot, int typeOfDamage) :
@@ -46,8 +47,35 @@ REDamagePrevention::~REDamagePrevention()
{ {
SAFE_DELETE(tcSource); SAFE_DELETE(tcSource);
SAFE_DELETE(tcTarget); SAFE_DELETE(tcTarget);
}
//counters replacement effect///////////////////
RECountersPrevention::RECountersPrevention(MTGAbility * source,MTGCardInstance * cardSource,MTGCardInstance * cardTarget,Counter * counter) :
source(source),cardSource(cardSource),cardTarget(cardTarget),counter(counter)
{
} }
WEvent * RECountersPrevention::replace(WEvent *event)
{
if (!event) return event;
WEventCounters * e = dynamic_cast<WEventCounters*> (event);
if (!e) return event;
if((MTGCardInstance*)e->targetCard)
{
if((MTGCardInstance*)e->targetCard == cardSource && counter)
{
if(e->power == counter->power && e->toughness == counter->toughness && e->name == counter->name)
return event = NULL;
}
else if((MTGCardInstance*)e->targetCard == cardSource)
return event = NULL;
}
return event;
}
RECountersPrevention::~RECountersPrevention()
{
}
//////////////////////////////////////////////
ReplacementEffects::ReplacementEffects() ReplacementEffects::ReplacementEffects()
{ {
} }
+1
View File
@@ -34,6 +34,7 @@ SimpleMenu::SimpleMenu(int id, JGuiListener* listener, int fontId, float x, floa
: JGuiController(id, listener), fontId(fontId), mCenterHorizontal(centerHorizontal), mCenterVertical(centerVertical) : JGuiController(id, listener), fontId(fontId), mCenterHorizontal(centerHorizontal), mCenterVertical(centerVertical)
{ {
autoTranslate = true; autoTranslate = true;
isMultipleChoice = false;
mHeight = 2 * kVerticalMargin; mHeight = 2 * kVerticalMargin;
mWidth = 0; mWidth = 0;
mX = x; mX = x;
+2
View File
@@ -65,6 +65,8 @@ string Subtypes::find(unsigned int id)
bool Subtypes::isSubtypeOfType(unsigned int subtype, unsigned int type) bool Subtypes::isSubtypeOfType(unsigned int subtype, unsigned int type)
{ {
if(subtype >= size_t(subtypesToType.size()))
return false;
return (subtypesToType[subtype] == type); return (subtypesToType[subtype] == type);
} }
+99 -100
View File
@@ -43,10 +43,10 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
}; };
found = s.find("other "); found = s.find("other ");
if (found == 0) if (found != string::npos)
{ {
other = true; other = true;
s = s.substr(6); s = s.erase(found,found+6-found);
} }
found = s.find("trigger"); found = s.find("trigger");
@@ -65,13 +65,20 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
if (found != string::npos) if (found != string::npos)
{ {
int maxtargets = 1; int maxtargets = 1;
size_t several = s.find_first_of('s', 5); size_t several = s.find("<anyamount>");
if (several != string::npos) maxtargets = -1; if (several != string::npos) maxtargets = TargetChooser::UNLITMITED_TARGETS;
found = s.find("creature"); found = s.find("creature");
if (found != string::npos) return NEW DamageableTargetChooser(card, maxtargets, other); //Any Damageable target (player, creature) if (found != string::npos) return NEW DamageableTargetChooser(card, maxtargets, other); //Any Damageable target (player, creature)
return NEW PlayerTargetChooser(card, maxtargets); //Any player return NEW PlayerTargetChooser(card, maxtargets); //Any player
} }
found = s.find("proliferation");
if (found != string::npos)
{
int maxtargets = TargetChooser::UNLITMITED_TARGETS;
return NEW ProliferateChooser(card, maxtargets); //Any player
}
string s1; string s1;
found = s.find("|"); found = s.find("|");
if (found != string::npos) if (found != string::npos)
@@ -152,6 +159,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
TargetChooser * tc = NULL; TargetChooser * tc = NULL;
int maxtargets = 1; int maxtargets = 1;
bool targetMin = false;
CardDescriptor * cd = NULL; CardDescriptor * cd = NULL;
//max targets allowed //max targets allowed
size_t limit = s1.find('<'); size_t limit = s1.find('<');
@@ -162,8 +170,18 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
if (end != string::npos) if (end != string::npos)
{ {
howmany = s1.substr(limit + 1, end - limit - 1); howmany = s1.substr(limit + 1, end - limit - 1);
WParsedInt * howmuch = NEW WParsedInt(howmany, NULL, card); size_t uptoamount= howmany.find("upto:");
maxtargets = howmuch->getValue();
if(uptoamount != string::npos)
{
howmany = s1.substr(uptoamount + 6, end - uptoamount - 6);
}
else
{
targetMin = true;//if upto: is not found, then we need to have a minimum of the amount....
}
WParsedInt * howmuch = NEW WParsedInt(howmany, (Spell*)card, card);
howmany.find("anyamount") != string::npos?maxtargets = TargetChooser::UNLITMITED_TARGETS:maxtargets = howmuch->getValue();
delete howmuch; delete howmuch;
s1 = s1.substr(end + 1); s1 = s1.substr(end + 1);
} }
@@ -195,6 +213,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
while (attributes.size()) while (attributes.size())
{ {
size_t found2 = attributes.find(";"); size_t found2 = attributes.find(";");
size_t foundAnd = attributes.find("&");
string attribute; string attribute;
if (found2 != string::npos) if (found2 != string::npos)
{ {
@@ -202,6 +221,12 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
attribute = attributes.substr(0, found2); attribute = attributes.substr(0, found2);
attributes = attributes.substr(found2 + 1); attributes = attributes.substr(found2 + 1);
} }
else if (foundAnd != string::npos)
{
cd->mode = CD_AND;
attribute = attributes.substr(0, foundAnd);
attributes = attributes.substr(foundAnd + 1);
}
else else
{ {
attribute = attributes; attribute = attributes;
@@ -396,71 +421,6 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->setisMultiColored(1); cd->setisMultiColored(1);
} }
}
else if (attribute.find("blackandgreen") != string::npos)
{
//card is both colors?
if (minus)
{
cd->setisBlackAndGreen(-1);
}
else
{
cd->setisBlackAndGreen(1);
}
}
else if (attribute.find("blackandwhite") != string::npos)
{
//card is both colors?
if (minus)
{
cd->setisBlackAndWhite(-1);
}
else
{
cd->setisBlackAndWhite(1);
}
}
else if (attribute.find("redandblue") != string::npos)
{
//card is both colors?
if (minus)
{
cd->setisRedAndBlue(-1);
}
else
{
cd->setisRedAndBlue(1);
}
}
else if (attribute.find("blueandgreen") != string::npos)
{
//card is both colors?
if (minus)
{
cd->setisBlueAndGreen(-1);
}
else
{
cd->setisBlueAndGreen(1);
}
}
else if (attribute.find("redandwhite") != string::npos)
{
//card is both colors?
if (minus)
{
cd->setisRedAndWhite(-1);
}
else
{
cd->setisRedAndWhite(1);
}
} }
else if (attribute.find("power") != string::npos) else if (attribute.find("power") != string::npos)
{ {
@@ -615,20 +575,13 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->mode = CD_AND; cd->mode = CD_AND;
typeName = typeName.substr(0, found); typeName = typeName.substr(0, found);
} }
//X targets allowed ?
if (typeName.at(typeName.length() - 1) == 's' && !Subtypes::subtypesList->find(typeName, false) && typeName.compare("this")
!= 0)
{
typeName = typeName.substr(0, typeName.length() - 1);
maxtargets = -1;
}
if (cd) if (cd)
{ {
if (!tc) if (!tc)
{ {
if (typeName.compare("*") != 0) cd->setSubtype(typeName); if (typeName.compare("*") != 0) cd->setSubtype(typeName);
tc = NEW DescriptorTargetChooser(cd, zones, nbzones, card, maxtargets, other); tc = NEW DescriptorTargetChooser(cd, zones, nbzones, card, maxtargets, other, targetMin);
} }
else else
{ {
@@ -642,7 +595,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
{ {
if (typeName.compare("*") == 0) if (typeName.compare("*") == 0)
{ {
return NEW TargetZoneChooser(zones, nbzones, card, maxtargets, other); return NEW TargetZoneChooser(zones, nbzones, card, maxtargets, other, targetMin);
} }
else if (typeName.compare("this") == 0) else if (typeName.compare("this") == 0)
{ {
@@ -650,7 +603,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
} }
else else
{ {
tc = NEW TypeTargetChooser(typeName.c_str(), zones, nbzones, card, maxtargets, other); tc = NEW TypeTargetChooser(typeName.c_str(), zones, nbzones, card, maxtargets, other, targetMin);
} }
} }
else else
@@ -718,7 +671,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(MTGCardInstance * card
} }
} }
TargetChooser::TargetChooser(MTGCardInstance * card, int _maxtargets, bool _other) : TargetChooser::TargetChooser(MTGCardInstance * card, int _maxtargets, bool _other,bool _targetMin) :
TargetsList() TargetsList()
{ {
forceTargetListReady = 0; forceTargetListReady = 0;
@@ -726,6 +679,11 @@ TargetChooser::TargetChooser(MTGCardInstance * card, int _maxtargets, bool _othe
targetter = card; targetter = card;
maxtargets = _maxtargets; maxtargets = _maxtargets;
other = _other; other = _other;
targetMin = _targetMin;
done = false;
attemptsToFill = 0;
if(source)
Owner = source->controller();
} }
//Default targetter : every card can be targetted, unless it is protected from the targetter card //Default targetter : every card can be targetted, unless it is protected from the targetter card
@@ -810,10 +768,11 @@ int TargetChooser::targetListSet()
return 0; return 0;
} }
bool TargetChooser::validTargetsExist() bool TargetChooser::validTargetsExist(int maxTargets)
{ {
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
int maxAmount = 0;
Player *p = GameObserver::GetInstance()->players[i]; Player *p = GameObserver::GetInstance()->players[i];
if (canTarget(p)) return true; if (canTarget(p)) return true;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile }; MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile };
@@ -824,10 +783,12 @@ bool TargetChooser::validTargetsExist()
{ {
for (int j = 0; j < z->nb_cards; j++) for (int j = 0; j < z->nb_cards; j++)
{ {
if (canTarget(z->cards[j])) return true; if (canTarget(z->cards[j])) maxAmount++;
} }
} }
} }
if(maxAmount >= maxTargets)
return true;
} }
return false; return false;
} }
@@ -838,6 +799,8 @@ int TargetChooser::countValidTargets()
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
Player *p = GameObserver::GetInstance()->players[i]; Player *p = GameObserver::GetInstance()->players[i];
if(canTarget(p))
result++;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile }; MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile };
for (int k = 0; k < 5; k++) for (int k = 0; k < 5; k++)
{ {
@@ -909,8 +872,8 @@ bool CardTargetChooser::equals(TargetChooser * tc)
/** /**
Choose anything that has a given list of types Choose anything that has a given list of types
**/ **/
TypeTargetChooser::TypeTargetChooser(const char * _type, MTGCardInstance * card, int _maxtargets, bool other) : TypeTargetChooser::TypeTargetChooser(const char * _type, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(card, _maxtargets, other) TargetZoneChooser(card, _maxtargets, other,targetMin)
{ {
int id = Subtypes::subtypesList->find(_type); int id = Subtypes::subtypesList->find(_type);
nbtypes = 0; nbtypes = 0;
@@ -920,8 +883,8 @@ TypeTargetChooser::TypeTargetChooser(const char * _type, MTGCardInstance * card,
} }
TypeTargetChooser::TypeTargetChooser(const char * _type, int * _zones, int nbzones, MTGCardInstance * card, int _maxtargets, TypeTargetChooser::TypeTargetChooser(const char * _type, int * _zones, int nbzones, MTGCardInstance * card, int _maxtargets,
bool other) : bool other,bool targetMin) :
TargetZoneChooser(card, _maxtargets, other) TargetZoneChooser(card, _maxtargets, other,targetMin)
{ {
int id = Subtypes::subtypesList->find(_type); int id = Subtypes::subtypesList->find(_type);
nbtypes = 0; nbtypes = 0;
@@ -1021,8 +984,8 @@ bool TypeTargetChooser ::equals(TargetChooser * tc)
/** /**
A Target Chooser associated to a Card Descriptor object, for fine tuning of targets description A Target Chooser associated to a Card Descriptor object, for fine tuning of targets description
**/ **/
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card, int _maxtargets, bool other) : DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(card, _maxtargets, other) TargetZoneChooser(card, _maxtargets, other,targetMin)
{ {
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD }; int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2); init(default_zones, 2);
@@ -1030,8 +993,8 @@ DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGCardIn
} }
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card, DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card,
int _maxtargets, bool other) : int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(card, _maxtargets, other) TargetZoneChooser(card, _maxtargets, other,targetMin)
{ {
if (nbzones == 0) if (nbzones == 0)
{ {
@@ -1092,14 +1055,14 @@ bool DescriptorTargetChooser::equals(TargetChooser * tc)
} }
/* TargetzoneChooser targets everything in a given zone */ /* TargetzoneChooser targets everything in a given zone */
TargetZoneChooser::TargetZoneChooser(MTGCardInstance * card, int _maxtargets, bool other) : TargetZoneChooser::TargetZoneChooser(MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetChooser(card, _maxtargets, other) TargetChooser(card, _maxtargets, other,targetMin)
{ {
init(NULL, 0); init(NULL, 0);
} }
TargetZoneChooser::TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card, int _maxtargets, bool other) : TargetZoneChooser::TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetChooser(card, _maxtargets, other) TargetChooser(card, _maxtargets, other,targetMin)
{ {
init(_zones, _nbzones); init(_zones, _nbzones);
} }
@@ -1275,8 +1238,8 @@ bool DamageableTargetChooser::equals(TargetChooser * tc)
/*Spell */ /*Spell */
SpellTargetChooser::SpellTargetChooser(MTGCardInstance * card, int _color, int _maxtargets, bool other) : SpellTargetChooser::SpellTargetChooser(MTGCardInstance * card, int _color, int _maxtargets, bool other,bool targetMin) :
TargetChooser(card, _maxtargets, other) TargetChooser(card, _maxtargets, other,targetMin)
{ {
color = _color; color = _color;
} }
@@ -1318,8 +1281,8 @@ bool SpellTargetChooser::equals(TargetChooser * tc)
} }
/*Spell or Permanent */ /*Spell or Permanent */
SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(MTGCardInstance * card, int _color, int _maxtargets, bool other) : SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(MTGCardInstance * card, int _color, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(card, _maxtargets, other) TargetZoneChooser(card, _maxtargets, other,targetMin)
{ {
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD }; int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2); init(default_zones, 2);
@@ -1444,3 +1407,39 @@ bool TriggerTargetChooser::equals(TargetChooser * tc)
return TargetChooser::equals(tc); return TargetChooser::equals(tc);
} }
/*Proliferate Target */
bool ProliferateChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (target->typeAsTarget() == TARGET_CARD)
{
MTGCardInstance * card = (MTGCardInstance*)target;
if(card->counters && card->counters->counters.empty())
return false;
return true;
}
if (target->typeAsTarget() == TARGET_PLAYER)
{
Player * p = (Player*)target;
if(!p->poisonCount)
return false;
return true;
}
return TypeTargetChooser::canTarget(target,withoutProtections);
}
ProliferateChooser* ProliferateChooser::clone() const
{
ProliferateChooser * a = NEW ProliferateChooser(*this);
return a;
}
bool ProliferateChooser::equals(TargetChooser * tc)
{
ProliferateChooser * dtc = dynamic_cast<ProliferateChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
+18 -4
View File
@@ -20,8 +20,23 @@ int TargetsList::addTarget(Targetable * target)
{ {
if (!alreadyHasTarget(target)) if (!alreadyHasTarget(target))
{ {
targets.push_back(target); GameObserver * state = state->GetInstance();
return 1; TargetChooser * tc = state->getCurrentTargetChooser();
if(!tc || (tc && tc->maxtargets == 1))
{
//because this was originally coded with targets as an array
//we have to add this condiational to insure that cards with single target effects
//and abilities that seek the nextcardtarget still work correctly.
targets.clear();
targets.push_back(target);
return 1;
}
else
{
targets.push_back(target);
return 1;
}
} }
return 0; return 0;
@@ -46,7 +61,6 @@ int TargetsList::removeTarget(Targetable * target)
return 1; return 1;
} }
} }
return 0; return 0;
} }
@@ -72,7 +86,7 @@ Targetable * TargetsList::getNextTarget(Targetable * previous, int type)
{ {
if (found && (type == -1 || targets[i]->typeAsTarget() == type)) if (found && (type == -1 || targets[i]->typeAsTarget() == type))
{ {
return (targets[i]); return targets[i];
} }
if (targets[i] == previous) found = 1; if (targets[i] == previous) found = 1;
} }
+10
View File
@@ -37,6 +37,11 @@ WEventCardUpdate::WEventCardUpdate(MTGCardInstance * card) :
} }
; ;
WEventCounters::WEventCounters(Counters *counter,string name,int power,int toughness,bool added,bool removed) :
WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(added),removed(removed)
{
}
WEventPhaseChange::WEventPhaseChange(Phase * from, Phase * to) : WEventPhaseChange::WEventPhaseChange(Phase * from, Phase * to) :
WEvent(CHANGE_PHASE), from(from), to(to) WEvent(CHANGE_PHASE), from(from), to(to)
{ {
@@ -168,6 +173,11 @@ Targetable * WEventLife::getTarget(int target)
return NULL; return NULL;
} }
Targetable * WEventCounters::getTarget()
{
return targetCard;
}
Targetable * WEventVampire::getTarget(int target) Targetable * WEventVampire::getTarget(int target)
{ {
switch (target) switch (target)