added a "while " tag for aslongas effects which are not supposed to be treated as oneshot abilities. adding it as a tag allows for maximum flexibility in the code.
while i was at it reworked the aslongas class completely, i promised myself if another bug popped up with aslongas i would rewrite it. 20 hours later, we have an aslongas which does not care about when cards come or go.
aslongas should never have used the added/removed to determine the validity of its effect. i allow update to sort it out now in the update function of aslongas...also added a new function to it called sorterfunction tho it looks as it could be reduced in code i would appreciate that it remains as it is, simply because of the nightmare i went through fixing the previous 7 bugs or more reported for aslongas. the logic was far to jumbled up. this i hope is atleast cleaner and easier to understand for the future devs that might work on it.
note: all test passed, all manual testing also passed.
new while tag is used as follows.
[card]
name=Emperor Crocodile
auto=aslongas(other creature|myBattlefield) all(this) sacrifice while <1
text=When you control no other creatures, sacrifice Emperor Crocodile.
mana={3}{G}
type=Creature
subtype=Crocodile
power=5
toughness=5
[/card]
this will denote that the ability is NOT a oneshot ability and should remain effective for the entire time the card is in the field.
Issue: 613
This commit is contained in:
@@ -2347,9 +2347,10 @@ public:
|
|||||||
MTGAbility * a;
|
MTGAbility * a;
|
||||||
int includeSelf;
|
int includeSelf;
|
||||||
int mini, maxi;
|
int mini, maxi;
|
||||||
|
bool miniFound, maxiFound;
|
||||||
AAsLongAs(int _id, MTGCardInstance * _source, Damageable * _target, TargetChooser * _tc, int _includeSelf,
|
AAsLongAs(int _id, MTGCardInstance * _source, Damageable * _target, TargetChooser * _tc, int _includeSelf,
|
||||||
MTGAbility * ability, int mini = 0, int maxi = 0) :
|
MTGAbility * ability, int mini = 0, int maxi = 0,bool miniFound = false,bool maxiFound = false) :
|
||||||
ListMaintainerAbility(_id, _source, _target), NestedAbility(ability), mini(mini), maxi(maxi)
|
ListMaintainerAbility(_id, _source, _target), NestedAbility(ability), mini(mini), maxi(maxi),miniFound(miniFound),maxiFound(maxiFound)
|
||||||
{
|
{
|
||||||
tc = _tc;
|
tc = _tc;
|
||||||
includeSelf = _includeSelf;
|
includeSelf = _includeSelf;
|
||||||
@@ -2359,34 +2360,70 @@ public:
|
|||||||
a = NULL;
|
a = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int canBeInList(MTGCardInstance * card)
|
void Update(float dt)
|
||||||
{
|
{
|
||||||
if(card->isPhased || source->isPhased)
|
ListMaintainerAbility::Update(dt);
|
||||||
return 0;
|
if(!ability->oneShot)
|
||||||
int size = 0;
|
SorterFunction();
|
||||||
size = (int) cards.size();
|
|
||||||
if (includeSelf && maxi && card == source && size > maxi)
|
}
|
||||||
{
|
|
||||||
removed(card);
|
int SorterFunction()
|
||||||
}
|
|
||||||
if ((includeSelf || card != source) && tc->canTarget(card))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int resolve()
|
|
||||||
{
|
{
|
||||||
//TODO check if ability is oneShot ?
|
|
||||||
updateTargets();
|
updateTargets();
|
||||||
int size = (int) cards.size();
|
int size = 0;
|
||||||
if (maxi && size < maxi && (!mini || size > mini)) addAbilityToGame(); //special case for 0
|
size = (int) cards.size();
|
||||||
if (ability->oneShot) a = NULL; //allows to call the effect several times
|
/////////////////DO NOT REFACTOR THIS SECTION/////////////////////////////////////////
|
||||||
|
//these were seperated becuase previous methods were far too confusing to understand//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if (miniFound)
|
||||||
|
{
|
||||||
|
if (size > mini)
|
||||||
|
{
|
||||||
|
addAbilityToGame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeAbilityFromGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxiFound)
|
||||||
|
{
|
||||||
|
if (size < maxi)
|
||||||
|
{
|
||||||
|
addAbilityToGame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeAbilityFromGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
cards.clear();
|
cards.clear();
|
||||||
players.clear();
|
players.clear();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int canBeInList(MTGCardInstance * card)
|
||||||
|
{
|
||||||
|
if(card->isPhased || source->isPhased)
|
||||||
|
return 0;
|
||||||
|
if ((includeSelf || card != source) && tc->canTarget(card))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//////////resolve is used when the aslongas is nested, or used on instants and sorceries/////////
|
||||||
|
int resolve()
|
||||||
|
{
|
||||||
|
SorterFunction();
|
||||||
|
if (ability->oneShot)
|
||||||
|
{
|
||||||
|
a = NULL; //allows to call the effect several times
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int addAbilityToGame()
|
int addAbilityToGame()
|
||||||
{
|
{
|
||||||
if (a) return 0;
|
if (a) return 0;
|
||||||
@@ -2410,52 +2447,36 @@ public:
|
|||||||
a = NULL;
|
a = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/////////////////section required/////////////////////
|
||||||
int _added(Damageable * d)
|
|
||||||
{
|
|
||||||
int size = (int) cards.size();
|
|
||||||
if (maxi && size >= maxi) return removeAbilityFromGame();
|
|
||||||
if (maxi) return 0;
|
|
||||||
if (size <= mini) return 0;
|
|
||||||
return addAbilityToGame();
|
|
||||||
}
|
|
||||||
|
|
||||||
int added(MTGCardInstance * card)
|
int added(MTGCardInstance * card)
|
||||||
{
|
{
|
||||||
return _added(card);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int added(Player * p)
|
int added(Player * p)
|
||||||
{
|
{
|
||||||
return _added(p);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int removed(MTGCardInstance * card)
|
int removed(MTGCardInstance * card)
|
||||||
{
|
{
|
||||||
size_t size = cards.size();
|
return 1;
|
||||||
if (maxi && (int) size < maxi) return addAbilityToGame();
|
|
||||||
if (mini && (int) size > mini) return 0;
|
|
||||||
if (mini && (int) size <= mini) return removeAbilityFromGame();
|
|
||||||
if (!mini && !maxi && size != 0) return 0;
|
|
||||||
return removeAbilityFromGame();
|
|
||||||
}
|
}
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
~AAsLongAs()
|
~AAsLongAs()
|
||||||
{
|
{
|
||||||
if (!isClone)
|
if (!isClone)
|
||||||
SAFE_DELETE(ability);
|
SAFE_DELETE(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * getMenuText()
|
const char * getMenuText()
|
||||||
{
|
{
|
||||||
if(ability)
|
if(ability)
|
||||||
{
|
{
|
||||||
return ability->getMenuText();
|
return ability->getMenuText();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return "Ability";
|
return "Ability";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AAsLongAs * clone() const
|
AAsLongAs * clone() const
|
||||||
|
|||||||
@@ -1291,6 +1291,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
oneShot = 1;
|
oneShot = 1;
|
||||||
if (a->oneShot)
|
if (a->oneShot)
|
||||||
oneShot = 1;
|
oneShot = 1;
|
||||||
|
found = s.find("while ");
|
||||||
|
if (found != string::npos)
|
||||||
|
oneShot = 0;
|
||||||
Damageable * _target = NULL;
|
Damageable * _target = NULL;
|
||||||
if (spell)
|
if (spell)
|
||||||
_target = spell->getNextDamageableTarget();
|
_target = spell->getNextDamageableTarget();
|
||||||
@@ -1299,14 +1302,22 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
|
|
||||||
int mini = 0;
|
int mini = 0;
|
||||||
int maxi = 0;
|
int maxi = 0;
|
||||||
|
bool miniFound = false;
|
||||||
|
bool maxiFound = false;
|
||||||
|
|
||||||
found = s.find(" >");
|
found = s.find(" >");
|
||||||
if (found != string::npos)
|
if (found != string::npos)
|
||||||
|
{
|
||||||
mini = atoi(s.substr(found + 2, 3).c_str());
|
mini = atoi(s.substr(found + 2, 3).c_str());
|
||||||
|
miniFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
found = s.find(" <");
|
found = s.find(" <");
|
||||||
if (found != string::npos)
|
if (found != string::npos)
|
||||||
|
{
|
||||||
maxi = atoi(s.substr(found + 2, 3).c_str());
|
maxi = atoi(s.substr(found + 2, 3).c_str());
|
||||||
|
maxiFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
@@ -1317,7 +1328,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
result = NEW AForeach(id, card, _target, lordTargets, lordIncludeSelf, a, mini, maxi);
|
result = NEW AForeach(id, card, _target, lordTargets, lordIncludeSelf, a, mini, maxi);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
result = NEW AAsLongAs(id, card, _target, lordTargets, lordIncludeSelf, a, mini, maxi);
|
{
|
||||||
|
if (!miniFound && !maxiFound)//for code without an operator treat as a mini.
|
||||||
|
{
|
||||||
|
miniFound = true;
|
||||||
|
}
|
||||||
|
result = NEW AAsLongAs(id, card, _target, lordTargets, lordIncludeSelf, a, mini, maxi,miniFound,maxiFound);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
result = NEW ATeach(id, card, lordTargets, lordIncludeSelf, a);
|
result = NEW ATeach(id, card, lordTargets, lordIncludeSelf, a);
|
||||||
|
|||||||
Reference in New Issue
Block a user