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:
+440
-405
@@ -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){
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user