From 473abd981421efa2526003c22b732d17837924c3 Mon Sep 17 00:00:00 2001 From: "omegablast2002@yahoo.com" Date: Fri, 21 Jan 2011 20:18:56 +0000 Subject: [PATCH] im forced to do this commit in whole instead of parts as originally planned, and before my beta test period of the changes is complete BECAUSE there are people doing "clean up" and the MASSIVE amount of conflicts i have to resolve from it is WAY too much for me to take on after nearly 200 hours of coding this patch. i cant seem to get enough respect to have people hold off on "clean up" so this brings me to being forced to do a full commit before playtest period is done, so they can go ahead with there *super important* clean up. ok i WAS going to write a full change log with code exsamples ect, but since im rushed you will get the short version of this log. first bug fixes, and there were many, indestructible creature bug fixed halimar execavator *embearessing youtube video" bug is fixed token text now displays source name and tokens abilities fixed a card view null pointer in an iterator when code used combinations of foreach and aslongas with CD. epic struggle bug fixed, aslongas was only parsing one space to the right of the operator. extra cost containing targetting fixed, cards can now have multiple extra cost in all mana...this includes giving a card 2 targeted sacrifices as its main cost. angelic chorus bug fixed, the card will be soft coded now. and many other minor bugs fixed, hard to remember all which were fixed. now, new abilities = words "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", all true landwalks will now be supported. new cost types: morph which is coded as follows [card] name=Bloodstoke Howler facedown={3} autofacedown={6}{R}:morph autofaceup=3/0 all(beast|mybattlefield)) text=Morph {6}{R} (You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.) -- When Bloodstoke Howler is turned face up, Beast creatures you control get +3/+0 until end of turn. mana={5}{R} type=Creature subtype=Beast power=3 toughness=4 [/card] you will notice new auto lines autofaceup and autofacedown these are abilities the cards will have when theyre in that state. the cost is coded as facedown={cost} when a card is faced up it gains auto= lines also. tho is played normally it will NOT gain autofaceup=lines card restrictions: cards can now have restrictions placed on them the restrictions are. all previous restrictions usable in activated abilities with the follow additions control two or more vampires control less creatures control snow land casted a spell one of a kind fourth turn before battle damage after battle during battle [card] name=Blood Frenzy target=creature[attacking;blocking] restriction=before battle damage auto=4/0 auto=treason text=Cast Blood Frenzy only before the combat damage step. -- Target attacking or blocking creature gets +4/+0 until end of turn. Destroy that creature at the beginning of the next end step. mana={1}{R} type=Instant [/card] other cost now can have specail restrictions also: otherrestriction=mytypemin:1 type(swamp),opponenttypemin:1 opponenttype(plains) these are minimums required inplay of a type it can be just you, or you and opponent or just opponent you can also use the words "more" and "less" and * to compare the 2 players fields. [card] name=Cho-Arrim Legate abilities=protection from black other={0} otherrestriction=mytypemin:1 type(swamp) , opponenttypemin:1 opponenttype(plains) text=Protection from black -- If an opponent controls a Swamp and you control a Plains, you may cast Cho-Arrim Legate without paying its mana cost. mana={2}{W} type=Creature subtype=Human Soldier power=1 toughness=2 [/card] activated ability gained a new restriction "opponentturnonly" variables will now be recalculated during the resolve of the major abilities to produce the most current number. {x}:draw:x <---- new number variables words: using draw as an exsample draw:auras <--auras on a creature draw:type:ally <---counts the allys in your field. self explanitory draw:thatmuch <--mostly a triggered effects number. when you take damage draw that much draw:lifelost draw:oplifelost these return the value of the life lost that turn. new TRIGGER restricitions sourcenottap sourceTap foelostthree<--card cycle uses opponent lost life foelosttwo<--same as above once<--this trigger will only ever trigger one time and never again. new card discriptor words [multicolor] [leveler] [enchanted] [blackandgreen] [blackandwhite] [redandblue] [blueandgreen] [redandwhite] CD will now recalculate the number again on resolve meaning {x}:target(CreatureTargetChooser[manacost <=x]) will work, with an added bonus {x}:target(CreatureTargetChooser[manacost <=any word variable]) new this(: this(tapped)<--for strange case cards. this(untapped) this(auras) new MTGAbility keywords (blink) (blink)forsrc <--stay blinked while source inplay hand(blink <---adding hand to the front makes it target hand. livingweapon this is an extension of token, simple attach the words "livingweapon" to the front of token( and it will autoamtically token that and attach the card to it. token( gained: "targetcontroller" targetting. "battleready" if put in the tokens abilities it will be a attacker and tapped as it is entering play. phaseout <--self explanitory spiritlink <--stacking lifelink style effect that benifits the OWNER of the card. combatspiritlink same as above. stacking flanking, requires 2 abilities unfortunately [card] name=Agility target=creature auto=teach(creature) flanker auto=teach(creature) flanking text=Enchant creature -- Enchanted creature gets +1/+1 and has flanking. (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.) mana={1}{R} type=Enchantment subtype=Aura [/card] removeallcounters(number/number,name) removes all counters of the type from a card, can all be "all" vampire hexmage effect. added new tools for transforms ,setpower=number ,settoughness=number removetypes morph autofacedown={0}:morph eradicate <---same as the card name. cumulativeupcost[ <--self explanitory upcostmulti[ <--an upcost that will resolve with a && ability phaseaction[ phase name ] ability an ability that will trigger on the stated phase name. also support for phaseactionmulti[ new triggers added: @vampired( <--sengir vampire effect @targeted( @lifeloss( @lifed( add a special ability builder called dynamicability it acts alot like a choose your own adventure book dynamicability optional ability targetting the original target. variable list 1: this is the primary amount source source mytgt myself myfoe variable list 2: this is the variable we're after, or the amount power toughness manacost colors age charge oneonecounters thatmuch variable list 3: this is the main effect strike draw lifeloss lifegain pumppow pumptough pumpboth deplete countersoneone variable list 4: how it will do this effect to. itself eachother targetcontroller targetopponent tosrc srccontroller srcopponent the best way to explain its usage is to look at cards coded with this ability. or experiment with combinations. new gameoption First turn player:player, opponent, random who takes the first turn added poisoned status, tho not complete since MBS hasnt spoiled enough cards to see where this variable will be used. taught ai how to counter spell improved ai, it will now cast instants during interupts and during your turn. previously ai treated instant cards the same as it treated sorceries, which was not fair to the ai. im sure there is some messed items, but the rev directly before this one had formatting in the code that created hundreds of conflicts with this one, so i had to dig this info out of red and green sections. cards and test are coming soon, i ask PLEASE do not alter these new additions until the test are commited. im commiting without the test because instead of allowing me to proceed with my beta test period, there are some that wish to rush me into a commit. if you do not like this commit revert it, i absolutely on no grounds give permission to recommit afterwards. and i will not recommit if a revert is called. --- projects/mtg/include/AIPlayer.h | 93 +- projects/mtg/include/ActionStack.h | 304 +++--- projects/mtg/include/AllAbilities.h | 818 ++++++++++++-- projects/mtg/include/CardDescriptor.h | 68 +- projects/mtg/include/CardPrimitive.h | 185 +++- projects/mtg/include/Damage.h | 92 +- projects/mtg/include/ExtraCost.h | 186 ++-- projects/mtg/include/GameObserver.h | 119 +- projects/mtg/include/GameOptions.h | 483 ++++---- projects/mtg/include/MTGAbility.h | 671 ++++++------ projects/mtg/include/MTGCardInstance.h | 271 ++--- projects/mtg/include/MTGDefinitions.h | 400 +++---- projects/mtg/include/MTGGameZones.h | 293 +++-- projects/mtg/include/MTGRules.h | 22 +- projects/mtg/include/ManaCost.h | 142 +-- projects/mtg/include/Player.h | 1 + projects/mtg/include/ThisDescriptor.h | 147 +-- projects/mtg/include/WEvent.h | 256 +++-- projects/mtg/src/AIPlayer.cpp | 282 +++-- projects/mtg/src/ActionStack.cpp | 48 +- projects/mtg/src/AllAbilities.cpp | 1390 ++++++++++++++++++++++-- projects/mtg/src/CardDescriptor.cpp | 60 +- projects/mtg/src/CardGui.cpp | 21 +- projects/mtg/src/CardPrimitive.cpp | 21 + projects/mtg/src/Damage.cpp | 6 +- projects/mtg/src/DuelLayers.cpp | 2 +- projects/mtg/src/ExtraCost.cpp | 40 +- projects/mtg/src/GameApp.cpp | 8 + projects/mtg/src/GameObserver.cpp | 222 +++- projects/mtg/src/GameOptions.cpp | 16 + projects/mtg/src/GameStateOptions.cpp | 4 + projects/mtg/src/GuiHand.cpp | 7 +- projects/mtg/src/MTGAbility.cpp | 981 +++++++++++++++-- projects/mtg/src/MTGCardInstance.cpp | 76 +- projects/mtg/src/MTGDeck.cpp | 91 +- projects/mtg/src/MTGDefinitions.cpp | 13 + projects/mtg/src/MTGGameZones.cpp | 92 +- projects/mtg/src/MTGRules.cpp | 196 +++- projects/mtg/src/ManaCost.cpp | 9 +- projects/mtg/src/Rules.cpp | 12 +- projects/mtg/src/TargetChooser.cpp | 145 ++- projects/mtg/src/TestSuiteAI.cpp | 41 +- projects/mtg/src/ThisDescriptor.cpp | 85 +- projects/mtg/src/Token.cpp | 2 + projects/mtg/src/WCachedResource.cpp | 6 +- projects/mtg/src/WEvent.cpp | 51 + 46 files changed, 6161 insertions(+), 2317 deletions(-) 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;