From 851e1f20f1ab76667d1c5226147d4baec1c38b6c Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Sat, 19 Nov 2011 14:07:57 +0000 Subject: [PATCH] - 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 :( --- projects/mtg/include/AIPlayerBaka.h | 1 + projects/mtg/include/ActionStack.h | 7 +- projects/mtg/include/MTGCardInstance.h | 1 - projects/mtg/include/MTGRules.h | 2 +- projects/mtg/include/Player.h | 4 - projects/mtg/include/Targetable.h | 5 -- projects/mtg/include/TargetsList.h | 4 +- projects/mtg/src/AIPlayer.cpp | 62 +++++--------- projects/mtg/src/AIPlayerBaka.cpp | 107 +++++++++++------------- projects/mtg/src/ActionElement.cpp | 8 +- projects/mtg/src/ActionStack.cpp | 7 +- projects/mtg/src/AllAbilities.cpp | 30 ++++--- projects/mtg/src/MTGAbility.cpp | 85 +++++-------------- projects/mtg/src/MTGRules.cpp | 33 ++++---- projects/mtg/src/TargetChooser.cpp | 111 +++++++++++-------------- projects/mtg/src/TargetsList.cpp | 87 ++++++++++--------- 16 files changed, 237 insertions(+), 317 deletions(-) diff --git a/projects/mtg/include/AIPlayerBaka.h b/projects/mtg/include/AIPlayerBaka.h index 42b0a30e8..ca20c5e90 100644 --- a/projects/mtg/include/AIPlayerBaka.h +++ b/projects/mtg/include/AIPlayerBaka.h @@ -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 gotPayment = vector()); virtual int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0); virtual ManaCost * getPotentialMana(MTGCardInstance * card = NULL); diff --git a/projects/mtg/include/ActionStack.h b/projects/mtg/include/ActionStack.h index ee9b81328..927e2501b 100644 --- a/projects/mtg/include/ActionStack.h +++ b/projects/mtg/include/ActionStack.h @@ -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(); }; diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index c5e40899a..642d03fbb 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -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 backupTargets; diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index 9016f4fe6..492ff170d 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -250,7 +250,7 @@ class MTGVampireRule: public PermanentAbility { public: MTGVampireRule(GameObserver* observer, int _id); - map > victems; + map > victims; int receiveEvent(WEvent * event); virtual ostream& toString(ostream& out) const; virtual MTGVampireRule * clone() const; diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index a5dfb2160..4f0824ff1 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -48,10 +48,6 @@ public: return 1; } const string getDisplayName() const; - int typeAsTarget() - { - return TARGET_PLAYER; - } int afterDamage(); diff --git a/projects/mtg/include/Targetable.h b/projects/mtg/include/Targetable.h index 68b3d5996..c67e4c789 100644 --- a/projects/mtg/include/Targetable.h +++ b/projects/mtg/include/Targetable.h @@ -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; }; diff --git a/projects/mtg/include/TargetsList.h b/projects/mtg/include/TargetsList.h index afc67bb56..922979d13 100644 --- a/projects/mtg/include/TargetsList.h +++ b/projects/mtg/include/TargetsList.h @@ -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(); diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 18f2092ec..1c7ad29ca 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -98,24 +98,17 @@ int AIAction::clickMultiAct(vector& 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(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& potentia vector::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(*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(*ite)) { clickstream.push(NEW AIAction(this, pTarget)); DebugTrace("Ai clicked Player as a target"); @@ -192,26 +184,18 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector& potentia int AIPlayer::clickSingleTarget(TargetChooser * tc, vector& 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(potentialTargets[i])) + { + if (!chosenCard) + clickstream.push(NEW AIAction(this, card)); + } + else if(Player * player = dynamic_cast(potentialTargets[i])) + { + clickstream.push(NEW AIAction(this, player)); + } + return 1; } diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index 8a124db6e..84bb2eb38 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -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(_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(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(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(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::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(potentialTargets[0]); - if(targeting && targeting->typeAsTarget() == TARGET_CARD) - check = NEW OrderedAIAction(this, a,c,targeting); + MTGCardInstance * cTargeting = dynamic_cast(potentialTargets[0]); + if(cTargeting) + check = NEW OrderedAIAction(this, a,c,cTargeting); - Player * ptargeting = dynamic_cast(potentialTargets[0]); - if(ptargeting && ptargeting->typeAsTarget() == TARGET_PLAYER) - check = NEW OrderedAIAction(this, a,ptargeting,c); + Player * pTargeting = dynamic_cast(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(realTargets[0]); + aiAction.playerAbilityTarget = dynamic_cast(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(ability->target)) + check = NEW OrderedAIAction(this, ability, ability->source, cTarget); + else if(Player * pTarget = dynamic_cast(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(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; } } } diff --git a/projects/mtg/src/ActionElement.cpp b/projects/mtg/src/ActionElement.cpp index 57a9ee6e2..2d6c33c1b 100644 --- a/projects/mtg/src/ActionElement.cpp +++ b/projects/mtg/src/ActionElement.cpp @@ -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(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(object)) + return reactToClick(cObject); return 0; } diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 020103499..b898a528d 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -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(_target) || dynamic_cast(_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() diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 8fada24ef..e3408f11e 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -568,19 +568,23 @@ int AAProliferate::resolve() return 0; vectorpcounters; - if(target->typeAsTarget() == TARGET_PLAYER && ((Player*)target)->poisonCount && target != source->controller()) + + Player * pTarget = dynamic_cast(target); + MTGCardInstance * cTarget = dynamic_cast(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(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(_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(_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(_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(a1->target)) + a1->target = aTarget; + if(a1->oneShot) { a1->resolve(); diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 089dce1b2..bc7b1c4f8 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -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(target)) + return cTarget->controller(); - return (Player *) target; + if (Player * cPlayer = dynamic_cast(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(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(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(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: diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 995bf6f25..3cbcaa36c 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -1877,52 +1877,53 @@ PermanentAbility(observer, _id) int MTGVampireRule::receiveEvent(WEvent * event) { - WEventDamage * e = dynamic_cast (event); - WEventZoneChange * z = dynamic_cast (event); - WEventPhaseChange * pe = dynamic_cast(event); - if (e) + if (WEventDamage * e = dynamic_cast (event)) { if(!e->damage->damage) return 0; if (!e->damage->target) return 0; - if(e->damage->target->typeAsTarget() != TARGET_CARD) + + MTGCardInstance * newVictim = dynamic_cast(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 (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(event)) { if( pe->from->id == Constants::MTG_PHASE_ENDOFTURN) { - victems.clear(); + victims.clear(); } } return 0; diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index ad8c2df59..0d62784f7 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -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(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(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(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(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(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(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(target)) { - MTGCardInstance * _target = (MTGCardInstance *) target; if (cd->match(_target)) return true; } - else if (target->typeAsTarget() == TARGET_STACKACTION) + else if (Interruptible * action = dynamic_cast(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(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(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(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(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(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(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(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(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(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(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(target)) + { if(type == 1) { if(!source->childrenCards.size()) diff --git a/projects/mtg/src/TargetsList.cpp b/projects/mtg/src/TargetsList.cpp index da03a4dc0..020cfc8c8 100644 --- a/projects/mtg/src/TargetsList.cpp +++ b/projects/mtg/src/TargetsList.cpp @@ -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(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(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(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(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(targets[i])) { - if (found) - { - return ((MTGCardInstance *) targets[i]); - } - else - { - if ((MTGCardInstance *) targets[i] == previous) found = 1; - } + return cTarget; } } return NULL;