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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
18
projects/mtg/bin/Res/test/ardakar_wastes.txt
Normal file
18
projects/mtg/bin/Res/test/ardakar_wastes.txt
Normal file
@@ -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]
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,51 @@ using std::map;
|
||||
*/
|
||||
|
||||
|
||||
//MultiAbility : triggers several actions for a cost
|
||||
class MultiAbility:public ActivatedAbility{
|
||||
public:
|
||||
vector<MTGAbility *> abilities;
|
||||
vector<TriggeredEvent *> 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<int>::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<int>::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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#if defined (WIN32) || defined (LINUX)
|
||||
#define TESTSUITE 1
|
||||
#else
|
||||
#define OutputDebugString(val) {}
|
||||
#endif
|
||||
|
||||
#if defined (_DEBUG) && defined (WIN32)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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){
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user