Added new features and triggers to game about tokens and counters, fixed and added new primitives.

This commit is contained in:
valfieri
2020-07-10 19:53:46 +02:00
parent fc40971dc7
commit 52e3177ef2
11 changed files with 1042 additions and 732 deletions
+150 -6
View File
@@ -1894,7 +1894,7 @@ AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, M
}
if(!maxNb || (maxNb && currentAmount < maxNb))
{
_target->counters->addCounter(name.c_str(), power, toughness);
_target->counters->addCounter(name.c_str(), power, toughness, false, false, source);
}
}
}
@@ -1904,7 +1904,7 @@ AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, M
{
while (_target->next)
_target = _target->next;
_target->counters->removeCounter(name.c_str(), power, toughness);
_target->counters->removeCounter(name.c_str(), power, toughness, false, false, source);
}
}
@@ -1920,7 +1920,7 @@ AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, M
{
if (_target->counters->counters[i]->cancels(power, toughness) && !name.size() && _target->counters->counters[i]->nb > 0)
{
_target->counters->counters[i]->cancelCounter(power,toughness);
_target->counters->counters[i]->cancelCounter(power,toughness, source);
}
}
}
@@ -2157,8 +2157,147 @@ AARemoveAllCounter * AARemoveAllCounter::clone() const
return NEW AARemoveAllCounter(*this);
}
//remove a single counter of a spefic kind chosen by user
AARemoveSingleCounter::AARemoveSingleCounter(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, ManaCost * cost, int nb) :
ActivatedAbility(observer, id, source, cost, 0), nb(nb)
{
this->GetId();
}
int AARemoveSingleCounter::resolve()
{
if (!target)
return 0;
vector<MTGAbility*>pcounters;
Player * pTarget = dynamic_cast<Player *>(target);
MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target);
if(pTarget && pTarget->poisonCount)
{
MTGAbility * a = NEW AAAlterPoison(game, game->mLayers->actionLayer()->getMaxId(), source, target, -nb, NULL);
a->oneShot = true;
pcounters.push_back(a);
}
else if(pTarget && pTarget->energyCount)
{
MTGAbility * a = NEW AAAlterEnergy(game, game->mLayers->actionLayer()->getMaxId(), source, target, -nb, NULL);
a->oneShot = true;
pcounters.push_back(a);
}
else if (cTarget && cTarget->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, cTarget,"", counter->name.c_str(), counter->power, counter->toughness, -nb, 0);
a->oneShot = true;
pcounters.push_back(a);
}
}
if(pcounters.size())
{
MTGAbility * a = NEW MenuAbility(game, this->GetId(), target, source,false,pcounters);
a->resolve();
}
return 1;
}
const string AARemoveSingleCounter::getMenuText()
{
return "Remove single specific counter";
}
AARemoveSingleCounter * AARemoveSingleCounter::clone() const
{
return NEW AARemoveSingleCounter(*this);
}
AARemoveSingleCounter::~AARemoveSingleCounter()
{
}
//duplicate counters
AADuplicateCounters::AADuplicateCounters(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0)
{
this->GetId();
allcounters = false;
}
int AADuplicateCounters::resolve()
{
if (!target)
return 0;
vector<MTGAbility*>pcounters;
Player * pTarget = dynamic_cast<Player *>(target);
MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target);
if(pTarget && pTarget->poisonCount)
{
MTGAbility * a = NEW AAAlterPoison(game, game->mLayers->actionLayer()->getMaxId(), source, target, pTarget->poisonCount, NULL);
a->oneShot = true;
pcounters.push_back(a);
}
else if(pTarget && pTarget->energyCount)
{
MTGAbility * a = NEW AAAlterEnergy(game, game->mLayers->actionLayer()->getMaxId(), source, target, pTarget->energyCount, NULL);
a->oneShot = true;
pcounters.push_back(a);
}
else if (cTarget && cTarget->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, cTarget,"", counter->name.c_str(), counter->power, counter->toughness, counter->nb, 0);
a->oneShot = true;
pcounters.push_back(a);
}
}
if(pcounters.size())
{
if(allcounters)
{
for(size_t j = 0; j < pcounters.size(); j++)
{
pcounters[j]->resolve();
}
}
else
{
MTGAbility * a = NEW MenuAbility(game, this->GetId(), target, source,false,pcounters);
a->resolve();
}
}
return 1;
}
const string AADuplicateCounters::getMenuText()
{
if(allcounters)
return "Duplicate all Counters";
return "Duplicate specific Counters";
}
AADuplicateCounters * AADuplicateCounters::clone() const
{
return NEW AADuplicateCounters(*this);
}
AADuplicateCounters::~AADuplicateCounters()
{
}
//proliferate a target
AAProliferate::AAProliferate(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,ManaCost * cost) :
AAProliferate::AAProliferate(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0)
{
this->GetId();
@@ -2193,7 +2332,7 @@ int AAProliferate::resolve()
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, cTarget,"", 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);
}
@@ -4366,12 +4505,13 @@ AALifeSet::~AALifeSet()
//AACloner
//cloning...this makes a token thats a copy of the target.
AACloner::AACloner(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int who,
string abilitiesStringList,string TypesList) :
string abilitiesStringList, string TypesList, string optionsList) :
ActivatedAbility(observer, _id, _source, _cost, 0), who(who)
{
aType = MTGAbility::CLONING;
target = _target;
source = _source;
options = optionsList;
if (abilitiesStringList.size() > 0)
{
PopulateAbilityIndexVector(awith, abilitiesStringList);
@@ -4497,6 +4637,10 @@ int AACloner::resolve()
andAbilityClone->addToGame();
}
}
if(options.find("notrigger") == string::npos){ // check if the @tokencreated trigger has to be activated or not
WEvent * e = NEW WEventTokenCreated(spell->source);
source->getObserver()->receiveEvent(e); // triggers the @tokencreated event for any other listener.
}
delete spell;
}
return 1;
+19 -14
View File
@@ -38,14 +38,14 @@ bool Counter::cancels(int _power, int _toughness)
return (power == -_power && toughness == -_toughness);
}
int Counter::cancelCounter(int power, int toughness)
int Counter::cancelCounter(int power, int toughness, MTGCardInstance * _source)
{
while(this->target->counters->hasCounter(power,toughness) && this->target->counters->hasCounter(power*-1,toughness*-1))
{
GameObserver *g = this->target->getObserver();
this->removed();
this->nb--;
WEvent * t = NEW WEventCounters(NULL,"",power*-1,toughness*-1,false,true);
WEvent * t = NEW WEventCounters(NULL,"",power*-1,toughness*-1,false,true,_source);
dynamic_cast<WEventCounters*>(t)->targetCard = this->target;
g->receiveEvent(t);
this->target->counters->removeCounter(power,toughness);
@@ -98,7 +98,7 @@ Counters::~Counters()
}
}
int Counters::addCounter(const char * _name, int _power, int _toughness, bool _noevent)
int Counters::addCounter(const char * _name, int _power, int _toughness, bool _noevent, bool duplicated, MTGCardInstance * _source)
{
/*420.5n If a permanent has both a +1/+1 counter and a -1/-1 counter on it, N +1/+1 and N -1/-1 counters are removed from it, where N is the smaller of the number of +1/+1 and -1/-1 counters on it.*/
GameObserver *g = target->getObserver();
@@ -112,9 +112,12 @@ int Counters::addCounter(const char * _name, int _power, int _toughness, bool _n
{
counters[i]->added();
counters[i]->nb++;
WEvent * j = NEW WEventCounters(this,_name,_power,_toughness,true,false);
dynamic_cast<WEventCounters*>(j)->targetCard = this->target;
g->receiveEvent(j);
if (!duplicated)
{
WEvent * j = NEW WEventCounters(this,_name,_power,_toughness,true,false,_source);
dynamic_cast<WEventCounters*>(j)->targetCard = this->target;
g->receiveEvent(j);
}
delete(e);
return mCount;
}
@@ -122,13 +125,13 @@ int Counters::addCounter(const char * _name, int _power, int _toughness, bool _n
Counter * counter = NEW Counter(target, _name, _power, _toughness);
counters.push_back(counter);
counter->added();
if (!_noevent)
mCount++;
if (!_noevent && !duplicated)
{
WEvent * w = NEW WEventCounters(this,_name,_power,_toughness,true,false);
WEvent * w = NEW WEventCounters(this,_name,_power,_toughness,true,false,_source);
dynamic_cast<WEventCounters*>(w)->targetCard = this->target;
g->receiveEvent(w);
}
mCount++;
/*the damage test should be handled on game state based effect i think*/
//this->target->doDamageTest = 1;
//this->target->afterDamage();
@@ -160,7 +163,7 @@ int Counters::init()
return 1;
}
int Counters::removeCounter(const char * _name, int _power, int _toughness)
int Counters::removeCounter(const char * _name, int _power, int _toughness, bool _noevent, bool duplicated, MTGCardInstance * _source)
{
for (int i = 0; i < mCount; i++)
{
@@ -172,10 +175,12 @@ int Counters::removeCounter(const char * _name, int _power, int _toughness)
counters[i]->removed();
counters[i]->nb--;
GameObserver *g = target->getObserver();
WEvent * e = NEW WEventCounters(this,_name,_power,_toughness,false,true);
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
g->receiveEvent(e);
if (!_noevent && !duplicated)
{
WEvent * e = NEW WEventCounters(this,_name,_power,_toughness,false,true,_source);
dynamic_cast<WEventCounters*>(e)->targetCard = this->target;
g->receiveEvent(e);
}
// special case: when the last time counter is removed from non-suspended card
// sacrifice that card
if (!target->suspended && counters[i]->name == "time" && counters[i]->nb == 0) {
+59 -10
View File
@@ -1072,9 +1072,8 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
fromTc = tcf.createTargetChooser(starget, card);
fromTc->targetter = NULL; //avoid protection from
}
TriggeredAbility * mover = NEW TrCardAddedToZone(observer, id, card, (TargetZoneChooser *) toTc,
toTcCard, (TargetZoneChooser *) fromTc, fromTcCard, once, sourceUntapped, isSuspended, limitOnceATurn);
if(neverRemove)
TriggeredAbility * mover = NEW TrCardAddedToZone(observer, id, card, (TargetZoneChooser *) toTc, toTcCard, (TargetZoneChooser *) fromTc, fromTcCard, once, sourceUntapped, isSuspended, limitOnceATurn);
if(neverRemove && mover)
{
mover->forcedAlive = 1;
mover->forceDestroy = -1;
@@ -1172,6 +1171,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
//Card is mutated
if (TargetChooser * tc = parseSimpleTC(s, "mutated", card))
return NEW TrCardMutated(observer, id, card, tc,once);
//Token has been created
if (TargetChooser * tc = parseSimpleTC(s, "tokencreated", card))
return NEW TrTokenCreated(observer, id, card, tc,once);
//Card is sacrificed
if (TargetChooser * tc = parseSimpleTC(s, "sacrificed", card))
@@ -1331,17 +1334,35 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (s.find("counteradded(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"counteradded(",")");
Counter * counter = parseCounter(splitCounter[1],card,NULL);
Counter * counter = NULL;
bool duplicate = false;
if(s.find("(duplicateall)") != string::npos)
duplicate = true;
else if(s.find("(any)") == string::npos)
counter = parseCounter(splitCounter[1],card,NULL);
TargetChooser * tc = parseSimpleTC(s, "from", card);
return NEW TrCounter(observer, id, card, counter, tc, 1,once);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop (eg. Doubling Season)
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, exception->source);
else
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate);
}
if (s.find("counterremoved(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"counterremoved(",")");
Counter * counter = parseCounter(splitCounter[1],card,NULL);
Counter * counter = NULL;
bool duplicate = false;
if(s.find("(duplicateall)") != string::npos)
duplicate = true;
else if(s.find("(any)") == string::npos)
counter = parseCounter(splitCounter[1],card,NULL);
TargetChooser * tc = parseSimpleTC(s, "from", card);
return NEW TrCounter(observer, id, card, counter, tc, 0,once);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop (eg. Doubling Season)
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, exception->source);
else
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate);
}
int who = 0;
@@ -3047,6 +3068,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
{
string with = "";
string types = "";
string options = "";
vector<string> splitWith = parseBetween(s, "with(", ")");
if (splitWith.size())
{
@@ -3057,7 +3079,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
{
types = splitTypes[1];
}
MTGAbility * a = NEW AACloner(observer, id, card, target, 0, who, with,types);
vector<string> splitOptions = parseBetween(s, "options(", ")");
if (splitOptions.size())
{
options = splitOptions[1];
}
MTGAbility * a = NEW AACloner(observer, id, card, target, 0, who, with, types, options);
a->oneShot = 1;
if(storedAndAbility.size())
{
@@ -3132,7 +3159,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
bool asNormalMadness = splitCastCard[1].find("madness") != string::npos;
bool sendNoEvent = splitCastCard[1].find("noevent") != string::npos;
bool putinplay = splitCastCard[1].find("putinplay") != string::npos;
bool alternative = splitCastCard[1].find("alternative") != string::npos;
bool alternative = splitCastCard[1].find("alternative") != string::npos;
string nameCard = "";
if(splitCastCard[1].find("named!:") != string::npos)
{
@@ -3719,6 +3746,28 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
string splitCounterTrack = splitCounterTracking[1];
return NEW ACounterTracker(observer, id, card, target,splitCounterTrack);
}
//duplicate counters
vector<string> splitDuplicateCounters = parseBetween(s, "duplicatecounters(", ")");
if (splitDuplicateCounters.size())
{
MTGAbility * a = NEW AADuplicateCounters(observer, id, card, target, NULL);
a->oneShot = 1;
a->canBeInterrupted = false;
string counterString = splitDuplicateCounters[1];
if(counterString.find("all") != string::npos)
((AADuplicateCounters*)a)->allcounters = true;
return a;
}
//remove single counter of any type
vector<string> splitRemoveSpecificCounters = parseBetween(s, "removesinglecountertype(", ")");
if (splitRemoveSpecificCounters.size())
{
int nb = atoi(splitRemoveSpecificCounters[1].c_str());
MTGAbility * a = NEW AARemoveSingleCounter(observer, id, card, target, NULL, nb);
a->oneShot = 1;
a->canBeInterrupted = false;
return a;
}
//removes all counters of the specifified type.
vector<string> splitRemoveCounter = parseBetween(s, "removeallcounters(", ")");
if (splitRemoveCounter.size())
@@ -4176,7 +4225,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
((AAProliferate*)a)->allcounters = true;
return a;
}
//frozen, next untap this does not untap.
found = s.find("frozen");
if (found != string::npos)
+2 -2
View File
@@ -911,7 +911,7 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter
ManaCost * Xcost = NEW ManaCost();
Xcost->copy(alternateCost);
Xcost->add(Constants::MTG_COLOR_ARTIFACT, card->setX);
card->X = card->setX; // Fix to don't loose X value on alternative cast
card->X = card->setX; // Fix to don't loose X value on alternative cast
Xcost->remove(7, 1);//remove the X
if (playerMana->canAfford(Xcost))
{
@@ -3414,7 +3414,7 @@ int MTGNewLegend::receiveEvent(WEvent * e)
{
if(card->basicAbilities[(int)Constants::MUTATE] && card->alternateCostPaid[(int)ManaCost::MANA_PAID_WITH_ALTERNATIVE])
return 0; // The Leged rule for Mutating card will be checked later just if it's a Mutation Over choice
CheckLegend(card);
CheckLegend(card);
return 1;
}
}
+13 -2
View File
@@ -43,8 +43,8 @@ WEventCardUpdate::WEventCardUpdate(MTGCardInstance * card) :
}
;
WEventCounters::WEventCounters(Counters *counter,string name,int power,int toughness,bool added,bool removed) :
WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(added),removed(removed)
WEventCounters::WEventCounters(Counters *counter,string name,int power,int toughness,bool added,bool removed, MTGCardInstance* source) :
WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(added),removed(removed),source(source)
{
}
@@ -291,6 +291,11 @@ WEventCardMutated::WEventCardMutated(MTGCardInstance * card) :
WEventCardUpdate(card)
{
}
WEventTokenCreated::WEventTokenCreated(MTGCardInstance * card) :
WEventCardUpdate(card)
{
}
;
Targetable * WEventDamage::getTarget(int target)
@@ -495,6 +500,12 @@ Targetable * WEventCardMutated::getTarget(int target)
return NULL;
}
Targetable * WEventTokenCreated::getTarget(int target)
{
if (target) return card;
return NULL;
}
Targetable * WEventplayerEnergized::getTarget(Player * player)
{
if (player) return player;