diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 836bb5676..00cb00ed0 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -102,6 +102,7 @@ behemoth_sledge.txt behemoth_sledge2.txt behemoth_sledge3.txt behemoth_sledge4.txt +behemoth_sledge5.txt belligerent_hatchling.txt benalish_knight.txt black_vise.txt diff --git a/projects/mtg/bin/Res/test/behemoth_sledge5.txt b/projects/mtg/bin/Res/test/behemoth_sledge5.txt new file mode 100644 index 000000000..60a1997b8 --- /dev/null +++ b/projects/mtg/bin/Res/test/behemoth_sledge5.txt @@ -0,0 +1,24 @@ +#Test:equipment outside of main phase +[INIT] +COMBATATTACKERS +[PLAYER1] +manapool:{3} +inplay:grizzly bears,behemoth sledge +[PLAYER2] +[DO] +behemoth sledge +grizzly bears +next +#blockers +next +#damage +next +#end combat +[ASSERT] +COMBATEND +[PLAYER1] +life:20 +inplay:grizzly bears,behemoth sledge +[PLAYER2] +life:18 +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index d2fd2a50d..1a081efdf 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -384,7 +384,7 @@ class GenericActivatedAbility:public ActivatedAbility{ int limitPerTurn; int counters; MTGGameZone * activeZone; - GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, int limit = 0, int myTurnOnly = 0, MTGGameZone * dest = NULL):ActivatedAbility(_id, card,_cost,myTurnOnly,_tap),ability(a),limitPerTurn(limit),activeZone(dest){ + GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 0, int limit = 0, int restrictions = 0, MTGGameZone * dest = NULL):ActivatedAbility(_id, card,_cost,restrictions,_tap),ability(a),limitPerTurn(limit),activeZone(dest){ counters = 0; target = ability->target; } @@ -441,7 +441,7 @@ public: int limitPerTurn; int counters; MTGGameZone * activeZone; - GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc,MTGAbility * a, ManaCost * _cost = NULL, int _tap=0, int limit = 0, int myTurnOnly = 0, MTGGameZone * dest = NULL):TargetAbility(_id,_source, _tc,_cost,myTurnOnly,_tap),limitPerTurn(limit), activeZone(dest){ + GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc,MTGAbility * a, ManaCost * _cost = NULL, int _tap=0, int limit = 0, int restrictions = 0, MTGGameZone * dest = NULL):TargetAbility(_id,_source, _tc,_cost,restrictions,_tap),limitPerTurn(limit), activeZone(dest){ ability = a; counters = 0; } @@ -988,7 +988,7 @@ class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{ class AEquip:public TargetAbility{ public: vector currentAbilities; - AEquip(int _id, MTGCardInstance * _source, ManaCost * _cost=NULL, int doTap=0, int myturnOnly = 1):TargetAbility(_id,_source,NULL,_cost,myturnOnly,doTap){ + AEquip(int _id, MTGCardInstance * _source, ManaCost * _cost=NULL, int doTap=0, int restrictions = ActivatedAbility::AS_SORCERY):TargetAbility(_id,_source,NULL,_cost,restrictions,doTap){ } @@ -2316,12 +2316,12 @@ class APreventAllCombatDamage:public MTGAbility{ if (fromTc) fromTc->targetter = NULL; re = NEW REDamagePrevention (this, fromTc, toTc, -1, false, DAMAGE_COMBAT); game->replacementEffects->add(re); - return 1; + return MTGAbility::addToGame(); } int destroy(){ game->replacementEffects->remove(re); - delete re; + SAFE_DELETE(re); return 1; } @@ -2337,18 +2337,25 @@ class APreventAllCombatDamage:public MTGAbility{ class APreventAllCombatDamageUEOT: public InstantAbility{ public: APreventAllCombatDamage * ability; + vector clones; APreventAllCombatDamageUEOT(int id,MTGCardInstance * source,string to, string from):InstantAbility(id,source){ ability = NEW APreventAllCombatDamage(id,source,to, from); } int resolve(){ - ability->target = this->target; - ability->addToGame(); + APreventAllCombatDamage * a = ability->clone(); + a->target = this->target; + a->forceDestroy = -1; //Prevent the effect from getting destroyed because its source is not inplay + a->addToGame(); + clones.push_back(a); return 1; } int destroy(){ - ability->destroy(); + for (size_t i = 0; i < clones.size(); ++i){ + clones[i]->forceDestroy = 0; + } + clones.clear(); return 1; } diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 4e5dc7012..9d249fee6 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -100,9 +100,14 @@ class TriggeredAbility:public MTGAbility{ class ActivatedAbility:public MTGAbility{ public: - int playerturnonly; + enum { + NO_RESTRICTION = 0, + PLAYER_TURN_ONLY = 1, + AS_SORCERY = 2 + }; + int restrictions; int needsTapping; - ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _restrictions = NO_RESTRICTION,int tap = 1); virtual int reactToClick(MTGCardInstance * card); virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); virtual int reactToTargetClick(Targetable * object); @@ -202,6 +207,7 @@ class AbilityFactory{ int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); int parsePowerToughness(string s, int *power, int *toughness); TriggeredAbility * parseTrigger(string s, int id, Spell * spell, MTGCardInstance *card, Targetable * target); + int parseRestriction(string s); public: int getAbilities(vector * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL); MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0,MTGGameZone * dest = NULL); diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index a9bca13be..d0fee35cb 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -11,7 +11,7 @@ #include "../include/utils.h" #include "../include/DeckDataWrapper.h" -static const char* GAME_VERSION = "WTH?! 0.9.3 - by wololo"; +static const char* GAME_VERSION = "WTH?! 0.10.0 - by wololo"; #define DEFAULT_ANGLE_MULTIPLIER 0.4 #define MAX_ANGLE_MULTIPLIER (3*M_PI) diff --git a/projects/mtg/src/GameStateOptions.cpp b/projects/mtg/src/GameStateOptions.cpp index f0ea6b4c2..8214c887c 100644 --- a/projects/mtg/src/GameStateOptions.cpp +++ b/projects/mtg/src/GameStateOptions.cpp @@ -144,12 +144,12 @@ void GameStateOptions::Render() "Art: Ilya B, Julio, Jeck, J", "Check themeinfo.txt for the full credits of each theme!", "", - "Dev Team: Abrasax, Daddy32, Dr.Solomat, J,", - "Jeck, Leungclj, Superhiro, Psyringe, Wololo", + "Dev Team: Abrasax, Daddy32, Dr.Solomat, J, Jeck", + "Leungclj, Superhiro, Psyringe, Wololo, Yeshua", "", "Thanks to everyone who contributes code/content on the forums!", "", - "Developed with the JGE++ Library (http://jge.khors.com)", + "Developed with the JGE++ Library (http://code.google.com/p/wagic)", "SFX From www.soundsnap.com", "", "Music by Celestial Aeon Project, http://www.jamendo.com", diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index d80f968e1..796c107e4 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -143,6 +143,11 @@ TriggeredAbility * AbilityFactory::parseTrigger(string magicText, int id, Spell return NULL; } +int AbilityFactory::parseRestriction(string s){ + if (s.find("myturnonly") != string::npos) return ActivatedAbility::PLAYER_TURN_ONLY; + if (s.find("assorcery") != string::npos) return ActivatedAbility::AS_SORCERY; + return ActivatedAbility::NO_RESTRICTION; +} //Parses a string and returns the corresponding MTGAbility object @@ -186,8 +191,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG int doTap = 0; //Tap in the cost ? if (s.find("{t}") != string::npos) doTap = 1; - int myTurnOnly = 0; - if (s.find("myturnonly") != string::npos) myTurnOnly = 1; + int restrictions = parseRestriction(s); size_t delimiter = s.find("}:"); size_t firstNonSpace = s.find_first_not_of(" "); @@ -213,15 +217,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return amp; } - AEquip *ae = dynamic_cast(a); - if (ae){ - ae->cost = cost; - TargetChooserFactory tcf; - ae->tc = tcf.createTargetChooser("creature|myBattlefield", card); - return ae; - } - - int limit = 0; unsigned int limit_str = s.find("limit:"); if (limit_str != string::npos){ @@ -238,8 +233,19 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG tc = tcf.createTargetChooser(starget, card); } - if (tc) return NEW GenericTargetAbility(id, card, tc, a,cost, doTap,limit,myTurnOnly,dest); - return NEW GenericActivatedAbility(id, card, a,cost,doTap,limit,myTurnOnly,dest); + AEquip *ae = dynamic_cast(a); + if (ae){ + ae->cost = cost; + if (!tc) { + TargetChooserFactory tcf; + tc = tcf.createTargetChooser("creature|myBattlefield", card); + } + ae->tc = tc; + return ae; + } + + if (tc) return NEW GenericTargetAbility(id, card, tc, a,cost, doTap,limit,restrictions,dest); + return NEW GenericActivatedAbility(id, card, a,cost,doTap,limit,restrictions,dest); } SAFE_DELETE(cost); } @@ -426,6 +432,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } + //Equipment (attach) + found = s.find("attach"); + if (found != string::npos){ + MTGAbility * a = NEW AEquip(id,card,0,0,ActivatedAbility::NO_RESTRICTION); + return a; + } + //MoveTo Move a card from a zone to another found = s.find("moveto("); @@ -1702,15 +1715,25 @@ ostream& MTGAbility::toString(ostream& out) const // -ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int _playerturnonly,int tap):MTGAbility(id,card), playerturnonly(_playerturnonly), needsTapping(tap){ +ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int restrictions,int tap):MTGAbility(id,card), restrictions(restrictions), needsTapping(tap){ cost = _cost; } int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana){ - Player * player = game->currentPlayer; - if (!playerturnonly) player = game->currentlyActing(); - if (card == source && source->controller()==player && player==game->currentlyActing() && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness()))){ + Player * player = game->currentlyActing(); + int cPhase = game->getCurrentGamePhase(); + switch(restrictions) { + case PLAYER_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 (card == source && source->controller()==player && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness()))){ if (!cost) return 1; if (!mana) mana = player->getManaPool(); if (!mana->canAfford(cost)) return 0; @@ -1756,18 +1779,13 @@ int ActivatedAbility::reactToTargetClick(Targetable * object){ ostream& ActivatedAbility::toString(ostream& out) const { - out << "ActivatedAbility ::: playerturnonly : " << playerturnonly + out << "ActivatedAbility ::: restrictions : " << restrictions << " ; needsTapping : " << needsTapping << " ("; return MTGAbility::toString(out) << ")"; } -//The whole targetAbility mechanism is messed up, mainly because of its interactions with -// the ActionLayer, GameObserver, and parent class ActivatedAbility. -// Currently choosing a target is a complete different mechanism for put into play and for other abilities. -// It probably shouldn't be the case. - TargetAbility::TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ tc = _tc; ability = NULL;