- some dangerous casts Player/MTGCardInstance fixed

- removed typeAsTarget function and replaced with dynamic casting
- The test suite passes, but it is possible that I busted some of AI's features :(
This commit is contained in:
wagic.the.homebrew
2011-11-19 14:07:57 +00:00
parent e9139bedab
commit 851e1f20f1
16 changed files with 237 additions and 317 deletions

View File

@@ -98,6 +98,7 @@ class AIPlayerBaka: public AIPlayer{
//used by MomirPlayer, hence protected instead of private
virtual int getEfficiency(OrderedAIAction * action);
virtual int getEfficiency(MTGAbility * ability);
virtual bool payTheManaCost(ManaCost * cost, MTGCardInstance * card = NULL,vector<MTGAbility*> gotPayment = vector<MTGAbility*>());
virtual int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0);
virtual ManaCost * getPotentialMana(MTGCardInstance * card = NULL);

View File

@@ -77,11 +77,6 @@ public:
virtual void Render()
{
}
int typeAsTarget()
{
return TARGET_STACKACTION;
}
Interruptible(GameObserver* observer, int inID = 0, bool hasFocus = false)
: PlayGuiObject(40, x, y, inID, hasFocus), Targetable(observer), state(NOT_RESOLVED), display(0), source(NULL)
@@ -139,7 +134,7 @@ public:
Interruptible * getNextInterruptible(Interruptible * previous, int type);
Spell * getNextSpellTarget(Spell * previous = 0);
Damage * getNextDamageTarget(Damage * previous = 0);
Targetable * getNextTarget(Targetable * previous = 0, int type = -1);
Targetable * getNextTarget(Targetable * previous = 0);
int getNbTargets();
};

View File

@@ -113,7 +113,6 @@ public:
MTGCardInstance * changeController(Player * newcontroller);
Player * owner;
Counters * counters;
int typeAsTarget(){return TARGET_CARD;}
const string getDisplayName() const;
MTGCardInstance * target;
vector<Targetable *> backupTargets;

View File

@@ -250,7 +250,7 @@ class MTGVampireRule: public PermanentAbility
{
public:
MTGVampireRule(GameObserver* observer, int _id);
map<MTGCardInstance*,vector<MTGCardInstance*> > victems;
map<MTGCardInstance*,vector<MTGCardInstance*> > victims;
int receiveEvent(WEvent * event);
virtual ostream& toString(ostream& out) const;
virtual MTGVampireRule * clone() const;

View File

@@ -48,10 +48,6 @@ public:
return 1;
}
const string getDisplayName() const;
int typeAsTarget()
{
return TARGET_PLAYER;
}
int afterDamage();

View File

