-Fix for issue 583 (fireball crash)
-- converted an array into a vector to avoid weird edge cases -- fixed bugs with array "backupTargets"
This commit is contained in:
@@ -275,6 +275,7 @@ fault_line.txt
|
||||
feral_hydra.txt
|
||||
fieldmist_borderpost.txt
|
||||
fire_tempest.txt
|
||||
fireball_i583.txt
|
||||
firebreathing.txt
|
||||
fists_of_ironwood.txt
|
||||
flagstones.txt
|
||||
|
||||
29
projects/mtg/bin/Res/test/fireball_i583.txt
Normal file
29
projects/mtg/bin/Res/test/fireball_i583.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
#Bug: fireball can crash the game if unselecting a target
|
||||
#see http://code.google.com/p/wagic/issues/detail?id=583
|
||||
#Target 8 creatures and remove 1 of them
|
||||
[INIT]
|
||||
FIRSTMAIN
|
||||
[PLAYER1]
|
||||
hand:fireball
|
||||
manapool:{7}{R}{R}{R}{R}{R}{R}{R}{R}
|
||||
inplay:raging goblin,Akrasan Squire,Alpha Myr,Ambush Party,Apprentice Wizard,Arbor Elf,Aven Squire,Bay Falcon
|
||||
[PLAYER2]
|
||||
[DO]
|
||||
fireball
|
||||
raging goblin
|
||||
Akrasan Squire
|
||||
Alpha Myr
|
||||
Ambush Party
|
||||
Apprentice Wizard
|
||||
Arbor Elf
|
||||
Aven Squire
|
||||
Bay Falcon
|
||||
Alpha Myr
|
||||
fireball
|
||||
[ASSERT]
|
||||
FIRSTMAIN
|
||||
[PLAYER1]
|
||||
graveyard:raging goblin,Akrasan Squire,Ambush Party,Apprentice Wizard,Arbor Elf,Aven Squire,Bay Falcon, Fireball
|
||||
inplay:Alpha Myr
|
||||
[PLAYER2]
|
||||
[END]
|
||||
@@ -1,43 +1,43 @@
|
||||
#ifndef _AIHINTS_H_
|
||||
#define _AIHINTS_H_
|
||||
|
||||
#ifndef _AIHINTS_H_
|
||||
#define _AIHINTS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#include "AIPlayer.h"
|
||||
|
||||
class ManaCost;
|
||||
class MTGAbility;
|
||||
|
||||
class AIHint
|
||||
{
|
||||
public:
|
||||
string mCondition;
|
||||
string mAction;
|
||||
int mSourceId;
|
||||
AIHint(string line);
|
||||
};
|
||||
|
||||
|
||||
class AIHints
|
||||
{
|
||||
protected:
|
||||
AIPlayer * mPlayer;
|
||||
vector<AIHint *> hints;
|
||||
AIHint * getByCondition (string condition);
|
||||
AIAction * findAbilityRecursive(AIHint * hint, ManaCost * potentialMana);
|
||||
vector<MTGAbility *> findAbilities(AIHint * hint);
|
||||
RankingContainer findActions(AIHint * hint);
|
||||
string constraintsNotFulfilled(AIAction * a, AIHint * hint, ManaCost * potentialMana);
|
||||
bool findSource(int sourceId);
|
||||
bool abilityMatches(MTGAbility * a, AIHint * hint);
|
||||
public:
|
||||
AIHints (AIPlayer * player);
|
||||
AIAction * suggestAbility(ManaCost * potentialMana);
|
||||
void add(string line);
|
||||
~AIHints();
|
||||
};
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#include "AIPlayer.h"
|
||||
|
||||
class ManaCost;
|
||||
class MTGAbility;
|
||||
|
||||
class AIHint
|
||||
{
|
||||
public:
|
||||
string mCondition;
|
||||
string mAction;
|
||||
int mSourceId;
|
||||
AIHint(string line);
|
||||
};
|
||||
|
||||
|
||||
class AIHints
|
||||
{
|
||||
protected:
|
||||
AIPlayer * mPlayer;
|
||||
vector<AIHint *> hints;
|
||||
AIHint * getByCondition (string condition);
|
||||
AIAction * findAbilityRecursive(AIHint * hint, ManaCost * potentialMana);
|
||||
vector<MTGAbility *> findAbilities(AIHint * hint);
|
||||
RankingContainer findActions(AIHint * hint);
|
||||
string constraintsNotFulfilled(AIAction * a, AIHint * hint, ManaCost * potentialMana);
|
||||
bool findSource(int sourceId);
|
||||
bool abilityMatches(MTGAbility * a, AIHint * hint);
|
||||
public:
|
||||
AIHints (AIPlayer * player);
|
||||
AIAction * suggestAbility(ManaCost * potentialMana);
|
||||
void add(string line);
|
||||
~AIHints();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
int typeAsTarget(){return TARGET_CARD;}
|
||||
const string getDisplayName() const;
|
||||
MTGCardInstance * target;
|
||||
Targetable * backupTargets[MAX_TARGETS];
|
||||
vector<Targetable *> backupTargets;
|
||||
|
||||
|
||||
//types
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
virtual int full()
|
||||
{
|
||||
if (maxtargets != -1 && cursor >= maxtargets)
|
||||
if (maxtargets != -1 && ((int) (targets.size())) >= maxtargets)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
;
|
||||
virtual int ready()
|
||||
{
|
||||
return cursor;
|
||||
return (int) (targets.size());
|
||||
}
|
||||
;
|
||||
virtual ~TargetChooser()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef _TARGETSLIST_H_
|
||||
#define _TARGETSLIST_H_
|
||||
|
||||
#define MAX_TARGETS 20
|
||||
|
||||
class Targetable;
|
||||
class MTGCardInstance;
|
||||
class Player;
|
||||
@@ -11,13 +9,15 @@ class Spell;
|
||||
class Interruptible;
|
||||
class Damage;
|
||||
|
||||
#include <vector>
|
||||
using std::vector;
|
||||
|
||||
class TargetsList
|
||||
{
|
||||
public:
|
||||
int cursor;
|
||||
TargetsList();
|
||||
TargetsList(Targetable * _targets[], int nbtargets);
|
||||
Targetable* targets[MAX_TARGETS];
|
||||
vector<Targetable*> targets;
|
||||
int alreadyHasTarget(Targetable * target);
|
||||
int removeTarget(Targetable * _card);
|
||||
int toggleTarget(Targetable * _card);
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
Targetable * getNextTarget(Targetable * previous = 0, int type = -1);
|
||||
void initTargets()
|
||||
{
|
||||
cursor = 0;
|
||||
targets.clear();
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
@@ -217,10 +217,12 @@ Interruptible(id), tc(tc), cost(_cost), payResult(payResult)
|
||||
mHeight = 40;
|
||||
type = ACTION_SPELL;
|
||||
from = _source->getCurrentZone();
|
||||
for(int i = 0;i < MAX_TARGETS;i++)
|
||||
|
||||
_source->backupTargets.clear();
|
||||
if (tc)
|
||||
{
|
||||
if(tc && tc->targets[i] != NULL)
|
||||
_source->backupTargets[i] = tc->targets[i];
|
||||
for(size_t i = 0;i < tc->targets.size();i++)
|
||||
_source->backupTargets.push_back(tc->targets[i]);
|
||||
}
|
||||
|
||||
// fill information on how the card came into this zone. Right now the quickest way is to do it here, based on how the mana was paid...
|
||||
@@ -360,7 +362,7 @@ int Spell::getNbTargets()
|
||||
{
|
||||
if (!tc)
|
||||
return 0;
|
||||
return tc->cursor;
|
||||
return (int) (tc->targets.size());
|
||||
}
|
||||
|
||||
void Spell::Render()
|
||||
|
||||
@@ -1762,9 +1762,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
found = s.find("wingame");
|
||||
if (found != string::npos)
|
||||
{
|
||||
Damageable * d = NULL;
|
||||
if (spell)
|
||||
d = spell->getNextDamageableTarget();
|
||||
Damageable * d = spell ? spell->getNextDamageableTarget() : NULL;
|
||||
MTGAbility * a = NEW AAWinGame(id, card, d, NULL, who);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
|
||||
@@ -486,7 +486,7 @@ 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[0]->typeAsTarget() == TARGET_STACKACTION)
|
||||
if( card && card->isSpell() && card->backupTargets.size() && card->backupTargets[0]->typeAsTarget() == TARGET_STACKACTION)
|
||||
{
|
||||
//spells always store their targets in :targets[]
|
||||
//however they are all erased as the spell resolves
|
||||
@@ -785,7 +785,7 @@ int TargetChooser::ForceTargetListReady()
|
||||
|
||||
int TargetChooser::targetsReadyCheck()
|
||||
{
|
||||
if (cursor <= 0)
|
||||
if (!targets.size())
|
||||
{
|
||||
return TARGET_NOK;
|
||||
}
|
||||
|
||||
@@ -8,24 +8,19 @@
|
||||
|
||||
TargetsList::TargetsList()
|
||||
{
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
TargetsList::TargetsList(Targetable * _targets[], int nbtargets)
|
||||
{
|
||||
for (int i = 0; i < nbtargets; i++)
|
||||
{
|
||||
targets[i] = _targets[i];
|
||||
}
|
||||
cursor = nbtargets;
|
||||
targets.push_back(_targets[i]);
|
||||
}
|
||||
|
||||
int TargetsList::addTarget(Targetable * target)
|
||||
{
|
||||
if (!alreadyHasTarget(target))
|
||||
{
|
||||
targets[cursor] = target;
|
||||
cursor++;
|
||||
targets.push_back(target);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -34,7 +29,7 @@ int TargetsList::addTarget(Targetable * target)
|
||||
|
||||
int TargetsList::alreadyHasTarget(Targetable * target)
|
||||
{
|
||||
for (int i = 0; i < cursor; i++)
|
||||
for (size_t i = 0; i < targets.size(); i++)
|
||||
{
|
||||
if (targets[i] == target) return 1;
|
||||
}
|
||||
@@ -43,13 +38,12 @@ int TargetsList::alreadyHasTarget(Targetable * target)
|
||||
|
||||
int TargetsList::removeTarget(Targetable * target)
|
||||
{
|
||||
for (int i = 0; i < cursor; i++)
|
||||
for (size_t i = 0; i < targets.size(); i++)
|
||||
{
|
||||
if (targets[i] == target)
|
||||
{
|
||||
targets[i] = targets[cursor];
|
||||
targets[cursor] = NULL;
|
||||
cursor--;
|
||||
targets.erase(targets.begin() + i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +68,7 @@ Targetable * TargetsList::getNextTarget(Targetable * previous, int type)
|
||||
{
|
||||
int found = 0;
|
||||
if (!previous) found = 1;
|
||||
for (int i = 0; i < cursor; i++)
|
||||
for (size_t i = 0; i < targets.size(); i++)
|
||||
{
|
||||
if (found && (type == -1 || targets[i]->typeAsTarget() == type))
|
||||
{
|
||||
@@ -99,7 +93,7 @@ Interruptible * TargetsList::getNextInterruptible(Interruptible * previous, int
|
||||
{
|
||||
int found = 0;
|
||||
if (!previous) found = 1;
|
||||
for (int i = 0; i < cursor; i++)
|
||||
for (size_t i = 0; i < targets.size(); i++)
|
||||
{
|
||||
if (found && targets[i]->typeAsTarget() == TARGET_STACKACTION)
|
||||
{
|
||||
@@ -131,7 +125,7 @@ Damageable * TargetsList::getNextDamageableTarget(Damageable * previous)
|
||||
{
|
||||
int found = 0;
|
||||
if (!previous) found = 1;
|
||||
for (int i = 0; i < cursor; i++)
|
||||
for (size_t i = 0; i < targets.size(); i++)
|
||||
{
|
||||
|
||||
if (targets[i]->typeAsTarget() == TARGET_PLAYER)
|
||||
|
||||
Reference in New Issue
Block a user