fixed a reported bug with @vampired, it was tricky, but ultimately i had to move the building of vampevent outside of TRVampired...the reason being that all instances of TRVamp were able to send and react to other instances of it sending out "vampevents", so move it into rules so only one object handles that, also changed the method it was handled, it now maps the cards with a 2nd vector of the vampires...basically "this card was dealt damage by X, Y, Z this turn"...
let me know if i missed some strange edge case somewhere. as far as i tested, it seems to work just fine.
This commit is contained in:
@@ -749,10 +749,8 @@ class TrVampired: public TriggeredAbility
|
||||
public:
|
||||
TargetChooser * tc;
|
||||
TargetChooser * fromTc;
|
||||
vector<MTGCardInstance*> victems;
|
||||
int type;
|
||||
TrVampired(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0) :
|
||||
TriggeredAbility(id, source), tc(tc), fromTc(fromTc), type(type)
|
||||
TrVampired(int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL) :
|
||||
TriggeredAbility(id, source), tc(tc), fromTc(fromTc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -764,64 +762,17 @@ public:
|
||||
int triggerOnEvent(WEvent * event)
|
||||
{
|
||||
if(source->isPhased) return 0;
|
||||
WEventDamage * e = dynamic_cast<WEventDamage *> (event);
|
||||
WEventZoneChange * z = dynamic_cast<WEventZoneChange *> (event);
|
||||
WEventPhaseChange * pe = dynamic_cast<WEventPhaseChange*>(event);
|
||||
WEventVampire * vamp = dynamic_cast<WEventVampire*>(event);
|
||||
if (e == event)
|
||||
if (vamp)
|
||||
{
|
||||
if (!tc->canTarget(e->damage->target)) return 0;
|
||||
if (fromTc && !fromTc->canTarget(e->damage->source)) return 0;
|
||||
|
||||
MTGCardInstance * newVictem = (MTGCardInstance*)(e->damage->target);
|
||||
|
||||
victems.push_back(newVictem);
|
||||
std::sort(victems.begin(), victems.end());
|
||||
victems.erase(std::unique(victems.begin(), victems.end()), victems.end());
|
||||
}
|
||||
else if (z == event && !victems.empty())
|
||||
{
|
||||
MTGCardInstance * card = z->card;
|
||||
|
||||
|
||||
for(unsigned int k = 0;k < victems.size();k--)
|
||||
{
|
||||
if(victems[k] == NULL)
|
||||
continue;
|
||||
if(victems[k] != z->card->previous)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for(unsigned int w = 0;w < victems.size();w++)
|
||||
{
|
||||
if(victems[w] == NULL)
|
||||
continue;
|
||||
Player * p = victems[w]->controller();
|
||||
if (z->from == p->game->inPlay && z->to == p->game->graveyard)
|
||||
{
|
||||
if(victems[w] == z->card->previous)
|
||||
{
|
||||
if(!source->isInPlay())
|
||||
return 0;
|
||||
WEvent * e = NEW WEventVampire(victems[w],victems[w],source);
|
||||
game->receiveEvent(e);
|
||||
victems[w] = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vamp == event)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (pe == event)
|
||||
{
|
||||
if( pe->from->id == Constants::MTG_PHASE_ENDOFTURN)
|
||||
{
|
||||
victems.clear();
|
||||
}
|
||||
if(fromTc && !fromTc->canTarget(vamp->source))
|
||||
return 0;
|
||||
tc->setAllZones();
|
||||
//creature that were "vampired" only happens in battlefield, and event sent when they hit a grave.
|
||||
//setting allzones, as we don't care since we know the preexisting condiations cover the zones.
|
||||
if(!tc->canTarget(vamp->victem))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -253,6 +253,17 @@ public:
|
||||
int testDestroy();
|
||||
virtual MTGPersistRule * clone() const;
|
||||
};
|
||||
/* vampire Rule */
|
||||
class MTGVampireRule: public MTGAbility
|
||||
{
|
||||
public:
|
||||
MTGVampireRule(int _id);
|
||||
map<MTGCardInstance*,vector<MTGCardInstance*> > victems;
|
||||
int receiveEvent(WEvent * event);
|
||||
virtual ostream& toString(ostream& out) const;
|
||||
int testDestroy();
|
||||
virtual MTGVampireRule * clone() const;
|
||||
};
|
||||
//unearths destruction if leaves play effect
|
||||
class MTGUnearthRule: public MTGAbility
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ void DuelLayers::init()
|
||||
action->Add(NEW MTGPlaneWalkerRule(-1));
|
||||
action->Add(NEW MTGTokensCleanup(-1)); // needs to be before persist
|
||||
action->Add(NEW MTGPersistRule(-1));
|
||||
action->Add(NEW MTGVampireRule(-1));
|
||||
action->Add(NEW MTGUnearthRule(-1));
|
||||
action->Add(NEW MTGLifelinkRule(-1));
|
||||
action->Add(NEW MTGDeathtouchRule(-1));
|
||||
|
||||
@@ -713,7 +713,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string magicText, int
|
||||
fromTc = tcf.createTargetChooser(starget, card);
|
||||
fromTc->targetter = NULL;
|
||||
}
|
||||
return NEW TrVampired(id, card, tc, fromTc, 0);
|
||||
return NEW TrVampired(id, card, tc, fromTc);
|
||||
}
|
||||
|
||||
//when card becomes the target of a spell or ability
|
||||
|
||||
@@ -1819,6 +1819,83 @@ MTGPersistRule * MTGPersistRule::clone() const
|
||||
return a;
|
||||
}
|
||||
|
||||
//vampires rule
|
||||
//handled seperately as a rule since we only want one object to send out events that a card was "vampired".
|
||||
//otherwise vampire event is sent per instance of @vampired on the battlefield, multipling the results.
|
||||
MTGVampireRule::MTGVampireRule(int _id) :
|
||||
MTGAbility(_id, NULL)
|
||||
{
|
||||
}
|
||||
;
|
||||
|
||||
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(!e->damage->damage)
|
||||
return 0;
|
||||
if (!e->damage->target)
|
||||
return 0;
|
||||
|
||||
MTGCardInstance * newVictem = (MTGCardInstance*)(e->damage->target);
|
||||
MTGCardInstance * vampire = (MTGCardInstance*)(e->damage->source);
|
||||
|
||||
victems[newVictem].push_back(vampire);
|
||||
|
||||
}
|
||||
else if (z)
|
||||
{
|
||||
MTGCardInstance * card = z->card->previous;
|
||||
if(card && victems[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++)
|
||||
{
|
||||
if(victems[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);
|
||||
game->receiveEvent(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (pe)
|
||||
{
|
||||
if( pe->from->id == Constants::MTG_PHASE_ENDOFTURN)
|
||||
{
|
||||
victems.clear();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ostream& MTGVampireRule::toString(ostream& out) const
|
||||
{
|
||||
out << "MTGVampireRule ::: (";
|
||||
return MTGAbility::toString(out) << ")";
|
||||
}
|
||||
int MTGVampireRule::testDestroy()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
MTGVampireRule * MTGVampireRule::clone() const
|
||||
{
|
||||
MTGVampireRule * a = NEW MTGVampireRule(*this);
|
||||
a->isClone = 1;
|
||||
return a;
|
||||
}
|
||||
/////////////////////////////////////////////////
|
||||
//unearth rule----------------------------------
|
||||
//if the card leaves play, exile it instead.
|
||||
MTGUnearthRule::MTGUnearthRule(int _id) :
|
||||
|
||||
@@ -173,9 +173,9 @@ Targetable * WEventVampire::getTarget(int target)
|
||||
switch (target)
|
||||
{
|
||||
case TARGET_TO:
|
||||
return source->next;
|
||||
return victem->next;
|
||||
case TARGET_FROM:
|
||||
return victem;
|
||||
return source;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user