@@ -1,17 +1,12 @@
#ifndef _TARGETABLE_H_
#define _TARGETABLE_H_
#define TARGET_CARD 1
#define TARGET_PLAYER 2
#define TARGET_STACKACTION 3
class Targetable
{
protected:
GameObserver* observer;
public:
Targetable(GameObserver* observer) : observer(observer) {};
virtual int typeAsTarget() = 0;
virtual const string getDisplayName() const = 0;
inline GameObserver* getObserver() { return observer; };
virtual void setObserver(GameObserver*g) { observer = g; };

View File

@@ -14,6 +14,8 @@ using std::vector;
class TargetsList
{
private:
size_t iterateTarget(Targetable * previous);
public:
TargetsList();
TargetsList(Targetable * _targets[], int nbtargets);
@@ -28,7 +30,7 @@ public:
Interruptible * getNextInterruptible(Interruptible * previous, int type);
Spell * getNextSpellTarget(Spell * previous = 0);
Damage * getNextDamageTarget(Damage * previous = 0);
Targetable * getNextTarget(Targetable * previous = 0, int type = -1);
Targetable * getNextTarget(Targetable * previous = 0);
void initTargets()
{
targets.clear();

View File

@@ -98,24 +98,17 @@ int AIAction::clickMultiAct(vector<Targetable*>& actionTargets)
}
ite++;
}
owner->getRandomGenerator()->random_shuffle(actionTargets.begin(), actionTargets.end());
//shuffle to make it less predictable, otherwise ai will always seem to target from right to left. making it very obvious.
for(int k = 0;k < int(actionTargets.size());k++)
owner->getRandomGenerator()->random_shuffle(actionTargets.begin(), actionTargets.end());
for(int k = 0 ;k < int(actionTargets.size()) && k < tc->maxtargets; k++)
{
int type = actionTargets[k]->typeAsTarget();
switch (type)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(actionTargets[k]))
{
case TARGET_CARD:
{
if(k < tc->maxtargets)
{
MTGCardInstance * card = ((MTGCardInstance *) actionTargets[k]);
if(k+1 == int(actionTargets.size()))
tc->done = true;
g->cardClick(card);
}
}
break;
if(k+1 == int(actionTargets.size()))
tc->done = true;
g->cardClick(card);
}
}
tc->attemptsToFill++;
@@ -158,16 +151,15 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector<Targetable*>& potentia
vector<Targetable*>::iterator ite = potentialTargets.begin();
while(ite != potentialTargets.end())
{
MTGCardInstance * card = ((MTGCardInstance *) (*ite));
Player * pTarget = (Player*)(*ite);
if(card && card == (MTGCardInstance*)tc->source)//if the source is part of the targetting deal with it first. second click is "confirming click".
MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(*ite);
if(card && card == tc->source)//if the source is part of the targetting deal with it first. second click is "confirming click".
{
clickstream.push(NEW AIAction(this, card));
DebugTrace("Ai clicked source as a target: " << (card ? card->name : "None" ) << endl );
ite = potentialTargets.erase(ite);
continue;
}
if(pTarget && pTarget->typeAsTarget() == TARGET_PLAYER)
else if(Player * pTarget = dynamic_cast<Player *>(*ite))
{
clickstream.push(NEW AIAction(this, pTarget));
DebugTrace("Ai clicked Player as a target");
@@ -192,26 +184,18 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector<Targetable*>& potentia
int AIPlayer::clickSingleTarget(TargetChooser * tc, vector<Targetable*>& potentialTargets, MTGCardInstance * chosenCard)
{
int i = randomGenerator.random() % potentialTargets.size();
int type = potentialTargets[i]->typeAsTarget();
switch (type)
{
case TARGET_CARD:
{
if(!chosenCard)
{
MTGCardInstance * card = ((MTGCardInstance *) potentialTargets[i]);
clickstream.push(NEW AIAction(this, card));
}
break;
}
case TARGET_PLAYER:
{
Player * player = ((Player *) potentialTargets[i]);
clickstream.push(NEW AIAction(this, player));
break;
}
}
int i = randomGenerator.random() % potentialTargets.size();
if(MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(potentialTargets[i]))
{
if (!chosenCard)
clickstream.push(NEW AIAction(this, card));
}
else if(Player * player = dynamic_cast<Player *>(potentialTargets[i]))
{
clickstream.push(NEW AIAction(this, player));
}
return 1;
}

View File

@@ -19,9 +19,6 @@ Player * OrderedAIAction::getPlayerTarget()
if (playerAbilityTarget)
return (Player *)playerAbilityTarget;
if (target && target->typeAsTarget() == TARGET_PLAYER)
return (Player *)target;
return NULL;
}
@@ -408,9 +405,9 @@ int OrderedAIAction::getEfficiency()
AbilityFactory af(g);
int suggestion = af.abilityEfficiency(a, p, MODE_ABILITY);
if(_t->typeAsTarget() == TARGET_CARD)
if(MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(_t))
{
if((suggestion == BAKA_EFFECT_BAD && ((MTGCardInstance*)_t)->controller() == p) || (suggestion == BAKA_EFFECT_GOOD && ((MTGCardInstance*)_t)->controller() != p))
if((suggestion == BAKA_EFFECT_BAD && (cTarget)->controller() == p) || (suggestion == BAKA_EFFECT_GOOD && (cTarget)->controller() != p))
efficiency = 0;
}
else if ((suggestion == BAKA_EFFECT_BAD && _t == p) || (suggestion == BAKA_EFFECT_GOOD && _t != p))
@@ -549,16 +546,16 @@ int OrderedAIAction::getEfficiency()
}
else if (AAProliferate * aap = dynamic_cast<AAProliferate *>(a))
{
if (aap && target && target->typeAsTarget() == TARGET_PLAYER && (Player*)target != p)
if (playerAbilityTarget && playerAbilityTarget != p)
{
efficiency = 60;//ai determines if the counters are good or bad on menu check.
}
else if (aap)
else
efficiency = 90;
}
else if (AAAlterPoison * aaap = dynamic_cast<AAAlterPoison *>(a))
{
if (aaap && target && target->typeAsTarget() == TARGET_PLAYER && (Player*)target != p)
if (playerAbilityTarget && playerAbilityTarget != p)
{
efficiency = 90;
}
@@ -566,7 +563,7 @@ int OrderedAIAction::getEfficiency()
else if (ATokenCreator * atc = dynamic_cast<ATokenCreator *>(a))
{
efficiency = 80;
if(atc && atc->name.length() && atc->sabilities.length() && atc->types.size() && p->game->inPlay->findByName(atc->name))
if(atc->name.length() && atc->sabilities.length() && atc->types.size() && p->game->inPlay->findByName(atc->name))
{
list<int>::iterator it;
for (it = atc->types.begin(); it != atc->types.end(); it++)
@@ -1196,23 +1193,22 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank
a->getActionTc()->done = true;
return 0;
}
int targetThis = 0;
while(potentialTargets.size())
{
OrderedAIAction * check = NULL;
MTGCardInstance * targeting = dynamic_cast<MTGCardInstance*>(potentialTargets[0]);
if(targeting && targeting->typeAsTarget() == TARGET_CARD)
check = NEW OrderedAIAction(this, a,c,targeting);
MTGCardInstance * cTargeting = dynamic_cast<MTGCardInstance*>(potentialTargets[0]);
if(cTargeting)
check = NEW OrderedAIAction(this, a,c,cTargeting);
Player * ptargeting = dynamic_cast<Player*>(potentialTargets[0]);
if(ptargeting && ptargeting->typeAsTarget() == TARGET_PLAYER)
check = NEW OrderedAIAction(this, a,ptargeting,c);
Player * pTargeting = dynamic_cast<Player*>(potentialTargets[0]);
if(pTargeting)
check = NEW OrderedAIAction(this, a,pTargeting,c);
targetThis = getEfficiency(check);
if(targetThis && ptargeting && ptargeting->typeAsTarget() == TARGET_PLAYER)
int targetThis = getEfficiency(check);
if(targetThis && pTargeting)
{
OrderedAIAction aiAction(this, a,ptargeting,c);
OrderedAIAction aiAction(this, a,pTargeting,c);
ranking[aiAction] = 1;
}
if(targetThis)
@@ -1223,7 +1219,9 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank
if(!realTargets.size() || (int(realTargets.size()) < a->getActionTc()->maxtargets && a->getActionTc()->targetMin))
return 0;
OrderedAIAction aiAction(this, a, c,realTargets);
aiAction.target = dynamic_cast<MTGCardInstance*>(realTargets[0]);
aiAction.playerAbilityTarget = dynamic_cast<Player*>(realTargets[0]);
ranking[aiAction] = 1;
}
return 1;
@@ -1508,6 +1506,29 @@ int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCard
return 1;
}
//Returns -1 if error, a number between 0 and 100 otherwise
int AIPlayerBaka::getEfficiency(MTGAbility * ability)
{
if (!ability)
return -1;
OrderedAIAction * check = NULL;
if(MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(ability->target))
check = NEW OrderedAIAction(this, ability, ability->source, cTarget);
else if(Player * pTarget = dynamic_cast<Player *>(ability->target))
check = NEW OrderedAIAction(this, ability, pTarget, ability->source);
else
check = NEW OrderedAIAction(this, ability, ability->source);
if (!check)
return -1;
int result = getEfficiency(check);
SAFE_DELETE(check);
return result;
}
int AIPlayerBaka::selectMenuOption()
{
ActionLayer * object = observer->mLayers->actionLayer();
@@ -1515,10 +1536,10 @@ int AIPlayerBaka::selectMenuOption()
if (object->menuObject)
{
int checkedLast = 0;
int checked = 0;
MenuAbility * currentMenu = NULL;
if(object->abilitiesMenu->isMultipleChoice && object->currentActionCard)
{
MenuAbility * currentMenu = NULL;
for(size_t m = object->mObjects.size()-1;m > 0;m--)
{
MenuAbility * ability = dynamic_cast<MenuAbility *>(object->mObjects[m]);
@@ -1531,60 +1552,28 @@ int AIPlayerBaka::selectMenuOption()
if(currentMenu)
for(unsigned int mk = 0;mk < currentMenu->abilities.size();mk++)
{
MTGAbility * checkEff = NULL;
OrderedAIAction * check = NULL;
checkEff = currentMenu->abilities[mk];
if(checkEff)
{
if(checkEff->target && checkEff->target->typeAsTarget() == TARGET_CARD)
check = NEW OrderedAIAction(this, checkEff,checkEff->source,(MTGCardInstance*)checkEff->target);
else if(checkEff->target && checkEff->target->typeAsTarget() == TARGET_PLAYER)
check = NEW OrderedAIAction(this, checkEff,(Player*)checkEff->target,checkEff->source);
else
check = NEW OrderedAIAction(this, checkEff,checkEff->source);
}
if(check)
{
checked = getEfficiency(check);
SAFE_DELETE(check);
}
int checked = getEfficiency(currentMenu->abilities[mk]);
if(checked > 60 && checked > checkedLast)
{
doThis = mk;
checkedLast = checked;
}
checked = 0;
}
}
else
{
for(unsigned int k = 0;k < object->abilitiesMenu->mObjects.size();k++)
{
MTGAbility * checkEff = NULL;
OrderedAIAction * check = NULL;
if(object->abilitiesMenu->mObjects[k]->GetId() >= 0)
checkEff = (MTGAbility *)object->mObjects[object->abilitiesMenu->mObjects[k]->GetId()];
if(checkEff)
{
Targetable * checkTarget = checkEff->target;
if(checkTarget && checkTarget->typeAsTarget() == TARGET_CARD)
check = NEW OrderedAIAction(this, checkEff,checkEff->source,(MTGCardInstance*)checkTarget);
else if(checkTarget && checkTarget->typeAsTarget() == TARGET_PLAYER)
check = NEW OrderedAIAction(this, checkEff,(Player*)checkTarget,checkEff->source);
else
check = NEW OrderedAIAction(this, checkEff,checkEff->source);
}
if(check)
{
checked = getEfficiency(check);
SAFE_DELETE(check);
}
if(object->abilitiesMenu->mObjects[k]->GetId() <= 0)
continue;
MTGAbility * checkEff = (MTGAbility *)object->mObjects[object->abilitiesMenu->mObjects[k]->GetId()];
int checked = getEfficiency(checkEff);
if(checked > 60 && checked > checkedLast)
{
doThis = k;
checkedLast = checked;
}
checked = 0;
}
}
}

View File

@@ -39,14 +39,14 @@ int ActionElement::getActivity()
int ActionElement::isReactingToTargetClick(Targetable * object)
{
if (object && object->typeAsTarget() == TARGET_CARD)
return isReactingToClick((MTGCardInstance *) object);
if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
return isReactingToClick(cObject);
return 0;
}
int ActionElement::reactToTargetClick(Targetable * object)
{
if (object->typeAsTarget() == TARGET_CARD)
return reactToClick((MTGCardInstance *) object);
if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
return reactToClick(cObject);
return 0;
}

View File

@@ -148,8 +148,7 @@ void StackAbility::Render()
_target = t;
}
Damageable * target = NULL;
if (_target != ability->source && (_target->typeAsTarget() == TARGET_CARD || _target->typeAsTarget()
== TARGET_PLAYER))
if (_target != ability->source && (dynamic_cast<MTGCardInstance *>(_target) || dynamic_cast<Player *>(_target)))
{
target = (Damageable *) _target;
}
@@ -346,11 +345,11 @@ Damage * Spell::getNextDamageTarget(Damage * previous)
return NULL;
return tc->getNextDamageTarget(previous);
}
Targetable * Spell::getNextTarget(Targetable * previous, int type)
Targetable * Spell::getNextTarget(Targetable * previous)
{
if (!tc)
return NULL;
return tc->getNextTarget(previous, type);
return tc->getNextTarget(previous);
}
int Spell::getNbTargets()

View File

@@ -568,19 +568,23 @@ int AAProliferate::resolve()
return 0;
vector<MTGAbility*>pcounters;
if(target->typeAsTarget() == TARGET_PLAYER && ((Player*)target)->poisonCount && target != source->controller())
Player * pTarget = dynamic_cast<Player *>(target);
MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target);
if(pTarget && pTarget->poisonCount && pTarget != source->controller())
{
MTGAbility * a = NEW AAAlterPoison(game, game->mLayers->actionLayer()->getMaxId(), source, target, 1, NULL);
a->oneShot = true;
pcounters.push_back(a);
}
else if (target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance*)target)->counters)
else if (cTarget && cTarget->counters)
{
Counters * counters = ((MTGCardInstance*)target)->counters;
Counters * counters = cTarget->counters;
for(size_t i = 0; i < counters->counters.size(); ++i)
{
Counter * counter = counters->counters[i];
MTGAbility * a = NEW AACounter(game, game->mLayers->actionLayer()->getMaxId(), source, (MTGCardInstance*)target,"", counter->name.c_str(), counter->power, counter->toughness, 1,0);
MTGAbility * a = NEW AACounter(game, game->mLayers->actionLayer()->getMaxId(), source, cTarget,"", counter->name.c_str(), counter->power, counter->toughness, 1,0);
a->oneShot = true;
pcounters.push_back(a);
}
@@ -651,13 +655,13 @@ int AAFizzler::resolve()
//ai is casting a spell from its hand to fizzle.
target = stack->getActionElementFromCard(source->target);
}
else if(target->typeAsTarget() == TARGET_CARD)
else if(MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target))
{
//ai targeted using an ability on a card to fizzle.
target = stack->getActionElementFromCard((MTGCardInstance*)target);
target = stack->getActionElementFromCard(cTarget);
}
Spell * sTarget = (Spell *) target;
MTGCardInstance* sCard = (MTGCardInstance*)sTarget->source;
MTGCardInstance* sCard = sTarget->source;
if(!sCard || !sTarget || sCard->has(Constants::NOFIZZLE))
return 0;
stack->Fizzle(sTarget);
@@ -1062,7 +1066,7 @@ int AADynamic::resolve()
_target = OriginalSrc->controller()->opponent();//looking at controllers opponent for amount
if(!_target)
return 0;
while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next)
while (dynamic_cast<MTGCardInstance *>(_target) && ((MTGCardInstance *)_target)->next)
_target = ((MTGCardInstance *)_target)->next;
//find the amount variables that will be used
@@ -1178,7 +1182,7 @@ int AADynamic::resolve()
}
if (_target)
{
while (_target->typeAsTarget() == TARGET_CARD && ((MTGCardInstance *)_target)->next)
while (dynamic_cast<MTGCardInstance *>(_target) && ((MTGCardInstance *)_target)->next)
_target = ((MTGCardInstance *)_target)->next;
if(sourceamount < 0)
sourceamount = 0;
@@ -1306,7 +1310,7 @@ int AADynamic::resolve()
}
case DYNAMIC_ABILITY_EFFECT_COUNTERSONEONE:
{
if(_target->typeAsTarget() != TARGET_CARD)
if(!dynamic_cast<MTGCardInstance *>(_target))
_target = OriginalSrc;
for(int j = 0;j < sourceamount;j++)
((MTGCardInstance*)_target)->counters->addCounter(1,1);
@@ -2168,8 +2172,10 @@ int IfThenAbility::resolve()
MTGAbility * a1 = delayedAbility->clone();
if (!a1)
return 0;
if(a1->target && a1->target->typeAsTarget() != TARGET_PLAYER)
a1->target = aTarget;
if(a1->target && !dynamic_cast<Player *>(a1->target))
a1->target = aTarget;
if(a1->oneShot)
{
a1->resolve();

View File

@@ -1043,7 +1043,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
if (amp)
{
amp->setCost(cost);
if (cost && card->typeAsTarget() == TARGET_CARD)
if (cost)
cost->setExtraCostsAction(a, card);
amp->oneShot = 0;
amp->tap = doTap;
@@ -3620,10 +3620,13 @@ Player * MTGAbility::getPlayerFromTarget(Targetable * target)
if (!target)
return NULL;
if (target->typeAsTarget() == TARGET_CARD)
return ((MTGCardInstance *) target)->controller();
if (MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target))
return cTarget->controller();
return (Player *) target;
if (Player * cPlayer = dynamic_cast<Player *>(target))
return cPlayer;
return ((Interruptible *) target)->source->controller();
}
Player * MTGAbility::getPlayerFromDamageable(Damageable * target)
@@ -3770,8 +3773,8 @@ int ActivatedAbility::reactToTargetClick(Targetable * object)
ManaCost * cost = getCost();
if (cost)
{
if (object->typeAsTarget() == TARGET_CARD)
cost->setExtraCostsAction(this, (MTGCardInstance *) object);
if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
cost->setExtraCostsAction(this, cObject);
if (!cost->isExtraPaymentSet())
{
game->mExtraPayment = cost->extraCosts;
@@ -3891,8 +3894,9 @@ TargetAbility::TargetAbility(GameObserver* observer, int id, MTGCardInstance * c
int TargetAbility::reactToTargetClick(Targetable * object)
{
if (object->typeAsTarget() == TARGET_CARD)
return reactToClick((MTGCardInstance *) object);
if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
return reactToClick(cObject);
if (waitingForAnswer)
{
if (tc->toggleTarget(object) == TARGET_OK_FULL)
@@ -3976,7 +3980,7 @@ int TargetAbility::resolve()
ability->target = t;
//do nothing if the target controller responded by phasing out the target.
if (t->typeAsTarget() == TARGET_CARD && ((MTGCardInstance*)t)->isPhased)
if (dynamic_cast<MTGCardInstance *>(t) && ((MTGCardInstance*)t)->isPhased)
return 0;
if (ability->oneShot)
{
@@ -4575,21 +4579,12 @@ int AManaProducer::isReactingToClick(MTGCardInstance * _card, ManaCost * mana)
int AManaProducer::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
player->getManaPool()->add(output, source);
return 1;
}
return 0;
Player * player = getPlayerFromTarget(_target);
if (!player)
return 0;
player->getManaPool()->add(output, source);
return 1;
}
int AManaProducer::reactToClick(MTGCardInstance * _card)
@@ -4672,19 +4667,7 @@ Targetable * AbilityTP::getTarget()
switch (who)
{
case TargetChooser::TARGET_CONTROLLER:
if (target)
{
switch (target->typeAsTarget())
{
case TARGET_CARD:
return ((MTGCardInstance *) target)->controller();
case TARGET_STACKACTION:
return ((Interruptible *) target)->source->controller();
default:
return (Player *) target;
}
}
return NULL;
return getPlayerFromTarget(target);
case TargetChooser::CONTROLLER:
return source->controller();
case TargetChooser::OPPONENT:
@@ -4709,19 +4692,7 @@ Targetable * ActivatedAbilityTP::getTarget()
switch (who)
{
case TargetChooser::TARGET_CONTROLLER:
if (target)
{
switch (target->typeAsTarget())
{
case TARGET_CARD:
return ((MTGCardInstance *) target)->controller();
case TARGET_STACKACTION:
return ((Interruptible *) target)->source->controller();
default:
return (Player *) target;
}
}
return NULL;
return getPlayerFromTarget(target);
case TargetChooser::CONTROLLER:
return source->controller();
case TargetChooser::OPPONENT:
@@ -4747,19 +4718,7 @@ Targetable * InstantAbilityTP::getTarget()
switch (who)
{
case TargetChooser::TARGET_CONTROLLER:
if (target)
{
switch (target->typeAsTarget())
{
case TARGET_CARD:
return ((MTGCardInstance *) target)->controller();
case TARGET_STACKACTION:
return ((Interruptible *) target)->source->controller();
default:
return (Player *) target;
}
}
return NULL;
return getPlayerFromTarget(target);
case TargetChooser::CONTROLLER:
return source->controller();
case TargetChooser::OPPONENT:

View File

@@ -1877,52 +1877,53 @@ PermanentAbility(observer, _id)
int MTGVampireRule::receiveEvent(WEvent * event)
{
WEventDamage * e = dynamic_cast<WEventDamage *> (event);
WEventZoneChange * z = dynamic_cast<WEventZoneChange *> (event);
WEventPhaseChange * pe = dynamic_cast<WEventPhaseChange*>(event);
if (e)
if (WEventDamage * e = dynamic_cast<WEventDamage *> (event))
{
if(!e->damage->damage)
return 0;
if (!e->damage->target)
return 0;
if(e->damage->target->typeAsTarget() != TARGET_CARD)
MTGCardInstance * newVictim = dynamic_cast<MTGCardInstance*>(e->damage->target);
if(!newVictim)
return 0;
MTGCardInstance * newVictem = (MTGCardInstance*)(e->damage->target);
MTGCardInstance * vampire = (MTGCardInstance*)(e->damage->source);
victems[newVictem].push_back(vampire);
victims[newVictim].push_back(vampire);
}
else if (z)
else if ( WEventZoneChange * z = dynamic_cast<WEventZoneChange *> (event))
{
MTGCardInstance * card = z->card->previous;
if(card && victems[card].empty())
if(card && victims[card].empty())
return 0;
std::sort(victems[card].begin(), victems[card].end());
victems[card].erase(std::unique(victems[card].begin(), victems[card].end()), victems[card].end());
//sort and remove duplicates, we only want one event of a vampire damaging a card stored per victem.
for(unsigned int w = 0;w < victems[card].size();w++)
std::sort(victims[card].begin(), victims[card].end());
victims[card].erase(std::unique(victims[card].begin(), victims[card].end()), victims[card].end());
for(unsigned int w = 0;w < victims[card].size();w++)
{
if(victems[card].at(w) == NULL)
if(victims[card].at(w) == NULL)
continue;
Player * p = card->controller();
if (z->from == p->game->inPlay && z->to == p->game->graveyard)
{
if(card == z->card->previous)
{
WEvent * e = NEW WEventVampire(card,victems[card].at(w),card);
WEvent * e = NEW WEventVampire(card,victims[card].at(w),card);
game->receiveEvent(e);
}
}
}
return 0;
}
else if (pe)
else if (WEventPhaseChange * pe = dynamic_cast<WEventPhaseChange*>(event))
{
if( pe->from->id == Constants::MTG_PHASE_ENDOFTURN)
{
victems.clear();
victims.clear();
}
}
return 0;

View File

@@ -467,16 +467,17 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
size_t start = attribute.find("share!");
size_t end = attribute.rfind("!");
string CDtype = attribute.substr(start + 6,end - start);
if( card && card->isSpell() && card->backupTargets.size() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION)
if( card && card->isSpell() && card->backupTargets.size())
{
//spells always store their targets in :targets[]
//however they are all erased as the spell resolves
//added a array to store these backups incase theyre needed
//again for effects such as these.
Spell * spell;
spell = (Spell*)card->backupTargets[0];
if(spell)
card->target = spell->source;
if (Spell * targetSpell = dynamic_cast<Spell *>(card->backupTargets[0]))
{
//spells always store their targets in :targets[]
//however they are all erased as the spell resolves
//added a array to store these backups incase theyre needed
//again for effects such as these.
card->target = targetSpell->source;
}
}
if( CDtype.find("name") != string::npos )
{
@@ -715,9 +716,8 @@ TargetChooser::TargetChooser(GameObserver *observer, MTGCardInstance * card, int
bool TargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!target) return false;
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
MTGCardInstance * card = (MTGCardInstance *) target;
if (other)
{
MTGCardInstance * tempcard = card;
@@ -747,7 +747,9 @@ bool TargetChooser::canTarget(Targetable * target,bool withoutProtections)
}
return true;
}
else if (target->typeAsTarget() == TARGET_STACKACTION) return true;
else if (dynamic_cast<Interruptible *>(target))
return true;
return false;
}
@@ -875,10 +877,12 @@ CardTargetChooser::CardTargetChooser(GameObserver *observer, MTGCardInstance * _
bool CardTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!target) return false;
if (target->typeAsTarget() != TARGET_CARD) return false;
MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target);
if (!card) return false;
if (!nbzones && !TargetChooser::canTarget(target,withoutProtections)) return false;
if (nbzones && !TargetZoneChooser::canTarget(target,withoutProtections)) return false;
MTGCardInstance * card = (MTGCardInstance *) target;
while (card)
{
if (card == validTarget) return true;
@@ -953,9 +957,8 @@ void TypeTargetChooser::addType(int type)
bool TypeTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetZoneChooser::canTarget(target,withoutProtections)) return false;
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
MTGCardInstance * card = (MTGCardInstance *) target;
for (int i = 0; i < nbtypes; i++)
{
@@ -967,9 +970,9 @@ bool TypeTargetChooser::canTarget(Targetable * target,bool withoutProtections)
}
return false;
}
else if (target->typeAsTarget() == TARGET_STACKACTION)
else if (Interruptible * action = dynamic_cast<Interruptible *>(target))
{
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
@@ -1049,15 +1052,13 @@ DescriptorTargetChooser::DescriptorTargetChooser(GameObserver *observer, CardDes
bool DescriptorTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetZoneChooser::canTarget(target,withoutProtections)) return false;
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * _target = dynamic_cast<MTGCardInstance *>(target))
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (cd->match(_target))
return true;
}
else if (target->typeAsTarget() == TARGET_STACKACTION)
else if (Interruptible * action = dynamic_cast<Interruptible *>(target))
{
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
@@ -1126,22 +1127,19 @@ int TargetZoneChooser::setAllZones()
bool TargetZoneChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetChooser::canTarget(target,withoutProtections)) return false;
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
MTGCardInstance * card = (MTGCardInstance *) target;
for (int i = 0; i < nbzones; i++)
{
if (zones[i] == MTGGameZone::ALL_ZONES) return true;
if (MTGGameZone::intToZone(observer, zones[i], source, card)->hasCard(card)) return true;
}
}
else if (target->typeAsTarget() == TARGET_STACKACTION)
else if (Spell * spell = dynamic_cast<Spell *>(target))
{
DebugTrace("CHECKING INTERRUPTIBLE\n");
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
DebugTrace("CHECKING Spell\n");
if (spell->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
MTGCardInstance * card = spell->source;
for (int i = 0; i < nbzones; i++)
if (MTGGameZone::intToZone(Owner->getObserver(), zones[i], source, card)->hasCard(card)) return true;
@@ -1217,7 +1215,9 @@ bool PlayerTargetChooser::canTarget(Targetable * target,bool withoutProtections)
if (source && targetter && (targetter->controller() == targetter->controller())
&& (targetter->controller()->game->inPlay->hasAbility(Constants::PLAYERSHROUD)) && targetter->controller()
== target) return false;
return (target->typeAsTarget() == TARGET_PLAYER) && (!p || p == (Player*) target);
Player * pTarget = dynamic_cast<Player *>(target);
return (pTarget && (!p || p == pTarget));
}
PlayerTargetChooser* PlayerTargetChooser::clone() const
@@ -1251,7 +1251,7 @@ bool DamageableTargetChooser::canTarget(Targetable * target,bool withoutProtecti
if (source && targetter && (targetter->controller() == targetter->controller())
&& (targetter->controller()->game->inPlay->hasAbility(Constants::PLAYERSHROUD)) && targetter->controller()
== target) return false;
if (target->typeAsTarget() == TARGET_PLAYER)
if (dynamic_cast<Player *>(target))
{
return true;
}
@@ -1284,16 +1284,14 @@ SpellTargetChooser::SpellTargetChooser(GameObserver *observer, MTGCardInstance *
bool SpellTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_STACKACTION)
Spell * spell = dynamic_cast<Spell *>(target);
if (!spell)
return false;
if (spell->state == NOT_RESOLVED)
{
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 true;
}
MTGCardInstance * card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
return false;
@@ -1329,19 +1327,16 @@ SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(GameObserver *obser
bool SpellOrPermanentTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
card = (MTGCardInstance *) target;
if (color == -1 || card->hasColor(color)) return TargetZoneChooser::canTarget(target,withoutProtections);
}
else if (target->typeAsTarget() == TARGET_STACKACTION)
else if (Spell * spell = dynamic_cast<Spell *>(target))
{
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
if (spell->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
card = spell->source;
MTGCardInstance * card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
}
@@ -1377,14 +1372,11 @@ DamageTargetChooser::DamageTargetChooser(GameObserver *observer, MTGCardInstance
bool DamageTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
MTGCardInstance * card = NULL;
if (target->typeAsTarget() == TARGET_STACKACTION)
if ( Damage * damage = dynamic_cast<Damage *>(target))
{
Interruptible * action = (Interruptible *) target;
if (action->type == ACTION_DAMAGE && (action->state == state || state == -1))
if (damage->state == state || state == -1)
{
Damage * damage = (Damage *) action;
card = damage->source;
MTGCardInstance * card = damage->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
}
@@ -1450,16 +1442,14 @@ bool TriggerTargetChooser::equals(TargetChooser * tc)
/*Proliferate Target */
bool ProliferateChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (target->typeAsTarget() == TARGET_CARD)
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
MTGCardInstance * card = (MTGCardInstance*)target;
if(card->counters && card->counters->counters.empty())
return false;
return true;
}
if (target->typeAsTarget() == TARGET_PLAYER)
else if (Player * p = dynamic_cast<Player*>(target))
{
Player * p = (Player*)target;
if(!p->poisonCount)
return false;
return true;
@@ -1486,9 +1476,8 @@ bool ProliferateChooser::equals(TargetChooser * tc)
/*parents or children Target */
bool ParentChildChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (target->typeAsTarget() == TARGET_CARD)
{
MTGCardInstance * card = (MTGCardInstance*)target;
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if(type == 1)
{
if(!source->childrenCards.size())

View File

@@ -24,7 +24,7 @@ int TargetsList::addTarget(Targetable * target)
if(!tc || (tc && tc->maxtargets == 1))
{
//because this was originally coded with targets as an array
//we have to add this condiational to insure that cards with single target effects
//we have to add this conditional to insure that cards with single target effects
//and abilities that seek the nextcardtarget still work correctly.
targets.clear();
targets.push_back(target);
@@ -76,46 +76,66 @@ int TargetsList::toggleTarget(Targetable * target)
}
}
Targetable * TargetsList::getNextTarget(Targetable * previous, int type)
{
int found = 0;
if (!previous) found = 1;
for (size_t i = 0; i < targets.size(); i++)
{
if (found && (type == -1 || targets[i]->typeAsTarget() == type))
{
return targets[i];
}
if (targets[i] == previous) found = 1;
size_t TargetsList::iterateTarget(Targetable * previous){
if (!previous)
return 0;
for (size_t i = 0; i < targets.size(); i++) {
if (targets[i] == previous)
return i + 1;
}
return targets.size() + 1;
}
Targetable * TargetsList::getNextTarget(Targetable * previous)
{
size_t nextIndex = iterateTarget(previous);
if (nextIndex < targets.size())
return targets[nextIndex];
return NULL;
}
MTGCardInstance * TargetsList::getNextCardTarget(MTGCardInstance * previous)
{
return ((MTGCardInstance *) getNextTarget(previous, TARGET_CARD));
size_t nextIndex = iterateTarget(previous);
for (size_t i = nextIndex; i < targets.size(); ++i)
{
if (MTGCardInstance * c = dynamic_cast<MTGCardInstance *>(targets[i]))
return c;
}
return NULL;
}
Player * TargetsList::getNextPlayerTarget(Player * previous)
{
return ((Player *) getNextTarget(previous, TARGET_PLAYER));
size_t nextIndex = iterateTarget(previous);
for (size_t i = nextIndex; i < targets.size(); ++i)
{
if (Player * p = dynamic_cast<Player *>(targets[i]))
return p;
}
return NULL;
}
Interruptible * TargetsList::getNextInterruptible(Interruptible * previous, int type)
{
int found = 0;
if (!previous) found = 1;
for (size_t i = 0; i < targets.size(); i++)
size_t nextIndex = iterateTarget(previous);
for (size_t i = nextIndex; i < targets.size(); i++)
{
if (found && targets[i]->typeAsTarget() == TARGET_STACKACTION)
if (Interruptible * action = dynamic_cast<Interruptible *>(targets[i]))
{
Interruptible * action = (Interruptible *) targets[i];
if (action->type == type)
{
return action;
}
}
if (targets[i] == previous) found = 1;
}
return NULL;
}
@@ -135,32 +155,17 @@ Damage * TargetsList::getNextDamageTarget(Damage * previous)
Damageable * TargetsList::getNextDamageableTarget(Damageable * previous)
{
int found = 0;
if (!previous) found = 1;
for (size_t i = 0; i < targets.size(); i++)
size_t nextIndex = iterateTarget(previous);
for (size_t i = nextIndex; i < targets.size(); i++)
{
if (targets[i]->typeAsTarget() == TARGET_PLAYER)
if (Player * pTarget = dynamic_cast<Player *>(targets[i]))
{
if (found)
{
return ((Player *) targets[i]);
}
else
{
if ((Player *) targets[i] == previous) found = 1;
}
return pTarget;
}
else if (targets[i]->typeAsTarget() == TARGET_CARD)
else if (MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(targets[i]))
{
if (found)
{
return ((MTGCardInstance *) targets[i]);
}
else
{
if ((MTGCardInstance *) targets[i] == previous) found = 1;
}
return cTarget;
}
}
return NULL;