added stack check, modified life check

if activating ability, playing a land or casting sorcery spell at
sorcery level(timing restriction), if the stack is not empty, don't
allow it. Modified the life state check, if any of the players would
lose the game, allow the gamestateeffects to check... added
reduceto:value for ali from cairo...
This commit is contained in:
Anthony Calosa
2015-10-01 22:25:26 +08:00
parent e1c02c8bf5
commit ddee2c08e2
10 changed files with 112 additions and 71 deletions

View File

@@ -2168,7 +2168,7 @@ toughness=1
[/card] [/card]
[card] [card]
name=Ali from Cairo name=Ali from Cairo
auto=@damaged(controller) restriction{compare(lifetotal)~lessthan~1}:this(controllerlife < 1) lifeset:1 controller auto=this(controllerlife >= 1) transforms((,newability[reduceto:1]))
text=Damage that would reduce your life total to less than 1 reduces it to 1 instead. text=Damage that would reduce your life total to less than 1 reduces it to 1 instead.
mana={2}{R}{R} mana={2}{R}{R}
type=Creature type=Creature
@@ -28928,7 +28928,7 @@ toughness=6
name=Elderscale Wurm name=Elderscale Wurm
abilities=trample abilities=trample
auto=if compare(lifetotal)~lessthan~7 then lifeset:7 controller auto=if compare(lifetotal)~lessthan~7 then lifeset:7 controller
auto=this(controllerlife > 6) transforms((,newability[@damaged(controller):if compare(lifetotal)~lessthan~7 then lifeset:7 controller])) auto=this(controllerlife >= 7) transforms((,newability[reduceto:7]))
text=Trample. -- When Elderscale Wurm enters the battlefield, if your life total is less than 7, your life total becomes 7. -- As long as you have 7 or more life, damage that would reduce your life total to less than 7 reduces it to 7 instead. text=Trample. -- When Elderscale Wurm enters the battlefield, if your life total is less than 7, your life total becomes 7. -- As long as you have 7 or more life, damage that would reduce your life total to less than 7 reduces it to 7 instead.
mana={4}{G}{G}{G} mana={4}{G}{G}{G}
type=Creature type=Creature
@@ -36160,7 +36160,7 @@ toughness=3
name=Fortune Thief name=Fortune Thief
facedown={3} facedown={3}
autofacedown={R}{R}:morph autofacedown={R}{R}:morph
auto=@damaged(controller) restriction{compare(lifetotal)~lessthan~1}:this(controllerlife < 1) lifeset:1 controller auto=this(controllerlife >= 1) transforms((,newability[reduceto:1]))
text=Damage that would reduce your life total to less than 1 reduces it to 1 instead. -- Morph {R}{R} (You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.) text=Damage that would reduce your life total to less than 1 reduces it to 1 instead. -- Morph {R}{R} (You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)
mana={4}{R} mana={4}{R}
type=Creature type=Creature
@@ -98227,6 +98227,17 @@ power=2
toughness=3 toughness=3
[/card] [/card]
[card] [card]
name=Sustaining Spirit
auto=cumulativeupcost[{1}{W}] sacrifice
auto=this(controllerlife >= 1) transforms((,newability[reduceto:1]))
text=Cumulative upkeep {1}{W} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.) -- Damage that would reduce your life total to less than 1 reduces it to 1 instead.
mana={1}{W}
type=Creature
subtype=Angel Spirit
power=0
toughness=3
[/card]
[card]
name=Sustenance name=Sustenance
auto={1}{S(land|myBattlefield)}:1/1 target(creature) auto={1}{S(land|myBattlefield)}:1/1 target(creature)
text={1}, Sacrifice a land: Target creature gets +1/+1 until end of turn. text={1}, Sacrifice a land: Target creature gets +1/+1 until end of turn.
@@ -114654,6 +114665,13 @@ mana={3}
type=Artifact type=Artifact
[/card] [/card]
[card] [card]
name=Worship
auto=this(variable{worshipped} >= 1) transforms((,newability[reduceto:1]))
text=If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead.
mana={3}{W}
type=Enchantment
[/card]
[card]
name=Worthy Cause name=Worthy Cause
auto=life:storedtoughness controller auto=life:storedtoughness controller
buyback={W}{2} buyback={W}{2}

