diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 40becb8c8..55577a209 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -625,7 +625,7 @@ public: int power; int toughness; string name; - string menu; + string menu; AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness, int nb, ManaCost * cost = NULL, int doTap = 0); @@ -1019,7 +1019,7 @@ public: who = who; tokenId = 0; 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; + //TODO this is a copy/past of other code that's all around the place, everything should be in a dedicated parser class; for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++) { @@ -1192,8 +1192,8 @@ public: ABasicAbilityModifier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int _modifier = 1) : MTGAbility(_id, _source, _target), modifier(_modifier), ability(_ability) { - aType = MTGAbility::STANDARDABILITYGRANT; - abilitygranted = ability; + aType = MTGAbility::STANDARDABILITYGRANT; + abilitygranted = ability; } int addToGame() @@ -1251,8 +1251,8 @@ public: int _modifier = 1, int _tap = 1) : TargetAbility(_id, _source, _cost, 0, _tap), modifier(_modifier), ability(_ability) { - aType = MTGAbility::STANDARDABILITYGRANT; - abilitygranted = ability; + aType = MTGAbility::STANDARDABILITYGRANT; + abilitygranted = ability; nbTargets = 0; tc = _tc; if (!tc) tc = NEW CreatureTargetChooser(_source); @@ -1325,8 +1325,8 @@ public: 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() @@ -1375,8 +1375,8 @@ public: { target = _target; ability = NEW AInstantBasicAbilityModifierUntilEOT(_id, _source, _target, _ability, _value); - aType = MTGAbility::STANDARDABILITYGRANT; - abilitygranted = _ability; + aType = MTGAbility::STANDARDABILITYGRANT; + abilitygranted = _ability; } int isReactingToClick(MTGCardInstance * card, ManaCost * cost = NULL) @@ -1430,7 +1430,7 @@ public: ASpellCastLife(int id, MTGCardInstance * _source, CardDescriptor _trigger, ManaCost * _cost, int _life) : MTGAbility(id, _source), trigger(_trigger), cost(_cost), life(_life), lastUsedOn(NULL), lastChecked(NULL) { - aType = MTGAbility::LIFER; + aType = MTGAbility::LIFER; } ASpellCastLife(int id, MTGCardInstance * _source, int color, ManaCost * _cost, int _life) : MTGAbility(id, _source), cost(_cost), life(_life), lastUsedOn(NULL), lastChecked(NULL) @@ -2270,84 +2270,84 @@ public: SAFE_DELETE(ability); } - const char * getMenuText() - { - if (AAMover * move = dynamic_cast(ability)) - { - MTGGameZone * dest = move->destinationZone(); - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2; i++) - { - // Move card to hand - if (dest == g->players[i]->game->hand) - { - if (tc->targetsZone(g->players[i]->game->inPlay)) - { - return "Bounce"; - } - else if (tc->targetsZone(g->players[i]->game->graveyard)) - { - return "Reclaim"; - } - else if (tc->targetsZone(g->opponent()->game->hand)) - { - return "Steal"; - } - } - // Move card to graveyard - else if (dest == g->players[i]->game->graveyard) - { - if (tc->targetsZone(g->players[i]->game->inPlay)) - { - return "Sacrifice"; - } - else if (tc->targetsZone(g->players[i]->game->hand)) - { - return "Discard"; - } - else if (tc->targetsZone(g->opponent()->game->hand)) - { - return "Opponent Discards"; - } - } - // move card to library - else if (dest == g->players[i]->game->library) - { - if (tc->targetsZone(g->players[i]->game->graveyard)) - { - return "Recycle"; - } - else - { - return "Put in Library"; - } - } - // move card to battlefield - else if (dest == g->players[i]->game->battlefield && tc->targetsZone(g->players[i]->game->graveyard)) - { - return "Reanimate"; - } - // move card in play ( different from battlefield? ) - else if (dest == g->players[i]->game->inPlay) - { - return "Put in Play"; - } - // move card into exile - else if (dest == g->players[i]->game->exile) - { - return "Exile"; - } - // move card from Library - else if (tc->targetsZone(g->players[i]->game->library)) - { - return "Fetch"; - } - } - return "Move"; - } - else - return ability->getMenuText(); - } + const char * getMenuText() + { + if (AAMover * move = dynamic_cast(ability)) + { + MTGGameZone * dest = move->destinationZone(); + GameObserver * g = GameObserver::GetInstance(); + for (int i = 0; i < 2; i++) + { + // Move card to hand + if (dest == g->players[i]->game->hand) + { + if (tc->targetsZone(g->players[i]->game->inPlay)) + { + return "Bounce"; + } + else if (tc->targetsZone(g->players[i]->game->graveyard)) + { + return "Reclaim"; + } + else if (tc->targetsZone(g->opponent()->game->hand)) + { + return "Steal"; + } + } + // Move card to graveyard + else if (dest == g->players[i]->game->graveyard) + { + if (tc->targetsZone(g->players[i]->game->inPlay)) + { + return "Sacrifice"; + } + else if (tc->targetsZone(g->players[i]->game->hand)) + { + return "Discard"; + } + else if (tc->targetsZone(g->opponent()->game->hand)) + { + return "Opponent Discards"; + } + } + // move card to library + else if (dest == g->players[i]->game->library) + { + if (tc->targetsZone(g->players[i]->game->graveyard)) + { + return "Recycle"; + } + else + { + return "Put in Library"; + } + } + // move card to battlefield + else if (dest == g->players[i]->game->battlefield && tc->targetsZone(g->players[i]->game->graveyard)) + { + return "Reanimate"; + } + // move card in play ( different from battlefield? ) + else if (dest == g->players[i]->game->inPlay) + { + return "Put in Play"; + } + // move card into exile + else if (dest == g->players[i]->game->exile) + { + return "Exile"; + } + // move card from Library + else if (tc->targetsZone(g->players[i]->game->library)) + { + return "Fetch"; + } + } + return "Move"; + } + else + return ability->getMenuText(); + } ALord * clone() const { @@ -3175,8 +3175,8 @@ public: { for (int i = 0; i < nbOpponents; i++) { - if (game->isInPlay(opponents[i])) - opponents[i]->destroy(); + if (game->isInPlay(opponents[i])) + opponents[i]->destroy(); } } } @@ -3288,7 +3288,7 @@ public: list oldcolors; list oldtypes; bool remove; - string menu; + string menu; ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities); int addToGame(); @@ -3305,7 +3305,7 @@ public: list abilities; list types; list colors; - string menu; + string menu; AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities); int addToGame(); @@ -3344,12 +3344,12 @@ public: class ASwapPTUEOT: public InstantAbility { public: - ASwapPT * ability; - ASwapPTUEOT(int id, MTGCardInstance * source, MTGCardInstance * target); - int resolve(); - const char * getMenuText(); - ASwapPTUEOT * clone() const; - ~ASwapPTUEOT(); + ASwapPT * ability; + ASwapPTUEOT(int id, MTGCardInstance * source, MTGCardInstance * target); + int resolve(); + const char * getMenuText(); + ASwapPTUEOT * clone() const; + ~ASwapPTUEOT(); }; //becomes ability @@ -4027,61 +4027,61 @@ public: AErgRaiders * a = NEW AErgRaiders(*this); a->isClone = 1; return a; - } + } }; //Fastbond class AFastbond: public TriggeredAbility { public: - int alreadyPlayedALand; - int previous; - AFastbond(int _id, MTGCardInstance * card) : - TriggeredAbility(_id, card) - { - alreadyPlayedALand = 0; - if (source->controller()->landsPlayerCanStillPlay == 0) - { - alreadyPlayedALand = 1; - source->controller()->landsPlayerCanStillPlay += 1; - source->controller()->canPutLandsIntoPlay = true; + int alreadyPlayedALand; + int previous; + AFastbond(int _id, MTGCardInstance * card) : + TriggeredAbility(_id, card) + { + alreadyPlayedALand = 0; + if (source->controller()->landsPlayerCanStillPlay == 0) + { + alreadyPlayedALand = 1; + source->controller()->landsPlayerCanStillPlay += 1; + source->controller()->canPutLandsIntoPlay = true; - } - previous = source->controller()->landsPlayerCanStillPlay; - } + } + previous = source->controller()->landsPlayerCanStillPlay; + } - void Update(float dt) - { - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP) - { - alreadyPlayedALand = 0; - } - TriggeredAbility::Update(dt); - } + void Update(float dt) + { + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP) + { + alreadyPlayedALand = 0; + } + TriggeredAbility::Update(dt); + } - int trigger() - { - if (source->controller()->landsPlayerCanStillPlay == 0 && previous >= 1) - { - previous = 0; - source->controller()->canPutLandsIntoPlay = true; - source->controller()->landsPlayerCanStillPlay += 1; - if (alreadyPlayedALand) return 1; - alreadyPlayedALand = 1; - return 0; - } - previous = source->controller()->landsPlayerCanStillPlay; - return 0; - } + int trigger() + { + if (source->controller()->landsPlayerCanStillPlay == 0 && previous >= 1) + { + previous = 0; + source->controller()->canPutLandsIntoPlay = true; + source->controller()->landsPlayerCanStillPlay += 1; + if (alreadyPlayedALand) return 1; + alreadyPlayedALand = 1; + return 0; + } + previous = source->controller()->landsPlayerCanStillPlay; + return 0; + } - int resolve() - { - game->mLayers->stackLayer()->addDamage(source, source->controller(), 1); - game->mLayers->stackLayer()->resolve(); - return 1; - } + int resolve() + { + game->mLayers->stackLayer()->addDamage(source, source->controller(), 1); + game->mLayers->stackLayer()->resolve(); + return 1; + } - virtual ostream& toString(ostream& out) const + virtual ostream& toString(ostream& out) const { out << "AFastbond ::: alreadyPlayedALand : " << alreadyPlayedALand << " ; previous : " << previous << " ("; return TriggeredAbility::toString(out) << ")"; @@ -5222,10 +5222,8 @@ public: // utility functions -void PopulateColorIndexVector( list& colors, const string& colorsString, char delimiter = ','); -void PopulateAbilityIndexVector( list& abilities, const string& abilitiesString, char delimiter = ','); -void PopulateSubtypesIndexVector( list& subtypes, const string& subtypesString, char delimiter = ' '); - - +void PopulateColorIndexVector(list& colors, const string& colorsString, char delimiter = ','); +void PopulateAbilityIndexVector(list& abilities, const string& abilitiesString, char delimiter = ','); +void PopulateSubtypesIndexVector(list& subtypes, const string& subtypesString, char delimiter = ' '); #endif diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index a90dc24a7..65ae34b24 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -9,140 +9,172 @@ #include "WEvent.h" #include "CardSelector.h" -class OtherAbilitiesEventReceiver:public MTGAbility{ +class OtherAbilitiesEventReceiver: public MTGAbility +{ public: - int testDestroy(); - int receiveEvent(WEvent * event); - OtherAbilitiesEventReceiver(int _id); - OtherAbilitiesEventReceiver * clone() const; + int testDestroy(); + int receiveEvent(WEvent * event); + OtherAbilitiesEventReceiver(int _id); + OtherAbilitiesEventReceiver * clone() const; }; -class MTGPutInPlayRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGPutInPlayRule(int _id); - const char * getMenuText(){return "Play Card Normally";} - virtual MTGPutInPlayRule * clone() const; +class MTGPutInPlayRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGPutInPlayRule(int _id); + const char * getMenuText() + { + return "Play Card Normally"; + } + virtual MTGPutInPlayRule * clone() const; }; -class MTGAlternativeCostRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGAlternativeCostRule(int _id); - const char * getMenuText(){return "Pay Alternative Cost";} - virtual MTGAlternativeCostRule * clone() const; +class MTGAlternativeCostRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGAlternativeCostRule(int _id); + const char * getMenuText() + { + return "Pay Alternative Cost"; + } + virtual MTGAlternativeCostRule * clone() const; }; -class MTGBuyBackRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGBuyBackRule(int _id); - const char * getMenuText(){return "Cast And Buy Back";} - virtual MTGBuyBackRule * clone() const; +class MTGBuyBackRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGBuyBackRule(int _id); + const char * getMenuText() + { + return "Cast And Buy Back"; + } + virtual MTGBuyBackRule * clone() const; }; -class MTGFlashBackRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGFlashBackRule(int _id); - const char * getMenuText(){return "Flash Back";} - virtual MTGFlashBackRule * clone() const; +class MTGFlashBackRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGFlashBackRule(int _id); + const char * getMenuText() + { + return "Flash Back"; + } + virtual MTGFlashBackRule * clone() const; }; -class MTGRetraceRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGRetraceRule(int _id); - const char * getMenuText(){return "Retrace";} - virtual MTGRetraceRule * clone() const; +class MTGRetraceRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGRetraceRule(int _id); + const char * getMenuText() + { + return "Retrace"; + } + virtual MTGRetraceRule * clone() const; }; -class MTGAttackRule:public MTGAbility, public Limitor{ - public: - virtual bool select(Target*); - virtual bool greyout(Target*); - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGAttackRule(int _id); - const char * getMenuText(){return "Attacker";} - int receiveEvent(WEvent * event); - virtual MTGAttackRule * clone() const; +class MTGAttackRule: public MTGAbility, public Limitor +{ +public: + virtual bool select(Target*); + virtual bool greyout(Target*); + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGAttackRule(int _id); + const char * getMenuText() + { + return "Attacker"; + } + int receiveEvent(WEvent * event); + virtual MTGAttackRule * clone() const; }; - /* handles combat trigger send recieve events*/ -class MTGCombatTriggersRule:public MTGAbility{ - public: - MTGCombatTriggersRule(int _id); - int receiveEvent(WEvent * event); - virtual ostream& toString(ostream& out) const; - int testDestroy(); - virtual MTGCombatTriggersRule * clone() const; +class MTGCombatTriggersRule: public MTGAbility +{ +public: + MTGCombatTriggersRule(int _id); + int receiveEvent(WEvent * event); + virtual ostream& toString(ostream& out) const; + int testDestroy(); + virtual MTGCombatTriggersRule * clone() const; }; -class MTGBlockRule:public MTGAbility{ - public: - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - MTGBlockRule(int _id); - const char * getMenuText(){return "Blocker";} - virtual MTGBlockRule * clone() const; +class MTGBlockRule: public MTGAbility +{ +public: + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + MTGBlockRule(int _id); + const char * getMenuText() + { + return "Blocker"; + } + virtual MTGBlockRule * clone() const; }; - /* Persist Rule */ -class MTGPersistRule:public MTGAbility{ - public: - MTGPersistRule(int _id); - int receiveEvent(WEvent * event); - virtual ostream& toString(ostream& out) const; - int testDestroy(); - virtual MTGPersistRule * clone() const; +class MTGPersistRule: public MTGAbility +{ +public: + MTGPersistRule(int _id); + int receiveEvent(WEvent * event); + virtual ostream& toString(ostream& out) const; + int testDestroy(); + virtual MTGPersistRule * clone() const; }; //affinity rules -class MTGAffinityRule:public MTGAbility{ - public: - MTGAffinityRule(int _id); - int receiveEvent(WEvent * event); - virtual ostream& toString(ostream& out) const; - int testDestroy(); - virtual MTGAffinityRule * clone() const; +class MTGAffinityRule: public MTGAbility +{ +public: + MTGAffinityRule(int _id); + int receiveEvent(WEvent * event); + virtual ostream& toString(ostream& out) const; + int testDestroy(); + virtual MTGAffinityRule * clone() const; }; //unearths destruction if leaves play effect -class MTGUnearthRule:public MTGAbility{ - public: - MTGUnearthRule(int _id); - int receiveEvent(WEvent * event); - virtual ostream& toString(ostream& out) const; - int testDestroy(); - virtual MTGUnearthRule * clone() const; +class MTGUnearthRule: public MTGAbility +{ +public: + MTGUnearthRule(int _id); + int receiveEvent(WEvent * event); + virtual ostream& toString(ostream& out) const; + int testDestroy(); + virtual MTGUnearthRule * clone() const; }; -class MTGTokensCleanup:public MTGAbility{ - public: - vector list; - MTGTokensCleanup(int _id); - int receiveEvent(WEvent * event); - int testDestroy(); - virtual MTGTokensCleanup * clone() const; +class MTGTokensCleanup: public MTGAbility +{ +public: + vector list; + MTGTokensCleanup(int _id); + int receiveEvent(WEvent * event); + int testDestroy(); + virtual MTGTokensCleanup * clone() const; }; /* @@ -151,99 +183,112 @@ class MTGTokensCleanup:public MTGAbility{ * owners' graveyards. This is called the "legend rule." If only one of those permanents is * legendary, this rule doesn't apply. */ -class MTGLegendRule:public ListMaintainerAbility{ - public: - MTGLegendRule(int _id); - int canBeInList(MTGCardInstance * card); - int added(MTGCardInstance * card); - int removed(MTGCardInstance * card); - int testDestroy(); - virtual ostream& toString(ostream& out) const; - virtual MTGLegendRule * clone() const; +class MTGLegendRule: public ListMaintainerAbility +{ +public: + MTGLegendRule(int _id); + int canBeInList(MTGCardInstance * card); + int added(MTGCardInstance * card); + int removed(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + virtual MTGLegendRule * clone() const; }; - -class MTGMomirRule:public MTGAbility{ +class MTGMomirRule: public MTGAbility +{ private: - int genRandomCreatureId(int convertedCost); - static vector pool[20]; - static int initialized; + int genRandomCreatureId(int convertedCost); + static vector pool[20]; + static int initialized; - int textAlpha; - string text; + int textAlpha; + string text; public: - int alreadyplayed; - MTGAllCards * collection; - MTGCardInstance * genCreature(int id); - int testDestroy(); - void Update(float dt); - void Render(); - MTGMomirRule(int _id, MTGAllCards * _collection); - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); - int reactToClick(MTGCardInstance * card); - int reactToClick(MTGCardInstance * card, int id); - const char * getMenuText(){return "Momir";} - virtual ostream& toString(ostream& out) const; - virtual MTGMomirRule * clone() const; + int alreadyplayed; + MTGAllCards * collection; + MTGCardInstance * genCreature(int id); + int testDestroy(); + void Update(float dt); + void Render(); + MTGMomirRule(int _id, MTGAllCards * _collection); + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + int reactToClick(MTGCardInstance * card, int id); + const char * getMenuText() + { + return "Momir"; + } + virtual ostream& toString(ostream& out) const; + virtual MTGMomirRule * clone() const; }; - /* LifeLink */ -class MTGLifelinkRule:public MTGAbility{ - public: - MTGLifelinkRule(int _id); +class MTGLifelinkRule: public MTGAbility +{ +public: + MTGLifelinkRule(int _id); - int receiveEvent(WEvent * event); + int receiveEvent(WEvent * event); - int testDestroy(); + int testDestroy(); - virtual ostream& toString(ostream& out) const; + virtual ostream& toString(ostream& out) const; - virtual MTGLifelinkRule * clone() const; + virtual MTGLifelinkRule * clone() const; }; /* Deathtouch */ -class MTGDeathtouchRule:public MTGAbility{ - public: - MTGDeathtouchRule(int _id); +class MTGDeathtouchRule: public MTGAbility +{ +public: + MTGDeathtouchRule(int _id); - int receiveEvent(WEvent * event); + int receiveEvent(WEvent * event); - int testDestroy(); - const char * getMenuText(){return "Deathtouch";} + int testDestroy(); + const char * getMenuText() + { + return "Deathtouch"; + } - virtual MTGDeathtouchRule * clone() const; + virtual MTGDeathtouchRule * clone() const; }; /* HUD Display */ -class HUDString { +class HUDString +{ public: - string value; - float timestamp; - int quantity; - HUDString(string s, float ts):value(s),timestamp(ts){quantity = 1;}; + string value; + float timestamp; + int quantity; + HUDString(string s, float ts) : + value(s), timestamp(ts) + { + quantity = 1; + } + ; }; -class HUDDisplay:public MTGAbility{ +class HUDDisplay: public MTGAbility +{ private: - list events; - float timestamp; - float popdelay; - WFont * f; - float maxWidth; - int addEvent(string s); + list events; + float timestamp; + float popdelay; + WFont * f; + float maxWidth; + int addEvent(string s); public: - int testDestroy(); - int receiveEvent(WEvent * event); - void Update(float dt); - void Render(); - HUDDisplay(int _id); - ~HUDDisplay(); - virtual HUDDisplay * clone() const; + int testDestroy(); + int receiveEvent(WEvent * event); + void Update(float dt); + void Render(); + HUDDisplay(int _id); + ~HUDDisplay(); + virtual HUDDisplay * clone() const; }; - - #endif diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index cbca07ec7..b3e2cce7e 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -22,27 +22,27 @@ public: MODE_TEST_SUITE, MODE_HUMAN, MODE_AI, }; - JTexture * mAvatarTex; - JQuad * mAvatar; - int playMode; - bool canPutLandsIntoPlay; - int landsPlayerCanStillPlay; - bool nomaxhandsize; - int castedspellsthisturn; - bool onlyonecast; - int castcount; - bool nocreatureinstant; - bool nospellinstant; - bool onlyoneinstant; - bool castrestrictedcreature; - bool castrestrictedspell; - bool onlyoneboth; - bool bothrestrictedspell; - bool bothrestrictedcreature; - MTGPlayerCards * game; - string deckFile; - string deckFileSmall; - string deckName; + JTexture * mAvatarTex; + JQuad * mAvatar; + int playMode; + bool canPutLandsIntoPlay; + int landsPlayerCanStillPlay; + bool nomaxhandsize; + int castedspellsthisturn; + bool onlyonecast; + int castcount; + bool nocreatureinstant; + bool nospellinstant; + bool onlyoneinstant; + bool castrestrictedcreature; + bool castrestrictedspell; + bool onlyoneboth; + bool bothrestrictedspell; + bool bothrestrictedcreature; + MTGPlayerCards * game; + string deckFile; + string deckFileSmall; + string deckName; Player(MTGDeck * deck, string deckFile, string deckFileSmall); virtual ~Player(); @@ -71,7 +71,6 @@ public: return 0; } - virtual int isAI() { return 0; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 215bc4bb5..efc8f9c3a 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -14,1346 +14,1406 @@ int AIAction::currentId = 0; int AIAction::Act() { - GameObserver * g = GameObserver::GetInstance(); - if (player) - { - g->cardClick(NULL, player); - return 1; - } - if (ability) - { - g->mLayers->actionLayer()->reactToClick(ability, click); - if (target) g->cardClick(target); - return 1; - } - else if (click) - { //Shouldn't be used, really... - g->cardClick(click, click); - if (target) g->cardClick(target); - return 1; - } - return 0; + GameObserver * g = GameObserver::GetInstance(); + if (player) + { + g->cardClick(NULL, player); + return 1; + } + if (ability) + { + g->mLayers->actionLayer()->reactToClick(ability, click); + if (target) + g->cardClick(target); + return 1; + } + else if (click) + { //Shouldn't be used, really... + g->cardClick(click, click); + if (target) + g->cardClick(target); + return 1; + } + return 0; } AIPlayer::AIPlayer(MTGDeck * deck, string file, string fileSmall) : -Player(deck, file, fileSmall) + Player(deck, file, fileSmall) { - nextCardToPlay = NULL; - stats = NULL; - agressivity = 50; - forceBestAbilityUse = false; - Checked = false; - playMode = Player::MODE_AI; + nextCardToPlay = NULL; + stats = NULL; + agressivity = 50; + forceBestAbilityUse = false; + Checked = false; + playMode = Player::MODE_AI; } AIPlayer::~AIPlayer() { - if (stats) - { - stats->save(); - SAFE_DELETE(stats); - } - while (!clickstream.empty()) - { - AIAction * action = clickstream.front(); - SAFE_DELETE(action); - clickstream.pop(); - } + if (stats) + { + stats->save(); + SAFE_DELETE(stats); + } + while (!clickstream.empty()) + { + AIAction * action = clickstream.front(); + SAFE_DELETE(action); + clickstream.pop(); + } } MTGCardInstance * AIPlayer::chooseCard(TargetChooser * tc, MTGCardInstance * source, int random) { - for (int i = 0; i < game->hand->nb_cards; i++) - { - MTGCardInstance * card = game->hand->cards[i]; - if (!tc->alreadyHasTarget(card) && tc->canTarget(card)) - { - return card; - } - } - return NULL; + for (int i = 0; i < game->hand->nb_cards; i++) + { + MTGCardInstance * card = game->hand->cards[i]; + if (!tc->alreadyHasTarget(card) && tc->canTarget(card)) + { + return card; + } + } + return NULL; } int AIPlayer::Act(float dt) { - GameObserver * gameObs = GameObserver::GetInstance(); - if (gameObs->currentPlayer == this) gameObs->userRequestNextGamePhase(); - return 1; + GameObserver * gameObs = GameObserver::GetInstance(); + if (gameObs->currentPlayer == this) + gameObs->userRequestNextGamePhase(); + return 1; } bool AIPlayer::tapLandsForMana(ManaCost * cost, MTGCardInstance * target) { - DebugTrace(" AI attempting to tap land for mana." << endl - << "- Target: " << (target ? target->name : "None" ) << endl - << "- Cost: " << (cost ? cost->toString() : "NULL") ); - if (!cost) - { - DebugTrace("Mana cost is NULL. "); - return false; - } + DebugTrace(" AI attempting to tap land for mana." << endl + << "- Target: " << (target ? target->name : "None" ) << endl + << "- Cost: " << (cost ? cost->toString() : "NULL") ); + if (!cost) + { + DebugTrace("Mana cost is NULL. "); + return false; + } - ManaCost * pMana = getPotentialMana(target); - ManaCost * diff = pMana->Diff(cost); - delete (pMana); - GameObserver * g = GameObserver::GetInstance(); + ManaCost * pMana = getPotentialMana(target); + ManaCost * diff = pMana->Diff(cost); + delete (pMana); + GameObserver * g = GameObserver::GetInstance(); - map used; - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) - { //0 is not a mtgability...hackish - //Make sure we can use the ability - MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); - AManaProducer * amp = dynamic_cast (a); - if (amp && canHandleCost(amp)) - { - 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) - { - used[card] = true; - int doTap = 1; - for (int i = Constants::MTG_NB_COLORS - 1; i >= 0; i--) - { - if (diff->getCost(i) && amp->output->getCost(i)) - { - diff->remove(i, 1); - doTap = 0; - break; - } - } - if (doTap) - { - AIAction * action = NEW AIAction(amp, card); - clickstream.push(action); - } - } - } - } - delete (diff); - return true; + map used; + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) + { //0 is not a mtgability...hackish + //Make sure we can use the ability + MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); + AManaProducer * amp = dynamic_cast (a); + if (amp && canHandleCost(amp)) + { + 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) + { + used[card] = true; + int doTap = 1; + for (int i = Constants::MTG_NB_COLORS - 1; i >= 0; i--) + { + if (diff->getCost(i) && amp->output->getCost(i)) + { + diff->remove(i, 1); + doTap = 0; + break; + } + } + if (doTap) + { + AIAction * action = NEW AIAction(amp, card); + clickstream.push(action); + } + } + } + } + delete (diff); + return true; } ManaCost * AIPlayer::getPotentialMana(MTGCardInstance * target) { - ManaCost * result = NEW ManaCost(); - GameObserver * g = GameObserver::GetInstance(); - map used; - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) - { //0 is not a mtgability...hackish - //Make sure we can use the ability - MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); - AManaProducer * amp = dynamic_cast (a); - if (amp && canHandleCost(amp)) - { - 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) - { - result->add(amp->output); - used[card] = true; - } - } - } - if(this->getManaPool()->getConvertedCost()) - { - //adding the current manapool if any, to the potential mana Ai can use. - result->add(this->getManaPool()); - } - return result; + ManaCost * result = NEW ManaCost(); + GameObserver * g = GameObserver::GetInstance(); + map used; + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) + { //0 is not a mtgability...hackish + //Make sure we can use the ability + MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); + AManaProducer * amp = dynamic_cast (a); + if (amp && canHandleCost(amp)) + { + 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) + { + result->add(amp->output); + used[card] = true; + } + } + } + if (this->getManaPool()->getConvertedCost()) + { + //adding the current manapool if any, to the potential mana Ai can use. + result->add(this->getManaPool()); + } + return result; } int AIPlayer::getEfficiency(AIAction * action) { - return action->getEfficiency(); + return action->getEfficiency(); } //Can't yet handle extraCost objects (ex: sacrifice) if they require a target :( int AIPlayer::CanHandleCost(ManaCost * cost) { - if (!cost) return 1; + if (!cost) + return 1; - ExtraCosts * ec = cost->extraCosts; - if (!ec) return 1; + ExtraCosts * ec = cost->extraCosts; + if (!ec) + return 1; - for (size_t i = 0; i < ec->costs.size(); ++i) - { - if (ec->costs[i]->tc) - { - return 0; - } - } - return 1; + for (size_t i = 0; i < ec->costs.size(); ++i) + { + if (ec->costs[i]->tc) + { + return 0; + } + } + return 1; } int AIPlayer::canHandleCost(MTGAbility * ability) { - return CanHandleCost(ability->cost); + return CanHandleCost(ability->cost); } // In this function, target represents the target of the currentAIAction object, while _target is the target of the ability of this AIAction object // I can't remember as I type this in which condition we use one or the other for this function, if you find out please replace this comment int AIAction::getEfficiency() { - //TODO add multiplier according to what the player wants - if (efficiency != -1) return efficiency; - if (!ability) return 0; - GameObserver * g = GameObserver::GetInstance(); - ActionStack * s = g->mLayers->stackLayer(); - Player * p = g->currentlyActing(); - if (s->has(ability)) return 0; + //TODO add multiplier according to what the player wants + if (efficiency != -1) + return efficiency; + if (!ability) + return 0; + GameObserver * g = GameObserver::GetInstance(); + ActionStack * s = g->mLayers->stackLayer(); + Player * p = g->currentlyActing(); + if (s->has(ability)) + return 0; - MTGAbility * a = AbilityFactory::getCoreAbility(ability); + MTGAbility * a = AbilityFactory::getCoreAbility(ability); - if (!a) - { - DebugTrace("FATAL: Ability is NULL in AIAction::getEfficiency()"); - return 0; - } + if (!a) + { + DebugTrace("FATAL: Ability is NULL in AIAction::getEfficiency()"); + return 0; + } - if (!((AIPlayer *) p)->canHandleCost(ability)) return 0; - switch (a->aType) - { - case MTGAbility::DAMAGER: - { - AADamager * aad = (AADamager *) a; - if (!target) - { - Targetable * _t = aad->getTarget(); - if (_t == p->opponent()) - efficiency = 90; - else - efficiency = 0; - break; - } - if (p == target->controller()) - { - efficiency = 0; - } - else if (aad->damage->getValue() >= target->toughness) - { - efficiency = 100; - } - else if (target->toughness) - { - efficiency = (50 * aad->damage->getValue()) / target->toughness; - } - else - { - efficiency = 0; - } - break; - } - case MTGAbility::STANDARD_REGENERATE: - { - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - efficiency = 0; - if (!_target) break; + if (!((AIPlayer *) p)->canHandleCost(ability)) + return 0; + switch (a->aType) + { + case MTGAbility::DAMAGER: + { + AADamager * aad = (AADamager *) a; + if (!target) + { + Targetable * _t = aad->getTarget(); + if (_t == p->opponent()) + efficiency = 90; + else + efficiency = 0; + break; + } + if (p == target->controller()) + { + efficiency = 0; + } + else if (aad->damage->getValue() >= target->toughness) + { + efficiency = 100; + } + else if (target->toughness) + { + efficiency = (50 * aad->damage->getValue()) / target->toughness; + } + else + { + efficiency = 0; + } + break; + } + case MTGAbility::STANDARD_REGENERATE: + { + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + efficiency = 0; + if (!_target) + break; - if (!_target->regenerateTokens && g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS && (_target->defenser - || _target->blockers.size())) - { - efficiency = 95; - } + if (!_target->regenerateTokens && g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS + && (_target->defenser || _target->blockers.size()) + ) + { + efficiency = 95; + } - //TODO If the card is the target of a damage spell - break; - } - case MTGAbility::STANDARD_PREVENT: - { - efficiency = 0;//starts out low to avoid spamming it when its not needed. - if (!target) break; + //TODO If the card is the target of a damage spell + break; + } + case MTGAbility::STANDARD_PREVENT: + { + efficiency = 0;//starts out low to avoid spamming it when its not needed. + if (!target) + break; - bool NeedPreventing; - NeedPreventing = false; - if (g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS) - { - if ((target->defenser || target->blockers.size()) && target->preventable < target->getNextOpponent()->power) NeedPreventing - = true; - } - if (p == target->controller() && NeedPreventing == true && !(target->getNextOpponent()->has(Constants::DEATHTOUCH) - || target->getNextOpponent()->has(Constants::WITHER))) - { - efficiency = 20 * (target->DangerRanking());//increase this chance to be used in combat if the creature blocking/blocked could kill the creature this chance is taking into consideration how good the creature is, best creature will always be the first "saved".. - if (target->toughness == 1 && target->getNextOpponent()->power == 1) efficiency += 15; - //small bonus added for the poor 1/1s, if we can save them, we will unless something else took precidence. - } - //note is the target is being blocked or blocking a creature with wither or deathtouch, it is not even considered for preventing as it is a waste. - //if its combat blockers, it is being blocked or blocking, and has less prevents the the amount of damage it will be taking, the effeincy is increased slightly and totalled by the danger rank multiplier for final result. - //TODO If the card is the target of a damage spell - break; - } - case MTGAbility::STANDARD_EQUIP: - { + bool NeedPreventing; + NeedPreventing = false; + if (g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS) + { + if ((target->defenser || target->blockers.size()) && target->preventable < target->getNextOpponent()->power) + NeedPreventing = true; + } + if (p == target->controller() && NeedPreventing == true && !(target->getNextOpponent()->has(Constants::DEATHTOUCH) + || target->getNextOpponent()->has(Constants::WITHER))) + { + efficiency = 20 * (target->DangerRanking());//increase this chance to be used in combat if the creature blocking/blocked could kill the creature this chance is taking into consideration how good the creature is, best creature will always be the first "saved".. + if (target->toughness == 1 && target->getNextOpponent()->power == 1) + efficiency += 15; + //small bonus added for the poor 1/1s, if we can save them, we will unless something else took precidence. + } + //note is the target is being blocked or blocking a creature with wither or deathtouch, it is not even considered for preventing as it is a waste. + //if its combat blockers, it is being blocked or blocking, and has less prevents the the amount of damage it will be taking, the effeincy is increased slightly and totalled by the danger rank multiplier for final result. + //TODO If the card is the target of a damage spell + break; + } + case MTGAbility::STANDARD_EQUIP: + { - efficiency = 0; - if (!target) break; + efficiency = 0; + if (!target) + break; - int equips = p->game->battlefield->countByType("Equipment"); - int myArmy = p->game->battlefield->countByType("Creature"); - int equilized = abs(equips / myArmy); + int equips = p->game->battlefield->countByType("Equipment"); + int myArmy = p->game->battlefield->countByType("Creature"); + int equilized = abs(equips / myArmy); - if (p == target->controller() && target->equipment <= 1 && !a->source->target) - { - efficiency = 20 * (target->DangerRanking()); - if (target->hasColor(5)) efficiency += 20;//this is to encourage Ai to equip white creatures in a weenie deck. ultimately it will depend on what had the higher dangerranking. - if (target->power == 1 && target->toughness == 1 && target->isToken == 0) efficiency += 10; //small bonus to encourage equipping nontoken 1/1 creatures. - } + if (p == target->controller() && target->equipment <= 1 && !a->source->target) + { + efficiency = 20 * (target->DangerRanking()); + if (target->hasColor(5)) + efficiency += 20;//this is to encourage Ai to equip white creatures in a weenie deck. ultimately it will depend on what had the higher dangerranking. + if (target->power == 1 && target->toughness == 1 && target->isToken == 0) + efficiency += 10; //small bonus to encourage equipping nontoken 1/1 creatures. + } - if (p == target->controller() && !a->source->target && target->equipment < equilized) - { - efficiency = 15 * (target->DangerRanking()); - efficiency -= 5 * (target->equipment); - } - break; - } + if (p == target->controller() && !a->source->target && target->equipment < equilized) + { + efficiency = 15 * (target->DangerRanking()); + efficiency -= 5 * (target->equipment); + } + break; + } - case MTGAbility::STANDARD_LEVELUP: - { - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - efficiency = 0; - Counter * targetCounter = NULL; - int currentlevel = 0; + case MTGAbility::STANDARD_LEVELUP: + { + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + efficiency = 0; + Counter * targetCounter = NULL; + int currentlevel = 0; - if (_target) - { - if (_target->counters && _target->counters->hasCounter("level", 0, 0)) - { - targetCounter = _target->counters->hasCounter("level", 0, 0); - currentlevel = targetCounter->nb; - } - } - - if (currentlevel < _target->MaxLevelUp) - { - efficiency = 85; - //increase the efficeincy of leveling up by a small amount equal to current level. - efficiency += currentlevel; - } - - if (p->game->hand->nb_cards > 0 && p->isAI()) - { - efficiency -= (10 * p->game->hand->nb_cards);//reduce the eff if by 10 times the amount of cards in Ais hand. - //it should always try playing more cards before deciding - } - - if (g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN) - { - efficiency = 100; - //in 2nd main, go all out and try to max stuff. - } - break; - } - case MTGAbility::STANDARD_PUMP: - { - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - if (!target) break; - //i do not set a starting eff. on this ability, this allows Ai to sometimes randomly do it as it normally does. - if (g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS) - { - if (BAKA_EFFECT_GOOD) - { - if ((_target->defenser || _target->blockers.size()) && ((_target->power < _target->getNextOpponent()->toughness - || _target->toughness < _target->getNextOpponent()->power) || (_target->has(Constants::TRAMPLE)))) - { - //this pump is based on a start eff. of 20 multiplied by how good the creature is. - efficiency = 20 * _target->DangerRanking(); - } - if (_target->isAttacker() && !_target->blockers.size()) - { - //this means im heading directly for the player, pump this creature as much as possible. - efficiency = 100; - } - } - } - break; - } - case MTGAbility::STANDARD_BECOMES: - { - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - //nothing huge here, just ensuring that Ai makes his noncreature becomers into creatures during first main, so it can actually use them in combat. - if (_target && !_target->hasType("Creature") && g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN) - { - efficiency = 100; - } - break; - } - - case MTGAbility::UPCOST: - { - //hello, Ai pay your upcost please :P, this entices Ai into paying upcost, the conditional isAi() is required strangely ai is able to pay upcost during YOUR upkeep. - if (g->getCurrentGamePhase() == Constants::MTG_PHASE_UPKEEP && g->currentPlayer->isAI()) - { - efficiency = 100; - } - break; - } - - case MTGAbility::FOREACH: - { - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - MTGAbility * a = AbilityFactory::getCoreAbility(ability); - AManaProducer * amp = dynamic_cast (a); - efficiency = 0; - //trying to encourage Ai to use his foreach manaproducers in first main - if (a->naType == MTGAbility::MANA_PRODUCER && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN - || g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN) && _target->controller()->game->hand->nb_cards > 0) - { - for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) - { - if ((p->game->hand->hasColor(i) || p->game->hand->hasColor(0)) - && (dynamic_cast ((dynamic_cast (a)->ability))->output->hasColor(i))) - { - efficiency = 100; - } - } - - if (p->game->hand->hasX()) efficiency = 100; - - } - else - { - AbilityFactory af; - int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); - - if (target && a->naType != MTGAbility::MANA_PRODUCER && ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) - || (suggestion == BAKA_EFFECT_GOOD && p != target->controller()))) - { - efficiency = 0; - } - else if (a->naType != MTGAbility::MANA_PRODUCER && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN - || g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN)) - { - //if its not a manaproducing foreach, and its not targetted, its eff is 90. - //added this basically to cover the unknown foreachs, or untrained ones which were not targetted effects. - efficiency = 90; - } - - } - break; - } - - case MTGAbility::STANDARDABILITYGRANT: - { - efficiency = 0; - MTGCardInstance * _target = (MTGCardInstance *) (a->target); - if (!target) break; - //ensuring that Ai grants abilities to creatures during first main, so it can actually use them in combat. - //quick note: the eff is multiplied by creatures ranking then divided by the number of cards in hand. - //the reason i do this is to encourage more casting and less waste of mana on abilities. - AbilityFactory af; - int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); - - int efficiencyModifier = (25 * target->DangerRanking()); - if (p->game->hand->nb_cards > 1) + if (_target) + { + if (_target->counters && _target->counters->hasCounter("level", 0, 0)) { - efficiencyModifier /= p->game->hand->nb_cards; + targetCounter = _target->counters->hasCounter("level", 0, 0); + currentlevel = targetCounter->nb; } - if (suggestion == BAKA_EFFECT_BAD && p != target->controller() && target->has(a->abilitygranted) && p->isAI()) - { - efficiency += efficiencyModifier; - } + } - if (!target->has(a->abilitygranted) && g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBEGIN && p == target->controller() && p->isAI()) - { - efficiency += efficiencyModifier; - } + if (currentlevel < _target->MaxLevelUp) + { + efficiency = 85; + //increase the efficeincy of leveling up by a small amount equal to current level. + efficiency += currentlevel; + } - if (suggestion == BAKA_EFFECT_GOOD && target->has(a->abilitygranted)) - { - //trying to avoid Ai giving ie:flying creatures ie:flying twice. - efficiency = 0; - } + if (p->game->hand->nb_cards > 0 && p->isAI()) + { + efficiency -= (10 * p->game->hand->nb_cards);//reduce the eff if by 10 times the amount of cards in Ais hand. + //it should always try playing more cards before deciding + } - if ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) || (suggestion == BAKA_EFFECT_GOOD && p - != target->controller())) - { - efficiency = 0; - //stop giving trample to the players creatures. - } - break; - } + if (g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN) + { + efficiency = 100; + //in 2nd main, go all out and try to max stuff. + } + break; + } + case MTGAbility::STANDARD_PUMP: + { + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + if (!target) + break; + //i do not set a starting eff. on this ability, this allows Ai to sometimes randomly do it as it normally does. + if (g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBLOCKERS) + { + if (BAKA_EFFECT_GOOD) + { + if ((_target->defenser || _target->blockers.size()) && ((_target->power < _target->getNextOpponent()->toughness + || _target->toughness < _target->getNextOpponent()->power) || (_target->has(Constants::TRAMPLE)))) + { + //this pump is based on a start eff. of 20 multiplied by how good the creature is. + efficiency = 20 * _target->DangerRanking(); + } + if (_target->isAttacker() && !_target->blockers.size()) + { + //this means im heading directly for the player, pump this creature as much as possible. + efficiency = 100; + } + } + } + break; + } + case MTGAbility::STANDARD_BECOMES: + { + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + //nothing huge here, just ensuring that Ai makes his noncreature becomers into creatures during first main, so it can actually use them in combat. + if (_target && !_target->hasType("Creature") && g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN) + { + efficiency = 100; + } + break; + } - case MTGAbility::UNTAPPER: - //untap things that Ai owns and are tapped. - { - efficiency = 0; - if (!target) break; + case MTGAbility::UPCOST: + { + //hello, Ai pay your upcost please :P, this entices Ai into paying upcost, the conditional isAi() is required strangely ai is able to pay upcost during YOUR upkeep. + if (g->getCurrentGamePhase() == Constants::MTG_PHASE_UPKEEP && g->currentPlayer->isAI()) + { + efficiency = 100; + } + break; + } - if (target->isTapped() && target->controller()->isAI()) - { - efficiency = (20 * target->DangerRanking()); - } - break; - } + case MTGAbility::FOREACH: + { + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + MTGAbility * a = AbilityFactory::getCoreAbility(ability); + AManaProducer * amp = dynamic_cast (a); + efficiency = 0; + //trying to encourage Ai to use his foreach manaproducers in first main + if (a->naType == MTGAbility::MANA_PRODUCER && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN + || g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN) && _target->controller()->game->hand->nb_cards > 0) + { + for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) + { + if ((p->game->hand->hasColor(i) || p->game->hand->hasColor(0)) + && (dynamic_cast ((dynamic_cast (a)->ability))->output->hasColor(i))) + { + efficiency = 100; + } + } - case MTGAbility::TAPPER: - //tap things the player owns and that are untapped. - { - if (!target) break; + if (p->game->hand->hasX()) + efficiency = 100; - if (!target->controller()->isAI()) efficiency = (20 * target->DangerRanking()); + } + else + { + AbilityFactory af; + int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); - if (target->isTapped()) efficiency = 0; + if (target && a->naType != MTGAbility::MANA_PRODUCER && ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) + || (suggestion == BAKA_EFFECT_GOOD && p != target->controller()))) + { + efficiency = 0; + } + else if (a->naType != MTGAbility::MANA_PRODUCER && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN + || g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN)) + { + //if its not a manaproducing foreach, and its not targetted, its eff is 90. + //added this basically to cover the unknown foreachs, or untrained ones which were not targetted effects. + efficiency = 90; + } - break; - } + } + break; + } - case MTGAbility::LIFER: - { - //use life abilities whenever possible. - AALifer * alife = (AALifer *) a; - Targetable * _t = alife->getTarget(); + case MTGAbility::STANDARDABILITYGRANT: + { + efficiency = 0; + MTGCardInstance * _target = (MTGCardInstance *) (a->target); + if (!target) + break; + //ensuring that Ai grants abilities to creatures during first main, so it can actually use them in combat. + //quick note: the eff is multiplied by creatures ranking then divided by the number of cards in hand. + //the reason i do this is to encourage more casting and less waste of mana on abilities. + AbilityFactory af; + int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); - efficiency = 100; - AbilityFactory af; - int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); + int efficiencyModifier = (25 * target->DangerRanking()); + if (p->game->hand->nb_cards > 1) + { + efficiencyModifier /= p->game->hand->nb_cards; + } + if (suggestion == BAKA_EFFECT_BAD && p != target->controller() && target->has(a->abilitygranted) && p->isAI()) + { + efficiency += efficiencyModifier; + } - if ((suggestion == BAKA_EFFECT_BAD && _t == p && p->isAI()) || (suggestion == BAKA_EFFECT_GOOD && _t == p && !p->isAI())) - { - efficiency = 0; - } + if (!target->has(a->abilitygranted) && g->getCurrentGamePhase() == Constants::MTG_PHASE_COMBATBEGIN + && p == target->controller() && p->isAI() + ) + { + efficiency += efficiencyModifier; + } - break; - } - case MTGAbility::STANDARD_DRAW: - { - //adding this case since i played a few games where Ai litterally decided to mill himself to death. fastest and easiest win ever. - //this should help a little, tho ultimately it will be decided later what the best course of action is. - efficiency = 0; - //eff of drawing ability is calculated by base 20 + the amount of cards in library minus the amount of cards in hand times 7. - //drawing is never going to return a hundred eff because later eff is multiplied by 1.3 if no cards in hand. - efficiency = int(20 + p->game->library->nb_cards) - int(p->game->hand->nb_cards * 7); - if(p->game->hand->nb_cards > 8)//reduce by 50 if cards in hand are over 8, high chance ai cant play them. - { - efficiency -= 70; - } - if((a->nbcardAmount >= p->game->library->nb_cards && p->isAI()) || (p->game->hand->nb_cards > 10 && p->isAI())) - { - //if the amount im drawing will mill me to death or i have more then 10 cards in hand, eff is 0; - efficiency = 0; - } - break; - } - case MTGAbility::CLONING: - { - efficiency = 0; - if (p == target->controller()) - { - efficiency = 20 * target->DangerRanking(); - } - break; - } - case MTGAbility::MANA_PRODUCER: - efficiency = 0; - break; + if (suggestion == BAKA_EFFECT_GOOD && target->has(a->abilitygranted)) + { + //trying to avoid Ai giving ie:flying creatures ie:flying twice. + efficiency = 0; + } - default: - if (target) - { - AbilityFactory af; - int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); - if ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) || (suggestion == BAKA_EFFECT_GOOD && p - != target->controller())) - { - efficiency = 0; - } - else - { - efficiency = WRand() % 5; //Small percentage of chance for unknown abilities - } - } - else - { - efficiency = WRand() % 10; - } - break; - } + if ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) + || (suggestion == BAKA_EFFECT_GOOD && p != target->controller()) + ) + { + efficiency = 0; + //stop giving trample to the players creatures. + } + break; + } - if (p->game->hand->nb_cards == 0) efficiency = (int) ((float) efficiency * 1.3); //increase chance of using ability if hand is empty - if (ability->cost) - { - ExtraCosts * ec = ability->cost->extraCosts; - if (ec) efficiency = efficiency / 3; //Decrease chance of using ability if there is an extra cost to use the ability - } - return efficiency; + case MTGAbility::UNTAPPER: + //untap things that Ai owns and are tapped. + { + efficiency = 0; + if (!target) + break; + + if (target->isTapped() && target->controller()->isAI()) + { + efficiency = (20 * target->DangerRanking()); + } + break; + } + + case MTGAbility::TAPPER: + //tap things the player owns and that are untapped. + { + if (!target) + break; + + if (!target->controller()->isAI()) + efficiency = (20 * target->DangerRanking()); + + if (target->isTapped()) + efficiency = 0; + + break; + } + + case MTGAbility::LIFER: + { + //use life abilities whenever possible. + AALifer * alife = (AALifer *) a; + Targetable * _t = alife->getTarget(); + + efficiency = 100; + AbilityFactory af; + int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); + + if ((suggestion == BAKA_EFFECT_BAD && _t == p && p->isAI()) || (suggestion == BAKA_EFFECT_GOOD && _t == p && !p->isAI())) + { + efficiency = 0; + } + + break; + } + case MTGAbility::STANDARD_DRAW: + { + //adding this case since i played a few games where Ai litterally decided to mill himself to death. fastest and easiest win ever. + //this should help a little, tho ultimately it will be decided later what the best course of action is. + efficiency = 0; + //eff of drawing ability is calculated by base 20 + the amount of cards in library minus the amount of cards in hand times 7. + //drawing is never going to return a hundred eff because later eff is multiplied by 1.3 if no cards in hand. + efficiency = int(20 + p->game->library->nb_cards) - int(p->game->hand->nb_cards * 7); + if (p->game->hand->nb_cards > 8)//reduce by 50 if cards in hand are over 8, high chance ai cant play them. + { + efficiency -= 70; + } + if ((a->nbcardAmount >= p->game->library->nb_cards && p->isAI()) || (p->game->hand->nb_cards > 10 && p->isAI())) + { + //if the amount im drawing will mill me to death or i have more then 10 cards in hand, eff is 0; + efficiency = 0; + } + break; + } + case MTGAbility::CLONING: + { + efficiency = 0; + if (p == target->controller()) + { + efficiency = 20 * target->DangerRanking(); + } + break; + } + case MTGAbility::MANA_PRODUCER: + efficiency = 0; + break; + + default: + if (target) + { + AbilityFactory af; + int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY); + if ((suggestion == BAKA_EFFECT_BAD && p == target->controller()) + || (suggestion == BAKA_EFFECT_GOOD && p != target->controller())) + { + efficiency = 0; + } + else + { + efficiency = WRand() % 5; //Small percentage of chance for unknown abilities + } + } + else + { + efficiency = WRand() % 10; + } + break; + } + + if (p->game->hand->nb_cards == 0) + efficiency = (int) ((float) efficiency * 1.3); //increase chance of using ability if hand is empty + if (ability->cost) + { + ExtraCosts * ec = ability->cost->extraCosts; + if (ec) + efficiency = efficiency / 3; //Decrease chance of using ability if there is an extra cost to use the ability + } + return efficiency; } int AIPlayer::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingContainer& ranking) { - if (!a->tc) - { - AIAction aiAction(a, c, NULL); - ranking[aiAction] = 1; - return 1; - } - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2; i++) - { - Player * p = g->players[i]; - MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay }; - for (int j = 0; j < 4; j++) - { - MTGGameZone * zone = playerZones[j]; - for (int k = 0; k < zone->nb_cards; k++) - { - MTGCardInstance * t = zone->cards[k]; - if (a->tc->canTarget(t)) - { + if (!a->tc) + { + AIAction aiAction(a, c, NULL); + ranking[aiAction] = 1; + return 1; + } + GameObserver * g = GameObserver::GetInstance(); + for (int i = 0; i < 2; i++) + { + Player * p = g->players[i]; + MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay }; + for (int j = 0; j < 4; j++) + { + MTGGameZone * zone = playerZones[j]; + for (int k = 0; k < zone->nb_cards; k++) + { + MTGCardInstance * t = zone->cards[k]; + if (a->tc->canTarget(t)) + { - AIAction aiAction(a, c, t); - ranking[aiAction] = 1; - } - } - } - } - return 1; + AIAction aiAction(a, c, t); + ranking[aiAction] = 1; + } + } + } + } + return 1; } int AIPlayer::selectAbility() { - static bool findingAbility = false; - //this guard is put in place to prevent Ai from - //ever running selectAbility() function WHILE its already doing so. - + static bool findingAbility = false; + //this guard is put in place to prevent Ai from + //ever running selectAbility() function WHILE its already doing so. + // Break if this happens in debug mode. If this happens, it's actually a bug assert(!findingAbility); - if (findingAbility) - {//is already looking kick me out of this function! - return 0; - } - findingAbility = true;//im looking now safely! - RankingContainer ranking; - list::iterator it; - GameObserver * g = GameObserver::GetInstance(); - //This loop is extrmely inefficient. TODO: optimize! - ManaCost * totalPotentialMana = getPotentialMana(); - for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) - { //0 is not a mtgability...hackish - MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); - //Skip mana abilities for performance - if (dynamic_cast (a)) continue; - //Make sure we can use the ability - for (int j = 0; j < game->inPlay->nb_cards; j++) - { - MTGCardInstance * card = game->inPlay->cards[j]; - if (a->isReactingToClick(card, totalPotentialMana)) - { //This test is to avoid the huge call to getPotentialManaCost after that - ManaCost * pMana = getPotentialMana(card); - if (a->isReactingToClick(card, pMana)) + if (findingAbility) + {//is already looking kick me out of this function! + return 0; + } + findingAbility = true;//im looking now safely! + RankingContainer ranking; + list::iterator it; + GameObserver * g = GameObserver::GetInstance(); + //This loop is extrmely inefficient. TODO: optimize! + ManaCost * totalPotentialMana = getPotentialMana(); + for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++) + { //0 is not a mtgability...hackish + MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]); + //Skip mana abilities for performance + if (dynamic_cast (a)) + continue; + //Make sure we can use the ability + for (int j = 0; j < game->inPlay->nb_cards; j++) + { + MTGCardInstance * card = game->inPlay->cards[j]; + if (a->isReactingToClick(card, totalPotentialMana)) + { //This test is to avoid the huge call to getPotentialManaCost after that + ManaCost * pMana = getPotentialMana(card); + if (a->isReactingToClick(card, pMana)) createAbilityTargets(a, card, ranking); - delete (pMana); - } - } - } - delete totalPotentialMana; + delete (pMana); + } + } + } + delete totalPotentialMana; - if (ranking.size()) - { - AIAction action = ranking.begin()->first; - int chance = 1; - if (!forceBestAbilityUse) chance = 1 + WRand() % 100; - if (action.getEfficiency() >= chance) - { - if (!clickstream.size()) - { - DebugTrace("AIPlayer:Using Activated ability"); - if (tapLandsForMana(action.ability->cost, action.click)) - clickstream.push(NEW AIAction(action)); - } - } - } - findingAbility = false;//ok to start looking again. - return 1; + if (ranking.size()) + { + AIAction action = ranking.begin()->first; + int chance = 1; + if (!forceBestAbilityUse) + chance = 1 + WRand() % 100; + if (action.getEfficiency() >= chance) + { + if (!clickstream.size()) + { + DebugTrace("AIPlayer:Using Activated ability"); + if (tapLandsForMana(action.ability->cost, action.click)) + clickstream.push(NEW AIAction(action)); + } + } + } + findingAbility = false;//ok to start looking again. + return 1; } int AIPlayer::interruptIfICan() { - GameObserver * g = GameObserver::GetInstance(); + GameObserver * g = GameObserver::GetInstance(); - if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this) - { - if (!clickstream.empty()) - g->mLayers->stackLayer()->cancelInterruptOffer(); - else - g->mLayers->stackLayer()->setIsInterrupting(this); - return 1; - } - return 0; + if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this) + { + if (!clickstream.empty()) + g->mLayers->stackLayer()->cancelInterruptOffer(); + else + g->mLayers->stackLayer()->setIsInterrupting(this); + return 1; + } + return 0; } int AIPlayer::effectBadOrGood(MTGCardInstance * card, int mode, TargetChooser * tc) { - int id = card->getMTGId(); - AbilityFactory af; - int autoGuess = af.magicText(id, NULL, card, mode, tc); - if (autoGuess) return autoGuess; - return BAKA_EFFECT_DONTKNOW; + int id = card->getMTGId(); + AbilityFactory af; + int autoGuess = af.magicText(id, NULL, card, mode, tc); + if (autoGuess) + return autoGuess; + return BAKA_EFFECT_DONTKNOW; } int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget) { - vector potentialTargets; - TargetChooser * tc = _tc; - int nbtargets = 0; - GameObserver * gameObs = GameObserver::GetInstance(); - int checkOnly = 0; - if (tc) - { - checkOnly = 1; - } - else - { - tc = gameObs->getCurrentTargetChooser(); - } - if (!tc) return 0; + vector potentialTargets; + TargetChooser * tc = _tc; + int nbtargets = 0; + GameObserver * gameObs = GameObserver::GetInstance(); + int checkOnly = 0; + if (tc) + { + checkOnly = 1; + } + else + { + tc = gameObs->getCurrentTargetChooser(); + } + if (!tc) + return 0; tc->initTargets(); //cleanup the targetchooser just in case. - if (!(gameObs->currentlyActing() == this)) return 0; - Player * target = forceTarget; + if (!(gameObs->currentlyActing() == this)) + return 0; + Player * target = forceTarget; - if (!target) - { - target = this; - int cardEffect = effectBadOrGood(tc->source, MODE_TARGET, tc); - if (cardEffect != BAKA_EFFECT_GOOD) - { - target = this->opponent(); - } - } + if (!target) + { + target = this; + int cardEffect = effectBadOrGood(tc->source, MODE_TARGET, tc); + if (cardEffect != BAKA_EFFECT_GOOD) + { + target = this->opponent(); + } + } - if (!tc->alreadyHasTarget(target) && tc->canTarget(target) && nbtargets < 50) - { - for (int i = 0; i < 3; i++) - { //Increase probability to target a player when this is possible - potentialTargets.push_back(target); - nbtargets++; - } - if (checkOnly) return 1; - } - MTGPlayerCards * playerZones = target->game; - MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard }; - for (int j = 0; j < 4; j++) - { - MTGGameZone * zone = zones[j]; - 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) - { - int i = WRand() % nbtargets; - int type = potentialTargets[i]->typeAsTarget(); - switch (type) - { - case TARGET_CARD: - { - 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; - } - } - } - //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()); + if (!tc->alreadyHasTarget(target) && tc->canTarget(target) && nbtargets < 50) + { + for (int i = 0; i < 3; i++) + { //Increase probability to target a player when this is possible + potentialTargets.push_back(target); + nbtargets++; + } + if (checkOnly) + return 1; + } + MTGPlayerCards * playerZones = target->game; + MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard }; + for (int j = 0; j < 4; j++) + { + MTGGameZone * zone = zones[j]; + 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) + { + int i = WRand() % nbtargets; + int type = potentialTargets[i]->typeAsTarget(); + switch (type) + { + case TARGET_CARD: + { + 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; + } + } + } + //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()); - //ERROR!!! - DebugTrace("AIPLAYER: ERROR! AI needs to choose a target but can't decide!!!"); - return 0; + //ERROR!!! + DebugTrace("AIPLAYER: ERROR! AI needs to choose a target but can't decide!!!"); + return 0; } int AIPlayer::getCreaturesInfo(Player * player, int neededInfo, int untapMode, int canAttack) { - int result = 0; - CardDescriptor cd; - cd.init(); - cd.setType("Creature"); - cd.unsecureSetTapped(untapMode); - MTGCardInstance * card = NULL; - while ((card = cd.nextmatch(player->game->inPlay, card))) - { - if (!canAttack || card->canAttack()) - { - if (neededInfo == INFO_NBCREATURES) - { - result++; - } - else - { - result += card->power; - } - } - } - return result; + int result = 0; + CardDescriptor cd; + cd.init(); + cd.setType("Creature"); + cd.unsecureSetTapped(untapMode); + MTGCardInstance * card = NULL; + while ((card = cd.nextmatch(player->game->inPlay, card))) + { + if (!canAttack || card->canAttack()) + { + if (neededInfo == INFO_NBCREATURES) + { + result++; + } + else + { + result += card->power; + } + } + } + return result; } int AIPlayer::chooseAttackers() { - //Attack with all creatures - //How much damage can the other player do during his next Attack ? - int opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER); - int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES); - int myForce = getCreaturesInfo(this, INFO_CREATURESPOWER, -1, 1); - int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1, 1); - bool attack = ((myCreatures > opponentCreatures) || (myForce > opponentForce) || (myForce > 2 * opponent()->life)); - if (agressivity > 80 && !attack && life > opponentForce) - { - opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); - opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER, -1); - attack = (myCreatures >= opponentCreatures && myForce > opponentForce) || (myForce > opponentForce) || (myForce - > opponent()->life); - } - printf("Choose attackers : %i %i %i %i -> %i\n", opponentForce, opponentCreatures, myForce, myCreatures, attack); - if (attack) - { - CardDescriptor cd; - cd.init(); - cd.setType("creature"); - MTGCardInstance * card = NULL; - GameObserver * g = GameObserver::GetInstance(); - MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_ATTACK_RULE); - while ((card = cd.nextmatch(game->inPlay, card))) - { - g->mLayers->actionLayer()->reactToClick(a, card); - } - } - return 1; + //Attack with all creatures + //How much damage can the other player do during his next Attack ? + int opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER); + int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES); + int myForce = getCreaturesInfo(this, INFO_CREATURESPOWER, -1, 1); + int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1, 1); + bool attack = ((myCreatures > opponentCreatures) || (myForce > opponentForce) || (myForce > 2 * opponent()->life)); + if (agressivity > 80 && !attack && life > opponentForce) + { + opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); + opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER, -1); + attack = (myCreatures >= opponentCreatures && myForce > opponentForce) + || (myForce > opponentForce) || (myForce > opponent()->life); + } + printf("Choose attackers : %i %i %i %i -> %i\n", opponentForce, opponentCreatures, myForce, myCreatures, attack); + if (attack) + { + CardDescriptor cd; + cd.init(); + cd.setType("creature"); + MTGCardInstance * card = NULL; + GameObserver * g = GameObserver::GetInstance(); + MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_ATTACK_RULE); + while ((card = cd.nextmatch(game->inPlay, card))) + { + g->mLayers->actionLayer()->reactToClick(a, card); + } + } + return 1; } /* Can I first strike my oponent and get away with murder ? */ int AIPlayer::canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy) { - if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) return 0; - if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) return 0; - if (!(card->power >= ennemy->toughness)) return 0; - if (!(card->power >= ennemy->toughness + 1) && ennemy->has(Constants::FLANKING)) return 0; - return 1; + if (ennemy->has(Constants::FIRSTSTRIKE) || ennemy->has(Constants::DOUBLESTRIKE)) + return 0; + if (!(card->has(Constants::FIRSTSTRIKE) || card->has(Constants::DOUBLESTRIKE))) + return 0; + if (!(card->power >= ennemy->toughness)) + return 0; + if (!(card->power >= ennemy->toughness + 1) && ennemy->has(Constants::FLANKING)) + return 0; + return 1; } int AIPlayer::chooseBlockers() { - map opponentsToughness; - int opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER); - //int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); - //int myForce = getCreaturesInfo(this,INFO_CREATURESPOWER); - //int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES, -1); - CardDescriptor cd; - cd.init(); - cd.setType("Creature"); - cd.unsecureSetTapped(-1); - MTGCardInstance * card = NULL; - GameObserver * g = GameObserver::GetInstance(); - MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_BLOCK_RULE); + map opponentsToughness; + int opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER); + CardDescriptor cd; + cd.init(); + cd.setType("Creature"); + cd.unsecureSetTapped(-1); + MTGCardInstance * card = NULL; + GameObserver * g = GameObserver::GetInstance(); + MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_BLOCK_RULE); - while ((card = cd.nextmatch(game->inPlay, card))) - { - g->mLayers->actionLayer()->reactToClick(a, card); - int set = 0; - while (!set) - { - if (!card->defenser) - { - set = 1; - } - else - { - MTGCardInstance * attacker = card->defenser; - map::iterator it = opponentsToughness.find(attacker); - if (it == opponentsToughness.end()) - { - opponentsToughness[attacker] = attacker->toughness; - it = opponentsToughness.find(attacker); - } - if (opponentsToughness[attacker] > 0 && getStats() && getStats()->isInTop(attacker, 3, false)) - { - opponentsToughness[attacker] -= card->power; - set = 1; - } - else - { - g->mLayers->actionLayer()->reactToClick(a, card); - } - } - } - } - card = NULL; - while ((card = cd.nextmatch(game->inPlay, card))) - { - if (card->defenser && opponentsToughness[card->defenser] > 0) - { - while (card->defenser) - { - g->mLayers->actionLayer()->reactToClick(a, card); - } - } - } - card = NULL; - while ((card = cd.nextmatch(game->inPlay, card))) - { - if (!card->defenser) - { - g->mLayers->actionLayer()->reactToClick(a, card); - int set = 0; - while (!set) - { - if (!card->defenser) - { - set = 1; - } - else - { - MTGCardInstance * attacker = card->defenser; - if (opponentsToughness[attacker] <= 0 || (card->toughness <= attacker->power && opponentForce * 2 < life - && !canFirstStrikeKill(card, attacker)) || attacker->nbOpponents() > 1 || attacker->controller()->isAI()) - { - g->mLayers->actionLayer()->reactToClick(a, card); - } - else - { - set = 1; - } - } - } - } - } - return 1; + while ((card = cd.nextmatch(game->inPlay, card))) + { + g->mLayers->actionLayer()->reactToClick(a, card); + int set = 0; + while (!set) + { + if (!card->defenser) + { + set = 1; + } + else + { + MTGCardInstance * attacker = card->defenser; + map::iterator it = opponentsToughness.find(attacker); + if (it == opponentsToughness.end()) + { + opponentsToughness[attacker] = attacker->toughness; + it = opponentsToughness.find(attacker); + } + if (opponentsToughness[attacker] > 0 && getStats() && getStats()->isInTop(attacker, 3, false)) + { + opponentsToughness[attacker] -= card->power; + set = 1; + } + else + { + g->mLayers->actionLayer()->reactToClick(a, card); + } + } + } + } + card = NULL; + while ((card = cd.nextmatch(game->inPlay, card))) + { + if (card->defenser && opponentsToughness[card->defenser] > 0) + { + while (card->defenser) + { + g->mLayers->actionLayer()->reactToClick(a, card); + } + } + } + card = NULL; + while ((card = cd.nextmatch(game->inPlay, card))) + { + if (!card->defenser) + { + g->mLayers->actionLayer()->reactToClick(a, card); + int set = 0; + while (!set) + { + if (!card->defenser) + { + set = 1; + } + else + { + MTGCardInstance * attacker = card->defenser; + if (opponentsToughness[attacker] <= 0 || (card->toughness <= attacker->power && opponentForce * 2 < life + && !canFirstStrikeKill(card, attacker)) || attacker->nbOpponents() > 1 + || attacker->controller()->isAI()) + { + g->mLayers->actionLayer()->reactToClick(a, card); + } + else + { + set = 1; + } + } + } + } + } + return 1; } int AIPlayer::orderBlockers() { - GameObserver * g = GameObserver::GetInstance(); - if (ORDER == g->combatStep && g->currentPlayer == this) - { - DebugTrace("AIPLAYER: order blockers"); - g->userRequestNextGamePhase(); //TODO clever rank of blockers - return 1; - } + GameObserver * g = GameObserver::GetInstance(); + if (ORDER == g->combatStep && g->currentPlayer == this) + { + DebugTrace("AIPLAYER: order blockers"); + g->userRequestNextGamePhase(); //TODO clever rank of blockers + return 1; + } - return 0; + return 0; } int AIPlayer::affectCombatDamages(CombatStep step) { - GameObserver * g = GameObserver::GetInstance(); - GuiCombat * gc = g->mLayers->combatLayer(); - for (vector::iterator attacker = gc->attackers.begin(); attacker != gc->attackers.end(); ++attacker) - gc->autoaffectDamage(*attacker, step); - return 1; + GameObserver * g = GameObserver::GetInstance(); + GuiCombat * gc = g->mLayers->combatLayer(); + for (vector::iterator attacker = gc->attackers.begin(); attacker != gc->attackers.end(); ++attacker) + gc->autoaffectDamage(*attacker, step); + return 1; } //TODO: Deprecate combatDamages int AIPlayer::combatDamages() { - //int result = 0; - GameObserver * gameObs = GameObserver::GetInstance(); - int currentGamePhase = gameObs->getCurrentGamePhase(); + //int result = 0; + GameObserver * gameObs = GameObserver::GetInstance(); + int currentGamePhase = gameObs->getCurrentGamePhase(); - if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS) return orderBlockers(); + if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS) + return orderBlockers(); - if (currentGamePhase != Constants::MTG_PHASE_COMBATDAMAGE) return 0; + if (currentGamePhase != Constants::MTG_PHASE_COMBATDAMAGE) + return 0; - return 0; + return 0; } AIStats * AIPlayer::getStats() { - if (!stats) - { - char statFile[512]; - sprintf(statFile, JGE_GET_RES("ai/baka/stats/%s.stats").c_str(), opponent()->deckFileSmall.c_str()); - stats = NEW AIStats(this, statFile); - } - return stats; + if (!stats) + { + char statFile[512]; + sprintf(statFile, JGE_GET_RES("ai/baka/stats/%s.stats").c_str(), opponent()->deckFileSmall.c_str()); + stats = NEW AIStats(this, statFile); + } + return stats; } AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid) { - char deckFile[512]; - char avatarFile[512]; - char deckFileSmall[512]; + char deckFile[512]; + char avatarFile[512]; + char deckFileSmall[512]; - if (deckid == GameStateDuel::MENUITEM_EVIL_TWIN) - { //Evil twin - sprintf(deckFile, "%s", opponent->deckFile.c_str()); - DebugTrace(opponent->deckFile); - sprintf(avatarFile, "%s", "baka.jpg"); - sprintf(deckFileSmall, "%s", "ai_baka_eviltwin"); - } - else - { - if (!deckid) - { - //random deck - int nbdecks = 0; - int found = 1; - while (found && nbdecks < options[Options::AIDECKS_UNLOCKED].number) - { - found = 0; - char buffer[512]; - sprintf(buffer, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), nbdecks + 1); - std::ifstream file(buffer); - if (file) - { - found = 1; - file.close(); - nbdecks++; - } - } - if (!nbdecks) return NULL; - deckid = 1 + WRand() % (nbdecks); - } - sprintf(deckFile, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), deckid); - sprintf(avatarFile, "avatar%i.jpg", deckid); - sprintf(deckFileSmall, "ai_baka_deck%i", deckid); - } + if (deckid == GameStateDuel::MENUITEM_EVIL_TWIN) + { //Evil twin + sprintf(deckFile, "%s", opponent->deckFile.c_str()); + DebugTrace(opponent->deckFile); + sprintf(avatarFile, "%s", "baka.jpg"); + sprintf(deckFileSmall, "%s", "ai_baka_eviltwin"); + } + else + { + if (!deckid) + { + //random deck + int nbdecks = 0; + int found = 1; + while (found && nbdecks < options[Options::AIDECKS_UNLOCKED].number) + { + found = 0; + char buffer[512]; + sprintf(buffer, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), nbdecks + 1); + std::ifstream file(buffer); + if (file) + { + found = 1; + file.close(); + nbdecks++; + } + } + if (!nbdecks) + return NULL; + deckid = 1 + WRand() % (nbdecks); + } + sprintf(deckFile, JGE_GET_RES("ai/baka/deck%i.txt").c_str(), deckid); + sprintf(avatarFile, "avatar%i.jpg", deckid); + sprintf(deckFileSmall, "ai_baka_deck%i", deckid); + } - MTGDeck * tempDeck = NEW MTGDeck(deckFile, collection); - //MTGPlayerCards * deck = NEW MTGPlayerCards(tempDeck); - AIPlayerBaka * baka = NEW AIPlayerBaka(tempDeck, deckFile, deckFileSmall, avatarFile); - baka->deckId = deckid; + MTGDeck * tempDeck = NEW MTGDeck(deckFile, collection); + //MTGPlayerCards * deck = NEW MTGPlayerCards(tempDeck); + AIPlayerBaka * baka = NEW AIPlayerBaka(tempDeck, deckFile, deckFileSmall, avatarFile); + baka->deckId = deckid; - delete tempDeck; - return baka; + delete tempDeck; + return baka; } MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * type) { - int maxCost = -1; - MTGCardInstance * nextCardToPlay = NULL; - MTGCardInstance * card = NULL; - CardDescriptor cd; - cd.init(); - cd.setType(type); - card = NULL; - while ((card = cd.nextmatch(game->hand, card))) - { - if (!CanHandleCost(card->getManaCost())) continue; - if (card->hasType(Subtypes::TYPE_CREATURE) && this->castrestrictedcreature == true && this->castrestrictedspell == true) continue; - if (card->hasType(Subtypes::TYPE_ENCHANTMENT) && this->castrestrictedspell == true) continue; - if (card->hasType(Subtypes::TYPE_ARTIFACT) && this->castrestrictedspell == true) continue; - if (card->hasType(Subtypes::TYPE_SORCERY) && this->castrestrictedspell == true) continue; - if (card->hasType(Subtypes::TYPE_INSTANT) && this->castrestrictedspell == true) continue; - if (card->hasType(Subtypes::TYPE_LAND) && !this->canPutLandsIntoPlay) continue; - if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->inPlay->findByName(card->name)) continue; - int currentCost = card->getManaCost()->getConvertedCost(); - int hasX = card->getManaCost()->hasX(); - if ((currentCost > maxCost || hasX) && pMana->canAfford(card->getManaCost())) - { - TargetChooserFactory tcf; - TargetChooser * tc = tcf.createTargetChooser(card); - int shouldPlayPercentage = 10; - if (tc) - { - int hasTarget = (chooseTarget(tc)); - delete tc; - if (!hasTarget) continue; - shouldPlayPercentage = 90; - } - else - { - int shouldPlay = effectBadOrGood(card); - if (shouldPlay == BAKA_EFFECT_GOOD) - { - shouldPlayPercentage = 90; - } - else if (BAKA_EFFECT_DONTKNOW == shouldPlay) - { - shouldPlayPercentage = 80; - } - } - //Reduce the chances of playing a spell with X cost if available mana is low - if (hasX) - { - int xDiff = pMana->getConvertedCost() - currentCost; - if (xDiff < 0) xDiff = 0; - shouldPlayPercentage = shouldPlayPercentage - static_cast ((shouldPlayPercentage * 1.9f) / (1 + xDiff)); - } + int maxCost = -1; + MTGCardInstance * nextCardToPlay = NULL; + MTGCardInstance * card = NULL; + CardDescriptor cd; + cd.init(); + cd.setType(type); + card = NULL; + while ((card = cd.nextmatch(game->hand, card))) + { + if (!CanHandleCost(card->getManaCost())) + continue; + if (card->hasType(Subtypes::TYPE_CREATURE) && this->castrestrictedcreature == true && this->castrestrictedspell == true) + continue; + if (card->hasType(Subtypes::TYPE_ENCHANTMENT) && this->castrestrictedspell == true) + continue; + if (card->hasType(Subtypes::TYPE_ARTIFACT) && this->castrestrictedspell == true) + continue; + if (card->hasType(Subtypes::TYPE_SORCERY) && this->castrestrictedspell == true) + continue; + if (card->hasType(Subtypes::TYPE_INSTANT) && this->castrestrictedspell == true) + continue; + if (card->hasType(Subtypes::TYPE_LAND) && !this->canPutLandsIntoPlay) + continue; + if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->inPlay->findByName(card->name)) + continue; + int currentCost = card->getManaCost()->getConvertedCost(); + int hasX = card->getManaCost()->hasX(); + if ((currentCost > maxCost || hasX) && pMana->canAfford(card->getManaCost())) + { + TargetChooserFactory tcf; + TargetChooser * tc = tcf.createTargetChooser(card); + int shouldPlayPercentage = 10; + if (tc) + { + int hasTarget = (chooseTarget(tc)); + delete tc; + if (!hasTarget) + continue; + shouldPlayPercentage = 90; + } + else + { + int shouldPlay = effectBadOrGood(card); + if (shouldPlay == BAKA_EFFECT_GOOD) + { + shouldPlayPercentage = 90; + } + else if (BAKA_EFFECT_DONTKNOW == shouldPlay) + { + shouldPlayPercentage = 80; + } + } + //Reduce the chances of playing a spell with X cost if available mana is low + if (hasX) + { + int xDiff = pMana->getConvertedCost() - currentCost; + if (xDiff < 0) + xDiff = 0; + shouldPlayPercentage = shouldPlayPercentage - static_cast ((shouldPlayPercentage * 1.9f) / (1 + xDiff)); + } - if (WRand() % 100 > shouldPlayPercentage) continue; - nextCardToPlay = card; - maxCost = currentCost; - if (hasX) maxCost = pMana->getConvertedCost(); - } - } - return nextCardToPlay; + if (WRand() % 100 > shouldPlayPercentage) + continue; + nextCardToPlay = card; + maxCost = currentCost; + if (hasX) + maxCost = pMana->getConvertedCost(); + } + } + return nextCardToPlay; } AIPlayerBaka::AIPlayerBaka(MTGDeck * deck, string file, string fileSmall, string avatarFile) : -AIPlayer(deck, file, fileSmall) + AIPlayer(deck, file, fileSmall) { - mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR); + mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR); - if (!mAvatarTex) - { - avatarFile = "baka.jpg"; - mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR); - } + if (!mAvatarTex) + { + avatarFile = "baka.jpg"; + mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR); + } - if (mAvatarTex) - mAvatar = WResourceManager::Instance()->RetrieveQuad(avatarFile, 0, 0, 35, 50, "bakaAvatar", RETRIEVE_NORMAL, - TEXTURE_SUB_AVATAR); - else - mAvatar = NULL; + if (mAvatarTex) + mAvatar = WResourceManager::Instance()->RetrieveQuad(avatarFile, 0, 0, 35, 50, "bakaAvatar", RETRIEVE_NORMAL, + TEXTURE_SUB_AVATAR); + else + mAvatar = NULL; - initTimer(); + initTimer(); } void AIPlayerBaka::initTimer() { - timer = 0.1f; + timer = 0.1f; } int AIPlayerBaka::computeActions() { - GameObserver * g = GameObserver::GetInstance(); - Player * p = g->currentPlayer; - if (!(g->currentlyActing() == this)) return 0; - if (g->mLayers->actionLayer()->menuObject) - { - g->mLayers->actionLayer()->doReactTo(0); - return 1; - } - if (chooseTarget()) return 1; - int currentGamePhase = g->getCurrentGamePhase(); - if (g->isInterrupting == this) - { // interrupting - selectAbility(); - return 1; - } - else if (p == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0) - { //standard actions - CardDescriptor cd; - MTGCardInstance * card = NULL; - switch (currentGamePhase) - { - case Constants::MTG_PHASE_FIRSTMAIN: - case Constants::MTG_PHASE_SECONDMAIN: - { + GameObserver * g = GameObserver::GetInstance(); + Player * p = g->currentPlayer; + if (!(g->currentlyActing() == this)) + return 0; + if (g->mLayers->actionLayer()->menuObject) + { + g->mLayers->actionLayer()->doReactTo(0); + return 1; + } + if (chooseTarget()) + return 1; + int currentGamePhase = g->getCurrentGamePhase(); + if (g->isInterrupting == this) + { // interrupting + selectAbility(); + return 1; + } + else if (p == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0) + { //standard actions + CardDescriptor cd; + MTGCardInstance * card = NULL; + 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) - { - if (onlyoneinstant == false || castcount < 2) - { - 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(); - } - } - } + 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) + { + if (onlyoneinstant == false || castcount < 2) + { + 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(); + } + } + } - } - 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)) - { - ManaCost * SunCheck = manaPool; - SunCheck = getPotentialMana(); - for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) - { - //sunburst for Ai - if (SunCheck->hasColor(i)) - { - if (nextCardToPlay->getManaCost()->hasColor(i) > 0) - {//do nothing if the card already has this color. - } - else - { - if (nextCardToPlay->sunburst < nextCardToPlay->getManaCost()->getConvertedCost()) - { - nextCardToPlay->getManaCost()->add(i, 1); - nextCardToPlay->getManaCost()->remove(0, 1); - nextCardToPlay->sunburst += 1; - } - } - } - } - delete (SunCheck); - } - ///////////////////////// - tapLandsForMana(nextCardToPlay->getManaCost()); - } - 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; - } - case Constants::MTG_PHASE_COMBATATTACKERS: - chooseAttackers(); - break; - case Constants::MTG_PHASE_ENDOFTURN: - Checked = false; - break; - default: - selectAbility(); - break; - } - } - else - { - cout << "my turn" << endl; - switch (currentGamePhase) - { - case Constants::MTG_PHASE_COMBATBLOCKERS: - chooseBlockers(); - break; - default: - break; - } - return 1; - } - return 1; + } + 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)) + { + ManaCost * SunCheck = manaPool; + SunCheck = getPotentialMana(); + for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) + { + //sunburst for Ai + if (SunCheck->hasColor(i)) + { + if (nextCardToPlay->getManaCost()->hasColor(i) > 0) + {//do nothing if the card already has this color. + } + else + { + if (nextCardToPlay->sunburst < nextCardToPlay->getManaCost()->getConvertedCost()) + { + nextCardToPlay->getManaCost()->add(i, 1); + nextCardToPlay->getManaCost()->remove(0, 1); + nextCardToPlay->sunburst += 1; + } + } + } + } + delete (SunCheck); + } + ///////////////////////// + tapLandsForMana(nextCardToPlay->getManaCost()); + } + 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; + } + case Constants::MTG_PHASE_COMBATATTACKERS: + chooseAttackers(); + break; + case Constants::MTG_PHASE_ENDOFTURN: + Checked = false; + break; + default: + selectAbility(); + break; + } + } + else + { + cout << "my turn" << endl; + switch (currentGamePhase) + { + case Constants::MTG_PHASE_COMBATBLOCKERS: + chooseBlockers(); + break; + default: + break; + } + return 1; + } + return 1; } ; int AIPlayer::receiveEvent(WEvent * event) { - if (getStats()) return getStats()->receiveEvent(event); - return 0; + if (getStats()) + return getStats()->receiveEvent(event); + return 0; } void AIPlayer::Render() { #ifdef RENDER_AI_STATS - if (getStats()) getStats()->Render(); + if (getStats()) getStats()->Render(); #endif } int AIPlayerBaka::Act(float dt) { - GameObserver * g = GameObserver::GetInstance(); + GameObserver * g = GameObserver::GetInstance(); - if (!(g->currentlyActing() == this)) - { - return 0; - } + if (!(g->currentlyActing() == this)) + { + return 0; + } - int currentGamePhase = g->getCurrentGamePhase(); + int currentGamePhase = g->getCurrentGamePhase(); - oldGamePhase = currentGamePhase; + oldGamePhase = currentGamePhase; - timer -= dt; - if (timer > 0) - { - return 0; - } - initTimer(); - if (combatDamages()) - { - return 0; - } - interruptIfICan(); - if (!(g->currentlyActing() == this)) - { - DebugTrace("Cannot interrupt"); - return 0; - } - if (clickstream.empty()) computeActions(); - if (clickstream.empty()) - { - if (g->isInterrupting == this) - { - g->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption(); - } - else - { - g->userRequestNextGamePhase(); - } - } - else - { - AIAction * action = clickstream.front(); - action->Act(); - SAFE_DELETE(action); - clickstream.pop(); - } - return 1; + timer -= dt; + if (timer > 0) + { + return 0; + } + initTimer(); + if (combatDamages()) + { + return 0; + } + interruptIfICan(); + if (!(g->currentlyActing() == this)) + { + DebugTrace("Cannot interrupt"); + return 0; + } + if (clickstream.empty()) + computeActions(); + if (clickstream.empty()) + { + if (g->isInterrupting == this) + { + g->mLayers->stackLayer()->cancelInterruptOffer(); //endOfInterruption(); + } + else + { + g->userRequestNextGamePhase(); + } + } + else + { + AIAction * action = clickstream.front(); + action->Act(); + SAFE_DELETE(action); + clickstream.pop(); + } + return 1; } ; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 3217822e4..1e0ccb04b 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1,7 +1,6 @@ #include "PrecompiledHeader.h" #include "AllAbilities.h" - //Activated Abilities //Generic Activated Abilities @@ -21,19 +20,22 @@ int GenericActivatedAbility::resolve() SAFE_DELETE(diff); //SAFE_DELETE(abilityCost); this line has been reported as a bug. removing it doesn't seem to break anything, although I didn't get any error in the test suite by leaving it either, so... leaving it for now as a comment, in case. ability->target = target; //may have been updated... - if (ability) return ability->resolve(); + if (ability) + return ability->resolve(); return 0; } const char * GenericActivatedAbility::getMenuText() { - if (ability) return ability->getMenuText(); + if (ability) + return ability->getMenuText(); return "Error"; } int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { - if (limitPerTurn && counters >= limitPerTurn) return 0; + if (limitPerTurn && counters >= limitPerTurn) + return 0; return ActivatedAbility::isReactingToClick(card, mana); } @@ -48,8 +50,10 @@ void GenericActivatedAbility::Update(float dt) int GenericActivatedAbility::testDestroy() { - if (!activeZone) return ActivatedAbility::testDestroy(); - if (activeZone->hasCard(source)) return 0; + if (!activeZone) + return ActivatedAbility::testDestroy(); + if (activeZone->hasCard(source)) + return 0; return 1; } @@ -195,7 +199,8 @@ int AADepleter::resolve() 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 (library->nb_cards) + player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); } } return 1; @@ -249,7 +254,8 @@ AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, ActivatedAbility(id, source, cost, 0, doTap), nb(nb), power(power), toughness(toughness), name(_name) { this->target = target; - if (name.find("Level")) aType = MTGAbility::STANDARD_LEVELUP; + if (name.find("Level")) + aType = MTGAbility::STANDARD_LEVELUP; menu = ""; } @@ -283,34 +289,34 @@ int AACounter::resolve() const char* AACounter::getMenuText() { - if(menu.size()) - { - return menu.c_str(); - } - char buffer[128]; + if (menu.size()) + { + return menu.c_str(); + } + char buffer[128]; - if(name.size()) - { - string s = name; - menu.append(s.c_str()); - } + 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); - } + if (power != 0 || toughness != 0) + { + sprintf(buffer, " %i/%i", power, toughness); + menu.append(buffer); + } - menu.append(" Counter"); - if(nb != 1) - { - sprintf(buffer, ": %i", nb); - menu.append(buffer); - } + menu.append(" Counter"); + if (nb != 1) + { + sprintf(buffer, ": %i", nb); + menu.append(buffer); + } - sprintf(menuText, "%s",menu.c_str()); - return menuText; - } + sprintf(menuText, "%s", menu.c_str()); + return menuText; +} AACounter * AACounter::clone() const { @@ -329,7 +335,8 @@ AAFizzler::AAFizzler(int _id, MTGCardInstance * card, Spell * _target, ManaCost int AAFizzler::resolve() { Spell * _target = (Spell *) target; - if (target && _target->source->has(Constants::NOFIZZLE)) return 0; + if (target && _target->source->has(Constants::NOFIZZLE)) + return 0; game->mLayers->stackLayer()->Fizzle(_target); return 1; } @@ -350,7 +357,8 @@ AAFizzler* AAFizzler::clone() const AABanishCard::AABanishCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) : ActivatedAbility(_id, _source, NULL), banishmentType(_banishmentType) { - if (_target) target = _target; + if (_target) + target = _target; } const char * AABanishCard::getMenuText() @@ -577,7 +585,7 @@ AAFrozen * AAFrozen::clone() const 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) { - aType = MTGAbility::LIFER; + aType = MTGAbility::LIFER; } int AALifer::resolve() @@ -657,10 +665,10 @@ AACloner::AACloner(int _id, MTGCardInstance * _source, MTGCardInstance * _target string abilitiesStringList) : ActivatedAbility(_id, _source, _cost, 0, 0), who(who) { - aType = MTGAbility::CLONING; + aType = MTGAbility::CLONING; target = _target; source = _source; - if ( abilitiesStringList.size() > 0 ) + if (abilitiesStringList.size() > 0) { PopulateAbilityIndexVector(awith, abilitiesStringList); PopulateColorIndexVector(colors, abilitiesStringList); @@ -676,8 +684,10 @@ 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) + 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 @@ -703,7 +713,8 @@ int AACloner::resolve() const char * AACloner::getMenuText() { - if (who == 1) return "Clone For Opponent"; + if (who == 1) + return "Clone For Opponent"; return "Clone"; } @@ -772,7 +783,8 @@ AAMoreLandPlz::~AAMoreLandPlz() AAMover::AAMover(int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest, ManaCost * _cost, int doTap) : ActivatedAbility(_id, _source, _cost, 0, doTap), destination(dest) { - if (_target) target = _target; + if (_target) + target = _target; } MTGGameZone * AAMover::destinationZone() @@ -1019,7 +1031,7 @@ AATapper::AATapper(int id, MTGCardInstance * card, MTGCardInstance * _target, Ma ActivatedAbility(id, card, _cost, 0, doTap) { target = _target; - aType = MTGAbility::TAPPER; + aType = MTGAbility::TAPPER; } int AATapper::resolve() @@ -1051,7 +1063,7 @@ AAUntapper::AAUntapper(int id, MTGCardInstance * card, MTGCardInstance * _target ActivatedAbility(id, card, _cost, 0, doTap) { target = _target; - aType = MTGAbility::UNTAPPER; + aType = MTGAbility::UNTAPPER; } int AAUntapper::resolve() @@ -1156,7 +1168,6 @@ AAWinGame * AAWinGame::clone() const return a; } - //Generic Abilities //May Abilities @@ -1175,7 +1186,8 @@ void MayAbility::Update(float dt) triggered = 1; if (TargetAbility * ta = dynamic_cast(ability)) { - if (!ta->tc->validTargetsExist()) return; + if (!ta->tc->validTargetsExist()) + return; } game->mLayers->actionLayer()->setMenuObject(source, must); game->mLayers->stackLayer()->setIsInterrupting(source->controller()); @@ -1189,15 +1201,19 @@ const char * MayAbility::getMenuText() int MayAbility::testDestroy() { - if (!triggered) return 0; - if (game->mLayers->actionLayer()->menuObject) return 0; - if (game->mLayers->actionLayer()->getIndexOf(mClone) != -1) return 0; + if (!triggered) + return 0; + if (game->mLayers->actionLayer()->menuObject) + return 0; + if (game->mLayers->actionLayer()->getIndexOf(mClone) != -1) + return 0; return 1; } int MayAbility::isReactingToTargetClick(Targetable * card) { - if (card == source) return 1; + if (card == source) + return 1; return 0; } @@ -1226,7 +1242,8 @@ MayAbility::~MayAbility() MultiAbility::MultiAbility(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap) : ActivatedAbility(_id, card, _cost, 0, _tap) { - if (_target) target = _target; + if (_target) + target = _target; } int MultiAbility::Add(MTGAbility * ability) @@ -1240,9 +1257,11 @@ int MultiAbility::resolve() vector::size_type sz = abilities.size(); for (unsigned int i = 0; i < sz; i++) { - if (abilities[i] == NULL) continue; + if (abilities[i] == NULL) + continue; Targetable * backup = abilities[i]->target; - if (target && target != source && abilities[i]->target == abilities[i]->source) abilities[i]->target = target; + if (target && target != source && abilities[i]->target == abilities[i]->source) + abilities[i]->target = target; abilities[i]->resolve(); abilities[i]->target = backup; } @@ -1251,7 +1270,8 @@ int MultiAbility::resolve() const char * MultiAbility::getMenuText() { - if (abilities.size()) return abilities[0]->getMenuText(); + if (abilities.size()) + return abilities[0]->getMenuText(); return ""; } @@ -1275,7 +1295,6 @@ MultiAbility::~MultiAbility() abilities.clear(); } - //Generic Target Ability GenericTargetAbility::GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost, int _tap, int limit, int restrictions, MTGGameZone * dest) : @@ -1283,13 +1302,15 @@ GenericTargetAbility::GenericTargetAbility(int _id, MTGCardInstance * _source, T { ability = a; MTGAbility * core = AbilityFactory::getCoreAbility(a); - if (dynamic_cast (core)) tc->other = true; //http://code.google.com/p/wagic/issues/detail?id=209 (avoid inifinite loop) + if (dynamic_cast (core)) + tc->other = true; //http://code.google.com/p/wagic/issues/detail?id=209 (avoid inifinite loop) counters = 0; } const char * GenericTargetAbility::getMenuText() { - if (!ability) return "Error"; + if (!ability) + return "Error"; MTGAbility * core = AbilityFactory::getCoreAbility(ability); if (AAMover * move = dynamic_cast(core)) @@ -1318,7 +1339,9 @@ const char * GenericTargetAbility::getMenuText() { return "Reanimate"; } - else if ((tc->targetsZone(g->players[i]->game->inPlay) && dest == g->players[i]->game->library) || dest == g->players[i]->game->library ) + else if ((tc->targetsZone(g->players[i]->game->inPlay) + && dest == g->players[i]->game->library) + || dest == g->players[i]->game->library) { return "Put in Library"; } @@ -1361,7 +1384,8 @@ int GenericTargetAbility::resolve() int GenericTargetAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { - if (limitPerTurn && counters >= limitPerTurn) return 0; + if (limitPerTurn && counters >= limitPerTurn) + return 0; return TargetAbility::isReactingToClick(card, mana); } @@ -1376,8 +1400,10 @@ void GenericTargetAbility::Update(float dt) int GenericTargetAbility::testDestroy() { - if (!activeZone) return TargetAbility::testDestroy(); - if (activeZone->hasCard(source)) return 0; + if (!activeZone) + return TargetAbility::testDestroy(); + if (activeZone->hasCard(source)) + return 0; return 1; } @@ -1388,7 +1414,8 @@ GenericTargetAbility * GenericTargetAbility::clone() const a->ability = ability->clone(); a->cost = NEW ManaCost(); a->cost->copy(cost); - if (tc) a->tc = tc->clone(); + if (tc) + a->tc = tc->clone(); return a; } @@ -1461,19 +1488,23 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t PopulateColorIndexVector(colors, sabilities); remove = false; - if (stypes == "removesubtypes") remove = true; + if (stypes == "removesubtypes") + remove = true; if (stypes == "allsubtypes" || stypes == "removesubtypes") { for (int i = Subtypes::LAST_TYPE + 1;; i++) { string s = Subtypes::subtypesList->find(i); { - if (s == "") break; - if (s.find(" ") != string::npos) continue; - if (s == "Nothing" || s == "Swamp" || s == "Plains" || s == "Mountain" || s == "Forest" || s == "Island" || s - == "Shrine" || s == "Basic" || s == "Colony" || s == "Desert" || s == "Dismiss" || s == "Equipment" || s - == "Everglades" || s == "Grasslands" || s == "Lair" || s == "Level" || s == "Levelup" || s == "Mine" || s - == "Oasis" || s == "World" || s == "Aura") + if (s == "") + break; + if (s.find(" ") != string::npos) + continue; + if (s == "Nothing" || s == "Swamp" || s == "Plains" || s == "Mountain" || s == "Forest" + || s == "Island" || s == "Shrine" || s == "Basic" || s == "Colony" || s == "Desert" + || s == "Dismiss" || s == "Equipment" || s == "Everglades" || s == "Grasslands" || s == "Lair" + || s == "Level" || s == "Levelup" || s == "Mine" || s == "Oasis" || s == "World" || s == "Aura" + ) {//dont add "nothing" or land type to this card. } else @@ -1488,7 +1519,7 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t PopulateSubtypesIndexVector(types, stypes); } - menu = stypes; + menu = stypes; } int ATransformer::addToGame() @@ -1500,13 +1531,16 @@ int ATransformer::addToGame() _target = _target->next; for (int j = 0; j < Constants::MTG_NB_COLORS; j++) { - if (_target->hasColor(j)) oldcolors.push_back(j); + if (_target->hasColor(j)) + oldcolors.push_back(j); } for (int j = Subtypes::LAST_TYPE + 1;; j++) { string otypes = Subtypes::subtypesList->find(j); - if (otypes == "") break; - if (otypes.find(" ") != string::npos) continue; + if (otypes == "") + break; + if (otypes.find(" ") != string::npos) + continue; if (_target->hasSubtype(j)) { oldtypes.push_back(j); @@ -1554,7 +1588,8 @@ int ATransformer::destroy() list::iterator it; for (it = types.begin(); it != types.end(); it++) { - if (remove == false) _target->removeType(*it); + if (remove == false) + _target->removeType(*it); } for (it = colors.begin(); it != colors.end(); it++) { @@ -1572,7 +1607,8 @@ int ATransformer::destroy() { for (it = oldtypes.begin(); it != oldtypes.end(); it++) { - if (!_target->hasSubtype(*it)) _target->addType(*it); + if (!_target->hasSubtype(*it)) + _target->addType(*it); } } } @@ -1608,7 +1644,7 @@ AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCa PopulateAbilityIndexVector(abilities, sabilities); PopulateColorIndexVector(colors, sabilities); PopulateSubtypesIndexVector(types, stypes); - menu = stypes; + menu = stypes; } int AForeverTransformer::addToGame() @@ -1673,7 +1709,7 @@ int ATransformerUEOT::resolve() } const char * ATransformerUEOT::getMenuText() { - return ability->getMenuText(); + return ability->getMenuText(); } ATransformerUEOT * ATransformerUEOT::clone() const @@ -1707,7 +1743,7 @@ int ATransformerFOREVER::resolve() const char * ATransformerFOREVER::getMenuText() { - return ability->getMenuText(); + return ability->getMenuText(); } ATransformerFOREVER * ATransformerFOREVER::clone() const @@ -1740,7 +1776,7 @@ int ASwapPTUEOT::resolve() const char * ASwapPTUEOT::getMenuText() { - return ability->getMenuText(); + return ability->getMenuText(); } ASwapPTUEOT * ASwapPTUEOT::clone() const @@ -1766,7 +1802,7 @@ ABecomes::ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, s PopulateAbilityIndexVector(abilities, sabilities); PopulateColorIndexVector(colors, sabilities); PopulateSubtypesIndexVector(types, stypes); - menu = stypes; + menu = stypes; } int ABecomes::addToGame() @@ -1824,7 +1860,8 @@ const char * ABecomes::getMenuText() ABecomes * ABecomes::clone() const { ABecomes * a = NEW ABecomes(*this); - if (a->wppt) a->wppt = NEW WParsedPT(*(a->wppt)); + if (a->wppt) + a->wppt = NEW WParsedPT(*(a->wppt)); a->isClone = 1; return a; } @@ -1887,9 +1924,11 @@ int APreventDamageTypes::addToGame() } TargetChooserFactory tcf; TargetChooser *toTc = tcf.createTargetChooser(to, source, this); - if (toTc) toTc->targetter = NULL; + if (toTc) + toTc->targetter = NULL; TargetChooser *fromTc = tcf.createTargetChooser(from, source, this); - if (fromTc) fromTc->targetter = NULL; + if (fromTc) + fromTc->targetter = NULL; if (type != 1 && type != 2) {//not adding this creates a memory leak. re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, DAMAGE_COMBAT); @@ -1974,7 +2013,7 @@ AUpkeep::AUpkeep(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _co ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), phase(_phase), once(_once) { paidThisTurn = 0; - aType = MTGAbility::UPCOST; + aType = MTGAbility::UPCOST; } void AUpkeep::Update(float dt) @@ -1990,14 +2029,16 @@ void AUpkeep::Update(float dt) { ability->resolve(); } - if (newPhase == phase + 1 && once) once = 2; + if (newPhase == phase + 1 && once) + once = 2; } ActivatedAbility::Update(dt); } int AUpkeep::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { - if (currentPhase != phase || paidThisTurn || once >= 2) return 0; + if (currentPhase != phase || paidThisTurn || once >= 2) + return 0; return ActivatedAbility::isReactingToClick(card, mana); } @@ -2028,48 +2069,47 @@ AUpkeep * AUpkeep::clone() const AUpkeep::~AUpkeep() { if (!isClone) - SAFE_DELETE(ability); + SAFE_DELETE(ability); } - // utility functions // Given a delimited string of abilities, add the ones to the list that are "Basic" MTG abilities -void PopulateAbilityIndexVector( list& abilities, const string& abilityStringList, char delimiter ) +void PopulateAbilityIndexVector(list& abilities, const string& abilityStringList, char delimiter) { - vector abilitiesList = split( abilityStringList, delimiter); - for ( vector::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter) + vector abilitiesList = split(abilityStringList, delimiter); + for (vector::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter) { - int abilityIndex = Constants::GetBasicAbilityIndex( *iter ); + int abilityIndex = Constants::GetBasicAbilityIndex(*iter); if (abilityIndex != -1) - abilities.push_back( abilityIndex ); + abilities.push_back(abilityIndex); } } - -void PopulateColorIndexVector( list& colors, const string& colorStringList, char delimiter ) +void PopulateColorIndexVector(list& colors, const string& colorStringList, char delimiter) { - vector abilitiesList = split( colorStringList, delimiter); - for ( vector::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter) + vector abilitiesList = split(colorStringList, delimiter); + for (vector::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter) { for (int colorIndex = Constants::MTG_COLOR_ARTIFACT; colorIndex < Constants::MTG_NB_COLORS; ++colorIndex) { // if the text is not a basic ability but contains a valid color add it to the color vector - if ( (Constants::GetBasicAbilityIndex( *iter ) != -1) && ((*iter).find( Constants::MTGColorStrings[ colorIndex ] ) != string::npos) ) + if ((Constants::GetBasicAbilityIndex(*iter) != -1) + && ((*iter).find(Constants::MTGColorStrings[colorIndex]) != string::npos)) colors.push_back(colorIndex); } } } -void PopulateSubtypesIndexVector( list& types, const string& subTypesStringList, char delimiter) +void PopulateSubtypesIndexVector(list& types, const string& subTypesStringList, char delimiter) { - vector subTypesList = split( subTypesStringList, delimiter); + vector subTypesList = split(subTypesStringList, delimiter); for (vector::iterator it = subTypesList.begin(); it != subTypesList.end(); ++it) { string subtype = *it; - size_t id = Subtypes::subtypesList->find( subtype ); - if ( id != string::npos ) + size_t id = Subtypes::subtypesList->find(subtype); + if (id != string::npos) types.push_back(id); } } diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 508de3a53..89e7fa059 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -72,19 +72,19 @@ void GameObserver::nextPlayer() void GameObserver::nextGamePhase() { Phase * cPhaseOld = phaseRing->getCurrentPhase(); - if (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE) - if (FIRST_STRIKE == combatStep || END_FIRST_STRIKE == combatStep || DAMAGE == combatStep) - { - nextCombatStep(); - return; - } + if (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE) + if ((FIRST_STRIKE == combatStep) || (END_FIRST_STRIKE == combatStep) || (DAMAGE == combatStep)) + { + nextCombatStep(); + return; + } - if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS) - if (BLOCKERS == combatStep || TRIGGERS == combatStep) - { - nextCombatStep(); - return; - } + if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS) + if (BLOCKERS == combatStep || TRIGGERS == combatStep) + { + nextCombatStep(); + return; + } phaseRing->forward(); @@ -99,25 +99,25 @@ void GameObserver::nextGamePhase() currentGamePhase = cPhase->id; if (Constants::MTG_PHASE_COMBATDAMAGE == currentGamePhase) - nextCombatStep(); + nextCombatStep(); if (currentPlayer != cPhase->player) - nextPlayer(); + nextPlayer(); //init begin of turn if (currentGamePhase == Constants::MTG_PHASE_BEFORE_BEGIN) - { - cleanupPhase(); - currentPlayer->canPutLandsIntoPlay = true; - currentPlayer->landsPlayerCanStillPlay = 1; - currentPlayer->castedspellsthisturn = 0; - currentPlayer->opponent()->castedspellsthisturn = 0; - currentPlayer->castcount = 0; - currentPlayer->nocreatureinstant = false; - currentPlayer->nospellinstant = false; - currentPlayer->onlyoneinstant = false; - currentPlayer->damageCount = 0; - currentPlayer->preventable = 0; + { + cleanupPhase(); + currentPlayer->canPutLandsIntoPlay = true; + currentPlayer->landsPlayerCanStillPlay = 1; + currentPlayer->castedspellsthisturn = 0; + currentPlayer->opponent()->castedspellsthisturn = 0; + currentPlayer->castcount = 0; + currentPlayer->nocreatureinstant = false; + currentPlayer->nospellinstant = false; + currentPlayer->onlyoneinstant = false; + currentPlayer->damageCount = 0; + currentPlayer->preventable = 0; mLayers->actionLayer()->cleanGarbage(); //clean abilities history for this turn; mLayers->stackLayer()->garbageCollect(); //clean stack history for this turn; mLayers->actionLayer()->Update(0); @@ -147,7 +147,7 @@ void GameObserver::nextGamePhase() switch (currentGamePhase) { case Constants::MTG_PHASE_UNTAP: - DebugTrace("Untap Phase ------------- Turn " << turn ); + DebugTrace("Untap Phase ------------- Turn " << turn ); untapPhase(); break; case Constants::MTG_PHASE_DRAW: @@ -198,37 +198,39 @@ void GameObserver::nextCombatStep() void GameObserver::userRequestNextGamePhase() { - if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) - return; - if (getCurrentTargetChooser()) - return; - //if (mLayers->actionLayer()->isWaitingForAnswer()) - // return; + if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) + return; + if (getCurrentTargetChooser()) + return; + //if (mLayers->actionLayer()->isWaitingForAnswer()) + // return; // Wil 12/5/10: additional check, not quite understanding why TargetChooser doesn't seem active at this point. // If we deem that an extra cost payment needs to be made, don't allow the next game phase to proceed. // Here's what I find weird - if the extra cost is something like a sacrifice, doesn't that imply a TargetChooser? - if (WaitForExtraPayment(NULL)) - return; + if (WaitForExtraPayment(NULL)) + return; - bool executeNextPhaseImmediately = true; + bool executeNextPhaseImmediately = true; - Phase * cPhaseOld = phaseRing->getCurrentPhase(); - if ((cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == ORDER) || (cPhaseOld->id - == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS) || cPhaseOld->id - == Constants::MTG_PHASE_COMBATDAMAGE || opponent()->isAI() - || options[Options::optionInterrupt(currentGamePhase)].number) - { - executeNextPhaseImmediately = false; - } + Phase * cPhaseOld = phaseRing->getCurrentPhase(); + if ((cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == ORDER) + || (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS) + || (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE) + || opponent()->isAI() + || options[Options::optionInterrupt(currentGamePhase)].number + ) + { + executeNextPhaseImmediately = false; + } - if (executeNextPhaseImmediately) - { - nextGamePhase(); - } - else - { - mLayers->stackLayer()->AddNextGamePhase(); - } + if (executeNextPhaseImmediately) + { + nextGamePhase(); + } + else + { + mLayers->stackLayer()->AddNextGamePhase(); + } } @@ -254,8 +256,8 @@ void GameObserver::startGame(Rules * rules) { turn = 0; mRules = rules; - if (rules) - rules->initPlayers(); + if (rules) + rules->initPlayers(); options.automaticStyle(players[0], players[1]); @@ -266,8 +268,8 @@ void GameObserver::startGame(Rules * rules) currentPlayer = players[0]; currentActionPlayer = currentPlayer; phaseRing = NEW PhaseRing(players, nbPlayers); - if (rules) - rules->initGame(); + if (rules) + rules->initGame(); //Preload images from hand if (!players[0]->isAI()) @@ -346,12 +348,12 @@ void GameObserver::Update(float dt) { Player * player = currentPlayer; - if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) - player = player->opponent(); + if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) + player = player->opponent(); currentActionPlayer = player; - if (isInterrupting) - player = isInterrupting; + if (isInterrupting) + player = isInterrupting; mLayers->Update(dt, player); while (mLayers->actionLayer()->stuffHappened) @@ -359,8 +361,8 @@ void GameObserver::Update(float dt) mLayers->actionLayer()->Update(0); } - gameStateBasedEffects(); - oldGamePhase = currentGamePhase; + gameStateBasedEffects(); + oldGamePhase = currentGamePhase; } //applies damage to creatures after updates @@ -368,268 +370,269 @@ void GameObserver::Update(float dt) //Handles game state based effects void GameObserver::gameStateBasedEffects() { - //check land playability at start; as we want this effect to happen reguardless of unresolved - //effects or menus actions - for (int i = 0; i < 2; i++) - { - if(players[i]->landsPlayerCanStillPlay <= 0) - { - players[i]->canPutLandsIntoPlay = false; - } - else - { - players[i]->canPutLandsIntoPlay = true; - } - } - if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0) - return; - if (mLayers->actionLayer()->menuObject) - return; - if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) - return; + //check land playability at start; as we want this effect to happen reguardless of unresolved + //effects or menus actions + for (int i = 0; i < 2; i++) + { + if (players[i]->landsPlayerCanStillPlay <= 0) + { + players[i]->canPutLandsIntoPlay = false; + } + else + { + players[i]->canPutLandsIntoPlay = true; + } + } + if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0) + return; + if (mLayers->actionLayer()->menuObject) + return; + if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) + return; - //////////////////////// - //---apply damage-----// - //after combat effects// - //////////////////////// - for (int i = 0; i < 2; i++) - { - MTGGameZone * zone = players[i]->game->inPlay; - for (int j = zone->nb_cards - 1; j >= 0; j--) - { - MTGCardInstance * card = zone->cards[j]; - card->afterDamage(); + //////////////////////// + //---apply damage-----// + //after combat effects// + //////////////////////// + for (int i = 0; i < 2; i++) + { + MTGGameZone * zone = players[i]->game->inPlay; + for (int j = zone->nb_cards - 1; j >= 0; j--) + { + MTGCardInstance * card = zone->cards[j]; + card->afterDamage(); - //Remove auras that don't have a valid target anymore - if (card->target && !isInPlay(card->target) && !card->hasType("equipment")) - { - players[i]->game->putInGraveyard(card); - } - } - } - //------------------------------------- + //Remove auras that don't have a valid target anymore + if (card->target && !isInPlay(card->target) && !card->hasType("equipment")) + { + players[i]->game->putInGraveyard(card); + } + } + } + //------------------------------------- - for (int i = 0; i < 2; i++) - { - /////////////////////////////////////////////////////////// - //life checks/poison checks also checks cant win or lose.// - /////////////////////////////////////////////////////////// - if (players[i]->life <= 0) - { - int cantlosers = 0; - MTGGameZone * z = players[i]->game->inPlay; - int nbcards = z->nb_cards; - for (int j = 0; j < nbcards; ++j) - { - MTGCardInstance * c = z->cards[j]; - if (c->has(Constants::CANTLOSE) || c->has(Constants::CANTLIFELOSE)) - { - cantlosers++; - } - } - MTGGameZone * k = players[i]->opponent()->game->inPlay; - int onbcards = k->nb_cards; - for (int m = 0; m < onbcards; ++m) - { - MTGCardInstance * e = k->cards[m]; - if (e->has(Constants::CANTWIN)) - { - cantlosers++; - } - } - if (cantlosers < 1) - { - gameOver = players[i]; - } - if (players[i]->poisonCount >= 10) - { - gameOver = players[i]; - } - } - } - ////////////////////////////////////////////////////// - //-------------card based states effects------------// - ////////////////////////////////////////////////////// - //ie:cantcast; extra land; extra turn;no max hand;--// - ////////////////////////////////////////////////////// + for (int i = 0; i < 2; i++) + { + /////////////////////////////////////////////////////////// + //life checks/poison checks also checks cant win or lose.// + /////////////////////////////////////////////////////////// + if (players[i]->life <= 0) + { + int cantlosers = 0; + MTGGameZone * z = players[i]->game->inPlay; + int nbcards = z->nb_cards; + for (int j = 0; j < nbcards; ++j) + { + MTGCardInstance * c = z->cards[j]; + if (c->has(Constants::CANTLOSE) || c->has(Constants::CANTLIFELOSE)) + { + cantlosers++; + } + } + MTGGameZone * k = players[i]->opponent()->game->inPlay; + int onbcards = k->nb_cards; + for (int m = 0; m < onbcards; ++m) + { + MTGCardInstance * e = k->cards[m]; + if (e->has(Constants::CANTWIN)) + { + cantlosers++; + } + } + if (cantlosers < 1) + { + gameOver = players[i]; + } + if (players[i]->poisonCount >= 10) + { + gameOver = players[i]; + } + } + } + ////////////////////////////////////////////////////// + //-------------card based states effects------------// + ////////////////////////////////////////////////////// + //ie:cantcast; extra land; extra turn;no max hand;--// + ////////////////////////////////////////////////////// - for (int i = 0; i < 2; i++) - { - //checks if a player has a card which has the stated ability in play. - Player * p = players[i]; - MTGGameZone * z = players[i]->game->inPlay; - int nbcards = z->nb_cards; - p->onlyonecast = false; - p->opponent()->onlyonecast = false; - //------------------------------ - if (z->hasAbility(Constants::NOMAXHAND)) - { - p->nomaxhandsize = true; - } - else - { - p->nomaxhandsize = false; - } - //------------------------------ - if (z->hasAbility(Constants::CANTCASTCREATURE)) - { - p->castrestrictedcreature = true; - } - else - { - p->castrestrictedcreature = false; - } - //------------------------------ - if (z->hasAbility(Constants::CANTCAST)) - { - p->castrestrictedspell = true; - } - else - { - p->castrestrictedspell = false; - } - //------------------------------ - if (z->hasAbility(Constants::CANTCASTTWO)) - { - p->onlyonecast = true; - } - else - { - p->onlyonecast = false; - } - //-------------------------------- - if (z->hasAbility(Constants::BOTHCANTCAST)) - { - p->bothrestrictedspell = true; - } - else - { - p->bothrestrictedspell = false; - } - //--------------------------------- - if (z->hasAbility(Constants::BOTHNOCREATURE)) - { - p->bothrestrictedcreature = true; - } - else - { - p->bothrestrictedcreature = false; - } - //----------------------------------- - if (z->hasAbility(Constants::ONLYONEBOTH)) - { - p->onlyoneboth = true; - } - else - { - p->onlyoneboth = false; - } - //------------------------------------ - if(players[0]->bothrestrictedcreature) - players[1]->castrestrictedcreature = true; - //------------------------------------ - if(players[0]->bothrestrictedspell) - players[1]->castrestrictedspell = true; - //------------------------------------ - if(players[0]->onlyoneboth) - players[1]->onlyoneboth = true; - //------------------------------------ - if(players[1]->bothrestrictedcreature) - players[0]->castrestrictedcreature = true; - //------------------------------------ - if(players[1]->bothrestrictedspell) - players[0]->castrestrictedspell = true; - //------------------------------------ - if(players[1]->onlyoneboth) - players[0]->onlyoneboth = true; - //------------------------------------ - ///////////////////////////////////////////////// - //handle end of turn effects while we're at it.// - ///////////////////////////////////////////////// - if( currentGamePhase == Constants::MTG_PHASE_ENDOFTURN) - { - for (int j = 0; j < nbcards; ++j) - { - MTGCardInstance * c = z->cards[j]; - while (c->flanked) - {//undoes the flanking on a card - c->power += 1; - c->addToToughness(1); - c->flanked -= 1; - } - if (c->has(Constants::TREASON)) - { - WEvent * e = NEW WEventCardSacrifice(c); - GameObserver * game = GameObserver::GetInstance(); - game->receiveEvent(e); - p->game->putInGraveyard(c); - } - if (c->has(Constants::UNEARTH)) - p->game->putInExile(c); - if (c->fresh) - c->fresh = 0; - if (c->has(Constants::ONLYONEBOTH)) - { - c->controller()->castcount = 0; - c->controller()->opponent()->castcount = 0; - } + for (int i = 0; i < 2; i++) + { + //checks if a player has a card which has the stated ability in play. + Player * p = players[i]; + MTGGameZone * z = players[i]->game->inPlay; + int nbcards = z->nb_cards; + p->onlyonecast = false; + p->opponent()->onlyonecast = false; + //------------------------------ + if (z->hasAbility(Constants::NOMAXHAND)) + { + p->nomaxhandsize = true; + } + else + { + p->nomaxhandsize = false; + } + //------------------------------ + if (z->hasAbility(Constants::CANTCASTCREATURE)) + { + p->castrestrictedcreature = true; + } + else + { + p->castrestrictedcreature = false; + } + //------------------------------ + if (z->hasAbility(Constants::CANTCAST)) + { + p->castrestrictedspell = true; + } + else + { + p->castrestrictedspell = false; + } + //------------------------------ + if (z->hasAbility(Constants::CANTCASTTWO)) + { + p->onlyonecast = true; + } + else + { + p->onlyonecast = false; + } + //-------------------------------- + if (z->hasAbility(Constants::BOTHCANTCAST)) + { + p->bothrestrictedspell = true; + } + else + { + p->bothrestrictedspell = false; + } + //--------------------------------- + if (z->hasAbility(Constants::BOTHNOCREATURE)) + { + p->bothrestrictedcreature = true; + } + else + { + p->bothrestrictedcreature = false; + } + //----------------------------------- + if (z->hasAbility(Constants::ONLYONEBOTH)) + { + p->onlyoneboth = true; + } + else + { + p->onlyoneboth = false; + } + //------------------------------------ + if (players[0]->bothrestrictedcreature) + players[1]->castrestrictedcreature = true; + //------------------------------------ + if (players[0]->bothrestrictedspell) + players[1]->castrestrictedspell = true; + //------------------------------------ + if (players[0]->onlyoneboth) + players[1]->onlyoneboth = true; + //------------------------------------ + if (players[1]->bothrestrictedcreature) + players[0]->castrestrictedcreature = true; + //------------------------------------ + if (players[1]->bothrestrictedspell) + players[0]->castrestrictedspell = true; + //------------------------------------ + if (players[1]->onlyoneboth) + players[0]->onlyoneboth = true; + //------------------------------------ + ///////////////////////////////////////////////// + //handle end of turn effects while we're at it.// + ///////////////////////////////////////////////// + if (currentGamePhase == Constants::MTG_PHASE_ENDOFTURN) + { + for (int j = 0; j < nbcards; ++j) + { + MTGCardInstance * c = z->cards[j]; + while (c->flanked) + {//undoes the flanking on a card + c->power += 1; + c->addToToughness(1); + c->flanked -= 1; + } + if (c->has(Constants::TREASON)) + { + WEvent * e = NEW WEventCardSacrifice(c); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(e); + p->game->putInGraveyard(c); + } + if (c->has(Constants::UNEARTH)) p->game->putInExile(c); + if (c->fresh) c->fresh = 0; + if (c->has(Constants::ONLYONEBOTH)) + { + c->controller()->castcount = 0; + c->controller()->opponent()->castcount = 0; + } - } - MTGGameZone * f = p->game->graveyard; - for (int k = 0; k < f->nb_cards; k++) - { - MTGCardInstance * card = f->cards[k]; - card->fresh = 0; - } - } - if(z->nb_cards == 0) - { - p->nomaxhandsize = false; - if(!p->bothrestrictedcreature && !p->opponent()->bothrestrictedcreature) - p->castrestrictedcreature = false; - if(!p->bothrestrictedspell && !p->opponent()->bothrestrictedspell) - p->castrestrictedspell = false; - p->onlyonecast = false; - } - } - /////////////////////////////////// - //phase based state effects------// - /////////////////////////////////// - if (combatStep == TRIGGERS) - { - if (!mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED) && !targetChooser && !mLayers->actionLayer()->isWaitingForAnswer()) + } + MTGGameZone * f = p->game->graveyard; + for (int k = 0; k < f->nb_cards; k++) + { + MTGCardInstance * card = f->cards[k]; + card->fresh = 0; + } + } + if (z->nb_cards == 0) + { + p->nomaxhandsize = false; + if (!p->bothrestrictedcreature && !p->opponent()->bothrestrictedcreature) + p->castrestrictedcreature = false; + if (!p->bothrestrictedspell && !p->opponent()->bothrestrictedspell) + p->castrestrictedspell = false; + p->onlyonecast = false; + } + } + /////////////////////////////////// + //phase based state effects------// + /////////////////////////////////// + if (combatStep == TRIGGERS) + { + if (!mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED) && !targetChooser + && !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; - int nrCreatures = currentPlayer->game->inPlay->countByType("Creature"); + //Auto skip Phases + GameObserver * game = game->GetInstance(); + int skipLevel = (game->currentPlayer->playMode == Player::MODE_TEST_SUITE) ? Constants::ASKIP_NONE + : 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)))) + 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(); - } - if (skipLevel == Constants::ASKIP_FULL) - { - if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == Constants::MTG_PHASE_UPKEEP || currentGamePhase - == Constants::MTG_PHASE_COMBATDAMAGE)) - userRequestNextGamePhase(); - } + } + if (skipLevel == Constants::ASKIP_FULL) + { + if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == Constants::MTG_PHASE_UPKEEP + || currentGamePhase == Constants::MTG_PHASE_COMBATDAMAGE)) + userRequestNextGamePhase(); + } } void GameObserver::Render() { mLayers->Render(); - if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) - JRenderer::GetInstance()->DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(255,255,0,0)); - if (mExtraPayment) - mExtraPayment->Render(); + if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) + JRenderer::GetInstance()->DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(255,255,0,0)); + if (mExtraPayment) + mExtraPayment->Render(); + for (int i = 0; i < nbPlayers; ++i) { players[i]->Render(); @@ -701,8 +704,8 @@ void GameObserver::stackObjectClicked(Interruptible * action) else { int reaction = mLayers->actionLayer()->isReactingToTargetClick(action); - if (reaction == -1) - mLayers->actionLayer()->reactToTargetClick(action); + if (reaction == -1) + mLayers->actionLayer()->reactToTargetClick(action); } } @@ -729,8 +732,8 @@ bool GameObserver::WaitForExtraPayment(MTGCardInstance * card) int GameObserver::cardClick(MTGCardInstance * card, Targetable * object) { Player * clickedPlayer = NULL; - if (!card) - clickedPlayer = ((Player *) object); + if (!card) + clickedPlayer = ((Player *) object); if (targetChooser) { int result; @@ -763,10 +766,10 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object) return 1; } - if (WaitForExtraPayment(card)) - return 1; + if (WaitForExtraPayment(card)) + return 1; - int reaction = 0; + int reaction = 0; if (ORDER == combatStep) { @@ -793,22 +796,22 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object) } reaction = mLayers->actionLayer()->isReactingToClick(card); - if (reaction == -1) - return mLayers->actionLayer()->reactToClick(card); + if (reaction == -1) + return mLayers->actionLayer()->reactToClick(card); } else {//this handles abilities on a menu...not just when card is being played reaction = mLayers->actionLayer()->isReactingToTargetClick(object); - if (reaction == -1) - return mLayers->actionLayer()->reactToTargetClick(object); + if (reaction == -1) + return mLayers->actionLayer()->reactToTargetClick(object); } - if (!card) - return 0; + if (!card) + return 0; //Current player's hand if (currentPlayer->game->hand->hasCard(card) && currentGamePhase == Constants::MTG_PHASE_CLEANUP - && currentPlayer->game->hand->nb_cards > 7 && currentPlayer->nomaxhandsize == false) + && currentPlayer->game->hand->nb_cards > 7 && currentPlayer->nomaxhandsize == false) { currentPlayer->game->putInGraveyard(card); } @@ -840,9 +843,9 @@ int GameObserver::untap(MTGCardInstance * card) return 0; } if (card->has(Constants::DOESNOTUNTAP)) - return 0; - if (card->frozen > 0) - return 0; + return 0; + if (card->frozen > 0) + return 0; card->attemptUntap(); return 1; } @@ -850,8 +853,8 @@ int GameObserver::untap(MTGCardInstance * card) TargetChooser * GameObserver::getCurrentTargetChooser() { TargetChooser * _tc = mLayers->actionLayer()->getCurrentTargetChooser(); - if (_tc) - return _tc; + if (_tc) + return _tc; return targetChooser; } @@ -860,8 +863,8 @@ int GameObserver::isInPlay(MTGCardInstance * card) { for (int i = 0; i < 2; i++) { - if (players[i]->game->isInPlay(card)) - return 1; + if (players[i]->game->isInPlay(card)) + return 1; } return 0; } @@ -884,11 +887,11 @@ void GameObserver::untapPhase() int GameObserver::receiveEvent(WEvent * e) { - if (!e) - return 0; + if (!e) + return 0; eventsQueue.push(e); - if (eventsQueue.size() > 1) - return -1; //resolving events can generate more events + if (eventsQueue.size() > 1) + return -1; //resolving events can generate more events int result = 0; while (eventsQueue.size()) { @@ -906,8 +909,8 @@ int GameObserver::receiveEvent(WEvent * e) Player * GameObserver::currentlyActing() { - if (isInterrupting) - return isInterrupting; + if (isInterrupting) + return isInterrupting; return currentActionPlayer; } diff --git a/projects/mtg/src/GuiStatic.cpp b/projects/mtg/src/GuiStatic.cpp index dd0909d30..33983e904 100644 --- a/projects/mtg/src/GuiStatic.cpp +++ b/projects/mtg/src/GuiStatic.cpp @@ -21,7 +21,7 @@ bool GuiStatic::Leaving(JButton key) GuiAvatar::GuiAvatar(float x, float y, bool hasFocus, Player * player, Corner corner, GuiAvatars* parent) : GuiStatic(static_cast (GuiAvatar::Height), x, y, hasFocus, parent), avatarRed(255), currentLife(player->life), - currentpoisonCount(player->poisonCount), corner(corner), player(player) + currentpoisonCount(player->poisonCount), corner(corner), player(player) { type = GUI_AVATAR; } @@ -135,7 +135,7 @@ void GuiAvatar::Render() ostream& GuiAvatar::toString(ostream& out) const { return out << "GuiAvatar ::: avatarRed : " << avatarRed << " ; currentLife : " << currentLife << " ; currentpoisonCount : " - << currentpoisonCount << " ; player : " << player; + << currentpoisonCount << " ; player : " << player; } void GuiGameZone::toggleDisplay() @@ -166,7 +166,7 @@ void GuiGameZone::Render() if (mHasFocus) JRenderer::GetInstance()->FillRect(actX, actY, quad->mWidth * scale * actZ, quad->mHeight * scale * actZ, - ARGB(abs(128 - wave),255,255,255)); + ARGB(abs(128 - wave),255,255,255)); //Number of cards WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index b733926f7..d37a5a1d8 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -19,9 +19,11 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) Player * currentPlayer = game->currentPlayer; if (!player->game->hand->hasCard(card)) return 0; - if ((game->turn < 1) && (cardsinhand != 0) && (card->basicAbilities[Constants::LEYLINE]) && game->currentGamePhase - == Constants::MTG_PHASE_FIRSTMAIN && game->players[0]->game->graveyard->nb_cards == 0 - && game->players[0]->game->exile->nb_cards == 0) + if ((game->turn < 1) && (cardsinhand != 0) && (card->basicAbilities[Constants::LEYLINE]) + && game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN + && game->players[0]->game->graveyard->nb_cards == 0 + && game->players[0]->game->exile->nb_cards == 0 + ) { Player * p = game->currentPlayer; if (card->basicAbilities[Constants::LEYLINE]) @@ -35,15 +37,18 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) } if (card->hasType("land")) { - if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase - == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) + if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay + && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN) + ) { return 1; } } - else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase - == Constants::MTG_PHASE_SECONDMAIN))) + else 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(); @@ -241,15 +246,17 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * return 0; if (card->hasType("land")) { - if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase - == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) - { + if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay + && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN + || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN) + ) return 1; - } } - else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase - == Constants::MTG_PHASE_SECONDMAIN))) + else 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(); @@ -431,14 +438,14 @@ int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (card->hasType("land")) { if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase - == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) + == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) { return 1; } } else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase - == Constants::MTG_PHASE_SECONDMAIN))) + && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase + == Constants::MTG_PHASE_SECONDMAIN))) { ManaCost * playerMana = player->getManaPool(); ManaCost * cost = card->getManaCost(); @@ -455,11 +462,11 @@ int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { return 0; } - if (player->nospellinstant == true ) + if (player->nospellinstant == true) { return 0; } - if (player->onlyoneinstant == true ) + if (player->onlyoneinstant == true) { if (player->castcount >= 1) { @@ -621,9 +628,11 @@ int MTGFlashBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) return 0; if (!card->getManaCost()->FlashBack) return 0; - if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase - == Constants::MTG_PHASE_SECONDMAIN))) + 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(); @@ -640,11 +649,11 @@ int MTGFlashBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { return 0; } - if (player->nospellinstant == true ) + if (player->nospellinstant == true) { return 0; } - if (player->onlyoneinstant == true ) + if (player->onlyoneinstant == true) { if (player->castcount >= 1) { @@ -732,7 +741,7 @@ int MTGFlashBackRule::reactToClick(MTGCardInstance * card) game->targetChooser = NULL; player->castedspellsthisturn += 1; player->opponent()->castedspellsthisturn += 1; - if (player->onlyonecast == true || player->onlyoneinstant == true ) + if (player->onlyonecast == true || player->onlyoneinstant == true) { player->castcount += 1; } @@ -805,9 +814,11 @@ int MTGRetraceRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) return 0; if (!card->getManaCost()->Retrace) return 0; - if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase - == Constants::MTG_PHASE_SECONDMAIN))) + 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(); @@ -824,11 +835,11 @@ int MTGRetraceRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { return 0; } - if (player->nospellinstant == true ) + if (player->nospellinstant == true) { return 0; } - if (player->onlyoneinstant == true ) + if (player->onlyoneinstant == true) { if (player->castcount >= 1) { @@ -874,7 +885,8 @@ int MTGRetraceRule::reactToClick(MTGCardInstance * card) { cost->Retrace->setExtraCostsAction(this, card); game->mExtraPayment = cost->Retrace->extraCosts; - card->paymenttype = MTGAbility::RETRACE_COST;; + card->paymenttype = MTGAbility::RETRACE_COST; + ; return 0; } } @@ -912,7 +924,7 @@ int MTGRetraceRule::reactToClick(MTGCardInstance * card) game->targetChooser = NULL; player->castedspellsthisturn += 1; player->opponent()->castedspellsthisturn += 1; - if (player->onlyonecast == true || player->onlyoneinstant == true ) + if (player->onlyonecast == true || player->onlyoneinstant == true) { player->castcount += 1; } @@ -1013,8 +1025,10 @@ int MTGAttackRule::receiveEvent(WEvent *e) for (int i = 0; i < z->nb_cards; i++) { MTGCardInstance * card = z->cards[i]; - if (!card->isAttacker() && card->has(Constants::MUSTATTACK)) reactToClick(card); - if (!card->isAttacker() && card->has(Constants::TREASON) && p->isAI()) reactToClick(card); + if (!card->isAttacker() && card->has(Constants::MUSTATTACK)) + reactToClick(card); + if (!card->isAttacker() && card->has(Constants::TREASON) && p->isAI()) + reactToClick(card); if (card->isAttacker() && card->isTapped()) card->setAttacker(0); if (card->isAttacker() && !card->has(Constants::VIGILANCE)) @@ -1223,8 +1237,9 @@ MTGBlockRule::MTGBlockRule(int _id) : int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { - if (currentPhase == Constants::MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting && card->controller() - == game->currentlyActing()) + if (currentPhase == Constants::MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting + && card->controller() == game->currentlyActing() + ) { if (card->canBlock()) return 1; @@ -1245,8 +1260,8 @@ int MTGBlockRule::reactToClick(MTGCardInstance * card) canDefend = card->toggleDefenser(currentOpponent); DebugTrace("Defenser Toggle: " << card->getName() << endl - << "- canDefend: " << (canDefend == 0) << endl - << "- currentOpponent: " << currentOpponent); + << "- canDefend: " << (canDefend == 0) << endl + << "- currentOpponent: " << currentOpponent); result = (canDefend || currentOpponent == NULL); } return 1; @@ -1291,7 +1306,7 @@ MTGMomirRule::MTGMomirRule(int _id, MTGAllCards * _collection) : { MTGCard * card = collection->collection[collection->ids[i]]; if (card->data->isCreature() && (card->getRarity() != Constants::RARITY_T) && //remove tokens - card->setId != MTGSets::INTERNAL_SET //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally + card->setId != MTGSets::INTERNAL_SET //remove cards that are defined in primitives. Those are workarounds (usually tokens) and should only be used internally ) { int convertedCost = card->data->getManaCost()->getConvertedCost(); @@ -1315,8 +1330,10 @@ int MTGMomirRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) Player * currentPlayer = game->currentPlayer; if (!player->game->hand->hasCard(card)) return 0; - if (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)) + if (player == currentPlayer && !game->isInterrupting + && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN + || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN) + ) { return 1; } @@ -1414,8 +1431,9 @@ void MTGMomirRule::Render() ostream& MTGMomirRule::toString(ostream& out) const { - out << "MTGMomirRule ::: pool : " << pool << " ; initialized : " << initialized << " ; textAlpha : " << textAlpha << " ; text " - << text << " ; alreadyplayed : " << alreadyplayed << " ; collection : " << collection << "("; + out << "MTGMomirRule ::: pool : " << pool << " ; initialized : " << initialized << " ; textAlpha : " << textAlpha + << " ; text " << text << " ; alreadyplayed : " << alreadyplayed + << " ; collection : " << collection << "("; return MTGAbility::toString(out) << ")"; } @@ -1487,7 +1505,7 @@ int HUDDisplay::receiveEvent(WEvent * event) { char buffer[512]; sprintf(buffer, "%s: %i -> %s", _(ed->damage->source->name).c_str(), ed->damage->damage, _( - ed->damage->target->getDisplayName()).c_str()); + ed->damage->target->getDisplayName()).c_str()); string s = buffer; return addEvent(s); } @@ -1615,23 +1633,23 @@ MTGUnearthRule::MTGUnearthRule(int _id) : int MTGUnearthRule::receiveEvent(WEvent * event) { if (event->type == WEvent::CHANGE_ZONE) - { - WEventZoneChange * e = (WEventZoneChange *) event; - MTGCardInstance * card = e->card->previous; - if (e->from == e->card->controller()->game->battlefield && e->to == e->card->controller()->game->graveyard) - { - e->card->fresh = 1; - } - if (e->to == e->card->controller()->game->battlefield) - { - e->card->fresh = 1; - } + { + WEventZoneChange * e = (WEventZoneChange *) event; + MTGCardInstance * card = e->card->previous; + if (e->from == e->card->controller()->game->battlefield && e->to == e->card->controller()->game->graveyard) + { + e->card->fresh = 1; + } + if (e->to == e->card->controller()->game->battlefield) + { + e->card->fresh = 1; + } - if (card && card->basicAbilities[Constants::UNEARTH]) - { - int ok = 0; - for (int i = 0; i < 2; i++) - { + if (card && card->basicAbilities[Constants::UNEARTH]) + { + int ok = 0; + for (int i = 0; i < 2; i++) + { Player * p = game->players[i]; if (e->from == p->game->inPlay) ok = 1; @@ -1696,10 +1714,19 @@ int MTGAffinityRule::receiveEvent(WEvent * event) //when cards with affinity enter you hand from anywhere a redux is applied to them for the artifacts in play. if (ok == 1) {//enters play from anywhere - if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from - == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield - || e->from == p->game->temp || e->from == p->game->battlefield) + if (e->from == p->game->graveyard + || e->from == p->game->hand + || e->from == p->game->library + || e->from == p->game->exile + || e->from == p->game->stack + || e->from == p->opponent()->game->battlefield + || e->from == p->game->temp + || e->from == p->game->battlefield + ) { + // TODO: + // what happens if there are any cards with two or more affinity abilities? If no such card exist + // then could this block be changed to use else if? That will save on the number of operations. MTGCardInstance * card = e->card->previous; if (card && card->has(Constants::AFFINITYARTIFACTS)) { @@ -1743,13 +1770,14 @@ int MTGAffinityRule::receiveEvent(WEvent * event) { MTGCardInstance * c = z->cards[j]; int check = e->card->getManaCost()->getConvertedCost(); - if ((e->card->has(Constants::AFFINITYARTIFACTS) && c->hasSubtype("artifact")) || (e->card->has( - Constants::AFFINITYSWAMP) && c->hasSubtype("swamp")) || (e->card->has( - Constants::AFFINITYMOUNTAIN) && c->hasSubtype("moutain")) || (e->card->has( - Constants::AFFINITYPLAINS) && c->hasSubtype("plains")) || (e->card->has( - Constants::AFFINITYISLAND) && c->hasSubtype("island")) || (e->card->has( - Constants::AFFINITYFOREST) && c->hasSubtype("forest")) || (e->card->has( - Constants::AFFINITYGREENCREATURES) && c->hasColor(1) && c->isCreature())) + if ((e->card->has(Constants::AFFINITYARTIFACTS) && c->hasSubtype("artifact")) + || (e->card->has(Constants::AFFINITYSWAMP) && c->hasSubtype("swamp")) + || (e->card->has(Constants::AFFINITYMOUNTAIN) && c->hasSubtype("moutain")) + || (e->card->has(Constants::AFFINITYPLAINS) && c->hasSubtype("plains")) + || (e->card->has(Constants::AFFINITYISLAND) && c->hasSubtype("island")) + || (e->card->has(Constants::AFFINITYFOREST) && c->hasSubtype("forest")) + || (e->card->has(Constants::AFFINITYGREENCREATURES) && c->hasColor(1) && c->isCreature()) + ) { if (check > 0) { @@ -1776,8 +1804,13 @@ int MTGAffinityRule::receiveEvent(WEvent * event) ok = 2;//card enters play if (ok == 2) {//enters play from anywhere - if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from - == p->game->exile || e->from == p->game->stack || e->from == p->game->temp) + if (e->from == p->game->graveyard + || e->from == p->game->hand + || e->from == p->game->library + || e->from == p->game->exile + || e->from == p->game->stack + || e->from == p->game->temp + ) { //--redux effect MTGGameZone * z = card->controller()->game->hand; @@ -1817,13 +1850,14 @@ int MTGAffinityRule::receiveEvent(WEvent * event) for (int j = 0; j < nbcards; ++j) { MTGCardInstance * c = z->cards[j]; - if ((c->has(Constants::AFFINITYARTIFACTS) && etype.find("art") != string::npos) || (c->has( - Constants::AFFINITYSWAMP) && etype.find("swa") != string::npos) || (c->has( - Constants::AFFINITYMOUNTAIN) && etype.find("mou") != string::npos) || (c->has( - Constants::AFFINITYPLAINS) && etype.find("pla") != string::npos) || (c->has( - Constants::AFFINITYISLAND) && etype.find("isl") != string::npos) || (c->has( - Constants::AFFINITYFOREST) && etype.find("for") != string::npos) || (c->has( - Constants::AFFINITYGREENCREATURES) && etype.find("cre") != string::npos)) + if ((c->has(Constants::AFFINITYARTIFACTS) && etype.find("art") != string::npos) + || (c->has(Constants::AFFINITYSWAMP) && etype.find("swa") != string::npos) + || (c->has(Constants::AFFINITYMOUNTAIN) && etype.find("mou") != string::npos) + || (c->has(Constants::AFFINITYPLAINS) && etype.find("pla") != string::npos) + || (c->has(Constants::AFFINITYISLAND) && etype.find("isl") != string::npos) + || (c->has(Constants::AFFINITYFOREST) && etype.find("for") != string::npos) + || (c->has(Constants::AFFINITYGREENCREATURES) && etype.find("cre") != string::npos) + ) { if (c->getManaCost()->getConvertedCost() > 0) { @@ -1839,9 +1873,15 @@ int MTGAffinityRule::receiveEvent(WEvent * event) }//--end of redux bracket ok == 2 //--------- ok = 0; - if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile - || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) + if (e->to == p->game->graveyard + || e->to == p->game->hand + || e->to == p->game->library + || e->to == p->game->exile + || e->to == p->game->stack + || e->to == p->opponent()->game->battlefield + ) ok = 3;//card leaves play + if (ok == 3) {//leave play from your battlefield if (e->from == p->game->battlefield) @@ -1883,13 +1923,14 @@ int MTGAffinityRule::receiveEvent(WEvent * event) for (int j = 0; j < nbcards; ++j) { MTGCardInstance * c = z->cards[j]; - if (c && ((c->has(Constants::AFFINITYARTIFACTS) && etype.find("art") != string::npos) || (c->has( - Constants::AFFINITYSWAMP) && etype.find("swa") != string::npos) || (c->has( - Constants::AFFINITYMOUNTAIN) && etype.find("mou") != string::npos) || (c->has( - Constants::AFFINITYPLAINS) && etype.find("pla") != string::npos) || (c->has( - Constants::AFFINITYISLAND) && etype.find("isl") != string::npos) || (c->has( - Constants::AFFINITYFOREST) && etype.find("for") != string::npos) || (c->has( - Constants::AFFINITYGREENCREATURES) && etype.find("cre") != string::npos))) + if (c && ((c->has(Constants::AFFINITYARTIFACTS) && etype.find("art") != string::npos) + || (c->has(Constants::AFFINITYSWAMP) && etype.find("swa") != string::npos) + || (c->has(Constants::AFFINITYMOUNTAIN) && etype.find("mou") != string::npos) + || (c->has(Constants::AFFINITYPLAINS) && etype.find("pla") != string::npos) + || (c->has(Constants::AFFINITYISLAND) && etype.find("isl") != string::npos) + || (c->has(Constants::AFFINITYFOREST) && etype.find("for") != string::npos) + || (c->has(Constants::AFFINITYGREENCREATURES) && etype.find("cre") != string::npos)) + ) { if (c->reduxamount > 0) { @@ -1911,21 +1952,25 @@ int MTGAffinityRule::receiveEvent(WEvent * event) } return 0; } + ostream& MTGAffinityRule::toString(ostream& out) const { out << "MTGAffinityRule ::: ("; return MTGAbility::toString(out) << ")"; } + int MTGAffinityRule::testDestroy() { return 0; } + MTGAffinityRule * MTGAffinityRule::clone() const { MTGAffinityRule * a = NEW MTGAffinityRule(*this); a->isClone = 1; return a; } + //------------------------------------------------------------------- MTGTokensCleanup::MTGTokensCleanup(int _id) :