Files
wagic/projects/mtg/src/TargetChooser.cpp
wagic.the.homebrew 61463d047b Erwan
- fix a bug with nyxathid
2009-03-14 15:03:55 +00:00

614 lines
17 KiB
C++

#include "../include/config.h"
#include "../include/TargetChooser.h"
#include "../include/CardDescriptor.h"
#include "../include/MTGGameZones.h"
#include "../include/GameObserver.h"
#include "../include/Subtypes.h"
TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInstance * card){
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * zones[10];
int nbzones = 0;
int size = s.size();
if (size != 0){
unsigned int found;
found = s.find("player");
if (found != string::npos){
int maxtargets = 1;
unsigned int several = s.find_first_of('s',5);
if (several != string::npos) maxtargets = -1;
found = s.find("creature");
if (found != string::npos){
return NEW DamageableTargetChooser(card,maxtargets); //Any Damageable target (player, creature)
}else{
return NEW PlayerTargetChooser(card,maxtargets); //Any player
}
}else{
string s1;
found = s.find("|");
if (found != string::npos){
string s2;
s1 = s.substr(0,found);
s2 = s.substr(found+1);
while(s2.size()){
found = s2.find(",");
string zoneName;
if (found != string::npos){
zoneName = s2.substr(0,found);
s2 = s2.substr(found+1);
}else{
zoneName = s2;
s2 = "";
}
zones[nbzones] = game->currentlyActing()->game->inPlay;
//Graveyards
if(zoneName.compare("graveyard") == 0){
zones[nbzones] = game->players[0]->game->graveyard;
nbzones++;
zones[nbzones] = game->players[1]->game->graveyard;
}else if(zoneName.compare("inplay") == 0){
zones[nbzones] = game->players[0]->game->inPlay;
nbzones++;
zones[nbzones] = game->players[1]->game->inPlay;
}else{
MTGGameZone * zone = MTGGameZone::stringToZone(zoneName, card,card);
if (zone) zones[nbzones] = zone;
}
nbzones++;
}
}else{
s1 = s;
nbzones = 2;
zones[0]= game->players[0]->game->inPlay;
zones[1]= game->players[1]->game->inPlay;
}
TargetChooser * tc = NULL;
int maxtargets = 1;
CardDescriptor * cd = NULL;
while(s1.size()){
found = s1.find(",");
string typeName;
if (found != string::npos){
typeName = s1.substr(0,found);
s1 = s1.substr(found+1);
}else{
typeName = s1;
s1 = "";
}
//Advanced cards caracteristics ?
found = typeName.find("[");
if (found != string::npos){
int nbminuses = 0;
int end = typeName.find("]");
#ifdef WIN32
OutputDebugString("Advanced Attributes 1 \n");
#endif
string attributes = typeName.substr(found+1,end-found-1);
#ifdef WIN32
OutputDebugString(attributes.c_str());
OutputDebugString("\n");
#endif
cd = NEW CardDescriptor();
while(attributes.size()){
unsigned int found2 = attributes.find(";");
string attribute;
if (found2 != string::npos){
attribute = attributes.substr(0,found2);
attributes = attributes.substr(found2+1);
}else{
attribute = attributes;
attributes = "";
}
int minus = 0;
if (attribute[0] == '-'){
#ifdef WIN32
OutputDebugString("MINUS\n");
#endif
minus = 1;
nbminuses++;
attribute=attribute.substr(1);
}
#ifdef WIN32
OutputDebugString(attribute.c_str());
OutputDebugString("\n");
#endif
//Attacker
if (attribute.find("attacking") != string::npos){
if (minus){
cd->attacker = -1;
}else{
cd->attacker = 1;
}
//Blocker
}else if (attribute.find("blocking") != string::npos){
if (minus){
cd->defenser = (MTGCardInstance *)-1; //Oh yeah, that's ugly....
}else{
cd->defenser = (MTGCardInstance *)1;
}
//Tapped, untapped
}else if (attribute.find("tapped") != string::npos){
if (minus){
cd->tapped = -1;
}else{
cd->tapped = 1;
}
}else{
int attributefound = 0;
//Colors
for (int cid = 0; cid < Constants::MTG_NB_COLORS; cid++){
if (attribute.find(Constants::MTGColorStrings[cid]) != string::npos){
attributefound = 1;
if (minus){
cd->colors[cid] = -1;
}else{
cd->colors[cid] = 1;
#ifdef WIN32
OutputDebugString("COLOR FOUND !!!");
#endif
}
}
}
if (!attributefound){
//Abilities
for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){
if (attribute.find(Constants::MTGBasicAbilities[j]) != string::npos){
attributefound = 1;
if (minus){
cd->basicAbilities[j] = -1;
}else{
cd->basicAbilities[j] = 1;
}
}
}
}
if (!attributefound){
//Subtypes
if (minus){
cd->setNegativeSubtype(attribute);
}else{
cd->setSubtype(attribute);
}
}
}
}
if (nbminuses == 0){
#ifdef WIN32
OutputDebugString("Switching to OR\n");
#endif
cd->mode = CD_OR;
}
typeName = typeName.substr(0,found);
}
//X targets allowed ?
if (typeName.at(typeName.length()-1) == 's' && !Subtypes::subtypesList->find(typeName)){
typeName = typeName.substr(0,typeName.length()-1);
maxtargets = -1;
}
if (cd){
if (!tc){
if (typeName.compare("*")!=0) cd->setSubtype(typeName);
tc = NEW DescriptorTargetChooser(cd,zones,nbzones,card,maxtargets);
#ifdef WIN32
OutputDebugString("Advanced Attributes 2 \n");
#endif
}else{
return NULL;
}
}else{
if (!tc){
if (typeName.compare("*")==0){
return NEW TargetZoneChooser(zones, nbzones,card, maxtargets);
}else{
tc = NEW TypeTargetChooser(typeName.c_str(), zones, nbzones, card,maxtargets);
}
}else{
((TypeTargetChooser *)tc)->addType(typeName.c_str());
tc->maxtargets = maxtargets;
}
}
}
return tc;
}
}
return NULL;
}
TargetChooser * TargetChooserFactory::createTargetChooser(MTGCardInstance * card){
int id = card->getId();
string s = card->spellTargetType;
if (card->alias){
id = card->alias;
//TODO load target as well... ?
}
TargetChooser * tc = createTargetChooser(s, card);
if (tc) return tc;
//Any target than cannot be defined automatically is determined by its id
switch (id){
//Spell
case 1196: //CounterSpell
case 1224: //Spell blast
{
#if defined (WIN32) || defined (LINUX)
OutputDebugString ("Counter Spell !\n");
#endif
return NEW SpellTargetChooser(card);
}
//Spell Or Permanent
case 1282: //ChaosLace
case 1152: //DeathLace
case 1358: //PureLace
case 1227: //ThoughLace
case 1257: //Lifelace
{
return NEW SpellOrPermanentTargetChooser(card);
}
//Red Spell or Permanent
case 1191: //Blue Elemental Blast
{
return NEW SpellOrPermanentTargetChooser(card,Constants::MTG_COLOR_RED);
}
//Blue Spell or Permanent
case 1312: //Red Elemental Blast
{
return NEW SpellOrPermanentTargetChooser(card,Constants::MTG_COLOR_BLUE);
}
//Damage History
case 1344: //Eye for an Eye
{
return NEW DamageTargetChooser(card,-1,1,RESOLVED_OK);
}
default:
{
return NULL;
}
}
}
TargetChooser::TargetChooser(MTGCardInstance * card, int _maxtargets): TargetsList(){
forceTargetListReady = 0;
source = card;
maxtargets = _maxtargets;
}
//Default targetter : every card can be targetted, unless it is protected from the source card
// For spells that do not "target" a specific card, set source to NULL
int TargetChooser::canTarget(Targetable * target){
if (target->typeAsTarget() == TARGET_CARD){
MTGCardInstance * card = (MTGCardInstance *) target;
if (source && (card->protectedAgainst(source) || card->has(Constants::SHROUD))) return 0;
return 1;
}
return 0;
}
int TargetChooser::addTarget(Targetable * target){
if (canTarget(target) && TargetsList::addTarget(target)){
}
#if defined (WIN32) || defined (LINUX)
char buf[4096];
sprintf(buf, "Nb targets : %i\n", cursor);
OutputDebugString(buf);
#endif
return targetsReadyCheck();
}
int TargetChooser::ForceTargetListReady(){
int state = targetsReadyCheck() ;
if (state == TARGET_OK){
forceTargetListReady = 1;
}
return forceTargetListReady;
}
int TargetChooser::targetsReadyCheck(){
if (cursor == 0){
return TARGET_NOK;
}
if (full()){
return TARGET_OK_FULL;
}
if (!ready()){
return TARGET_OK_NOT_READY;
}
return TARGET_OK;
}
int TargetChooser::targetListSet(){
int state = targetsReadyCheck();
if (state == TARGET_OK_FULL || forceTargetListReady){
return 1;
}
return 0;
}
/**
Choose anything that has a given list of types
**/
TypeTargetChooser::TypeTargetChooser(const char * _type, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
int id = Subtypes::subtypesList->Add(_type);
nbtypes = 0;
addType(id);
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
}
TypeTargetChooser::TypeTargetChooser(const char * _type, MTGGameZone ** _zones, int nbzones, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
int id = Subtypes::subtypesList->Add(_type);
nbtypes = 0;
addType(id);
GameObserver * game = GameObserver::GetInstance();
if (nbzones == 0){
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
}else{
init(_zones, nbzones);
}
}
void TypeTargetChooser::addType(const char * _type){
int id = Subtypes::subtypesList->Add(_type);
addType(id);
}
void TypeTargetChooser::addType(int type){
types[nbtypes] = type;
nbtypes++;
}
int TypeTargetChooser::canTarget(Targetable * target ){
if (target->typeAsTarget() == TARGET_CARD){
MTGCardInstance * card = (MTGCardInstance *) target;
if (!TargetZoneChooser::canTarget(card)) return 0;
for (int i= 0; i < nbtypes; i++){
if (card->hasSubtype(types[i])) return 1;
if (Subtypes::subtypesList->find(card->name) == types[i]) return 1;
}
return 0;
}
return 0;
}
/**
A Target Chooser associated to a Card Descriptor object, for fine tuning of targets description
**/
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
cd = _cd;
}
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGGameZone ** _zones, int nbzones, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
if (nbzones == 0){
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
}else{
init(_zones, nbzones);
}
cd = _cd;
}
int DescriptorTargetChooser::canTarget(Targetable * target){
if (target->typeAsTarget() == TARGET_CARD){
MTGCardInstance * _target = (MTGCardInstance *) target;
if (!TargetZoneChooser::canTarget(_target)) return 0;
if (cd->match(_target)) return 1;
}
return 0;
}
/**
Choose a creature
**/
CreatureTargetChooser::CreatureTargetChooser( MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
maxpower= -1;
maxtoughness= -1;
}
CreatureTargetChooser::CreatureTargetChooser(MTGGameZone ** _zones, int nbzones, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
if (nbzones == 0){
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
}else{
init(_zones, nbzones);
}
maxpower = -1;
maxtoughness= -1;
}
int CreatureTargetChooser::canTarget(Targetable * target){
if (!TargetZoneChooser::canTarget(target)) return 0;
if (target->typeAsTarget() == TARGET_CARD){
MTGCardInstance * card = (MTGCardInstance *) target;
if (maxpower != -1 && card->power > maxpower) return 0;
if (maxtoughness != -1 && card->toughness > maxtoughness) return 0;
return card->isACreature();
}
return 0;
}
TargetZoneChooser::TargetZoneChooser(MTGCardInstance * card, int _maxtargets){
init(NULL,0);
source = card;
maxtargets = _maxtargets;
}
TargetZoneChooser::TargetZoneChooser(MTGGameZone ** _zones, int _nbzones,MTGCardInstance * card, int _maxtargets){
init(_zones, _nbzones);
source = card;
maxtargets = _maxtargets;
}
int TargetZoneChooser::init(MTGGameZone ** _zones, int _nbzones){
for (int i = 0; i < _nbzones; i++){
zones[i] = _zones[i];
}
nbzones = _nbzones;
return nbzones;
}
int TargetZoneChooser::canTarget(Targetable * target){
if (!TargetChooser::canTarget(target)) return 0;
if (target->typeAsTarget() == TARGET_CARD){
MTGCardInstance * card = (MTGCardInstance *) target;
for (int i = 0; i<nbzones; i++){
if (zones[i]->hasCard(card)) return 1;
}
}
return 0;
}
/* Player Target */
int PlayerTargetChooser::canTarget(Targetable * target){
if (target->typeAsTarget() == TARGET_PLAYER){
return 1;
}
return 0;
}
/*Damageable Target */
int DamageableTargetChooser::canTarget(Targetable * target){
if (target->typeAsTarget() == TARGET_PLAYER){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("Targetting Player !!!\n");
#endif
return 1;
}
return CreatureTargetChooser::canTarget(target);
}
/*Spell */
SpellTargetChooser::SpellTargetChooser(MTGCardInstance * card,int _color, int _maxtargets ):TargetChooser(card, _maxtargets){
color = _color;
}
int SpellTargetChooser::canTarget(Targetable * target){
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_STACKACTION){
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){
Spell * spell = (Spell *) action;
card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return 1;
}
}
return 0;
}
/*Spell or Permanent */
SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(MTGCardInstance * card,int _color, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
color = _color;
}
int SpellOrPermanentTargetChooser::canTarget(Targetable * target){
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_CARD){
card = (MTGCardInstance *) target;
if (color == -1 || card->hasColor(color)) return TargetZoneChooser::canTarget(target);
}else if (target->typeAsTarget() == TARGET_STACKACTION){
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state==NOT_RESOLVED){
Spell * spell = (Spell *) action;
card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return 1;
}
}
return 0;
}
/*Damage */
DamageTargetChooser::DamageTargetChooser(MTGCardInstance * card,int _color, int _maxtargets, int _state):TargetChooser(card, _maxtargets){
color = _color;
state = _state;
}
int DamageTargetChooser::canTarget(Targetable * target){
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_STACKACTION){
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_DAMAGE && (action->state == state || state == -1)){
Damage * damage = (Damage *) action;
card = damage->source;
if (card && (color == -1 || card->hasColor(color))) return 1;
}
}
return 0;
}
/*Damage or Permanent */
DamageOrPermanentTargetChooser::DamageOrPermanentTargetChooser(MTGCardInstance * card,int _color, int _maxtargets):TargetZoneChooser(card, _maxtargets){
GameObserver * game = GameObserver::GetInstance();
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
init(default_zones,2);
color = _color;
}
int DamageOrPermanentTargetChooser::canTarget(Targetable * target){
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_CARD){
card = (MTGCardInstance *) target;
if (color == -1 || card->hasColor(color)) return TargetZoneChooser::canTarget(target);
}else if (target->typeAsTarget() == TARGET_STACKACTION){
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_DAMAGE){
Damage * damage = (Damage *) action;
card = damage->source;
if (card && (color == -1 || card->hasColor(color))) return 1;
}
}
return 0;
}