View File

@@ -16201,15 +16201,6 @@ type=Sorcery
text=You gain 2 life. Then if you have more life than an opponent, draw a card. Rebound (If you cast this spell from your hand, exile it as it resolves. At the beginning of your next upkeep, you may cast this card from exile without paying its mana cost.) text=You gain 2 life. Then if you have more life than an opponent, draw a card. Rebound (If you cast this spell from your hand, exile it as it resolves. At the beginning of your next upkeep, you may cast this card from exile without paying its mana cost.)
[/card] [/card]
[card] [card]
name=Sustaining Spirit
text=Cumulative upkeep {1}{W} (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.) -- Damage that would reduce your life total to less than 1 reduces it to 1 instead.
mana={1}{W}
type=Creature
subtype=Angel Spirit
power=0
toughness=3
[/card]
[card]
name=Sutured Ghoul name=Sutured Ghoul
text=Trample -- As Sutured Ghoul enters the battlefield, exile any number of creature cards from your graveyard. -- Sutured Ghoul's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness. text=Trample -- As Sutured Ghoul enters the battlefield, exile any number of creature cards from your graveyard. -- Sutured Ghoul's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness.
mana={4}{B}{B}{B} mana={4}{B}{B}{B}
@@ -18718,12 +18709,6 @@ mana={2}{B}{B}{B}
type=Enchantment type=Enchantment
[/card] [/card]
[card] [card]
name=Worship
text=If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead.
mana={3}{W}
type=Enchantment
[/card]
[card]
name=Wort, the Raidmother name=Wort, the Raidmother
text=When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. -- Each red or green instant or sorcery spell you cast has conspire. (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) text=When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. -- Each red or green instant or sorcery spell you cast has conspire. (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.)
mana={4}{RG}{RG} mana={4}{RG}{RG}

View File

