diff --git a/projects/mtg/include/ActionStack.h b/projects/mtg/include/ActionStack.h index ba0a9db87..ebd592609 100644 --- a/projects/mtg/include/ActionStack.h +++ b/projects/mtg/include/ActionStack.h @@ -213,6 +213,7 @@ public: int setIsInterrupting(Player * player); int count( int type = 0 , int state = 0 , int display = -1); + int getActionElementFromCard(MTGCardInstance * card); Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1); int getPreviousIndex(Interruptible * next, int type = 0, int state = 0 , int display = -1); Interruptible * getNext(Interruptible * previous, int type = 0, int state = 0 , int display = -1); diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index e21db317c..d5b64db95 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -75,6 +75,10 @@ public: { intValue = target->equipment; } + else if (s == "colors") + { + intValue = target->countColors(); + } else if (s == "auras") { intValue = target->auras; @@ -106,6 +110,7 @@ public: for (int k = 0; k < 4; k++) { MTGGameZone * zone = zones[k]; + if(tc->targetsZone(zone,target)) intValue += zone->countByCanTarget(tc); } } @@ -368,182 +373,29 @@ public: } }; -class TrCardAttackedNotBlocked: public TriggeredAbility +class TrCombatTrigger: public TriggeredAbility { public: - TargetChooser * tc; - TrCardAttackedNotBlocked(int id, MTGCardInstance * source, TargetChooser * tc) : - TriggeredAbility(id, source), tc(tc) - { - } - - int resolve() - { - return 0; //This is a trigger, this function should not be called - } - - int triggerOnEvent(WEvent * event) - { - if(source->isPhased) return 0; - WEventCardAttackedNotBlocked * e = dynamic_cast (event); - if (!e) return 0; - if (e->card->didattacked < 1) return 0; - if (e->card->blocked) return 0; - if (!tc->canTarget(e->card)) return 0; - return 1; - } - - ~TrCardAttackedNotBlocked() - { - SAFE_DELETE(tc); - } - - TrCardAttackedNotBlocked * clone() const - { - TrCardAttackedNotBlocked * a = NEW TrCardAttackedNotBlocked(*this); - a->isClone = 1; - return a; - } -}; - -class TrCardAttackedBlocked: public TriggeredAbility -{ -public: - TargetChooser * tc; - TargetChooser * fromTc; - bool limitOnceATurn; - int triggeredTurn; - TrCardAttackedBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL,bool limitOnceATurn = false) : - TriggeredAbility(id, source), tc(tc), fromTc(fromTc),limitOnceATurn(limitOnceATurn) - { - triggeredTurn = -1; - } - - int resolve() - { - return 0; //This is a trigger, this function should not be called - } - - int triggerOnEvent(WEvent * event) - { - if(source->isPhased) return 0; - WEventCardAttackedBlocked * e = dynamic_cast (event); - if (!e) return 0; - GameObserver * g = GameObserver::GetInstance(); - if (limitOnceATurn && triggeredTurn == g->turn) - return 0; - if (e->card->didattacked < 1) return 0; - if (!e->card->blocked) return 0; - if (fromTc && !fromTc->canTarget(e->card->getNextOpponent())) return 0; - if (!tc->canTarget(e->card)) return 0; - triggeredTurn = g->turn; - return 1; - } - - ~TrCardAttackedBlocked() - { - SAFE_DELETE(tc); - SAFE_DELETE(fromTc); - } - - TrCardAttackedBlocked * clone() const - { - TrCardAttackedBlocked * a = NEW TrCardAttackedBlocked(*this); - a->isClone = 1; - return a; - } -}; - -class TrCardAttacked: public TriggeredAbility -{ -public: - TargetChooser * tc; + TargetChooser * tc;//source(card) + TargetChooser * fromTc;//from(card) + bool once;//can only activate one time ever. + bool activeTrigger; + bool limitOnceATurn;//can activate one time per turn + int triggeredTurn;//the turn it last activated bool sourceUntapped; bool opponentPoisoned; - TrCardAttacked(int id, MTGCardInstance * source, TargetChooser * tc,bool sourceUntapped,bool opponentPoisoned) : - TriggeredAbility(id, source), tc(tc), sourceUntapped(sourceUntapped),opponentPoisoned(opponentPoisoned) - { - } - - int resolve() - { - return 0; //This is a trigger, this function should not be called - } - - int triggerOnEvent(WEvent * event) - { - if(source->isPhased) return 0; - WEventCardAttacked * e = dynamic_cast (event); - if (!e) return 0; - if (sourceUntapped && source->isTapped() == 1) - return 0; - if (e->card->didattacked < 1) return 0; - if (!tc->canTarget(e->card)) return 0; - if (opponentPoisoned && !source->controller()->opponent()->isPoisoned) return 0; - return 1; - } - - ~TrCardAttacked() - { - SAFE_DELETE(tc); - } - - TrCardAttacked * clone() const - { - TrCardAttacked * a = NEW TrCardAttacked(*this); - a->isClone = 1; - return a; - } -}; - -class TrCardAttackedAlone: public TriggeredAbility -{ -public: - TargetChooser * tc; - TrCardAttackedAlone(int id, MTGCardInstance * source, TargetChooser * tc) : - TriggeredAbility(id, source), tc(tc) - { - } - - int resolve() - { - return 0; //This is a trigger, this function should not be called - } - - int triggerOnEvent(WEvent * event) - { - if(source->isPhased) return 0; - WEventCardAttackedAlone * e = dynamic_cast (event); - if (!e) return 0; - if (e->card->didattacked < 1) return 0; - if (!tc->canTarget(e->card)) return 0; - return 1; - } - - ~TrCardAttackedAlone() - { - SAFE_DELETE(tc); - } - - TrCardAttackedAlone * clone() const - { - TrCardAttackedAlone * a = NEW TrCardAttackedAlone(*this); - a->isClone = 1; - return a; - } -}; - -class TrCardBlocked: public TriggeredAbility -{ -public: - TargetChooser * tc; - TargetChooser * fromTc; - bool once; - bool activeTrigger; - bool limitOnceATurn; - int triggeredTurn; - TrCardBlocked(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL,bool once = false,bool limitOnceATurn = false) : - TriggeredAbility(id, source), tc(tc), fromTc(fromTc), once(once),limitOnceATurn(limitOnceATurn) + //trigger types + bool attackingTrigger; + bool attackedAloneTrigger; + bool notBlockedTrigger; + bool attackBlockedTrigger; + bool blockingTrigger; + TrCombatTrigger(int id, MTGCardInstance * source, TargetChooser * tc,TargetChooser * fromTc = NULL, + bool once = false,bool limitOnceATurn = false,bool sourceUntapped = false,bool opponentPoisoned = false, + bool attackingTrigger = false,bool attackedAloneTrigger = false,bool notBlockedTrigger = false,bool attackBlockedTrigger = false,bool blockingTrigger = false) : + TriggeredAbility(id, source),tc(tc), fromTc(fromTc), once(once),limitOnceATurn(limitOnceATurn),sourceUntapped(sourceUntapped),opponentPoisoned(opponentPoisoned), + attackingTrigger(attackingTrigger),attackedAloneTrigger(attackedAloneTrigger),notBlockedTrigger(notBlockedTrigger), + attackBlockedTrigger(attackBlockedTrigger),blockingTrigger(blockingTrigger) { activeTrigger = true; triggeredTurn = -1; @@ -556,31 +408,103 @@ public: int triggerOnEvent(WEvent * event) { - if(source->isPhased) return 0; - WEventCardBlocked * e = dynamic_cast (event); - if (!e) return 0; + //general restrictions + if(source->isPhased) + return 0; + if (opponentPoisoned && !source->controller()->opponent()->isPoisoned) + return 0; + if (sourceUntapped && source->isTapped() == 1) + return 0; + if (limitOnceATurn && triggeredTurn == game->turn) + return 0; if(activeTrigger == false) return 0; - GameObserver * g = GameObserver::GetInstance(); - if (limitOnceATurn && triggeredTurn == g->turn) - return 0; - if (fromTc && !fromTc->canTarget(e->card->getNextOpponent())) return 0; - if (!tc->canTarget(e->card)) return 0; - if(once && activeTrigger ) + //the follow cases are not "else'd" on purpose, triggers which are conjoined such as + //"whenever this card attacks, or attacks and is not blocked, are supposed to gernerally + //trigger only once MTG rule 509.a-d, from either/or..not else'ing the statements and + //listing them in order allows just that, a return on an event before hitting the + //next trigger condiational. + //when triggers are not conjoined you can simply add another combat trigger to the card as normal. + //an attacking creature can not also be a blocking creature. + WEventCardAttacked * attacked = dynamic_cast (event); + //event when a card was declared an attacker. + if (attacked && attackingTrigger && !attacked->card->didblocked) + { + if (!attacked->card->didattacked) + return 0; + if (!tc->canTarget(attacked->card)) + return 0; + return returnResult(); + } + WEventCardAttackedAlone * attackedAlone = dynamic_cast (event); + //event when a card was declared an attacker, and attacked alone. + if (attackedAlone && attackedAloneTrigger && !attackedAlone->card->didblocked) + { + if (!attackedAlone->card->didattacked) + return 0; + if (!tc->canTarget(attackedAlone->card)) + return 0; + return returnResult(); + } + WEventCardBlocked * blocked = dynamic_cast (event); + //event when a card was declared a blocker. + if (blocked && blockingTrigger && !blocked->card->didattacked) + { + if(!blocked->card->didblocked) + return 0; + if (fromTc && !fromTc->canTarget(blocked->opponent)) + return 0; + if (!tc->canTarget(blocked->card)) + return 0; + return returnResult(); + } + WEventCardAttackedNotBlocked * notblocked = dynamic_cast (event); + //event when a card was declared an attacker, but the attack was not blocked. + if (notblocked && notBlockedTrigger && !notblocked->card->didblocked) + { + if (!notblocked->card->didattacked) + return 0; + if (notblocked->card->blocked) + return 0; + if (!tc->canTarget(notblocked->card)) + return 0; + return returnResult(); + } + WEventCardAttackedBlocked * attackblocked = dynamic_cast (event); + //event when a card was declared an attacker, then it became "blocked". + if (attackblocked && attackBlockedTrigger && !attackblocked->card->didblocked) + { + if (!attackblocked->card->didattacked) + return 0; + if (!attackblocked->card->blocked) + return 0; + if (fromTc && !fromTc->canTarget(attackblocked->opponent)) + return 0; + if (!tc->canTarget(attackblocked->card)) + return 0; + return returnResult(); + } + //default return is 0 || not triggered. + return 0; + } + + int returnResult() + { + if(once && activeTrigger ) activeTrigger = false; - triggeredTurn = g->turn; + triggeredTurn = game->turn; return 1; } - - ~TrCardBlocked() + + ~TrCombatTrigger() { SAFE_DELETE(tc); SAFE_DELETE(fromTc); } - TrCardBlocked * clone() const + TrCombatTrigger * clone() const { - TrCardBlocked * a = NEW TrCardBlocked(*this); + TrCombatTrigger * a = NEW TrCombatTrigger(*this); a->isClone = 1; return a; } @@ -1027,12 +951,10 @@ public: class GenericActivatedAbility: public ActivatedAbility, public NestedAbility { public: - int limitPerTurn; - string limit; - int counters; MTGGameZone * activeZone; + string newName; - GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, string limit = "", + GenericActivatedAbility(string newName,int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, string limit = "", int restrictions = 0, MTGGameZone * dest = NULL); int resolve(); const char * getMenuText(); @@ -1158,8 +1080,9 @@ public: string limit; int counters; MTGGameZone * activeZone; + string newName; - GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost = NULL, + GenericTargetAbility(string newName,int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost = NULL, int _tap = 0, string limit = "", int restrictions = 0, MTGGameZone * dest = NULL); const char * getMenuText(); ~GenericTargetAbility(); @@ -1357,45 +1280,6 @@ public: AAWinGame * clone() const; }; - -//naming an ability line------------------------------------------------------------------------- -class ANamer: public ActivatedAbility -{ -public: - string name; - ANamer(int _id, MTGCardInstance * _source, ManaCost * _cost, string sname, int _doTap) : - ActivatedAbility(_id, _source, _cost, 0, _doTap) - { - name = sname; - } - int resolve() - { - return 0; - } - const char * getMenuText() - { - sprintf(menuText, "%s", name.c_str()); - return menuText; - } - virtual ostream& toString(ostream& out) const - { - out << "ANamer ::: name" << name << " ("; - return ActivatedAbility::toString(out) << ")"; - } - ANamer * clone() const - { - ANamer * a = NEW ANamer(*this); - a->isClone = 1; - return a; - } - ~ANamer() - { - if (!isClone) - { - } - } -}; - /*Changes one of the basic abilities of target source : spell target : spell target (creature) @@ -1901,12 +1785,30 @@ class APowerToughnessModifier: public MTGAbility { public: WParsedPT * wppt; - APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, WParsedPT * wppt) : - MTGAbility(id, _source, _target), wppt(wppt) + string PT; + bool nonstatic; + APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, WParsedPT * wppt,string PT,bool nonstatic) : + MTGAbility(id, _source, _target), wppt(wppt),PT(PT),nonstatic(nonstatic) { aType = MTGAbility::STANDARD_PUMP; } - + + void Update(float dt) + { + if(!nonstatic) + return; + ((MTGCardInstance *) target)->power -= wppt->power.getValue(); + ((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue()); + if(PT.size()) + { + SAFE_DELETE(wppt); + wppt = NEW WParsedPT(PT,NULL,(MTGCardInstance *) target); + } + MTGCardInstance * _target = (MTGCardInstance *) target; + _target->power += wppt->power.getValue(); + _target->addToToughness(wppt->toughness.getValue()); + } + int addToGame() { MTGCardInstance * _target = (MTGCardInstance *) target; @@ -3932,7 +3834,10 @@ public: list colors; list oldcolors; list oldtypes; + vector dontremove; + bool addNewColors; bool remove; + bool removeTypes; string menu; string newpower; bool newpowerfound; @@ -3943,9 +3848,9 @@ public: map > newAbilities; vector newAbilitiesList; bool newAbilityFound; + bool aForever; - - ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector newAbilitiesList,bool newAbilityFound = false); + ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector newAbilitiesList,bool newAbilityFound = false,bool aForever = false); int addToGame(); int destroy(); const char * getMenuText(); @@ -3953,34 +3858,8 @@ public: ~ATransformer(); }; -//transforms forever class -class AForeverTransformer: public MTGAbility -{ -public: - list abilities; - list types; - list colors; - string menu; - string newpower; - bool newpowerfound; - int oldpower; - string newtoughness; - bool newtoughnessfound; - int oldtoughness; - bool remove; - vector newAbilitiesList; - map > newAbilities; - bool newAbilityFound; - - AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vectornewAbilitiesList = vector(),bool newAbilityFound = false); - int addToGame(); - const char * getMenuText(); - AForeverTransformer * clone() const; - ~AForeverTransformer(); -}; - -//Adds types/abilities/changes color to a card (until end of turn) -class ATransformerUEOT: public InstantAbility +//Adds types/abilities/changes color to a card (generally until end of turn) +class ATransformerInstant: public InstantAbility { public: ATransformer * ability; @@ -3991,32 +3870,13 @@ public: vector newAbilitiesList; map > newAbilities; bool newAbilityFound; + bool aForever; - ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types = "", string abilities = "",string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vectornewAbilitiesList = vector(),bool newAbilityFound = false); + ATransformerInstant(int id, MTGCardInstance * source, MTGCardInstance * target, string types = "", string abilities = "",string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vectornewAbilitiesList = vector(),bool newAbilityFound = false,bool aForever = false); int resolve(); const char * getMenuText(); - ATransformerUEOT * clone() const; - ~ATransformerUEOT(); -}; - -//transforms forever -class ATransformerFOREVER: public InstantAbility -{ -public: - AForeverTransformer * ability; - string newpower; - bool newpowerfound; - string newtoughness; - bool newtoughnessfound; - vector newAbilitiesList; - map > newAbilities; - bool newAbilityFound; - - ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower = "",bool newpowerfound = false,string newtoughness = "",bool newtoughnessfound = false,vectornewAbilitiesList = vector(),bool newAbilityFound = false); - int resolve(); - const char * getMenuText(); - ATransformerFOREVER * clone() const; - ~ATransformerFOREVER(); + ATransformerInstant * clone() const; + ~ATransformerInstant(); }; //switch p/t ueot @@ -4031,38 +3891,6 @@ public: ~ASwapPTUEOT(); }; -//becomes ability -//Adds types/abilities/P/T to a card (aura) -class ABecomes: public MTGAbility -{ -public: - list abilities; - list types; - list colors; - WParsedPT * wppt; - string menu; - ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, WParsedPT * wppt, string sabilities); - int addToGame(); - int destroy(); - const char * getMenuText(); - ABecomes * clone() const; - ~ABecomes(); - -}; - -//Adds types/abilities/P/T to a card (until end of turn) -class ABecomesUEOT: public InstantAbility -{ -public: - ABecomes * ability; - ABecomesUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, WParsedPT * wpt, string abilities); - int resolve(); - const char * getMenuText(); - ABecomesUEOT * clone() const; - ~ABecomesUEOT(); - -}; - class APreventDamageTypes: public MTGAbility { public: diff --git a/projects/mtg/include/CardPrimitive.h b/projects/mtg/include/CardPrimitive.h index 42f4e1e4f..8ec1a0b10 100644 --- a/projects/mtg/include/CardPrimitive.h +++ b/projects/mtg/include/CardPrimitive.h @@ -17,70 +17,6 @@ class CardPrimitive { ManaCost manaCost; public: - enum { - NO_RESTRICTION = 0, - PLAYER_TURN_ONLY = 1, - AS_SORCERY = 2, - MY_BEFORE_BEGIN = 3, - MY_UNTAP = 4, - MY_UPKEEP = 5, - MY_DRAW = 6, - MY_FIRSTMAIN = 7, - MY_COMBATBEGIN = 8, - MY_COMBATATTACKERS = 9, - MY_COMBATBLOCKERS = 10, - MY_COMBATDAMAGE = 11, - MY_COMBATEND = 12, - MY_SECONDMAIN = 13, - MY_ENDOFTURN = 14, - MY_EOT = 15, - MY_CLEANUP = 16, - MY_AFTER_EOT = 17, - - OPPONENT_BEFORE_BEGIN = 23, - OPPONENT_UNTAP = 24, - OPPONENT_UPKEEP = 25, - OPPONENT_DRAW = 26, - OPPONENT_FIRSTMAIN = 27, - OPPONENT_COMBATBEGIN = 28, - OPPONENT_COMBATATTACKERS = 29, - OPPONENT_COMBATBLOCKERS = 30, - OPPONENT_COMBATDAMAGE = 31, - OPPONENT_COMBATEND = 32, - OPPONENT_SECONDMAIN = 33, - OPPONENT_ENDOFTURN = 34, - OPPONENT_EOT = 35, - OPPONENT_CLEANUP = 36, - OPPONENT_AFTER_EOT = 37, - - BEFORE_BEGIN = 43, - UNTAP = 44, - UPKEEP = 45, - DRAW = 46, - FIRSTMAIN = 47, - COMBATBEGIN = 48, - COMBATATTACKERS = 49, - COMBATBLOCKERS = 50, - COMBATDAMAGE = 51, - COMBATEND = 52, - SECONDMAIN = 53, - ENDOFTURN = 54, - EOT = 55, - CLEANUP = 56, - AFTER_EOT = 57, - - VAMPIRES = 60, - LESS_CREATURES = 61, - SNOW_LAND_INPLAY =62, - CASTED_A_SPELL = 63, - ONE_OF_AKIND = 64, - FOURTHTURN = 65, - BEFORECOMBATDAMAGE = 66, - AFTERCOMBAT = 67, - DURINGCOMBAT = 68, - OPPONENT_TURN_ONLY = 69, - - }; string text; string name; int init(); @@ -94,7 +30,7 @@ class CardPrimitive { int power; int toughness; bool hasRestriction; - int restriction; + string restriction; string otherrestriction; int suspendedTime; @@ -143,8 +79,8 @@ class CardPrimitive { int getPower(); void setToughness(int _toughness); int getToughness(); - void setRestrictions(int _restriction); - int getRestrictions(); + void setRestrictions(string _restriction); + void getRestrictions(); void setOtherRestrictions(string _restriction); void getOtherRestrictions(); const vector& formattedText(); diff --git a/projects/mtg/include/ExtraCost.h b/projects/mtg/include/ExtraCost.h index b414fadec..2f52d07c8 100644 --- a/projects/mtg/include/ExtraCost.h +++ b/projects/mtg/include/ExtraCost.h @@ -61,7 +61,14 @@ public: virtual int doPay(); virtual LifeCost * clone() const; }; - +//pyrhaixa mana +class LifeorManaCost: public ExtraCost{ +public: + LifeorManaCost(TargetChooser *_tc = NULL,string manaType = ""); + string manaType; + virtual int doPay(); + virtual LifeorManaCost * clone() const; +}; //Discard a random card cost class DiscardRandomCost: public ExtraCost{ public: diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 1749ba593..b74ac38f1 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -98,17 +98,10 @@ class MTGAbility: public ActionElement{ CLEANUP = 56, AFTER_EOT = 57, - VAMPIRES = 60, - LESS_CREATURES = 61, - SNOW_LAND_INPLAY =62, - CASTED_A_SPELL = 63, - ONE_OF_AKIND = 64, - FOURTHTURN = 65, - BEFORECOMBATDAMAGE = 66, - AFTERCOMBAT = 67, - DURINGCOMBAT = 68, - OPPONENT_TURN_ONLY = 69, + OPPONENT_TURN_ONLY = 60, + }; + int parseCastRestrictions(MTGCardInstance * card,Player * player,string restrictions,string otherRestrictions); int allowedToCast(MTGCardInstance * card,Player * player); int allowedToAltCast(MTGCardInstance * card,Player * player); int oneShot; @@ -260,9 +253,20 @@ class ActivatedAbility:public MTGAbility{ }; ManaCost * abilityCost; int restrictions; + int limitPerTurn; + string limit; + int counters; int needsTapping; - ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1); + ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1,string limit = ""); virtual ~ActivatedAbility(); + virtual void Update(float dt) + { + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT) + { + counters = 0; + } + return MTGAbility::Update(dt); + } virtual int reactToClick(MTGCardInstance * card); virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); virtual int reactToTargetClick(Targetable * object); @@ -371,11 +375,11 @@ class AbilityFactory{ string storedString; int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); TriggeredAbility * parseTrigger(string s, string magicText, int id, Spell * spell, MTGCardInstance *card, Targetable * target); - int parseRestriction(string s); MTGAbility * getAlternateCost( string s, int id, Spell *spell, MTGCardInstance *card ); MTGAbility * getManaReduxAbility(string s, int id, Spell *spell, MTGCardInstance *card, MTGCardInstance *target); public: + int parseRestriction(string s); Counter * parseCounter(string s, MTGCardInstance * target, Spell * spell = NULL); int parsePowerToughness(string s, int *power, int *toughness); int getAbilities(vector * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL); @@ -421,10 +425,10 @@ class AManaProducer: public ActivatedAbilityTP{ protected: - string menutext; Player * controller; public: + string menutext; ManaCost * output; int tap; AManaProducer(int id, MTGCardInstance * card, Targetable * t, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 0, int who = TargetChooser::UNSET ); diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 1cef23edc..c8a919932 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -185,8 +185,8 @@ class MTGCardInstance: public CardPrimitive, public MTGCard, public Damageable { void eventattacked(); void eventattackedAlone(); void eventattackednotblocked(); - void eventattackedblocked(); - void eventblocked(); + void eventattackedblocked(MTGCardInstance * opponent); + void eventblocked(MTGCardInstance * opponent); int isInPlay(); JSample * getSample(); diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index 2fa94e6cd..6dfe56946 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -18,6 +18,50 @@ public: OtherAbilitiesEventReceiver(int _id); OtherAbilitiesEventReceiver * clone() const; }; + +class MTGEventBonus: public MTGAbility +{ +public: + int textAlpha; + string text; + int army[2]; + bool army1[2]; + bool army2[2]; + bool army3[2]; + int toys[2]; + bool toybonusgranted[2]; + int chain[2]; + int highestChain[2]; + bool beastbonusgranted[2]; + int beast[2]; + bool zombiebonusgranted[2]; + int zombie[2]; + bool knightbonusgranted[2]; + int knight[2]; + bool insectbonusgranted[2]; + int insect[2]; + bool elementalbonusgranted[2]; + int elemental[2]; + bool vampirebonusgranted[2]; + int vampire[2]; + bool clericbonusgranted[2]; + int cleric[2]; + bool elfbonusgranted[2]; + int elf[2]; + bool Angelbonusgranted[2]; + int Angel[2]; + bool dragonbonusgranted[2]; + int dragon[2]; + + int receiveEvent(WEvent * event); + void grantAward(string awardName,int amount); + int testDestroy(); + void Update(float dt); + void Render(); + MTGEventBonus(int _id); + virtual MTGEventBonus * clone() const; +}; + class MTGPutInPlayRule: public MTGAbility { public: @@ -38,7 +82,7 @@ class MTGAlternativeCostRule: public MTGAbility protected: int isReactingToClick(MTGCardInstance * card, ManaCost * mana, ManaCost *alternateManaCost); int reactToClick(MTGCardInstance * card, ManaCost * alternateManaCost, int paymentType = ManaCost::MANA_PAID); - + string alternativeName; public: int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); int reactToClick(MTGCardInstance * card); @@ -48,6 +92,8 @@ public: MTGAlternativeCostRule(int _id); const char * getMenuText() { + if(alternativeName.size()) + return alternativeName.c_str(); return "Pay Alternative Cost"; } virtual MTGAlternativeCostRule * clone() const; diff --git a/projects/mtg/include/ManaCost.h b/projects/mtg/include/ManaCost.h index 19d1f93eb..cacbb0822 100644 --- a/projects/mtg/include/ManaCost.h +++ b/projects/mtg/include/ManaCost.h @@ -45,6 +45,7 @@ public: ManaCost * Retrace; ManaCost * morph; ManaCost * suspend; + string alternativeName; static ManaCost * parseManaCost(string value, ManaCost * _manacost = NULL, MTGCardInstance * c = NULL); virtual void init(); void x(); diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 66e4e7b62..0ec320a65 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -34,7 +34,6 @@ public: string deckFileSmall; string deckName; string phaseRing; - Player(string deckFile, string deckFileSmall, MTGDeck * deck = NULL); virtual ~Player(); diff --git a/projects/mtg/include/TargetChooser.h b/projects/mtg/include/TargetChooser.h index d293c64cb..b6b7895d1 100644 --- a/projects/mtg/include/TargetChooser.h +++ b/projects/mtg/include/TargetChooser.h @@ -51,6 +51,10 @@ public: { return false; } + virtual bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource) + { + return false; + } ; int ForceTargetListReady(); int targetsReadyCheck(); @@ -100,6 +104,7 @@ public: int nbzones; int init(int * _zones, int _nbzones); bool targetsZone(MTGGameZone * z); + bool targetsZone(MTGGameZone * z,MTGCardInstance * mSource); bool withoutProtections; TargetZoneChooser(MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); TargetZoneChooser(int * _zones, int _nbzones, MTGCardInstance * card = NULL, int _maxtargets = 1, bool other = false); diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index 8f93e0e66..e5e0f0034 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -145,13 +145,15 @@ struct WEventCardAttackedNotBlocked : public WEventCardUpdate { //event when card attacks but is blocked. struct WEventCardAttackedBlocked : public WEventCardUpdate { - WEventCardAttackedBlocked(MTGCardInstance * card); + WEventCardAttackedBlocked(MTGCardInstance * card,MTGCardInstance * opponent); + MTGCardInstance * opponent; virtual Targetable * getTarget(int target); }; //event when card blocked. struct WEventCardBlocked : public WEventCardUpdate { - WEventCardBlocked(MTGCardInstance * card); + WEventCardBlocked(MTGCardInstance * card,MTGCardInstance * opponent); + MTGCardInstance * opponent; virtual Targetable * getTarget(int target); }; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 7182c69f4..e3e4850d9 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -1296,6 +1296,7 @@ int AIPlayerBaka::computeActions() { GameObserver * g = GameObserver::GetInstance(); Player * p = g->currentPlayer; + Player * currentP = g->currentlyActing(); if (!(g->currentlyActing() == this)) return 0; if (g->mLayers->actionLayer()->menuObject) @@ -1315,7 +1316,19 @@ int AIPlayerBaka::computeActions() {//is already looking kick me out of this function! return 0; } - if ((interruptIfICan() || g->isInterrupting == this) && p != this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 1) + Interruptible * action = g->mLayers->stackLayer()->getAt(-1); + Spell * spell = (Spell *) action; + Player * lastStackActionController = NULL; + if(spell && spell->type == ACTION_SPELL) + lastStackActionController = spell->source->controller(); + if ((interruptIfICan() || g->isInterrupting == this) + //i can interupt or am interupting + && p != this + //and its not my turn + && this == currentP + //and i am the currentlyActivePlayer + && ((lastStackActionController && lastStackActionController != this) || (g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0))) + //am im not interupting my own spell, or the stack contains nothing. { findingCard = true; CardDescriptor cd; @@ -1504,7 +1517,7 @@ int AIPlayerBaka::Act(float dt) DebugTrace("Cannot interrupt"); return 0; } - if (clickstream.empty()) + if (clickstream.empty() && g->currentlyActing() == this)//computeActions only when i have priority computeActions(); if (clickstream.empty()) { diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index b43210d1f..07f4d8deb 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -772,6 +772,19 @@ int ActionStack::count(int type, int state, int display) } return result; } +int ActionStack::getActionElementFromCard(MTGCardInstance * card) +{ + +for (int i = 0; i < mCount; i++) + { + Interruptible * current = (Interruptible *) mObjects[i]; + if (current->source == card) + { + return i; + } + } +return NULL; +} Interruptible * ActionStack::getNext(Interruptible * previous, int type, int state, int display) { diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index bd8e9e0d5..338154c6d 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -4,9 +4,9 @@ //Activated Abilities //Generic Activated Abilities -GenericActivatedAbility::GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap, +GenericActivatedAbility::GenericActivatedAbility(string newName,int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap, string limit, int restrictions, MTGGameZone * dest) : - ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), limit(limit), activeZone(dest) + ActivatedAbility(_id, card, _cost, restrictions, _tap,limit), NestedAbility(a), activeZone(dest),newName(newName) { counters = 0; target = ability->target; @@ -14,7 +14,6 @@ GenericActivatedAbility::GenericActivatedAbility(int _id, MTGCardInstance * card int GenericActivatedAbility::resolve() { - counters++; ManaCost * diff = abilityCost->Diff(cost); source->X = diff->hasX(); source->XX = source->X/2; @@ -28,6 +27,8 @@ int GenericActivatedAbility::resolve() const char * GenericActivatedAbility::getMenuText() { +if(newName.size()) +return newName.c_str(); if (ability) return ability->getMenuText(); return "Error"; @@ -37,24 +38,11 @@ int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost { if (dynamic_cast (ability) && !card->isMorphed && !card->morphed && card->turningOver) return 0; - limitPerTurn = 0; - if(limit.size()) - { - WParsedInt * value = NEW WParsedInt(limit.c_str(),NULL,source); - limitPerTurn = value->getValue(); - delete value; - } - if (limitPerTurn && counters >= limitPerTurn) - return 0; return ActivatedAbility::isReactingToClick(card, mana); } void GenericActivatedAbility::Update(float dt) { - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT) - { - counters = 0; - } ActivatedAbility::Update(dt); } @@ -486,15 +474,12 @@ int AAFizzler::resolve() if(!target && !_target) { //if we hit this condiational its because Ai was targetting. - target = source->target; - Interruptible * laststackitem = game->mLayers->stackLayer()->getAt(-2); - //fizzle the spell that was played directly before this counterspell - //ai will tend to respond to you extremely quick. - if (laststackitem && laststackitem->type == ACTION_SPELL) - { - Spell * spell = (Spell*) laststackitem; - _target = spell; - } + Interruptible * targetCard = game->mLayers->stackLayer()->getAt(game->mLayers->stackLayer()->getActionElementFromCard(source->target)); + if (source->target && source->target->has(Constants::NOFIZZLE)) + return 0; + _target = (Spell *) targetCard; + game->mLayers->stackLayer()->Fizzle(_target); + return 1; } if (target && _target->source->has(Constants::NOFIZZLE)) return 0; @@ -1065,7 +1050,12 @@ int AADynamic::resolve() { while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next) _target = ((MTGCardInstance *)_target)->next; - + if(sourceamount < 0) + sourceamount = 0; + if(targetamount < 0) + targetamount = 0; + //set values less then 0 to 0, it was reported that negitive numbers such as a creature who get -3/-3 having the power become + //negitive, if then used as the amount, would cuase weird side effects on resolves. switch(effect) { case 0://deal damage @@ -1469,8 +1459,6 @@ AACloner::~AACloner() { } - - // Cast/Play Restriction modifier ACastRestriction::ACastRestriction(int _id, MTGCardInstance * card, Targetable * _target, TargetChooser * _restrictionsScope, WParsedInt * _value, bool _modifyExisting, int _zoneId, int who) : AbilityTP(_id, card, _target, who), restrictionsScope(_restrictionsScope), value(_value), modifyExisting(_modifyExisting),zoneId(_zoneId) @@ -2012,9 +2000,9 @@ MultiAbility::~MultiAbility() } //Generic Target Ability -GenericTargetAbility::GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, +GenericTargetAbility::GenericTargetAbility(string newName,int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a, ManaCost * _cost, int _tap, string limit, int restrictions, MTGGameZone * dest) : - TargetAbility(_id, _source, _tc, _cost, restrictions, _tap), limit(limit), activeZone(dest) + TargetAbility(_id, _source, _tc, _cost, restrictions, _tap), limit(limit), activeZone(dest),newName(newName) { ability = a; MTGAbility * core = AbilityFactory::getCoreAbility(a); @@ -2027,6 +2015,8 @@ const char * GenericTargetAbility::getMenuText() { if (!ability) return "Error"; + if (newName.size()) + return newName.c_str(); MTGAbility * core = AbilityFactory::getCoreAbility(ability); if (AAMover * move = dynamic_cast(core)) @@ -2229,16 +2219,23 @@ AAlterCost::~AAlterCost() } // ATransformer -ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector newAbilitiesList,bool newAbilityFound) : - MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound) +ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector newAbilitiesList,bool newAbilityFound,bool aForever) : + MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever) { PopulateAbilityIndexVector(abilities, sabilities); PopulateColorIndexVector(colors, sabilities); - + + addNewColors = false; + if(sabilities.find("newcolors") != string::npos) + addNewColors = true; + //this subkeyword adds a color without removing the existing colors. remove = false; if (stypes == "removesubtypes") remove = true; + removeTypes = false; + if (stypes == "removetypes") + removeTypes = true; if (stypes == "allsubtypes" || stypes == "removesubtypes") { for (int i = Subtypes::LAST_TYPE + 1;; i++) @@ -2272,7 +2269,20 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t int ATransformer::addToGame() { - MTGCardInstance * _target = (MTGCardInstance *) target; + MTGCardInstance * _target = NULL; + Interruptible * action = (Interruptible *) target; + if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED) + { + Spell * spell = (Spell *) action; + _target = spell->source; + aForever = true; + //when targeting the stack, set the effect to forever, incase the person does not use it + //otherwise we will end up with a null pointer on the destroy. + } + else + { + _target = (MTGCardInstance *) target; + } if (_target) { while (_target->next) @@ -2297,18 +2307,43 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t list::iterator it; for (it = colors.begin(); it != colors.end(); it++) { - _target->setColor(0, 1); + if(!addNewColors) + _target->setColor(0, 1); } for (it = types.begin(); it != types.end(); it++) { - if (remove ) + if (removeTypes) + { + //remove the main types from a card, ie: hidden enchantment cycle. + _target->removeType(0,1); + _target->removeType(1,1); + _target->removeType(2,1); + _target->removeType(3,1); + _target->removeType(4,1); + _target->removeType(5,1); + _target->removeType(6,1); + _target->removeType(7,1); + } + if (remove) { _target->removeType(*it); } else { - _target->addType(*it); + if(_target->hasSubtype(*it)) + { + //we generally don't want to give a creature type creature again + //all it does is create a sloppy mess of the subtype line on alternative quads + //also creates instances where a card gained a type from an ability like this one + //then loses the type through another ability, when this effect is destroyed the creature regains + //the type, which is wrong. + dontremove.push_back(*it); + } + else + { + _target->addType(*it); + } } } for (it = colors.begin(); it != colors.end(); it++) @@ -2372,15 +2407,17 @@ ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * t oldtoughness = _target->toughness; _target->addToToughness(val->getValue()); _target->addToToughness(-oldtoughness); + _target->life = _target->toughness; delete val; } - } return MTGAbility::addToGame(); } int ATransformer::destroy() { + if(aForever) + return 0; MTGCardInstance * _target = (MTGCardInstance *) target; if (_target) { @@ -2389,8 +2426,18 @@ int ATransformer::destroy() list::iterator it; for (it = types.begin(); it != types.end(); it++) { - if (remove == false) - _target->removeType(*it); + if (!remove) + { + bool removing = true; + for(unsigned int k = 0;k < dontremove.size();k++) + { + if(dontremove[k] == *it) + removing = false; + } + if(removing) + _target->removeType(*it); + } + //iterators annoy me :/ } for (it = colors.begin(); it != colors.end(); it++) { @@ -2404,7 +2451,7 @@ int ATransformer::destroy() { _target->setColor(*it); } - if (remove ) + if (remove) { for (it = oldtypes.begin(); it != oldtypes.end(); it++) { @@ -2453,196 +2500,35 @@ ATransformer::~ATransformer() { } -// AForeverTransformer -AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, - string sabilities,string newpower,bool newpowerfound, string newtoughness,bool newtoughnessfound,vector newAbilitiesList,bool newAbilityFound) : - MTGAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound) +//ATransformerInstant +ATransformerInstant::ATransformerInstant(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vectornewAbilitiesList,bool newAbilityFound,bool aForever) : + InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever) { - aType = MTGAbility::STANDARD_BECOMES; - - PopulateAbilityIndexVector(abilities, sabilities); - PopulateColorIndexVector(colors, sabilities); - PopulateSubtypesIndexVector(types, stypes); - menu = stypes; - - remove = false; - if (stypes == "removetypes") - remove = true; -} - -int AForeverTransformer::addToGame() -{ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (_target) - { - while (_target->next) - _target = _target->next; - list::iterator it; - for (it = colors.begin(); it != colors.end(); it++) - { - _target->setColor(0, 1); - } - for (it = types.begin(); it != types.end(); it++) - { - if(remove) - { - _target->removeType(0,1); - _target->removeType(1,1); - _target->removeType(2,1); - _target->removeType(3,1); - _target->removeType(4,1); - _target->removeType(5,1); - _target->removeType(6,1); - _target->removeType(7,1); - } - else - _target->addType(*it); - } - for (it = colors.begin(); it != colors.end(); it++) - { - _target->setColor(*it); - } - for (it = abilities.begin(); it != abilities.end(); it++) - { - _target->basicAbilities[*it]++; - } - if (newAbilityFound) - { - for (unsigned int k = 0 ; k < newAbilitiesList.size();k++) - { - AbilityFactory af; - MTGAbility * aNew = af.parseMagicLine(newAbilitiesList[k], 0, NULL, _target); - aNew->isClone = 1; - - GenericTargetAbility * gta = dynamic_cast (aNew); - if (gta) - { - ((GenericTargetAbility *)aNew)->source = _target; - ((GenericTargetAbility *)aNew)->ability->source = _target; - } - GenericActivatedAbility * gaa = dynamic_cast (aNew); - if (gaa) - { - ((GenericActivatedAbility *)aNew)->source = _target; - ((GenericActivatedAbility *)aNew)->ability->source = _target; - } - if (MultiAbility * abi = dynamic_cast(aNew)) - { - ((MultiAbility *)aNew)->source = _target; - ((MultiAbility *)aNew)->abilities[0]->source = _target; - } - aNew->target = _target; - aNew->source = (MTGCardInstance *) _target; - if(aNew->oneShot) - { - aNew->resolve(); - delete aNew; - } - else - aNew->addToGame(); - newAbilities[_target].push_back(aNew); - } - } - if(newpowerfound ) - { - WParsedInt * val = NEW WParsedInt(newpower,NULL, source); - oldpower = _target->power -= oldpower; - _target->power += val->getValue(); - _target->power -= oldpower; - delete val; - } - if(newtoughnessfound ) - { - WParsedInt * val = NEW WParsedInt(newtoughness,NULL, source); - oldtoughness = _target->toughness; - _target->addToToughness(val->getValue()); - _target->addToToughness(-oldtoughness); - delete val; - } - } - return MTGAbility::addToGame(); -} - -const char * AForeverTransformer::getMenuText() -{ - string s = menu; - sprintf(menuText, "Becomes %s", s.c_str()); - return menuText; -} - -AForeverTransformer * AForeverTransformer::clone() const -{ - AForeverTransformer * a = NEW AForeverTransformer(*this); - a->isClone = 1; - return a; -} -AForeverTransformer::~AForeverTransformer() -{ -} - -//ATransformerUEOT -ATransformerUEOT::ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vectornewAbilitiesList,bool newAbilityFound) : - InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound) -{ - ability = NEW ATransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound); + ability = NEW ATransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,aForever); aType = MTGAbility::STANDARD_BECOMES; } -int ATransformerUEOT::resolve() +int ATransformerInstant::resolve() { ATransformer * a = ability->clone(); GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a); wrapper->addToGame(); return 1; } -const char * ATransformerUEOT::getMenuText() +const char * ATransformerInstant::getMenuText() { return ability->getMenuText(); } -ATransformerUEOT * ATransformerUEOT::clone() const +ATransformerInstant * ATransformerInstant::clone() const { - ATransformerUEOT * a = NEW ATransformerUEOT(*this); + ATransformerInstant * a = NEW ATransformerInstant(*this); a->ability = this->ability->clone(); a->isClone = 1; return a; } -ATransformerUEOT::~ATransformerUEOT() -{ - SAFE_DELETE(ability); -} - -// ATransformerFOREVER -ATransformerFOREVER::ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vectornewAbilitiesList,bool newAbilityFound) : - InstantAbility(id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound) -{ - ability = NEW AForeverTransformer(id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound); - aType = MTGAbility::STANDARD_BECOMES; -} - -int ATransformerFOREVER::resolve() -{ - AForeverTransformer * a = ability->clone(); - GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a); - wrapper->addToGame(); - return 1; -} - -const char * ATransformerFOREVER::getMenuText() -{ - return ability->getMenuText(); -} - -ATransformerFOREVER * ATransformerFOREVER::clone() const -{ - ATransformerFOREVER * a = NEW ATransformerFOREVER(*this); - a->ability = this->ability->clone(); - a->isClone = 1; - return a; -} - -ATransformerFOREVER::~ATransformerFOREVER() +ATransformerInstant::~ATransformerInstant() { SAFE_DELETE(ability); } @@ -2680,122 +2566,6 @@ ASwapPTUEOT::~ASwapPTUEOT() SAFE_DELETE(ability); } -// ABecomes -ABecomes::ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, WParsedPT * wppt, string sabilities) : - MTGAbility(id, source, target), wppt(wppt) -{ - - aType = MTGAbility::STANDARD_BECOMES; - - PopulateAbilityIndexVector(abilities, sabilities); - PopulateColorIndexVector(colors, sabilities); - PopulateSubtypesIndexVector(types, stypes); - menu = stypes; - -} -int ABecomes::addToGame() -{ - MTGCardInstance * _target = (MTGCardInstance *) target; - list::iterator it; - for (it = types.begin(); it != types.end(); it++) - { - _target->addType(*it); - } - for (it = colors.begin(); it != colors.end(); it++) - { - _target->setColor(*it); - } - for (it = abilities.begin(); it != abilities.end(); it++) - { - _target->basicAbilities[*it]++; - } - - if (wppt) - { - _target->power = wppt->power.getValue(); - _target->toughness = wppt->toughness.getValue(); - _target->life = _target->toughness; - } - return MTGAbility::addToGame(); -} - -int ABecomes::destroy() -{ - MTGCardInstance * _target = (MTGCardInstance *) target; - list::iterator it; - for (it = types.begin(); it != types.end(); it++) - { - _target->removeType(*it); - } - for (it = colors.begin(); it != colors.end(); it++) - { - _target->removeColor(*it); - } - for (it = abilities.begin(); it != abilities.end(); it++) - { - _target->basicAbilities[*it]--; - } - return 1; -} - -const char * ABecomes::getMenuText() -{ - string s = menu; - sprintf(menuText, "Becomes %s", s.c_str()); - return menuText; -} - -ABecomes * ABecomes::clone() const -{ - ABecomes * a = NEW ABecomes(*this); - if (a->wppt) - a->wppt = NEW WParsedPT(*(a->wppt)); - a->isClone = 1; - return a; -} - -ABecomes::~ABecomes() -{ - SAFE_DELETE (wppt); -} - -// ABecomes - -// ABecomesUEOT -ABecomesUEOT::ABecomesUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, WParsedPT * wpt, - string abilities) : - InstantAbility(id, source, target) -{ - ability = NEW ABecomes(id, source, target, types, wpt, abilities); - aType = MTGAbility::STANDARD_BECOMES; -} - -int ABecomesUEOT::resolve() -{ - ABecomes * a = ability->clone(); - GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a); - wrapper->addToGame(); - return 1; -} - -const char * ABecomesUEOT::getMenuText() -{ - return ability->getMenuText(); -} - -ABecomesUEOT * ABecomesUEOT::clone() const -{ - ABecomesUEOT * a = NEW ABecomesUEOT(*this); - a->ability = this->ability->clone(); - a->isClone = 1; - return a; -} - -ABecomesUEOT::~ABecomesUEOT() -{ - SAFE_DELETE(ability); -} - //APreventDamageTypes APreventDamageTypes::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) : MTGAbility(id, source), to(to), from(from), type(type) diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index e20a87542..9f1cde3a0 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -246,7 +246,6 @@ void CardGui::Render() mFont->SetScale(1); } } - if (tc && !tc->canTarget(card)) { if (!shadow) diff --git a/projects/mtg/src/CardPrimitive.cpp b/projects/mtg/src/CardPrimitive.cpp index c796c9d1a..429d7b8fa 100644 --- a/projects/mtg/src/CardPrimitive.cpp +++ b/projects/mtg/src/CardPrimitive.cpp @@ -23,6 +23,8 @@ CardPrimitive::CardPrimitive(CardPrimitive * source) for (int i = 0; i < Constants::MTG_NB_COLORS; ++i) colors[i] = source->colors[i]; manaCost.copy(source->getManaCost()); + if(source->getManaCost()->alternative) + manaCost.alternative->alternativeName = source->getManaCost()->alternative->alternativeName; text = source->text; setName(source->name); @@ -87,13 +89,13 @@ bool CardPrimitive::isSpell() return (!isCreature() && !isLand()); } -void CardPrimitive::setRestrictions(int _restriction) +void CardPrimitive::setRestrictions(string _restriction) { restriction = _restriction; } -int CardPrimitive::getRestrictions() +void CardPrimitive::getRestrictions() { - return restriction; + restriction; } void CardPrimitive::setOtherRestrictions(string _restriction) diff --git a/projects/mtg/src/DuelLayers.cpp b/projects/mtg/src/DuelLayers.cpp index 53bda5207..a0a4aa2e9 100644 --- a/projects/mtg/src/DuelLayers.cpp +++ b/projects/mtg/src/DuelLayers.cpp @@ -23,6 +23,7 @@ void DuelLayers::init() action = NEW ActionLayer(); action->Add(NEW MTGGamePhase(action->getMaxId())); //Add Magic Specific Rules + action->Add(NEW MTGEventBonus(-1)); action->Add(NEW MTGPutInPlayRule(-1)); action->Add(NEW MTGAlternativeCostRule(-1)); action->Add(NEW MTGBuyBackRule(-1)); diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index ceb095ac1..8aeddace8 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -87,7 +87,44 @@ int LifeCost::doPay() tc->initTargets(); return 1; } +//life or Mana cost +LifeorManaCost * LifeorManaCost::clone() const +{ + LifeorManaCost * ec = NEW LifeorManaCost(*this); + if (tc) + ec->tc = tc->clone(); + return ec; +} +LifeorManaCost::LifeorManaCost(TargetChooser *_tc,string manaType) : + ExtraCost("Phyrexian Mana", _tc),manaType(manaType) +{ +} + +int LifeorManaCost::doPay() +{ + if (!target) + return 0; + + MTGCardInstance * _target = (MTGCardInstance *) target; + string buildType ="{"; + buildType.append(manaType); + buildType.append("}"); + ManaCost * newCost = ManaCost::parseManaCost(buildType); + if(_target->controller()->getManaPool()->canAfford(newCost)) + { + _target->controller()->getManaPool()->pay(newCost); + } + else + { + _target->controller()->loseLife(2); + } + SAFE_DELETE(newCost); + target = NULL; + if (tc) + tc->initTargets(); + return 1; +} //discard a card at random as a cost //DiscardRandom cost DiscardRandomCost * DiscardRandomCost::clone() const diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 501d622ae..0843979d8 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -22,165 +22,189 @@ const string kMaxCastKeywords[] = { "maxplay(", "maxcast("}; const int kMaxCastZones[] = { MTGGameZone::BATTLEFIELD, MTGGameZone::STACK}; const size_t kMaxCastKeywordsCount = 2; -int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player) +int MTGAbility::parseCastRestrictions(MTGCardInstance * card,Player * player,string restrictions,string otherRestrictions) { + restrictions.append(otherRestrictions); + //we can do this becuase the function calls send them seperately, so one will always be empty + vector restriction = split(restrictions, ','); + AbilityFactory af; int cPhase = game->getCurrentGamePhase(); - int restrictions = 0; - restrictions = card->getRestrictions(); - - int vamps = 0; - int playercreatures = 0; - int opponentcreatures = 0; - - switch (restrictions) + for(unsigned int i = 0;i < restriction.size();i++) { - case PLAYER_TURN_ONLY: - if (player != game->currentPlayer) - return 0; - break; - case OPPONENT_TURN_ONLY: - if (player == game->currentPlayer) - return 0; - break; - case AS_SORCERY: - if (player != game->currentPlayer) - return 0; - if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN) - return 0; - break; - case VAMPIRES: - vamps = player->game->inPlay->countByType("vampire"); - if(vamps < 2) - return 0; - break; - case LESS_CREATURES: + int checkPhaseBased = af.parseRestriction(restriction[i]); + switch (checkPhaseBased) + { + case PLAYER_TURN_ONLY: + if (player != game->currentPlayer) + return 0; + break; + case OPPONENT_TURN_ONLY: + if (player == game->currentPlayer) + return 0; + break; + case AS_SORCERY: + if (player != game->currentPlayer) + return 0; + if (cPhase != Constants::MTG_PHASE_FIRSTMAIN && cPhase != Constants::MTG_PHASE_SECONDMAIN) + return 0; + break; + } + if (checkPhaseBased >= MY_BEFORE_BEGIN && checkPhaseBased <= MY_AFTER_EOT) + { + if (player != game->currentPlayer) + return 0; + if (cPhase != checkPhaseBased - MY_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + if (checkPhaseBased >= OPPONENT_BEFORE_BEGIN && checkPhaseBased <= OPPONENT_AFTER_EOT) + { + if (player == game->currentPlayer) + return 0; + if (cPhase != checkPhaseBased - OPPONENT_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + if (checkPhaseBased >= BEFORE_BEGIN && checkPhaseBased <= AFTER_EOT) + { + if (cPhase != checkPhaseBased - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) + return 0; + } + size_t typeRelated = restriction[i].find("typemin:"); + size_t check = NULL; + if(typeRelated != string::npos) + { + bool less = false; + bool more = false; + int mytypemin = 0; + int opponenttypemin = 0; + int min = 0; + int opponentmin = 0; + string type = "*"; + string opponenttype = "*"; - playercreatures = player->game->inPlay->countByType("creature"); - opponentcreatures = player->opponent()->game->inPlay->countByType("creature"); - if(playercreatures > opponentcreatures) - return 0; - break; - case SNOW_LAND_INPLAY: - if(!player->game->inPlay->hasPrimaryType("snow","land")) - return 0; - break; - case CASTED_A_SPELL: - if(player->game->stack->seenThisTurn("*", Constants::CAST_ALL) < 1) - return 0; - break; - case ONE_OF_AKIND: - if(player->game->inPlay->hasName(card->name)) - return 0; - break; - case FOURTHTURN: - if(game->turn <= 7) - return 0; - break; - case BEFORECOMBATDAMAGE: - if(cPhase > Constants::MTG_PHASE_COMBATBLOCKERS) - return 0; - break; - case AFTERCOMBAT: - if(cPhase < Constants::MTG_PHASE_COMBATBLOCKERS) - return 0; - break; - case DURINGCOMBAT: - if(cPhase < Constants::MTG_PHASE_COMBATBEGIN ||cPhase > Constants::MTG_PHASE_COMBATEND ) - return 0; - break; - } + check = restriction[i].find("mytypemin:"); + if( check != string::npos) + { + size_t start = restriction[i].find(":", check); + size_t end = restriction[i].find(" ", check); + size_t lesser = restriction[i].find(":less",check); + size_t morer = restriction[i].find(":more",check); + if(lesser != string::npos) + { + less = true; + } + else if(morer != string::npos) + { + more = true; + } + else + { + min = atoi(restriction[i].substr(start + 1, end - start - 1).c_str()); + } + size_t found = restriction[i].find("type("); + if (found != string::npos) + { + end = restriction[i].find(")", found); + type = restriction[i].substr(found + 5, end - found - 5).c_str(); + } + mytypemin = card->controller()->game->inPlay->countByType(type.c_str()); + if(mytypemin < min && less == false && more == false) + return 0; + } + check = restriction[i].find("opponenttypemin:"); + if( check != string::npos) + { + size_t start = restriction[i].find(":", check); + size_t end = restriction[i].find(" ", check); + opponentmin = atoi(restriction[i].substr(start + 1, end - start - 1).c_str()); - if (restrictions >= MY_BEFORE_BEGIN && restrictions <= MY_AFTER_EOT) - { - if (player != game->currentPlayer) - return 0; - if (cPhase != restrictions - MY_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) - return 0; - } - - if (restrictions >= OPPONENT_BEFORE_BEGIN && restrictions <= OPPONENT_AFTER_EOT) - { - if (player == game->currentPlayer) - return 0; - if (cPhase != restrictions - OPPONENT_BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) - return 0; - } - - if (restrictions >= BEFORE_BEGIN && restrictions <= AFTER_EOT) - { - if (cPhase != restrictions - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) - return 0; + size_t found = restriction[i].find("opponenttype("); + if (found != string::npos) + { + end = restriction[i].find(")", found); + opponenttype = restriction[i].substr(found + 13, end - found - 13).c_str(); + } + opponenttypemin = card->controller()->opponent()->game->inPlay->countByType(opponenttype.c_str()); + if(opponenttypemin < opponentmin && less == false && more == false) + return 0; + } + if(less && more == false && opponenttypemin <= mytypemin) + return 0; + if(less == false && more && opponenttypemin >= mytypemin) + return 0; + } + check = restriction[i].find("turn:"); + if(check != string::npos) + { + int Turn = 0; + size_t start = restriction[i].find(":", check); + size_t end = restriction[i].find(" ", check); + Turn = atoi(restriction[i].substr(start + 1, end - start - 1).c_str()); + if(game->turn < Turn) + return 0; + } + check = restriction[i].find("casted a spell"); + if(check != string::npos) + { + if(player->game->stack->seenThisTurn("*", Constants::CAST_ALL) < 1) + return 0; + } + check = restriction[i].find("one of a kind"); + if(check != string::npos) + { + if(player->game->inPlay->hasName(card->name)) + return 0; + } + check = restriction[i].find("before battle damage"); + if(check != string::npos) + { + if(cPhase > Constants::MTG_PHASE_COMBATBLOCKERS) + return 0; + } + check = restriction[i].find("after battle"); + if(check != string::npos) + { + if(cPhase < Constants::MTG_PHASE_COMBATBLOCKERS) + return 0; + } + check = restriction[i].find("during battle"); + if(check != string::npos) + { + if(cPhase < Constants::MTG_PHASE_COMBATBEGIN ||cPhase > Constants::MTG_PHASE_COMBATEND ) + return 0; + } + check = restriction[i].find("control snow land"); + if(check != string::npos) + { + if(!player->game->inPlay->hasPrimaryType("snow","land")) + return 0; + } + check = restriction[i].find("control two or more vampires"); + if(check != string::npos) + { + restriction.push_back("mytypemin:2 type(vampire)"); + } + check = restriction[i].find("control less creatures"); + if(check != string::npos) + { + restriction.push_back("mytypemin:less type(creature)"); + } + check = restriction[i].find("fourth turn"); + if(check != string::npos) + { + restriction.push_back("turn:4"); + } } return 1; } +int MTGAbility::allowedToCast(MTGCardInstance * card,Player * player) +{ + return parseCastRestrictions(card,player,card->restriction,""); +} + int MTGAbility::allowedToAltCast(MTGCardInstance * card,Player * player) { - int cPhase = game->getCurrentGamePhase(); - string restrictions = ""; - restrictions = card->otherrestriction; - static bool less = false; - static bool more = false; - int mytypemin = 0; - int opponenttypemin = 0; - int min = 0; - int opponentmin = 0; - string type = "*"; - string opponenttype = "*"; - - size_t check = restrictions.find("mytypemin:"); - if( check != string::npos) - { - size_t start = restrictions.find(":", check); - size_t end = restrictions.find(" ", check); - size_t lesser = restrictions.find(":less",check); - size_t morer = restrictions.find(":more",check); - if(lesser != string::npos) - { - less = true; - } - else if(morer != string::npos) - { - more = true; - } - else - { - min = atoi(restrictions.substr(start + 1, end - start - 1).c_str()); - } - - - size_t found = restrictions.find("type("); - if (found != string::npos) - { - end = restrictions.find(")", found); - type = restrictions.substr(found + 5, end - found - 5).c_str(); - } - mytypemin = card->controller()->game->inPlay->countByType(type.c_str()); - if(mytypemin < min && less == false && more == false) - return 0; - } - check = restrictions.find("opponenttypemin:"); - if( check != string::npos) - { - size_t start = restrictions.find(":", check); - size_t end = restrictions.find(" ", check); - opponentmin = atoi(restrictions.substr(start + 1, end - start - 1).c_str()); - - size_t found = restrictions.find("opponenttype("); - if (found != string::npos) - { - end = restrictions.find(")", found); - opponenttype = restrictions.substr(found + 13, end - found - 13).c_str(); - } - opponenttypemin = card->controller()->opponent()->game->inPlay->countByType(opponenttype.c_str()); - if(opponenttypemin < opponentmin && less == false && more == false) - return 0; - } - if(less && more == false && opponenttypemin <= mytypemin) - return 0; - if(less == false && more && opponenttypemin >= mytypemin) - return 0; - return 1; + return parseCastRestrictions(card,player,"",card->otherrestriction); } int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option) @@ -447,89 +471,61 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int return NEW TrCardTappedformana(id, card, tc, true); } - - //Card is attacking - found = s.find("attacking("); - if (found != string::npos) - { - size_t end = s.find(")"); - string starget = s.substr(found + 10, end - found - 10); - TargetChooserFactory tcf; - TargetChooser *tc = tcf.createTargetChooser(starget, card); - tc->targetter = NULL; - - return NEW TrCardAttacked(id, card, tc,sourceUntapped,opponentPoisoned); - } - //Card is attacking alone - found = s.find("attackedalone("); - if (found != string::npos) - { - size_t end = s.find(")"); - string starget = s.substr(found + 14, end - found - 14); - TargetChooserFactory tcf; - TargetChooser *tc = tcf.createTargetChooser(starget, card); - tc->targetter = NULL; - - return NEW TrCardAttackedAlone(id, card, tc); - } - - //Card card attacked and is not blocked - found = s.find("notblocked("); - if (found != string::npos) - { - size_t end = s.find(")"); - string starget = s.substr(found + 11, end - found - 11); - TargetChooserFactory tcf; - TargetChooser *tc = tcf.createTargetChooser(starget, card); - tc->targetter = NULL; - - return NEW TrCardAttackedNotBlocked(id, card, tc); - } - + +//CombatTrigger //Card card attacked and is blocked - found = s.find("blocked("); + found = s.find("combat("); if (found != string::npos) { - size_t end = s.find(")"); - string starget = s.substr(found + 8, end - found - 8); - TargetChooserFactory tcf; - TargetChooser *tc = tcf.createTargetChooser(starget, card); - tc->targetter = NULL; - found = s.find("from("); - + size_t end = s.find(")",found); + string combatTrigger = s.substr(found + 7, end - found - 7); + //find combat traits, only trigger types, the general restrictions are found earlier. + bool attackingTrigger = false; + bool attackedAloneTrigger = false; + bool notBlockedTrigger = false; + bool attackBlockedTrigger = false; + bool blockingTrigger = false; + vector combatTriggerVector = split(combatTrigger, ','); + for (unsigned int i = 0 ; i < combatTriggerVector.size() ; i++) + { + if(combatTriggerVector[i] == "attacking") + attackingTrigger = true; + if(combatTriggerVector[i] == "attackedalone") + attackedAloneTrigger = true; + if(combatTriggerVector[i] == "notblocked") + notBlockedTrigger = true; + if(combatTriggerVector[i] == "blocked") + attackBlockedTrigger = true; + if(combatTriggerVector[i] == "blocking") + blockingTrigger = true; + } + //build triggers TCs + TargetChooser *tc = NULL; TargetChooser *fromTc = NULL; - if (found != string::npos) + TargetChooserFactory tcf; + string starget; + string ftarget; + size_t sourceCard = s.find("source("); + if (sourceCard != string::npos) { - end = s.find(")", found); - starget = s.substr(found + 5, end - found - 5); - fromTc = tcf.createTargetChooser(starget, card); + size_t sEnd = s.find(")",sourceCard); + starget = s.substr(sourceCard + 7, sEnd - sourceCard - 7); + tc = tcf.createTargetChooser(starget, card); + tc->targetter = NULL; + } + size_t From = s.find("from("); + if (From != string::npos) + { + size_t fromEnd = s.find(")", From); + ftarget = s.substr(From + 5, fromEnd - From - 5); + fromTc = tcf.createTargetChooser(ftarget, card); fromTc->targetter = NULL; } - - return NEW TrCardAttackedBlocked(id, card, tc, fromTc,limitOnceATurn); - } - - //Card card is a blocker - found = s.find("blocking("); - if (found != string::npos) - { - size_t end = s.find(")"); - string starget = s.substr(found + 9, end - found - 9); - TargetChooserFactory tcf; - TargetChooser *tc = tcf.createTargetChooser(starget, card); - tc->targetter = NULL; - found = s.find("from("); - - TargetChooser *fromTc = NULL; - if (found != string::npos) - { - end = s.find(")", found); - starget = s.substr(found + 5, end - found - 5); - fromTc = tcf.createTargetChooser(starget, card); - fromTc->targetter = NULL; - } - - return NEW TrCardBlocked(id, card, tc, fromTc,once,limitOnceATurn); + if(tc)//a source( is required, from( is optional. + return NEW TrCombatTrigger(id, card, tc, fromTc,once,limitOnceATurn,sourceUntapped,opponentPoisoned, + attackingTrigger,attackedAloneTrigger,notBlockedTrigger,attackBlockedTrigger,blockingTrigger); + else + return NULL; } //Card card is drawn @@ -884,6 +880,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG TargetChooser * tc = NULL; string sWithoutTc = s; + string newName = ""; + found = sWithoutTc.find("name("); + if (found != string::npos) + { + size_t end = sWithoutTc.find(")", found); + newName = sWithoutTc.substr(found + 5, end - found - 5); + } //Target Abilities found = s.find("target("); if (found != string::npos) @@ -950,8 +953,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return ae; } if (tc) - return NEW GenericTargetAbility(id, card, tc, a, cost, doTap, limit, restrictions, dest); - return NEW GenericActivatedAbility(id, card, a, cost, doTap, limit, restrictions, dest); + return NEW GenericTargetAbility(newName,id, card, tc, a, cost, doTap, limit, restrictions, dest); + return NEW GenericActivatedAbility(newName,id, card, a, cost, doTap, limit, restrictions, dest); } SAFE_DELETE(cost); } @@ -1011,11 +1014,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return NULL; if (tc) - a1 = NEW GenericTargetAbility(id, card, tc, a1); + a1 = NEW GenericTargetAbility(newName,id, card, tc, a1); else - a1 = NEW GenericActivatedAbility(id, card, a1, NULL); + a1 = NEW GenericActivatedAbility(newName,id, card, a1, NULL); return NEW MayAbility(id, a1, card); } + //When...comes into play, choose one... found = s.find("choice "); if (found == 0) @@ -1026,9 +1030,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return NULL; if (tc) - a1 = NEW GenericTargetAbility(id, card, tc, a1); + a1 = NEW GenericTargetAbility(newName,id, card, tc, a1); else - a1 = NEW GenericActivatedAbility(id, card, a1, NULL); + a1 = NEW GenericActivatedAbility(newName,id, card, a1, NULL); return NEW MayAbility(id, a1, card, true); } @@ -1386,7 +1390,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG DebugTrace("ABILITYFACTORY Error parsing: " << s); return NULL; } - a = NEW GenericTargetAbility(id, card, tc, a); + a = NEW GenericTargetAbility(newName,id, card, tc, a); return NEW MayAbility(id, a, card, true); } @@ -1831,18 +1835,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return tok; } - //name an ability line - found = s.find("name("); - if (found != string::npos) - { - size_t end = s.find(")", found); - string sname = s.substr(found + 5, end - found - 5); - - ANamer * tok = NEW ANamer(id, card, NULL, sname, 0); - return tok; - } -//living weapon - //Equipment found = s.find("equip"); if (found != string::npos) @@ -2298,15 +2290,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG Targetable * t = NULL; if (spell) t = spell->getNextTarget(); - if (!activated) + if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT) { - if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT) - { - return NEW AInstantCastRestrictionUEOT(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who); - } - return NEW ACastRestriction(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who); + return NEW AInstantCastRestrictionUEOT(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who); } - return NULL; //TODO NEW ACastRestrictionUntilEndOfTurn(id, card, t, value, modifyExisting, kMaxCastZones[i], who); + return NEW ACastRestriction(id, card, t, castTargets, value, modifyExisting, kMaxCastZones[i], who); + //TODO NEW ACastRestrictionUntilEndOfTurn(id, card, t, value, modifyExisting, kMaxCastZones[i], who); } } @@ -2437,6 +2426,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG string stypes = s.substr(found + 8, end - found - 8); WParsedPT * pt = NULL; string sabilities; + string newPower = ""; + string newToughness = ""; if (end != real_end) { int previous = end + 1; @@ -2444,27 +2435,41 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG if (end == string::npos) end = real_end; string temp = s.substr(previous, end - previous); - pt = NEW WParsedPT(temp, spell, card); - if (!pt->ok) + size_t seperator = temp.find("/"); + if(seperator != string::npos) + { + newPower = temp.substr(0,seperator); + newToughness = temp.substr(seperator + 1); + } + else { - SAFE_DELETE(pt); sabilities = temp; } } - if (pt && end != real_end) + if ((newPower.length() || newToughness.length()) && end != real_end) { sabilities = s.substr(end + 1, real_end - end - 1); } MTGAbility * ab; - if (forceUEOT) + bool foreverEffect = false; + if (forceFOREVER) { - ab = NEW ABecomesUEOT(id, card, target, stypes, pt, sabilities); + foreverEffect = true; + } + if (oneShot || forceUEOT) + { + ab = NEW ATransformerInstant(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector(),false,foreverEffect); + } + else if(foreverEffect) + { + ab = NEW ATransformerInstant(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector(),false,foreverEffect); } else { - ab = NEW ABecomes(id, card, target, stypes, pt, sabilities); + ab = NEW ATransformer(id, card, target, stypes, sabilities,newPower,true,newToughness,true,vector(),false,foreverEffect); } return ab; + } //bloodthirst @@ -2587,13 +2592,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG } } MTGAbility * a; + bool foreverEffect = false; if (forceFOREVER) { - a = NEW ATransformerFOREVER(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound); + foreverEffect = true; } - else if (forceUEOT) + if (oneShot || forceUEOT) { - a = NEW ATransformerUEOT(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound); + a = NEW ATransformerInstant(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,foreverEffect); + } + else if(foreverEffect) + { + a = NEW ATransformerInstant(id, card, target, stypes, sabilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,foreverEffect); } else { @@ -2604,15 +2614,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG //Change Power/Toughness WParsedPT * wppt = NEW WParsedPT(s, spell, card); + bool nonstatic = false; if (wppt->ok) { + if(s.find("nonstatic") != string::npos) + nonstatic = true; if (!activated) { if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT) { return NEW AInstantPowerToughnessModifierUntilEOT(id, card, target, wppt); } - return NEW APowerToughnessModifier(id, card, target, wppt); + return NEW APowerToughnessModifier(id, card, target, wppt,s,nonstatic); } return NEW APowerToughnessModifierUntilEndOfTurn(id, card, target, wppt); } @@ -2631,6 +2644,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG t = spell->getNextTarget(); MTGAbility * a = NEW AManaProducer(id, card, t, output, NULL, doTap, who); a->oneShot = 1; + if(newName.size()) + ((AManaProducer*)a)->menutext = newName; return a; } @@ -3941,9 +3956,10 @@ NestedAbility::NestedAbility(MTGAbility * _ability) // -ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions, int tap) : - MTGAbility(id, card), restrictions(restrictions), needsTapping(tap) +ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions, int tap,string limit) : + MTGAbility(id, card), restrictions(restrictions), needsTapping(tap),limit(limit) { + counters = 0; cost = _cost; abilityCost = 0; } @@ -3951,7 +3967,8 @@ ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _c int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { if(card->isPhased) - return 0; + return 0; + Player * player = game->currentlyActing(); int cPhase = game->getCurrentGamePhase(); switch (restrictions) @@ -3992,7 +4009,20 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (cPhase != restrictions - BEFORE_BEGIN + Constants::MTG_PHASE_BEFORE_BEGIN) return 0; } - + limitPerTurn = 0; + if(limit.size()) + { + WParsedInt * value = NEW WParsedInt(limit.c_str(),NULL,source); + limitPerTurn = value->getValue(); + delete value; + //only run this check if we have a valid limit string. + //limits on uses are based on when the ability is used, not when it is resolved + //incrementing of counters directly after the fireability() + //as ability limits are supposed to count the use regaurdless of the ability actually + //resolving. this check was previously located in genericactivated, and incrementing was handled in the resolve. + if (limitPerTurn && counters >= limitPerTurn) + return 0; + } if (card == source && source->controller() == player && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness()))) { @@ -4032,7 +4062,7 @@ int ActivatedAbility::reactToClick(MTGCardInstance * card) if (needsTapping && source->isInPlay()) source->tap(); fireAbility(); - + counters++; return 1; } diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index fd12c9015..55e4276fd 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -360,19 +360,19 @@ void MTGCardInstance::eventattackednotblocked() } //sets card as attacked and sends events -void MTGCardInstance::eventattackedblocked() +void MTGCardInstance::eventattackedblocked(MTGCardInstance * opponent) { didattacked = 1; - WEvent * e = NEW WEventCardAttackedBlocked(this); + WEvent * e = NEW WEventCardAttackedBlocked(this,opponent); GameObserver * game = GameObserver::GetInstance(); game->receiveEvent(e); } //sets card as blocking and sends events -void MTGCardInstance::eventblocked() +void MTGCardInstance::eventblocked(MTGCardInstance * opponent) { didblocked = 1; - WEvent * e = NEW WEventCardBlocked(this); + WEvent * e = NEW WEventCardBlocked(this,opponent); GameObserver * game = GameObserver::GetInstance(); game->receiveEvent(e); } @@ -439,10 +439,13 @@ int MTGCardInstance::triggerRegenerate() return 0; regenerateTokens--; tap(); - life = toughness; - initAttackersDefensers(); - if (life < 1) - return 0; //regeneration didn't work (wither ?) + if(isCreature()) + { + life = toughness; + initAttackersDefensers(); + if (life < 1) + return 0; //regeneration didn't work (wither ?) + } return 1; } @@ -452,7 +455,7 @@ int MTGCardInstance::initAttackersDefensers() setDefenser(NULL); banding = NULL; blockers.clear(); - blocked = false; + blocked = 0; didattacked = 0; didblocked = 0; return 1; @@ -1049,8 +1052,11 @@ JSample * MTGCardInstance::getSample() } } - string type = Subtypes::subtypesList->find(types[0]); - type = type + ".wav"; + string type = ""; + if(!types.size()) + return NULL; + type = Subtypes::subtypesList->find(types[0]); + type.append(".wav"); js = WResourceManager::Instance()->RetrieveSample(type); if (js) { diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 4ed2241a4..6746670ad 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -141,7 +141,6 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi { string value = val; primitive->setOtherRestrictions(value); - } else { @@ -150,6 +149,12 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi string value = val; std::transform(value.begin(), value.end(), value.begin(), ::tolower); cost->alternative = ManaCost::parseManaCost(value); + size_t name = value.find("name("); + if(name != string::npos) + { + size_t endName = value.find(")",name); + cost->alternative->alternativeName = value.substr(name + 5,endName - name - 5); + } } } break; @@ -222,55 +227,8 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi { if (!primitive) primitive = NEW CardPrimitive(); string value = val; - primitive->setRestrictions(CardPrimitive::NO_RESTRICTION); - primitive->hasRestriction = false; - if (value.find("control two or more vampires") != string::npos) - primitive->setRestrictions(CardPrimitive::VAMPIRES); - if (value.find("control less creatures") != string::npos) - primitive->setRestrictions(CardPrimitive::LESS_CREATURES); - if (value.find("control snow land") != string::npos) - primitive->setRestrictions(CardPrimitive::SNOW_LAND_INPLAY); - if (value.find("casted a spell") != string::npos) - primitive->setRestrictions(CardPrimitive::CASTED_A_SPELL); - if (value.find("one of a kind") != string::npos) - primitive->setRestrictions(CardPrimitive::ONE_OF_AKIND); - if (value.find("fourth turn") != string::npos) - primitive->setRestrictions(CardPrimitive::FOURTHTURN); - if (value.find("before battle damage") != string::npos) - primitive->setRestrictions(CardPrimitive::BEFORECOMBATDAMAGE); - if (value.find("after battle") != string::npos) - primitive->setRestrictions(CardPrimitive::AFTERCOMBAT); - if (value.find("during battle") != string::npos) - primitive->setRestrictions(CardPrimitive::DURINGCOMBAT); - if (value.find("myturnonly") != string::npos) - primitive->setRestrictions(CardPrimitive::PLAYER_TURN_ONLY); - if (value.find("opponentturnonly") != string::npos) - primitive->setRestrictions(CardPrimitive::OPPONENT_TURN_ONLY); - if (value.find("assorcery") != string::npos) - primitive->setRestrictions(CardPrimitive::AS_SORCERY); - string types[] = { "my", "opponent", "" }; - int starts[] = { CardPrimitive::MY_BEFORE_BEGIN, CardPrimitive::OPPONENT_BEFORE_BEGIN, CardPrimitive::BEFORE_BEGIN }; - for (int j = 0; j < 3; ++j) - { - size_t found = value.find(types[j]); - if (found != string::npos) - { - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - string toFind = types[j]; - toFind.append(Constants::MTGPhaseCodeNames[i]).append("only"); - found = value.find(toFind); - if (found != string::npos) - { - if(primitive->hasRestriction == false) - { - primitive->setRestrictions(starts[j] + i); - primitive->hasRestriction = true; - } - } - } - } - } + primitive->setRestrictions(value); + primitive->hasRestriction = true; } else if ('e' == key[1] && 't' == key[2]) { //retrace diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 6ed8bde1f..bf2cb2310 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -5,7 +5,284 @@ #include "Translate.h" #include "Subtypes.h" #include "GameOptions.h" +#include "Credits.h" +MTGEventBonus::MTGEventBonus(int _id) : +MTGAbility(_id,NULL) +{ + textAlpha = 0; + text = ""; + for(int i = 0;i < 2;i++) + { + chain[i] = 0; + highestChain[i] = 0; + //----------- + army[i] = 0; + army1[i] = false; + army2[i] = false; + army3[i] = false; + //-------- + + toybonusgranted[i] = false; + toys[i] = 0; + beastbonusgranted[i] = false; + beast[i] = 0; + zombiebonusgranted[i] = false; + zombie[i] = 0; + knightbonusgranted[i] = false; + knight[i] = 0; + insectbonusgranted[i] = false; + insect[i] = 0; + elementalbonusgranted[i] = false; + elemental[i] = 0; + vampirebonusgranted[i] = false; + vampire[i] = 0; + clericbonusgranted[i] = false; + cleric[i] = 0; + elfbonusgranted[i] = false; + elf[i] = 0; + Angelbonusgranted[i] = false; + Angel[i] = 0; + dragonbonusgranted[i] = false; + dragon[i] = 0; + + } +} +int MTGEventBonus::receiveEvent(WEvent * event) +{ + Player * player = game->currentlyActing(); + Player * currentPlayer = game->currentPlayer; + //bonus for chain chain casting without tapping for mana or being interupted; + //note gaining mana from other sources is still possible. + //only spells going to the stack are counted. + if (WEventCardTappedForMana* e = dynamic_cast(event)) + { + if(e) + { + if(chain[currentPlayer->getId()]/5 > 0) + { + text = "Chain Broken!"; + textAlpha = 255; + } + chain[currentPlayer->getId()] = 0; + } + } + if (event->type == WEvent::CHANGE_ZONE && !currentPlayer->isAI()) + { + WEventZoneChange * e = (WEventZoneChange *) event; + if (e->to == currentPlayer->game->stack) + { + chain[currentPlayer->getId()]++; + if(chain[currentPlayer->getId()] > highestChain[currentPlayer->getId()]) + highestChain[currentPlayer->getId()] = chain[currentPlayer->getId()]; + if(chain[currentPlayer->getId()] > 4) + { + + if(highestChain[currentPlayer->getId()] > 14) + { + char buffer3[20]; + sprintf(buffer3,"Killer!-Combo %i",chain[currentPlayer->getId()]); + grantAward(buffer3,100); + //increase the chains bonus by 100 for every card after playing a chain of 15 in a match. + //this is almost impossible would require superior draw and mana production. + } + else if(highestChain[currentPlayer->getId()] > 9) + { + char buffer2[30]; + sprintf(buffer2,"Abundant Resources-Combo %i",chain[currentPlayer->getId()]); + grantAward(buffer2,50); + //increase the chains bonus by 50 for every card after playing a chain of 10 in a match. + //this is extremely hard to do. would require a very well built deck an an abundence of mana + //to spend in a single go combined with decent card drawing. + } + else if(highestChain[currentPlayer->getId()] > 4) + { + char buffer[20]; + sprintf(buffer,"Chained-Combo %i",chain[currentPlayer->getId()]); + grantAward(buffer,chain[currentPlayer->getId()]); + //gain credits for every card played after you played a chain of 5 + //during the match. this would require a very decent hand to do + //and good mana production. + } + } + } + //end of chain bonuses + //========================== + //creatures entering play consecutively will allow you a chance + //to gain a bonus for maintaining force sizes, it will trigger every 10th + //creature which enters play consecutively. + if (e->to == currentPlayer->game->inPlay && !currentPlayer->isAI()) + { + if(e->card->hasType(Subtypes::TYPE_CREATURE)) + army[currentPlayer->getId()]++; + else + army[currentPlayer->getId()] = 0; + if(army[currentPlayer->getId()] > 9) + { + //this might seem easy at first glance, but you have to both maintain a high + //creature count, and triggers when 10 or more enter consecutively. if any thing else + //enters play the count is reset. + army[currentPlayer->getId()] = 0; + int forceSize = currentPlayer->inPlay()->countByType("creature"); + if(forceSize > 40 && !army3[currentPlayer->getId()]) + { + grantAward("Malignant Conqueror Bonus!",1000); + army3[currentPlayer->getId()] = true; + } + else if(forceSize > 19 && !army2[currentPlayer->getId()]) + { + grantAward("Extreme Infantry Bonus!",500); + army2[currentPlayer->getId()] = true; + } + else if(forceSize > 9 && !army1[currentPlayer->getId()]) + { + grantAward("Deadly Force Bonus!",250); + army1[currentPlayer->getId()] = true; + } + } + //////bonus for having a LOT of specific type. + //not else'd becuase it is possible for a card to contain + //more then one of the types, and for more then one to trigger. + if(e->card->hasType(Subtypes::TYPE_ARTIFACT)) + toys[currentPlayer->getId()]++; + if(e->card->isCreature()) + { + if(e->card->hasType("beast")) + beast[currentPlayer->getId()]++; + if(e->card->hasType("vampire")) + vampire[currentPlayer->getId()]++; + if(e->card->hasType("insect")) + insect[currentPlayer->getId()]++; + if(e->card->hasType("elemental")) + elemental[currentPlayer->getId()]++; + if(e->card->hasType("zombie")) + zombie[currentPlayer->getId()]++; + if(e->card->hasType("soldier")||e->card->hasType("knight")||e->card->hasType("warrior")) + knight[currentPlayer->getId()]++; + if(e->card->hasType("cleric")||e->card->hasType("shaman")||e->card->hasType("druid")) + cleric[currentPlayer->getId()]++; + if(e->card->hasType("elf")) + elf[currentPlayer->getId()]++; + if(e->card->hasType("angel")||e->card->hasType("spirit")) + Angel[currentPlayer->getId()]++; + if(e->card->hasType("dragon")||e->card->hasType("wurm")||e->card->hasType("drake")||e->card->hasType("snake")||e->card->hasType("hydra")) + dragon[currentPlayer->getId()]++; + } + if(toys[currentPlayer->getId()] > 30 && !toybonusgranted[currentPlayer->getId()]) + { + grantAward("Toy Collector!",300); + toybonusgranted[currentPlayer->getId()] = true; + } + if(beast[currentPlayer->getId()] > 30 && !beastbonusgranted[currentPlayer->getId()]) + { + grantAward("Beast Tamer!",300); + beastbonusgranted[currentPlayer->getId()] = true; + } + if(vampire[currentPlayer->getId()] > 30 && !vampirebonusgranted[currentPlayer->getId()]) + { + grantAward("Vampire King!",300); + vampirebonusgranted[currentPlayer->getId()] = true; + } + if(insect[currentPlayer->getId()] > 30 && !insectbonusgranted[currentPlayer->getId()]) + { + grantAward("Lord of Swarms!",300); + insectbonusgranted[currentPlayer->getId()] = true; + } + if(elemental[currentPlayer->getId()] > 30 && !elementalbonusgranted[currentPlayer->getId()]) + { + grantAward("Master of Elements!",300); + elementalbonusgranted[currentPlayer->getId()] = true; + } + if(zombie[currentPlayer->getId()] > 30 && !zombiebonusgranted[currentPlayer->getId()]) + { + grantAward("Zombie Apocalypse!",300); + zombiebonusgranted[currentPlayer->getId()] = true; + } + if(knight[currentPlayer->getId()] > 30 && !knightbonusgranted[currentPlayer->getId()]) + { + grantAward("Sword And Shield!",300); + knightbonusgranted[currentPlayer->getId()] = true; + } + if(cleric[currentPlayer->getId()] > 30 && !clericbonusgranted[currentPlayer->getId()]) + { + grantAward("Medic!",300); + clericbonusgranted[currentPlayer->getId()] = true; + } + + if(elf[currentPlayer->getId()] > 30 && !elfbonusgranted[currentPlayer->getId()]) + { + grantAward("The Promenade!",300); + elfbonusgranted[currentPlayer->getId()] = true; + } + if(Angel[currentPlayer->getId()] > 30 && !Angelbonusgranted[currentPlayer->getId()]) + { + grantAward("Heavenly Host!",300); + Angelbonusgranted[currentPlayer->getId()] = true; + } + if(dragon[currentPlayer->getId()] > 30 && !dragonbonusgranted[currentPlayer->getId()]) + { + grantAward("Teeth And Scales!",300); + dragonbonusgranted[currentPlayer->getId()] = true; + } + } + } + //bonus for dealing 100+ damage from a single source + WEventDamage * damageEvent = dynamic_cast (event); + if(damageEvent && !currentPlayer->isAI()) + { + MTGCardInstance * damageSource = (MTGCardInstance*)damageEvent->getTarget(damageEvent->TARGET_FROM); + if(damageSource && damageSource->controller() == currentPlayer && damageEvent->damage->damage > 99) + grantAward("Overkill!",500); + } + return 1; +} + +void MTGEventBonus::grantAward(string awardName,int amount) +{ + JSample * sample = WResourceManager::Instance()->RetrieveSample("bonus.wav"); + if (sample) + { + JSoundSystem::GetInstance()->PlaySample(sample); + } + text = awardName; + textAlpha = 255; + Credits::addCreditBonus(amount); +} + +int MTGEventBonus::testDestroy() +{ + return 0; +} + +void MTGEventBonus::Update(float dt) +{ + if (textAlpha) + { + textAlpha -= static_cast (200 * dt); + if (textAlpha < 0) + textAlpha = 0; + } + MTGAbility::Update(dt); +} + +void MTGEventBonus::Render() +{ + if (!textAlpha) + return; + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::OPTION_FONT/*MENU_FONT*/); + mFont->SetScale(2 - (float) textAlpha / 130); + mFont->SetColor(ARGB(255,255,255,255)); + mFont->DrawString(text.c_str(), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, JGETEXT_CENTER); +} + +MTGEventBonus * MTGEventBonus::clone() const +{ + MTGEventBonus * a = NEW MTGEventBonus(*this); + a->isClone = 1; + return a; +} + +// MTGPutInPlayRule::MTGPutInPlayRule(int _id) : MTGAbility(_id, NULL) { @@ -64,8 +341,6 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) #ifdef WIN32 cost->Dump(); #endif - if(!cost->getConvertedCost() && card->getManaCost()->suspend) - return 0; //cost of card. if (playerMana->canAfford(cost)) { @@ -218,11 +493,11 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * if (!alternateManaCost) return 0; - - if(!allowedToCast(card,player)) - return 0; if(!allowedToAltCast(card,player)) return 0; + card->getManaCost()->alternativeName; + if(card->model->data->getManaCost()->alternative && card->model->data->getManaCost()->alternative->alternativeName.size()) + alternativeName = card->model->data->getManaCost()->alternative->alternativeName; if (card->isLand()) { @@ -368,10 +643,10 @@ MTGAlternativeCostRule(_id) int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) { Player * player = game->currentlyActing(); - if(!allowedToCast(card,player)) - return 0; if (!player->game->hand->hasCard(card)) return 0; + if(!allowedToCast(card,player)) + return 0; return MTGAlternativeCostRule::isReactingToClick( card, mana, card->getManaCost()->BuyBack ); } @@ -637,8 +912,6 @@ int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) return 0; if (!card->getManaCost()->morph) return 0; - if(!allowedToCast(card,player)) - return 0; if(!allowedToAltCast(card,player)) return 0; //note lands can morph too, this is different from other cost types. @@ -919,6 +1192,15 @@ int MTGCombatTriggersRule::receiveEvent(WEvent *e) } if (dynamic_cast(e)) { + MTGGameZone* opponentZone = game->currentPlayer->opponent()->game->inPlay; + for (int i = 0; i < opponentZone->nb_cards; i++) + { + MTGCardInstance* card = opponentZone->cards[i]; + if (card && card->didblocked) + { + card->eventblocked(card->getNextOpponent()); + } + } Player * p = game->currentPlayer; MTGGameZone * z = p->game->inPlay; for (int i = 0; i < z->nb_cards; i++) @@ -927,21 +1209,18 @@ int MTGCombatTriggersRule::receiveEvent(WEvent *e) if (card && card->isAttacker() && !card->blocked) { card->eventattackednotblocked(); - card->notblocked += 1; + card->notblocked = 1; } if (card && card->isAttacker() && card->blocked) { - card->eventattackedblocked(); - } - } - MTGGameZone* opponentZone = game->currentPlayer->opponent()->game->inPlay; - for (int i = 0; i < opponentZone->nb_cards; i++) - { - MTGCardInstance* card = opponentZone->cards[i]; - if (card && card->didblocked > 0) - { - card->eventblocked(); + MTGCardInstance * opponent = card->getNextOpponent(); + while (opponent) + { + card->eventattackedblocked(opponent); + opponent = card->getNextOpponent(opponent); + } + } } } diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index 8567a5cee..40c4f4147 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -144,6 +144,15 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan tc = tcf.createTargetChooser("creature|myBattlefield", c); manaCost->addExtraCost(NEW Ninja(tc)); break; + case 'p' : + { + SAFE_DELETE(tc); + size_t start = value.find("("); + size_t end = value.rfind(")"); + string manaType = value.substr(start + 1, end - start - 1); + manaCost->addExtraCost(NEW LifeorManaCost(NULL,manaType)); + break; + } case 'c': //Counters { size_t counter_start = value.find("("); diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index e27c8fb18..286fd22df 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -486,7 +486,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta size_t start = attribute.find("share!"); size_t end = attribute.rfind("!"); string CDtype = attribute.substr(start + 6,end - start); - if(card->isSpell() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION) + if( card && card->isSpell() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION) { //spells always store their targets in :targets[] //however they are all erased as the spell resolves @@ -518,7 +518,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta } else if( CDtype.find("types") != string::npos ) { - if(card->target) + if(card && card->target) { cd->types = card->target->types; //remove main types because we only care about subtypes here. @@ -1138,6 +1138,14 @@ bool TargetZoneChooser::targetsZone(MTGGameZone * z) if (MTGGameZone::intToZone(zones[i], source) == z) return true; return false; } +bool TargetZoneChooser::targetsZone(MTGGameZone * z,MTGCardInstance * mSource) +{ +if(mSource) +source = mSource; + for (int i = 0; i < nbzones; i++) + if (MTGGameZone::intToZone(zones[i], source) == z) return true; + return false; +} TargetZoneChooser * TargetZoneChooser::clone() const { diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index e3f1f4728..b0702a1c6 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -67,13 +67,13 @@ WEventCardAttackedNotBlocked::WEventCardAttackedNotBlocked(MTGCardInstance * car { } -WEventCardAttackedBlocked::WEventCardAttackedBlocked(MTGCardInstance * card) : - WEventCardUpdate(card) +WEventCardAttackedBlocked::WEventCardAttackedBlocked(MTGCardInstance * card,MTGCardInstance * opponent) : + WEventCardUpdate(card),opponent(opponent) { } -WEventCardBlocked::WEventCardBlocked(MTGCardInstance * card) : - WEventCardUpdate(card) +WEventCardBlocked::WEventCardBlocked(MTGCardInstance * card,MTGCardInstance * opponent) : + WEventCardUpdate(card),opponent(opponent) { } @@ -235,7 +235,7 @@ Targetable * WEventCardAttackedBlocked::getTarget(int target) case TARGET_TO: return card; case TARGET_FROM: - return card->getNextOpponent(); + return opponent; } return NULL; } @@ -247,7 +247,7 @@ Targetable * WEventCardBlocked::getTarget(int target) case TARGET_TO: return card; case TARGET_FROM: - return card->getNextOpponent(); + return opponent; } return NULL; }