From 9e314720e909634c285e54c927a86c3c7d083662 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Sun, 18 Jan 2009 06:42:59 +0000 Subject: [PATCH] Erwan - Parser: Added possibility to add multiple abilities for one cost, using keyword && (see Ardakar wastes in 10E). Currently only works with mana and damage - Added a dozen new cards - Improved testing suite : new keyword "choice" to select an item in the abilities popup menu --- projects/mtg/bin/Res/sets/10E/_cards.dat | 110 +++ projects/mtg/bin/Res/sets/10E/todo.dat | 81 +- projects/mtg/bin/Res/sets/SHM/_cards.dat | 64 ++ projects/mtg/bin/Res/sets/SHM/todo.dat | 55 -- projects/mtg/bin/Res/test/_tests.txt | 1 + projects/mtg/bin/Res/test/ardakar_wastes.txt | 18 + projects/mtg/include/ActionLayer.h | 1 + projects/mtg/include/AllAbilities.h | 55 +- projects/mtg/include/MTGAbility.h | 12 + projects/mtg/include/config.h | 2 + projects/mtg/src/ActionLayer.cpp | 14 +- projects/mtg/src/GameObserver.cpp | 4 +- projects/mtg/src/MTGAbility.cpp | 845 ++++++++++--------- projects/mtg/src/MTGCardInstance.cpp | 1 + projects/mtg/src/TestSuiteAI.cpp | 6 +- 15 files changed, 723 insertions(+), 546 deletions(-) create mode 100644 projects/mtg/bin/Res/test/ardakar_wastes.txt diff --git a/projects/mtg/bin/Res/sets/10E/_cards.dat b/projects/mtg/bin/Res/sets/10E/_cards.dat index a5092e61e..652296c38 100644 --- a/projects/mtg/bin/Res/sets/10E/_cards.dat +++ b/projects/mtg/bin/Res/sets/10E/_cards.dat @@ -101,6 +101,17 @@ subtype=Angel toughness=3 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {W} or {U} to your mana pool. Adarkar Wastes deals 1 damage to you. +auto={T}:Add {1} +auto={T}:Add {W} && Damage 1 controller +auto={T}:Add {B} && Damage 1 controller +id=129458 +name=Adarkar Wastes +rarity=R +color=Land +type=Land +[/card] +[card] text=Flying (This creature can't be blocked except by creatures with flying or reach.) Other black creatures get +1/+1. Nonblack creatures get -1/-1. abilities=Legendary, flying auto=lord(creature[black]) 1/1 @@ -127,6 +138,17 @@ type=Sorcery mana={2}{B} [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {R} or {W} to your mana pool. Battlefield Forge deals 1 damage to you. +id=129479 +auto={T}:Add {1} +auto={T}:Add {R} && Damage 1 controller +auto={T}:Add {W} && Damage 1 controller +name=Battlefield Forge +rarity=R +color=Land +type=Land +[/card] +[card] text=Flash (You may play this spell any time you could play an instant.) First strike (This creature deals combat damage before creatures without first strike.) abilities=flash,first strike id=136279 @@ -189,6 +211,28 @@ type=Instant mana={U}{U} [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {G} or {W} to your mana pool. Brushland deals 1 damage to you. +auto={T}:Add {1} +auto={T}:Add {G} && Damage 1 controller +auto={T}:Add {W} && Damage 1 controller +id=129496 +name=Brushland +rarity=R +color=Land +type=Land +[/card] +[card] +text={T}: Add {1} to your mana pool. {T}: Add {W} or {B} to your mana pool. Caves of Koilos deals 1 damage to you. +auto={T}:Add {1} +auto={T}:Add {W} && Damage 1 controller +auto={T}:Add {B} && Damage 1 controller +id=129497 +name=Caves of Koilos +rarity=R +color=Land +type=Land +[/card] +[card] text=Counter target spell. alias=1196 id=129882 @@ -809,6 +853,17 @@ subtype=Human Barbarian toughness=1 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {R} or {G} to your mana pool. Karplusan Forest deals 1 damage to you. +auto={T}:Add {1} +auto={T}:Add {R} && Damage 1 controller +auto={T}:Add {G} && Damage 1 controller +id=129614 +name=Karplusan Forest +rarity=R +color=Land +type=Land +[/card] +[card] text=When Kavu Climber comes into play, draw a card. id=129511 name=Kavu Climber @@ -859,6 +914,17 @@ subtype=Elf Druid toughness=1 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {B} or {G} to your mana pool. Llanowar Wastes deals 1 damage to you. +id=129627 +auto={T}:Add {1} +auto={T}:Add {B} && Damage 1 controller +auto={T}:Add {G} && Damage 1 controller +name=Llanowar Wastes +rarity=R +color=Land +type=Land +[/card] +[card] text={B}: Looming Shade gets +1/+1 until end of turn. auto={B}:1/1 id=129628 @@ -1547,6 +1613,17 @@ subtype=Dragon toughness=5 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {U} or {R} to your mana pool. Shivan Reef deals 1 damage to you. +id=129731 +auto={T}:Add {1} +auto={T}:Add {U} && Damage 1 controller +auto={T}:Add {R} && Damage 1 controller +name=Shivan Reef +rarity=R +color=Land +type=Land +[/card] +[card] text=Shock deals 2 damage to target creature or player. target=creature,player auto=Damage:2 @@ -1712,6 +1789,17 @@ subtype=Human Rebel toughness=2 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {B} or {R} to your mana pool. Sulfurous Springs deals 1 damage to you. +id=129751 +auto={T}:Add {1} +auto={T}:Add {B} && Damage 1 controller +auto={T}:Add {R} && Damage 1 controller +name=Sulfurous Springs +rarity=R +color=Land +type=Land +[/card] +[card] text=Flying (This creature can't be blocked except by creatures with flying or reach.) abilities=flying id=129753 @@ -1845,6 +1933,17 @@ subtype=Wolf toughness=1 [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {U} or {B} to your mana pool. Underground River deals 1 damage to you. +id=129778 +auto={T}:Add {1} +auto={T}:Add {U} && Damage 1 controller +auto={T}:Add {B} && Damage 1 controller +name=Underground River +rarity=R +color=Land +type=Land +[/card] +[card] text=Enchant creature (Target a creature as you play this. This card comes into play attached to that creature.) Enchanted creature gets +2/+1. target=creature auto=:2/1 @@ -1984,6 +2083,17 @@ type=Sorcery mana={2}{W}{W} [/card] [card] +text={T}: Add {1} to your mana pool. {T}: Add {G} or {U} to your mana pool. Yavimaya Coast deals 1 damage to you. +id=129810 +auto={T}:Add {1} +auto={T}:Add {G} && Damage 1 controller +auto={T}:Add {U} && Damage 1 controller +name=Yavimaya Coast +rarity=R +color=Land +type=Land +[/card] +[card] text=First strike (This creature deals combat damage before creatures without first strike.) abilities=first strike id=129790 diff --git a/projects/mtg/bin/Res/sets/10E/todo.dat b/projects/mtg/bin/Res/sets/10E/todo.dat index 62ec791a7..569bcaf30 100644 --- a/projects/mtg/bin/Res/sets/10E/todo.dat +++ b/projects/mtg/bin/Res/sets/10E/todo.dat @@ -20,14 +20,6 @@ subtype=Human Wizard toughness=2 [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {W} or {U} to your mana pool. Adarkar Wastes deals 1 damage to you. -id=129458 -name=Adarkar Wastes -rarity=R -color=Land -type=Land -[/card] -[card] text=Look at target player's hand and choose two cards from it. Put them on top of that player's library in any order. id=135228 name=Agonizing Memories @@ -178,14 +170,6 @@ type=Instant mana={W} [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {R} or {W} to your mana pool. Battlefield Forge deals 1 damage to you. -id=129479 -name=Battlefield Forge -rarity=R -color=Land -type=Land -[/card] -[card] text=Beacon of Destruction deals 5 damage to target creature or player. Shuffle Beacon of Destruction into its owner's library. id=135262 name=Beacon of Destruction @@ -271,22 +255,6 @@ subtype=Gnome toughness=3 [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {G} or {W} to your mana pool. Brushland deals 1 damage to you. -id=129496 -name=Brushland -rarity=R -color=Land -type=Land -[/card] -[card] -text={T}: Add {1} to your mana pool. {T}: Add {W} or {B} to your mana pool. Caves of Koilos deals 1 damage to you. -id=129497 -name=Caves of Koilos -rarity=R -color=Land -type=Land -[/card] -[card] text=Whenever Cephalid Constable deals combat damage to a player, return up to that many target permanents that player controls to their owners' hands. id=135261 name=Cephalid Constable @@ -945,14 +913,6 @@ subtype=Juggernaut toughness=3 [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {R} or {G} to your mana pool. Karplusan Forest deals 1 damage to you. -id=129614 -name=Karplusan Forest -rarity=R -color=Land -type=Land -[/card] -[card] text=Karplusan Strider can't be the target of blue or black spells. id=129911 name=Karplusan Strider @@ -1041,14 +1001,6 @@ subtype=Elf toughness=3 [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {B} or {G} to your mana pool. Llanowar Wastes deals 1 damage to you. -id=129627 -name=Llanowar Wastes -rarity=R -color=Land -type=Land -[/card] -[card] text=Equipped creature gets +3/+0 and has lifelink and trample. (When it deals damage, you gain that much life. If it would deal enough combat damage to its blockers to destroy them, you may have it deal the rest of its damage to defending player.) Equip {3} ({3}: Attach to target creature you control. Equip only as a sorcery.) id=129630 name=Loxodon Warhammer @@ -1645,14 +1597,6 @@ mana={U} subtype=Aura [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {U} or {R} to your mana pool. Shivan Reef deals 1 damage to you. -id=129731 -name=Shivan Reef -rarity=R -color=Land -type=Land -[/card] -[card] text=Change the target of target spell with a single target. id=130362 name=Shunt @@ -1870,14 +1814,7 @@ color=Red type=Instant mana={3}{R} [/card] -[card] -text={T}: Add {1} to your mana pool. {T}: Add {B} or {R} to your mana pool. Sulfurous Springs deals 1 damage to you. -id=129751 -name=Sulfurous Springs -rarity=R -color=Land -type=Land -[/card] + [card] text=At the beginning of each player's upkeep, that player returns a creature he or she controls to its owner's hand. id=129509 @@ -2077,14 +2014,6 @@ mana={2}{R}{R} subtype=Aura [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {U} or {B} to your mana pool. Underground River deals 1 damage to you. -id=129778 -name=Underground River -rarity=R -color=Land -type=Land -[/card] -[card] text=Whenever an opponent draws a card, Underworld Dreams deals 1 damage to him or her. id=129779 name=Underworld Dreams @@ -2212,14 +2141,6 @@ type=Artifact mana={2} [/card] [card] -text={T}: Add {1} to your mana pool. {T}: Add {G} or {U} to your mana pool. Yavimaya Coast deals 1 damage to you. -id=129810 -name=Yavimaya Coast -rarity=R -color=Land -type=Land -[/card] -[card] text=Yavimaya Enchantress gets +1/+1 for each enchantment in play. id=130515 name=Yavimaya Enchantress diff --git a/projects/mtg/bin/Res/sets/SHM/_cards.dat b/projects/mtg/bin/Res/sets/SHM/_cards.dat index 0ace5a83f..4abbe9c96 100644 --- a/projects/mtg/bin/Res/sets/SHM/_cards.dat +++ b/projects/mtg/bin/Res/sets/SHM/_cards.dat @@ -12,6 +12,32 @@ subtype=Imp toughness=1 [/card] [card] +text=Red creatures you control have first strike. +auto=lord(creature[red]|myinplay) first strike includeself +id=142062 +name=Bloodmark Mentor +rarity=U +type=Creature +mana={1}{R} +power=1 +subtype=Goblin Warrior +toughness=1 +[/card] +[card] +text=Trample Other red creatures you control get +1/+1. Other green creatures you control get +1/+1. +abilities=trample +auto=lord(creature[red]|myinplay) 1/1 +auto=lord(creature[green]|myinplay) 1/1 +id=147428 +name=Boartusk Liege +rarity=R +type=Creature +mana={1}{RG}{RG}{RG} +power=3 +subtype=Goblin Knight +toughness=4 +[/card] +[card] text=Haste Wither (This deals damage to creatures in the form of -1/-1 counters.) abilities=haste,wither id=153970 @@ -37,6 +63,30 @@ subtype=Elemental Skeleton toughness=1 [/card] [card] +text=Black creatures you control have wither. (They deal damage to creatures in the form of -1/-1 counters.) +auto=lord(creature[black]|myinplay) wither includeself +id=142034 +name=Corrosive Mentor +rarity=U +type=Creature +mana={2}{B} +power=1 +subtype=Elemental Rogue +toughness=3 +[/card] +[card] +text=Blue creatures you control are unblockable. +auto=lord(creature[blue]|myinplay) unblockable includeself +id=141981 +name=Deepchannel Mentor +rarity=U +type=Creature +mana={5}{U} +power=2 +subtype=Merfolk Rogue +toughness=2 +[/card] +[card] text={T}: Add {1} to your mana pool. {RG}, {T}: Add {R}{R}, {R}{G}, or {G}{G} to your mana pool. auto={T}:Add{1} auto={RG}{T}:Add{R}{R} @@ -106,6 +156,20 @@ subtype=Treefolk Shaman toughness=6 [/card] [card] +text=Flying Other blue creatures you control get +1/+1. Other black creatures you control get +1/+1. +abilities=flying +auto=lord(creature[blue]|myinplay) 1/1 +auto=lord(creature[black]|myinplay) 1/1 +id=146743 +name=Glen Elendra Liege +rarity=R +type=Creature +mana={1}{UB}{UB}{UB} +power=2 +subtype=Faerie Knight +toughness=3 +[/card] +[card] text=Persist (When this creature is put into a graveyard from play, if it had no -1/-1 counters on it, return it to play under its owner's control with a -1/-1 counter on it.) abilities=persist id=141935 diff --git a/projects/mtg/bin/Res/sets/SHM/todo.dat b/projects/mtg/bin/Res/sets/SHM/todo.dat index 77211a679..63ea2802f 100644 --- a/projects/mtg/bin/Res/sets/SHM/todo.dat +++ b/projects/mtg/bin/Res/sets/SHM/todo.dat @@ -165,17 +165,6 @@ mana={2} subtype=Equipment [/card] [card] -text=Red creatures you control have first strike. -id=142062 -name=Bloodmark Mentor -rarity=U -type=Creature -mana={1}{R} -power=1 -subtype=Goblin Warrior -toughness=1 -[/card] -[card] text=Enchant creature Enchanted creature attacks each turn if able. id=159395 name=Bloodshed Fever @@ -193,17 +182,6 @@ type=Enchantment mana={2}{B} [/card] [card] -text=Trample Other red creatures you control get +1/+1. Other green creatures you control get +1/+1. -id=147428 -name=Boartusk Liege -rarity=R -type=Creature -mana={1}{RG}{RG}{RG} -power=3 -subtype=Goblin Knight -toughness=4 -[/card] -[card] text=Plainswalk {2}{R}, Sacrifice Boggart Arsonists: Destroy target Scarecrow or Plains. id=158684 name=Boggart Arsonists @@ -299,17 +277,6 @@ type=Instant mana={2}{U} [/card] [card] -text=Black creatures you control have wither. (They deal damage to creatures in the form of -1/-1 counters.) -id=142034 -name=Corrosive Mentor -rarity=U -type=Creature -mana={2}{B} -power=1 -subtype=Elemental Rogue -toughness=3 -[/card] -[card] text=Corrupt deals damage equal to the number of Swamps you control to target creature or player. You gain life equal to the damage dealt this way. id=146013 name=Corrupt @@ -406,17 +373,6 @@ type=Sorcery mana={X}{GW} [/card] [card] -text=Blue creatures you control are unblockable. -id=141981 -name=Deepchannel Mentor -rarity=U -type=Creature -mana={5}{U} -power=2 -subtype=Merfolk Rogue -toughness=2 -[/card] -[card] text=Deep-Slumber Titan comes into play tapped. Deep-Slumber Titan doesn't untap during your untap step. Whenever Deep-Slumber Titan is dealt damage, untap it. id=159396 name=Deep-Slumber Titan @@ -755,17 +711,6 @@ type=Sorcery mana={1}{G} [/card] [card] -text=Flying Other blue creatures you control get +1/+1. Other black creatures you control get +1/+1. -id=146743 -name=Glen Elendra Liege -rarity=R -type=Creature -mana={1}{UB}{UB}{UB} -power=2 -subtype=Faerie Knight -toughness=3 -[/card] -[card] text=Destroy target creature. If that creature was green or white, its controller discards a card. id=158757 name=Gloomlance diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 9e551753d..d9cae6a3b 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -15,6 +15,7 @@ afflict.txt anarchy.txt animate_dead.txt animate_dead2.txt +ardakar_wastes.txt ascendant_evincar.txt ascendant_evincar2.txt brass_man.txt diff --git a/projects/mtg/bin/Res/test/ardakar_wastes.txt b/projects/mtg/bin/Res/test/ardakar_wastes.txt new file mode 100644 index 000000000..56f8385e5 --- /dev/null +++ b/projects/mtg/bin/Res/test/ardakar_wastes.txt @@ -0,0 +1,18 @@ +#Testing Ardakar Wastes with multi +[INIT] +FIRSTMAIN +[PLAYER1] +inplay:129458 +[PLAYER2] +[DO] +129458 +choice 1 +129458 +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:129458 +manapool:{W} +life:19 +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/include/ActionLayer.h b/projects/mtg/include/ActionLayer.h index 00e35cb9c..70fd097fe 100644 --- a/projects/mtg/include/ActionLayer.h +++ b/projects/mtg/include/ActionLayer.h @@ -30,6 +30,7 @@ class ActionLayer: public GuiLayer, public JGuiListener{ int reactToClick(MTGCardInstance * card); void setMenuObject(Targetable * object); void ButtonPressed(int controllerid, int controlid); + void doReactTo(int menuIndex); TargetChooser * getCurrentTargetChooser(); }; diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index eb3523c19..fc0fe4040 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -23,6 +23,51 @@ using std::map; */ +//MultiAbility : triggers several actions for a cost +class MultiAbility:public ActivatedAbility{ +public: + vector abilities; + vector events; + + MultiAbility(int _id, MTGCardInstance * card,ManaCost * _cost, int _tap):ActivatedAbility(_id, card,_cost,0,_tap){ + } + + + int Add(TriggeredEvent * event){ + events.push_back(event); + return 1; + } + + int Add(MTGAbility * ability){ + abilities.push_back(ability); + return 1; + } + + int resolve(){ + vector::size_type sz = abilities.size(); + for (unsigned int i = 0; i < sz; i++){ + abilities[i]->resolve(); + } + sz = events.size(); + for (unsigned int i = 0; i < sz; i++){ + events[i]->resolve(); + } + return 1; + } + + ~MultiAbility(){ + vector::size_type sz = abilities.size(); + for (unsigned int i = 0; i < sz; i++){ + delete abilities[i]; + } + sz = events.size(); + for (unsigned int i = 0; i < sz; i++){ + delete events[i]; + } + } +}; + + //Drawer, allows to draw a card for a cost: class ADrawer:public ActivatedAbility{ @@ -627,7 +672,7 @@ class AManaProducer: public MTGAbility{ if (animation < 0){ animation = 0; currentlyTapping--; - controller->getManaPool()->add(output); + resolve(); if (mParticleSys) mParticleSys->Stop(); } } @@ -653,6 +698,12 @@ class AManaProducer: public MTGAbility{ return result; } + int resolve(){ + controller = source->controller(); + controller->getManaPool()->add(output); + return 1; + } + int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; source->tapped = 1; @@ -664,7 +715,7 @@ class AManaProducer: public MTGAbility{ x0 = cardg->x + 15; y0 = cardg->y + 20; } - controller = source->controller(); + if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME] > 0 && currentlyTapping < 3){ JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/mana.wav"); diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 6d4c83c6c..3c15eff7d 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -147,6 +147,8 @@ class TriggerNextPhase:public TriggerAtPhase{ class TriggeredEvent:public MTGAbilityBasicFeatures{ public: + TriggeredEvent(); + TriggeredEvent(MTGCardInstance * source, Damageable * target = NULL); virtual int resolve()=0; }; @@ -163,6 +165,15 @@ class BuryEvent: public TriggeredEvent{ int resolve(); }; +class DamageEvent:public TriggeredEvent{ + public: + int damage; + DamageEvent(MTGCardInstance * _source, Damageable * _target, int _damage); + int resolve(); +}; + + + class DestroyCondition:public MTGAbilityBasicFeatures{ public: virtual int testDestroy(); @@ -189,6 +200,7 @@ class AbilityFactory{ int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p); int parsePowerToughness(string s, int *power, int *toughness); Trigger * parseTrigger(string magicText); + Damageable * parseCollateralTarget(MTGCardInstance * card, string s); public: int magicText(int id, Spell * spell, MTGCardInstance * card = NULL); void addAbilities(int _id, Spell * spell); diff --git a/projects/mtg/include/config.h b/projects/mtg/include/config.h index f9a36849e..2eedd16b7 100644 --- a/projects/mtg/include/config.h +++ b/projects/mtg/include/config.h @@ -3,6 +3,8 @@ #if defined (WIN32) || defined (LINUX) #define TESTSUITE 1 +#else +#define OutputDebugString(val) {} #endif #if defined (_DEBUG) && defined (WIN32) diff --git a/projects/mtg/src/ActionLayer.cpp b/projects/mtg/src/ActionLayer.cpp index 469ded1f2..fe854625c 100644 --- a/projects/mtg/src/ActionLayer.cpp +++ b/projects/mtg/src/ActionLayer.cpp @@ -176,10 +176,22 @@ void ActionLayer::setMenuObject(Targetable * object){ modal = 1; } +void ActionLayer::doReactTo(int menuIndex){ + + if (menuObject){ + int controlid = abilitiesMenu->mObjects[menuIndex]->GetId(); + char buf[4096]; + sprintf(buf, "doReact To %i\n",controlid); + OutputDebugString(buf); + ActionElement * currentAction = (ActionElement *)mObjects[controlid]; + currentAction->reactToTargetClick(menuObject); + menuObject = 0; + } +} void ActionLayer::ButtonPressed(int controllerid, int controlid){ if (controlid == -1){ - + }else{ ActionElement * currentAction = (ActionElement *)mObjects[controlid]; currentAction->reactToTargetClick(menuObject); diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 972361066..6a6bab569 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -321,9 +321,9 @@ void GameObserver::cardClick (MTGCardInstance * card, Targetable * object){ } }else if (reaction){ if (reaction == 1){ - mLayers->actionLayer()->reactToClick(card); + mLayers->actionLayer()->reactToClick(card); }else{ - mLayers->actionLayer()->setMenuObject(object); + mLayers->actionLayer()->setMenuObject(object); } }else if (card->isTapped() && card->controller() == currentPlayer){ // int a = ConstraintResolver::untap(this, card); diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 720ab625b..d133d8c71 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -9,8 +9,6 @@ #include "../include/MTGDeck.h" - - int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option){ int result = 0; GameObserver * game = GameObserver::GetInstance(); @@ -60,6 +58,11 @@ int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone return 1; } +Damageable * AbilityFactory::parseCollateralTarget(MTGCardInstance * card, string s){ + size_t found = s.find("controller"); + if (found != string::npos) return card->controller(); + return NULL; +} int AbilityFactory::parsePowerToughness(string s, int *power, int *toughness){ size_t found = s.find("/"); @@ -118,7 +121,7 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ //An awful way to get access to the aliasedcard magicText = GameObserver::GetInstance()->players[0]->game->collection->getCardById(card->alias)->magicText; } - string s; + string line; int size = magicText.size(); if (size == 0) return 0; unsigned int found; @@ -128,442 +131,465 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ while (magicText.size()){ found = magicText.find("\n"); if (found != string::npos){ - s = magicText.substr(0,found); + line = magicText.substr(0,found); magicText = magicText.substr(found+1); }else{ - s = magicText; + line = magicText; magicText = ""; } #if defined (WIN32) || defined (LINUX) char buf[4096]; - sprintf(buf, "AUTO ACTION: %s\n", s.c_str()); + sprintf(buf, "AUTO ACTION: %s\n", line.c_str()); OutputDebugString(buf); #endif - TargetChooser * tc = NULL; + + MultiAbility * multi = NULL; + int delimiter = line.find("}:"); + ManaCost * cost = NULL; + if (delimiter!= string::npos){ + cost = ManaCost::parseManaCost(line.substr(0,delimiter+1)); + } + OutputDebugString("Pqrsing cost\n"); + if (cost && !cost->getConvertedCost()){ + OutputDebugString("Cost is null\n"); + SAFE_DELETE(cost); + } int doTap = 0; - TargetChooser * lordTargets = NULL; - int lordIncludeSelf = 0; - - Trigger * trigger = parseTrigger(s); - //Dirty way to remove the trigger text (could get in the way) - if (trigger){ - found = s.find(":"); - s = s.substr(found+1); - } - //Tap in the cost ? - if (s.find("{t}") != string::npos) doTap = 1; + if (line.find("{t}") != string::npos) doTap = 1; - //Target Abilities - found = s.find("target("); - if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 7,end - found - 7); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(starget, card); - - } - - //Lord - found = s.find("lord("); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+5); - if (end != string::npos){ - string lordType = s.substr(found+5,end-found-5).c_str(); - TargetChooserFactory tcf; - lordTargets = tcf.createTargetChooser(lordType, card); - } - if (s.find("includeself") != string::npos) lordIncludeSelf = 1; - } - - //foreach. Very basic, needs to be improved ! - found = s.find("foreach(name:"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+13); - if (end != string::npos){ - string type = s.substr(found+13,end-found-13).c_str(); - game->addObserver(NEW APlagueRats(id,card,type.c_str())); - result++; - continue; - } - } - - //Untapper (Ley Druid...) - found = s.find("untap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW AUntaper(id, card, cost, tc)); - }else{ - target->tapped = 0; - } - - result++; - continue; - } - - - //Regeneration - found = s.find("}:regenerate"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordTargets){ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,-1,cost)); - }else{ - - if (tc){ - //TODO - }else{ - game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); - //TODO death ward ! - } - } - result++; - continue; - } - - - //Token creator. Name, type, p/t, abilities - found = s.find("token("); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - int end = s.find(",", found); - string sname = s.substr(found + 6,end - found - 6); - int previous = end+1; - end = s.find(",",previous); - string stypes = s.substr(previous,end - previous); - previous = end+1; - end = s.find(",",previous); - string spt = s.substr(previous,end - previous); - int power, toughness; - parsePowerToughness(spt,&power, &toughness); - string sabilities = s.substr(end+1); - ManaCost * cost = ManaCost::parseManaCost(s); - int multiplier = 1; - found = s.find("*"); - if (found != string::npos)multiplier = atoi(s.substr(found+1).c_str()); - if(cost->getConvertedCost() || doTap){ - game->addObserver(NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap)); - }else{ - delete cost; - cost = NULL; - ATokenCreator * tok = NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap); - for (int i=0; i < multiplier; i++){ - tok->resolve(); - } - delete tok; - } - result++; - continue; - } - //MoveTo Move a card from a zone to another - found = s.find("moveto("); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_BAD; //TODO : depends on where from, where to... - int end = s.find(")"); - string szone = s.substr(found + 7,end - found - 7); - if (tc){ - ManaCost * cost = ManaCost::parseManaCost(s); - if (cost->getConvertedCost() == 0){ - delete cost; - cost = NULL; - } - game->addObserver(NEW AZoneMover(id,card,tc,szone,cost)); - }else{ - MTGGameZone * fromZone = target->getCurrentZone(); - MTGGameZone * destZone = MTGGameZone::stringToZone(szone, target); - target->controller()->game->putInZone(target,fromZone,destZone); - } - result++; - continue; - } - //Bury - found = s.find("bury"); - if (found != string::npos){ - if (trigger){ - if (dryMode) return BAKA_EFFECT_BAD; - BuryEvent * action = NEW BuryEvent(); - game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); - }else{ - found = s.find("all("); - if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 4,end - found - 4); - TargetChooserFactory tcf; - TargetChooser * targetAll = tcf.createTargetChooser(starget, card); - if (dryMode){ - int myNbCards = countCards(targetAll,card->controller()); - int opponentNbCards = countCards(targetAll, card->controller()->opponent()); - int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); - int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); - delete targetAll; - if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - }else{ - this->destroyAllInPlay(targetAll,1); - delete targetAll; - } - - }else{ - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ABurier(id, card,tc)); - }else{ - target->controller()->game->putInGraveyard(target); - } - } - } - result++; - continue; - } - - //Destroy - found = s.find("destroy"); - if (found != string::npos){ - - found = s.find("all("); + while (line.size()){ + string s; + found = line.find("&&"); if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 4,end - found - 4); - TargetChooserFactory tcf; - TargetChooser * targetAll = tcf.createTargetChooser(starget, card); - if (dryMode){ - int myNbCards = countCards(targetAll,card->controller()); - int opponentNbCards = countCards(targetAll, card->controller()->opponent()); - int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); - int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); - delete targetAll; - if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - }else{ - this->destroyAllInPlay(targetAll); - delete targetAll; - } + s = line.substr(0,found); + line = line.substr(found+2); + if (!multi){ + OutputDebugString("Multi initializing\n"); + multi = NEW MultiAbility(id, card, cost,doTap); + game->addObserver(multi); + OutputDebugString("Multi initialized\n"); + } }else{ - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ADestroyer(id, card,tc)); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(target); - } + s = line; + line = ""; } - result++; - continue; - } - //Damage - found = s.find("damage"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - if (start == string::npos) start = s.find(" ",found); - unsigned int end = s.find(" ",start); - int damage; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - damage = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - damage = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ADamager(id, card, cost, damage, tc,doTap)); - }else{ - delete cost; - game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(), damage); - } - result++; - continue; - } + TargetChooser * tc = NULL; - //gain/lose life - found = s.find("life"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int life; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - life = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - life = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_GOOD; - if (tc){ - //TODO ? - }else{ - if (cost->getConvertedCost() == 0 && !doTap){ - delete cost; - card->controller()->life+=life; - }else{ - //TODO; - } - } - result++; - continue; - } + TargetChooser * lordTargets = NULL; + int lordIncludeSelf = 0; - //Draw - found = s.find("draw:"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int nbcards; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - nbcards = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - nbcards = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_GOOD; + Trigger * trigger = parseTrigger(s); + //Dirty way to remove the trigger text (could get in the way) if (trigger){ - DrawEvent * action = NEW DrawEvent(card->controller(),nbcards); - game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); - }else{ - if (tc){ - //TODO ? - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - game->mLayers->stackLayer()->addDraw(card->controller(),nbcards); - }else{ - game->addObserver(NEW ADrawer(id,card,cost,nbcards,doTap)); - } - } + found = s.find(":"); + s = s.substr(found+1); } - result++; - continue; - } - //Change Power/Toughness - int power, toughness; - if ( parsePowerToughness(s,&power, &toughness)){ - if (dryMode){ - if (power >=0 && toughness >= 0 ) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - } - int limit = 0; - unsigned int limit_str = s.find("limit:"); - if (limit_str != string::npos){ - limit = atoi(s.substr(limit_str+6).c_str()); - } - ManaCost * cost = ManaCost::parseManaCost(s); - if (lordTargets){ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,power,toughness)); - }else{ - if(tc){ - game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card,power,toughness, cost, tc)); - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - if(card->hasType("enchantment")){ - game->addObserver(NEW APowerToughnessModifier(id, card, target,power,toughness)); - }else{ - game->addObserver(NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness)); - } + //Target Abilities + found = s.find("target("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 7,end - found - 7); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(starget, card); + + } + + //Lord + found = s.find("lord("); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+5); + if (end != string::npos){ + string lordType = s.substr(found+5,end-found-5).c_str(); + TargetChooserFactory tcf; + lordTargets = tcf.createTargetChooser(lordType, card); + } + if (s.find("includeself") != string::npos) lordIncludeSelf = 1; + } + + //foreach. Very basic, needs to be improved ! + found = s.find("foreach(name:"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+13); + if (end != string::npos){ + string type = s.substr(found+13,end-found-13).c_str(); + game->addObserver(NEW APlagueRats(id,card,type.c_str())); + result++; + continue; + } + } + + //Untapper (Ley Druid...) + found = s.find("untap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + if (tc){ + game->addObserver(NEW AUntaper(id, card, cost, tc)); + }else{ + target->tapped = 0; + } + result++; + continue; + } + + + //Regeneration + found = s.find("}:regenerate"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + + if (lordTargets){ + game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,-1,cost)); + }else{ + if (tc){ + //TODO }else{ - game->addObserver(NEW APowerToughnessModifierUntilEndOfTurn(id, card, target,power,toughness, cost, limit)); + game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); + //TODO death ward ! } - } - } - result++; - continue; - } - - //Mana Producer - found = s.find("add"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s.substr(0,found)); - ManaCost * output = ManaCost::parseManaCost(s.substr(found)); - if (cost->getConvertedCost()){ - game->addObserver(NEW AManaProducer(id, target, output, cost)); - }else{ - delete cost; - if (doTap){ - game->addObserver(NEW AManaProducer(id, target, output)); - }else{ - card->controller()->getManaPool()->add(output); - delete output; - } - - } - result++; - continue; - } - - //Gain/loose Ability - for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ - found = s.find(Constants::MTGBasicAbilities[j]); - if (found!= string::npos){ - int modifier = 1; - if (found > 0 && s[found-1] == '-') modifier = 0; - if (dryMode){ - if (j == Constants::DEFENDER){ - if (modifier == 1) return BAKA_EFFECT_BAD; - return BAKA_EFFECT_GOOD; - }else{ - if (modifier == 1) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - } - } - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordTargets){ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,j)); - }else{ - - if (tc){ - game->addObserver(NEW ABasicAbilityModifierUntilEOT(id, card, j, cost,tc, modifier)); - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - if(card->hasType("enchantment")){ - game->addObserver(NEW ABasicAbilityModifier(id, card,target, j,modifier)); - }else{ - game->addObserver(NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier)); - } - }else{ - game->addObserver(NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, cost,j,modifier)); - } - } - } - result++; - continue; + } + result++; + continue; } - //Tapper (icy manipulator) - found = s.find("tap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW ATapper(id, card, cost, tc)); - }else{ - target->tapped = 1; + //Token creator. Name, type, p/t, abilities + found = s.find("token("); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + int end = s.find(",", found); + string sname = s.substr(found + 6,end - found - 6); + int previous = end+1; + end = s.find(",",previous); + string stypes = s.substr(previous,end - previous); + previous = end+1; + end = s.find(",",previous); + string spt = s.substr(previous,end - previous); + int power, toughness; + parsePowerToughness(spt,&power, &toughness); + string sabilities = s.substr(end+1); + int multiplier = 1; + found = s.find("*"); + if (found != string::npos)multiplier = atoi(s.substr(found+1).c_str()); + if(cost || doTap){ + game->addObserver(NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap)); + }else{ + ATokenCreator * tok = NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap); + for (int i=0; i < multiplier; i++){ + tok->resolve(); + } + delete tok; + } + result++; + continue; } - result++; - continue; - } + //MoveTo Move a card from a zone to another + found = s.find("moveto("); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_BAD; //TODO : depends on where from, where to... + int end = s.find(")"); + string szone = s.substr(found + 7,end - found - 7); + if (tc){ + if (cost){ + game->addObserver(NEW AZoneMover(id,card,tc,szone,cost)); + } + }else{ + MTGGameZone * fromZone = target->getCurrentZone(); + MTGGameZone * destZone = MTGGameZone::stringToZone(szone, target); + target->controller()->game->putInZone(target,fromZone,destZone); + } + result++; + continue; + } + + //Bury + found = s.find("bury"); + if (found != string::npos){ + if (trigger){ + if (dryMode) return BAKA_EFFECT_BAD; + BuryEvent * action = NEW BuryEvent(); + game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); + }else{ + found = s.find("all("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 4,end - found - 4); + TargetChooserFactory tcf; + TargetChooser * targetAll = tcf.createTargetChooser(starget, card); + if (dryMode){ + int myNbCards = countCards(targetAll,card->controller()); + int opponentNbCards = countCards(targetAll, card->controller()->opponent()); + int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); + int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); + delete targetAll; + if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + }else{ + this->destroyAllInPlay(targetAll,1); + delete targetAll; + } + }else{ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ABurier(id, card,tc)); + }else{ + target->controller()->game->putInGraveyard(target); + } + } + } + result++; + continue; + } + + //Destroy + found = s.find("destroy"); + if (found != string::npos){ + + found = s.find("all("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 4,end - found - 4); + TargetChooserFactory tcf; + TargetChooser * targetAll = tcf.createTargetChooser(starget, card); + if (dryMode){ + int myNbCards = countCards(targetAll,card->controller()); + int opponentNbCards = countCards(targetAll, card->controller()->opponent()); + int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); + int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); + delete targetAll; + if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + }else{ + this->destroyAllInPlay(targetAll); + delete targetAll; + } + }else{ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ADestroyer(id, card,tc)); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(target); + } + } + result++; + continue; + } + + //Damage + found = s.find("damage"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + if (start == string::npos) start = s.find(" ",found); + unsigned int end = s.find(" ",start); + int damage; + if (end != string::npos){ + damage = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + damage = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + MTGAbility * a = NEW ADamager(id, card, cost, damage, tc,doTap); + if (multi){ + multi->Add(a); + }else{ + game->addObserver(a); + } + }else{ + if (multi){ + Damageable * target = parseCollateralTarget(card, s); + if (!target) target = spell->getNextDamageableTarget(); + if (!target)OutputDebugString("NO TARGET FOR DAMAGE\n"); + multi->Add(NEW DamageEvent(card,target,damage)); + }else{ + game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(), damage); + } + } + result++; + continue; + } + + //gain/lose life + found = s.find("life"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int life; + if (end != string::npos){ + life = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + life = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_GOOD; + if (tc){ + //TODO ? + }else{ + if (!cost && !doTap){ + card->controller()->life+=life; + }else{ + //TODO; + } + } + result++; + continue; + } + + //Draw + found = s.find("draw:"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int nbcards; + if (end != string::npos){ + nbcards = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + nbcards = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_GOOD; + if (trigger){ + DrawEvent * action = NEW DrawEvent(card->controller(),nbcards); + game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); + }else{ + if (tc){ + //TODO ? + }else{ + if (!cost){ + game->mLayers->stackLayer()->addDraw(card->controller(),nbcards); + }else{ + game->addObserver(NEW ADrawer(id,card,cost,nbcards,doTap)); + } + } + } + result++; + continue; + } + + //Change Power/Toughness + int power, toughness; + if ( parsePowerToughness(s,&power, &toughness)){ + if (dryMode){ + if (power >=0 && toughness >= 0 ) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + int limit = 0; + unsigned int limit_str = s.find("limit:"); + if (limit_str != string::npos){ + limit = atoi(s.substr(limit_str+6).c_str()); + } + if (lordTargets){ + game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,power,toughness)); + }else{ + if(tc){ + game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card,power,toughness, cost, tc)); + }else{ + if (!cost){ + if(card->hasType("enchantment")){ + game->addObserver(NEW APowerToughnessModifier(id, card, target,power,toughness)); + }else{ + game->addObserver(NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness)); + } + }else{ + game->addObserver(NEW APowerToughnessModifierUntilEndOfTurn(id, card, target,power,toughness, cost, limit)); + } + } + } + result++; + continue; + } + + //Mana Producer + found = s.find("add"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * input = ManaCost::parseManaCost(s.substr(0,found)); + ManaCost * output = ManaCost::parseManaCost(s.substr(found)); + if (input->getConvertedCost() || doTap){ + SAFE_DELETE(cost); //erk + if (!input->getConvertedCost()){ + SAFE_DELETE(input); + } + MTGAbility * a = NEW AManaProducer(id, target, output, input); + if (multi){ + multi->Add(a); + }else{ + game->addObserver(a); + } + }else{ + OutputDebugString ("uh oh\n"); + card->controller()->getManaPool()->add(output); + delete output; + } + result++; + continue; + } + + //Gain/loose Ability + for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ + found = s.find(Constants::MTGBasicAbilities[j]); + if (found!= string::npos){ + int modifier = 1; + if (found > 0 && s[found-1] == '-') modifier = 0; + if (dryMode){ + if (j == Constants::DEFENDER){ + if (modifier == 1) return BAKA_EFFECT_BAD; + return BAKA_EFFECT_GOOD; + }else{ + if (modifier == 1) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + } + + if (lordTargets){ + game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,j)); + }else{ + if (tc){ + game->addObserver(NEW ABasicAbilityModifierUntilEOT(id, card, j, cost,tc, modifier)); + }else{ + if (!cost){ + if(card->hasType("enchantment")){ + game->addObserver(NEW ABasicAbilityModifier(id, card,target, j,modifier)); + }else{ + game->addObserver(NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier)); + } + }else{ + game->addObserver(NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, cost,j,modifier)); + } + } + } + result++; + continue; + } + } + + //Tapper (icy manipulator) + found = s.find("tap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + if (tc){ + game->addObserver(NEW ATapper(id, card, cost, tc)); + }else{ + target->tapped = 1; + } + result++; + continue; + } +#if defined (WIN32) || defined (LINUX) + char buf[4096]; + sprintf(buf, "AUTO ACTION PARSED: %s\n", line.c_str()); + OutputDebugString(buf); +#endif } } - - - - return result; - - } void AbilityFactory::addAbilities(int _id, Spell * spell){ @@ -1853,8 +1879,17 @@ int TriggerNextPhase::testDestroy(){ return 0; } +TriggeredEvent::TriggeredEvent():MTGAbilityBasicFeatures(){} +TriggeredEvent::TriggeredEvent(MTGCardInstance * _source, Damageable * _target):MTGAbilityBasicFeatures(_source, _target){} +DamageEvent::DamageEvent(MTGCardInstance * _source, Damageable * _target, int _damage):TriggeredEvent(_source,_target),damage(_damage){ +} + +int DamageEvent::resolve(){ + game->mLayers->stackLayer()->addDamage(source,target, damage); + return damage; +} DrawEvent::DrawEvent(Player * _player, int _nbcards):TriggeredEvent(),player(_player),nbcards(_nbcards){ } diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index bf66e39c4..e00b823ec 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -206,6 +206,7 @@ Player * MTGCardInstance::controller(){ if (game->players[i]->game->inPlay->hasCard(this)) return game->players[i]; if (game->players[i]->game->stack->hasCard(this)) return game->players[i]; if (game->players[i]->game->graveyard->hasCard(this)) return game->players[i]; + if (game->players[i]->game->hand->hasCard(this)) return game->players[i]; } return NULL; } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index bacf9c995..eea792192 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -83,6 +83,10 @@ int TestSuiteAI::Act(float dt){ if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this){ g->mLayers->stackLayer()->cancelInterruptOffer(); } + }else if(action.find("choice ")!=string::npos){ + OutputDebugString("choice !!!\n"); + int choice = atoi(action.substr(action.find("choice ") + 7).c_str()); + g->mLayers->actionLayer()->doReactTo(choice); }else{ int mtgid = atoi(action.c_str()); if (mtgid){ @@ -92,7 +96,7 @@ int TestSuiteAI::Act(float dt){ }else{ MTGCardInstance * card = suite->getCardByMTGId(mtgid); if (card) { - g->cardClick(card); + g->cardClick(card,card); } } }else{