@@ -688,6 +688,13 @@ private:
{ {
intValue = target->controller()->opponent()->game->hand->nb_cards; intValue = target->controller()->opponent()->game->hand->nb_cards;
} }
else if (s == "worshipped")//Worship
{
if(card->controller()->game->battlefield->hasType("creature"))
intValue = card->controller()->life;
else
intValue = 0;
}
else if (s == "pancientooze")//Ancient Ooze else if (s == "pancientooze")//Ancient Ooze
{ {
intValue = 0; intValue = 0;
@@ -5997,6 +6004,37 @@ public:
} }
}; };
//Reduce to .. Ali from Cairo...
class AReduceToAbility: public MTGAbility
{
public:
string life_s;
AReduceToAbility(GameObserver* observer, int _id, MTGCardInstance * _source, string _life_s) :
MTGAbility(observer, _id, _source)
{
life_s = _life_s;
}
int receiveEvent(WEvent * event)
{
if(WEventDamage * isDamaged = dynamic_cast<WEventDamage *> (event))
{
if (isDamaged->damage->target->type_as_damageable == Damageable::DAMAGEABLE_PLAYER)
{
Player * p = (Player *) isDamaged->damage->target;
WParsedInt lifetoset(life_s, NULL, source);
if(p && p == source->controller() && p->life <= lifetoset.getValue())
p->life = lifetoset.getValue();
}
}
return 1;
}
AReduceToAbility * clone() const
{
return NEW AReduceToAbility(*this);
}
};
//flanking ability //flanking ability
class AFlankerAbility: public MTGAbility class AFlankerAbility: public MTGAbility
{ {

View File

@@ -234,9 +234,9 @@ public:
void revertbaseP(); void revertbaseP();
void revertbaseT(); void revertbaseT();
int getCurrentPower(); int getCurrentPower();
int getCurrentToughness();
int LKIpower; int LKIpower;
int LKItoughness; int LKItoughness;
int getCurrentToughness();
void cdaPT(int p = 0, int t = 0); void cdaPT(int p = 0, int t = 0);
bool isCDA; bool isCDA;
void switchPT(bool apply = false); void switchPT(bool apply = false);
@@ -248,6 +248,7 @@ public:
bool discarded; bool discarded;
int copiedID; int copiedID;
int modifiedbAbi; int modifiedbAbi;
bool StackIsEmptyandSorcerySpeed();
void eventattacked(); void eventattacked();
void eventattackedAlone(); void eventattackedAlone();

View File

@@ -71,7 +71,7 @@ public:
ManaPool * getManaPool(); ManaPool * getManaPool();
void takeMulligan(); void takeMulligan();
void serumMulligan(); void serumMulligan();
bool DeadLifeState(); bool DeadLifeState(bool check = false);
ManaCost * doesntEmpty; ManaCost * doesntEmpty;
ManaCost * poolDoesntEmpty; ManaCost * poolDoesntEmpty;
void cleanupPhase(); void cleanupPhase();

View File

@@ -578,6 +578,8 @@ void GameObserver::Update(float dt)
{ {
mLayers->actionLayer()->Update(0); mLayers->actionLayer()->Update(0);
} }
players[0]->DeadLifeState();
players[1]->DeadLifeState();
gameStateBasedEffects(); gameStateBasedEffects();
} }
oldGamePhase = mCurrentGamePhase; oldGamePhase = mCurrentGamePhase;
@@ -764,7 +766,7 @@ void GameObserver::gameStateBasedEffects()
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//life checks/poison checks also checks cant win or lose.// //life checks/poison checks also checks cant win or lose.//
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
players[i]->DeadLifeState();//refactored players[i]->DeadLifeState(true);//refactored
} }
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
//-------------card based states effects------------// //-------------card based states effects------------//

View File

