diff --git a/projects/mtg/include/AIPlayer.h b/projects/mtg/include/AIPlayer.h index cfec89593..71bbe748b 100644 --- a/projects/mtg/include/AIPlayer.h +++ b/projects/mtg/include/AIPlayer.h @@ -18,6 +18,7 @@ using std::queue; #define INFO_CREATURESTOUGHNESS 3 #define INFO_CREATURESATTACKINGPOWER 4 + class AIStats; class AIAction @@ -33,26 +34,23 @@ public: bool checked; MTGCardInstance * click; MTGCardInstance * target; // TODO Improve - - AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL) : - efficiency(-1), ability(a), player(NULL), click(c), target(t) + + AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL) + : efficiency(-1), ability(a), player(NULL), click(c), target(t) { id = currentId++; - } - ; + }; - AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL) : - efficiency(-1), ability(NULL), player(NULL), click(c), target(t) + AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL) + : efficiency(-1), ability(NULL), player(NULL), click(c), target(t) { id = currentId++; - } - ; - - AIAction(Player * p) : - efficiency(-1), ability(NULL), player(p), click(NULL), target(NULL) + }; + + AIAction(Player * p) + : efficiency(-1), ability(NULL), player(p), click(NULL), target(NULL) { - } - ; + }; int getEfficiency(); int Act(); @@ -60,24 +58,22 @@ public: // compares Abilities efficiency class CmpAbilities -{ +{ public: bool operator()(const AIAction& a1, const AIAction& a2) const { - AIAction* a1Ptr = const_cast (&a1); - AIAction* a2Ptr = const_cast (&a2); + AIAction* a1Ptr = const_cast(&a1); + AIAction* a2Ptr = const_cast(&a2); int e1 = a1Ptr->getEfficiency(); int e2 = a2Ptr->getEfficiency(); - if (e1 == e2) - return a1Ptr->id < a2Ptr->id; + if (e1 == e2) return a1Ptr->id < a2Ptr->id; return (e1 > e2); } }; typedef std::map RankingContainer; -class AIPlayer: public Player -{ +class AIPlayer: public Player{ protected: //Variables used by Test suite MTGCardInstance * nextCardToPlay; @@ -90,40 +86,29 @@ protected: int chooseBlockers(); int canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy); int effectBadOrGood(MTGCardInstance * card, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL); - int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES, int untapMode = 0, int canAttack = 0); + int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0); AIStats * getStats(); // returns 1 if the AI algorithm supports a given cost (ex:simple mana cost), 0 otherwise (ex: cost involves Sacrificing a target) - int CanHandleCost(ManaCost * cost); + int CanHandleCost(ManaCost * cost); public: AIStats * stats; int agressivity; bool Checked; bool forceBestAbilityUse; - void End() - { - } - ; - virtual int displayStack() - { - return 0; - } - ; + void End(){}; + virtual int displayStack() {return 0;}; int receiveEvent(WEvent * event); void Render(); ManaCost * getPotentialMana(MTGCardInstance * card = NULL); AIPlayer(MTGDeck * deck, string deckFile, string deckFileSmall); virtual ~AIPlayer(); virtual MTGCardInstance * chooseCard(TargetChooser * tc, MTGCardInstance * source, int random = 0); - virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget = NULL); + virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget =NULL,MTGCardInstance * Choosencard = NULL); virtual int Act(float dt); virtual int affectCombatDamages(CombatStep); - int isAI() - { - return 1; - } - ; + int isAI(){return 1;}; int canHandleCost(MTGAbility * ability); int selectAbility(); int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingContainer& ranking); @@ -132,24 +117,24 @@ public: }; -class AIPlayerBaka: public AIPlayer -{ -protected: - int oldGamePhase; - float timer; - MTGCardInstance * FindCardToPlay(ManaCost * potentialMana, const char * type); -public: - int deckId; - AIPlayerBaka(MTGDeck * deck, string deckFile, string deckfileSmall, string avatarFile); - virtual int Act(float dt); - void initTimer(); - virtual int computeActions(); + +class AIPlayerBaka: public AIPlayer{ + protected: + int oldGamePhase; + float timer; + MTGCardInstance * FindCardToPlay(ManaCost * potentialMana, const char * type); + public: + int deckId; + AIPlayerBaka(MTGDeck * deck, string deckFile, string deckfileSmall, string avatarFile); + virtual int Act(float dt); + void initTimer(); + virtual int computeActions(); }; -class AIPlayerFactory -{ -public: - AIPlayer * createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid = 0); +class AIPlayerFactory{ + public: + AIPlayer * createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid = 0); }; + #endif diff --git a/projects/mtg/include/ActionStack.h b/projects/mtg/include/ActionStack.h index 89e325108..a540a1327 100644 --- a/projects/mtg/include/ActionStack.h +++ b/projects/mtg/include/ActionStack.h @@ -9,6 +9,7 @@ #define MAX_SPELL_TARGETS 10 + #define ACTION_SPELL 10 #define ACTION_DAMAGE 11 #define ACTION_DAMAGES 12 @@ -38,197 +39,172 @@ class DamageStack; class ManaCost; class TargetChooser; + #define ACTIONSTACK_STANDARD 0 #define ACTIONSTACK_TARGET 1 -class Interruptible: public PlayGuiObject, public Targetable -{ -public: - //TODO : remove these when they are back in PlayGuiObject - float x, y; +class Interruptible: public PlayGuiObject, public Targetable{ + public: + //TODO : remove these when they are back in PlayGuiObject + float x, y; - int state, display; - MTGCardInstance * source; - virtual void Entering() - { - mHasFocus = true; - } - ; - virtual bool Leaving(JButton key) - { - mHasFocus = false; - return true; - } - ; - virtual bool ButtonPressed() - { - return true; - } - ; - virtual int resolve() - { - return 0; - } - ; - virtual void Render() - { - } - ; - int typeAsTarget() - { - return TARGET_STACKACTION; - } - ; - Interruptible(bool hasFocus = false) : - PlayGuiObject(40, x, y, hasFocus) - { - state = NOT_RESOLVED; - display = 0; - source = NULL; - } - ; - virtual const string getDisplayName() const; - void Render(MTGCardInstance * source, JQuad * targetQuad, string alt1, string alt2, string action, bool bigQuad = false); - virtual int receiveEvent(WEvent * event) - { - return 0; - } - ; + int state, display; + MTGCardInstance * source; + virtual void Entering(){mHasFocus = true;}; + virtual bool Leaving(JButton key){mHasFocus = false;return true;}; + virtual bool ButtonPressed(){return true;}; + virtual int resolve(){return 0;}; + virtual void Render(){}; + int typeAsTarget(){return TARGET_STACKACTION;}; + Interruptible(bool hasFocus = false):PlayGuiObject(40,x,y,hasFocus){state=NOT_RESOLVED;display=0;source=NULL;}; + virtual const string getDisplayName() const; + void Render(MTGCardInstance * source, JQuad * targetQuad, string alt1, string alt2, string action, bool bigQuad = false); + virtual int receiveEvent(WEvent * event) {return 0;}; #if defined (WIN32) || defined (LINUX) || defined (IOS) - virtual void Dump(); + virtual void Dump(); #endif protected: - float GetVerticalTextOffset() const; + float GetVerticalTextOffset() const; }; -class NextGamePhase: public Interruptible -{ -public: - int resolve(); - bool extraDamagePhase(); - void Render(); - virtual ostream& toString(ostream& out) const; - virtual const string getDisplayName() const; - NextGamePhase(int id); +class NextGamePhase: public Interruptible { + public: + int resolve(); + bool extraDamagePhase(); + void Render(); + virtual ostream& toString(ostream& out) const; + virtual const string getDisplayName() const; + NextGamePhase(int id); }; -class Spell: public Interruptible -{ -protected: +class Spell: public Interruptible { + protected: -public: - MTGGameZone * from; - TargetChooser * tc; - ManaCost * cost; - int payResult; - int computeX(MTGCardInstance * card); - int computeXX(MTGCardInstance * card); - Spell(MTGCardInstance* _source); - Spell(int id, MTGCardInstance* _source, TargetChooser *_tc, ManaCost * _cost, int payResult); - ~Spell(); - int resolve(); - void Render(); - bool FullfilledAlternateCost(const int &costType); - const string getDisplayName() const; - virtual ostream& toString(ostream& out) const; - MTGCardInstance * getNextCardTarget(MTGCardInstance * previous = 0); - Player * getNextPlayerTarget(Player * previous = 0); - Damageable * getNextDamageableTarget(Damageable * previous = 0); - Interruptible * getNextInterruptible(Interruptible * previous, int type); - Spell * getNextSpellTarget(Spell * previous = 0); - Damage * getNextDamageTarget(Damage * previous = 0); - Targetable * getNextTarget(Targetable * previous = 0, int type = -1); - int getNbTargets(); + public: + MTGGameZone * from; + TargetChooser * tc; + ManaCost * cost; + int payResult; + int computeX(MTGCardInstance * card); + int computeXX(MTGCardInstance * card); + Spell(MTGCardInstance* _source); + Spell(int id, MTGCardInstance* _source, TargetChooser *_tc, ManaCost * _cost, int payResult); + ~Spell(); + int resolve(); + void Render(); + bool FullfilledAlternateCost(const int &costType); + const string getDisplayName() const; + virtual ostream& toString(ostream& out) const; + MTGCardInstance * getNextCardTarget(MTGCardInstance * previous = 0); + Player * getNextPlayerTarget(Player * previous = 0); + Damageable * getNextDamageableTarget(Damageable * previous = 0); + Interruptible * getNextInterruptible(Interruptible * previous, int type); + Spell * getNextSpellTarget(Spell * previous = 0); + Damage * getNextDamageTarget(Damage * previous = 0); + Targetable * getNextTarget(Targetable * previous = 0, int type = -1); + int getNbTargets(); }; -class StackAbility: public Interruptible -{ -public: - MTGAbility * ability; - int resolve(); - void Render(); - virtual ostream& toString(ostream& out) const; - virtual const string getDisplayName() const; - StackAbility(int id, MTGAbility * _ability); +class StackAbility: public Interruptible { + public: + MTGAbility * ability; + int resolve(); + void Render(); + virtual ostream& toString(ostream& out) const; + virtual const string getDisplayName() const; + StackAbility(int id, MTGAbility * _ability); }; -class PutInGraveyard: public Interruptible -{ -public: - MTGCardInstance * card; - int removeFromGame; - int resolve(); - void Render(); - virtual ostream& toString(ostream& out) const; - PutInGraveyard(int id, MTGCardInstance * _card); +class PutInGraveyard: public Interruptible { + public: + MTGCardInstance * card; + int removeFromGame; + int resolve(); + void Render(); + virtual ostream& toString(ostream& out) const; + PutInGraveyard(int id, MTGCardInstance * _card); }; -class DrawAction: public Interruptible -{ -public: - int nbcards; - Player * player; - int resolve(); - void Render(); - virtual ostream& toString(ostream& out) const; - DrawAction(int id, Player * _player, int _nbcards); + +class DrawAction: public Interruptible { + public: + int nbcards; + Player * player; + int resolve(); + void Render(); + virtual ostream& toString(ostream& out) const; + DrawAction(int id, Player * _player, int _nbcards); }; -class ActionStack: public GuiLayer -{ -protected: - JQuad * pspIcons[8]; - GameObserver* game; - int interruptDecision[2]; - float timer; - int currentState; - int mode; - int checked; +class LifeAction: public Interruptible { + public: + int amount; + Damageable * target; + int resolve(); + void Render(); + virtual ostream& toString(ostream& out) const; + LifeAction(int id, Damageable * _target, int amount); +}; -public: +class ActionStack :public GuiLayer{ + protected: + JQuad * pspIcons[8]; + GameObserver* game; + int interruptDecision[2]; + float timer; + int currentState; + int mode; + int checked; - enum - { - NOT_DECIDED = 0, - INTERRUPT = -1, - DONT_INTERRUPT = 1, - DONT_INTERRUPT_ALL = 2, - }; + public: - int setIsInterrupting(Player * player); - int count(int type = 0, int state = 0, int display = -1); - Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0, int display = -1); - int getPreviousIndex(Interruptible * next, int type = 0, int state = 0, int display = -1); - Interruptible * getNext(Interruptible * previous, int type = 0, int state = 0, int display = -1); - int getNextIndex(Interruptible * previous, int type = 0, int state = 0, int display = -1); - void Fizzle(Interruptible * action); - Interruptible * getAt(int id); - void cancelInterruptOffer(int cancelMode = 1); - void endOfInterruption(); - Interruptible * getLatest(int state); - Player * askIfWishesToInterrupt; - int garbageCollect(); - int addAction(Interruptible * interruptible); - Spell * addSpell(MTGCardInstance* card, TargetChooser * tc, ManaCost * mana, int payResult, int storm); - int AddNextGamePhase(); - int AddNextCombatStep(); - int addPutInGraveyard(MTGCardInstance * card); - int addDraw(Player * player, int nbcards = 1); - int addDamage(MTGCardInstance * _source, Damageable * target, int _damage); - int addAbility(MTGAbility * ability); - void Update(float dt); - bool CheckUserInput(JButton key); - virtual void Render(); - ActionStack(GameObserver* game); - int resolve(); - int has(Interruptible * action); - int has(MTGAbility * ability); - int receiveEventPlus(WEvent * event); + enum + { + NOT_DECIDED = 0, + INTERRUPT = -1, + DONT_INTERRUPT = 1, + DONT_INTERRUPT_ALL = 2, + }; + + int setIsInterrupting(Player * player); + int count( int type = 0 , int state = 0 , int display = -1); + Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1); + int getPreviousIndex(Interruptible * next, int type = 0, int state = 0 , int display = -1); + Interruptible * getNext(Interruptible * previous, int type = 0, int state = 0 , int display = -1); + int getNextIndex(Interruptible * previous, int type = 0, int state = 0 , int display = -1); + void Fizzle(Interruptible * action); + Interruptible * getAt(int id); + void cancelInterruptOffer(int cancelMode = 1); + void endOfInterruption(); + Interruptible * getLatest(int state); + Player * askIfWishesToInterrupt; + int garbageCollect(); + int addAction(Interruptible * interruptible); + Spell * addSpell(MTGCardInstance* card, TargetChooser * tc, ManaCost * mana, int payResult, int storm); + int AddNextGamePhase(); + int AddNextCombatStep(); + int addPutInGraveyard(MTGCardInstance * card); + int addDraw(Player * player, int nbcards = 1); + int addLife(Damageable * _target,int amount = 0); + int addDamage(MTGCardInstance * _source, Damageable * target, int _damage); + int addAbility(MTGAbility * ability); + void Update(float dt); + bool CheckUserInput(JButton key); + virtual void Render(); + ActionStack(GameObserver* game); + int resolve(); + int has(Interruptible * action); + int has(MTGAbility * ability); + int receiveEventPlus(WEvent * event); #if defined (WIN32) || defined (LINUX) || defined (IOS) - void Dump(); + void Dump(); #endif }; + + + + #endif diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 8bcbc8d60..3e100c823 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -34,11 +34,13 @@ public: int computeX(Spell * spell, MTGCardInstance * card) { if (spell) return spell->computeX(card); + if (card) return card->X; return 1; //this should only hapen when the ai calls the ability. This is to give it an idea of the "direction" of X (positive/negative) } int computeXX(Spell * spell, MTGCardInstance * card) { if (spell) return spell->computeXX(card); + if (card) return card->XX; return 1; //this should only hapen when the ai calls the ability. This is to give it an idea of the "direction" of X (positive/negative) } WParsedInt(int value = 0) @@ -49,6 +51,7 @@ public: WParsedInt(string s, Spell * spell, MTGCardInstance * card) { MTGCardInstance * target = card->target; + intValue = 0; if (!target) target = card; int multiplier = 1; if (s[0] == '-') @@ -59,19 +62,33 @@ public: if (s == "x" || s == "X") { intValue = computeX(spell, card); + if(intValue < 0) + intValue = 0; } else if (s == "xx" || s == "XX") { intValue = computeXX(spell, card); + if(intValue < 0) + intValue = 0; } else if (s == "gear") { intValue = target->equipment; } + else if (s == "auras") + { + intValue = target->auras; + } else if (s == "manacost") { intValue = target->getManaCost()->getConvertedCost(); } + else if (s.find("type:") != string::npos) + { + size_t begins = s.find(":"); + string theType = s.substr(begins + 1); + intValue = target->controller()->game->inPlay->countByType(theType.c_str()); + } else if (s == "sunburst") { intValue = 0; @@ -84,6 +101,29 @@ public: { intValue = target->controller()->life; } + else if (s == "thatmuch") + { + intValue = 0; + intValue = target->thatmuch; + int checkagain = 0; + if(target->hasSubtype("aura") || target->hasSubtype("equipment")) + { + if(target->target) + { + checkagain = target->target->thatmuch; + } + } + if(checkagain > intValue) + intValue = checkagain; + } + else if (s == "oplifelost") + { + intValue = target->controller()->opponent()->lifeLostThisTurn; + } + else if (s == "lifelost") + { + intValue = target->controller()->lifeLostThisTurn; + } else if (s == "pdcount") { intValue = target->controller()->damageCount; @@ -162,10 +202,14 @@ class TrCardAddedToZone: public TriggeredAbility public: TargetZoneChooser * toTcZone, *fromTcZone; TargetChooser * toTcCard, *fromTcCard; + bool once; + bool sourceUntapped; + bool activeTrigger; TrCardAddedToZone(int id, MTGCardInstance * source, TargetZoneChooser * toTcZone, TargetChooser * toTcCard, - TargetZoneChooser * fromTcZone = NULL, TargetChooser * fromTcCard = NULL) : - TriggeredAbility(id, source), toTcZone(toTcZone), fromTcZone(fromTcZone), toTcCard(toTcCard), fromTcCard(fromTcCard) + TargetZoneChooser * fromTcZone = NULL, TargetChooser * fromTcCard = NULL,bool once = false,bool sourceUntapped = false) : + TriggeredAbility(id, source), toTcZone(toTcZone), fromTcZone(fromTcZone), toTcCard(toTcCard), fromTcCard(fromTcCard),once(once),sourceUntapped(sourceUntapped) { + activeTrigger = true; } ; @@ -176,9 +220,13 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventZoneChange * e = dynamic_cast (event); if (!e) return 0; - + if(sourceUntapped == true && source->isTapped() == 1) + return 0; + if(activeTrigger == false) + return 0; if (!toTcZone->targetsZone(e->to)) return 0; if (!toTcCard->canTarget(e->card)) return 0; if (fromTcZone && !fromTcZone->targetsZone(e->from)) return 0; @@ -191,7 +239,9 @@ public: { return 0; } - return 1; + if(once == true && activeTrigger == true) + activeTrigger = false; + return 1; } ~TrCardAddedToZone() @@ -227,6 +277,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardTap * e = dynamic_cast (event); if (!e) return 0; if (e->before == e->after) return 0; @@ -265,6 +316,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardTappedForMana * e = dynamic_cast (event); if (!e) return 0; if (e->before == e->after) return 0; @@ -302,6 +354,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardAttackedNotBlocked * e = dynamic_cast (event); if (!e) return 0; if (e->card->didattacked < 1) return 0; @@ -340,6 +393,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardAttackedBlocked * e = dynamic_cast (event); if (!e) return 0; if (e->card->didattacked < 1) return 0; @@ -367,8 +421,9 @@ class TrCardAttacked: public TriggeredAbility { public: TargetChooser * tc; - TrCardAttacked(int id, MTGCardInstance * source, TargetChooser * tc) : - TriggeredAbility(id, source), tc(tc) + bool sourceUntapped; + TrCardAttacked(int id, MTGCardInstance * source, TargetChooser * tc,bool sourceUntapped) : + TriggeredAbility(id, source), tc(tc), sourceUntapped(sourceUntapped) { } @@ -379,8 +434,11 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardAttacked * e = dynamic_cast (event); if (!e) return 0; + if (sourceUntapped == true && source->isTapped() == 1) + return 0; if (e->card->didattacked < 1) return 0; if (!tc->canTarget(e->card)) return 0; return 1; @@ -415,6 +473,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardAttackedAlone * e = dynamic_cast (event); if (!e) return 0; if (e->card->didattacked < 1) return 0; @@ -440,9 +499,12 @@ class TrCardBlocked: public TriggeredAbility public: TargetChooser * tc; TargetChooser * fromTc; - TrCardBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL) : - TriggeredAbility(id, source), tc(tc), fromTc(fromTc) + bool once; + bool activeTrigger; + TrCardBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL,bool once = false) : + TriggeredAbility(id, source), tc(tc), fromTc(fromTc), once(once) { + activeTrigger = true; } int resolve() @@ -452,11 +514,16 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardBlocked * e = dynamic_cast (event); if (!e) return 0; + if(activeTrigger == false) + return 0; //if(e->card->didblocked < 1) return 0; if (fromTc && !fromTc->canTarget(e->card->getNextOpponent())) return 0; if (!tc->canTarget(e->card)) return 0; + if(once == true && activeTrigger == true) + activeTrigger = false; return 1; } @@ -490,6 +557,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventcardDraw * e = dynamic_cast (event); if (!e) return 0; if (!tc->canTarget(e->player)) return 0; @@ -525,6 +593,7 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardSacrifice * e = dynamic_cast (event); if (!e) return 0; if (!tc->canTarget(e->card)) return 0; @@ -559,6 +628,7 @@ public: } int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventCardDiscard * e = dynamic_cast (event); if (!e) return 0; if (!tc->canTarget(e->card)) return 0; @@ -582,8 +652,9 @@ public: TargetChooser * tc; TargetChooser * fromTc; int type;//this allows damagenoncombat and combatdamage to share this trigger - TrDamaged(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0) : - TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type) + bool sourceUntapped; + TrDamaged(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0,bool sourceUntapped = false) : + TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type) , sourceUntapped(sourceUntapped) { } @@ -594,12 +665,17 @@ public: int triggerOnEvent(WEvent * event) { + if(source->isPhased) return 0; WEventDamage * e = dynamic_cast (event); if (!e) return 0; + if (sourceUntapped == true && source->isTapped() == 1) + return 0; if (!tc->canTarget(e->damage->target)) return 0; if (fromTc && !fromTc->canTarget(e->damage->source)) return 0; if (type == 1 && e->damage->typeOfDamage != DAMAGE_COMBAT) return 0; if (type == 2 && e->damage->typeOfDamage == DAMAGE_COMBAT) return 0; + e->damage->target->thatmuch = e->damage->damage; + e->damage->source->thatmuch = e->damage->damage; return 1; } @@ -617,24 +693,232 @@ public: } }; +class TrLifeGained: public TriggeredAbility +{ +public: + TargetChooser * tc; + TargetChooser * fromTc; + int type;//this allows damagenoncombat and combatdamage to share this trigger + bool sourceUntapped; + TrLifeGained(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0,bool sourceUntapped = false) : + TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type) , sourceUntapped(sourceUntapped) + { + } + + int resolve() + { + return 0; //This is a trigger, this function should not be called + } + + int triggerOnEvent(WEvent * event) + { + if(source->isPhased) return 0; + WEventLife * e = dynamic_cast (event); + if (!e) return 0; + if (sourceUntapped == true && source->isTapped() == 1) + return 0; + if (!tc->canTarget(e->player)) return 0; + if (fromTc && !fromTc->canTarget(e->player)) return 0; + if (type == 1 && (e->amount > 0 || e->Ltype == 0)) return 0; + if (type == 0 && (e->amount < 0 || e->Ltype == 1)) return 0; + if(type != 1) + e->player->thatmuch = e->amount; + else + e->player->thatmuch = abs(e->amount); + return 1; + } + + ~TrLifeGained() + { + SAFE_DELETE(tc); + SAFE_DELETE(fromTc); + } + + TrLifeGained * clone() const + { + TrLifeGained * a = NEW TrLifeGained(*this); + a->isClone = 1; + return a; + } +}; + +//vampire trigger +class TrVampired: public TriggeredAbility +{ +public: + TargetChooser * tc; + TargetChooser * fromTc; + vector victems; + int type; + TrVampired(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0) : + TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type) + { + } + + int resolve() + { + return 0; //This is a trigger, this function should not be called + } + + int triggerOnEvent(WEvent * event) + { + if(source->isPhased) return 0; + WEventDamage * e = dynamic_cast (event); + WEventZoneChange * z = dynamic_cast (event); + WEventPhaseChange * pe = dynamic_cast(event); + WEventVampire * vamp = dynamic_cast(event); + if (e == event) + { + if (!tc->canTarget(e->damage->target)) return 0; + if (fromTc && !fromTc->canTarget(e->damage->source)) return 0; + + MTGCardInstance * newVictem = (MTGCardInstance*)(e->damage->target); + + victems.push_back(newVictem); + std::sort(victems.begin(), victems.end()); + victems.erase(std::unique(victems.begin(), victems.end()), victems.end()); + } + else if (z == event && !victems.empty()) + { + MTGCardInstance * card = z->card; + + + for(unsigned int k = 0;k < victems.size();k--) + { + if(victems[k] == NULL) + continue; + if(victems[k] != z->card->previous) + { + return 0; + } + } + for(unsigned int w = 0;w < victems.size();w++) + { + if(victems[w] == NULL) + continue; + Player * p = victems[w]->controller(); + if (z->from == p->game->inPlay && z->to == p->game->graveyard) + { + if(victems[w] == z->card->previous) + { + if(!source->isInPlay()) + return 0; + WEvent * e = NEW WEventVampire(victems[w],victems[w],source); + game->receiveEvent(e); + victems[w] = NULL; + return 0; + } + } + } + } + else if (vamp == event) + { + return 1; + } + else if (pe == event) + { + if( pe->from->id == Constants::MTG_PHASE_ENDOFTURN) + { + victems.clear(); + } + } + return 0; + } + + ~TrVampired() + { + SAFE_DELETE(tc); + SAFE_DELETE(fromTc); + } + + TrVampired * clone() const + { + TrVampired * a = NEW TrVampired(*this); + a->isClone = 1; + return a; + } +}; + +//targetted trigger +class TrTargeted: public TriggeredAbility +{ +public: + TargetChooser * tc; + TargetChooser * fromTc; + int type; + TrTargeted(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0) : + TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type) + { + } + + int resolve() + { + return 0; //This is a trigger, this function should not be called + } + + int triggerOnEvent(WEvent * event) + { + if(source->isPhased) return 0; + WEventTarget * e = dynamic_cast (event); + if (!e) return 0; + if (!tc->canTarget(e->card)) return 0; + if (fromTc && !fromTc->canTarget(e->source)) return 0; + + return 1; + } + + ~TrTargeted() + { + SAFE_DELETE(tc); + SAFE_DELETE(fromTc); + } + + TrTargeted * clone() const + { + TrTargeted * a = NEW TrTargeted(*this); + a->isClone = 1; + return a; + } +}; //counters class AACounter: public ActivatedAbility { +public: + string counterstring; + int nb; + int power; + int toughness; + string name; + string menu; + + AACounter(int id, MTGCardInstance * source, MTGCardInstance * target,string counterstring, const char * _name, int power, int toughness, int nb, + ManaCost * cost = NULL, int doTap = 0); + + int resolve(); + const char* getMenuText(); + AACounter * clone() const; +}; + +//counters +class AARemoveAllCounter: public ActivatedAbility +{ public: int nb; int power; int toughness; string name; string menu; + bool all; - AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, int nb, - ManaCost * cost = NULL, int doTap = 0); + AARemoveAllCounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, int nb, + bool all,ManaCost * cost = NULL, int doTap = 0); int resolve(); const char* getMenuText(); - AACounter * clone() const; + AARemoveAllCounter * clone() const; }; + class AAFizzler: public ActivatedAbility { @@ -717,7 +1001,15 @@ public: const char * getMenuText(); AACopier * clone() const; }; - +//imprint +class AAPhaseOut: public ActivatedAbility +{ +public: + AAPhaseOut(int _id, MTGCardInstance * _source, MTGCardInstance * _target = NULL, ManaCost * _cost = NULL); + int resolve(); + const char * getMenuText(); + AAPhaseOut * clone() const; +}; //cloning...this makes a token thats a copy of the target. class AACloner: public ActivatedAbility { @@ -899,7 +1191,7 @@ public: } }; -//ninjutsu +//remove from combat class ACombatRemovel: public ActivatedAbility { @@ -939,8 +1231,11 @@ class AADrawer: public ActivatedAbilityTP { public: WParsedInt *nbcards; + WParsedInt *RefreshedNbcards; + + string nbcardsStr; - AADrawer(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, WParsedInt * _nbcards, int _tap = 0, int who = + AADrawer(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, WParsedInt * nbcards,string nbcardsStr, int _tap = 0, int who = TargetChooser::UNSET); int resolve(); const char * getMenuText(); @@ -968,8 +1263,10 @@ public: class AALifer: public ActivatedAbilityTP { public: + string life_s; WParsedInt *life; - AALifer(int _id, MTGCardInstance * card, Targetable * _target, WParsedInt * life, ManaCost * _cost = NULL, int _tap = 0, + WParsedInt *RefreshedLife; + AALifer(int _id, MTGCardInstance * card, Targetable * _target,string life_s, WParsedInt * life, ManaCost * _cost = NULL, int _tap = 0, int who = TargetChooser::UNSET); int resolve(); const char * getMenuText(); @@ -998,26 +1295,35 @@ public: int power, toughness; int tokenId; string name; + string sabilities; + string starfound; WParsedInt * multiplier; int who; - ATokenCreator(int _id, MTGCardInstance * _source, ManaCost * _cost, int tokenId, int _doTap, WParsedInt * multiplier = NULL, - int who = 0) : - ActivatedAbility(_id, _source, _cost, 0, _doTap), tokenId(tokenId), multiplier(multiplier), who(who) + bool aLivingWeapon; + bool battleReady; + MTGCardInstance * myToken; + vector currentAbilities; + ATokenCreator(int _id, MTGCardInstance * _source, Targetable * _target, ManaCost * _cost, int tokenId, int _doTap,string starfound, WParsedInt * multiplier = NULL, + int who = 0,bool aLivingWeapon = false) : + ActivatedAbility(_id, _source, _cost, 0, _doTap), tokenId(tokenId), starfound(starfound),multiplier(multiplier), who(who),aLivingWeapon(aLivingWeapon) { if (!multiplier) this->multiplier = NEW WParsedInt(1); MTGCard * card = GameApp::collection->getCardById(tokenId); if (card) name = card->data->getName(); + battleReady = false; } - ATokenCreator(int _id, MTGCardInstance * _source, ManaCost * _cost, string sname, string stypes, int _power, int _toughness, - string sabilities, int _doTap, WParsedInt * multiplier = NULL, int who = 0) : - ActivatedAbility(_id, _source, _cost, 0, _doTap), multiplier(multiplier), who(who) + ATokenCreator(int _id, MTGCardInstance * _source, Targetable * _target, ManaCost * _cost, string sname, string stypes, int _power, int _toughness, + string sabilities, int _doTap, string starfound,WParsedInt * multiplier = NULL, int who = 0,bool aLivingWeapon = false) : + ActivatedAbility(_id, _source, _cost, 0, _doTap),sabilities(sabilities),starfound(starfound), multiplier(multiplier), who(who),aLivingWeapon(aLivingWeapon) { power = _power; toughness = _toughness; name = sname; who = who; tokenId = 0; + aType = MTGAbility::STANDARD_TOKENCREATOR; + battleReady = false; if (!multiplier) this->multiplier = NEW WParsedInt(1); //TODO this is a copy/past of other code that's all around the place, everything should be in a dedicated parser class; @@ -1030,6 +1336,9 @@ public: } } + if(sabilities.find("battleready") != string::npos) + battleReady = true; + for (int j = 0; j < Constants::MTG_NB_COLORS; j++) { size_t found = sabilities.find(Constants::MTGColorStrings[j]); @@ -1060,13 +1369,18 @@ public: int resolve() { + if(!starfound.empty()) + { + multiplier = NEW WParsedInt(starfound, NULL, (MTGCardInstance *)source); + } for (int i = 0; i < multiplier->getValue(); ++i) { - MTGCardInstance * myToken; + //MTGCardInstance * myToken; if (tokenId) { MTGCard * card = GameApp::collection->getCardById(tokenId); myToken = NEW MTGCardInstance(card, source->controller()->game); + } else { @@ -1085,16 +1399,48 @@ public: myToken->basicAbilities[*it] = 1; } } - if (who == 0 || who != 1) + string tokenText = ""; + if(sabilities.find("token(") == string::npos) + { + tokenText = "("; + size_t endAbility = sabilities.find(")"); + string words = sabilities.substr(0,endAbility); + tokenText.append(words); + string sourcename = ((MTGCardInstance*)source)->name; + tokenText.append(") source: "); + tokenText.append( sourcename); + myToken->text = tokenText; + } + if (who == 0 && who != 1 && who != 2) { source->controller()->game->temp->addCard(myToken); Spell * spell = NEW Spell(myToken); spell->resolve(); spell->source->isToken = 1; spell->source->fresh = 1; + if(aLivingWeapon) + { + source->target = spell->source; + source->target->equipment += 1; + AbilityFactory af; + af.getAbilities(¤tAbilities, NULL, source); + for (size_t i = 0; i < currentAbilities.size(); ++i) + { + MTGAbility * a = currentAbilities[i]; + if (a->aType == MTGAbility::STANDARD_EQUIP) continue; + if (a->aType == MTGAbility::STANDARD_TEACH) continue; + a->addToGame(); + } + } + if(battleReady) + { + spell->source->summoningSickness = 0; + spell->source->tap(); + spell->source->setAttacker(1); + } delete spell; } - else if (who == 1) + else if (who == 1 && who != 0 && who != 2) { source->controller()->opponent()->game->temp->addCard(myToken); Spell * spell = NEW Spell(myToken); @@ -1102,6 +1448,57 @@ public: spell->source->owner = spell->source->controller(); spell->source->isToken = 1; spell->source->fresh = 1; + if(aLivingWeapon) + { + source->target = spell->source; + source->target->equipment += 1; + AbilityFactory af; + af.getAbilities(¤tAbilities, NULL, source); + for (size_t i = 0; i < currentAbilities.size(); ++i) + { + MTGAbility * a = currentAbilities[i]; + if (a->aType == MTGAbility::STANDARD_EQUIP) continue; + if (a->aType == MTGAbility::STANDARD_TEACH) continue; + a->addToGame(); + } + } + if(battleReady) + { + spell->source->summoningSickness = 0; + spell->source->tap(); + spell->source->setAttacker(1); + } + delete spell; + } + else + { + ((MTGCardInstance*)target)->controller()->game->temp->addCard(myToken); + Spell * spell = NEW Spell(myToken); + spell->resolve(); + spell->source->owner = ((MTGCardInstance*)target)->controller(); + spell->source->isToken = 1; + spell->source->fresh = 1; + myToken = spell->source; + if(aLivingWeapon) + { + source->target = spell->source; + source->target->equipment += 1; + AbilityFactory af; + af.getAbilities(¤tAbilities, NULL, source); + for (size_t i = 0; i < currentAbilities.size(); ++i) + { + MTGAbility * a = currentAbilities[i]; + if (a->aType == MTGAbility::STANDARD_EQUIP) continue; + if (a->aType == MTGAbility::STANDARD_TEACH) continue; + a->addToGame(); + } + } + if(battleReady) + { + spell->source->summoningSickness = 0; + spell->source->tap(); + spell->source->setAttacker(1); + } delete spell; } } @@ -1109,7 +1506,7 @@ public: } const char * getMenuText() - { + { sprintf(menuText, "Create %s", name.c_str()); return menuText; } @@ -1134,6 +1531,7 @@ public: { if (!isClone) { + if(multiplier != NULL) delete (multiplier); } } @@ -1199,20 +1597,32 @@ public: int addToGame() { value_before_modification = ((MTGCardInstance *) target)->basicAbilities[ability]; - ((MTGCardInstance *) target)->basicAbilities[ability] = modifier; + if(ability != Constants::ABSORB && ability != Constants::FLANKING) + { + ((MTGCardInstance *) target)->basicAbilities[ability] = modifier; + } + else + { + ((MTGCardInstance *) target)->basicAbilities[ability] += modifier; + } return MTGAbility::addToGame(); } int destroy() { - if (((MTGCardInstance *) target)->basicAbilities[ability] == modifier) + if (((MTGCardInstance *) target)->basicAbilities[ability] == modifier && (ability != Constants::ABSORB && ability != Constants::FLANKING)) { ((MTGCardInstance *) target)->basicAbilities[ability] = value_before_modification; return 1; } + else if (ability == Constants::ABSORB || ability == Constants::FLANKING) + { + ((MTGCardInstance *) target)->basicAbilities[ability] -= 1; + return 1; + } else { - //BUG !!! + //BUG !!! return 0; } } @@ -1324,23 +1734,30 @@ public: int value; AInstantBasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int value) : InstantAbility(_id, _source, _target), ability(_ability), value(value) - { - aType = MTGAbility::STANDARDABILITYGRANT; - abilitygranted = ability; - } + { + aType = MTGAbility::STANDARDABILITYGRANT; + abilitygranted = ability; + } - int addToGame() - { - MTGCardInstance * _target = (MTGCardInstance *) target; - stateBeforeActivation = _target->basicAbilities[ability]; - _target->basicAbilities[ability] = value; - return InstantAbility::addToGame(); - } + int addToGame() + { + MTGCardInstance * _target = (MTGCardInstance *) target; + stateBeforeActivation = _target->basicAbilities[ability]; + if(ability != Constants::ABSORB) + { + _target->basicAbilities[ability] = value; + } + else + { + _target->basicAbilities[ability] += value; + } + return InstantAbility::addToGame(); + } - const char * getMenuText() - { - return Constants::MTGBasicAbilities[ability]; - } + const char * getMenuText() + { + return Constants::MTGBasicAbilities[ability]; + } int destroy() { @@ -1629,6 +2046,10 @@ public: MTGCardInstance * _target = (MTGCardInstance *) target; _target->power += wppt->power.getValue(); _target->addToToughness(wppt->toughness.getValue()); + if(_target->has(Constants::INDESTRUCTIBLE) && wppt->toughness.getValue() < 0 && _target->toughness <= 0) + { + _target->controller()->game->putInGraveyard(_target); + } return MTGAbility::addToGame(); } @@ -1659,20 +2080,25 @@ class AInstantPowerToughnessModifierUntilEOT: public InstantAbility { public: WParsedPT * wppt; + string s; AInstantPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, WParsedPT * wppt) : InstantAbility(_id, _source, _target), wppt(wppt) { aType = MTGAbility::STANDARD_PUMP; - } + } - int resolve() - { - ((MTGCardInstance *) target)->power += wppt->power.getValue(); - ((MTGCardInstance *) target)->addToToughness(wppt->toughness.getValue()); - return 1; - } + int resolve() + { + ((MTGCardInstance *) target)->power += wppt->power.getValue(); + ((MTGCardInstance *) target)->addToToughness(wppt->toughness.getValue()); + if(((MTGCardInstance *) target)->has(Constants::INDESTRUCTIBLE) && wppt->toughness.getValue() < 0 && ((MTGCardInstance *) target)->toughness <= 0) + { + ((MTGCardInstance *) target)->controller()->game->putInGraveyard(((MTGCardInstance *) target)); + } + return 1; + } - int destroy() + int destroy() { ((MTGCardInstance *) target)->power -= wppt->power.getValue(); ((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue()); @@ -2082,19 +2508,23 @@ public: a = NULL; } - int canBeInList(MTGCardInstance * card) - { - int size = 0; - size = (int) cards.size(); - if (includeSelf && maxi && card == source && size > maxi) + int canBeInList(MTGCardInstance * card) { - removed(card); - } - if ((includeSelf || card != source) && tc->canTarget(card)) return 1; - return 0; - } + if(card->isPhased || source->isPhased) + return 0; + int size = 0; + size = (int) cards.size(); + if (includeSelf && maxi && card == source && size > maxi) + { + removed(card); + } + if ((includeSelf || card != source) && tc->canTarget(card)) + return 1; - int resolve() + return 0; + } + + int resolve() { //TODO check if ability is oneShot ? updateTargets(); @@ -2133,8 +2563,7 @@ public: int _added(Damageable * d) { int size = (int) cards.size(); - if (maxi && size < maxi) return 0; - if (maxi && size > maxi) return removeAbilityFromGame(); + if (maxi && size >= maxi) return removeAbilityFromGame(); if (maxi) return 0; if (size <= mini) return 0; return addAbilityToGame(); @@ -2153,7 +2582,7 @@ public: int removed(MTGCardInstance * card) { size_t size = cards.size(); - if (maxi && (int) size <= maxi) return addAbilityToGame(); + if (maxi && (int) size < maxi) return addAbilityToGame(); if (mini && (int) size > mini) return 0; if (mini && (int) size <= mini) return removeAbilityFromGame(); if (!mini && !maxi && size != 0) return 0; @@ -2168,7 +2597,14 @@ public: const char * getMenuText() { + if(ability) + { return ability->getMenuText(); + } + else + { + return "Ability"; + } } AAsLongAs * clone() const @@ -2204,6 +2640,8 @@ public: int canBeInList(MTGCardInstance * card) { + if(card->isPhased || source->isPhased) + return 0; if ((includeSelf || card != source) && tc->canTarget(card)) return 1; return 0; } @@ -2372,6 +2810,7 @@ public: tc = _tc; tc->targetter = NULL; includeSelf = NULL; + aType = MTGAbility::STANDARD_TEACH; } int canBeInList(MTGCardInstance * card) @@ -2563,11 +3002,13 @@ public: naType = ability->aType; } - int canBeInList(MTGCardInstance * card) - { - if ((includeSelf || card != source) && tc->canTarget(card)) return 1; - return 0; - } + int canBeInList(MTGCardInstance * card) + { + if(card->isPhased || source->isPhased) + return 0; + if ((includeSelf || card != source) && tc->canTarget(card)) return 1; + return 0; + } int added(MTGCardInstance * card) { @@ -2838,8 +3279,10 @@ class AADamager: public ActivatedAbilityTP { public: WParsedInt * damage; + WParsedInt * RefreshedDamage; + string d; - AADamager(int _id, MTGCardInstance * _source, Targetable * _target, WParsedInt * damage, ManaCost * _cost = NULL, + AADamager(int _id, MTGCardInstance * _source, Targetable * _target,WParsedInt * damage, string d, ManaCost * _cost = NULL, int doTap = 0, int who = TargetChooser::UNSET); int resolve(); const char * getMenuText(); @@ -2880,11 +3323,11 @@ class TADamager: public TargetAbility { public: - TADamager(int id, MTGCardInstance * card, ManaCost * _cost, WParsedInt * damage, TargetChooser * _tc = NULL, int _tap = 0) : + TADamager(int id, MTGCardInstance * card, ManaCost * _cost,WParsedInt *damage, string d, TargetChooser * _tc = NULL, int _tap = 0) : TargetAbility(id, card, _tc, _cost, 0, _tap) { if (!tc) tc = NEW DamageableTargetChooser(card); - ability = NEW AADamager(id, card, NULL, damage); + ability = NEW AADamager(id, card, NULL,damage, d); } TADamager * clone() const @@ -2935,6 +3378,62 @@ public: const char * getMenuText(); AAFrozen * clone() const; }; +/* ghetto new target*/ +class AANewTarget: public ActivatedAbility +{ +public: + AANewTarget(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost = NULL, int doTap = 0); + int resolve(); + const char * getMenuText(); + AANewTarget * clone() const; +}; +/* morph*/ +class AAMorph: public ActivatedAbility +{ +public: + vector currentAbilities; + AAMorph(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost = NULL, int doTap = 0); + int resolve(); + int testDestroy(); + const char * getMenuText(); + AAMorph * clone() const; +}; +/* dynamic ability build*/ +class AADYNAMIC: public ActivatedAbility +{ +public: +int type; +int effect; +int who; +int sourceamount; +int targetamount; +int amountsource; +bool eachother; +bool tosrc; +MTGCardInstance * OriginalSrc; +MTGCardInstance * storedTarget; +MTGAbility * storedAbility; +MTGAbility * clonedStored; +string menu; + + AADYNAMIC(int id, MTGCardInstance * card, Damageable * _target,int type = 0,int effect = 0,int who = 0,int amountsource = 1,MTGAbility * storedAbility = NULL, ManaCost * _cost = NULL, int doTap = 0); + int resolve(); + int activateStored(); + const char * getMenuText(); + AADYNAMIC * clone() const; + ~AADYNAMIC(); +}; + +/* removes a card and all with the same name as it from the game */ +class AAEradicate: public ActivatedAbility +{ +public: +int type; + AAEradicate(int id, MTGCardInstance * card, MTGCardInstance * _target,int type = 0, ManaCost * _cost = NULL, int doTap = 0); + int resolve(); + const char * getMenuText(); + AAEradicate * clone() const; +}; /* switch power and toughness of target */ class ASwapPT: public InstantAbility @@ -3296,8 +3795,15 @@ public: list oldtypes; bool remove; string menu; + int newpower; + bool newpowerfound; + int oldpower; + int newtoughness; + bool newtoughnessfound; + int oldtoughness; - ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities); + + ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound); int addToGame(); int destroy(); const char * getMenuText(); @@ -3313,8 +3819,15 @@ public: list types; list colors; string menu; + int newpower; + bool newpowerfound; + int oldpower; + int newtoughness; + bool newtoughnessfound; + int oldtoughness; + bool remove; - AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities); + AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound); int addToGame(); const char * getMenuText(); AForeverTransformer * clone() const; @@ -3326,8 +3839,12 @@ class ATransformerUEOT: public InstantAbility { public: ATransformer * ability; + int newpower; + bool newpowerfound; + int newtoughness; + bool newtoughnessfound; - ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities); + ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound); int resolve(); const char * getMenuText(); ATransformerUEOT * clone() const; @@ -3339,8 +3856,12 @@ class ATransformerFOREVER: public InstantAbility { public: AForeverTransformer * ability; - - ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities); + int newpower; + bool newpowerfound; + int newtoughness; + bool newtoughnessfound; + + ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,int newpower = 0,bool newpowerfound = false,int newtoughness = 0,bool newtoughnessfound = false); int resolve(); const char * getMenuText(); ATransformerFOREVER * clone() const; @@ -3427,9 +3948,11 @@ public: int paidThisTurn; int phase; int once; + bool Cumulative; + int currentage; AUpkeep(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, int restrictions = 0, int _phase = - Constants::MTG_PHASE_UPKEEP, int _once = 0); + Constants::MTG_PHASE_UPKEEP, int _once = 0,bool Cumulative = false); void Update(float dt); int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); int resolve(); @@ -3439,6 +3962,73 @@ public: ~AUpkeep(); }; +//phase based actions +class APhaseAction: public MTGAbility, public NestedAbility +{ +public: + int phase; + bool forcedestroy; + bool next; + Player * abilityOwner; + + APhaseAction(int _id, MTGCardInstance * card, MTGCardInstance * target, MTGAbility * a, int _tap = 0, int restrictions = 0, int _phase = + Constants::MTG_PHASE_UPKEEP,bool forcedestroy = false,bool next = true); + void Update(float dt); + int resolve(); + int removeAbility(); + const char * getMenuText(); + APhaseAction * clone() const; + ~APhaseAction(); +}; + +//Adds types/abilities/P/T to a card (until end of turn) +class APhaseActionGeneric: public InstantAbility +{ +public: + APhaseAction * ability; + APhaseActionGeneric(int _id, MTGCardInstance * card, MTGCardInstance * target, MTGAbility * a, int _tap = 0, int restrictions = 0, int _phase = + Constants::MTG_PHASE_UPKEEP,bool forcedestroy = false,bool next = true); + int resolve(); + const char * getMenuText(); + APhaseActionGeneric * clone() const; + ~APhaseActionGeneric(); + +}; + +//ABlink +class ABlink: public MTGAbility +{ +public: + bool blinkueot; + bool blinkForSource; + bool blinkhand; + MTGCardInstance * Blinked; + bool resolved; + ABlink(int _id, MTGCardInstance * card, MTGCardInstance * _target,bool blinkueot=false,bool blinkForSource = false,bool blinkhand = false); + void Update(float dt); + void resolveBlink(); + int resolve(); + const char * getMenuText(); + ABlink * clone() const; + ~ABlink(); +}; + +//blinkinstant +class ABlinkGeneric: public InstantAbility +{ +public: + bool blinkueot; + bool blinkForSource; + bool blinkhand; + ABlink * ability; + ABlinkGeneric(int _id, MTGCardInstance * card, MTGCardInstance * _target,bool blinkueot=false,bool blinkForSource = false,bool blinkhand = false); + int resolve(); + const char * getMenuText(); + ABlinkGeneric * clone() const; + ~ABlinkGeneric(); + +}; + /* Specific Classes */ @@ -3474,14 +4064,16 @@ public: game->currentlyActing()->getManaPool()->pay(cost); nbcards = 0; MTGGameZone * library = game->currentlyActing()->game->library; - while (nbcards < wished && nbcards < library->nb_cards) + while (nbcards < wished) { cd.AddCard(library->cards[library->nb_cards - 1 - nbcards]); nbcards++; } init = 1; + Render(dt); } cd.Update(dt); + // cd.CheckUserInput(dt); } } @@ -3498,9 +4090,10 @@ public: { source->tap(); MTGLibrary * library = game->currentlyActing()->game->library; + MTGHand * hand = game->currentlyActing()->game->hand; MTGCardInstance * card = library->removeCard(tc->getNextCardTarget()); - library->shuffleTopToBottom(nbcards - 1); - library->addCard(card); + //library->shuffleTopToBottom(nbcards - 1); + hand->addCard(card); init = 0; return 1; } @@ -4254,7 +4847,7 @@ public: void Update(float dt) { - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_EOT) + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_ENDOFTURN) { if (!game->players[0]->game->inPlay->hasType("creature") && !game->players[1]->game->inPlay->hasType("creature")) { @@ -4854,13 +5447,16 @@ public: class AADepleter: public ActivatedAbilityTP { public: - int nbcards; + WParsedInt * nbcards; + WParsedInt * RefreshedNbcards; + string nbcardsStr; - AADepleter(int _id, MTGCardInstance * card, Targetable * _target, int nbcards = 1, ManaCost * _cost = NULL, int _tap = 0, + AADepleter(int _id, MTGCardInstance * card, Targetable * _target, WParsedInt * nbcards,string nbcardsStr, ManaCost * _cost = NULL, int _tap = 0, int who = TargetChooser::UNSET); int resolve(); const char * getMenuText(); AADepleter * clone() const; + ~AADepleter(); }; //Shuffle @@ -4911,13 +5507,16 @@ public: class AARandomDiscarder: public ActivatedAbilityTP { public: - int nbcards; + WParsedInt * nbcards; + WParsedInt * RefreshedNbcards; + string nbcardsStr; - AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target, int nbcards = 1, ManaCost * _cost = NULL, + AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target, WParsedInt * nbcards,string nbcardsStr, ManaCost * _cost = NULL, int _tap = 0, int who = TargetChooser::UNSET); int resolve(); const char * getMenuText(); AARandomDiscarder * clone() const; + ~AARandomDiscarder(); }; //Minion of Leshrac @@ -5133,6 +5732,47 @@ public: return a; } }; + +//A Spirit Link Ability +class ASpiritLinkAbility: public MTGAbility +{ +public: + MTGCardInstance * source; + bool combatonly; + ASpiritLinkAbility(int _id, MTGCardInstance * _source,bool combatonly = false) : + MTGAbility(_id, _source),source(_source),combatonly(combatonly) + { + } + int receiveEvent(WEvent * event) + { + if (event->type == WEvent::DAMAGE) + { + WEventDamage * e = (WEventDamage *) event; + Damage * d = e->damage; + if (combatonly == true && e->damage->typeOfDamage != DAMAGE_COMBAT) + return 0; + MTGCardInstance * card = d->source; + if (d->damage > 0 && card && (card == source || card == source->target)) + { + source->owner->life += d->damage; + source->owner->thatmuch = d->damage; + WEvent * lifed = NULL; + lifed = NEW WEventLife(source->owner,d->damage); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); + return 1; + } + } + return 0; + } + ASpiritLinkAbility * clone() const + { + ASpiritLinkAbility * a = NEW ASpiritLinkAbility(*this); + a->isClone = 1; + return a; + } +}; + //Instant Steal control of a target class AInstantControlSteal: public InstantAbility { diff --git a/projects/mtg/include/CardDescriptor.h b/projects/mtg/include/CardDescriptor.h index d5416b920..42a7530c7 100644 --- a/projects/mtg/include/CardDescriptor.h +++ b/projects/mtg/include/CardDescriptor.h @@ -1,6 +1,6 @@ /* - A Filter/Mask system for Card Instances to find cards matching specific settings such as color, type, etc... - */ + A Filter/Mask system for Card Instances to find cards matching specific settings such as color, type, etc... +*/ #ifndef _CARDDESCRIPTOR_H_ #define _CARDDESCRIPTOR_H_ @@ -13,42 +13,48 @@ #define CD_AND 2 enum ENUM_COMPARISON_MODES -{ - COMPARISON_NONE = 0, // Needs to remain 0 for quick if(comparison_mode) checks + { + COMPARISON_NONE = 0, // Needs to remain 0 for quick if(comparison_mode) checks COMPARISON_AT_MOST, COMPARISON_AT_LEAST, COMPARISON_EQUAL, COMPARISON_GREATER, COMPARISON_LESS, COMPARISON_UNEQUAL -}; + }; -class CardDescriptor: public MTGCardInstance -{ -protected: - MTGCardInstance * match_or(MTGCardInstance * card); - MTGCardInstance * match_and(MTGCardInstance * card); - bool valueInRange(int comparisonMode, int value, int criterion); -public: - int mode; - int powerComparisonMode; - int toughnessComparisonMode; - int manacostComparisonMode; - int counterComparisonMode; - int convertedManacost; // might fit better into MTGCardInstance? - int anyCounter; - int init(); - CardDescriptor(); - void unsecureSetTapped(int i); - void unsecuresetfresh(int k); - void setNegativeSubtype(string value); - int counterPower; - int counterToughness; - int counterNB; - string counterName; - MTGCardInstance * match(MTGCardInstance * card); - MTGCardInstance * match(MTGGameZone * zone); - MTGCardInstance * nextmatch(MTGGameZone * zone, MTGCardInstance * previous); +class CardDescriptor: public MTGCardInstance{ + protected: + MTGCardInstance * match_or(MTGCardInstance * card); + MTGCardInstance * match_and(MTGCardInstance * card); + bool valueInRange(int comparisonMode, int value, int criterion); + public: + int mode; + int powerComparisonMode; + int toughnessComparisonMode; + int manacostComparisonMode; + int counterComparisonMode; + int convertedManacost; // might fit better into MTGCardInstance? + int anyCounter; + int init(); + CardDescriptor(); + void unsecureSetTapped(int i); + void unsecuresetfresh(int k); + 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); + int counterPower; + int counterToughness; + int counterNB; + string counterName; + MTGCardInstance * match(MTGCardInstance * card); + MTGCardInstance * match(MTGGameZone * zone); + MTGCardInstance * nextmatch(MTGGameZone * zone, MTGCardInstance * previous); }; #endif diff --git a/projects/mtg/include/CardPrimitive.h b/projects/mtg/include/CardPrimitive.h index d99a0a5df..ecd6f1643 100644 --- a/projects/mtg/include/CardPrimitive.h +++ b/projects/mtg/include/CardPrimitive.h @@ -1,6 +1,7 @@ #ifndef _CARDPRIMITIVE_H_ #define _CARDPRIMITIVE_H_ + #include #include #include @@ -9,72 +10,144 @@ using namespace std; -class CardPrimitive -{ -protected: - vector ftdText; - string lcname; - ManaCost manaCost; +class CardPrimitive { + protected: + vector ftdText; + string lcname; + ManaCost manaCost; -public: - string text; - string name; - int init(); + public: + enum { + NO_RESTRICTION = 0, + PLAYER_TURN_ONLY = 1, + AS_SORCERY = 2, + MY_BEFORE_BEGIN = 3, + MY_UNTAP = 4, + MY_UPKEEP = 5, + MY_DRAW = 6, + MY_FIRSTMAIN = 7, + MY_COMBATBEGIN = 8, + MY_COMBATATTACKERS = 9, + MY_COMBATBLOCKERS = 10, + MY_COMBATDAMAGE = 11, + MY_COMBATEND = 12, + MY_SECONDMAIN = 13, + MY_ENDOFTURN = 14, + MY_EOT = 15, + MY_CLEANUP = 16, + MY_AFTER_EOT = 17, - int colors[Constants::MTG_NB_COLORS]; - map basicAbilities; - map magicTexts; - string magicText; - int alias; - string spellTargetType; - int power; - int toughness; - vector types; - CardPrimitive(); - CardPrimitive(CardPrimitive * source); + OPPONENT_BEFORE_BEGIN = 23, + OPPONENT_UNTAP = 24, + OPPONENT_UPKEEP = 25, + OPPONENT_DRAW = 26, + OPPONENT_FIRSTMAIN = 27, + OPPONENT_COMBATBEGIN = 28, + OPPONENT_COMBATATTACKERS = 29, + OPPONENT_COMBATBLOCKERS = 30, + OPPONENT_COMBATDAMAGE = 31, + OPPONENT_COMBATEND = 32, + OPPONENT_SECONDMAIN = 33, + OPPONENT_ENDOFTURN = 34, + OPPONENT_EOT = 35, + OPPONENT_CLEANUP = 36, + OPPONENT_AFTER_EOT = 37, - void setColor(int _color, int removeAllOthers = 0); - void setColor(string _color, int removeAllOthers = 0); - void removeColor(int color); - int getColor(); - int hasColor(int _color); - int countColors(); + BEFORE_BEGIN = 43, + UNTAP = 44, + UPKEEP = 45, + DRAW = 46, + FIRSTMAIN = 47, + COMBATBEGIN = 48, + COMBATATTACKERS = 49, + COMBATBLOCKERS = 50, + COMBATDAMAGE = 51, + COMBATEND = 52, + SECONDMAIN = 53, + ENDOFTURN = 54, + EOT = 55, + CLEANUP = 56, + AFTER_EOT = 57, + + VAMPIRES = 60, + LESS_CREATURES = 61, + SNOW_LAND_INPLAY =62, + CASTED_A_SPELL = 63, + ONE_OF_AKIND = 64, + FOURTHTURN = 65, + BEFORECOMBATDAMAGE = 66, + AFTERCOMBAT = 67, + DURINGCOMBAT = 68, + OPPONENT_TURN_ONLY = 69, + + }; + string text; + string name; + int init(); - int has(int ability); + int colors[Constants::MTG_NB_COLORS]; + map basicAbilities; + map magicTexts; + string magicText; + int alias; + string spellTargetType; + int power; + int toughness; + bool hasRestriction; + int restriction; + string otherrestriction; - void setText(const string& value); - const char * getText(); + vectortypes; + CardPrimitive(); + CardPrimitive(CardPrimitive * source); - void addMagicText(string value); - void addMagicText(string value, string zone); + void setColor(int _color, int removeAllOthers = 0); + void setColor(string _color, int removeAllOthers = 0); + void removeColor(int color); + int getColor(); + int hasColor(int _color); + int countColors(); - void setName(const string& value); - const string& getName() const; - const string& getLCName() const; + int has(int ability); - void addType(char * type_text); - void addType(int id); - void setType(const string& type_text); - void setSubtype(const string& value); - int removeType(string value, int removeAll = 0); - int removeType(int value, int removeAll = 0); - bool hasSubtype(int _subtype); - bool hasSubtype(const char * _subtype); - bool hasSubtype(string _subtype); - bool hasType(int _type); - bool hasType(const char * type); + void setText(const string& value); + const char * getText(); - void setManaCost(string value); - ManaCost * getManaCost(); - bool isCreature(); - bool isLand(); - bool isSpell(); + void addMagicText(string value); + void addMagicText(string value, string zone); - void setPower(int _power); - int getPower(); - void setToughness(int _toughness); - int getToughness(); - const vector& formattedText(); + void setName(const string& value); + const string& getName() const; + const string& getLCName() const; + + void addType(char * type_text); + void addType(int id); + void setType(const string& type_text); + void setSubtype(const string& value); + int removeType(string value, int removeAll = 0); + int removeType(int value, int removeAll = 0); + bool hasSubtype(int _subtype); + bool hasSubtype(const char * _subtype); + bool hasSubtype(string _subtype); + bool hasType(int _type); + bool hasType(const char * type); + + void setManaCost(string value); + ManaCost * getManaCost(); + bool isCreature(); + bool isLand(); + bool isSpell(); + + void setPower(int _power); + int getPower(); + void setToughness(int _toughness); + int getToughness(); + void setRestrictions(int _restriction); + int getRestrictions(); + void setOtherRestrictions(string _restriction); + void getOtherRestrictions(); + const vector& formattedText(); }; + #endif diff --git a/projects/mtg/include/Damage.h b/projects/mtg/include/Damage.h index 7eff18312..9cf3b506f 100644 --- a/projects/mtg/include/Damage.h +++ b/projects/mtg/include/Damage.h @@ -17,77 +17,51 @@ class GameObserver; #define DAMAGE_COMBAT 1 #define DAMAGE_OTHER 2 -class Damageable: public Targetable -{ +class Damageable:public Targetable { protected: public: int life; int poisonCount; int damageCount; int preventable; + int thatmuch; + int lifeLostThisTurn; int type_as_damageable; - Damageable(int _life) - { - life = _life; - } - ; - int getLife() - { - return life; - } - ; - virtual int dealDamage(int damage) - { - life -= damage; - return life; - } - ; - virtual int afterDamage() - { - return 0; - } - virtual int poisoned() - { - return 0; - } - virtual int prevented() - { - return 0; - } - virtual JQuad * getIcon() - { - return NULL; - } - ; + Damageable(int _life){life=_life;lifeLostThisTurn = 0;}; + int getLife(){return life;}; + virtual int dealDamage(int damage){life-=damage;return life;}; + virtual int afterDamage(){return 0;} + virtual int poisoned(){return 0;} + virtual int prevented(){return 0;} + virtual JQuad * getIcon(){return NULL;}; }; -class Damage: public Interruptible -{ -protected: - void init(MTGCardInstance * source, Damageable * target, int damage, int typeOfDamage); -public: - Damageable * target; - int typeOfDamage; - int damage; - void Render(); - Damage(MTGCardInstance* source, Damageable * target); - Damage(MTGCardInstance* source, Damageable * target, int damage, int typeOfDamage = DAMAGE_OTHER); - int resolve(); - virtual ostream& toString(ostream& out) const; +class Damage: public Interruptible { + protected: + void init(MTGCardInstance * source, Damageable * target, int damage, int typeOfDamage); + public: + Damageable * target; + int typeOfDamage; + int damage; + void Render(); + Damage(MTGCardInstance* source, Damageable * target); + Damage(MTGCardInstance* source, Damageable * target, int damage, int typeOfDamage = DAMAGE_OTHER); + int resolve(); + virtual ostream& toString(ostream& out) const; }; -class DamageStack: public GuiLayer, public Interruptible -{ -protected: - int currentState; - GameObserver* game; -public: - int receiveEvent(WEvent * event); - int resolve(); - void Render(); - virtual ostream& toString(ostream& out) const; - DamageStack(); +class DamageStack : public GuiLayer, public Interruptible{ + protected: + int currentState; + GameObserver* game; + + public: + int receiveEvent(WEvent * event); + int resolve(); + void Render(); + virtual ostream& toString(ostream& out) const; + DamageStack(); }; #endif diff --git a/projects/mtg/include/ExtraCost.h b/projects/mtg/include/ExtraCost.h index 1d8299fa9..94419350f 100644 --- a/projects/mtg/include/ExtraCost.h +++ b/projects/mtg/include/ExtraCost.h @@ -9,163 +9,145 @@ class TargetChooser; class MTGCardInstance; class MTGAbility; -class ExtraCost -{ +class ExtraCost{ public: - TargetChooser * tc; - MTGCardInstance * source; - MTGCardInstance * target; - std::string mCostRenderString; + TargetChooser * tc; + MTGCardInstance * source; + MTGCardInstance * target; + MTGCardInstance * targets[20]; + std::string mCostRenderString; - ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL); - virtual ~ExtraCost(); - virtual int setPayment(MTGCardInstance * card); - virtual int isPaymentSet() - { - return (target != NULL); - } - virtual int canPay() - { - return 1; - } - virtual int doPay() = 0; - virtual void Render(); - virtual int setSource(MTGCardInstance * _source); - virtual ExtraCost* clone() const = 0; + ExtraCost(const std::string& inCostRenderString, TargetChooser *_tc = NULL); + virtual ~ExtraCost(); + virtual int setPayment(MTGCardInstance * card); + virtual int isPaymentSet() { return (target != NULL && targets != NULL); } + virtual int canPay() { return 1; } + virtual int doPay() = 0; + virtual void Render(); + virtual int setSource(MTGCardInstance * _source); + virtual ExtraCost* clone() const = 0; }; -class ExtraCosts -{ +class ExtraCosts{ public: - vector costs; - MTGCardInstance * source; - MTGAbility * action; - ExtraCosts(); - ~ExtraCosts(); - void Render(); - int tryToSetPayment(MTGCardInstance * card); - int isPaymentSet(); - int canPay(); - int doPay(); - int reset(); - int setAction(MTGAbility * _action, MTGCardInstance * _source); - void Dump(); - ExtraCosts * clone() const; + vectorcosts; + MTGCardInstance * source; + MTGAbility * action; + ExtraCosts(); + ~ExtraCosts(); + void Render(); + int tryToSetPayment(MTGCardInstance * card); + int isPaymentSet(); + int canPay(); + int doPay(); + int reset(); + int setAction(MTGAbility * _action, MTGCardInstance * _source); + void Dump(); + ExtraCosts * clone() const; }; -class SacrificeCost: public ExtraCost -{ +class SacrificeCost: public ExtraCost{ public: - SacrificeCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual SacrificeCost * clone() const; + SacrificeCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual SacrificeCost * clone() const; }; //life cost -class LifeCost: public ExtraCost -{ +class LifeCost: public ExtraCost{ public: - LifeCost(TargetChooser *_tc = NULL); + LifeCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual LifeCost * clone() const; + virtual int doPay(); + virtual LifeCost * clone() const; }; //Discard a random card cost -class DiscardRandomCost: public ExtraCost -{ +class DiscardRandomCost: public ExtraCost{ public: - DiscardRandomCost(TargetChooser *_tc = NULL); - virtual int canPay(); - virtual int doPay(); - virtual DiscardRandomCost * clone() const; + DiscardRandomCost(TargetChooser *_tc = NULL); + virtual int canPay(); + virtual int doPay(); + virtual DiscardRandomCost * clone() const; }; //a choosen discard -class DiscardCost: public ExtraCost -{ +class DiscardCost: public ExtraCost{ public: - DiscardCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual DiscardCost * clone() const; + DiscardCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual DiscardCost * clone() const; }; //tolibrary cost -class ToLibraryCost: public ExtraCost -{ +class ToLibraryCost: public ExtraCost{ public: - ToLibraryCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual ToLibraryCost * clone() const; + ToLibraryCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual ToLibraryCost * clone() const; }; //Millyourself cost -class MillCost: public ExtraCost -{ +class MillCost: public ExtraCost{ public: - MillCost(TargetChooser *_tc = NULL); - virtual int canPay(); - virtual int doPay(); - virtual MillCost * clone() const; + MillCost(TargetChooser *_tc = NULL); + virtual int canPay(); + virtual int doPay(); + virtual MillCost * clone() const; }; //Mill to exile yourself cost -class MillExileCost: public MillCost -{ +class MillExileCost: public MillCost{ public: - MillExileCost(TargetChooser *_tc = NULL); - virtual int doPay(); + MillExileCost(TargetChooser *_tc = NULL); + virtual int doPay(); }; //tap other cost -class TapTargetCost: public ExtraCost -{ +class TapTargetCost: public ExtraCost{ public: TapTargetCost(TargetChooser *_tc = NULL); + virtual int isPaymentSet(); virtual int doPay(); virtual TapTargetCost * clone() const; }; //exile as cost -class ExileTargetCost: public ExtraCost -{ +class ExileTargetCost: public ExtraCost{ public: - ExileTargetCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual ExileTargetCost * clone() const; + ExileTargetCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual ExileTargetCost * clone() const; }; //bounce cost -class BounceTargetCost: public ExtraCost -{ +class BounceTargetCost: public ExtraCost{ public: - BounceTargetCost(TargetChooser *_tc = NULL); - virtual int doPay(); - virtual BounceTargetCost * clone() const; + BounceTargetCost(TargetChooser *_tc = NULL); + virtual int doPay(); + virtual BounceTargetCost * clone() const; }; //bounce cost -class Ninja: public ExtraCost -{ +class Ninja: public ExtraCost{ public: - Ninja(TargetChooser *_tc = NULL); - virtual int isPaymentSet(); - virtual int doPay(); - virtual Ninja * clone() const; + Ninja(TargetChooser *_tc = NULL); + virtual int isPaymentSet(); + virtual int doPay(); + virtual Ninja * clone() const; }; -class CounterCost: public ExtraCost -{ +class CounterCost: public ExtraCost{ public: - Counter * counter; - int hasCounters; - CounterCost(Counter * _counter, TargetChooser *_tc = NULL); - ~CounterCost(); - virtual int setPayment(MTGCardInstance * card); - virtual int isPaymentSet(); - virtual int canPay(); - virtual int doPay(); - virtual CounterCost * clone() const; + Counter * counter; + int hasCounters; + CounterCost(Counter * _counter,TargetChooser *_tc = NULL); + ~CounterCost(); + virtual int setPayment(MTGCardInstance * card); + virtual int isPaymentSet(); + virtual int canPay(); + virtual int doPay(); + virtual CounterCost * clone() const; }; #endif diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index b0a37ac4d..111d0a6cc 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -22,70 +22,71 @@ class TargetChooser; class Rules; using namespace std; -class GameObserver -{ -protected: - static GameObserver * mInstance; - MTGCardInstance * cardWaitingForTargets; - queue eventsQueue; +class GameObserver{ + protected: + static GameObserver * mInstance; + MTGCardInstance * cardWaitingForTargets; + queue eventsQueue; - int nbPlayers; - int untap(MTGCardInstance * card); - bool WaitForExtraPayment(MTGCardInstance* card); + int nbPlayers; + int untap(MTGCardInstance * card); + bool WaitForExtraPayment(MTGCardInstance* card); -public: - int currentPlayerId; - CombatStep combatStep; - int turn; - int forceShuffleLibraries(); - int targetListIsSet(MTGCardInstance * card); - PhaseRing * phaseRing; - int cancelCurrentAction(); - int currentGamePhase; - ExtraCosts * mExtraPayment; - int oldGamePhase; - TargetChooser * targetChooser; - DuelLayers * mLayers; - ReplacementEffects *replacementEffects; - Player * gameOver; - Player * players[2]; //created outside - time_t startedAt; - Rules * mRules; + public: + int currentPlayerId; + CombatStep combatStep; + int turn; + int forceShuffleLibraries(); + int targetListIsSet(MTGCardInstance * card); + PhaseRing * phaseRing; + int cancelCurrentAction(); + int currentGamePhase; + ExtraCosts * mExtraPayment; + int oldGamePhase; + TargetChooser * targetChooser; + DuelLayers * mLayers; + ReplacementEffects *replacementEffects; + Player * gameOver; + Player * players[2]; //created outside + time_t startedAt; + Rules * mRules; - TargetChooser * getCurrentTargetChooser(); - void stackObjectClicked(Interruptible * action); + TargetChooser * getCurrentTargetChooser(); + void stackObjectClicked(Interruptible * action); - int cardClick(MTGCardInstance * card, Targetable * _object = NULL); - int getCurrentGamePhase(); - void nextCombatStep(); - void userRequestNextGamePhase(); - void nextGamePhase(); - void cleanupPhase(); - void nextPlayer(); - static void Init(Player * _players[], int _nbplayers); - static GameObserver * GetInstance(); - static void EndInstance(); - Player * currentPlayer; - Player * currentActionPlayer; - Player * isInterrupting; - Player * opponent(); - Player * currentlyActing(); - GameObserver(Player * _players[], int _nbplayers); - ~GameObserver(); - void gameStateBasedEffects(); - void eventOccured(); - void addObserver(MTGAbility * observer); - void removeObserver(ActionElement * observer); - void startGame(Rules * rules); - void untapPhase(); - void draw(); - int isInPlay(MTGCardInstance * card); + int cardClick(MTGCardInstance * card,Targetable * _object = NULL ); + int getCurrentGamePhase(); + void nextCombatStep(); + void userRequestNextGamePhase(); + void nextGamePhase(); + void cleanupPhase(); + void nextPlayer(); + static void Init(Player * _players[], int _nbplayers); + static GameObserver * GetInstance(); + static void EndInstance(); + Player * currentPlayer; + Player * currentActionPlayer; + Player * isInterrupting; + Player * opponent(); + Player * currentlyActing(); + GameObserver(Player * _players[], int _nbplayers); + ~GameObserver(); + void gameStateBasedEffects(); + void enchantmentStatus(); + void eventOccured(); + void addObserver(MTGAbility * observer); + void removeObserver(ActionElement * observer); + void startGame(Rules * rules); + void untapPhase(); + void draw(); + int isInPlay(MTGCardInstance * card); + int isInGrave(MTGCardInstance * card); + int isInExile(MTGCardInstance * card); + void Update(float dt); + void Render(); + void ButtonPressed(PlayGuiObject*); - void Update(float dt); - void Render(); - void ButtonPressed(PlayGuiObject*); - - int receiveEvent(WEvent * event); + int receiveEvent(WEvent * event); }; #endif diff --git a/projects/mtg/include/GameOptions.h b/projects/mtg/include/GameOptions.h index 922a88b72..781185d4b 100644 --- a/projects/mtg/include/GameOptions.h +++ b/projects/mtg/include/GameOptions.h @@ -23,339 +23,260 @@ class WStyle; class StyleManager; class Player; -class Options -{ +class Options { public: - friend class GameSettings; - enum - { - //Global settings - ACTIVE_PROFILE, - LANG, - LAST_GLOBAL = LANG, //This must be the value above, to keep ordering. - //Values /must/ match ordering in optionNames, or everything loads wrong. - //Profile settings - ACTIVE_THEME, - ACTIVE_MODE, - MUSICVOLUME, - SFXVOLUME, - DIFFICULTY, - CHEATMODE, - OPTIMIZE_HAND, - CHEATMODEAIDECK, - OSD, - CLOSEDHAND, - HANDDIRECTION, - MANADISPLAY, - REVERSETRIGGERS, - DISABLECARDS, - MAX_GRADE, - ASPHASES, - ECON_DIFFICULTY, - TRANSITIONS, - GUI_STYLE, - INTERRUPT_SECONDS, - KEY_BINDINGS, - AIDECKS_UNLOCKED, - //My interrupts - INTERRUPTMYSPELLS, - INTERRUPTMYABILITIES, - //Other interrupts - INTERRUPT_BEFOREBEGIN, - INTERRUPT_UNTAP, - INTERRUPT_UPKEEP, - INTERRUPT_DRAW, - INTERRUPT_FIRSTMAIN, - INTERRUPT_BEGINCOMBAT, - INTERRUPT_ATTACKERS, - INTERRUPT_BLOCKERS, - INTERRUPT_DAMAGE, - INTERRUPT_ENDCOMBAT, - INTERRUPT_SECONDMAIN, - INTERRUPT_ENDTURN, - INTERRUPT_CLEANUP, - INTERRUPT_AFTEREND, - BEGIN_AWARDS, //Options after this use the GameOptionAward struct, which includes a timestamp. - DIFFICULTY_MODE_UNLOCKED = BEGIN_AWARDS, - MOMIR_MODE_UNLOCKED, - EVILTWIN_MODE_UNLOCKED, - RANDOMDECK_MODE_UNLOCKED, - AWARD_COLLECTOR, - LAST_NAMED, //Any option after this does not look up in optionNames. - SET_UNLOCKS = LAST_NAMED + 1, - //For sets. + friend class GameSettings; + enum { + //Global settings + ACTIVE_PROFILE, + LANG, + LAST_GLOBAL = LANG, //This must be the value above, to keep ordering. + //Values /must/ match ordering in optionNames, or everything loads wrong. + //Profile settings + ACTIVE_THEME, + ACTIVE_MODE, + MUSICVOLUME, + SFXVOLUME, + DIFFICULTY, + CHEATMODE, + OPTIMIZE_HAND, + CHEATMODEAIDECK, + OSD, + CLOSEDHAND, + HANDDIRECTION, + MANADISPLAY, + REVERSETRIGGERS, + DISABLECARDS, + MAX_GRADE, + ASPHASES, + FIRSTPLAYER, + ECON_DIFFICULTY, + TRANSITIONS, + GUI_STYLE, + INTERRUPT_SECONDS, + KEY_BINDINGS, + AIDECKS_UNLOCKED, + //My interrupts + INTERRUPTMYSPELLS, + INTERRUPTMYABILITIES, + //Other interrupts + INTERRUPT_BEFOREBEGIN, + INTERRUPT_UNTAP, + INTERRUPT_UPKEEP, + INTERRUPT_DRAW, + INTERRUPT_FIRSTMAIN, + INTERRUPT_BEGINCOMBAT, + INTERRUPT_ATTACKERS, + INTERRUPT_BLOCKERS, + INTERRUPT_DAMAGE, + INTERRUPT_ENDCOMBAT, + INTERRUPT_SECONDMAIN, + INTERRUPT_ENDTURN, + INTERRUPT_CLEANUP, + INTERRUPT_AFTEREND, + BEGIN_AWARDS, //Options after this use the GameOptionAward struct, which includes a timestamp. + DIFFICULTY_MODE_UNLOCKED = BEGIN_AWARDS, + MOMIR_MODE_UNLOCKED, + EVILTWIN_MODE_UNLOCKED, + RANDOMDECK_MODE_UNLOCKED, + AWARD_COLLECTOR, + LAST_NAMED, //Any option after this does not look up in optionNames. + SET_UNLOCKS = LAST_NAMED + 1, //For sets. - }; + }; + + static int optionSet(int setID); + static int optionInterrupt(int gamePhase); - static int optionSet(int setID); - static int optionInterrupt(int gamePhase); - - static int getID(string name); - static string getName(int option); + static int getID(string name); + static string getName(int option); private: - static const string optionNames[]; + static const string optionNames[]; }; -class GameOption -{ +class GameOption { public: - virtual ~GameOption() - { - } - ; - int number; - string str; - //All calls to asColor should include a fallback color for people without a theme. - PIXEL_TYPE asColor(PIXEL_TYPE fallback = ARGB(255,255,255,255)); + virtual ~GameOption() {}; + int number; + string str; + //All calls to asColor should include a fallback color for people without a theme. + PIXEL_TYPE asColor(PIXEL_TYPE fallback = ARGB(255,255,255,255)); - virtual bool isDefault(); //Returns true when number is 0 and string is "" or "Default" - virtual string menuStr(); //The string we'll use for GameStateOptions. - virtual bool write(std::ofstream * file, string name); - virtual bool read(string input); + virtual bool isDefault(); //Returns true when number is 0 and string is "" or "Default" + virtual string menuStr(); //The string we'll use for GameStateOptions. + virtual bool write(std::ofstream * file, string name); + virtual bool read(string input); - GameOption(int value = 0); - GameOption(string); - GameOption(int, string); + GameOption(int value = 0); + GameOption(string); + GameOption(int, string); }; -struct EnumDefinition -{ - int findIndex(int value); +struct EnumDefinition { + int findIndex(int value); - typedef pair assoc; - vector values; + typedef pair assoc; + vector values; }; -class GameOptionEnum: public GameOption -{ +class GameOptionEnum: public GameOption { public: - virtual string menuStr(); - virtual bool write(std::ofstream * file, string name); - virtual bool read(string input); - EnumDefinition * def; + virtual string menuStr(); + virtual bool write(std::ofstream * file, string name); + virtual bool read(string input); + EnumDefinition * def; }; -class GameOptionAward: public GameOption -{ +class GameOptionAward: public GameOption { public: - GameOptionAward(); - virtual string menuStr(); - virtual bool write(std::ofstream * file, string name); - virtual bool read(string input); - virtual bool giveAward(); //Returns false if already awarded - virtual bool isViewed(); - virtual void setViewed(bool v = true) - { - viewed = v; - } - ; + GameOptionAward(); + virtual string menuStr(); + virtual bool write(std::ofstream * file, string name); + virtual bool read(string input); + virtual bool giveAward(); //Returns false if already awarded + virtual bool isViewed(); + virtual void setViewed(bool v = true) {viewed = v;}; private: - time_t achieved; //When was it awarded? - bool viewed; //Flag it as "New!" or not. + time_t achieved; //When was it awarded? + bool viewed; //Flag it as "New!" or not. }; -class GameOptionKeyBindings: public GameOption -{ - virtual bool read(string input); - virtual bool write(std::ofstream*, string); +class GameOptionKeyBindings : public GameOption { + virtual bool read(string input); + virtual bool write(std::ofstream*, string); }; -class OptionVolume: public EnumDefinition -{ +class OptionVolume: public EnumDefinition{ public: - enum - { - MUTE = 0, MAX = 100 - }; - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + enum { MUTE = 0, MAX = 100 }; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionVolume(); - static OptionVolume mDef; + OptionVolume(); + static OptionVolume mDef; }; -class OptionClosedHand: public EnumDefinition -{ + +class OptionClosedHand: public EnumDefinition { public: - enum - { - INVISIBLE = 0, VISIBLE = 1 - }; - static EnumDefinition * getInstance() - { - return &mDef; - } - ; -private: - OptionClosedHand(); - static OptionClosedHand mDef; + enum { INVISIBLE = 0, VISIBLE = 1 }; + static EnumDefinition * getInstance() {return &mDef;}; +private: + OptionClosedHand(); + static OptionClosedHand mDef; }; -class OptionHandDirection: public EnumDefinition -{ +class OptionHandDirection: public EnumDefinition { public: - enum - { - VERTICAL = 0, HORIZONTAL = 1 - }; - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + enum { VERTICAL = 0, HORIZONTAL = 1}; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionHandDirection(); - static OptionHandDirection mDef; + OptionHandDirection(); + static OptionHandDirection mDef; }; -class OptionManaDisplay: public EnumDefinition -{ +class OptionManaDisplay: public EnumDefinition { public: - enum - { - DYNAMIC = 0, STATIC = 1, NOSTARSDYNAMIC = 2, BOTH = 3 - }; - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + enum { DYNAMIC = 0, STATIC = 1, NOSTARSDYNAMIC = 2, BOTH = 3}; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionManaDisplay(); - static OptionManaDisplay mDef; + OptionManaDisplay(); + static OptionManaDisplay mDef; }; -class OptionMaxGrade: public EnumDefinition -{ +class OptionMaxGrade: public EnumDefinition { public: - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionMaxGrade(); - static OptionMaxGrade mDef; + OptionMaxGrade(); + static OptionMaxGrade mDef; }; -class OptionASkipPhase: public EnumDefinition -{ +class OptionASkipPhase: public EnumDefinition { public: - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionASkipPhase(); - static OptionASkipPhase mDef; + OptionASkipPhase(); + static OptionASkipPhase mDef; }; -class OptionEconDifficulty: public EnumDefinition -{ +class OptionWhosFirst: public EnumDefinition { public: - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + enum { WHO_P = 0, WHO_O = 1, WHO_R = 2}; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionEconDifficulty(); - static OptionEconDifficulty mDef; + OptionWhosFirst(); + static OptionWhosFirst mDef; }; -class OptionDifficulty: public EnumDefinition -{ +class OptionEconDifficulty: public EnumDefinition { public: - enum - { - NORMAL = 0, HARD = 1, HARDER = 2, EVIL = 3 - }; - static EnumDefinition * getInstance() - { - return &mDef; - } - ; + static EnumDefinition * getInstance() {return &mDef;}; private: - OptionDifficulty(); - static OptionDifficulty mDef; + OptionEconDifficulty(); + static OptionEconDifficulty mDef; +}; +class OptionDifficulty: public EnumDefinition { +public: + enum { NORMAL = 0, HARD = 1, HARDER = 2, EVIL = 3}; + static EnumDefinition * getInstance() {return &mDef;}; +private: + OptionDifficulty(); + static OptionDifficulty mDef; }; -class GameOptions -{ -public: - string mFilename; - int save(); - int load(); +class GameOptions { + public: + string mFilename; + int save(); + int load(); - GameOption * get(int); - GameOption& operator[](int); - GameOptions(string filename); - ~GameOptions(); + GameOption * get(int); + GameOption& operator[](int); + GameOptions(string filename); + ~GameOptions(); + + private: + vector values; + vector unknown; +}; + +class GameSettings{ +public: + friend class GameApp; + GameSettings(); + ~GameSettings(); + int save(); + + SimplePad * keypadStart(string input, string * _dest = NULL, bool _cancel=true, bool _numpad=false, int _x = SCREEN_WIDTH/2, int _y = SCREEN_HEIGHT/2); + string keypadFinish(); + void keypadShutdown(); + void keypadTitle(string set); + bool keypadActive() {if(keypad) return keypad->isActive(); return false;}; + void keypadUpdate(float dt) {if(keypad) keypad->Update(dt);}; + void keypadRender() {if(keypad) keypad->Render();}; + + bool newAward(); + + //These return a filepath accurate to the current mode/profile/theme, and can + //optionally fallback to a file within a certain directory. + //The sanity=false option returns the adjusted path even if the file doesn't exist. + string profileFile(string filename="", string fallback="", bool sanity=false,bool relative=false); + + void reloadProfile(); //Reloads profile using current options[ACTIVE_PROFILE] + void checkProfile(); //Confirms that a profile is loaded and contains a collection. + void createUsersFirstDeck(int setId); + + GameOption * get(int); + GameOption& operator[](int); + + GameOptions* profileOptions; + GameOptions* globalOptions; + + static GameOption invalid_option; + + WStyle * getStyle(); + StyleManager * getStyleMan(); + void automaticStyle(Player * p1, Player * p2); private: - vector values; - vector unknown; -}; - -class GameSettings -{ -public: - friend class GameApp; - GameSettings(); - ~GameSettings(); - int save(); - - SimplePad * keypadStart(string input, string * _dest = NULL, bool _cancel = true, bool _numpad = false, int _x = SCREEN_WIDTH - / 2, int _y = SCREEN_HEIGHT / 2); - string keypadFinish(); - void keypadShutdown(); - void keypadTitle(string set); - bool keypadActive() - { - if (keypad) - return keypad->isActive(); - return false; - } - ; - void keypadUpdate(float dt) - { - if (keypad) - keypad->Update(dt); - } - ; - void keypadRender() - { - if (keypad) - keypad->Render(); - } - ; - - bool newAward(); - - //These return a filepath accurate to the current mode/profile/theme, and can - //optionally fallback to a file within a certain directory. - //The sanity=false option returns the adjusted path even if the file doesn't exist. - string profileFile(string filename = "", string fallback = "", bool sanity = false, bool relative = false); - - void reloadProfile(); //Reloads profile using current options[ACTIVE_PROFILE] - void checkProfile(); //Confirms that a profile is loaded and contains a collection. - void createUsersFirstDeck(int setId); - - GameOption * get(int); - GameOption& operator[](int); - - GameOptions* profileOptions; - GameOptions* globalOptions; - - static GameOption invalid_option; - - WStyle * getStyle(); - StyleManager * getStyleMan(); - void automaticStyle(Player * p1, Player * p2); - -private: - GameApp * theGame; - SimplePad * keypad; - StyleManager * styleMan; + GameApp * theGame; + SimplePad * keypad; + StyleManager * styleMan; }; extern GameSettings options; diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 5bf518430..85813fd59 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -1,6 +1,8 @@ #ifndef _MTGABILITY_H_ #define _MTGABILITY_H_ + + class MTGCardInstance; class Spell; class Damageable; @@ -22,6 +24,7 @@ class Counter; using std::string; using std::map; + //stupid variables used to give a hint to the AI: // Should I cast a spell on an enemy or friendly unit ? #define BAKA_EFFECT_GOOD 1 @@ -37,374 +40,386 @@ using std::map; #define PARSER_FOREACH 2 #define PARSER_ASLONGAS 3 -class MTGAbility: public ActionElement -{ -protected: - char menuText[50]; +class MTGAbility: public ActionElement{ + protected: + char menuText[50]; + + GameObserver * game; + public: + enum { + NO_RESTRICTION = 0, + PLAYER_TURN_ONLY = 1, + AS_SORCERY = 2, + MY_BEFORE_BEGIN = 3, + MY_UNTAP = 4, + MY_UPKEEP = 5, + MY_DRAW = 6, + MY_FIRSTMAIN = 7, + MY_COMBATBEGIN = 8, + MY_COMBATATTACKERS = 9, + MY_COMBATBLOCKERS = 10, + MY_COMBATDAMAGE = 11, + MY_COMBATEND = 12, + MY_SECONDMAIN = 13, + MY_ENDOFTURN = 14, + MY_EOT = 15, + MY_CLEANUP = 16, + MY_AFTER_EOT = 17, - GameObserver* game; -public: - int oneShot; - int forceDestroy; - ManaCost* cost; - ManaCost* alternative; - ManaCost* BuyBack; - ManaCost* FlashBack; - ManaCost* Retrace; + OPPONENT_BEFORE_BEGIN = 23, + OPPONENT_UNTAP = 24, + OPPONENT_UPKEEP = 25, + OPPONENT_DRAW = 26, + OPPONENT_FIRSTMAIN = 27, + OPPONENT_COMBATBEGIN = 28, + OPPONENT_COMBATATTACKERS = 29, + OPPONENT_COMBATBLOCKERS = 30, + OPPONENT_COMBATDAMAGE = 31, + OPPONENT_COMBATEND = 32, + OPPONENT_SECONDMAIN = 33, + OPPONENT_ENDOFTURN = 34, + OPPONENT_EOT = 35, + OPPONENT_CLEANUP = 36, + OPPONENT_AFTER_EOT = 37, - Targetable* target; - int aType; - int naType; - int abilitygranted; - int nbcardAmount; - MTGCardInstance* source; - MTGAbility(int id, MTGCardInstance* card); - MTGAbility(int id, MTGCardInstance* _source, Targetable* _target); - virtual int testDestroy(); - virtual ~MTGAbility(); - virtual void Render() {} - virtual int isReactingToClick(MTGCardInstance* card, ManaCost* mana = NULL) - { - return 0; - } - ; - virtual int reactToClick(MTGCardInstance* card) - { - return 0; - } - ; - virtual int receiveEvent(WEvent* event) - { - return 0; - } - ; - virtual void Update(float dt) {}; - virtual int fireAbility(); - virtual int stillInUse(MTGCardInstance* card); - virtual int resolve() - { - return 0; - } - ; - virtual MTGAbility* clone() const = 0; - virtual ostream& toString(ostream& out) const; - virtual int addToGame(); - virtual int removeFromGame(); + BEFORE_BEGIN = 43, + UNTAP = 44, + UPKEEP = 45, + DRAW = 46, + FIRSTMAIN = 47, + COMBATBEGIN = 48, + COMBATATTACKERS = 49, + COMBATBLOCKERS = 50, + COMBATDAMAGE = 51, + COMBATEND = 52, + SECONDMAIN = 53, + ENDOFTURN = 54, + EOT = 55, + CLEANUP = 56, + AFTER_EOT = 57, + + VAMPIRES = 60, + LESS_CREATURES = 61, + SNOW_LAND_INPLAY =62, + CASTED_A_SPELL = 63, + ONE_OF_AKIND = 64, + FOURTHTURN = 65, + BEFORECOMBATDAMAGE = 66, + AFTERCOMBAT = 67, + DURINGCOMBAT = 68, + OPPONENT_TURN_ONLY = 69, + }; + int allowedToCast(MTGCardInstance * card,Player * player); + int allowedToAltCast(MTGCardInstance * card,Player * player); + int oneShot; + int forceDestroy; + ManaCost * cost; + ManaCost * alternative; + ManaCost * BuyBack; + ManaCost * FlashBack; + ManaCost * Retrace; + ManaCost * morph; - /*Poor man's casting */ - /* Todo replace that crap with dynamic casting */ - enum - { - UNKNOWN = 0, - MANA_PRODUCER = 1, - MTG_ATTACK_RULE = 2, - DAMAGER = 3, - STANDARD_REGENERATE = 4, - PUT_INTO_PLAY = 5, - MOMIR = 6, - MTG_BLOCK_RULE = 7, - ALTERNATIVE_COST = 8, - BUYBACK_COST = 9, - FLASHBACK_COST = 10, - RETRACE_COST = 11, - MTG_COMBATTRIGGERS_RULE = 12, - STANDARD_PREVENT = 13, - STANDARD_EQUIP = 14, - STANDARD_LEVELUP = 15, - FOREACH = 16, - STANDARD_DRAW = 17, - STANDARD_PUMP = 18, - STANDARD_BECOMES = 19, - UPCOST = 20, - STANDARDABILITYGRANT = 21, - UNTAPPER = 22, - TAPPER = 23, - LIFER = 24, - CLONING = 25, - }; + Targetable * target; + int aType; + int naType; + int abilitygranted; + int nbcardAmount; + MTGCardInstance * source; + MTGAbility(int id, MTGCardInstance * card); + MTGAbility(int id, MTGCardInstance * _source, Targetable * _target); + virtual int testDestroy(); + virtual ~MTGAbility(); + virtual void Render(){}; + virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){return 0;}; + virtual int reactToClick(MTGCardInstance * card){return 0;}; + virtual int receiveEvent(WEvent * event){return 0;}; + virtual void Update(float dt){}; + virtual int fireAbility(); + virtual int stillInUse(MTGCardInstance * card); + virtual int resolve(){return 0;}; + virtual MTGAbility* clone() const = 0; + virtual ostream& toString(ostream& out) const; + virtual int addToGame(); + virtual int removeFromGame(); + + /*Poor man's casting */ + /* Todo replace that crap with dynamic casting */ + enum { + UNKNOWN = 0, + MANA_PRODUCER = 1, + MTG_ATTACK_RULE = 2, + DAMAGER = 3, + STANDARD_REGENERATE = 4, + PUT_INTO_PLAY = 5, + MOMIR = 6, + MTG_BLOCK_RULE = 7, + ALTERNATIVE_COST = 8, + BUYBACK_COST = 9, + FLASHBACK_COST = 10, + RETRACE_COST = 11, + MTG_COMBATTRIGGERS_RULE = 12, + STANDARD_PREVENT = 13, + STANDARD_EQUIP = 14, + STANDARD_LEVELUP = 15, + FOREACH = 16, + STANDARD_DRAW = 17, + STANDARD_PUMP = 18, + STANDARD_BECOMES = 19, + UPCOST = 20, + STANDARDABILITYGRANT = 21, + UNTAPPER = 22, + TAPPER = 23, + LIFER = 24, + CLONING = 25, + STANDARD_TEACH = 26, + STANDARD_TOKENCREATOR = 27, + MORPH_COST = 28, + + + }; }; -class NestedAbility -{ -public: - MTGAbility* ability; - NestedAbility(MTGAbility* _ability); +class NestedAbility{ + public: + MTGAbility * ability; + NestedAbility(MTGAbility * _ability); }; -class TriggeredAbility: public MTGAbility -{ -public: - TriggeredAbility(int id, MTGCardInstance* card); - TriggeredAbility(int id, MTGCardInstance* _source, Targetable* _target); - virtual void Update(float dt); - virtual void Render() {} - ; - virtual int trigger() - { - return 0; - } - ; - virtual int triggerOnEvent(WEvent* e) - { - return 0; - } - ; - int receiveEvent(WEvent* e); - virtual int resolve() = 0; - virtual TriggeredAbility* clone() const = 0; - virtual ostream& toString(ostream& out) const; +class TriggeredAbility:public MTGAbility{ + public: + TriggeredAbility(int id, MTGCardInstance * card); + TriggeredAbility(int id, MTGCardInstance * _source, Targetable * _target); + virtual void Update(float dt); + virtual void Render(){}; + virtual int trigger(){return 0;}; + virtual int triggerOnEvent(WEvent * e){return 0;}; + int receiveEvent(WEvent * e); + virtual int resolve() = 0; + virtual TriggeredAbility* clone() const = 0; + virtual ostream& toString(ostream& out) const; }; -class ActivatedAbility: public MTGAbility -{ -public: - enum - { - NO_RESTRICTION = 0, - PLAYER_TURN_ONLY = 1, - AS_SORCERY = 2, - MY_BEFORE_BEGIN = 3, - MY_UNTAP = 4, - MY_UPKEEP = 5, - MY_DRAW = 6, - MY_FIRSTMAIN = 7, - MY_COMBATBEGIN = 8, - MY_COMBATATTACKERS = 9, - MY_COMBATBLOCKERS = 10, - MY_COMBATDAMAGE = 11, - MY_COMBATEND = 12, - MY_SECONDMAIN = 13, - MY_ENDOFTURN = 14, - MY_EOT = 15, - MY_CLEANUP = 16, - MY_AFTER_EOT = 17, - OPPONENT_BEFORE_BEGIN = 23, - OPPONENT_UNTAP = 24, - OPPONENT_UPKEEP = 25, - OPPONENT_DRAW = 26, - OPPONENT_FIRSTMAIN = 27, - OPPONENT_COMBATBEGIN = 28, - OPPONENT_COMBATATTACKERS = 29, - OPPONENT_COMBATBLOCKERS = 30, - OPPONENT_COMBATDAMAGE = 31, - OPPONENT_COMBATEND = 32, - OPPONENT_SECONDMAIN = 33, - OPPONENT_ENDOFTURN = 34, - OPPONENT_EOT = 35, - OPPONENT_CLEANUP = 36, - OPPONENT_AFTER_EOT = 37, +class ActivatedAbility:public MTGAbility{ + public: + enum { + NO_RESTRICTION = 0, + PLAYER_TURN_ONLY = 1, + AS_SORCERY = 2, + MY_BEFORE_BEGIN = 3, + MY_UNTAP = 4, + MY_UPKEEP = 5, + MY_DRAW = 6, + MY_FIRSTMAIN = 7, + MY_COMBATBEGIN = 8, + MY_COMBATATTACKERS = 9, + MY_COMBATBLOCKERS = 10, + MY_COMBATDAMAGE = 11, + MY_COMBATEND = 12, + MY_SECONDMAIN = 13, + MY_ENDOFTURN = 14, + MY_EOT = 15, + MY_CLEANUP = 16, + MY_AFTER_EOT = 17, - BEFORE_BEGIN = 43, - UNTAP = 44, - UPKEEP = 45, - DRAW = 46, - FIRSTMAIN = 47, - COMBATBEGIN = 48, - COMBATATTACKERS = 49, - COMBATBLOCKERS = 50, - COMBATDAMAGE = 51, - COMBATEND = 52, - SECONDMAIN = 53, - ENDOFTURN = 54, - EOT = 55, - CLEANUP = 56, - AFTER_EOT = 57, - }; - ManaCost* abilityCost; - int restrictions; - int needsTapping; - ActivatedAbility(int id, MTGCardInstance* card, ManaCost* _cost = NULL, int _restrictions = NO_RESTRICTION, int tap = 1); - virtual ~ActivatedAbility(); - virtual int reactToClick(MTGCardInstance* card); - virtual int isReactingToClick(MTGCardInstance* card, ManaCost* mana = NULL); - virtual int reactToTargetClick(Targetable* object); - virtual int resolve() = 0; - virtual ActivatedAbility* clone() const = 0; - virtual ostream& toString(ostream& out) const; + OPPONENT_BEFORE_BEGIN = 23, + OPPONENT_UNTAP = 24, + OPPONENT_UPKEEP = 25, + OPPONENT_DRAW = 26, + OPPONENT_FIRSTMAIN = 27, + OPPONENT_COMBATBEGIN = 28, + OPPONENT_COMBATATTACKERS = 29, + OPPONENT_COMBATBLOCKERS = 30, + OPPONENT_COMBATDAMAGE = 31, + OPPONENT_COMBATEND = 32, + OPPONENT_SECONDMAIN = 33, + OPPONENT_ENDOFTURN = 34, + OPPONENT_EOT = 35, + OPPONENT_CLEANUP = 36, + OPPONENT_AFTER_EOT = 37, + + BEFORE_BEGIN = 43, + UNTAP = 44, + UPKEEP = 45, + DRAW = 46, + FIRSTMAIN = 47, + COMBATBEGIN = 48, + COMBATATTACKERS = 49, + COMBATBLOCKERS = 50, + COMBATDAMAGE = 51, + COMBATEND = 52, + SECONDMAIN = 53, + ENDOFTURN = 54, + EOT = 55, + CLEANUP = 56, + AFTER_EOT = 57, + + OPPONENT_TURN_ONLY = 69, + }; + ManaCost * abilityCost; + int restrictions; + int needsTapping; + ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1); + virtual ~ActivatedAbility(); + virtual int reactToClick(MTGCardInstance * card); + virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + virtual int reactToTargetClick(Targetable * object); + virtual int resolve() = 0; + virtual ActivatedAbility* clone() const = 0; + virtual ostream& toString(ostream& out) const; }; -class TargetAbility: public ActivatedAbility, public NestedAbility -{ -public: - TargetAbility(int id, MTGCardInstance* card, TargetChooser* _tc, ManaCost* _cost = NULL, int _playerturnonly = 0, int tap = 1); - TargetAbility(int id, MTGCardInstance* card, ManaCost* _cost = NULL, int _playerturnonly = 0, int tap = 1); - virtual int reactToClick(MTGCardInstance* card); - virtual int reactToTargetClick(Targetable* object); - virtual TargetAbility* clone() const = 0; - virtual void Render(); - virtual int resolve(); - virtual const char* getMenuText(); - virtual ostream& toString(ostream& out) const; - ~TargetAbility(); +class TargetAbility:public ActivatedAbility, public NestedAbility{ + public: + TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + virtual int reactToClick(MTGCardInstance * card); + virtual int reactToTargetClick(Targetable * object); + virtual TargetAbility* clone() const = 0; + virtual void Render(); + virtual int resolve(); + virtual const char * getMenuText(); + virtual ostream& toString(ostream& out) const; + ~TargetAbility(); }; -class InstantAbility: public MTGAbility -{ -public: - int init; - virtual void Update(float dt); - virtual int testDestroy(); - InstantAbility(int _id, MTGCardInstance* source); - InstantAbility(int _id, MTGCardInstance* source, Damageable* _target); - virtual int resolve() - { - return 0; - } - ; - virtual InstantAbility* clone() const = 0; - virtual ostream& toString(ostream& out) const; +class InstantAbility:public MTGAbility{ + public: + int init; + virtual void Update(float dt); + virtual int testDestroy(); + InstantAbility(int _id, MTGCardInstance * source); + InstantAbility(int _id, MTGCardInstance * source,Damageable * _target); + virtual int resolve(){return 0;}; + virtual InstantAbility* clone() const = 0; + virtual ostream& toString(ostream& out) const; }; /* State based effects. This class works ONLY for InPlay and needs to be extended for other areas of the game !!! */ -class ListMaintainerAbility: public MTGAbility -{ -public: - map cards; - map players; - ListMaintainerAbility(int _id) : MTGAbility(_id, NULL) - { - } - ; - ListMaintainerAbility(int _id, MTGCardInstance *_source) : MTGAbility(_id, _source) - { - } - ; - ListMaintainerAbility(int _id, MTGCardInstance *_source, Damageable* _target) : MTGAbility(_id, _source, _target) - { - } - ; - virtual void Update(float dt); - void updateTargets(); - virtual bool canTarget(MTGGameZone* zone); - virtual int canBeInList(MTGCardInstance* card) = 0; - virtual int added(MTGCardInstance* card) = 0; - virtual int removed(MTGCardInstance* card) = 0; - virtual int canBeInList(Player* p) - { - return 0; - } - ; - virtual int added(Player* p) - { - return 0; - } - ; - virtual int removed(Player* p) - { - return 0; - } - ; - virtual int destroy(); - virtual ListMaintainerAbility* clone() const = 0; - virtual ostream& toString(ostream& out) const; +class ListMaintainerAbility:public MTGAbility{ + public: + map cards; + map players; + ListMaintainerAbility(int _id):MTGAbility(_id,NULL){}; + ListMaintainerAbility(int _id, MTGCardInstance *_source):MTGAbility(_id, _source){}; + ListMaintainerAbility(int _id, MTGCardInstance *_source,Damageable * _target):MTGAbility(_id, _source, _target){}; + virtual void Update(float dt); + void updateTargets(); + virtual bool canTarget(MTGGameZone * zone); + virtual int canBeInList(MTGCardInstance * card) = 0; + virtual int added(MTGCardInstance * card) = 0; + virtual int removed(MTGCardInstance * card) = 0; + virtual int canBeInList(Player * p){return 0;}; + virtual int added(Player * p){return 0;}; + virtual int removed(Player * p){return 0;}; + virtual int destroy(); + virtual ListMaintainerAbility* clone() const = 0; + virtual ostream& toString(ostream& out) const; }; -class TriggerAtPhase: public TriggeredAbility -{ -public: - int phaseId; - int who; - TriggerAtPhase(int id, MTGCardInstance* source, Targetable* target, int _phaseId, int who = 0); - virtual int trigger(); - int resolve() - { - return 0; - } - ; - virtual TriggerAtPhase* clone() const; +class TriggerAtPhase:public TriggeredAbility{ + public: + int phaseId; + int who; + bool sourceUntapped; + bool sourceTap; + bool lifelost; + int lifeamount; + TriggerAtPhase(int id, MTGCardInstance * source, Targetable * target,int _phaseId, int who = 0,bool sourceUntapped = false,bool sourceTap = false,bool lifelost = false, int lifeamount = 0); + virtual int trigger(); + int resolve(){return 0;}; + virtual TriggerAtPhase* clone() const; }; -class TriggerNextPhase: public TriggerAtPhase -{ -public: - int destroyActivated; - TriggerNextPhase(int id, MTGCardInstance* source, Targetable* target, int _phaseId, int who = 0); - virtual TriggerNextPhase* clone() const; - virtual int testDestroy(); +class TriggerNextPhase:public TriggerAtPhase{ + public: + int destroyActivated; + bool sourceUntapped; + bool sourceTap; + TriggerNextPhase(int id, MTGCardInstance * source, Targetable * target,int _phaseId, int who = 0,bool sourceUntapped = false,bool sourceTap = false); + virtual TriggerNextPhase* clone() const; + virtual int testDestroy(); }; -class GenericTriggeredAbility: public TriggeredAbility, public NestedAbility -{ -public: - TriggeredAbility* t; - queue targets; - MTGAbility* destroyCondition; - GenericTriggeredAbility(int id, MTGCardInstance* _source, TriggeredAbility* _t, MTGAbility* a, MTGAbility* dc = NULL, - Targetable* _target = NULL); - virtual int trigger(); - virtual int triggerOnEvent(WEvent* e); - virtual int resolve(); - virtual int testDestroy(); - Targetable* getTriggerTarget(WEvent* e, MTGAbility* a); - void setTriggerTargets(Targetable* ta, MTGAbility* a); +class GenericTriggeredAbility:public TriggeredAbility, public NestedAbility{ + public: + TriggeredAbility * t; + queue targets; + MTGAbility * destroyCondition; + GenericTriggeredAbility(int id, MTGCardInstance * _source, TriggeredAbility * _t, MTGAbility * a,MTGAbility * dc = NULL, Targetable * _target = NULL); + virtual int trigger(); + virtual int triggerOnEvent(WEvent * e); + virtual int resolve(); + virtual int testDestroy(); - void Update(float dt); - virtual GenericTriggeredAbility* clone() const; - const char* getMenuText(); - ~GenericTriggeredAbility(); + Targetable * getTriggerTarget(WEvent * e, MTGAbility * a); + void setTriggerTargets(Targetable * ta, MTGAbility * a); + + void Update(float dt); + virtual GenericTriggeredAbility* clone() const; + const char * getMenuText(); + ~GenericTriggeredAbility(); }; /* Ability Factory */ -class AbilityFactory -{ -private: - int countCards(TargetChooser* tc, Player* player = NULL, int option = 0); - TriggeredAbility* parseTrigger(string s, string magicText, int id, Spell* spell, MTGCardInstance *card, Targetable* target); - int parseRestriction(string s); - MTGAbility* getAlternateCost(string s, int id, Spell *spell, MTGCardInstance *card); - MTGAbility* getManaReduxAbility(string s, int id, Spell *spell, MTGCardInstance *card, MTGCardInstance *target); - +class AbilityFactory{ + private: + int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); + TriggeredAbility * parseTrigger(string s, string magicText, int id, Spell * spell, MTGCardInstance *card, Targetable * target); + int parseRestriction(string s); + MTGAbility * getAlternateCost( string s, int id, Spell *spell, MTGCardInstance *card ); + MTGAbility * getManaReduxAbility(string s, int id, Spell *spell, MTGCardInstance *card, MTGCardInstance *target); + public: - Counter* parseCounter(string s, MTGCardInstance* target, Spell* spell = NULL); - int parsePowerToughness(string s, int* power, int* toughness); - int getAbilities(vector* v, Spell* spell, MTGCardInstance* card = NULL, int id = 0, MTGGameZone* dest = NULL); - MTGAbility* parseMagicLine(string s, int id, Spell* spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0, - int oneShot = 0, int forceForever = 0, MTGGameZone* dest = NULL); + Counter * parseCounter(string s, MTGCardInstance * target, Spell * spell = NULL); + int parsePowerToughness(string s, int *power, int *toughness); + int getAbilities(vector * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL); + MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0,int oneShot = 0,int forceForever = 0, MTGGameZone * dest = NULL); - int abilityEfficiency(MTGAbility* a, Player* p, int mode = MODE_ABILITY, TargetChooser* tc = 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 computeXX(Spell* spell, MTGCardInstance* card); - static MTGAbility* getCoreAbility(MTGAbility* a); - int destroyAllInPlay(TargetChooser* tc, int bury = 0); - int moveAll(TargetChooser* tc, string destinationZone); - int damageAll(TargetChooser* tc, int damage); - int TapAll(TargetChooser* tc); - int UntapAll(TargetChooser* tc); - void addAbilities(int _id, Spell* spell); + int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY, TargetChooser * tc = 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 computeXX(Spell * spell, MTGCardInstance * card); + static MTGAbility * getCoreAbility(MTGAbility * a); + int destroyAllInPlay(TargetChooser * tc, int bury = 0); + int moveAll(TargetChooser * tc, string destinationZone); + int damageAll(TargetChooser * tc, int damage); + int TapAll(TargetChooser * tc); + int UntapAll(TargetChooser * tc); + void addAbilities(int _id, Spell * spell); }; -class ActivatedAbilityTP: public ActivatedAbility -{ + +class ActivatedAbilityTP:public ActivatedAbility{ public: - int who; - ActivatedAbilityTP(int id, MTGCardInstance* card, Targetable* _target = NULL, ManaCost* cost = NULL, int doTap = 0, int who = - TargetChooser::UNSET); - Targetable* getTarget(); + int who; + ActivatedAbilityTP(int id, MTGCardInstance * card, Targetable * _target = NULL, ManaCost * cost=NULL, int doTap = 0, int who = TargetChooser::UNSET); + Targetable * getTarget(); }; -class AManaProducer: public ActivatedAbilityTP -{ -protected: +class AManaProducer: public ActivatedAbilityTP{ + protected: - string menutext; - Player* controller; + + string menutext; + Player * controller; -public: - ManaCost* output; - int tap; - AManaProducer(int id, MTGCardInstance* card, Targetable* t, ManaCost* _output, ManaCost* _cost = NULL, int doTap = 1, int who = TargetChooser::UNSET); - int isReactingToClick(MTGCardInstance* _card, ManaCost* mana = NULL); - int resolve(); - int reactToClick(MTGCardInstance* _card); - const char* getMenuText(); - ~AManaProducer(); - virtual AManaProducer* clone() const; + public: + ManaCost * output; + int tap; + AManaProducer(int id, MTGCardInstance * card, Targetable * t, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 1, int who = TargetChooser::UNSET ); + int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL); + int resolve(); + int reactToClick(MTGCardInstance * _card); + const char * getMenuText(); + ~AManaProducer(); + virtual AManaProducer * clone() const; }; +#include "MTGCardInstance.h" + #endif diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index bc4e4a2c0..e3d72f2a7 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -10,6 +10,7 @@ #include "Damage.h" #include "Targetable.h" + class MTGCardInstance; class MTGPlayerCards; class MTGAbility; @@ -23,150 +24,172 @@ struct Pos; #include using namespace std; -class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable -{ -protected: - int untapping; - int nb_damages; - string sample; - int tapped; - - int lifeOrig; - MTGPlayerCards * belongs_to; - MTGCardInstance * getNextPartner(); - void initMTGCI(); +class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable { + protected: + int untapping; + int nb_damages; + string sample; + int tapped; + int lifeOrig; + MTGPlayerCards * belongs_to; + MTGCardInstance * getNextPartner(); + void initMTGCI(); + int addBlocker(MTGCardInstance * c); + int removeBlocker(MTGCardInstance * c); + int init(); + public: + int setAttacker(int value); int setDefenser(MTGCardInstance * c); - int addBlocker(MTGCardInstance * c); - int removeBlocker(MTGCardInstance * c); - int init(); -public: - int setAttacker(int value); - MTGGameZone * currentZone; - Pos* view; - int X; - int XX; - int alternateCostPaid[ManaCost::MANA_PAID_WITH_RETRACE + 1]; - int paymenttype; - int frozen; - int sunburst; - int equipment; - int reduxamount; - int flanked; - int regenerateTokens; - int isToken; - int stillInUse(); - int didattacked; - int didblocked; - int notblocked; - int fresh; - int MaxLevelUp; - Player * lastController; - MTGGameZone * getCurrentZone(); - MTGGameZone * previousZone; - MTGCardInstance * previous; - MTGCardInstance * next; - int doDamageTest; - int summoningSickness; - // The recommended method to test for summoning Sickness ! - int hasSummoningSickness(); - MTGCardInstance * changeController(Player * newcontroller); - Player * owner; - Counters * counters; - int typeAsTarget() - { - return TARGET_CARD; - } - const string getDisplayName() const; - MTGCardInstance * target; + MTGGameZone * currentZone; + Pos* view; + int X; + int XX; + int alternateCostPaid[ManaCost::MANA_PAID_WITH_RETRACE + 1]; + int paymenttype; + int frozen; + int sunburst; + int equipment; + int auras; + int reduxamount; + int flanked; + int regenerateTokens; + int isToken; + int origpower; + int origtoughness; + int isMultiColored; + int isBlackAndWhite; + int isRedAndBlue; + int isBlackAndGreen; + int isBlueAndGreen; + int isRedAndWhite; + int isLeveler; + bool enchanted; + int CDenchanted; + bool blinked; + bool isExtraCostTarget; + bool morphed; + bool turningOver; + bool isMorphed; + bool isPhased; + bool isTempPhased; + int phasedTurn; + bool graveEffects; + bool exileEffects; + + int stillInUse(); + int didattacked; + int didblocked; + int notblocked; + int fresh; + int MaxLevelUp; + Player * lastController; + MTGGameZone * getCurrentZone(); + MTGGameZone * previousZone; + MTGCardInstance * previous; + MTGCardInstance * next; + int doDamageTest; + int summoningSickness; + // The recommended method to test for summoning Sickness ! + int hasSummoningSickness(); + MTGCardInstance * changeController(Player * newcontroller); + Player * owner; + Counters * counters; + int typeAsTarget(){return TARGET_CARD;} + const string getDisplayName() const; + MTGCardInstance * target; + MTGCardInstance * imprint; - //types - void addType(char * type_text); - virtual void addType(int id); - void setType(const char * type_text); - void setSubtype(string value); - int removeType(string value, int removeAll = 0); - int removeType(int value, int removeAll = 0); - //dangerranking is a hint to Ai which creatures are the ones it should be targetting for effects. - int DangerRanking(); - //Combat - bool blocked; //Blocked this turn or not? - MTGCardInstance * defenser; - list blockers; - int attacker; - int toggleDefenser(MTGCardInstance * opponent); - int raiseBlockerRankOrder(MTGCardInstance * blocker); + //types + void addType(char * type_text); + virtual void addType(int id); + void setType(const char * type_text); + void setSubtype( string value); + int removeType(string value, int removeAll = 0); + int removeType(int value, int removeAll = 0); - //Returns rank of the card in blockers if it is a blocker of this (starting at 1), 0 otherwise - int getDefenserRank(MTGCardInstance * blocker); - int toggleAttacker(); - MTGCardInstance * banding; // If belongs to a band when attacking - int canBlock(); - int canBlock(MTGCardInstance * opponent); - int canAttack(); - int isAttacker(); - MTGCardInstance * isDefenser(); - int initAttackersDefensers(); - MTGCardInstance * getNextOpponent(MTGCardInstance * previous = NULL); - int nbOpponents(); - int stepPower(CombatStep step); - int afterDamage(); - int has(int ability); - int cleanup(); + //dangerranking is a hint to Ai which creatures are the ones it should be targetting for effects. + int DangerRanking(); + //Combat + bool blocked; //Blocked this turn or not? + MTGCardInstance * defenser; + listblockers; + int attacker; + int toggleDefenser(MTGCardInstance * opponent); + int raiseBlockerRankOrder(MTGCardInstance * blocker); - MTGCard * model; - MTGCardInstance(); - MTGCardInstance(MTGCard * card, MTGPlayerCards * _belongs_to); - int regenerate(); - int triggerRegenerate(); - Player * controller(); + //Returns rank of the card in blockers if it is a blocker of this (starting at 1), 0 otherwise + int getDefenserRank(MTGCardInstance * blocker); + int toggleAttacker(); + MTGCardInstance * banding; // If belongs to a band when attacking + int canBlock(); + int canBlock(MTGCardInstance * opponent); + int canAttack(); + int isAttacker(); + MTGCardInstance * isDefenser(); + int initAttackersDefensers(); + MTGCardInstance * getNextOpponent(MTGCardInstance * previous=NULL); + int nbOpponents(); + int stepPower(CombatStep step); + int afterDamage(); + int has(int ability); + int cleanup(); - virtual ~MTGCardInstance(); - int bury(); - int destroy(); + MTGCard * model; + MTGCardInstance(); + MTGCardInstance(MTGCard * card, MTGPlayerCards * _belongs_to); + int regenerate(); + int triggerRegenerate(); + Player * controller(); - int addToToughness(int value); - int setToughness(int value); + virtual ~MTGCardInstance(); + int bury(); + int destroy(); - vector protections; - int addProtection(TargetChooser * tc); - int removeProtection(TargetChooser *tc, int erase = 0); - int protectedAgainst(MTGCardInstance * card); - vector cantBeBlockedBys; - int addCantBeBlockedBy(TargetChooser * tc); - int removeCantBeBlockedBy(TargetChooser *tc, int erase = 0); - int cantBeBlockedBy(MTGCardInstance * card); + int addToToughness(int value); + int setToughness(int value); - void copy(MTGCardInstance * card); + vectorprotections; + int addProtection(TargetChooser * tc); + int removeProtection(TargetChooser *tc, int erase = 0); + int protectedAgainst(MTGCardInstance * card); - void setUntapping(); - int isUntapping(); - int isTapped(); - void untap(); - void tap(); - void attemptUntap(); + vectorcantBeBlockedBys; + int addCantBeBlockedBy(TargetChooser * tc); + int removeCantBeBlockedBy(TargetChooser *tc, int erase = 0); + int cantBeBlockedBy(MTGCardInstance * card); - void eventattacked(); - void eventattackedAlone(); - void eventattackednotblocked(); - void eventattackedblocked(); - void eventblocked(); + void copy(MTGCardInstance * card); - int isInPlay(); - JSample * getSample(); + void setUntapping(); + int isUntapping(); + int isTapped(); + void untap(); + void tap(); + void attemptUntap(); - JQuad * getIcon(); + void eventattacked(); + void eventattackedAlone(); + void eventattackednotblocked(); + void eventattackedblocked(); + void eventblocked(); - ostream& toString(ostream&) const; + int isInPlay(); + JSample * getSample(); - static MTGCardInstance AnyCard; - static MTGCardInstance NoCard; + JQuad * getIcon(); - static MTGCardInstance ExtraRules[2]; + ostream& toString(ostream&) const; + + static MTGCardInstance AnyCard; + static MTGCardInstance NoCard; + + static MTGCardInstance ExtraRules[2]; }; ostream& operator<<(ostream&, const MTGCardInstance&); + #endif diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index cec978f13..81bd2a1c4 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -9,217 +9,239 @@ const float DEFAULT_TEXT_FONT_SCALE = 1.0f; using std::string; class Constants { -public: - // Exception Codes + public: + // Exception Codes - /* Exception codes */ - const static int PARSER_FAILED_INSTANTIATION = 1000; - const static int PARSER_KEYWORD_NOT_MATCHED = 2000; - const static int PARSER_INVALID_KEYWORD = 3000; +/* Exception codes */ + const static int PARSER_FAILED_INSTANTIATION = 1000; + const static int PARSER_KEYWORD_NOT_MATCHED = 2000; + const static int PARSER_INVALID_KEYWORD = 3000; - // color constants - static const string kManaColorless; - static const string kManaGreen; - static const string kManaBlue; - static const string kManaRed; - static const string kManaBlack; - static const string kManaWhite; - // alternative costs constants + // color constants + static const string kManaColorless; + static const string kManaGreen; + static const string kManaBlue; + static const string kManaRed; + static const string kManaBlack; + static const string kManaWhite; - static const string kAlternativeKeyword; - static const string kBuyBackKeyword; - static const string kFlashBackKeyword; - static const string kRetraceKeyword; - static const string kKickerKeyword; + // alternative costs constants - // used for deck statistics - static const int STATS_FOR_TURNS = 8; - static const int STATS_MAX_MANA_COST = 9; + static const string kAlternativeKeyword; + static const string kBuyBackKeyword; + static const string kFlashBackKeyword; + static const string kRetraceKeyword; + static const string kKickerKeyword; + static const string kMorphKeyword; - enum - { - MTG_COLOR_ARTIFACT = 0, - MTG_COLOR_GREEN = 1, - MTG_COLOR_BLUE = 2, - MTG_COLOR_RED = 3, - MTG_COLOR_BLACK = 4, - MTG_COLOR_WHITE = 5, - MTG_COLOR_LAND = 6, + // used for deck statistics + static const int STATS_FOR_TURNS = 8; + static const int STATS_MAX_MANA_COST = 9; + + enum + { + MTG_COLOR_ARTIFACT = 0, + MTG_COLOR_GREEN = 1, + MTG_COLOR_BLUE = 2, + MTG_COLOR_RED = 3, + MTG_COLOR_BLACK = 4, + MTG_COLOR_WHITE = 5, + MTG_COLOR_LAND = 6, - MTG_NB_COLORS = 7, + MTG_NB_COLORS = 7, - MTG_UNCOLORED = 0, - MTG_FOREST = 1, - MTG_ISLAND = 2, - MTG_MOUNTAIN = 3, - MTG_SWAMP = 4, - MTG_PLAIN = 5, - MTG_TYPE_CREATURE = 10, - MTG_TYPE_ARTIFACT = 11, - MTG_TYPE_ENCHANTMENT = 12, - MTG_TYPE_SORCERY = 13, - MTG_TYPE_LAND = 14, - MTG_TYPE_INSTANT = 15, + MTG_UNCOLORED = 0, + MTG_FOREST = 1, + MTG_ISLAND = 2, + MTG_MOUNTAIN = 3, + MTG_SWAMP = 4, + MTG_PLAIN = 5, - MTG_PHASE_BEFORE_BEGIN = 0, - MTG_PHASE_UNTAP = 1, - MTG_PHASE_UPKEEP = 2, - MTG_PHASE_DRAW = 3, - MTG_PHASE_FIRSTMAIN = 4, - MTG_PHASE_COMBATBEGIN = 5, - MTG_PHASE_COMBATATTACKERS = 6, - MTG_PHASE_COMBATBLOCKERS = 7, - MTG_PHASE_COMBATDAMAGE = 8, - MTG_PHASE_COMBATEND = 9, - MTG_PHASE_SECONDMAIN = 10, - MTG_PHASE_ENDOFTURN = 11, - MTG_PHASE_EOT = 11, - MTG_PHASE_CLEANUP = 12, - MTG_PHASE_AFTER_EOT = 13, - NB_MTG_PHASES = 14, - TRAMPLE = 0, - FORESTWALK = 1, - ISLANDWALK = 2, - MOUNTAINWALK = 3, - SWAMPWALK = 4, - PLAINSWALK = 5, - FLYING = 6, - FIRSTSTRIKE = 7, - DOUBLESTRIKE = 8, - FEAR = 9, - FLASH = 10, - HASTE = 11, - LIFELINK = 12, - REACH = 13, - SHROUD = 14, - VIGILANCE = 15, - DEFENSER = 16, - DEFENDER = 16, - BANDING = 17, - PROTECTIONGREEN = 18, - PROTECTIONBLUE = 19, - PROTECTIONRED = 20, - PROTECTIONBLACK = 21, - PROTECTIONWHITE = 22, - UNBLOCKABLE = 23, - WITHER = 24, - PERSIST = 25, - RETRACE = 26, - EXALTED = 27, - NOFIZZLE = 28, - SHADOW = 29, - REACHSHADOW = 30, - FORESTHOME = 31, - ISLANDHOME = 32, - MOUNTAINHOME = 33, - SWAMPHOME = 34, - PLAINSHOME = 35, - CLOUD = 36, - CANTATTACK = 37, - MUSTATTACK = 38, - CANTBLOCK = 39, - DOESNOTUNTAP = 40, - OPPONENTSHROUD = 41, - INDESTRUCTIBLE = 42, - INTIMIDATE = 43, - DEATHTOUCH = 44, - HORSEMANSHIP = 45, - CANTREGEN = 46, - ONEBLOCKER = 47, - INFECT = 48, - POISONTOXIC = 49, - POISONTWOTOXIC = 50, - POISONTHREETOXIC = 51, - PHANTOM = 52, - WILTING = 53, - VIGOR = 54, - CHANGELING = 55, - ABSORB = 56,//this need to be coded for players too "If a source would deal damage" - TREASON = 57, - UNEARTH = 58, - CANTLOSE = 59, - CANTLIFELOSE = 60, - CANTMILLLOSE = 61, - CANTCASTCREATURE = 62, - CANTCAST = 63, - CANTCASTTWO = 64, - STORM = 65, - BOTHCANTCAST = 66, - BOTHNOCREATURE = 67, - ONLYONEBOTH = 68, - AFFINITYARTIFACTS = 69, - AFFINITYPLAINS = 70, - AFFINITYFOREST = 71, - AFFINITYISLAND = 72, - AFFINITYMOUNTAIN = 73, - AFFINITYSWAMP = 74, - AFFINITYGREENCREATURES = 75, - CANTWIN = 76, - NOMAXHAND = 77, - LEYLINE = 78, - PLAYERSHROUD = 79, - CONTROLLERSHROUD = 80, - SUNBURST = 81, - FLANKING = 82, - EXILEDEATH = 83, + MTG_TYPE_CREATURE = 10, + MTG_TYPE_ARTIFACT = 11, + MTG_TYPE_ENCHANTMENT = 12, + MTG_TYPE_SORCERY = 13, + MTG_TYPE_LAND = 14, + MTG_TYPE_INSTANT = 15, - NB_BASIC_ABILITIES = 84, - RARITY_S = 'S', //Special Rarity - RARITY_M = 'M', //Mythics - RARITY_R = 'R', //Rares - RARITY_U = 'U', //Uncommons - RARITY_C = 'C', //Commons - RARITY_L = 'L', //Lands - RARITY_T = 'T', //Tokens + MTG_PHASE_BEFORE_BEGIN = 0, + MTG_PHASE_UNTAP = 1, + MTG_PHASE_UPKEEP = 2, + MTG_PHASE_DRAW = 3, + MTG_PHASE_FIRSTMAIN = 4, + MTG_PHASE_COMBATBEGIN = 5, + MTG_PHASE_COMBATATTACKERS = 6, + MTG_PHASE_COMBATBLOCKERS = 7, + MTG_PHASE_COMBATDAMAGE = 8, + MTG_PHASE_COMBATEND = 9, + MTG_PHASE_SECONDMAIN = 10, + MTG_PHASE_ENDOFTURN = 11, + MTG_PHASE_CLEANUP = 12, + MTG_PHASE_AFTER_EOT = 13, + NB_MTG_PHASES = 14, - ECON_NORMAL = 0, //Options default to 0. - ECON_HARD = 1, - ECON_LUCK = 2, - ECON_EASY = 3, + TRAMPLE = 0, + FORESTWALK = 1, + ISLANDWALK = 2, + MOUNTAINWALK = 3, + SWAMPWALK = 4, + PLAINSWALK = 5, + FLYING = 6, + FIRSTSTRIKE = 7, + DOUBLESTRIKE = 8, + FEAR = 9, + FLASH = 10, + HASTE = 11, + LIFELINK = 12, + REACH = 13, + SHROUD = 14, + VIGILANCE = 15, + DEFENSER = 16, + DEFENDER = 16, + BANDING = 17, + PROTECTIONGREEN = 18, + PROTECTIONBLUE = 19, + PROTECTIONRED = 20, + PROTECTIONBLACK = 21, + PROTECTIONWHITE = 22, + UNBLOCKABLE = 23, + WITHER = 24, + PERSIST = 25, + RETRACE = 26, + EXALTED = 27, + NOFIZZLE = 28, + SHADOW = 29, + REACHSHADOW = 30, + FORESTHOME = 31, + ISLANDHOME = 32, + MOUNTAINHOME = 33, + SWAMPHOME = 34, + PLAINSHOME = 35, + CLOUD = 36, + CANTATTACK = 37, + MUSTATTACK = 38, + CANTBLOCK = 39, + DOESNOTUNTAP = 40, + OPPONENTSHROUD = 41, + INDESTRUCTIBLE = 42, + INTIMIDATE = 43, + DEATHTOUCH = 44, + HORSEMANSHIP = 45, + CANTREGEN = 46, + ONEBLOCKER = 47, + INFECT = 48, + POISONTOXIC = 49, + POISONTWOTOXIC = 50, + POISONTHREETOXIC = 51, + PHANTOM = 52, + WILTING = 53, + VIGOR = 54, + CHANGELING = 55, + ABSORB = 56,//this need to be coded for players too "If a source would deal damage" + TREASON = 57, + UNEARTH = 58, + CANTLOSE = 59, + CANTLIFELOSE = 60, + CANTMILLLOSE = 61, + CANTCASTCREATURE = 62, + CANTCAST = 63, + CANTCASTTWO = 64, + STORM = 65, + BOTHCANTCAST = 66, + BOTHNOCREATURE = 67, + ONLYONEBOTH = 68, + AFFINITYARTIFACTS = 69, + AFFINITYPLAINS = 70, + AFFINITYFOREST = 71, + AFFINITYISLAND = 72, + AFFINITYMOUNTAIN = 73, + AFFINITYSWAMP = 74, + AFFINITYGREENCREATURES = 75, + CANTWIN = 76, + NOMAXHAND = 77, + LEYLINE = 78, + PLAYERSHROUD = 79, + CONTROLLERSHROUD = 80, + SUNBURST = 81, + FLANKING = 82, + EXILEDEATH = 83, + LEGENDARYWALK = 84, + DESERTWALK = 85, +SNOWFORESTWALK = 86, +SNOWPLAINSWALK = 87, +SNOWMOUNTAINWALK = 88, +SNOWISLANDWALK = 89, +SNOWSWAMPWALK = 90, +SNOWWALK = 91, +NONBASICWALK = 92, +STRONG = 93, +WEAK = 94, +PHASING = 95, - //Price for singles - PRICE_1M = 3000, - PRICE_1R = 500, - PRICE_1S = 200, - PRICE_1U = 100, - PRICE_1C = 20, - PRICE_1L = 5, + NB_BASIC_ABILITIES = 96, - //Price in booster - PRICE_BOOSTER = 700, - PRICE_MIXED_BOOSTER = 800, - CHANCE_CUSTOM_PACK = 15, - CHANCE_PURE_OVERRIDE = 50, - CHANCE_MIXED_OVERRIDE = 25, - GRADE_SUPPORTED = 0, - GRADE_BORDERLINE = 1, - GRADE_UNOFFICIAL = 2, - GRADE_CRAPPY = 3, - GRADE_UNSUPPORTED = 4, - GRADE_DANGEROUS = 5, + RARITY_S = 'S', //Special Rarity + RARITY_M = 'M', //Mythics + RARITY_R = 'R', //Rares + RARITY_U = 'U', //Uncommons + RARITY_C = 'C', //Commons + RARITY_L = 'L', //Lands + RARITY_T = 'T', //Tokens - ASKIP_NONE = 0, - ASKIP_SAFE = 1, - ASKIP_FULL = 2, - }; + ECON_NORMAL = 0, //Options default to 0. + ECON_HARD = 1, + ECON_LUCK = 2, + ECON_EASY = 3, - static char MTGColorChars[]; - static const char* MTGColorStrings[]; - static int _r[], _g[], _b[]; + //Price for singles + PRICE_1M = 3000, + PRICE_1R = 500, + PRICE_1S = 200, + PRICE_1U = 100, + PRICE_1C = 20, + PRICE_1L = 5, - static map MTGBasicAbilitiesMap; - static const char* MTGBasicAbilities[]; - static const char* MTGPhaseNames[]; - static const char* MTGPhaseCodeNames[]; + //Price in booster + PRICE_BOOSTER = 700, + PRICE_MIXED_BOOSTER = 800, + CHANCE_CUSTOM_PACK = 15, + CHANCE_PURE_OVERRIDE = 50, + CHANCE_MIXED_OVERRIDE = 25, - static int GetBasicAbilityIndex(string mtgAbility); - static int GetColorStringIndex(string mtgColor); + GRADE_SUPPORTED = 0, + GRADE_BORDERLINE = 1, + GRADE_UNOFFICIAL = 2, + GRADE_CRAPPY = 3, + GRADE_UNSUPPORTED = 4, + GRADE_DANGEROUS = 5, + ASKIP_NONE=0, + ASKIP_SAFE=1, + ASKIP_FULL=2, + + WHO_P=0, + WHO_O=1, + WHO_R=2, + + }; + + static char MTGColorChars[]; + static const char* MTGColorStrings[]; + static int _r[], _g[], _b[]; + + static map MTGBasicAbilitiesMap; + static const char* MTGBasicAbilities[]; + static const char* MTGPhaseNames[]; + static const char* MTGPhaseCodeNames[]; + + static int GetBasicAbilityIndex(string mtgAbility); + static int GetColorStringIndex(string mtgColor); + }; #endif diff --git a/projects/mtg/include/MTGGameZones.h b/projects/mtg/include/MTGGameZones.h index b6c035d4a..0a9769bc7 100644 --- a/projects/mtg/include/MTGGameZones.h +++ b/projects/mtg/include/MTGGameZones.h @@ -14,191 +14,168 @@ class MTGDeck; class MTGCardInstance; class Player; -class MTGGameZone -{ -protected: +class MTGGameZone { + protected: -public: + public: - enum - { - ALL_ZONES = -1, + enum{ + ALL_ZONES = -1, - MY_GRAVEYARD = 11, - OPPONENT_GRAVEYARD = 12, - TARGET_OWNER_GRAVEYARD = 13, - TARGET_CONTROLLER_GRAVEYARD = 14, - GRAVEYARD = 15, - OWNER_GRAVEYARD = 16, + MY_GRAVEYARD = 11, + OPPONENT_GRAVEYARD = 12, + TARGET_OWNER_GRAVEYARD = 13, + TARGET_CONTROLLER_GRAVEYARD = 14, + GRAVEYARD = 15, + OWNER_GRAVEYARD = 16, - MY_BATTLEFIELD = 21, - OPPONENT_BATTLEFIELD = 22, - TARGET_OWNER_BATTLEFIELD = 23, - TARGET_CONTROLLER_BATTLEFIELD = 24, - BATTLEFIELD = 25, - OWNER_BATTLEFIELD = 26, + MY_BATTLEFIELD = 21, + OPPONENT_BATTLEFIELD = 22, + TARGET_OWNER_BATTLEFIELD = 23, + TARGET_CONTROLLER_BATTLEFIELD = 24, + BATTLEFIELD = 25, + OWNER_BATTLEFIELD = 26, - MY_HAND = 31, - OPPONENT_HAND = 32, - TARGET_OWNER_HAND = 33, - TARGET_CONTROLLER_HAND = 34, - HAND = 35, - OWNER_HAND = 36, + MY_HAND = 31, + OPPONENT_HAND = 32, + TARGET_OWNER_HAND = 33, + TARGET_CONTROLLER_HAND = 34, + HAND = 35, + OWNER_HAND = 36, - MY_EXILE = 41, - OPPONENT_EXILE = 42, - TARGET_OWNER_EXILE = 43, - TARGET_CONTROLLER_EXILE = 44, - EXILE = 45, - OWNER_EXILE = 46, + MY_EXILE = 41, + OPPONENT_EXILE = 42, + TARGET_OWNER_EXILE = 43, + TARGET_CONTROLLER_EXILE = 44, + EXILE = 45, + OWNER_EXILE = 46, - MY_LIBRARY = 51, - OPPONENT_LIBRARY = 52, - TARGET_OWNER_LIBRARY = 53, - TARGET_CONTROLLER_LIBRARY = 54, - LIBRARY = 55, - OWNER_LIBRARY = 56, + MY_LIBRARY = 51, + OPPONENT_LIBRARY = 52, + TARGET_OWNER_LIBRARY = 53, + TARGET_CONTROLLER_LIBRARY = 54, + LIBRARY = 55, + OWNER_LIBRARY = 56, - MY_STACK = 61, - OPPONENT_STACK = 62, - TARGET_OWNER_STACK = 63, - TARGET_CONTROLLER_STACK = 64, - STACK = 65, - OWNER_STACK = 66, + MY_STACK = 61, + OPPONENT_STACK = 62, + TARGET_OWNER_STACK = 63, + TARGET_CONTROLLER_STACK = 64, + STACK = 65, + OWNER_STACK = 66, - }; + }; - Player * owner; - //Both cards and cardsMap contain the cards of a zone. The long term objective is to get rid of the array - vector cards; //[MTG_MAX_PLAYER_CARDS]; - map cardsMap; - int nb_cards; - MTGGameZone(); - ~MTGGameZone(); - void shuffle(); - void addCard(MTGCardInstance * card); - void debugPrint(); - MTGCardInstance * removeCard(MTGCardInstance * card, int createCopy = 1); - MTGCardInstance * hasCard(MTGCardInstance * card); - void cleanupPhase(); - int countByType(const char * value); - MTGCardInstance * findByName(string name); - int hasAbility(int ability); //returns 1 if one of the cards in the zone has the ability, 0 otherwise - int hasType(const char * value); //returns 1 if one of the cards in the zone has the type, 0 otherwise - int hasColor(int value); //returns 1 if one of the cards in the zone has the color, 0 otherwise - int hasX(); - void setOwner(Player * player); - MTGCardInstance * lastCardDrawn; - static MTGGameZone * stringToZone(string zoneName, MTGCardInstance * source, MTGCardInstance * target); - static int zoneStringToId(string zoneName); - static MTGGameZone *intToZone(int zoneId, MTGCardInstance * source = NULL, MTGCardInstance * target = NULL); - bool needShuffle; - virtual const char * getName() - { - return "zone"; - } - ; - virtual ostream& toString(ostream&) const; + Player * owner; + //Both cards and cardsMap contain the cards of a zone. The long term objective is to get rid of the array + vector cards; //[MTG_MAX_PLAYER_CARDS]; + map cardsMap; + int nb_cards; + MTGGameZone(); + ~MTGGameZone(); + void shuffle(); + void addCard(MTGCardInstance * card); + void debugPrint(); + MTGCardInstance * removeCard(MTGCardInstance * card, int createCopy = 1); + MTGCardInstance * hasCard(MTGCardInstance * card); + void cleanupPhase(); + int countByType(const char * value); + MTGCardInstance * findByName(string name); + int hasAbility(int ability); //returns 1 if one of the cards in the zone has the ability, 0 otherwise + int hasType(const char * value); //returns 1 if one of the cards in the zone has the type, 0 otherwise + int hasSpecificType(const char * value,const char * secondvalue); //returns 1 if one of the cards in the zone has the type, 0 otherwise + int hasPrimaryType(const char * value,const char * secondvalue); //returns 1 if one of the cards in the zone has the type, 0 otherwise + int hasTypeButNotType(const char * value,const char * secondvalue); //returns 1 if one of the cards in the zone has the type, 0 otherwise + int hasName(string value); + int hasColor(int value); //returns 1 if one of the cards in the zone has the color, 0 otherwise + int hasX(); + void setOwner(Player * player); + MTGCardInstance * lastCardDrawn; + static MTGGameZone * stringToZone(string zoneName, MTGCardInstance * source, MTGCardInstance * target); + static int zoneStringToId(string zoneName); + static MTGGameZone *intToZone(int zoneId, MTGCardInstance * source = NULL,MTGCardInstance * target = NULL); + bool needShuffle; + virtual const char * getName(){return "zone";}; + virtual ostream& toString(ostream&) const; }; -class MTGLibrary: public MTGGameZone -{ -public: - void shuffleTopToBottom(int nbcards); - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "library"; - } +class MTGLibrary: public MTGGameZone { + public: + void shuffleTopToBottom(int nbcards); + virtual ostream& toString(ostream&) const; + const char * getName(){return "library";} }; -class MTGGraveyard: public MTGGameZone -{ -public: - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "graveyard"; - } +class MTGGraveyard: public MTGGameZone { + public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "graveyard";} }; -class MTGHand: public MTGGameZone -{ -public: - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "hand"; - } +class MTGHand: public MTGGameZone { + public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "hand";} }; -class MTGRemovedFromGame: public MTGGameZone -{ -public: - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "exile"; - } +class MTGRemovedFromGame: public MTGGameZone { + public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "exile";} }; -class MTGStack: public MTGGameZone -{ -public: - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "stack"; - } +class MTGStack: public MTGGameZone { + public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "stack";} }; -class MTGInPlay: public MTGGameZone -{ -public: - void untapAll(); - MTGCardInstance * getNextAttacker(MTGCardInstance * previous); - virtual ostream& toString(ostream&) const; - const char * getName() - { - return "battlefield"; - } +class MTGInPlay: public MTGGameZone { + public: + void untapAll(); + MTGCardInstance * getNextAttacker(MTGCardInstance * previous); + virtual ostream& toString(ostream&) const; + const char * getName(){return "battlefield";} }; -class MTGPlayerCards -{ -protected: - void init(); -public: - MTGLibrary * library; - MTGGraveyard * graveyard; - MTGHand * hand; - MTGInPlay * inPlay; - MTGInPlay * battlefield; //alias to inPlay +class MTGPlayerCards { + protected: + void init(); - MTGStack * stack; - MTGRemovedFromGame * removedFromGame; - MTGRemovedFromGame * exile; //alias to removedFromZone - MTGGameZone * garbage; - MTGGameZone * temp; + public: + MTGLibrary * library; + MTGGraveyard * graveyard; + MTGHand * hand; + MTGInPlay * inPlay; + MTGInPlay * battlefield; //alias to inPlay - MTGPlayerCards(int * idList, int idListSize); - MTGPlayerCards(MTGDeck * deck); - ~MTGPlayerCards(); - void initGame(int shuffle = 1, int draw = 1); - void OptimizedHand(Player * who, int amount = 7, int lands = 3, int creatures = 0, int othercards = 4); - void setOwner(Player * player); - void discardRandom(MTGGameZone * from, MTGCardInstance * source); - void drawFromLibrary(); - void showHand(); - void resetLibrary(); - void initDeck(MTGDeck * deck); - MTGCardInstance * putInGraveyard(MTGCardInstance * card); - MTGCardInstance * putInExile(MTGCardInstance * card); - MTGCardInstance * putInLibrary(MTGCardInstance * card); - MTGCardInstance * putInHand(MTGCardInstance * card); - MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to); - int isInPlay(MTGCardInstance * card); + MTGStack * stack; + MTGRemovedFromGame * removedFromGame; + MTGRemovedFromGame * exile; //alias to removedFromZone + MTGGameZone * garbage; + MTGGameZone * temp; + + MTGPlayerCards(int * idList, int idListSize); + MTGPlayerCards(MTGDeck * deck); + ~MTGPlayerCards(); + void initGame(int shuffle = 1, int draw = 1); + void OptimizedHand(Player * who,int amount = 7,int lands = 3,int creatures = 0,int othercards = 4); + void setOwner(Player * player); + void discardRandom(MTGGameZone * from,MTGCardInstance * source); + void drawFromLibrary(); + void showHand(); + void resetLibrary(); + void initDeck(MTGDeck * deck); + MTGCardInstance * putInGraveyard(MTGCardInstance * card); + MTGCardInstance * putInExile(MTGCardInstance * card); + MTGCardInstance * putInLibrary(MTGCardInstance * card); + MTGCardInstance * putInHand(MTGCardInstance * card); + MTGCardInstance * putInBattlefield(MTGCardInstance * card); + MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to); + int isInPlay(MTGCardInstance * card); + int isInGrave(MTGCardInstance * card); + int isInZone(MTGCardInstance * card,MTGGameZone * zone); }; ostream& operator<<(ostream&, const MTGGameZone&); diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index 61967e082..039b5b495 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -18,7 +18,6 @@ public: OtherAbilitiesEventReceiver(int _id); OtherAbilitiesEventReceiver * clone() const; }; - class MTGPutInPlayRule: public MTGAbility { public: @@ -37,10 +36,11 @@ public: class MTGAlternativeCostRule: public MTGAbility { public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); int isReactingToClick(MTGCardInstance * card, ManaCost * mana, ManaCost *alternateManaCost); - int reactToClick(MTGCardInstance * card, ManaCost * alternateManaCost, MTGGameZone * originatingZone, int paymentType = ManaCost::MANA_PAID); + int reactToClick(MTGCardInstance * card, ManaCost * alternateManaCost, int paymentType = ManaCost::MANA_PAID); int reactToClick(MTGCardInstance * card); int testDestroy(); @@ -71,6 +71,7 @@ public: class MTGFlashBackRule: public MTGAlternativeCostRule { public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); int reactToClick(MTGCardInstance * card); int testDestroy(); @@ -98,9 +99,26 @@ public: virtual MTGRetraceRule * clone() const; }; +class MTGMorphCostRule: public MTGAbility +{ +public: + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGMorphCostRule(int _id); + const char * getMenuText() + { + return "Play Morphed"; + } + virtual MTGMorphCostRule * clone() const; +}; + class MTGAttackRule: public MTGAbility, public Limitor { public: + virtual bool select(Target*); virtual bool greyout(Target*); int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); diff --git a/projects/mtg/include/ManaCost.h b/projects/mtg/include/ManaCost.h index 4bfd44470..c312d8fc6 100644 --- a/projects/mtg/include/ManaCost.h +++ b/projects/mtg/include/ManaCost.h @@ -4,6 +4,7 @@ #include "utils.h" #include "MTGDefinitions.h" + class ManaCostHybrid; class ExtraCosts; class ExtraCost; @@ -11,90 +12,89 @@ class MTGAbility; class MTGCardInstance; class Player; -class ManaCost -{ -protected: - int cost[Constants::MTG_NB_COLORS + 1]; - ManaCostHybrid * hybrids[10]; - unsigned int nbhybrids; - int extraCostsIsCopy; +class ManaCost{ + protected: + int cost[Constants::MTG_NB_COLORS+1]; + ManaCostHybrid * hybrids[10]; + unsigned int nbhybrids; + int extraCostsIsCopy; + + public: + enum{ + MANA_UNPAID = 0, + MANA_PAID = 1, + MANA_PAID_WITH_KICKER = 2, + MANA_PAID_WITH_ALTERNATIVE = 3, + MANA_PAID_WITH_BUYBACK = 4, + MANA_PAID_WITH_FLASHBACK = 5, + MANA_PAID_WITH_RETRACE = 6, + MANA_PAID_WITH_MORPH = 7 -public: - enum - { - MANA_UNPAID = 0, - MANA_PAID = 1, - MANA_PAID_WITH_KICKER = 2, - MANA_PAID_WITH_ALTERNATIVE = 3, - MANA_PAID_WITH_BUYBACK = 4, - MANA_PAID_WITH_FLASHBACK = 5, - MANA_PAID_WITH_RETRACE = 6 + }; + ExtraCosts * extraCosts; + ManaCost * kicker; + ManaCost * alternative; + ManaCost * BuyBack; + ManaCost * FlashBack; + ManaCost * Retrace; + ManaCost * morph; + static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL); + virtual void init(); + void x(); + int hasX(); + ManaCost(int _cost[], int nb_elems = 1); + ManaCost(); + ~ManaCost(); + ManaCost(ManaCost * _manaCost); + void copy (ManaCost * _manaCost); + int isNull(); + int getConvertedCost(); + string toString(); + int getCost(int color); + //Returns NULL if i is greater than nbhybrids + ManaCostHybrid * getHybridCost(unsigned int i); + int hasColor(int color); + int remove (int color, int value); + int add(int color, int value); - }; - ExtraCosts * extraCosts; - ManaCost * kicker; - ManaCost * alternative; - ManaCost * BuyBack; - ManaCost * FlashBack; - ManaCost * Retrace; - static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL); - virtual void init(); - void x(); - int hasX(); - ManaCost(int _cost[], int nb_elems = 1); - ManaCost(); - ~ManaCost(); - ManaCost(ManaCost * _manaCost); - void copy(ManaCost * _manaCost); - int isNull(); - int getConvertedCost(); - string toString(); - int getCost(int color); - //Returns NULL if i is greater than nbhybrids - ManaCostHybrid * getHybridCost(unsigned int i); - int hasColor(int color); - int remove(int color, int value); - int add(int color, int value); + // + // Extra Costs (sacrifice,counters...) + // + int addExtraCost(ExtraCost * _cost); + int setExtraCostsAction(MTGAbility * action, MTGCardInstance * card); + int isExtraPaymentSet(); + int canPayExtra(); + int doPayExtra(); - // - // Extra Costs (sacrifice,counters...) - // - int addExtraCost(ExtraCost * _cost); - int setExtraCostsAction(MTGAbility * action, MTGCardInstance * card); - int isExtraPaymentSet(); - int canPayExtra(); - int doPayExtra(); + int addHybrid(int c1, int v1, int c2, int v2); + int tryToPayHybrids(ManaCostHybrid * _hybrids[], int _nbhybrids, int diff[]); + void randomDiffHybrids(ManaCost * _cost, int diff[]); + int add(ManaCost * _cost); + int pay (ManaCost * _cost); - int addHybrid(int c1, int v1, int c2, int v2); - int tryToPayHybrids(ManaCostHybrid * _hybrids[], int _nbhybrids, int diff[]); - void randomDiffHybrids(ManaCost * _cost, int diff[]); - int add(ManaCost * _cost); - int pay(ManaCost * _cost); + //return 1 if _cost can be paid with current data, 0 otherwise + int canAfford(ManaCost * _cost); - //return 1 if _cost can be paid with current data, 0 otherwise - int canAfford(ManaCost * _cost); - - int isPositive(); - ManaCost * Diff(ManaCost * _cost); + int isPositive(); + ManaCost * Diff(ManaCost * _cost); #ifdef WIN32 - void Dump(); + void Dump(); #endif }; std::ostream& operator<<(std::ostream& out, const ManaCost& m); -class ManaPool: public ManaCost -{ +class ManaPool:public ManaCost{ protected: - Player * player; + Player * player; public: - void init(); - ManaPool(Player * player); - ManaPool(ManaCost * _manaCost, Player * player); - int remove(int color, int value); - int add(int color, int value, MTGCardInstance * source = NULL); - int add(ManaCost * _cost, MTGCardInstance * source = NULL); - int pay(ManaCost * _cost); + void init(); + ManaPool(Player * player); + ManaPool(ManaCost * _manaCost, Player * player); + int remove (int color, int value); + int add(int color, int value, MTGCardInstance * source = NULL); + int add(ManaCost * _cost, MTGCardInstance * source = NULL); + int pay (ManaCost * _cost); }; #endif diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 7493b8e86..474dec2a9 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -41,6 +41,7 @@ public: bool onlyoneboth; bool bothrestrictedspell; bool bothrestrictedcreature; + bool isPoisoned; MTGPlayerCards * game; string deckFile; string deckFileSmall; diff --git a/projects/mtg/include/ThisDescriptor.h b/projects/mtg/include/ThisDescriptor.h index d3ea89163..7483ea3b6 100644 --- a/projects/mtg/include/ThisDescriptor.h +++ b/projects/mtg/include/ThisDescriptor.h @@ -1,6 +1,6 @@ /* - Filter-like system for determining if a card meats certain criteria, for this and thisforeach autos - */ + Filter-like system for determining if a card meats certain criteria, for this and thisforeach autos +*/ #ifndef _THISDESCRIPTOR_H_ #define _THISDESCRIPTOR_H_ @@ -10,102 +10,119 @@ #include "MTGCardInstance.h" #include "CardDescriptor.h" -class ThisDescriptor -{ -public: - int comparisonMode; - int comparisonCriterion; - virtual int match(MTGCardInstance * card) = 0; - int matchValue(int value); - virtual ~ThisDescriptor(); +class ThisDescriptor{ + public: + int comparisonMode; + int comparisonCriterion; + virtual int match(MTGCardInstance * card) = 0; + int matchValue(int value); + virtual ~ThisDescriptor(); }; -class ThisDescriptorFactory -{ +class ThisDescriptorFactory{ public: - ThisDescriptor * createThisDescriptor(string s); + ThisDescriptor * createThisDescriptor(string s); }; -class ThisCounter: public ThisDescriptor -{ -public: - Counter * counter; +class ThisCounter:public ThisDescriptor{ + public: + Counter * counter; + virtual int match(MTGCardInstance * card); + + ThisCounter(Counter * _counter); + ThisCounter(int power, int toughness, int nb, const char * name); + ~ThisCounter(); +}; + +class ThisCounterAny:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance *card); + + ThisCounterAny(int nb); +}; + +class ThisControllerlife:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - - ThisCounter(Counter * _counter); - ThisCounter(int power, int toughness, int nb, const char * name); - ~ThisCounter(); -}; - -class ThisCounterAny: public ThisDescriptor -{ -public: - virtual int match(MTGCardInstance *card); - - ThisCounterAny(int nb); -}; - -class ThisControllerlife: public ThisDescriptor -{ -public: - virtual int match(MTGCardInstance * card); - + ThisControllerlife(int life); }; -class ThisOpponentlife: public ThisDescriptor -{ -public: +class ThisOpponentlife:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - + ThisOpponentlife(int olife); }; -class ThisEquip: public ThisDescriptor -{ -public: +class ThisEquip:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - + ThisEquip(int equipment); }; -class ThisAttacked: public ThisDescriptor -{ -public: +class ThisAuras:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - - ThisAttacked(int attack); + + ThisAuras(int auras); }; -class ThisNotBlocked: public ThisDescriptor -{ -public: +class ThisOpponentDamageAmount:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - - ThisNotBlocked(int unblocked); + + ThisOpponentDamageAmount(int damagecount); }; -class ThisPower: public ThisDescriptor -{ -public: +class ThisUntapped:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + + ThisUntapped(int untapped); +}; + +class ThisTapped:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + + ThisTapped(int tapped); +}; + + +class ThisAttacked:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); + ThisAttacked(int attack); +}; + +class ThisNotBlocked:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + + ThisNotBlocked(int unblocked); +}; + +class ThisPower:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + ThisPower(int power); }; -class ThisToughness: public ThisDescriptor -{ -public: +class ThisToughness:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); - + ThisToughness(int toughness); }; -class ThisX: public ThisDescriptor -{ -public: +class ThisX:public ThisDescriptor{ + public: virtual int match(MTGCardInstance * card); ThisX(int x); }; -#endif +#endif diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index 52418b785..eee7e8872 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -26,217 +26,213 @@ public: TARGET_FROM, }; int type; //Deprecated, use dynamic casting instead - WEvent(int type = NOT_SPECIFIED); - virtual ~WEvent() {}; - virtual std::ostream& toString(std::ostream& out) const; - virtual int getValue() - { - return 0; - } - ; - virtual Targetable * getTarget(int target) - { - return 0; - } - ; + WEvent(int type = NOT_SPECIFIED); + virtual ~WEvent() {}; + virtual std::ostream& toString(std::ostream& out) const; + virtual int getValue() {return 0;}; + virtual Targetable * getTarget(int target) {return 0;}; }; -struct WEventZoneChange: public WEvent -{ - MTGCardInstance * card; - MTGGameZone * from; - MTGGameZone * to; - WEventZoneChange(MTGCardInstance * card, MTGGameZone * from, MTGGameZone *to); - virtual ~WEventZoneChange() {}; - virtual std::ostream& toString(std::ostream& out) const; +struct WEventZoneChange : public WEvent { + MTGCardInstance * card; + MTGGameZone * from; + MTGGameZone * to; + WEventZoneChange(MTGCardInstance * card, MTGGameZone * from, MTGGameZone *to); + virtual ~WEventZoneChange() {}; + virtual std::ostream& toString(std::ostream& out) const; + virtual Targetable * getTarget(int target); +}; + +struct WEventDamage : public WEvent { + Damage * damage; + WEventDamage(Damage * damage); + virtual std::ostream& toString(std::ostream& out) const; + virtual int getValue(); + virtual Targetable * getTarget(int target); +}; + +struct WEventLife : public WEvent { + Player * player; + int amount; + int Ltype; + WEventLife(Player * player,int amount,int Ltype = 0); virtual Targetable * getTarget(int target); }; -struct WEventDamage: public WEvent -{ - Damage * damage; - WEventDamage(Damage * damage); - virtual std::ostream& toString(std::ostream& out) const; - virtual int getValue(); - virtual Targetable * getTarget(int target); +struct WEventDamageStackResolved : public WEvent { + WEventDamageStackResolved(); }; -struct WEventDamageStackResolved: public WEvent -{ - WEventDamageStackResolved(); +struct WEventPhaseChange : public WEvent { + Phase * from; + Phase * to; + WEventPhaseChange(Phase * from, Phase * to); }; -struct WEventPhaseChange: public WEvent -{ - Phase * from; - Phase * to; - WEventPhaseChange(Phase * from, Phase * to); -}; //Abstract class of event when a card's status changes -struct WEventCardUpdate: public WEvent -{ - MTGCardInstance * card; - WEventCardUpdate(MTGCardInstance * card); +struct WEventCardUpdate : public WEvent { + MTGCardInstance * card; + WEventCardUpdate(MTGCardInstance * card); +}; + +//creature damaged was killed, triggers effects targetter +struct WEventVampire : public WEventCardUpdate { + MTGCardInstance * card; + MTGCardInstance * source; + MTGCardInstance * victem; + WEventVampire(MTGCardInstance * card,MTGCardInstance * source,MTGCardInstance * victem); + virtual Targetable * getTarget(int target); +}; + +//creature became the target of a spell or ability +struct WEventTarget : public WEventCardUpdate { + MTGCardInstance * card; + MTGCardInstance * source; + WEventTarget(MTGCardInstance * card,MTGCardInstance * source); + virtual Targetable * getTarget(int target); }; //Event when a card gains/looses types -struct WEventCardChangeType: public WEventCardUpdate -{ - int type; - bool before; - bool after; - WEventCardChangeType(MTGCardInstance * card, int type, bool before, bool after); +struct WEventCardChangeType : public WEventCardUpdate { + int type; + bool before; + bool after; + WEventCardChangeType(MTGCardInstance * card, int type, bool before, bool after); }; //Event when a card is tapped/untapped -struct WEventCardTap: public WEventCardUpdate -{ - bool before; - bool after; - WEventCardTap(MTGCardInstance * card, bool before, bool after); - virtual Targetable * getTarget(int target); +struct WEventCardTap : public WEventCardUpdate { + bool before; + bool after; + WEventCardTap(MTGCardInstance * card, bool before, bool after); + virtual Targetable * getTarget(int target); }; -struct WEventCardTappedForMana: public WEventCardUpdate -{ - bool before; - bool after; - WEventCardTappedForMana(MTGCardInstance * card, bool before, bool after); - virtual Targetable * getTarget(int target); +struct WEventCardTappedForMana : public WEventCardUpdate { + bool before; + bool after; + WEventCardTappedForMana(MTGCardInstance * card, bool before, bool after); + virtual Targetable * getTarget(int target); }; + //Event when a card's "attacker" status changes //before:Player/Planeswalker that card was attacking previously //after: Player/Planeswalker that card is attacking now -struct WEventCreatureAttacker: public WEventCardUpdate -{ - Targetable * before; - Targetable * after; - WEventCreatureAttacker(MTGCardInstance * card, Targetable * from, Targetable * to); +struct WEventCreatureAttacker : public WEventCardUpdate { + Targetable * before; + Targetable * after; + WEventCreatureAttacker(MTGCardInstance * card, Targetable * from, Targetable * to); }; //event when card attacks. -struct WEventCardAttacked: public WEventCardUpdate -{ - WEventCardAttacked(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardAttacked : public WEventCardUpdate { + WEventCardAttacked(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card attacks alone. -struct WEventCardAttackedAlone: public WEventCardUpdate -{ - WEventCardAttackedAlone(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardAttackedAlone : public WEventCardUpdate { + WEventCardAttackedAlone(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card attacks but is not blocked. -struct WEventCardAttackedNotBlocked: public WEventCardUpdate -{ - WEventCardAttackedNotBlocked(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardAttackedNotBlocked : public WEventCardUpdate { + WEventCardAttackedNotBlocked(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card attacks but is blocked. -struct WEventCardAttackedBlocked: public WEventCardUpdate -{ - WEventCardAttackedBlocked(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardAttackedBlocked : public WEventCardUpdate { + WEventCardAttackedBlocked(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card blocked. -struct WEventCardBlocked: public WEventCardUpdate -{ - WEventCardBlocked(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardBlocked : public WEventCardUpdate { + WEventCardBlocked(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card is sacrificed. -struct WEventCardSacrifice: public WEventCardUpdate -{ - WEventCardSacrifice(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardSacrifice : public WEventCardUpdate { + WEventCardSacrifice(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //event when card is discarded. -struct WEventCardDiscard: public WEventCardUpdate -{ - WEventCardDiscard(MTGCardInstance * card); - virtual Targetable * getTarget(int target); +struct WEventCardDiscard : public WEventCardUpdate { + WEventCardDiscard(MTGCardInstance * card); + virtual Targetable * getTarget(int target); }; //Event when a card's "defenser" status changes //before : attacker that card was blocking previously //after: attacker that card is blocking now -struct WEventCreatureBlocker: public WEventCardUpdate -{ - MTGCardInstance * before; - MTGCardInstance * after; - WEventCreatureBlocker(MTGCardInstance * card, MTGCardInstance * from, MTGCardInstance * to); +struct WEventCreatureBlocker : public WEventCardUpdate { + MTGCardInstance * before; + MTGCardInstance * after; + WEventCreatureBlocker(MTGCardInstance * card,MTGCardInstance * from,MTGCardInstance * to); }; //Event sent when attackers have been chosen and they //cannot be changed any more. -struct WEventAttackersChosen: public WEvent -{ +struct WEventAttackersChosen : public WEvent { }; //Event sent when blockers have been chosen and they //cannot be changed any more. -struct WEventBlockersChosen: public WEvent -{ +struct WEventBlockersChosen : public WEvent { }; -struct WEventcardDraw: public WEvent -{ - WEventcardDraw(Player * player, int nb_cards); - Player * player; - int nb_cards; - virtual Targetable * getTarget(Player * player); +struct WEventcardDraw : public WEvent { + WEventcardDraw(Player * player,int nb_cards); + Player * player; + int nb_cards; + virtual Targetable * getTarget(Player * player); }; //Event when a blocker is reordered //exchangeWith: exchange card's position with exchangeWith's position //attacker:both card and exchangeWith *should* be in attacker's "blockers" list. -struct WEventCreatureBlockerRank: public WEventCardUpdate -{ - MTGCardInstance * exchangeWith; - MTGCardInstance * attacker; - WEventCreatureBlockerRank(MTGCardInstance * card, MTGCardInstance * exchangeWith, MTGCardInstance * attacker); +struct WEventCreatureBlockerRank : public WEventCardUpdate { + MTGCardInstance * exchangeWith; + MTGCardInstance * attacker; + WEventCreatureBlockerRank(MTGCardInstance * card,MTGCardInstance * exchangeWith, MTGCardInstance * attacker); }; //Event when a combat phase step ends -struct WEventCombatStepChange: public WEvent +struct WEventCombatStepChange : public WEvent { - CombatStep step; - WEventCombatStepChange(CombatStep); + CombatStep step; + WEventCombatStepChange(CombatStep); }; + //Event when a mana is engaged //color : color -struct WEventEngageMana: public WEvent -{ - int color; - MTGCardInstance* card; - ManaPool * destination; - WEventEngageMana(int color, MTGCardInstance* card, ManaPool * destination); +struct WEventEngageMana : public WEvent { + int color; + MTGCardInstance* card; + ManaPool * destination; + WEventEngageMana(int color, MTGCardInstance* card, ManaPool * destination); }; //Event when a mana is consumed //color : color -struct WEventConsumeMana: public WEvent -{ - int color; - ManaPool * source; - WEventConsumeMana(int color, ManaPool * source); +struct WEventConsumeMana : public WEvent { + int color; + ManaPool * source; + WEventConsumeMana(int color, ManaPool * source); }; //Event when a manapool is emptied //color : color -struct WEventEmptyManaPool: public WEvent -{ - ManaPool * source; - WEventEmptyManaPool(ManaPool * source); +struct WEventEmptyManaPool : public WEvent { + ManaPool * source; + WEventEmptyManaPool(ManaPool * source); }; std::ostream& operator<<(std::ostream&, const WEvent&); diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 6eb4d1982..e2145bda4 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -150,7 +150,7 @@ ManaCost * AIPlayer::getPotentialMana(MTGCardInstance * target) MTGCardInstance * card = amp->source; if (card == target) used[card] = true; //http://code.google.com/p/wagic/issues/detail?id=76 - if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost() == 1) + if (!used[card] && amp->isReactingToClick(card) && amp->output->getConvertedCost() >= 1) { result->add(amp->output); used[card] = true; @@ -771,7 +771,7 @@ int AIPlayer::effectBadOrGood(MTGCardInstance * card, int mode, TargetChooser * return BAKA_EFFECT_DONTKNOW; } -int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget) +int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCardInstance * Choosencard) { vector potentialTargets; TargetChooser * tc = _tc; @@ -780,11 +780,13 @@ int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget) int checkOnly = 0; if (tc) { + if(!Choosencard) checkOnly = 1; } else { - tc = gameObs->getCurrentTargetChooser(); + tc = gameObs->getCurrentTargetChooser(); + } if (!tc) return 0; @@ -845,6 +847,35 @@ int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget) } } } + //targetting the stack + zone = playerZones->stack; + for (int k = 0; k < zone->nb_cards; k++) + { + MTGCardInstance* card = zone->cards[k]; + if (!tc->alreadyHasTarget(card) && tc->canTarget(card) && nbtargets < 50) + { + if (checkOnly) + return 1; + int multiplier = 1; + if (getStats() && getStats()->isInTop(card, 10)) + { + multiplier++; + if (getStats()->isInTop(card, 5)) + { + multiplier++; + if (getStats()->isInTop(card, 3)) + { + multiplier++; + } + } + } + for (int l = 0; l < multiplier; l++) + { + potentialTargets.push_back(card); + nbtargets++; + } + } + } } if (nbtargets) { @@ -853,26 +884,28 @@ int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget) switch (type) { case TARGET_CARD: - { - MTGCardInstance * card = ((MTGCardInstance *) potentialTargets[i]); - clickstream.push(NEW AIAction(card)); - return 1; - break; - } + { + MTGCardInstance * card = ((MTGCardInstance *) potentialTargets[i]); + clickstream.push(NEW AIAction(card)); + return 1; + break; + } case TARGET_PLAYER: - { - Player * player = ((Player *) potentialTargets[i]); - clickstream.push(NEW AIAction(player)); - return 1; - break; - } + { + Player * player = ((Player *) potentialTargets[i]); + clickstream.push(NEW AIAction(player)); + return 1; + break; + } } } //Couldn't find any valid target, //usually that's because we played a card that has bad side effects (ex: when X comes into play, return target land you own to your hand) //so we try again to choose a target in the other player's field... if (checkOnly) + { return 0; + } int cancel = gameObs->cancelCurrentAction(); if (!cancel && !forceTarget) return chooseTarget(_tc, target->opponent()); @@ -1180,6 +1213,7 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * ty if (tc) { int hasTarget = (chooseTarget(tc)); + if(tc) delete tc; if (!hasTarget) continue; @@ -1241,7 +1275,6 @@ void AIPlayerBaka::initTimer() { timer = 0.1f; } - int AIPlayerBaka::computeActions() { GameObserver * g = GameObserver::GetInstance(); @@ -1256,121 +1289,160 @@ int AIPlayerBaka::computeActions() if (chooseTarget()) return 1; int currentGamePhase = g->getCurrentGamePhase(); - if (g->isInterrupting == this) - { // interrupting - selectAbility(); - return 1; + static bool findingCard = false; + //this guard is put in place to prevent Ai from + //ever running computeActions() function WHILE its already doing so. + // Break if this happens in debug mode. If this happens, it's actually a bug + assert(!findingCard); + if (findingCard) + {//is already looking kick me out of this function! + return 0; + } + if (p != this && (Player*)g->isInterrupting == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 1) + { + findingCard = true; + CardDescriptor cd; + ManaCost * currentMana = getPotentialMana(); + bool potential = false; + if (currentMana->getConvertedCost()) + { + //if theres mana i can use there then potential is true. + potential = true; + } + //look for an instant of ability to interupt with + if((castrestrictedspell == false && nospellinstant == false)&& + (onlyonecast == false || castcount < 2) && (onlyoneinstant == false || castcount < 2)) + { + + if (!nextCardToPlay) + { + nextCardToPlay = FindCardToPlay(currentMana, "instant"); + } + if (!nextCardToPlay) + { + selectAbility(); + } + } + if (currentMana != NULL) + delete (currentMana); + if (nextCardToPlay) + { + if (potential) + { + tapLandsForMana(nextCardToPlay->getManaCost()); + } + AIAction * a = NEW AIAction(nextCardToPlay); + clickstream.push(a); + findingCard = false; + nextCardToPlay = NULL; + return 1; + } + nextCardToPlay = NULL; + findingCard = false; + return 0; } - else if (p == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0) + else if(p == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0) { //standard actions CardDescriptor cd; - switch (currentGamePhase) { case Constants::MTG_PHASE_FIRSTMAIN: case Constants::MTG_PHASE_SECONDMAIN: - { - - bool potential = false; - ManaCost * currentMana = getPotentialMana(); - if (currentMana->getConvertedCost()) { - //if theres mana i can use there then potential is true. - potential = true; - } - nextCardToPlay = FindCardToPlay(currentMana, "land"); - selectAbility(); - //look for the most expensive creature we can afford - if (castrestrictedspell == false && nospellinstant == false) - { - if (onlyonecast == false || castcount < 2) + ManaCost * currentMana = getPotentialMana(); + bool potential = false; + if (currentMana->getConvertedCost()) { - if (onlyoneinstant == false || castcount < 2) + //if theres mana i can use there then potential is true. + potential = true; + } + nextCardToPlay = FindCardToPlay(currentMana, "land"); + selectAbility(); + //look for the most expensive creature we can afford + if((castrestrictedspell == false && nospellinstant == false)&& + (onlyonecast == false || castcount < 2)&&(onlyoneinstant == false || castcount < 2)) + { + if (castrestrictedcreature == false && nocreatureinstant == false) { - if (castrestrictedcreature == false && nocreatureinstant == false) - { - if (!nextCardToPlay) - { - nextCardToPlay = FindCardToPlay(currentMana, "creature"); - } - } - //Let's Try an enchantment maybe ? if (!nextCardToPlay) { - nextCardToPlay = FindCardToPlay(currentMana, "enchantment"); - } - if (!nextCardToPlay) - { - nextCardToPlay = FindCardToPlay(currentMana, "artifact"); - } - if (!nextCardToPlay) - { - nextCardToPlay = FindCardToPlay(currentMana, "sorcery"); - } - if (!nextCardToPlay) - { - nextCardToPlay = FindCardToPlay(currentMana, "instant"); - } - if (!nextCardToPlay) - { - selectAbility(); + nextCardToPlay = FindCardToPlay(currentMana, "creature"); } } - } - - } - if (currentMana != NULL) - delete (currentMana); - if (nextCardToPlay) - { - if (potential) - { - ///////////////////////// - //had to force this on Ai other wise it would pay nothing but 1 color for a sunburst card. - //this does not teach it to use manaproducer more effectively, it simply allow it to use the manaproducers it does understand better on sunburst by force. - if (nextCardToPlay->has(Constants::SUNBURST)) + //Let's Try an enchantment maybe ? + if (!nextCardToPlay) { - ManaCost * SunCheck = manaPool; - SunCheck = getPotentialMana(); - for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) + nextCardToPlay = FindCardToPlay(currentMana, "enchantment"); + } + if (!nextCardToPlay) + { + nextCardToPlay = FindCardToPlay(currentMana, "artifact"); + } + if (!nextCardToPlay) + { + nextCardToPlay = FindCardToPlay(currentMana, "sorcery"); + } + if (!nextCardToPlay) + { + nextCardToPlay = FindCardToPlay(currentMana, "instant"); + } + if (!nextCardToPlay) + { + selectAbility(); + } + } + if (currentMana != NULL) + delete (currentMana); + if (nextCardToPlay) + { + if (potential) + { + ///////////////////////// + //had to force this on Ai other wise it would pay nothing but 1 color for a sunburst card. + //this does not teach it to use manaproducer more effectively, it simply allow it to use the manaproducers it does understand better on sunburst by force. + if (nextCardToPlay->has(Constants::SUNBURST)) { - //sunburst for Ai - if (SunCheck->hasColor(i)) + ManaCost * SunCheck = manaPool; + SunCheck = getPotentialMana(); + for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) { - if (nextCardToPlay->getManaCost()->hasColor(i) > 0) - {//do nothing if the card already has this color. - } - else + //sunburst for Ai + if (SunCheck->hasColor(i)) { - if (nextCardToPlay->sunburst < nextCardToPlay->getManaCost()->getConvertedCost()) + if (nextCardToPlay->getManaCost()->hasColor(i) > 0) + {//do nothing if the card already has this color. + } + else { - nextCardToPlay->getManaCost()->add(i, 1); - nextCardToPlay->getManaCost()->remove(0, 1); - nextCardToPlay->sunburst += 1; + if (nextCardToPlay->sunburst < nextCardToPlay->getManaCost()->getConvertedCost()) + { + nextCardToPlay->getManaCost()->add(i, 1); + nextCardToPlay->getManaCost()->remove(0, 1); + nextCardToPlay->sunburst += 1; + } } } } + delete (SunCheck); } - delete (SunCheck); + ///////////////////////// + tapLandsForMana(nextCardToPlay->getManaCost()); } - ///////////////////////// - tapLandsForMana(nextCardToPlay->getManaCost()); + AIAction * a = NEW AIAction(nextCardToPlay); + clickstream.push(a); + return 1; } - AIAction * a = NEW AIAction(nextCardToPlay); - clickstream.push(a); - return 1; + else + { + selectAbility(); + } + if (p->getManaPool()->getConvertedCost() > 0 && Checked == false)//not the best thing ever, but allows the Ai a chance to double check if its mana pool has something before moving on, atleast one time. + { + Checked = true; + computeActions(); + } + break; } - else - { - selectAbility(); - } - if (p->getManaPool()->getConvertedCost() > 0 && Checked == false)//not the best thing ever, but allows the Ai a chance to double check if its mana pool has something before moving on, atleast one time. - { - Checked = true; - computeActions(); - } - break; - } case Constants::MTG_PHASE_COMBATATTACKERS: chooseAttackers(); break; diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 8c825ed56..0ae784f28 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -214,7 +214,8 @@ Interruptible(id), tc(tc), cost(_cost), payResult(payResult) int Spell::computeX(MTGCardInstance * card) { ManaCost * c = cost->Diff(card->getManaCost()); - int x = c->getCost(Constants::MTG_NB_COLORS); + int x = 0; + x = c->getCost(Constants::MTG_NB_COLORS); delete c; return x; } @@ -222,7 +223,8 @@ int Spell::computeX(MTGCardInstance * card) int Spell::computeXX(MTGCardInstance * card) { ManaCost * c = cost->Diff(card->getManaCost()); - int xx = c->getCost(Constants::MTG_NB_COLORS) / 2; + int xx = 0; + xx = c->getCost(Constants::MTG_NB_COLORS) / 2; delete c; return xx; } @@ -451,7 +453,39 @@ ostream& DrawAction::toString(ostream& out) const out << "DrawAction ::: nbcards : " << nbcards << " ; player : " << player; return out; } +////// +LifeAction::LifeAction(int id, Damageable * _target, int amount) : +Interruptible(id), amount(amount),target(_target) +{ +} +int LifeAction::resolve() +{ +target->life += amount; + return 1; +} + +void LifeAction::Render() +{ + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetBase(0); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + char buffer[200]; + if(amount >= 0) + sprintf(buffer, _("Player gains %i life").c_str(), amount); + else if(amount >= 0) + sprintf(buffer, _("Player loses %i life").c_str(), amount); + else + sprintf(buffer, _("Nothing happened").c_str(), amount); + mFont->DrawString(buffer, x + 20, y, JGETEXT_LEFT); +} + +ostream& LifeAction::toString(ostream& out) const +{ + out << "LifeAction ::: amount : " << amount << " ; target : " << target; + return out; +} +/* The Action Stack itself */ int ActionStack::addPutInGraveyard(MTGCardInstance * card) { PutInGraveyard * death = NEW PutInGraveyard(mCount, card); @@ -482,10 +516,20 @@ int ActionStack::addDraw(Player * player, int nb_cards) return 1; } +int ActionStack::addLife(Damageable * _target, int amount) +{ + LifeAction * life = NEW LifeAction(mCount, _target, amount); + addAction(life); + return 1; +} + int ActionStack::addDamage(MTGCardInstance * _source, Damageable * _target, int _damage) { Damage * damage = NEW Damage(_source, _target, _damage); addAction(damage); + _source->thatmuch = _damage; + _target->thatmuch = _damage; + _target->lifeLostThisTurn += _damage; return 1; } diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 22a1e33b5..efa5f20ba 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -34,6 +34,8 @@ const char * GenericActivatedAbility::getMenuText() int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { + if (dynamic_cast (ability) && !card->isMorphed && !card->morphed && card->turningOver) + return 0; if (limitPerTurn && counters >= limitPerTurn) return 0; return ActivatedAbility::isReactingToClick(card, mana); @@ -140,29 +142,31 @@ AADamagePrevent::~AADamagePrevent() } //AADamager -AADamager::AADamager(int _id, MTGCardInstance * _source, Targetable * _target, WParsedInt * damage, ManaCost * _cost, int doTap, +AADamager::AADamager(int _id, MTGCardInstance * _source, Targetable * _target,WParsedInt * damage, string d, ManaCost * _cost, int doTap, int who) : - ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who), damage(damage) + ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who),damage(damage), d(d) { aType = MTGAbility::DAMAGER; -} - -int AADamager::resolve() -{ - Damageable * _target = (Damageable *) getTarget(); - if (_target) - { - game->mLayers->stackLayer()->addDamage(source, _target, damage->getValue()); - game->mLayers->stackLayer()->resolve(); - return 1; } - return 0; -} -const char * AADamager::getMenuText() -{ - return "Damage"; -} + int AADamager::resolve() + { + RefreshedDamage = NEW WParsedInt(d, NULL, (MTGCardInstance *)source); + Damageable * _target = (Damageable *) getTarget(); + if (_target) + { + game->mLayers->stackLayer()->addDamage(source, _target, RefreshedDamage->getValue()); + game->mLayers->stackLayer()->resolve(); + delete RefreshedDamage; + return 1; + } + return 0; + } + + const char * AADamager::getMenuText() + { + return "Damage"; + } AADamager * AADamager::clone() const { @@ -174,37 +178,41 @@ AADamager * AADamager::clone() const AADamager::~AADamager() { - SAFE_DELETE(damage); +SAFE_DELETE(damage); } //AADepleter -AADepleter::AADepleter(int _id, MTGCardInstance * card, Targetable * _target, int nbcards, ManaCost * _cost, int _tap, int who) : - ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards) +AADepleter::AADepleter(int _id, MTGCardInstance * card, Targetable * _target,WParsedInt * nbcards,string nbcardsStr, ManaCost * _cost, int _tap, int who) : + ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards),nbcardsStr(nbcardsStr) { +RefreshedNbcards = NULL; } -int AADepleter::resolve() -{ - Targetable * _target = getTarget(); - Player * player; - if (_target) + int AADepleter::resolve() { - if (_target->typeAsTarget() == TARGET_CARD) + + RefreshedNbcards = NEW WParsedInt(nbcardsStr, NULL, source); + Targetable * _target = getTarget(); + Player * player; + if (_target) { - player = ((MTGCardInstance *) _target)->controller(); - } - else - { - player = (Player *) _target; - } - MTGLibrary * library = player->game->library; - for (int i = 0; i < nbcards; i++) - { - if (library->nb_cards) - player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); + if (_target->typeAsTarget() == TARGET_CARD) + { + player = ((MTGCardInstance *) _target)->controller(); + } + else + { + player = (Player *) _target; + } + MTGLibrary * library = player->game->library; + for (int i = 0; i < RefreshedNbcards->getValue(); i++) + { + if (library->nb_cards) + player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); + } } + delete RefreshedNbcards; + return 1; } - return 1; -} const char * AADepleter::getMenuText() { @@ -217,7 +225,11 @@ AADepleter * AADepleter::clone() const a->isClone = 1; return a; } - +AADepleter::~AADepleter() +{ +if(!isClone) +SAFE_DELETE(nbcards); +} //AACopier AACopier::AACopier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) : ActivatedAbility(_id, _source, _cost, 0, 0) @@ -248,10 +260,40 @@ AACopier * AACopier::clone() const return a; } +//phaser +AAPhaseOut::AAPhaseOut(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) : + ActivatedAbility(_id, _source, _cost, 0, 0) +{ + target = _target; +} + +int AAPhaseOut::resolve() +{GameObserver * g = g->GetInstance(); + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + _target->isTempPhased = true; + return 1; + } + return 0; +} + +const char * AAPhaseOut::getMenuText() +{ + return "Phase Out"; +} + +AAPhaseOut * AAPhaseOut::clone() const +{ + AAPhaseOut * a = NEW AAPhaseOut(*this); + a->isClone = 1; + return a; +} + //Counters -AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, +AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target,string counterstring, const char * _name, int power, int toughness, int nb, ManaCost * cost, int doTap) : - ActivatedAbility(id, source, cost, 0, doTap), nb(nb), power(power), toughness(toughness), name(_name) + ActivatedAbility(id, source, cost, 0, doTap),counterstring(counterstring), nb(nb), power(power), toughness(toughness), name(_name) { this->target = target; if (name.find("Level")) @@ -259,13 +301,17 @@ AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, menu = ""; } -int AACounter::resolve() -{ - if (target) + int AACounter::resolve() { - MTGCardInstance * _target = (MTGCardInstance *) target; - if (nb > 0) + if (target) { + MTGCardInstance * _target = (MTGCardInstance *) target; + AbilityFactory af; + Counter * checkcounter = af.parseCounter(counterstring, _target, NULL); + nb = checkcounter->nb; + delete checkcounter; + if (nb > 0) + { for (int i = 0; i < nb; i++) { while (_target->next) @@ -282,6 +328,8 @@ int AACounter::resolve() _target->counters->removeCounter(name.c_str(), power, toughness); } } + if(_target->toughness <= 0 && _target->has(Constants::INDESTRUCTIBLE) && toughness < 0) + _target->controller()->game->putInGraveyard(_target); return nb; } return 0; @@ -308,7 +356,7 @@ const char* AACounter::getMenuText() } menu.append(" Counter"); - if (nb != 1) + if (nb != 1 && !(nb < -1000)) { sprintf(buffer, ": %i", nb); menu.append(buffer); @@ -325,9 +373,91 @@ AACounter * AACounter::clone() const return a; } +//Counters +AARemoveAllCounter::AARemoveAllCounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, + int nb,bool all, ManaCost * cost, int doTap) : + ActivatedAbility(id, source, cost, 0, doTap), nb(nb), power(power), toughness(toughness), name(_name),all(all) +{ + this->target = target; + menu = ""; +} + + int AARemoveAllCounter::resolve() + { + if (target) + { + MTGCardInstance * _target = (MTGCardInstance *) target; + if (all == true) + { + for(int amount = 0;amount < _target->counters->mCount;amount++) + { + while(_target->counters->counters[amount]->nb > 0) + _target->counters->removeCounter(_target->counters->counters[amount]->name.c_str(),_target->counters->counters[amount]->power,_target->counters->counters[amount]->toughness); + + } + } + Counter * targetCounter = NULL; + if (_target->counters && _target->counters->hasCounter(name.c_str(), power, toughness)) + { + targetCounter = _target->counters->hasCounter(name.c_str(), power, toughness); + nb = targetCounter->nb; + } + + if (nb > 0) + { + for (int i = 0; i < nb; i++) + { + while (_target->next) + _target = _target->next; + _target->counters->removeCounter(name.c_str(), power, toughness); + } + } + return nb; + } + return 0; +} + +const char* AARemoveAllCounter::getMenuText() +{ + if (menu.size()) + { + return menu.c_str(); + } + char buffer[128]; + + if (name.size()) + { + string s = name; + menu.append(s.c_str()); + } + + if (power != 0 || toughness != 0) + { + sprintf(buffer, " %i/%i", power, toughness); + menu.append(buffer); + } + + menu.append(" Counter Removed"); + if (nb != 1) + { + sprintf(buffer, ": %i", nb); + menu.append(buffer); + } + + sprintf(menuText, "%s", menu.c_str()); + return menuText; +} + +AARemoveAllCounter * AARemoveAllCounter::clone() const +{ + AARemoveAllCounter * a = NEW AARemoveAllCounter(*this); + a->isClone = 1; + return a; +} + // Fizzler AAFizzler::AAFizzler(int _id, MTGCardInstance * card, Spell * _target, ManaCost * _cost, int _tap) : - ActivatedAbility(_id, card, _cost, 0, _tap) +ActivatedAbility(_id, card, _cost, 0, _tap) { target = _target; } @@ -335,6 +465,19 @@ AAFizzler::AAFizzler(int _id, MTGCardInstance * card, Spell * _target, ManaCost int AAFizzler::resolve() { Spell * _target = (Spell *) target; + if(!target && !_target) + { + //if we hit this condiational its because Ai was targetting. + target = source->target; + Interruptible * laststackitem = game->mLayers->stackLayer()->getAt(-2); + //fizzle the spell that was played directly before this counterspell + //ai will tend to respond to you extremely quick. + if (laststackitem && laststackitem->type == ACTION_SPELL) + { + Spell * spell = (Spell*) laststackitem; + _target = spell; + } + } if (target && _target->source->has(Constants::NOFIZZLE)) return 0; game->mLayers->stackLayer()->Fizzle(_target); @@ -504,33 +647,35 @@ AADiscardCard * AADiscardCard::clone() const return a; } -AADrawer::AADrawer(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, WParsedInt * _nbcards, int _tap, +AADrawer::AADrawer(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost,WParsedInt * nbcards, string nbcardsStr, int _tap, int who) : - ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(_nbcards) + ActivatedAbilityTP(_id, card, _target, _cost, _tap, who),nbcards(nbcards), nbcardsStr(nbcardsStr) { aType = MTGAbility::STANDARD_DRAW; nbcardAmount = nbcards->getValue(); } -int AADrawer::resolve() -{ - Targetable * _target = getTarget(); - Player * player; - if (_target) + int AADrawer::resolve() { - if (_target->typeAsTarget() == TARGET_CARD) + RefreshedNbcards = NEW WParsedInt(nbcardsStr, NULL, source); + Targetable * _target = getTarget(); + Player * player; + if (_target) { - player = ((MTGCardInstance *) _target)->controller(); + if (_target->typeAsTarget() == TARGET_CARD) + { + player = ((MTGCardInstance *) _target)->controller(); + } + else + { + player = (Player *) _target; + } + game->mLayers->stackLayer()->addDraw(player, RefreshedNbcards->getValue()); + game->mLayers->stackLayer()->resolve(); } - else - { - player = (Player *) _target; - } - game->mLayers->stackLayer()->addDraw(player, nbcards->getValue()); - game->mLayers->stackLayer()->resolve(); + delete RefreshedNbcards; + return 1; } - return 1; -} const char * AADrawer::getMenuText() { @@ -547,12 +692,13 @@ AADrawer * AADrawer::clone() const AADrawer::~AADrawer() { - SAFE_DELETE(nbcards); + if(!isClone) + SAFE_DELETE(nbcards); } // AAFrozen: Prevent a card from untapping during next untap phase AAFrozen::AAFrozen(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) : - ActivatedAbility(id, card, _cost, 0, doTap) +ActivatedAbility(id, card, _cost, 0, doTap) { target = _target; } @@ -581,15 +727,625 @@ AAFrozen * AAFrozen::clone() const return a; } +// chose a new target for an aura or enchantment and equip it note: VERY basic right now. +AANewTarget::AANewTarget(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) : +ActivatedAbility(id, card, _cost, 0, doTap) +{ + target = _target; +} + +int AANewTarget::resolve() +{ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + while (_target->next) + _target = _target->next; //This is for cards such as rampant growth + + _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->exile); + _target = _target->next; + + MTGCardInstance * refreshed = source->controller()->game->putInZone(_target,_target->currentZone,source->controller()->game->battlefield); + Spell * reUp = NEW Spell(refreshed); + reUp->source->target = source; + reUp->resolve(); + delete reUp; + } + return 1; +} + +const char * AANewTarget::getMenuText() +{ + return "New Target"; +} + +AANewTarget * AANewTarget::clone() const +{ + AANewTarget * a = NEW AANewTarget(*this); + a->isClone = 1; + return a; +} +// morph a card +AAMorph::AAMorph(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) : +ActivatedAbility(id, card, _cost, restrictions, doTap) +{ + target = _target; +} + +int AAMorph::resolve() +{ + MTGCardInstance * Morpher = (MTGCardInstance*)source; + if(!Morpher->isMorphed && !Morpher->morphed && Morpher->turningOver) + return 0; + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + while (_target->next) + _target = _target->next; + + AbilityFactory af; + _target->morphed = false; + _target->isMorphed = false; + _target->turningOver = true; + af.getAbilities(¤tAbilities, NULL, _target,NULL); + for (size_t i = 0; i < currentAbilities.size(); ++i) + { + MTGAbility * a = currentAbilities[i]; + a->source = (MTGCardInstance *) _target; + if( a && dynamic_cast (a)) + { + a->removeFromGame(); + GameObserver * g = g->GetInstance(); + g->removeObserver(a); + } + if (a) + { + if (a->oneShot) + { + a->resolve(); + delete (a); + } + else + { + a->addToGame(); + } + } + } + currentAbilities.clear(); + testDestroy(); + } + return 1; +} + +int AAMorph::testDestroy() +{ + MTGCardInstance * _target = (MTGCardInstance *) target; + if(target) + { + if(_target->turningOver && !_target->isMorphed && !_target->morphed) + { + GameObserver * g = g->GetInstance(); + g->removeObserver(this); + return 1; + } + } + return 0; +} + +const char * AAMorph::getMenuText() +{ + return "Morph"; +} + +AAMorph * AAMorph::clone() const +{ + AAMorph * a = NEW AAMorph(*this); + a->isClone = 1; + a->forceDestroy = 1; + return a; +} +// AADYNAMIC: dynamic ability builder +AADYNAMIC::AADYNAMIC(int id, MTGCardInstance * card, Damageable * _target,int type,int effect,int who,int amountsource,MTGAbility * storedAbility, ManaCost * _cost, int doTap) : +ActivatedAbility(id, card, _cost, 0, doTap),type(type),effect(effect),who(who),amountsource(amountsource),eachother(eachother),storedAbility(storedAbility) +{ + target = _target; + sourceamount = 0; + targetamount = 0; + eachother = false; + tosrc = false; + menu = ""; + OriginalSrc = source; + storedAbility = storedAbility; + clonedStored = NULL; +} + +int AADYNAMIC::resolve() +{ + Damageable * _target = (Damageable *) target; + Damageable * secondaryTarget = NULL; + if(amountsource == 2) + source = (MTGCardInstance * )_target; + switch(who) + { + case 1://each other, both take the effect + eachother = true; + break; + case 2: + source = ((MTGCardInstance *) _target); + _target = _target; + break; + case 3: + _target = _target; + secondaryTarget = ((MTGCardInstance *) _target)->controller(); + break; + case 4: + _target = _target; + secondaryTarget = ((MTGCardInstance *) _target)->controller()->opponent(); + break; + case 5: + tosrc = true; + break; + case 6: + _target = _target; + secondaryTarget = ((MTGCardInstance *) OriginalSrc)->controller(); + break; + case 7: + secondaryTarget = OriginalSrc->controller()->opponent(); + break; + default: + _target = _target; + break; + } + if(amountsource == 3) + _target = OriginalSrc->controller();//looking at controller for amount + if(amountsource == 4) + _target = OriginalSrc->controller()->opponent();//looking at controllers opponent for amount + if(!_target) + return 0; + while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next) + _target = ((MTGCardInstance *)_target)->next; + + //find the amount variables that will be used + sourceamount = 0; + targetamount = 0; + int colored = 0; + switch(type) + { + case 0: + sourceamount = ((MTGCardInstance *) source)->power; + targetamount = ((MTGCardInstance *) _target)->power; + if(eachother == true) + sourceamount = ((MTGCardInstance *) source)->power; + break; + case 1: + sourceamount = ((MTGCardInstance *) source)->toughness; + targetamount = ((MTGCardInstance *) _target)->toughness; + if(eachother == true) + sourceamount = ((MTGCardInstance *) source)->toughness; + break; + case 2: + if(amountsource == 1) + sourceamount = ((MTGCardInstance *) source)->getManaCost()->getConvertedCost(); + else + sourceamount = ((MTGCardInstance *) _target)->getManaCost()->getConvertedCost(); + break; + case 3: + for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i) + { + if (amountsource == 1 && ((MTGCardInstance *)source)->hasColor(i)) + ++colored; + else + if (amountsource == 2 && ((MTGCardInstance *)_target)->hasColor(i)) + ++colored; + } + sourceamount = colored; + break; + case 4: + { + Counter * targetCounter = NULL; + if(amountsource == 2) + { + if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter("age", 0, 0)) + { + targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter("age", 0, 0); + sourceamount = targetCounter->nb; + } + } + else + { + if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter("age", 0, 0)) + { + targetCounter = ((MTGCardInstance *)source)->counters->hasCounter("age", 0, 0); + sourceamount = targetCounter->nb; + } + } + break; + } + case 5: + { + Counter * targetCounter = NULL; + if(amountsource == 2) + { + if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter("charge", 0, 0)) + { + targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter("charge", 0, 0); + sourceamount = targetCounter->nb; + } + } + else + { + if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter("charge", 0, 0)) + { + targetCounter = ((MTGCardInstance *)source)->counters->hasCounter("charge", 0, 0); + sourceamount = targetCounter->nb; + } + } + break; + } + case 6: + { + Counter * targetCounter = NULL; + if(amountsource == 2) + { + if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter(1, 1)) + { + targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter(1,1); + sourceamount = targetCounter->nb; + } + } + else + { + if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter(1, 1)) + { + targetCounter = ((MTGCardInstance *)source)->counters->hasCounter(1,1); + sourceamount = targetCounter->nb; + } + } + break; + } + case 7: + { + sourceamount = _target->thatmuch; + break; + } + default: + break; + } + + if(secondaryTarget != NULL) + { + _target = secondaryTarget; + } + if (_target) + { + while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next) + _target = ((MTGCardInstance *)_target)->next; + + switch(effect) + { + case 0://deal damage + if(storedAbility) + activateStored(); + if(tosrc == false) + game->mLayers->stackLayer()->addDamage((MTGCardInstance *)source, _target, sourceamount); + else + game->mLayers->stackLayer()->addDamage((MTGCardInstance *)source, OriginalSrc, sourceamount); + if(eachother == true) + { + game->mLayers->stackLayer()->addDamage((MTGCardInstance *)_target, source, targetamount); + } + return 1; + break; + case 1://draw cards + if(storedAbility) + activateStored(); + game->mLayers->stackLayer()->addDraw((Player *)_target,sourceamount); + return 1; + break; + case 2://gain life + if(storedAbility) + activateStored(); + game->mLayers->stackLayer()->addLife(_target,sourceamount); + return 1; + break; + case 3://pump power + { + if(storedAbility) + activateStored(); + if(tosrc == false) + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, (MTGCardInstance*)_target,NEW WParsedPT(sourceamount,0)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,(MTGCardInstance*)_target, a); + wrapper->addToGame(); + return 1; + } + else + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, OriginalSrc,NEW WParsedPT(sourceamount,0)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,OriginalSrc, a); + wrapper->addToGame(); + return 1; + } + break; + } + case 4://pump toughness + { + if(storedAbility) + activateStored(); + if(tosrc == false) + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, (MTGCardInstance*)_target,NEW WParsedPT(0,sourceamount)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,(MTGCardInstance*)_target, a); + wrapper->addToGame(); + return 1; + } + else + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, OriginalSrc,NEW WParsedPT(0,sourceamount)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,OriginalSrc, a); + wrapper->addToGame(); + return 1; + } + break; + } + case 5://pump both + { + if(storedAbility) + activateStored(); + if(tosrc == false) + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, (MTGCardInstance*)_target,NEW WParsedPT(sourceamount,sourceamount)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,(MTGCardInstance*)_target, a); + wrapper->addToGame(); + return 1; + } + else + { + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(this->GetId(), source, OriginalSrc,NEW WParsedPT(sourceamount,sourceamount)); + GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source,OriginalSrc, a); + wrapper->addToGame(); + return 1; + } + break; + } + case 6://lose life + if(storedAbility) + activateStored(); + game->mLayers->stackLayer()->addLife(_target,(sourceamount * -1)); + return 1; + break; + case 7://deplete cards + { + if(storedAbility) + activateStored(); + Player * player = (Player *)_target; + MTGLibrary * library = player->game->library; + for (int i = 0; i < sourceamount; i++) + { + if (library->nb_cards) + player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); + } + return 1; + break; + } + case 8: + { + if(_target->typeAsTarget() != TARGET_CARD) + _target = OriginalSrc; + for(int j = 0;j < sourceamount;j++) + ((MTGCardInstance*)_target)->counters->addCounter(1,1); + break; + } + default: + return 0; + } + } + + return 0; +} + +int AADYNAMIC::activateStored() +{ + clonedStored = storedAbility->clone(); + clonedStored->target = target; + if (clonedStored->oneShot) + { + clonedStored->resolve(); + delete (clonedStored); + } + else + { + clonedStored->addToGame(); + } + return 1; +} + +const char * AADYNAMIC::getMenuText() +{ + if (menu.size()) + { + return menu.c_str(); + } + + switch(type) + { + case 0: + menu.append("Power"); + break; + case 1: + menu.append("Tough"); + break; + case 2: + menu.append("Mana"); + break; + case 3: + menu.append("color"); + break; + case 4: + menu.append("Elder"); + break; + case 5: + menu.append("Charged"); + break; + case 6: + menu.append("Counter"); + break; + case 7: + menu.append("That Many "); + break; + default: + break; + } + + switch(effect) + { + case 0: + menu.append("Strike"); + break; + case 1: + menu.append("Draw"); + break; + case 2: + menu.append("Life"); + break; + case 3: + menu.append("Pump"); + break; + case 4: + menu.append("Fortify"); + break; + case 5: + menu.append("Buff"); + break; + case 6: + menu.append("Drain"); + break; + case 7: + menu.append("Deplete!"); + break; + case 8: + menu.append("Counters!"); + break; + default: + break; + } + sprintf(menuText, "%s", menu.c_str()); + return menuText; +} + +AADYNAMIC * AADYNAMIC::clone() const +{ + AADYNAMIC * a = NEW AADYNAMIC(*this); + a->isClone = 1; + return a; +} + +AADYNAMIC::~AADYNAMIC() +{ + if (!isClone) + SAFE_DELETE(storedAbility); +} + +// Eradicate +AAEradicate::AAEradicate(int id, MTGCardInstance * card, MTGCardInstance * _target,int type, ManaCost * _cost, int doTap) : + ActivatedAbility(id, card, _cost, 0, doTap),type(type) +{ + target = _target; +} + +int AAEradicate::resolve() +{ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + while (_target->next) + _target = _target->next; //This is for cards such as rampant growth + + string name= _target->name; + int cardtotal = _target->controller()->game->battlefield->nb_cards + + _target->controller()->game->hand->nb_cards + +_target->controller()->game->graveyard->nb_cards + +_target->controller()->game->library->nb_cards; + + Player * victem = _target->controller(); + victem->game->putInExile(_target); + + MTGGameZone * g = victem->game->graveyard; + MTGGameZone * l = victem->game->library; + MTGGameZone * h = victem->game->hand; + MTGGameZone * i = victem->game->inPlay; + + while(_target->controller()->inPlay()->hasName(name) || _target->controller()->game->graveyard->hasName(name)|| _target->controller()->game->library->hasName(name)|| _target->controller()->game->hand->hasName(name)) + { + for (int k = 0; k < g->nb_cards; k++) + { + MTGCardInstance * card = g->cards[k]; + if(card->name == name) + victem->game->putInZone(card,g,card->controller()->game->exile); + if(k > g->nb_cards) + { + k = 0; + } + } + for (int t = 0; t < l->nb_cards; t++) + { + MTGCardInstance * card = l->cards[t]; + if(card->name == name) + victem->game->putInZone(card,l,card->controller()->game->exile); + if(t > l->nb_cards) + { + t = 0; + } + } + for (int w = 0; w < h->nb_cards; w++) + { + MTGCardInstance * card = h->cards[w]; + if(card->name == name) + victem->game->putInZone(card,h,card->controller()->game->exile); + if(w > h->nb_cards) + { + w = 0; + } + } + for (int o = 0; o < i->nb_cards; o++) + { + MTGCardInstance * card = i->cards[o]; + if(card->name == name) + victem->game->putInZone(card,i,card->controller()->game->exile); + if(o > i->nb_cards) + { + o = 0; + } + } + } + + } + return 1; +} + +const char * AAEradicate::getMenuText() +{ + return "eradicate"; +} + +AAEradicate * AAEradicate::clone() const +{ + AAEradicate * a = NEW AAEradicate(*this); + a->isClone = 1; + return a; +} + //AALifer -AALifer::AALifer(int _id, MTGCardInstance * card, Targetable * _target, WParsedInt * life, ManaCost * _cost, int _tap, int who) : - ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), life(life) +AALifer::AALifer(int _id, MTGCardInstance * card, Targetable * _target, string life_s, WParsedInt * life, ManaCost * _cost, int _tap, int who) : +ActivatedAbilityTP(_id, card, _target, _cost, _tap, who),life_s(life_s), life(life) { aType = MTGAbility::LIFER; } int AALifer::resolve() { + RefreshedLife = NEW WParsedInt(life_s, NULL, source); Damageable * _target = (Damageable *) getTarget(); if (_target) { @@ -597,13 +1353,24 @@ int AALifer::resolve() { _target = ((MTGCardInstance *) _target)->controller(); } - _target->life += life->getValue(); + Player *player = (Player*)_target; + player->thatmuch = abs(RefreshedLife->getValue()); + WEvent * lifed = NULL; + lifed = NEW WEventLife(player,RefreshedLife->getValue()); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); + _target->life += RefreshedLife->getValue(); + if(life->getValue() < 0) + _target->lifeLostThisTurn += abs(RefreshedLife->getValue()); } + delete RefreshedLife; return 1; } const char * AALifer::getMenuText() { +if(life->getValue() < 0) +return "Life Loss"; return "Life"; } @@ -617,6 +1384,7 @@ AALifer * AALifer::clone() const AALifer::~AALifer() { +if(life) SAFE_DELETE(life); } @@ -636,6 +1404,22 @@ int AALifeSet::resolve() { _target = ((MTGCardInstance *) _target)->controller(); } + + int lifeDiff = life->getValue() - _target->life ; + WEvent * lifed = NULL; + if(lifeDiff < 0) + { + _target->thatmuch = abs(lifeDiff); + _target->lifeLostThisTurn += abs(lifeDiff); + lifed = NEW WEventLife((Player*)_target,lifeDiff,1); + } + else + { + _target->thatmuch = abs(lifeDiff); + lifed = NEW WEventLife((Player*)_target,lifeDiff,0); + } + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); _target->life = life->getValue(); } return 0; @@ -676,28 +1460,37 @@ AACloner::AACloner(int _id, MTGCardInstance * _source, MTGCardInstance * _target } -int AACloner::resolve() -{ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (_target) + int AACloner::resolve() { - MTGCardInstance * myClone = NULL; - MTGCard* clone = (_target->isToken ? _target : GameApp::collection->getCardById(_target->getId())); - - if (who != 1) - myClone = NEW MTGCardInstance(clone, source->controller()->game); - if (who == 1) - myClone = NEW MTGCardInstance(clone, source->controller()->opponent()->game); - if (who != 1) - source->controller()->game->temp->addCard(myClone); - else - source->controller()->opponent()->game->temp->addCard(myClone); - Spell * spell = NEW Spell(myClone); - spell->resolve(); - spell->source->isToken = 1; - spell->source->fresh = 1; - list::iterator it; - for (it = awith.begin(); it != awith.end(); it++) + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + MTGCardInstance * myClone = NULL; + MTGCard* clone = (_target->isToken ? _target: GameApp::collection->getCardByName(_target->name)); + if (who != 1) + { + myClone = NEW MTGCardInstance(clone, source->controller()->game); + } + if (who == 1) + { + myClone = NEW MTGCardInstance(clone, source->controller()->opponent()->game); + } + if (who != 1) + source->controller()->game->temp->addCard(myClone); + else + source->controller()->opponent()->game->temp->addCard(myClone); + Spell * spell = NEW Spell(myClone); + spell->resolve(); + spell->source->isToken = 1; + spell->source->fresh = 1; + if(_target->isToken) + { + spell->source->power = _target->origpower; + spell->source->toughness = _target->origtoughness; + spell->source->life = _target->origtoughness; + } + list::iterator it; + for (it = awith.begin(); it != awith.end(); it++) { spell->source->basicAbilities[*it] = 1; } @@ -948,9 +1741,9 @@ AAOnlyOne * AAOnlyOne::clone() const } //Random Discard -AARandomDiscarder::AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target, int nbcards, ManaCost * _cost, +AARandomDiscarder::AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target,WParsedInt * nbcards,string nbcardsStr, ManaCost * _cost, int _tap, int who) : - ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards) + ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards),nbcardsStr(nbcardsStr) { } @@ -968,11 +1761,15 @@ int AARandomDiscarder::resolve() { player = (Player *) _target; } - for (int i = 0; i < nbcards; i++) + + + RefreshedNbcards = NEW WParsedInt(nbcardsStr, NULL, source); + for (int i = 0; i < RefreshedNbcards->intValue; i++) { player->game->discardRandom(player->game->hand, source); } } + delete RefreshedNbcards; return 1; } @@ -987,6 +1784,10 @@ AARandomDiscarder * AARandomDiscarder::clone() const a->isClone = 1; return a; } +AARandomDiscarder ::~AARandomDiscarder () +{ +SAFE_DELETE(nbcards); +} // Shuffle AAShuffle::AAShuffle(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) : @@ -1101,6 +1902,7 @@ int AAWhatsMax::resolve() if (source) { source->MaxLevelUp = value; + source->isLeveler = 1; } return 1; } @@ -1255,16 +2057,28 @@ int MultiAbility::Add(MTGAbility * ability) int MultiAbility::resolve() { + Targetable * Phaseactiontarget = NULL; vector::size_type sz = abilities.size(); for (unsigned int i = 0; i < sz; i++) { if (abilities[i] == NULL) continue; Targetable * backup = abilities[i]->target; + + if (target && target != source && abilities[i]->target == abilities[i]->source) + { abilities[i]->target = target; + Phaseactiontarget = target; + } abilities[i]->resolve(); abilities[i]->target = backup; + if(dynamic_cast (abilities[i])) + { + if(Phaseactiontarget != NULL) + dynamic_cast (abilities[i])->target = Phaseactiontarget; + } + } return 1; } @@ -1480,8 +2294,8 @@ AAlterCost::~AAlterCost() } // ATransformer -ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities) : - MTGAbility(id, source, target) +ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound) : + MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound) { PopulateAbilityIndexVector(abilities, sabilities); @@ -1574,6 +2388,18 @@ int ATransformer::addToGame() for (it = oldcolors.begin(); it != oldcolors.end(); it++) { } + if(newpowerfound == true) + { + oldpower = _target->power; + _target->power += newpower; + _target->power -= oldpower; + } + if(newtoughnessfound == true) + { + oldtoughness = _target->toughness; + _target->addToToughness(newtoughness); + _target->addToToughness(-oldtoughness); + } } return MTGAbility::addToGame(); } @@ -1611,6 +2437,14 @@ int ATransformer::destroy() _target->addType(*it); } } + if(newpowerfound == true) + { + _target->power = oldpower; + } + if(newtoughnessfound == true) + { + _target->toughness = oldtoughness; + } } return 1; } @@ -1635,8 +2469,8 @@ ATransformer::~ATransformer() // AForeverTransformer AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, - string sabilities) : - MTGAbility(id, source, target) + string sabilities,int newpower,bool newpowerfound, int newtoughness,bool newtoughnessfound) : + MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound) { aType = MTGAbility::STANDARD_BECOMES; @@ -1644,6 +2478,10 @@ AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCa PopulateColorIndexVector(colors, sabilities); PopulateSubtypesIndexVector(types, stypes); menu = stypes; + + remove = false; + if (stypes == "removetypes") + remove = true; } int AForeverTransformer::addToGame() @@ -1660,7 +2498,19 @@ int AForeverTransformer::addToGame() } for (it = types.begin(); it != types.end(); it++) { - _target->addType(*it); + if(remove == true) + { + _target->removeType(0,1); + _target->removeType(1,1); + _target->removeType(2,1); + _target->removeType(3,1); + _target->removeType(4,1); + _target->removeType(5,1); + _target->removeType(6,1); + _target->removeType(7,1); + } + else + _target->addType(*it); } for (it = colors.begin(); it != colors.end(); it++) { @@ -1670,6 +2520,18 @@ int AForeverTransformer::addToGame() { _target->basicAbilities[*it]++; } + if(newpowerfound == true) + { + oldpower = _target->power -= oldpower; + _target->power += newpower; + _target->power -= oldpower; + } + if(newtoughnessfound == true) + { + oldtoughness = _target->toughness; + _target->addToToughness(newtoughness); + _target->addToToughness(-oldtoughness); + } } return MTGAbility::addToGame(); } @@ -1692,10 +2554,10 @@ AForeverTransformer::~AForeverTransformer() } //ATransformerUEOT -ATransformerUEOT::ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities) : - InstantAbility(id, source, target) +ATransformerUEOT::ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound) : + InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound) { - ability = NEW ATransformer(id, source, target, types, abilities); + ability = NEW ATransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound); aType = MTGAbility::STANDARD_BECOMES; } @@ -1725,10 +2587,10 @@ ATransformerUEOT::~ATransformerUEOT() } // ATransformerFOREVER -ATransformerFOREVER::ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities) : - InstantAbility(id, source, target) +ATransformerFOREVER::ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,int newpower,bool newpowerfound,int newtoughness,bool newtoughnessfound) : + InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound) { - ability = NEW AForeverTransformer(id, source, target, types, abilities); + ability = NEW AForeverTransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound); aType = MTGAbility::STANDARD_BECOMES; } @@ -2008,8 +2870,8 @@ APreventDamageTypesUEOT::~APreventDamageTypesUEOT() //AUpkeep AUpkeep::AUpkeep(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap, int restrictions, int _phase, - int _once) : - ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), phase(_phase), once(_once) + int _once,bool Cumulative) : + ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), phase(_phase), once(_once),Cumulative(Cumulative) { paidThisTurn = 0; aType = MTGAbility::UPCOST; @@ -2024,7 +2886,21 @@ void AUpkeep::Update(float dt) { paidThisTurn = 0; } - else if (newPhase == phase + 1 && !paidThisTurn) + else if(newPhase == Constants::MTG_PHASE_UPKEEP && Cumulative == true) + { + source->counters->addCounter("age",0,0); + Counter * targetCounter = NULL; + currentage = 0; + + if (source->counters && source->counters->hasCounter("age", 0, 0)) + { + targetCounter = source->counters->hasCounter("age", 0, 0); + currentage = targetCounter->nb - 1; + } + if(currentage) + paidThisTurn -= currentage; + } + else if (newPhase == phase + 1 && paidThisTurn < 1) { ability->resolve(); } @@ -2036,14 +2912,14 @@ void AUpkeep::Update(float dt) int AUpkeep::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { - if (currentPhase != phase || paidThisTurn || once >= 2) + if (currentPhase != phase || paidThisTurn > 0 || once >= 2) return 0; return ActivatedAbility::isReactingToClick(card, mana); } int AUpkeep::resolve() { - paidThisTurn = 1; + paidThisTurn += 1; return 1; } @@ -2071,6 +2947,296 @@ AUpkeep::~AUpkeep() SAFE_DELETE(ability); } +//A Phase based Action +APhaseAction::APhaseAction(int _id, MTGCardInstance * card, MTGCardInstance * target, MTGAbility * a, int _tap, int restrictions, int _phase,bool forcedestroy,bool next) : +MTGAbility(_id, card), NestedAbility(a), phase(_phase),forcedestroy(forcedestroy),next(next) +{ + abilityOwner = card->controller(); +} + +void APhaseAction::Update(float dt) +{ + if (newPhase != currentPhase) + { + if(newPhase == phase && next == true) + { + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + while (_target->next) + _target = _target->next; + } + ability->target = _target; + ability->source = _target; + ability->oneShot = 1; + ability->resolve(); + this->forceDestroy = 1; + removeAbility(); + } + else if(newPhase == phase && next == false) + next = true; + } + MTGAbility::Update(dt); +} + +int APhaseAction::resolve() +{ + return 0; +} + +const char * APhaseAction::getMenuText() +{ + return ability->getMenuText(); +} + +APhaseAction * APhaseAction::clone() const +{ + APhaseAction * a = NEW APhaseAction(*this); + if(forcedestroy == false) + a->forceDestroy = -1;// we want this ability to stay alive until it resolves. + a->isClone = 1; + return a; +} +int APhaseAction::removeAbility() +{ + if (!isClone) + SAFE_DELETE(ability); + return 1; +} + +APhaseAction::~APhaseAction() +{ +} + +// the main ability +APhaseActionGeneric::APhaseActionGeneric(int _id, MTGCardInstance * card, MTGCardInstance * target, MTGAbility * a, int _tap, int restrictions, int _phase,bool forcedestroy,bool next) : + InstantAbility(_id, source, target) +{ + MTGCardInstance * _target = target; + ability = NEW APhaseAction(_id, card,_target, a,_tap, restrictions, _phase,forcedestroy,next); +} + +int APhaseActionGeneric::resolve() +{ + APhaseAction * a = ability->clone(); + a->target = target; + a->addToGame(); + return 1; +} + +const char * APhaseActionGeneric::getMenuText() +{ + return ability->getMenuText(); +} + +APhaseActionGeneric * APhaseActionGeneric::clone() const +{ + APhaseActionGeneric * a = NEW APhaseActionGeneric(*this); + a->ability = this->ability->clone(); + a->oneShot = 1; + a->isClone = 1; + return a; +} + +APhaseActionGeneric::~APhaseActionGeneric() +{ + SAFE_DELETE(ability); +} + +//a blink +ABlink::ABlink(int _id, MTGCardInstance * card, MTGCardInstance * _target,bool blinkueot,bool blinkForSource,bool blinkhand) : +MTGAbility(_id, card),blinkueot(blinkueot),blinkForSource(blinkForSource),blinkhand(blinkhand) +{ + target = _target; + Blinked = NULL; + resolved = false; +} + +void ABlink::Update(float dt) +{ + if(resolved == false) + { + resolved = true; + resolveBlink(); + } + GameObserver * game = game->GetInstance(); + if ((blinkueot && currentPhase == Constants::MTG_PHASE_ENDOFTURN)||(blinkForSource && !source->isInPlay())) + { + if(Blinked == NULL) + MTGAbility::Update(dt); + MTGCardInstance * _target = Blinked; + MTGCardInstance * Blinker = NULL; + if(!blinkhand) + Blinker = _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->battlefield); + if(blinkhand) + { + _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->hand); + return; + } + Spell * spell = NEW Spell(Blinker); + spell->source->counters->init(); + if(spell->source->hasSubtype("aura") && !blinkhand) + { + TargetChooserFactory tcf; + TargetChooser * tc = tcf.createTargetChooser(spell->source->spellTargetType,spell->source); + if(!tc->validTargetsExist()) + { + spell->source->owner->game->putInExile(spell->source); + delete spell; + delete tc; + this->forceDestroy = 1; + return; + } + + MTGGameZone * inplay = spell->source->owner->game->inPlay; + spell->source->target = NULL; + for(int i = WRand()%inplay->nb_cards;;i = WRand()%inplay->nb_cards) + { + if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL) + { + spell->source->target = inplay->cards[i]; + spell->getNextCardTarget(); + spell->resolve(); + + delete spell; + delete tc; + this->forceDestroy = 1; + return; + } + } + } + spell->source->power = spell->source->origpower; + spell->source->toughness = spell->source->origtoughness; + if(!spell->source->hasSubtype("aura")) + { + spell->resolve(); + } + delete spell; + this->forceDestroy = 1; + Blinker = NULL; + return; + } + MTGAbility::Update(dt); +} + +void ABlink::resolveBlink() +{ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target) + { + _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->exile); + _target = _target->next; + Blinked = _target; + if(!blinkueot && !blinkForSource) + { + MTGCardInstance * Blinker = NULL; + if(!blinkhand) + Blinker = _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->battlefield); + if(blinkhand) + { + _target->controller()->game->putInZone(_target, _target->currentZone, + _target->owner->game->hand); + return; + } + Spell * spell = NEW Spell(Blinker); + spell->source->counters->init(); + if(spell->source->hasSubtype("aura") && !blinkhand) + { + TargetChooserFactory tcf; + TargetChooser * tc = tcf.createTargetChooser(spell->source->spellTargetType,spell->source); + if(!tc->validTargetsExist()) + { + spell->source->owner->game->putInExile(spell->source); + delete spell; + delete tc; + this->forceDestroy = 1; + return; + } + + MTGGameZone * inplay = spell->source->owner->game->inPlay; + spell->source->target = NULL; + for(int i = WRand()%inplay->nb_cards;;i = WRand()%inplay->nb_cards) + { + if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL) + { + spell->source->target = inplay->cards[i]; + spell->getNextCardTarget(); + spell->resolve(); + + delete spell; + delete tc; + this->forceDestroy = 1; + return; + } + } + } + spell->source->power = spell->source->origpower; + spell->source->toughness = spell->source->origtoughness; + spell->resolve(); + delete spell; + this->forceDestroy = 1; + Blinked = NULL; + } + } +} + +int ABlink::resolve() +{ + return 0; +} +const char * ABlink::getMenuText() +{ + return "Blink"; +} + +ABlink * ABlink::clone() const +{ + ABlink * a = NEW ABlink(*this); + a->isClone = 1; + a->forceDestroy = -1; + return a; +}; +ABlink::~ABlink() +{ +} + +ABlinkGeneric::ABlinkGeneric(int _id, MTGCardInstance * card, MTGCardInstance * _target,bool blinkueot,bool blinkForSource,bool blinkhand) : + InstantAbility(_id, source, _target) +{ + ability = NEW ABlink(_id,card,_target,blinkueot,blinkForSource,blinkhand); +} + +int ABlinkGeneric::resolve() +{ + ABlink * a = ability->clone(); + a->target = target; + a->addToGame(); + return 1; +} + +const char * ABlinkGeneric::getMenuText() +{ + return "Blink"; +} + +ABlinkGeneric * ABlinkGeneric::clone() const +{ + ABlinkGeneric * a = NEW ABlinkGeneric(*this); + a->ability = this->ability->clone(); + a->oneShot = 1; + a->isClone = 1; + return a; +} + +ABlinkGeneric::~ABlinkGeneric() +{ + SAFE_DELETE(ability); +} + // utility functions // Given a delimited string of abilities, add the ones to the list that are "Basic" MTG abilities diff --git a/projects/mtg/src/CardDescriptor.cpp b/projects/mtg/src/CardDescriptor.cpp index 3a459d254..79b486846 100644 --- a/projects/mtg/src/CardDescriptor.cpp +++ b/projects/mtg/src/CardDescriptor.cpp @@ -42,6 +42,32 @@ void CardDescriptor::unsecuresetfresh(int k) fresh = k; } +void CardDescriptor::setisMultiColored(int 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) { int id = Subtypes::subtypesList->find(value); @@ -203,10 +229,42 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card) match = NULL; } - if ((isToken == -1 && card->isToken) || (isToken == 1 && !card->isToken)) + if ((isMultiColored == -1 && card->isMultiColored) || (isMultiColored == 1 && !card->isMultiColored)) { 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)) + { + match = NULL; + } + if ((CDenchanted == -1 && card->enchanted) || (CDenchanted == 1 && !card->enchanted)) + { + match = NULL; + } + if ((isToken == -1 && card->isToken) || (isToken == 1 && !card->isToken)) + { + match = NULL; + } if (attacker == 1) { if (defenser == &AnyCard) diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index f754c66ec..2aaa58ed9 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -141,6 +141,7 @@ void CardGui::Render() bool alternate = true; JQuad * quad = WResourceManager::Instance()->RetrieveCard(card, CACHE_THUMB); + #if defined (WIN32) || defined (LINUX) //On pcs we render the big image if the thumbnail is not available if (!quad) quad = WResourceManager::Instance()->RetrieveCard(card); @@ -160,7 +161,13 @@ void CardGui::Render() shadow->SetColor(ARGB(static_cast(actA)/2,255,255,255)); renderer->RenderQuad(shadow, actX + (actZ - 1) * 15, actY + (actZ - 1) * 15, actT, 28 * actZ / 16, 40 * actZ / 16); } - + JQuad* extracostshadow = NULL; + if(card->isExtraCostTarget == true) + { + extracostshadow = WResourceManager::Instance()->GetQuad("extracostshadow"); + extracostshadow->SetColor(ARGB(static_cast(actA)/2,100,0,0)); + renderer->RenderQuad(extracostshadow, actX + (actZ - 1) * 15, actY + (actZ - 1) * 15, actT, 28 * actZ / 16, 40 * actZ / 16); + } if (quad) { quad->SetColor(ARGB(static_cast(actA),255,255,255)); @@ -185,7 +192,7 @@ void CardGui::Render() icon = WResourceManager::Instance()->GetQuad("c_red"); else if (card->hasSubtype("island")) icon = WResourceManager::Instance()->GetQuad("c_blue"); - + if (icon) { icon->SetColor(ARGB(static_cast(actA),255,255,255)); @@ -194,6 +201,14 @@ void CardGui::Render() } } + JQuad * mor = NULL; + if(card->isMorphed && !alternate) + { + mor = WResourceManager::Instance()->GetQuad("morph"); + mor->SetColor(ARGB(255,255,255,255)); + renderer->RenderQuad(mor, actX, actY, actT,scale, scale); + } + //draws the numbers power/toughness if (card->isCreature()) { @@ -236,7 +251,6 @@ void CardGui::Render() shadow->SetColor(ARGB(200,255,255,255)); renderer->RenderQuad(shadow, actX, actY, actT, (28 * actZ + 1) / 16, 40 * actZ / 16); } - PlayGuiObject::Render(); } @@ -552,6 +566,7 @@ void CardGui::TinyCropRender(MTGCard * card, const Pos& pos, JQuad * quad) break; } } + if (q && q->mTex) { q->SetHotSpot(static_cast (q->mTex->mWidth / 2), static_cast (q->mTex->mHeight / 2)); diff --git a/projects/mtg/src/CardPrimitive.cpp b/projects/mtg/src/CardPrimitive.cpp index cd7483417..8fd22dfe7 100644 --- a/projects/mtg/src/CardPrimitive.cpp +++ b/projects/mtg/src/CardPrimitive.cpp @@ -29,6 +29,8 @@ CardPrimitive::CardPrimitive(CardPrimitive * source) power = source->power; toughness = source->toughness; + restriction = source->restriction; + otherrestriction = source->otherrestriction; magicText = source->magicText; for (map::const_iterator it = source->magicTexts.begin(); it != source->magicTexts.end(); ++it) @@ -50,6 +52,7 @@ int CardPrimitive::init() magicTexts.clear(); spellTargetType = ""; alias = 0; + bool hasRestriction = false; return 1; } @@ -83,6 +86,24 @@ bool CardPrimitive::isSpell() return (!isCreature() && !isLand()); } +void CardPrimitive::setRestrictions(int _restriction) +{ + restriction = _restriction; +} +int CardPrimitive::getRestrictions() +{ + return restriction; +} + +void CardPrimitive::setOtherRestrictions(string _restriction) +{ + otherrestriction = _restriction; +} +void CardPrimitive::getOtherRestrictions() +{ + otherrestriction; +} + void CardPrimitive::setColor(string _color, int removeAllOthers) { if (_color.compare("blue") == 0) diff --git a/projects/mtg/src/Damage.cpp b/projects/mtg/src/Damage.cpp index 8d5ce3b30..d3850e510 100644 --- a/projects/mtg/src/Damage.cpp +++ b/projects/mtg/src/Damage.cpp @@ -94,7 +94,9 @@ int Damage::resolve() } if ((_target)->has(Constants::ABSORB)) { - damage -= 1; + damage -= (_target)->basicAbilities[Constants::ABSORB]; + if(damage < 0) + damage = 0; } if ((_target)->has(Constants::WILTING)) { @@ -132,6 +134,8 @@ int Damage::resolve() { _target->counters->addCounter(-1, -1); } + if(_target->toughness <= 0 && _target->has(Constants::INDESTRUCTIBLE)) + _target->controller()->game->putInGraveyard(_target); } else if (target->type_as_damageable == DAMAGEABLE_PLAYER && source->has(Constants::INFECT)) diff --git a/projects/mtg/src/DuelLayers.cpp b/projects/mtg/src/DuelLayers.cpp index ee7219b50..a89cefbea 100644 --- a/projects/mtg/src/DuelLayers.cpp +++ b/projects/mtg/src/DuelLayers.cpp @@ -39,7 +39,7 @@ void DuelLayers::init() action->Add(NEW MTGLifelinkRule(-1)); action->Add(NEW MTGDeathtouchRule(-1)); action->Add(NEW OtherAbilitiesEventReceiver(-1)); - + action->Add(NEW MTGMorphCostRule(-1)); //Other display elements action->Add(NEW HUDDisplay(-1)); diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index ef8110cfc..7103f603f 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -79,7 +79,13 @@ int LifeCost::doPay() MTGCardInstance * _target = (MTGCardInstance *) target; if (target) { + _target->controller()->thatmuch = 1; + WEvent * lifed = NULL; + lifed = NEW WEventLife(_target->controller(),-1,1); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); _target->controller()->life -= 1; + _target->controller()->lifeLostThisTurn += 1; target = NULL; if (tc) tc->initTargets(); @@ -263,6 +269,20 @@ TapTargetCost::TapTargetCost(TargetChooser *_tc) : { } +int TapTargetCost::isPaymentSet() +{ + if (target && target->isTapped()) + { + tc->removeTarget(target); + target->isExtraCostTarget = false; + target = NULL; + return 0; + } + if (target) + return 1; + return 0; +} + int TapTargetCost::doPay() { MTGCardInstance * _target = (MTGCardInstance *) target; @@ -563,8 +583,19 @@ int ExtraCosts::tryToSetPayment(MTGCardInstance * card) { for (size_t i = 0; i < costs.size(); i++) { - if (int result = costs[i]->setPayment(card)) - return result; + if(!costs[i]->isPaymentSet()) + { + for(size_t k = 0; k < costs.size(); k++) + { + if(card == costs[k]->target) + return 0; + } + if (int result = costs[i]->setPayment(card)) + { + card->isExtraCostTarget = true; + return result; + } + } } return 0; } @@ -584,7 +615,10 @@ int ExtraCosts::canPay() for (size_t i = 0; i < costs.size(); i++) { if (!costs[i]->canPay()) + { + costs[i]->target->isExtraCostTarget = false; return 0; + } } return 1; } @@ -594,6 +628,8 @@ int ExtraCosts::doPay() int result = 0; for (size_t i = 0; i < costs.size(); i++) { + if(costs[i]->target) + costs[i]->target->isExtraCostTarget = false; result += costs[i]->doPay(); } return result; diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index acc657235..d55beec8b 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -191,6 +191,8 @@ void GameApp::Create() WResourceManager::Instance()->RetrieveTexture("BattleIcon.png", RETRIEVE_MANAGE); WResourceManager::Instance()->RetrieveTexture("DefenderIcon.png", RETRIEVE_MANAGE); WResourceManager::Instance()->RetrieveTexture("shadow.png", RETRIEVE_MANAGE); + WResourceManager::Instance()->RetrieveTexture("extracostshadow.png", RETRIEVE_MANAGE); + WResourceManager::Instance()->RetrieveTexture("morph.jpg", RETRIEVE_MANAGE); jq = WResourceManager::Instance()->RetrieveQuad("BattleIcon.png", 0, 0, 25, 25, "BattleIcon", RETRIEVE_MANAGE); if (jq) @@ -201,6 +203,12 @@ void GameApp::Create() jq = WResourceManager::Instance()->RetrieveQuad("shadow.png", 0, 0, 16, 16, "shadow", RETRIEVE_MANAGE); if (jq) jq->SetHotSpot(8, 8); + jq = WResourceManager::Instance()->RetrieveQuad("extracostshadow.png", 0, 0, 16, 16, "extracostshadow", RETRIEVE_MANAGE); + if (jq) + jq->SetHotSpot(8, 8); + jq = WResourceManager::Instance()->RetrieveQuad("morph.jpg", 0, 0, MTG_MINIIMAGE_WIDTH, MTG_MINIIMAGE_HEIGHT, "morph", RETRIEVE_MANAGE); + if (jq) + jq->SetHotSpot(static_cast (jq->mTex->mWidth / 2), static_cast (jq->mTex->mHeight / 2)); jq = WResourceManager::Instance()->RetrieveQuad("phasebar.png", 0, 0, 0, 0, "phasebar", RETRIEVE_MANAGE); LOG("Init Collection"); diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 7ae697238..400036f6f 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -118,6 +118,7 @@ void GameObserver::nextGamePhase() currentPlayer->onlyoneinstant = false; currentPlayer->damageCount = 0; currentPlayer->preventable = 0; + currentPlayer->isPoisoned = false; mLayers->actionLayer()->cleanGarbage(); //clean abilities history for this turn; mLayers->stackLayer()->garbageCollect(); //clean stack history for this turn; mLayers->actionLayer()->Update(0); @@ -140,6 +141,8 @@ void GameObserver::nextGamePhase() while (currentPlayer->game->hand->nb_cards > 7 && currentPlayer->nomaxhandsize == false) currentPlayer->game->putInGraveyard(currentPlayer->game->hand->cards[0]); mLayers->actionLayer()->Update(0); + currentPlayer->lifeLostThisTurn = 0; + currentPlayer->opponent()->lifeLostThisTurn = 0; return nextGamePhase(); } @@ -382,6 +385,14 @@ void GameObserver::gameStateBasedEffects() { players[i]->canPutLandsIntoPlay = true; } + if(players[i]->poisonCount > 0) + { + players[i]->isPoisoned = true; + } + else + { + players[i]->isPoisoned = false; + } } if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0) return; @@ -401,12 +412,77 @@ void GameObserver::gameStateBasedEffects() { MTGCardInstance * card = zone->cards[j]; card->afterDamage(); - - //Remove auras that don't have a valid target anymore + /////////////////////////////////////////////////////// + //Remove auras that don't have a valid target anymore// + /////////////////////////////////////////////////////// if (card->target && !isInPlay(card->target) && !card->hasType("equipment")) { players[i]->game->putInGraveyard(card); } + card->enchanted = false; + if (card->target && isInPlay(card->target) && !card->hasType("equipment") && card->hasSubtype("aura")) + { + card->target->enchanted = true; + } + /////////////////////////// + //reset extracost shadows// + /////////////////////////// + card->isExtraCostTarget = false; + if(mExtraPayment != NULL) + { + for(unsigned int ec = 0;ec < mExtraPayment->costs.size();ec++) + { + if( mExtraPayment->costs[ec]->target) + mExtraPayment->costs[ec]->target->isExtraCostTarget = true; + } + } + ////////////////////// + //reset morph hiding// + ////////////////////// + if((card->previous && card->previous->morphed && !card->turningOver) || (card->morphed && !card->turningOver)) + { + card->morphed = true; + card->isMorphed = true; + } + else + { + card->isMorphed = false; + card->morphed = false; + } + ////////////////////////// + //handles phasing events// + ////////////////////////// + if((card->has(Constants::PHASING)&& currentGamePhase == Constants::MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn && !card->isPhased) || (card->isTempPhased && !card->isPhased)) + { + card->isPhased = true; + card->phasedTurn = turn; + if(card->view) + card->view->alpha = 50; + card->initAttackersDefensers(); + } + else if((card->has(Constants::PHASING) || card->isTempPhased)&& currentGamePhase == Constants::MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn) + { + card->isPhased = false; + card->phasedTurn = turn; + if(card->view) + card->view->alpha = 255; + card->isTempPhased = false; + } + if (card->target && isInPlay(card->target) && (card->hasSubtype("equipment") || card->hasSubtype("aura"))) + { + card->isPhased = card->target->isPhased; + card->phasedTurn = card->target->phasedTurn; + if(card->view && card->target->view) + card->view->alpha = card->target->view->alpha; + } + ////////////////////////// + //forceDestroy over ride// + ////////////////////////// + if(card->isInPlay()) + { + card->graveEffects = false; + card->exileEffects = false; + } } } //------------------------------------- @@ -524,22 +600,22 @@ void GameObserver::gameStateBasedEffects() } //------------------------------------ if (players[0]->bothrestrictedcreature) - players[1]->castrestrictedcreature = true; + players[1]->castrestrictedcreature = true; //------------------------------------ if (players[0]->bothrestrictedspell) - players[1]->castrestrictedspell = true; + players[1]->castrestrictedspell = true; //------------------------------------ if (players[0]->onlyoneboth) - players[1]->onlyoneboth = true; + players[1]->onlyoneboth = true; //------------------------------------ if (players[1]->bothrestrictedcreature) - players[0]->castrestrictedcreature = true; + players[0]->castrestrictedcreature = true; //------------------------------------ if (players[1]->bothrestrictedspell) - players[0]->castrestrictedspell = true; + players[0]->castrestrictedspell = true; //------------------------------------ if (players[1]->onlyoneboth) - players[0]->onlyoneboth = true; + players[0]->onlyoneboth = true; //------------------------------------ ///////////////////////////////////////////////// //handle end of turn effects while we're at it.// @@ -552,7 +628,10 @@ void GameObserver::gameStateBasedEffects() if(!c)break; while (c->flanked) - {//undoes the flanking on a card + { + ///////////////////////////////// + //undoes the flanking on a card// + ///////////////////////////////// c->power += 1; c->addToToughness(1); c->flanked -= 1; @@ -582,14 +661,13 @@ void GameObserver::gameStateBasedEffects() p->game->putInExile(c); } - if(nbcards > z->nb_cards) - { - t = 0; - nbcards = z->nb_cards; - } + if(nbcards > z->nb_cards) + { + t = 0; + nbcards = z->nb_cards; + } } - MTGGameZone * f = p->game->graveyard; for (int k = 0; k < f->nb_cards; k++) { @@ -601,11 +679,55 @@ void GameObserver::gameStateBasedEffects() { p->nomaxhandsize = false; if (!p->bothrestrictedcreature && !p->opponent()->bothrestrictedcreature) - p->castrestrictedcreature = false; + p->castrestrictedcreature = false; if (!p->bothrestrictedspell && !p->opponent()->bothrestrictedspell) - p->castrestrictedspell = false; + p->castrestrictedspell = false; p->onlyonecast = false; } + ////////////////////////// + // Check auras on a card// + ////////////////////////// + enchantmentStatus(); + ///////////////////////////////////// + // Check colored statuses on cards // + ///////////////////////////////////// + for(int w = 0;w < z->nb_cards;w++) + { + int colored = 0; + for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i) + { + if (z->cards[w]->hasColor(i)) + ++colored; + } + if(colored > 1) + { + z->cards[w]->isMultiColored = 1; + } + else + { + z->cards[w]->isMultiColored = 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; + } } /////////////////////////////////// //phase based state effects------// @@ -613,33 +735,58 @@ void GameObserver::gameStateBasedEffects() if (combatStep == TRIGGERS) { if (!mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED) && !targetChooser - && !mLayers->actionLayer()->isWaitingForAnswer()) - mLayers->stackLayer()->AddNextCombatStep(); + && !mLayers->actionLayer()->isWaitingForAnswer()) + mLayers->stackLayer()->AddNextCombatStep(); } //Auto skip Phases GameObserver * game = game->GetInstance(); int skipLevel = (game->currentPlayer->playMode == Player::MODE_TEST_SUITE) ? Constants::ASKIP_NONE - : options[Options::ASPHASES].number; + : options[Options::ASPHASES].number; int nrCreatures = currentPlayer->game->inPlay->countByType("Creature"); if (skipLevel == Constants::ASKIP_SAFE || skipLevel == Constants::ASKIP_FULL) { if ((opponent()->isAI() && !(isInterrupting)) && ((currentGamePhase == Constants::MTG_PHASE_UNTAP) - || (currentGamePhase == Constants::MTG_PHASE_DRAW) || (currentGamePhase == Constants::MTG_PHASE_COMBATBEGIN) - || ((currentGamePhase == Constants::MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0)) - || currentGamePhase == Constants::MTG_PHASE_COMBATEND || currentGamePhase == Constants::MTG_PHASE_ENDOFTURN - || ((currentGamePhase == Constants::MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8)))) - userRequestNextGamePhase(); + || (currentGamePhase == Constants::MTG_PHASE_DRAW) || (currentGamePhase == Constants::MTG_PHASE_COMBATBEGIN) + || ((currentGamePhase == Constants::MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0)) + || currentGamePhase == Constants::MTG_PHASE_COMBATEND || currentGamePhase == Constants::MTG_PHASE_ENDOFTURN + || ((currentGamePhase == Constants::MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8)))) + userRequestNextGamePhase(); } if (skipLevel == Constants::ASKIP_FULL) { if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == Constants::MTG_PHASE_UPKEEP - || currentGamePhase == Constants::MTG_PHASE_COMBATDAMAGE)) - userRequestNextGamePhase(); + || currentGamePhase == Constants::MTG_PHASE_COMBATDAMAGE)) + userRequestNextGamePhase(); } } +void GameObserver::enchantmentStatus() +{ + for (int i = 0; i < 2; i++) + { + MTGGameZone * zone = players[i]->game->inPlay; + for (int k = zone->nb_cards - 1; k >= 0; k--) + { + MTGCardInstance * card = zone->cards[k]; + if (card && !card->hasType("equipment") && !card->hasSubtype("aura")) + { + card->enchanted = false; + card->auras = 0; + } + } + for (int j = zone->nb_cards - 1; j >= 0; j--) + { + MTGCardInstance * card = zone->cards[j]; + if (card->target && isInPlay(card->target) && !card->hasType("equipment") && card->hasSubtype("aura")) + { + card->target->enchanted = true; + card->target->auras += 1; + } + } + } +} void GameObserver::Render() { mLayers->Render(); @@ -883,7 +1030,28 @@ int GameObserver::isInPlay(MTGCardInstance * card) } return 0; } +int GameObserver::isInGrave(MTGCardInstance * card) +{ + for (int i = 0; i < 2; i++) + { + MTGGameZone * graveyard = players[i]->game->graveyard; + if (players[i]->game->isInZone(card,graveyard)) + return 1; + } + return 0; +} +int GameObserver::isInExile(MTGCardInstance * card) +{ + + for (int i = 0; i < 2; i++) + { + MTGGameZone * exile = players[i]->game->exile; + if (players[i]->game->isInZone(card,exile)) + return 1; + } + return 0; +} void GameObserver::draw() { currentPlayer->game->drawFromLibrary(); diff --git a/projects/mtg/src/GameOptions.cpp b/projects/mtg/src/GameOptions.cpp index ca91df265..35cca2af6 100644 --- a/projects/mtg/src/GameOptions.cpp +++ b/projects/mtg/src/GameOptions.cpp @@ -28,6 +28,7 @@ const string Options::optionNames[] = { "disable_cards", "maxGrade", "ASPhases", + "FirstPlayer", "economic_difficulty", "transitions", "bgStyle", @@ -441,6 +442,11 @@ GameOption * GameOptions::get(int optionID) goEnum->def = OptionASkipPhase::getInstance(); go = goEnum; break; + case Options::FIRSTPLAYER: + goEnum = NEW GameOptionEnum(); + goEnum->def = OptionWhosFirst::getInstance(); + go = goEnum; + break; case Options::KEY_BINDINGS: go = NEW GameOptionKeyBindings(); break; @@ -870,6 +876,16 @@ OptionASkipPhase::OptionASkipPhase() mDef.values.push_back(EnumDefinition::assoc(Constants::ASKIP_FULL, "Full")); } ; + +OptionWhosFirst OptionWhosFirst::mDef; +OptionWhosFirst::OptionWhosFirst() +{ + mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_P, "Player")); + mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_O, "Opponent")); + mDef.values.push_back(EnumDefinition::assoc(Constants::WHO_R, "Random")); +} +; + OptionClosedHand OptionClosedHand::mDef; OptionClosedHand::OptionClosedHand() { diff --git a/projects/mtg/src/GameStateOptions.cpp b/projects/mtg/src/GameStateOptions.cpp index 302a3b6db..b75311f5e 100644 --- a/projects/mtg/src/GameStateOptions.cpp +++ b/projects/mtg/src/GameStateOptions.cpp @@ -103,6 +103,10 @@ void GameStateOptions::Start() optionsList->Add(oASPhases); optionsTabs->Add(optionsList); + WDecoEnum * oFirstPlayer = NEW WDecoEnum(NEW OptionInteger(Options::FIRSTPLAYER, "First Turn Player", Constants::WHO_R, 1, + Constants::WHO_P, "", Constants::WHO_P)); + optionsList->Add(oFirstPlayer); + optionsList = NEW WGuiKeyBinder("Key Bindings", this); optionsTabs->Add(optionsList); diff --git a/projects/mtg/src/GuiHand.cpp b/projects/mtg/src/GuiHand.cpp index 1b76d69b5..da77baae8 100644 --- a/projects/mtg/src/GuiHand.cpp +++ b/projects/mtg/src/GuiHand.cpp @@ -44,8 +44,11 @@ GuiHand::GuiHand(MTGHand* hand) : GuiHand::~GuiHand() { - for (vector::iterator it = cards.begin(); it != cards.end(); ++it) - delete (*it); + if(cards.size()) + { + for (vector::iterator it = cards.begin(); it != cards.end(); ++it) + delete (*it); + } } void GuiHand::Update(float dt) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 08ee83b29..0fca5d2b3 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -18,6 +18,168 @@ const size_t kLordKeywordsCount = 5; const string kThisKeywords[] = { "this(", "thisforeach(" }; const size_t kThisKeywordsCount = 2; +int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player) +{ + int cPhase = game->getCurrentGamePhase(); + int restrictions = 0; + restrictions = card->getRestrictions(); + + int vamps = 0; + int playercreatures = 0; + int opponentcreatures = 0; + + switch (restrictions) + { + case PLAYER_TURN_ONLY: + if (player != game->currentPlayer) + return 0; + break; + case OPPONENT_TURN_ONLY: + if (player == game->currentPlayer) + return 0; + break; + case AS_SORCERY: + if (player != game->currentPlayer) + return 0; + if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN) + return 0; + break; + case VAMPIRES: + + vamps = player->game->inPlay->countByType("vampire"); + if(vamps < 3) + return 0; + break; + case LESS_CREATURES: + + playercreatures = player->game->inPlay->countByType("creature"); + opponentcreatures = player->opponent()->game->inPlay->countByType("creature"); + if(playercreatures > opponentcreatures) + return 0; + break; + case SNOW_LAND_INPLAY: + if(!player->game->inPlay->hasPrimaryType("snow","land")) + return 0; + break; + case CASTED_A_SPELL: + if(player->castedspellsthisturn < 1) + return 0; + break; + case ONE_OF_AKIND: + if(player->game->inPlay->hasName(card->name)) + return 0; + break; + case FOURTHTURN: + if(game->turn <= 7) + return 0; + break; + case BEFORECOMBATDAMAGE: + if(cPhase > Constants::MTG_PHASE_COMBATBLOCKERS) + return 0; + break; + case AFTERCOMBAT: + if(cPhase < Constants::MTG_PHASE_COMBATBLOCKERS) + return 0; + break; + case DURINGCOMBAT: + if(cPhase < Constants::MTG_PHASE_COMBATBEGIN ||cPhase > Constants::MTG_PHASE_COMBATEND ) + return 0; + break; + } + + if (restrictions >= MY_BEFORE_BEGIN && restrictions <= MY_AFTER_EOT) + { + if (player != game->currentPlayer) + return 0; + if (cPhase != restrictions - MY_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + + if (restrictions >= OPPONENT_BEFORE_BEGIN && restrictions <= OPPONENT_AFTER_EOT) + { + if (player == game->currentPlayer) + return 0; + if (cPhase != restrictions - OPPONENT_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + + if (restrictions >= BEFORE_BEGIN && restrictions <= AFTER_EOT) + { + if (cPhase != restrictions - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + return 1; +} + +int MTGAbility::allowedToAltCast(MTGCardInstance * card,Player * player) +{ + int cPhase = game->getCurrentGamePhase(); + string restrictions = ""; + restrictions = card->otherrestriction; + static bool less = false; + static bool more = false; + int mytypemin = 0; + int opponenttypemin = 0; + int min = 0; + int opponentmin = 0; + string type = "*"; + string opponenttype = "*"; + + size_t check = restrictions.find("mytypemin:"); + if( check != string::npos) + { + size_t start = restrictions.find(":", check); + size_t end = restrictions.find(" ", check); + size_t lesser = restrictions.find(":less",check); + size_t morer = restrictions.find(":more",check); + if(lesser != string::npos) + { + less = true; + } + else if(morer != string::npos) + { + more = true; + } + else + { + min = atoi(restrictions.substr(start + 1, end - start - 1).c_str()); + } + + + size_t found = restrictions.find("type("); + if (found != string::npos) + { + end = restrictions.find(")", found); + type = restrictions.substr(found + 5, end - found - 5).c_str(); + } + mytypemin = card->controller()->game->inPlay->countByType(type.c_str()); + if(mytypemin < min && less == false && more == false) + return 0; + } + check = restrictions.find("opponenttypemin:"); + if( check != string::npos) + { + size_t start = restrictions.find(":", check); + size_t end = restrictions.find(" ", check); + opponentmin = atoi(restrictions.substr(start + 1, end - start - 1).c_str()); + + size_t found = restrictions.find("opponenttype("); + if (found != string::npos) + { + end = restrictions.find(")", found); + opponenttype = restrictions.substr(found + 13, end - found - 13).c_str(); + } + opponenttypemin = card->controller()->opponent()->game->inPlay->countByType(opponenttype.c_str()); + if(opponenttypemin < opponentmin && less == false && more == false) + return 0; + } + if(less == true && more == false && opponenttypemin <= mytypemin) + return 0; + if(less == false && more == true && opponenttypemin >= mytypemin) + return 0; + return 1; +} + int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option) { int result = 0; @@ -118,10 +280,43 @@ int AbilityFactory::parsePowerToughness(string s, int *power, int *toughness) // ie auto=@attacking(mytgt):destroy target(*) // eval only the text between the @ and the first : TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int id, Spell * spell, MTGCardInstance *card, - Targetable * target) + Targetable * target) { size_t found = string::npos; + //restrictions on triggers + bool once = false; + bool sourceUntapped = false; + bool sourceTap = false; + bool lifelost = false; + int lifeamount = 0; + found = s.find("once"); + if (found != string::npos) + { + once = true; + } + found = s.find("sourcenottap"); + if (found != string::npos) + { + sourceUntapped = true; + } + found = s.find("sourcetap"); + if (found != string::npos) + { + sourceTap = true; + } + found = s.find("foelostthree"); + if (found != string::npos) + { + lifelost = true; + lifeamount = 3; + } + found = s.find("foelosttwo"); + if (found != string::npos) + { + lifelost = true; + lifeamount = 2; + } //Card Changed Zone found = s.find("movedto("); if (found != string::npos) @@ -172,7 +367,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int fromTc = tcf.createTargetChooser(starget, card); fromTc->targetter = NULL; //avoid protection from } - return NEW TrCardAddedToZone(id, card, (TargetZoneChooser *) toTc, toTcCard, (TargetZoneChooser *) fromTc, fromTcCard); + return NEW TrCardAddedToZone(id, card, (TargetZoneChooser *) toTc, toTcCard, (TargetZoneChooser *) fromTc, fromTcCard,once,sourceUntapped); } //Card unTapped @@ -224,7 +419,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int TargetChooser *tc = tcf.createTargetChooser(starget, card); tc->targetter = NULL; - return NEW TrCardAttacked(id, card, tc); + return NEW TrCardAttacked(id, card, tc,sourceUntapped); } //Card is attacking alone found = s.find("attackedalone("); @@ -295,7 +490,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int fromTc->targetter = NULL; } - return NEW TrCardBlocked(id, card, tc, fromTc); + return NEW TrCardBlocked(id, card, tc, fromTc,once); } //Card card is drawn @@ -400,9 +595,96 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int fromTc = tcf.createTargetChooser(starget, card); fromTc->targetter = NULL; } - return NEW TrDamaged(id, card, tc, fromTc, 0); + return NEW TrDamaged(id, card, tc, fromTc, 0,sourceUntapped); } + //Card Damaging + found = s.find("lifed("); + if (found != string::npos) + { + size_t end = s.find(")"); + string starget = s.substr(found + 6, end - found - 6); + TargetChooserFactory tcf; + TargetChooser *tc = tcf.createTargetChooser(starget, card); + tc->targetter = NULL; + found = s.find("from("); + + TargetChooser *fromTc = NULL; + if (found != string::npos) + { + end = s.find(")", found); + starget = s.substr(found + 5, end - found - 5); + fromTc = tcf.createTargetChooser(starget, card); + fromTc->targetter = NULL; + } + return NEW TrLifeGained(id, card, tc, fromTc, 0,sourceUntapped); + } + + //Card Damaging + found = s.find("lifeloss("); + if (found != string::npos) + { + size_t end = s.find(")"); + string starget = s.substr(found + 9, end - found - 9); + TargetChooserFactory tcf; + TargetChooser *tc = tcf.createTargetChooser(starget, card); + tc->targetter = NULL; + found = s.find("from("); + + TargetChooser *fromTc = NULL; + if (found != string::npos) + { + end = s.find(")", found); + starget = s.substr(found + 5, end - found - 5); + fromTc = tcf.createTargetChooser(starget, card); + fromTc->targetter = NULL; + } + return NEW TrLifeGained(id, card, tc, fromTc,1,sourceUntapped); + } + + //Card Damaged and killed by a creature this turn + found = s.find("vampired("); + if (found != string::npos) + { + size_t end = s.find(")"); + string starget = s.substr(found + 9, end - found - 9); + TargetChooserFactory tcf; + TargetChooser *tc = tcf.createTargetChooser(starget, card); + tc->targetter = NULL; + found = s.find("from("); + + TargetChooser *fromTc = NULL; + if (found != string::npos) + { + end = s.find(")", found); + starget = s.substr(found + 5, end - found - 5); + fromTc = tcf.createTargetChooser(starget, card); + fromTc->targetter = NULL; + } + return NEW TrVampired(id, card, tc, fromTc, 0); + } + //when card becomes the target of a spell or ability + found = s.find("targeted("); + if (found != string::npos) + { + size_t end = s.find(")"); + string starget = s.substr(found + 9, end - found - 9); + TargetChooserFactory tcf; + TargetChooser *tc = tcf.createTargetChooser(starget, card); + tc->targetter = NULL; + found = s.find("from("); + + TargetChooser *fromTc = NULL; + if (found != string::npos) + { + end = s.find(")", found); + starget = s.substr(found + 5, end - found - 5); + fromTc = tcf.createTargetChooser(starget, card); + fromTc->targetter = NULL; + } + return NEW TrTargeted(id, card, tc, fromTc, 0); + } + int who = 0; if (s.find("my") != string::npos) who = 1; @@ -420,21 +702,25 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int found = s.find(Constants::MTGPhaseCodeNames[i]); if (found != string::npos) { - return NEW TriggerNextPhase(id, card, target, i, who); + return NEW TriggerNextPhase(id, card, target, i, who,sourceUntapped); } } } //Each Time... - found = magicText.find("each"); + found = s.find("each"); if (found != string::npos) { for (int i = 0; i < Constants::NB_MTG_PHASES; i++) { - found = magicText.find(Constants::MTGPhaseCodeNames[i]); + found = s.find(Constants::MTGPhaseCodeNames[i]); + //this was set to magicText.find which is not limitiing + //to the triggers text. i changed it to s.find. it is now possible to use "draw:" + //as before it was simply returning phase 3 since it found "draw" in the magic text BEFORE + //it was able to find secondmain. if (found != string::npos) { - return NEW TriggerAtPhase(id, card, target, i, who); + return NEW TriggerAtPhase(id, card, target, i, who,sourceUntapped,sourceTap,lifelost,lifeamount); } } } @@ -446,6 +732,8 @@ int AbilityFactory::parseRestriction(string s) { if (s.find("myturnonly") != string::npos) return ActivatedAbility::PLAYER_TURN_ONLY; + if (s.find("opponentturnonly") != string::npos) + return ActivatedAbility::OPPONENT_TURN_ONLY; if (s.find("assorcery") != string::npos) return ActivatedAbility::AS_SORCERY; @@ -604,7 +892,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG ae->tc = tc; return ae; } - if (tc) return NEW GenericTargetAbility(id, card, tc, a, cost, doTap, limit, restrictions, dest); return NEW GenericActivatedAbility(id, card, a, cost, doTap, limit, restrictions, dest); @@ -640,7 +927,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG costType = ManaCost::MANA_PAID_WITH_FLASHBACK; keyword = Constants::kFlashBackKeyword; } - + if (s.find(Constants::kMorphKeyword) == 0) + { + costType = ManaCost::MANA_PAID_WITH_MORPH; + keyword = Constants::kMorphKeyword; + } + if ((costType > -1) && (!keyword.empty())) { if (spell && spell->FullfilledAlternateCost(costType)) @@ -682,7 +974,106 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG a1 = NEW GenericActivatedAbility(id, card, a1, NULL); return NEW MayAbility(id, a1, card, true); } + + //Upkeep Cost + found = s.find("upcostmulti"); + if (found != string::npos) + { + bool Cumulative = false; + size_t cumulative = s.find("cumulativeupcost"); + if(cumulative != string::npos) + Cumulative = true; + size_t start = s.find("["); + size_t end = s.find("]", start); + string s1 = s.substr(start + 1, end - start - 1); + size_t seperator = s1.find(";"); + int phase = Constants::MTG_PHASE_UPKEEP; + int once = 0; + if (seperator != string::npos) + { + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + if (s1.find("next") != string::npos) + once = 1; + if (s1.find(Constants::MTGPhaseCodeNames[i]) != string::npos) + { + phase = i; + } + } + s1 = s1.substr(0, seperator - 1); + } + ManaCost * cost = ManaCost::parseManaCost(s1); + if (!cost) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + return NULL; + } + + string sAbility = s.substr(end + 1); + MTGAbility * a = parseMagicLine(sAbility, id, spell, card); + + if (!a) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + delete (cost); + return NULL; + } + + return NEW AUpkeep(id, card, a, cost, doTap, restrictions, phase, once,Cumulative); + } + + //Phase based actions + found = s.find("phaseactionmulti"); + if (found != string::npos) + { + size_t start = s.find("["); + size_t end = s.find("]", start); + string s1 = s.substr(start + 1, end - start - 1); + int phase = Constants::MTG_PHASE_UPKEEP; + + if (s1.find("combatends") != string::npos) + { + phase = Constants::MTG_PHASE_COMBATEND; + } + if (s1.find("endofturn") != string::npos) + { + phase = Constants::MTG_PHASE_ENDOFTURN; + } + if (s1.find("cleanup") != string::npos) + { + phase = Constants::MTG_PHASE_CLEANUP; + } + if (s1.find("secondmain") != string::npos) + { + phase = Constants::MTG_PHASE_SECONDMAIN; + } + bool sourceinPlay = false; + if (s1.find(",sourceinplay") != string::npos) + { + sourceinPlay = true; + } + bool next = true; + if (s1.find(",next") != string::npos) + { + next = false; + } + string sAbility = s.substr(end + 1); + MTGAbility * a = parseMagicLine(sAbility, id, spell, card); + + if (!a) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + return NULL; + } + MTGCardInstance * _target = NULL; + if (spell) + _target = spell->getNextCardTarget(); + if(!_target) + _target = target; + return NEW APhaseActionGeneric(id, card,_target, a, doTap, restrictions, phase,sourceinPlay,next); + } + //Multiple abilities for ONE cost found = s.find("&&"); if (found != string::npos) @@ -699,6 +1090,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return multi; } + //rather dirty way to stop thises and lords from conflicting with each other. size_t lord = string::npos; for (size_t j = 0; j < kLordKeywordsCount; ++j) @@ -869,11 +1261,11 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG found = s.find(" >"); if (found != string::npos) - mini = atoi(s.substr(found + 2, 1).c_str()); + mini = atoi(s.substr(found + 2, 3).c_str()); found = s.find(" <"); if (found != string::npos) - maxi = atoi(s.substr(found + 2, 1).c_str()); + maxi = atoi(s.substr(found + 2, 3).c_str()); switch (i) { @@ -916,11 +1308,233 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG } SAFE_DELETE(tc); + + //dynamic ability builder + found = s.find("dynamicability", start); + string s1 = s.substr(start + 2, end - start - 2); + int type = 0; + int effect = 0; + int who = 0; + int amountsource = 0; - //Upkeep Cost + size_t abilityamountsource = s1.find("source"); + if (abilityamountsource != string::npos) + { + amountsource = 1; + } + abilityamountsource = s1.find("mytgt"); + if (abilityamountsource != string::npos) + { + amountsource = 2; + } + abilityamountsource = s1.find("myself"); + if (abilityamountsource != string::npos) + { + amountsource = 3; + } + abilityamountsource = s1.find("myfoe"); + if (abilityamountsource != string::npos) + { + amountsource = 4; + } + //what will be main variable used or type + size_t abilitytype = s1.find("power"); + if (abilitytype != string::npos) + { + type = 0; + } + abilitytype = s1.find("toughness"); + if (abilitytype != string::npos) + { + type = 1; + } + abilitytype = s1.find("manacost"); + if (abilitytype != string::npos) + { + type = 2; + } + abilitytype = s1.find("colors"); + if (abilitytype != string::npos) + { + type = 3; + } + abilitytype = s1.find("age"); + if (abilitytype != string::npos) + { + type = 4; + } + abilitytype = s1.find("charge"); + if (abilitytype != string::npos) + { + type = 5; + } + + abilitytype = s1.find("oneonecounters"); + if (abilitytype != string::npos) + { + type = 6; + } + abilitytype = s1.find("thatmuch"); + if (abilitytype != string::npos) + { + type = 7; + } + //what the effect will be + size_t abilityeffect = s1.find("strike"); + if (abilityeffect != string::npos) + { + effect = 0; + } + abilityeffect = s1.find("draw"); + if (abilityeffect != string::npos) + { + effect = 1; + } + abilityeffect = s1.find("lifeloss"); + if (abilityeffect != string::npos) + { + effect = 6; + } + abilityeffect = s1.find("lifegain"); + if (abilityeffect != string::npos) + { + effect = 2; + } + abilityeffect = s1.find("pumppow"); + if (abilityeffect != string::npos) + { + effect = 3; + } + abilityeffect = s1.find("pumptough"); + if (abilityeffect != string::npos) + { + effect = 4; + } + abilityeffect = s1.find("pumpboth"); + if (abilityeffect != string::npos) + { + effect = 5; + } + abilityeffect = s1.find("deplete"); + if (abilityeffect != string::npos) + { + effect = 7; + } + abilityeffect = s1.find("countersoneone"); + if (abilityeffect != string::npos) + { + effect = 8; + } + //what the target will be + size_t abilitywho = s1.find("eachother"); + if (abilitywho != string::npos) + { + who = 1; + } + abilitywho = s1.find("itself"); + if (abilitywho != string::npos) + { + who = 2; + } + abilitywho = s1.find("targetcontroller"); + if (abilitywho != string::npos) + { + who = 3; + } + + abilitywho = s1.find("targetopponent"); + if (abilitywho != string::npos) + { + who = 4; + } + abilitywho = s1.find("tosrc"); + if (abilitywho != string::npos) + { + who = 5; + } + abilitywho = s1.find("srccontroller"); + if (abilitywho != string::npos) + { + who = 6; + } + abilitywho = s1.find("srcopponent"); + if (abilitywho != string::npos) + { + who = 7; + } + string sAbility = s.substr(end + 1); + MTGAbility * stored = NULL; + if(!sAbility.empty()) + { + stored = parseMagicLine(sAbility, id, spell, card); + } + MTGAbility * a = NEW AADYNAMIC(id, card, target,type,effect,who,amountsource,stored); + a->oneShot = 1; + return a; + } + //Phase based actions + found = s.find("phaseaction"); + if (found != string::npos) + { + size_t start = s.find("["); + size_t end = s.find("]", start); + string s1 = s.substr(start + 1, end - start - 1); + int phase = Constants::MTG_PHASE_UPKEEP; + + if (s1.find("combatends") != string::npos) + { + phase = Constants::MTG_PHASE_COMBATEND; + } + if (s1.find("endofturn") != string::npos) + { + phase = Constants::MTG_PHASE_ENDOFTURN; + } + if (s1.find("cleanup") != string::npos) + { + phase = Constants::MTG_PHASE_CLEANUP; + } + if (s1.find("secondmain") != string::npos) + { + phase = Constants::MTG_PHASE_SECONDMAIN; + } + bool sourceinPlay = false; + if (s1.find(",sourceinplay") != string::npos) + { + sourceinPlay = true; + } + bool next = true; + if (s1.find(",next") != string::npos) + { + next = false; + } + string sAbility = s.substr(end + 1); + MTGAbility * a = parseMagicLine(sAbility, id, spell, card); + + if (!a) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + return NULL; + } + MTGCardInstance * _target = NULL; + if (spell) + _target = spell->getNextCardTarget(); + if(!_target) + _target = target; + return NEW APhaseActionGeneric(id, card,_target, a, doTap, restrictions, phase,sourceinPlay,next); + } + + //Upkeep Cost found = s.find("upcost"); if (found != string::npos) { + bool Cumulative = false; + size_t cumulative = s.find("cumulativeupcost"); + if(cumulative != string::npos) + Cumulative = true; size_t start = s.find("["); size_t end = s.find("]", start); string s1 = s.substr(start + 1, end - start - 1); @@ -958,7 +1572,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return NULL; } - return NEW AUpkeep(id, card, a, cost, doTap, restrictions, phase, once); + return NEW AUpkeep(id, card, a, cost, doTap, restrictions, phase, once,Cumulative); } //Cycling @@ -988,6 +1602,28 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } + //momentary blink + found = s.find("(blink)"); + if (found != string::npos) + { + bool ueoteffect = false; + bool forsource = false; + bool blinkhand = false; + size_t blinkueot = s.find("(blink)ueot"); + if(blinkueot != string::npos) + ueoteffect = true; + size_t blinksrc = s.find("(blink)forsrc"); + if(blinksrc != string::npos) + forsource = true; + size_t hblink = s.find("hand(blink)"); + if(hblink != string::npos) + blinkhand = true; + MTGAbility * a = NEW ABlinkGeneric(id, card, target,ueoteffect,forsource,blinkhand); + a->oneShot = 1; + return a; + } + + //Fizzle (counterspell...) found = s.find("fizzle"); if (found != string::npos) @@ -1008,15 +1644,27 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG a->oneShot = 1; return a; } - + bool aLivingWeapon = false; + //livingweapon + size_t secondaryFound = s.find("livingweapon"); + if (secondaryFound != string::npos) + { + aLivingWeapon = true; + } //Token creator. Name, type, p/t, abilities found = s.find("token("); if (found != string::npos) { WParsedInt * multiplier = NULL; size_t star = s.find("*"); + string starfound = ""; if (star != string::npos) - multiplier = NEW WParsedInt(s.substr(star + 1), spell, card); + { + starfound = s.substr(star + 1); + size_t starEnd= starfound.find_first_of(" "); + starfound = starfound.substr(0,starEnd); + multiplier = NEW WParsedInt(starfound, spell, card); + } size_t end = s.find(")", found); int tokenId = atoi(s.substr(found + 6, end - found - 6).c_str()); int who; @@ -1029,19 +1677,24 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG { who = 0; } + size_t targetcontroller = s.find("targetcontroller"); + if (targetcontroller != string::npos) + { + who = 2; + } if (tokenId) { MTGCard * safetycard = GameApp::collection->getCardById(tokenId); if (safetycard) {//contenue - ATokenCreator * tok = NEW ATokenCreator(id, card, NULL, tokenId, 0, multiplier, who); + ATokenCreator * tok = NEW ATokenCreator(id, card,target, NULL, tokenId, 0, starfound, multiplier, who); tok->oneShot = 1; return tok; } else { tokenId = 0; - ATokenCreator * tok = NEW ATokenCreator(id, card, NULL, "ID NOT FOUND", "ERROR ID", NULL, NULL, "", 0, NULL); + ATokenCreator * tok = NEW ATokenCreator(id, card,target, NULL, "ID NOT FOUND", "ERROR ID", NULL, NULL, "", 0, NULL); return tok; } } @@ -1077,10 +1730,15 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG who = 0; } } - ATokenCreator * tok = NEW ATokenCreator(id, card, NULL, sname, stypes, power + value, toughness + value, sabilities, 0, - multiplier, who); + targetcontroller = s.find("targetcontroller"); + if (targetcontroller != string::npos) + { + who = 2; + } + ATokenCreator * tok = NEW ATokenCreator(id, card,target, NULL, sname, stypes, power + value, toughness + value, sabilities, 0,starfound, + multiplier, who,aLivingWeapon); tok->oneShot = 1; - return tok; + return tok; } //name an ability line @@ -1093,6 +1751,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG ANamer * tok = NEW ANamer(id, card, NULL, sname, 0); return tok; } +//living weapon //Equipment found = s.find("equip"); @@ -1101,7 +1760,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG MTGAbility * a = NEW AEquip(id, card); return a; } - + //Equipment (attach) found = s.find("attach"); if (found != string::npos) @@ -1136,7 +1795,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG a->oneShot = 1; return a; } - + //imprint + found = s.find("phaseout"); + if (found != string::npos) + { + MTGAbility * a = NEW AAPhaseOut(id, card, target); + a->oneShot = 1; + return a; + } //clone found = s.find("clone"); if (found != string::npos) @@ -1342,7 +2008,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG Targetable * t = NULL; if (spell) t = spell->getNextTarget(); - MTGAbility * a = NEW AADamager(id, card, t, damage, NULL, 0, who); + MTGAbility * a = NEW AADamager(id, card, t,damage, d, NULL, 0, who); a->oneShot = 1; return a; } @@ -1438,7 +2104,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG Targetable * t = NULL; if (spell) t = spell->getNextTarget(); - MTGAbility * a = NEW AALifer(id, card, t, life, NULL, 0, who); + MTGAbility * a = NEW AALifer(id, card, t,life_s, life, NULL, 0, who); a->oneShot = 1; return a; } @@ -1474,7 +2140,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG Targetable * t = NULL; if (spell) t = spell->getNextTarget(); - MTGAbility * a = NEW AADrawer(id, card, t, NULL, nbcards, 0, who); + MTGAbility * a = NEW AADrawer(id, card, t, NULL,nbcards ,nbcardsStr, 0, who); a->oneShot = 1; return a; } @@ -1508,20 +2174,20 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG { size_t start = s.find(":", found); size_t end = s.find(" ", start); - int nbcards; + string nbcardsStr; if (end != string::npos) { - nbcards = atoi(s.substr(start + 1, end - start - 1).c_str()); + nbcardsStr = s.substr(start + 1, end - start - 1); } else { - nbcards = atoi(s.substr(start + 1).c_str()); + nbcardsStr = s.substr(start + 1); } - + WParsedInt * nbcards = NEW WParsedInt(nbcardsStr, spell, card); Targetable * t = NULL; if (spell) t = spell->getNextTarget(); - MTGAbility * a = NEW AADepleter(id, card, t, nbcards, NULL, 0, who); + MTGAbility * a = NEW AADepleter(id, card, t,nbcards ,nbcardsStr, NULL, 0, who); a->oneShot = 1; return a; } @@ -1578,20 +2244,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG { size_t start = s.find(":", found); size_t end = s.find(" ", start); - int nbcards; + string nbcardsStr; if (end != string::npos) { - nbcards = atoi(s.substr(start + 1, end - start - 1).c_str()); + nbcardsStr = s.substr(start + 1, end - start - 1); } else { - nbcards = atoi(s.substr(start + 1).c_str()); + nbcardsStr = s.substr(start + 1); } + WParsedInt * nbcards = NEW WParsedInt(nbcardsStr, spell, card); Targetable * t = NULL; if (spell) t = spell->getNextPlayerTarget(); - MTGAbility * a = NEW AARandomDiscarder(id, card, t, nbcards, NULL, 0, who); + MTGAbility * a = NEW AARandomDiscarder(id, card, t, nbcards,nbcardsStr, NULL, 0, who); a->oneShot = 1; return a; } @@ -1610,7 +2277,25 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG } return NULL; } - + + //flanking + found = s.find("flanker"); + if (found != string::npos) + { + return NEW AFlankerAbility(id, card); + } + //combat damage spirit link + found = s.find("combatspiritlink"); + if (found != string::npos) + { + return NEW ASpiritLinkAbility(id, card,true); + } + //spirit link + found = s.find("spiritlink"); + if (found != string::npos) + { + return NEW ASpiritLinkAbility(id, card); + } //bushido found = s.find("bushido("); if (found != string::npos) @@ -1636,13 +2321,41 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG if (counter) { MTGAbility * a = - NEW AACounter(id, card, target, counter->name.c_str(), counter->power, counter->toughness, counter->nb); + NEW AACounter(id, card, target,counterString, counter->name.c_str(), counter->power, counter->toughness, counter->nb); delete (counter); a->oneShot = 1; return a; } return NULL; } + + //removes all counters of the specifified type. + found = s.find("removeallcounters("); + if (found != string::npos) + { + size_t start = s.find("("); + size_t end = s.find(")"); + string counterString = s.substr(start + 1, end - start - 1); + if(counterString.find("all") != string::npos) + { + bool all = true; + MTGAbility * a = + NEW AARemoveAllCounter(id, card, target, "All", 0, 0, 1,all); + a->oneShot = 1; + return a; + } + Counter * counter = parseCounter(counterString, target, spell); + if (counter) + { + MTGAbility * a = + NEW AARemoveAllCounter(id, card, target, counter->name.c_str(), counter->power, counter->toughness, counter->nb,false); + delete (counter); + a->oneShot = 1; + return a; + } + return NULL; + } + //Becomes... (animate artifact...: becomes(Creature, manacost/manacost) found = s.find("becomes("); if (found != string::npos) @@ -1725,21 +2438,41 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG string transformsParamsString = s.substr(stypesStartIndex, real_end - stypesStartIndex); vector effectParameters = split( transformsParamsString, ','); string stypes = effectParameters[0]; - + string sabilities = transformsParamsString.substr(stypes.length()); + bool newpowerfound = false; + int newpower = 0; + size_t powerability = sabilities.find("setpower="); + if(sabilities.find(",setpower=") != string::npos) + { + newpowerfound = true; + int powerstart = s.find("setpower=", powerability); + int powerend = s.find(real_end, powerstart); + newpower = atoi(s.substr(powerstart + 9).c_str()); + } + bool newtoughnessfound = false; + int newtoughness = 0; + size_t toughnessability = sabilities.find("settoughness="); + if(sabilities.find(",settoughness=") != string::npos) + { + newtoughnessfound = true; + int toughnessstart = s.find("settoughness=", toughnessability); + int toughnessend = s.find(real_end, toughnessstart); + newtoughness = atoi(s.substr(toughnessstart + 13).c_str()); + } MTGAbility * a; if (forceFOREVER) { - a = NEW ATransformerFOREVER(id, card, target, stypes, sabilities); + a = NEW ATransformerFOREVER(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound); } else if (forceUEOT) { - a = NEW ATransformerUEOT(id, card, target, stypes, sabilities); + a = NEW ATransformerUEOT(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound); } else { - a = NEW ATransformer(id, card, target, stypes, sabilities); + a = NEW ATransformer(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound); } return a; } @@ -1827,7 +2560,34 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG a->oneShot = 1; return a; } - + + //get a new target + found = s.find("newtarget"); + if (found != string::npos) + { + MTGAbility * a = NEW AANewTarget(id, card, target); + a->oneShot = 1; + return a; + } + + //morph + found = s.find("morph"); + if (found != string::npos) + { + MTGAbility * a = NEW AAMorph(id, card, target); + a->oneShot = 1; + return a; + } + + //eradicate + found = s.find("eradicate"); + if (found != string::npos) + { + MTGAbility * a = NEW AAEradicate(id, card, target,1); + a->oneShot = 1; + return a; + } + //identify what a leveler creature will max out at. found = s.find("maxlevel:"); if (found != string::npos) @@ -1863,9 +2623,23 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG found = s.find(Constants::MTGBasicAbilities[j]); if (found == 0 || found == 1) { - int modifier = 1; + int modifier = 0; + if(s.find("absorb") || s.find("flanking")) + { + modifier += 1; + } + else + { + modifier = 1; + } if (found > 0 && s[found - 1] == '-') + { modifier = 0; + } + else if(found > 0 && s[found - 1] == '-' && (s.find("absorb") || s.find("flanking"))) + { + modifier -= 1; + } if (!activated) { if (card->hasType("instant") || card->hasType("sorcery") || forceUEOT) @@ -1979,7 +2753,7 @@ int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, Targ if (AALifer * abi = dynamic_cast(a)) return abi->life > 0 ? BAKA_EFFECT_GOOD : BAKA_EFFECT_BAD; if (AAAlterPoison * abi = dynamic_cast(a)) - return abi->poison < 0 ? BAKA_EFFECT_GOOD : BAKA_EFFECT_BAD; + return abi->poison > 0 ? BAKA_EFFECT_GOOD : BAKA_EFFECT_BAD; if (dynamic_cast (a)) return BAKA_EFFECT_BAD; if (dynamic_cast (a)) @@ -2033,6 +2807,7 @@ int AbilityFactory::computeX(Spell * spell, MTGCardInstance * card) { if (spell) return spell->computeX(card); + if(card) return card->X; return 0; } @@ -2041,6 +2816,7 @@ int AbilityFactory::computeXX(Spell * spell, MTGCardInstance * card) { if (spell) return spell->computeXX(card); + if(card) return card->XX; return 0; } @@ -2055,6 +2831,8 @@ int AbilityFactory::getAbilities(vector * v, Spell * spell, MTGCar if (!target) target = card; string magicText; + card->graveEffects = false; + card->exileEffects = false; if (dest) { GameObserver * g = GameObserver::GetInstance(); @@ -2069,6 +2847,7 @@ int AbilityFactory::getAbilities(vector * v, Spell * spell, MTGCar if (dest == zones->graveyard) { magicText = card->magicTexts["graveyard"]; + card->graveEffects = true; break; } if (dest == zones->stack) @@ -2079,6 +2858,7 @@ int AbilityFactory::getAbilities(vector * v, Spell * spell, MTGCar if (dest == zones->exile) { magicText = card->magicTexts["exile"]; + card->exileEffects = true; break; } if (dest == zones->library) @@ -2092,7 +2872,48 @@ int AbilityFactory::getAbilities(vector * v, Spell * spell, MTGCar } else { - magicText = card->magicText; + if(card->previous && card->previous->morphed && !card->turningOver) + { + magicText = card->magicTexts["facedown"]; + card->power = 2; + card->life = 2; + card->toughness = 2; + card->setColor(0,1); + card->name = ""; + card->types.clear(); + string cre = "Creature"; + card->setType(cre.c_str()); + card->basicAbilities.clear(); + card->getManaCost()->remove(0,100); + card->getManaCost()->remove(1,100); + card->getManaCost()->remove(2,100); + card->getManaCost()->remove(3,100); + card->getManaCost()->remove(4,100); + card->getManaCost()->remove(5,100); + } + else if(card && !card->morphed && card->turningOver) + { + card->power += card->origpower-2; + card->life += card->origtoughness-2; + card->toughness += card->origtoughness-2; + card->setColor(0,1); + card->name = card->model->data->name; + card->types = card->model->data->types; + for (int i = 0; i < Constants::MTG_NB_COLORS; ++i) + card->colors[i] = card->model->data->colors[i]; + card->basicAbilities = card->model->data->basicAbilities; + ManaCost * copyCost = card->model->data->getManaCost(); + card->getManaCost()->copy(copyCost); + magicText = card->model->data->magicText; + string faceupC= card->magicTexts["faceup"]; + magicText.append("\n"); + magicText.append(faceupC); + + } + else + { + magicText = card->magicText; + } } if (card->alias && magicText.size() == 0 && !dest) { @@ -2453,6 +3274,11 @@ void AbilityFactory::addAbilities(int _id, Spell * spell) if (target->life < x) x = target->life; game->currentlyActing()->life += x; + game->currentlyActing()->thatmuch = x; + WEvent * lifed = NULL; + lifed = NEW WEventLife(game->currentlyActing(),x); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); break; } case 1159: //Erg Raiders @@ -2664,6 +3490,11 @@ void AbilityFactory::addAbilities(int _id, Spell * spell) { game->players[i]->game->putInGraveyard(current); current->controller()->life += current->getManaCost()->getConvertedCost(); + current->controller()->thatmuch = current->getManaCost()->getConvertedCost(); + WEvent * lifed = NULL; + lifed = NEW WEventLife(current->controller(),current->getManaCost()->getConvertedCost()); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); } } } @@ -2777,6 +3608,11 @@ void AbilityFactory::addAbilities(int _id, Spell * spell) player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); } game->currentlyActing()->life += x; + game->currentlyActing()->thatmuch = x; + WEvent * lifed = NULL; + lifed = NEW WEventLife(game->currentlyActing(),x); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); break; } @@ -2946,6 +3782,7 @@ int MTGAbility::removeFromGame() //returns 1 if this ability needs to be removed from the list of active abilities int MTGAbility::testDestroy() { +GameObserver * g=g->GetInstance(); if (game->mLayers->stackLayer()->has(this)) return 0; if (waitingForAnswer) @@ -2954,6 +3791,10 @@ int MTGAbility::testDestroy() return 1; if (forceDestroy == -1) return 0; + if(source->graveEffects && game->isInGrave(source)) + return 0; + if(source->exileEffects && game->isInExile(source)) + return 0; if (!game->isInPlay(source)) return 1; if (target && !game->isInPlay((MTGCardInstance *) target)) @@ -2966,7 +3807,6 @@ int MTGAbility::fireAbility() game->mLayers->stackLayer()->addAbility(this); return 1; } - ostream& MTGAbility::toString(ostream& out) const { return out << "MTGAbility ::: menuText : " << menuText << " ; game : " << game << " ; forceDestroy : " << forceDestroy @@ -2988,7 +3828,9 @@ ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _c } int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) -{ +{ + if(card->isPhased) + return 0; Player * player = game->currentlyActing(); int cPhase = game->getCurrentGamePhase(); switch (restrictions) @@ -2997,6 +3839,9 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (player != game->currentPlayer) return 0; break; + case OPPONENT_TURN_ONLY: + if (player == game->currentPlayer) + return 0; case AS_SORCERY: if (player != game->currentPlayer) return 0; @@ -3186,6 +4031,8 @@ int TargetAbility::reactToClick(MTGCardInstance * card) { waitingForAnswer = 0; game->mLayers->actionLayer()->setCurrentWaitingAction(NULL); + WEvent * e = NEW WEventTarget(card,source); + game->receiveEvent(e); } return result; } @@ -3330,7 +4177,9 @@ void ListMaintainerAbility::updateTargets() { MTGCardInstance * card = (*it).first; if (!canBeInList(card)) + { temp[card] = true; + } } for (map::iterator it = temp.begin(); it != temp.end(); ++it) @@ -3418,8 +4267,8 @@ ostream& ListMaintainerAbility::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } -TriggerAtPhase::TriggerAtPhase(int id, MTGCardInstance * source, Targetable * target, int _phaseId, int who) : - TriggeredAbility(id, source, target), phaseId(_phaseId), who(who) +TriggerAtPhase::TriggerAtPhase(int id, MTGCardInstance * source, Targetable * target, int _phaseId, int who, bool sourceUntapped, bool sourceTap,bool lifelost,int lifeamount) : + TriggeredAbility(id, source, target), phaseId(_phaseId), who(who), sourceUntapped(sourceUntapped), sourceTap(sourceTap),lifelost(lifelost),lifeamount(lifeamount) { GameObserver * g = GameObserver::GetInstance(); if (g) @@ -3427,16 +4276,25 @@ TriggerAtPhase::TriggerAtPhase(int id, MTGCardInstance * source, Targetable * ta newPhase = g->getCurrentGamePhase(); currentPhase = newPhase; } -} + } -int TriggerAtPhase::trigger() -{ - if (testDestroy()) - return 0; // http://code.google.com/p/wagic/issues/detail?id=426 - GameObserver * g = GameObserver::GetInstance(); - int result = 0; - if (currentPhase != newPhase && newPhase == phaseId) + int TriggerAtPhase::trigger() { + if(source->isPhased) return 0; + if(lifelost == true && source->controller()->opponent()->lifeLostThisTurn < lifeamount) + { + return 0; + } + if (sourceUntapped == true && source->isTapped() == 1) + return 0; + if (sourceTap == true && !source->isTapped()) + return 0; + if (testDestroy()) + return 0; // http://code.google.com/p/wagic/issues/detail?id=426 + GameObserver * g = GameObserver::GetInstance(); + int result = 0; + if (currentPhase != newPhase && newPhase == phaseId) + { result = 0; switch (who) { @@ -3475,8 +4333,8 @@ TriggerAtPhase* TriggerAtPhase::clone() const return a; } -TriggerNextPhase::TriggerNextPhase(int id, MTGCardInstance * source, Targetable * target, int _phaseId, int who) : - TriggerAtPhase(id, source, target, _phaseId, who) +TriggerNextPhase::TriggerNextPhase(int id, MTGCardInstance * source, Targetable * target, int _phaseId, int who,bool sourceUntapped, bool sourceTap) : + TriggerAtPhase(id, source, target, _phaseId, who, sourceUntapped, sourceTap) { destroyActivated = 0; } @@ -3592,6 +4450,7 @@ void GenericTriggeredAbility::Update(float dt) int GenericTriggeredAbility::resolve() { + if(source->isPhased) return 0; if (targets.size()) { setTriggerTargets(targets.front(), ability); @@ -3659,7 +4518,7 @@ int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana) if (!mana) mana = game->currentlyActing()->getManaPool(); if (_card == source && (!tap || !source->isTapped()) && game->currentlyActing()->game->inPlay->hasCard(source) - && (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness())) + && (source->hasType(Subtypes::TYPE_LAND) || !tap || !source->hasSummoningSickness()) && !source->isPhased) { if (!cost || mana->canAfford(cost)) { diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 95ed1fecf..27468015e 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -31,6 +31,8 @@ MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to model = card; attacker = 0; lifeOrig = life; + origpower = power; + origtoughness = toughness; belongs_to = arg_belongs_to; owner = NULL; if (arg_belongs_to) @@ -69,7 +71,6 @@ void MTGCardInstance::copy(MTGCardInstance * card) toughness = data->toughness; life = toughness; lifeOrig = life; - magicText = data->magicText; spellTargetType = data->spellTargetType; alias = data->alias; @@ -109,6 +110,7 @@ void MTGCardInstance::initMTGCI() { sample = ""; model = NULL; + imprint = NULL; isToken = false; lifeOrig = 0; doDamageTest = 1; @@ -117,11 +119,29 @@ void MTGCardInstance::initMTGCI() untapping = 0; frozen = 0; fresh = 0; + isMultiColored = 0; + isBlackAndWhite = 0; + isRedAndBlue = 0; + isBlackAndGreen = 0; + isBlueAndGreen = 0; + isRedAndWhite = 0; + isLeveler = 0; + enchanted = false; + CDenchanted = NULL; + blinked = false; + isExtraCostTarget = false; + morphed = false; + turningOver = false; + isMorphed = false; + isPhased = false; + isTempPhased = false; + phasedTurn = -1; didattacked = 0; didblocked = 0; notblocked = 0; sunburst = NULL; - equipment = NULL; + equipment = 0; + auras = 0; for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++) alternateCostPaid[i] = 0; @@ -161,13 +181,39 @@ void MTGCardInstance::initMTGCI() s == "Dismiss" || s == "Equipment" || s == "Everglades" || s == "Grasslands" || s == "Lair" || s == "Level" || s == "Levelup" || s == "Mine" || s == "Oasis" || s == "World" || s == "Aura" ) - continue; + continue; addType(i); } } } - + int colored = 0; + + for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i) + { + if (this->hasColor(i)) + ++colored; + } + if(colored > 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 == true && !turningOver) + { + morphed = true; + isMorphed = true; + } } const string MTGCardInstance::getDisplayName() const @@ -529,6 +575,10 @@ int MTGCardInstance::canBlock(MTGCardInstance * opponent) return 0; if (opponent->basicAbilities[Constants::ONEBLOCKER] && opponent->blocked) return 0; + if(opponent->basicAbilities[Constants::STRONG] && power < opponent->power) + return 0; + if(has(basicAbilities[Constants::WEAK]) && power < opponent->power) + return 0; if (opponent->basicAbilities[Constants::FEAR] && !(hasType(Subtypes::TYPE_ARTIFACT) || hasColor(Constants::MTG_COLOR_BLACK))) return 0; @@ -572,6 +622,24 @@ int MTGCardInstance::canBlock(MTGCardInstance * opponent) return 0; if (opponent->basicAbilities[Constants::PLAINSWALK] && controller()->game->inPlay->hasType("plains")) return 0; + if (opponent->basicAbilities[Constants::LEGENDARYWALK] && controller()->game->inPlay->hasPrimaryType("legendary","land")) + return 0; + if (opponent->basicAbilities[Constants::DESERTWALK] && controller()->game->inPlay->hasSpecificType("land","desert")) + return 0; + if (opponent->basicAbilities[Constants::SNOWSWAMPWALK] && controller()->game->inPlay->hasSpecificType("snow","swamp")) + return 0; + if (opponent->basicAbilities[Constants::SNOWFORESTWALK] && controller()->game->inPlay->hasSpecificType("snow","forest")) + return 0; + if (opponent->basicAbilities[Constants::SNOWISLANDWALK] && controller()->game->inPlay->hasSpecificType("snow","island")) + return 0; + if (opponent->basicAbilities[Constants::SNOWMOUNTAINWALK] && controller()->game->inPlay->hasSpecificType("snow","mountain")) + return 0; + if (opponent->basicAbilities[Constants::SNOWPLAINSWALK] && controller()->game->inPlay->hasSpecificType("snow","plains")) + return 0; + if (opponent->basicAbilities[Constants::SNOWWALK] && controller()->game->inPlay->hasPrimaryType("snow","land")) + return 0; + if (opponent->basicAbilities[Constants::NONBASICWALK] && controller()->game->inPlay->hasTypeButNotType("land","basic")) + return 0; return 1; } diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index d3e15e0d1..43c4eee57 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -138,12 +138,21 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi case 'o': //othercost if (!primitive) primitive = NEW CardPrimitive(); + if(key[5] == 'r')//otherrestrictions + { + string value = val; + primitive->setOtherRestrictions(value); + + } + else + { if (ManaCost * cost = primitive->getManaCost()) { string value = val; std::transform(value.begin(), value.end(), value.begin(), ::tolower); cost->alternative = ManaCost::parseManaCost(value); } + } break; case 'b': //buyback @@ -155,16 +164,26 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi cost->BuyBack = ManaCost::parseManaCost(value); } break; - case 'f': //flashback - if (!primitive) primitive = NEW CardPrimitive(); - if (ManaCost * cost = primitive->getManaCost()) + case 'f': //flashback//morph { - string value = val; - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - cost->FlashBack = ManaCost::parseManaCost(value); + if (!primitive) primitive = NEW CardPrimitive(); + if(ManaCost * cost = primitive->getManaCost()) + { + if( s.find("facedown") != string::npos)//morph + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->morph = ManaCost::parseManaCost(value); + } + else + { + string value = val; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + cost->FlashBack = ManaCost::parseManaCost(value); + } + } + break; } - break; - case 'i': //id if (!card) card = NEW MTGCard(); card->setMTGId(atoi(val)); @@ -200,7 +219,61 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi break; case 'r': //retrace/rarity - if ('e' == key[1]) + if('s' == key[2])//restrictions + { + if (!primitive) primitive = NEW CardPrimitive(); + string value = val; + primitive->setRestrictions(CardPrimitive::NO_RESTRICTION); + primitive->hasRestriction = false; + if (value.find("control two or more vampires") != string::npos) + primitive->setRestrictions(CardPrimitive::VAMPIRES); + if (value.find("control less creatures") != string::npos) + primitive->setRestrictions(CardPrimitive::LESS_CREATURES); + if (value.find("control snow land") != string::npos) + primitive->setRestrictions(CardPrimitive::SNOW_LAND_INPLAY); + if (value.find("casted a spell") != string::npos) + primitive->setRestrictions(CardPrimitive::CASTED_A_SPELL); + if (value.find("one of a kind") != string::npos) + primitive->setRestrictions(CardPrimitive::ONE_OF_AKIND); + if (value.find("fourth turn") != string::npos) + primitive->setRestrictions(CardPrimitive::FOURTHTURN); + if (value.find("before battle damage") != string::npos) + primitive->setRestrictions(CardPrimitive::BEFORECOMBATDAMAGE); + if (value.find("after battle") != string::npos) + primitive->setRestrictions(CardPrimitive::AFTERCOMBAT); + if (value.find("during battle") != string::npos) + primitive->setRestrictions(CardPrimitive::DURINGCOMBAT); + if (value.find("myturnonly") != string::npos) + primitive->setRestrictions(CardPrimitive::PLAYER_TURN_ONLY); + if (value.find("opponentturnonly") != string::npos) + primitive->setRestrictions(CardPrimitive::OPPONENT_TURN_ONLY); + if (value.find("assorcery") != string::npos) + primitive->setRestrictions(CardPrimitive::AS_SORCERY); + string types[] = { "my", "opponent", "" }; + int starts[] = { CardPrimitive::MY_BEFORE_BEGIN, CardPrimitive::OPPONENT_BEFORE_BEGIN, CardPrimitive::BEFORE_BEGIN }; + for (int j = 0; j < 3; ++j) + { + size_t found = value.find(types[j]); + if (found != string::npos) + { + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + string toFind = types[j]; + toFind.append(Constants::MTGPhaseCodeNames[i]).append("only"); + found = value.find(toFind); + if (found != string::npos) + { + if(primitive->hasRestriction == false) + { + primitive->setRestrictions(starts[j] + i); + primitive->hasRestriction = true; + } + } + } + } + } + } + else if ('e' == key[1]) { //retrace if (!primitive) primitive = NEW CardPrimitive(); if (ManaCost * cost = primitive->getManaCost()) diff --git a/projects/mtg/src/MTGDefinitions.cpp b/projects/mtg/src/MTGDefinitions.cpp index abc09c3f7..3f2564772 100644 --- a/projects/mtg/src/MTGDefinitions.cpp +++ b/projects/mtg/src/MTGDefinitions.cpp @@ -24,6 +24,7 @@ const string Constants::kBuyBackKeyword = "buyback"; const string Constants::kFlashBackKeyword = "flashback"; const string Constants::kRetraceKeyword = "retrace"; const string Constants::kKickerKeyword = "kicker"; +const string Constants::kMorphKeyword = "facedown"; const char* Constants::MTGBasicAbilities[] = { "trample", @@ -110,6 +111,18 @@ const char* Constants::MTGBasicAbilities[] = { "sunburst", "flanking", "exiledeath", + "legendarylandwalk", + "desertlandwalk", + "snowforestlandwalk", + "snowplainslandwalk", + "snowmountainlandwalk", + "snowislandlandwalk", + "snowswamplandwalk", + "snowlandwalk", + "nonbasiclandwalk", + "strong",//cant be blocked by creature with less power + "weak",//cant block creatures with more power + "phasing", }; map Constants::MTGBasicAbilitiesMap; diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index c465f50db..70930adad 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -275,6 +275,10 @@ MTGCardInstance * MTGPlayerCards::putInExile(MTGCardInstance * card) { copy = putInZone(card, stack, exile); } + else if (hand->hasCard(card)) + { + copy = putInZone(card, hand, exile); + } else if (graveyard->hasCard(card)) { copy = putInZone(card, graveyard, exile); @@ -325,6 +329,10 @@ MTGCardInstance * MTGPlayerCards::putInHand(MTGCardInstance * card) { copy = putInZone(card, graveyard, hand); } + else if (exile->hasCard(card)) + { + copy = putInZone(card, exile, hand); + } else { copy = putInZone(card, hand, hand); @@ -332,6 +340,33 @@ MTGCardInstance * MTGPlayerCards::putInHand(MTGCardInstance * card) return copy; } +MTGCardInstance * MTGPlayerCards::putInBattlefield(MTGCardInstance * card) +{ + MTGCardInstance * copy = NULL; + MTGInPlay * InPlay = card->owner->game->battlefield; + if (inPlay->hasCard(card)) + { + copy = putInZone(card, inPlay, InPlay); + } + else if (stack->hasCard(card)) + { + copy = putInZone(card, stack, InPlay); + } + else if (graveyard->hasCard(card)) + { + copy = putInZone(card, graveyard, InPlay); + } + else if (exile->hasCard(card)) + { + copy = putInZone(card, exile, InPlay); + } + else + { + copy = putInZone(card, InPlay, InPlay); + } + return copy; +} + MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to) { MTGCardInstance * copy = NULL; @@ -420,7 +455,14 @@ int MTGPlayerCards::isInPlay(MTGCardInstance * card) } return 0; } - +int MTGPlayerCards::isInZone(MTGCardInstance * card,MTGGameZone * zone) +{ + if (zone->hasCard(card)) + { + return 1; + } + return 0; +} //-------------------------------------- // Zones specific code //-------------------------------------- @@ -537,6 +579,54 @@ int MTGGameZone::hasType(const char * value) return 0; } +int MTGGameZone::hasPrimaryType(const char * value,const char * secondvalue) +{ + for (int i = 0; i < (nb_cards); i++) + { + if (cards[i]->hasType(value) && cards[i]->hasType(secondvalue)) + { + return 1; + } + } + return 0; +} + +int MTGGameZone::hasSpecificType(const char * value,const char * secondvalue) +{ + for (int i = 0; i < (nb_cards); i++) + { + if (cards[i]->hasType(value) && cards[i]->hasSubtype(secondvalue)) + { + return 1; + } + } + return 0; +} + +int MTGGameZone::hasTypeButNotType(const char * value,const char * secondvalue) +{ + for (int i = 0; i < (nb_cards); i++) + { + if (cards[i]->hasType(value) && cards[i]->hasSubtype(value) && !cards[i]->hasType(secondvalue) && !cards[i]->hasSubtype(secondvalue)) + { + return 1; + } + } + return 0; +} + +int MTGGameZone::hasName(string value) +{ + for (int i = 0; i < (nb_cards); i++) + { + if (cards[i]->name == value) + { + return 1; + } + } + return 0; +} + int MTGGameZone::hasColor(int value) { for (int i = 0; i < (nb_cards); i++) diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index ec6df5cfb..c31077e0a 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -35,6 +35,8 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) } return 1; } +if(!allowedToCast(card,player)) + return 0; if (card->hasType("land")) { if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay @@ -44,7 +46,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) return 1; } } - else if ((card->hasType("instant")) || card->has(Constants::FLASH) + else if ((card->hasType("instant")) || card->basicAbilities[Constants::FLASH] || (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) @@ -250,6 +252,11 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * if (!alternateManaCost) return 0; + if(!allowedToCast(card,player)) + return 0; + if(!allowedToAltCast(card,player)) + return 0; + if (card->hasType("land")) { if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay @@ -356,7 +363,7 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter if (card->hasType("land")) { - MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp); + MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->temp); spell = NEW Spell(copy); copy->alternateCostPaid[alternateCostType] = 1; spell->resolve(); @@ -368,7 +375,7 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter else { ManaCost *spellCost = previousManaPool->Diff(player->getManaPool()); - MTGCardInstance * copy = player->game->putInZone(card, originatingZone, player->game->stack); + MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack); copy->alternateCostPaid[alternateCostType] = 1; spell = game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, spellCost, payResult, 0); game->targetChooser = NULL; @@ -431,6 +438,8 @@ MTGAlternativeCostRule(_id) int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { Player * player = game->currentlyActing(); + if(!allowedToCast(card,player)) + return 0; if (!player->game->hand->hasCard(card)) return 0; return MTGAlternativeCostRule::isReactingToClick( card, mana, card->getManaCost()->BuyBack ); @@ -584,13 +593,179 @@ MTGRetraceRule * MTGRetraceRule::clone() const //------------------------------------------------------------------------- //------------------------------------------------------------------------- //------------------------------------------------------------------------- -//----------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + +MTGMorphCostRule::MTGMorphCostRule(int _id) : + MTGAbility(_id, NULL) +{ + aType = MTGAbility::MORPH_COST; +} +int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) +{ + int cardsinhand = game->players[0]->game->hand->nb_cards; + Player * player = game->currentlyActing(); + Player * currentPlayer = game->currentPlayer; + if (!player->game->hand->hasCard(card)) + return 0; + if (!card->getManaCost()->morph) + return 0; + if(!allowedToCast(card,player)) + return 0; + if(!allowedToAltCast(card,player)) + return 0; + //note lands can morph too, this is different from other cost types. + if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer + && !game->isInterrupting + && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN + || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) + ) + { + ManaCost * playerMana = player->getManaPool(); + ManaCost * cost = card->getManaCost(); + ManaCost * morph = card->getManaCost()->morph; +#ifdef WIN32 + cost->Dump(); +#endif + if (player->castrestrictedspell == true && !card->hasType("land")) + { + return 0; + } + if (player->onlyonecast == true && player->castcount >= 1) + { + return 0; + } + if (player->nospellinstant == true) + { + return 0; + } + if (player->onlyoneinstant == true) + { + if (player->castcount >= 1) + { + return 0; + } + } + if (player->nocreatureinstant == true && card->hasType("creature")) + { + return 0; + } + if (player->castrestrictedcreature == true && card->hasType("creature")) + { + return 0; + } + //cost of card. + if (morph && playerMana->canAfford(morph)) + { + return 1; + } + } + return 0;//dont play if you cant afford it. +} + +int MTGMorphCostRule::reactToClick(MTGCardInstance * card) +{ +//morphs reactToClick is extremely different then the other cost. + if (!isReactingToClick(card)) + return 0; + Player * player = game->currentlyActing(); + ManaCost * cost = card->getManaCost(); + ManaCost * morph = card->getManaCost()->morph; + ManaCost * playerMana = player->getManaPool(); + //this handles extra cost payments at the moment a card is played. + if (playerMana->canAfford(morph)) + { + if (cost->morph->isExtraPaymentSet()) + { + card->paymenttype = MTGAbility::MORPH_COST; + if (!game->targetListIsSet(card)) + { + return 0; + } + } + else + { + cost->morph->setExtraCostsAction(this, card); + game->mExtraPayment = cost->morph->extraCosts; + card->paymenttype = MTGAbility::MORPH_COST; + return 0; + } + } + //------------------------------------------------------------------------ + ManaCost * previousManaPool = NEW ManaCost(player->getManaPool()); + int payResult = player->getManaPool()->pay(card->getManaCost()->morph); + card->getManaCost()->morph->doPayExtra(); + payResult = ManaCost::MANA_PAID_WITH_MORPH; + //if morph has a extra payment thats set, this code pays it.the if statement is 100% needed as it would cause a crash on cards that dont have the morph cost. + if (morph) + { + card->getManaCost()->morph->doPayExtra(); + } + //--------------------------------------------------------------------------- + ManaCost * spellCost = previousManaPool->Diff(player->getManaPool()); + delete previousManaPool; + card->morphed = true; + card->isMorphed = true; + MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack); + Spell * spell = NULL; + spell = game->mLayers->stackLayer()->addSpell(copy, NULL, spellCost, payResult, 0); + spell->source->morphed = true; + spell->source->isMorphed = true; + spell->source->name = ""; + spell->source->power = 2; + spell->source->toughness = 2; + copy->morphed = true; + copy->isMorphed = true; + copy->power = 2; + copy->toughness = 2; + player->castedspellsthisturn += 1; + player->opponent()->castedspellsthisturn += 1; + if (player->onlyonecast == true || player->onlyoneinstant == true) + { + player->castcount += 1; + + } + if (!card->has(Constants::STORM)) + { + copy->X = spell->computeX(copy); + copy->XX = spell->computeXX(copy); + } + return 1; +} + +//The morph rule is never destroyed +int MTGMorphCostRule::testDestroy() +{ + return 0; +} + +ostream& MTGMorphCostRule::toString(ostream& out) const +{ + out << "MTGMorphCostRule ::: ("; + return MTGAbility::toString(out) << ")"; +} + +MTGMorphCostRule * MTGMorphCostRule::clone() const +{ + MTGMorphCostRule * a = NEW MTGMorphCostRule(*this); + a->isClone = 1; + return a; +} + +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- + + + + bool MTGAttackRule::select(Target* t) { if (CardView* c = dynamic_cast(t)) { MTGCardInstance * card = c->getCard(); - if (card->canAttack()) + if (card->canAttack() && !card->isPhased) return true; } return false; @@ -610,6 +785,8 @@ int MTGAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { if (currentPhase == Constants::MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer) { + if(card->isPhased) + return 0; if (card->isAttacker()) return 1; if (card->canAttack()) @@ -845,7 +1022,7 @@ int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) && card->controller() == game->currentlyActing() ) { - if (card->canBlock()) + if (card->canBlock() && !card->isPhased) return 1; } return 0; @@ -1620,6 +1797,8 @@ ListMaintainerAbility(_id) int MTGLegendRule::canBeInList(MTGCardInstance * card) { + if(card->isPhased) + return 0; if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->isInPlay(card)) { return 1; @@ -1684,6 +1863,11 @@ int MTGLifelinkRule::receiveEvent(WEvent * event) MTGCardInstance * card = d->source; if (d->damage > 0 && card && card->basicAbilities[Constants::LIFELINK]) { + card->controller()->thatmuch = d->damage; + WEvent * lifed = NULL; + lifed = NEW WEventLife(card->controller(),d->damage); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(lifed); card->controller()->life += d->damage; return 1; } diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index c4e955153..584e090a7 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -251,13 +251,13 @@ ManaCost::~ManaCost() { SAFE_DELETE(hybrids[i]); } - SAFE_DELETE(extraCosts); SAFE_DELETE(kicker); SAFE_DELETE(alternative); SAFE_DELETE(BuyBack); SAFE_DELETE(FlashBack); SAFE_DELETE(Retrace); + SAFE_DELETE(morph); } void ManaCost::x() @@ -285,6 +285,7 @@ void ManaCost::init() BuyBack = NULL; FlashBack = NULL; Retrace = NULL; + morph = NULL; } void ManaCost::copy(ManaCost * _manaCost) @@ -341,6 +342,12 @@ void ManaCost::copy(ManaCost * _manaCost) Retrace = NEW ManaCost(); Retrace->copy(_manaCost->Retrace); } + SAFE_DELETE(morph); + if (_manaCost->morph) + { + morph = NEW ManaCost(); + morph->copy(_manaCost->morph); + } } int ManaCost::getCost(int color) diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index f442f818d..3fcf2ca21 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -166,7 +166,7 @@ void RulesState::parsePlayerState(int playerId, string s) void Rules::addExtraRules() { GameObserver * g = GameObserver::GetInstance(); - + int id = g->mLayers->actionLayer()->getMaxId(); for (int i = 0; i < 2; ++i) { @@ -378,6 +378,16 @@ void Rules::initGame() DebugTrace("RULES Init Game\n"); //Set the current player/phase + if (g->currentPlayer->playMode + != Player::MODE_TEST_SUITE && /*g->mRules->gamemode != GAME_TYPE_MOMIR && g->mRules->gamemode + != GAME_TYPE_RANDOM1 && g->mRules->gamemode != GAME_TYPE_RANDOM2 &&*/ g->mRules->gamemode + != GAME_TYPE_STORY) + { + if(OptionWhosFirst::WHO_R == options[Options::FIRSTPLAYER].number) + initState.player = WRand() % 2; + if(OptionWhosFirst::WHO_O == options[Options::FIRSTPLAYER].number) + initState.player = 1; + } g->currentPlayer = g->players[initState.player]; g->currentActionPlayer = g->currentPlayer; g->currentPlayerId = initState.player; diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index a19977d57..312cd3bcb 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -7,6 +7,7 @@ #include "Subtypes.h" #include "Counters.h" #include "WEvent.h" +#include "AllAbilities.h" TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInstance * card, MTGAbility * ability) { @@ -153,8 +154,23 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta TargetChooser * tc = NULL; int maxtargets = 1; CardDescriptor * cd = NULL; +//max targets allowed + size_t limit = s1.find('<'); + if (limit != string::npos) + { + size_t end = s1.find(">", limit); + string howmany; + if (end != string::npos) + { + howmany = s1.substr(limit + 1, end - limit - 1); + WParsedInt * howmuch = NEW WParsedInt(howmany, NULL, card); + maxtargets = howmuch->getValue(); + delete howmuch; + s1 = s1.substr(end + 1); + } + } - while (s1.size()) + while (s1.size()) { found = s1.find(","); string typeName; @@ -206,8 +222,11 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta size_t operatorPosition = attribute.find("=", 1); if (operatorPosition != string::npos) { - comparisonCriterion = atoi( - attribute.substr(operatorPosition + 1, attribute.size() - operatorPosition - 1).c_str()); + string numberCD = attribute.substr(operatorPosition + 1, attribute.size() - operatorPosition - 1); + WParsedInt * val = NEW WParsedInt(numberCD,NULL, card); + comparisonCriterion = val->getValue(); + /*atoi(attribute.substr(operatorPosition + 1, attribute.size() - operatorPosition - 1).c_str());*/ + delete val; switch (attribute[operatorPosition - 1]) { case '<': @@ -305,10 +324,112 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta { cd->unsecuresetfresh(1); } - //Power restrictions + } + //creature is a level up creature + else if (attribute.find("leveler") != string::npos) + { + if (minus) + { + cd->isLeveler = -1; + } + else + { + cd->isLeveler = 1; + } + } + //creature is a level up creature + else if (attribute.find("enchanted") != string::npos) + { + if (minus) + { + cd->CDenchanted = -1; + } + else + { + cd->CDenchanted = 1; + } + } + else if (attribute.find("multicolor") != string::npos) + { + //card is multicolored? + if (minus) + { + cd->setisMultiColored(-1); + } + else + { + 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) { + //Power restrictions cd->setPower(comparisonCriterion); cd->powerComparisonMode = comparisonMode; //Toughness restrictions @@ -462,6 +583,8 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta TargetChooser * TargetChooserFactory::createTargetChooser(MTGCardInstance * card) { + if(!card) + return NULL; int id = card->getId(); string s = card->spellTargetType; if (card->alias) @@ -540,6 +663,11 @@ bool TargetChooser::canTarget(Targetable * target) tempcard = tempcard->previous; } } + if(source && ((source->hasSubtype("aura") || source->hasSubtype("equipment")) && source->target && source->target == card && source->target->isPhased && targetter->target == card)) + return true; + //this is kinda cheating but by defualt we let auras and equipments always contenue to target a phased creature. + else if(card->isPhased) + return false; if (source && targetter && card->isInPlay()) { if (card->has(Constants::SHROUD)) return false; @@ -574,7 +702,7 @@ int TargetChooser::ForceTargetListReady() int TargetChooser::targetsReadyCheck() { - if (cursor == 0) + if (cursor <= 0) { return TARGET_NOK; } @@ -605,8 +733,8 @@ bool TargetChooser::validTargetsExist() { Player *p = GameObserver::GetInstance()->players[i]; if (canTarget(p)) return true; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library }; - for (int k = 0; k < 4; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile }; + for (int k = 0; k < 5; k++) { MTGGameZone * z = zones[k]; if (targetsZone(z)) @@ -764,7 +892,8 @@ bool DescriptorTargetChooser::canTarget(Targetable * target) if (target->typeAsTarget() == TARGET_CARD) { MTGCardInstance * _target = (MTGCardInstance *) target; - if (cd->match(_target)) return true; + if (cd->match(_target)) + return true; } else if (target->typeAsTarget() == TARGET_STACKACTION) { diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index 7a4517b9f..aa0d8059b 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -135,13 +135,44 @@ int TestSuiteAI::Act(float dt) playMode = MODE_AI; return 1; } - else if (action.compare("next") == 0) + else if (action.compare("next") == 0 || action.find("goto") != string::npos) { - GuiCombat * gc = g->mLayers->combatLayer(); - if (ORDER == g->combatStep || DAMAGE == g->combatStep) - gc->clickOK(); + if(action.find("goto ")!= string::npos) + { + size_t found = action.find("goto "); + string phase = action.substr(found + 5); + int phaseToGo = 0; + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + if (phase.find(Constants::MTGPhaseCodeNames[i]) != string::npos) + { + phaseToGo = i; + } + } + if(g->currentGamePhase != phaseToGo) + suite->currentAction--; + else + { + return 1; + } + GuiCombat * gc = g->mLayers->combatLayer(); + if (ORDER == g->combatStep || DAMAGE == g->combatStep) + { + gc->clickOK(); + } + else + { + g->userRequestNextGamePhase(); + } + } else - g->userRequestNextGamePhase(); + { + GuiCombat * gc = g->mLayers->combatLayer(); + if (ORDER == g->combatStep || DAMAGE == g->combatStep) + gc->clickOK(); + else + g->userRequestNextGamePhase(); + } } else if (action.compare("yes") == 0) g->mLayers->stackLayer()->setIsInterrupting(this); diff --git a/projects/mtg/src/ThisDescriptor.cpp b/projects/mtg/src/ThisDescriptor.cpp index e0baf48c9..4057e21fa 100644 --- a/projects/mtg/src/ThisDescriptor.cpp +++ b/projects/mtg/src/ThisDescriptor.cpp @@ -144,7 +144,7 @@ ThisDescriptor * ThisDescriptorFactory::createThisDescriptor(string s) return NULL; } - //equips + //equips and auras found = s.find("gear");//still same meaning, better wording to word conflict with MTGAbility equip. if (found != string::npos) { @@ -156,7 +156,52 @@ ThisDescriptor * ThisDescriptorFactory::createThisDescriptor(string s) } return NULL; } - + found = s.find("auras"); + if (found != string::npos) + { + ThisAuras * td = NEW ThisAuras(criterion); + if (td) + { + td->comparisonMode = mode; + return td; + } + return NULL; + } + // opponent damage count + found = s.find("opponentdamagecount"); + if (found != string::npos) + { + ThisOpponentDamageAmount * td = NEW ThisOpponentDamageAmount(criterion); + if (td) + { + td->comparisonMode = mode; + return td; + } + return NULL; + } + //untapped status + found = s.find("untapped"); + if (found != string::npos) + { + ThisUntapped * td = NEW ThisUntapped(criterion); + if (td) + { + td->comparisonMode = mode; + return td; + } + return NULL; + } + found = s.find("tapped"); + if (found != string::npos) + { + ThisTapped * td = NEW ThisTapped(criterion); + if (td) + { + td->comparisonMode = mode; + return td; + } + return NULL; + } //whenever this creature attacks do effect found = s.find("attacking"); if (found != string::npos) @@ -338,6 +383,42 @@ int ThisEquip::match(MTGCardInstance * card) return matchValue(card->equipment); } +ThisAuras::ThisAuras(int auras) +{ + comparisonCriterion = auras; +} +int ThisAuras::match(MTGCardInstance * card) +{ + return matchValue(card->auras); +} + +ThisOpponentDamageAmount::ThisOpponentDamageAmount(int damagecount) +{ + comparisonCriterion = damagecount; +} +int ThisOpponentDamageAmount::match(MTGCardInstance * card) +{ + return matchValue(card->controller()->opponent()->damageCount); +} + +ThisUntapped::ThisUntapped(int untapped) +{ + comparisonCriterion = untapped; +} +int ThisUntapped::match(MTGCardInstance * card) +{ + return matchValue(!card->isTapped()); +} + +ThisTapped::ThisTapped(int tapped) +{ + comparisonCriterion = tapped; +} +int ThisTapped::match(MTGCardInstance * card) +{ + return matchValue(card->isTapped()); +} + ThisAttacked::ThisAttacked(int attack) { diff --git a/projects/mtg/src/Token.cpp b/projects/mtg/src/Token.cpp index 1535c21ce..0be3dd960 100644 --- a/projects/mtg/src/Token.cpp +++ b/projects/mtg/src/Token.cpp @@ -11,6 +11,8 @@ Token::Token(string _name, MTGCardInstance * source, int _power, int _toughness) toughness = _toughness; life = toughness; lifeOrig = life; + origpower = _power; + origtoughness = _toughness; rarity = Constants::RARITY_T; name = _name; if (name.size() && name[0] >= 97 && name[0] <= 122) name[0] -= 32; //Poor man's camelcase. We assume strings we get are either Camelcased or lowercase diff --git a/projects/mtg/src/WCachedResource.cpp b/projects/mtg/src/WCachedResource.cpp index 176eedc6d..634583958 100644 --- a/projects/mtg/src/WCachedResource.cpp +++ b/projects/mtg/src/WCachedResource.cpp @@ -103,7 +103,11 @@ bool WCachedTexture::isLocked() for (vector::iterator it = trackedQuads.begin(); it != trackedQuads.end(); it++) { - if ((*it)->isLocked()) return true; + if ((*it) && (*it)->isLocked()) return true; + //null case + //tokens that were using workarounds such as mixes of aslongas with CD checks + //and thisforeach would call to cache the tokens image, but since the effect never resolved it was NULL + //when it came time to check if it was locked, it would trigger a break point here. } return false; diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index c54dde981..baeaebae7 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -21,6 +21,11 @@ WEventDamage::WEventDamage(Damage *damage) : { } +WEventLife::WEventLife(Player * player,int amount,int Ltype) : + WEvent(), player(player),amount(amount), Ltype(Ltype) +{ +} + WEventDamageStackResolved::WEventDamageStackResolved() : WEvent() { @@ -87,6 +92,16 @@ WEventCardDiscard::WEventCardDiscard(MTGCardInstance * card) : { } +WEventVampire::WEventVampire(MTGCardInstance * card,MTGCardInstance * source,MTGCardInstance * victem) : + WEventCardUpdate(card),source(source),victem(victem) +{ +} + +WEventTarget::WEventTarget(MTGCardInstance * card,MTGCardInstance * source) : + WEventCardUpdate(card),card(card),source(source) +{ +} + WEventCardChangeType::WEventCardChangeType(MTGCardInstance * card, int type, bool before, bool after) : WEventCardUpdate(card), type(type), before(before), after(after) { @@ -144,6 +159,42 @@ int WEventDamage::getValue() return damage->damage; } +Targetable * WEventLife::getTarget(int target) +{ + switch (target) + { + case TARGET_TO: + return player; + case TARGET_FROM: + return player; + } + return NULL; +} + +Targetable * WEventVampire::getTarget(int target) +{ + switch (target) + { + case TARGET_TO: + return victem->next; + case TARGET_FROM: + return source; + } + return NULL; +} + +Targetable * WEventTarget::getTarget(int target) +{ + switch (target) + { + case TARGET_TO: + return card; + case TARGET_FROM: + return source; + } + return NULL; +} + Targetable * WEventZoneChange::getTarget(int target) { if (target) return card;