@@ -2665,6 +2665,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return NEW AProduceExtraAbility(observer, id, card,s.substr(13)); return NEW AProduceExtraAbility(observer, id, card,s.substr(13));
} }
//reducelife to specific value
if (s.find("reduceto:") != string::npos)
{
return NEW AReduceToAbility(observer, id, card,s.substr(9));
}
//flanking //flanking
if (s.find("flanker") != string::npos) if (s.find("flanker") != string::npos)
{ {
@@ -4594,6 +4600,8 @@ int ActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
return 0; return 0;
if (cPhase != MTG_PHASE_FIRSTMAIN && cPhase != MTG_PHASE_SECONDMAIN) if (cPhase != MTG_PHASE_FIRSTMAIN && cPhase != MTG_PHASE_SECONDMAIN)
return 0; return 0;
if (player->opponent()->getObserver()->mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0||game->mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0||player->getObserver()->mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0)
return 0;
break; break;
} }
if (restrictions >= MY_BEFORE_BEGIN && restrictions <= MY_AFTER_EOT) if (restrictions >= MY_BEFORE_BEGIN && restrictions <= MY_AFTER_EOT)
@@ -5016,30 +5024,6 @@ int TriggeredAbility::receiveEvent(WEvent * e)
resolve(); resolve();
return 1; return 1;
} }
if(dynamic_cast<WEventLife*>(e))
{
//check life state on life triger
WEventLife * lifecheck = dynamic_cast<WEventLife*>(e);
if (lifecheck->player->DeadLifeState())
{
return 0;
}
fireAbility();
return 1;
}
if(dynamic_cast<WEventDamage*>(e))
{
//check life state on damage trigger
WEventDamage * lifecheck = dynamic_cast<WEventDamage*>(e);
if (lifecheck->damage->target->type_as_damageable == Damageable::DAMAGEABLE_PLAYER)
{
Player * triggerPlayer = (Player *) lifecheck->damage->target;
if(triggerPlayer->DeadLifeState())
return 0;
}
fireAbility();
return 1;
}
WEventZoneChange * stackCheck = dynamic_cast<WEventZoneChange*>(e); WEventZoneChange * stackCheck = dynamic_cast<WEventZoneChange*>(e);
if(stackCheck && (stackCheck->to == game->currentPlayer->game->stack||stackCheck->to == game->currentPlayer->opponent()->game->stack)) if(stackCheck && (stackCheck->to == game->currentPlayer->game->stack||stackCheck->to == game->currentPlayer->opponent()->game->stack))
{ {

View File

@@ -739,6 +739,20 @@ int MTGCardInstance::getCurrentToughness()
return toughness; return toughness;
} }
//check stack
bool MTGCardInstance::StackIsEmptyandSorcerySpeed()
{
if((getObserver()->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0) &&
(getObserver()->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN ||
getObserver()->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN) &&
controller() == getObserver()->currentPlayer &&
!getObserver()->isInterrupting)
{
return true;
}
return false;
}
int MTGCardInstance::canBlock() int MTGCardInstance::canBlock()
{ {
if (tapped) if (tapped)

View File

@@ -310,18 +310,12 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost *)
{ {
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY)
return 0; return 0;
if (player == currentPlayer if (card->StackIsEmptyandSorcerySpeed())
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
)
{
return 1; return 1;
} else
return 0;
} }
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (card->StackIsEmptyandSorcerySpeed()))
|| (player == card->controller() && !game->isInterrupting
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
)
{ {
if(card->controller()->epic) if(card->controller()->epic)
return 0; return 0;
@@ -645,17 +639,12 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *
{ {
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY)
return 0; return 0;
if (player == currentPlayer if (card->StackIsEmptyandSorcerySpeed())
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
)
return 1; return 1;
else
return 0;
} }
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || card->has(Constants::SPELLMASTERY) || card->has(Constants::OFFERING) else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || card->has(Constants::SPELLMASTERY) || card->has(Constants::OFFERING) || (card->StackIsEmptyandSorcerySpeed()))
|| (player == card->controller() && !game->isInterrupting
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
)
{ {
if(card->controller()->epic) if(card->controller()->epic)
return 0; return 0;
@@ -1042,11 +1031,7 @@ int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *)
if(card->controller()->epic)//zoetic cavern... morph is casted for a cost... if(card->controller()->epic)//zoetic cavern... morph is casted for a cost...
return 0; return 0;
//note lands can morph too, this is different from other cost types. //note lands can morph too, this is different from other cost types.
if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == card->controller() if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (card->StackIsEmptyandSorcerySpeed()))
&& !game->isInterrupting
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
)
{ {
if (card->controller()->game->playRestrictions->canPutIntoZone(card, card->controller()->game->stack) == PlayRestriction::CANT_PLAY) if (card->controller()->game->playRestrictions->canPutIntoZone(card, card->controller()->game->stack) == PlayRestriction::CANT_PLAY)
return 0; return 0;

View File

@@ -236,7 +236,7 @@ void Player::serumMulligan()
//Draw hand no penalty //Draw hand no penalty
} }
bool Player::DeadLifeState() bool Player::DeadLifeState(bool check)
{ {
if ((life <= 0)||(poisonCount >= 10)) if ((life <= 0)||(poisonCount >= 10))
{ {
@@ -263,7 +263,21 @@ bool Player::DeadLifeState()
} }
if (cantlosers < 1) if (cantlosers < 1)
{ {
getObserver()->setLoser(this); if(!check)
{
ActionStack * stack = getObserver()->mLayers->stackLayer();
for (int i = stack->mObjects.size() - 1; i >= 0; i--)
{
Interruptible * current = ((Interruptible *) stack->mObjects[i]);
Spell * spell = (Spell *) current;
if (current->type == ACTION_SPELL)
spell->source->controller()->game->putInGraveyard(spell->source);
current->state = RESOLVED_NOK;
}
}
if(check)
game->owner->getObserver()->setLoser(this);
return true; return true;
} }
} }