Merge remote-tracking branch 'refs/remotes/WagicProject/master'

This commit is contained in:
Anthony Calosa
2016-06-29 08:26:31 +08:00
29 changed files with 3854 additions and 2289 deletions

View File

@@ -35,6 +35,7 @@ auto=lifelinkrule
auto=deathtouchrule
auto=soulbondrule
auto=dredgerule
auto=bestowrule
[PLAYERS]
life:20

View File

@@ -38,6 +38,117 @@ public:
virtual MTGEventText * clone() const;
};
class MTGRevealingCards : public MTGAbility, public CardDisplay
{
public:
vector<CardView*> cards;
Player * playerForZone;
MTGGameZone * RevealZone;
MTGGameZone * RevealFromZone;
string revealCertainTypes;
string revealUntil;
CardDisplay * revealDisplay;
vector<CardDisplay*>trashDisplays;//used for repeat
int nbCard;
string abilityString;
string number;
string abilityOne;
string abilityTwo;
string afterReveal;
bool afterEffectActivated;
MTGAbility * abilityToCast;
MTGAbility * abilityFirst;
MTGAbility * abilitySecond;
MTGAbility * abilityAfter;
vector<MTGAbility*>abilities;
bool repeat;//only the first ability can be repeated, and it must be targeted.
bool initCD;
void Update(float dt);
int testDestroy();
int toResolve();
void CardViewBackup(MTGCardInstance * backup);
void Render();
bool CheckUserInput(JButton key);
MTGAbility * contructAbility(string abilityToMake = "");
MTGRevealingCards(GameObserver* observer, int _id, MTGCardInstance * card, string text);
virtual MTGRevealingCards * clone() const;
~MTGRevealingCards();
int receiveEvent(WEvent*);
};
class RevealDisplay : public CardDisplay
{
public:
RevealDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener = NULL, TargetChooser * tc = NULL,
int nb_displayed_items = 7);
void AddCard(MTGCardInstance * _card);
bool CheckUserInput(JButton key);
};
class GenericRevealAbility : public ActivatedAbility
{
public:
string howMany;
MTGRevealingCards * ability;
GenericRevealAbility(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, string _howMany);
int resolve();
const string getMenuText();
GenericRevealAbility * clone() const;
~GenericRevealAbility();
};
class MTGScryCards : public MTGAbility, public CardDisplay
{
public:
vector<CardView*> cards;
MTGGameZone * RevealZone;
MTGGameZone * RevealFromZone;
CardDisplay * revealDisplay;
vector<CardDisplay*>trashDisplays;//used for repeat
int nbCard;
bool delayed;
bool dontRevealAfter;
int revealTopAmount;
string delayedAbilityString;
string abilityString;
string number;
string abilityOne;
string abilityTwo;
MTGAbility * abilityToCast;
MTGAbility * abilityFirst;
MTGAbility * abilitySecond;
vector<MTGAbility*>abilities;
bool initCD;
void Update(float dt);
int testDestroy();
void initDisplay(int value = 0);
int toResolve();
void Render();
bool CheckUserInput(JButton key);
MTGAbility * contructAbility(string abilityToMake = "");
MTGScryCards(GameObserver* observer, int _id, MTGCardInstance * card, string text);
virtual MTGScryCards * clone() const;
~MTGScryCards();
int receiveEvent(WEvent*);
};
class GenericScryAbility : public ActivatedAbility
{
public:
string howMany;
MTGScryCards * ability;
GenericScryAbility(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target, string _howMany);
int resolve();
const string getMenuText();
GenericScryAbility * clone() const;
~GenericScryAbility();
};
class WParsedInt
{
public:
@@ -240,6 +351,10 @@ private:
{
intValue = countDevotionTo(card,card->controller()->inPlay(),Constants::MTG_COLOR_BLUE,Constants::MTG_COLOR_GREEN);
}
else if (s == "Iroas")//devotion to red white
{
intValue = countDevotionTo(card, card->controller()->inPlay(), Constants::MTG_COLOR_RED, Constants::MTG_COLOR_WHITE);
}
else if (s.find("type:") != string::npos)
{
size_t begins = s.find("type:");
@@ -556,6 +671,10 @@ private:
{
intValue = target->getCurrentToughness();
}
else if (s == "countedamount")
{
intValue = target->CountedObjects;
}
else if (s == "kicked")
{
intValue = target->kicked;
@@ -745,6 +864,21 @@ private:
intValue += card->controller()->game->inPlay->cards[j]->power;
}
}
else if (s == "revealedp")
{
if (card->revealedLast)
intValue = card->revealedLast->power;
}
else if (s == "revealedt")
{
if (card->revealedLast)
intValue = card->revealedLast->toughness;
}
else if (s == "revealedmana")
{
if (card->revealedLast)
intValue = card->revealedLast->getManaCost()->getConvertedCost();
}
else
{
intValue = atoi(s.c_str());
@@ -2855,7 +2989,6 @@ public:
return NEW ARegularLifeModifierAura(*this);
}
};
//Generic Kird Ape
class AAsLongAs: public ListMaintainerAbility, public NestedAbility
{
@@ -3334,6 +3467,7 @@ public:
list<int> colors;
int power, toughness;
int tokenId;
string _cardName;
string name;
string sabilities;
string starfound;
@@ -3345,6 +3479,7 @@ public:
MTGCardInstance * myToken;
vector<MTGAbility *> currentAbilities;
Player * tokenReciever;
//by id
ATokenCreator(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable *, ManaCost * _cost, int tokenId,string starfound, WParsedInt * multiplier = NULL,
int who = 0,bool aLivingWeapon = false) :
ActivatedAbility(observer, _id, _source, _cost, 0), tokenId(tokenId), starfound(starfound),multiplier(multiplier), who(who),aLivingWeapon(aLivingWeapon)
@@ -3354,7 +3489,18 @@ public:
if (card) name = card->data->getName();
battleReady = false;
}
//by name, card still require valid card.dat info, this just makes the primitive code far more readable. token(Eldrazi scion) instead of token(-1234234)...
ATokenCreator(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable *, ManaCost * _cost, string cardName, string starfound, WParsedInt * multiplier = NULL,
int who = 0, bool aLivingWeapon = false) :
ActivatedAbility(observer, _id, _source, _cost, 0), _cardName(cardName), starfound(starfound), multiplier(multiplier), who(who), aLivingWeapon(aLivingWeapon)
{
if (!multiplier) this->multiplier = NEW WParsedInt(1);
MTGCard * card = MTGCollection()->getCardByName(_cardName);
tokenId = card->getId();
if (card) name = card->data->getName();
battleReady = false;
}
//by construction
ATokenCreator(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable *, ManaCost * _cost, string sname, string stypes, int _power, int _toughness,
string sabilities, string starfound,WParsedInt * multiplier = NULL, int _who = 0,bool aLivingWeapon = false,string spt = "") :
ActivatedAbility(observer, _id, _source, _cost, 0),sabilities(sabilities),starfound(starfound), multiplier(multiplier), who(_who),aLivingWeapon(aLivingWeapon),spt(spt)
@@ -3877,10 +4023,12 @@ class AThis: public MTGAbility, public NestedAbility
public:
MTGAbility * a;
ThisDescriptor * td;
AThis(GameObserver* observer, int _id, MTGCardInstance * _source, Damageable * _target, ThisDescriptor * _td, MTGAbility * ability) :
string restrictionCheck;
AThis(GameObserver* observer, int _id, MTGCardInstance * _source, Damageable * _target, ThisDescriptor * _td, MTGAbility * ability, string restriction = "") :
MTGAbility(observer, _id, _source, _target), NestedAbility(ability)
{
td = _td;
restrictionCheck = restriction;
ability->source = source;
ability->target = target;
a = NULL;
@@ -3904,9 +4052,18 @@ public:
int resolve()
{
//TODO check if ability is oneShot ?
int match;
match = td->match(source);
int match = 0;
if (td)
{
match = td->match(source);
}
else
{//restriction check instead of Targetchooser
AbilityFactory abf(target->getObserver());
int checkCond = abf.parseCastRestrictions(source, source->controller(), restrictionCheck);
if (checkCond)
match = 1;
}
if (match > 0)
{
addAbilityToGame();
@@ -3953,6 +4110,7 @@ public:
{
AThis * a = NEW AThis(*this);
a->ability = ability->clone();
if(a->td)
a->td = td->clone();
return a;
}
@@ -4166,6 +4324,16 @@ public:
return NEW TADamager(*this);
}
};
//bestow
class ABestow : public ActivatedAbility
{
public:
MTGCardInstance * _card;
ABestow(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost = NULL);
int resolve();
const string getMenuText();
ABestow * clone() const;
};
/* Can tap a target for a cost */
class AATapper: public ActivatedAbility
@@ -4197,12 +4365,22 @@ public:
int resolve();
AAWhatsMax * clone() const;
};
//counts a targetchooser for use later by other effects
class AACountObject : public ActivatedAbility
{
public:
string value;
AACountObject(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * source, ManaCost * _cost = NULL, string value ="");
int resolve();
AACountObject * clone() const;
};
/* Can prevent a card from untapping next untap */
class AAFrozen: public ActivatedAbility
{
public:
AAFrozen(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost = NULL);
bool freeze;
AAFrozen(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, bool tap, ManaCost * _cost = NULL);
int resolve();
const string getMenuText();
AAFrozen * clone() const;
@@ -6205,7 +6383,8 @@ public:
MTGCardInstance * theNamedCard;
bool noEvent;
bool putinplay;
AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool restricted,bool copied,bool _asNormal,string nameCard,string abilityName,bool _noEvent, bool putinplay);
bool asNormalMadness;
AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool restricted,bool copied,bool _asNormal,string nameCard,string abilityName,bool _noEvent, bool putinplay,bool asNormalMadness = false);
int testDestroy(){return 0;};
void Update(float dt);

View File

@@ -80,6 +80,7 @@ class GameObserver{
ExtraCosts * mExtraPayment;
int oldGamePhase;
TargetChooser * targetChooser;
CardDisplay * OpenedDisplay;
DuelLayers * mLayers;
ReplacementEffects *replacementEffects;
vector<Player *> players; //created outside

View File

@@ -121,6 +121,7 @@ public:
ManaCost* BuyBack;
ManaCost* FlashBack;
ManaCost* Retrace;
ManaCost* Bestow;
ManaCost* morph;
ManaCost* suspend;

View File

@@ -95,6 +95,7 @@ public:
bool exileEffects;
bool suspended;
bool miracle;
bool isBestowed;
int chooseacolor;
string chooseasubtype;
int coinSide;//1 = tails
@@ -105,6 +106,7 @@ public:
int notblocked;
int fresh;
int MaxLevelUp;
int CountedObjects;
int kicked;
int dredge;
bool isDualWielding;
@@ -272,6 +274,8 @@ public:
string currentimprintName;
vector<string>imprintedNames;
MTGCardInstance * revealedLast;//last card revealed by a ability this card owns.
bool MadnessPlay;
void eventattacked();
void eventattackedAlone();
void eventattackednotblocked();

View File

@@ -82,6 +82,7 @@ class Constants
static const string kRetraceKeyword;
static const string kKickerKeyword;
static const string kMorphKeyword;
static const string kBestowKeyword;
// used for deck statistics
static const int STATS_FOR_TURNS = 8;
@@ -246,8 +247,11 @@ class Constants
COMBATTOUGHNESS = 125,
CANTPAYLIFE = 126,
CANTBESACRIFIED = 127,
NB_BASIC_ABILITIES = 128,
SKULK = 128,
MENACE = 129,
NOSOLO = 130,//cant attack alone
MUSTBLOCK = 131,//blocks each turn
NB_BASIC_ABILITIES = 132,
RARITY_S = 'S', //Special Rarity
RARITY_M = 'M', //Mythics
@@ -308,6 +312,7 @@ class Constants
CAST_WITH_RETRACE = 6,
CAST_WITH_MORPH = 7,
CAST_WITH_SUSPEND = 8,
CAST_WITH_BESTOW = 9,
CAST_ALTERNATE = -1, //matches all alternate costs, including itself
CAST_ALL = -2, // matches everything except NOT_CAST

View File

@@ -72,6 +72,14 @@ class MTGGameZone {
OWNER_STACK = 66,
TARGETED_PLAYER_STACK = 67,
MY_REVEAL = 71,
OPPONENT_REVEAL = 72,
TARGET_OWNER_REVEAL = 73,
TARGET_CONTROLLER_REVEAL = 74,
REVEAL = 75,
OWNER_REVEAL = 76,
TARGETED_PLAYER_REVEAL = 77,
};
Player * owner;
@@ -194,6 +202,7 @@ public:
MTGRemovedFromGame * exile; //alias to removedFromZone
MTGGameZone * garbage;
MTGGameZone * garbageLastTurn;
MTGGameZone * reveal;
MTGGameZone * temp;
MTGPlayerCards();

View File

@@ -206,6 +206,21 @@ public:
virtual MTGOverloadRule * clone() const;
};
class MTGBestowRule : public MTGAlternativeCostRule
{
public:
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
int reactToClick(MTGCardInstance * card);
virtual ostream& toString(ostream& out) const;
MTGBestowRule(GameObserver* observer, int _id);
const string getMenuText()
{
return "Bestow";
}
virtual MTGBestowRule * clone() const;
};
class MTGSuspendRule: public MTGAlternativeCostRule
{
public:

View File

@@ -31,6 +31,7 @@ protected:
ManaCost * manaUsedToCast;
ManaCost * morph;
ManaCost * Retrace;
ManaCost * Bestow;
ManaCost * FlashBack;
ManaCost * BuyBack;
ManaCost * kicker;
@@ -75,6 +76,9 @@ public:
ManaCost * getSuspend(){ return suspend; };
void setSuspend(ManaCost * aMana){ SAFE_DELETE(suspend); suspend = aMana;};
ManaCost * getBestow() { return Bestow; };
void setBestow(ManaCost * aMana) { SAFE_DELETE(Bestow); Bestow = aMana; };
ManaCost * getManaUsedToCast(){ return manaUsedToCast; };
void setManaUsedToCast(ManaCost * aMana){ SAFE_DELETE(manaUsedToCast); manaUsedToCast = aMana;};

View File

@@ -25,6 +25,7 @@ class TargetChooser: public TargetsList
protected:
int forceTargetListReady;
public:
int forceTargetListReadyByPlayer;
const static int UNLITMITED_TARGETS = 1000;
enum
{

View File

@@ -1221,7 +1221,7 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank
for (int i = 0; i < 2; i++)
{
Player * p = observer->players[i];
MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay,p->game->stack,p->game->exile };
MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay,p->game->stack,p->game->exile, p->game->reveal };
if(a->getActionTc()->canTarget((Targetable*)p))
{
if(a->getActionTc()->maxtargets == 1)
@@ -1352,7 +1352,7 @@ int AIPlayerBaka::selectHintAbility()
int AIPlayerBaka::selectAbility()
{
if(observer->mExtraPayment && observer->mExtraPayment->source->controller() == this)
if(observer->mExtraPayment && observer->mExtraPayment->source && observer->mExtraPayment->source->controller() == this)
{
ExtraManaCost * check = NULL;
check = dynamic_cast<ExtraManaCost*>(observer->mExtraPayment->costs[0]);
@@ -1560,8 +1560,8 @@ int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCard
}
}
MTGPlayerCards * playerZones = target->game;
MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard,playerZones->stack,playerZones->exile };
for (int j = 0; j < 6; j++)
MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard,playerZones->stack,playerZones->exile,playerZones->reveal };
for (int j = 0; j < 7; j++)
{
MTGGameZone * zone = zones[j];
for (int k = 0; k < zone->nb_cards; k++)

View File

@@ -77,7 +77,7 @@ void ActionLayer::cleanGarbage()
int ActionLayer::reactToClick(ActionElement * ability, MTGCardInstance * card)
{
int result = ability->reactToClick(card);
int result = ability?ability->reactToClick(card):0;
if (result)
stuffHappened = 1;
return result;
@@ -186,8 +186,11 @@ void ActionLayer::Update(float dt)
without this, the game locks into a freeze state while you try to select the targets and dont have enough to
fill the maxtargets list.
*/
if(int(ae->getActionTc()->getNbTargets()) == countTargets-1)
ae->getActionTc()->done = true;
if (int(ae->getActionTc()->getNbTargets()) == countTargets)//if the amount of targets is equal the all we can target
{
ae->getActionTc()->done = true;//were done
ae->getActionTc()->source->getObserver()->cardClick(ae->getActionTc()->source, 0, false);//click source.
}
}
}
}

View File

@@ -578,6 +578,10 @@ int ActionStack::addAbility(MTGAbility * ability)
if (!observer->players[0]->isAI() && ability->source->controller() == observer->players[0] && 0
== options[Options::INTERRUPTMYABILITIES].number)
interruptDecision[0] = DONT_INTERRUPT;
if (observer->OpenedDisplay && observer->players[0]->game->reveal->cards.size())
{
interruptDecision[0] = DONT_INTERRUPT;
}
return result;
}

File diff suppressed because it is too large Load Diff

View File

@@ -756,9 +756,10 @@ int TapTargetCost::isPaymentSet()
int TapTargetCost::doPay()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
source->storedCard = target->createSnapShot();
if (target)
{
source->storedCard = target->createSnapShot();
_target->tap();
target = NULL;
if (tc)
@@ -799,9 +800,10 @@ int UnTapTargetCost::isPaymentSet()
int UnTapTargetCost::doPay()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
source->storedCard = target->createSnapShot();
if (target)
{
source->storedCard = target->createSnapShot();
_target->untap();
target = NULL;
if (tc)

File diff suppressed because it is too large Load Diff

View File

@@ -48,7 +48,8 @@ void GameStateOptions::Start()
}
optionsList->Add(NEW OptionInteger(Options::INTERRUPT_SECONDS, "Seconds to pause for an Interrupt", 20, 1));
optionsList->Add(NEW OptionInteger(Options::INTERRUPTMYSPELLS, "Interrupt my spells"));
optionsList->Add(NEW OptionInteger(Options::INTERRUPTMYABILITIES, "Interrupt my abilities"));
// optionsList->Add(NEW OptionInteger(Options::INTERRUPTMYABILITIES, "Interrupt my abilities"));
//this is a dev option, not meant for standard play. uncomment if you need to see abilities you own hitting the stack.
optionsList->Add(NEW OptionInteger(Options::INTERRUPT_SECONDMAIN, "Interrupt opponent's end of turn"));
optionsTabs = NEW WGuiTabMenu();
optionsTabs->Add(optionsList);

View File

@@ -149,12 +149,16 @@ ostream& GuiAvatar::toString(ostream& out) const
void GuiGameZone::toggleDisplay()
{
if (showCards)
showCards = 0;
else
if (showCards)
{
showCards = 0;
cd->zone->owner->getObserver()->OpenedDisplay = NULL;
}
else if(!cd->zone->owner->getObserver()->OpenedDisplay)//one display at a time please.
{
showCards = 1;
cd->init(zone);
cd->zone->owner->getObserver()->OpenedDisplay = cd;
}
}

View File

@@ -19,8 +19,8 @@
const string kLordKeywords[] = { "lord(", "foreach(", "aslongas(", "teach(", "all(" };
const size_t kLordKeywordsCount = 5;
const string kThisKeywords[] = { "this(", "thisforeach(" };
const size_t kThisKeywordsCount = 2;
const string kThisKeywords[] = { "this(", "thisforeach(","while(", };
const size_t kThisKeywordsCount = 3;
// Used for the maxCast/maxPlay ability parsing
@@ -353,6 +353,24 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe
return 0;
}
check = restriction[i].find("delirium");
if (check != string::npos)
{
Player * checkCurrent = card->controller();
MTGGameZone * grave = checkCurrent->game->graveyard;
int checkTypesAmount = 0;
if(grave->hasType("creature")) checkTypesAmount++;
if (grave->hasType("enchantment")) checkTypesAmount++;
if (grave->hasType("sorcery")) checkTypesAmount++;
if (grave->hasType("instant")) checkTypesAmount++;
if (grave->hasType("land")) checkTypesAmount++;
if (grave->hasType("artifact")) checkTypesAmount++;
if (grave->hasType("planeswalker")) checkTypesAmount++;
if (checkTypesAmount < 4)
return 0;
}
check = restriction[i].find("miracle");
if(check != string::npos)
{
@@ -362,6 +380,13 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe
return 0;
}
check = restriction[i].find("madnessplayed");
if (check != string::npos)
{
if (card->previous && !card->previous->MadnessPlay)
return 0;
}
check = restriction[i].find("prowl");
if(check != string::npos)
{
@@ -437,6 +462,13 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe
return 0;
}
check = restriction[i].find("geared");
if (check != string::npos)
{
if (card->equipment < 1)
return 0;
}
check = restriction[i].find("raid");
if(check != string::npos)
{
@@ -1139,6 +1171,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
observer->addObserver(NEW MTGFlashBackRule(observer, -1));
return NULL;
}
//alternative cost type flashback
found = s.find("bestowrule");
if (found != string::npos)
{
observer->addObserver(NEW MTGBestowRule(observer, -1));
return NULL;
}
//alternative cost type retrace
found = s.find("retracerule");
if(found != string::npos)
@@ -1306,19 +1345,46 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
//actual abilities, this is a limitation.
string unchangedS = "";
unchangedS.append(s);
found = s.find("pay(");
if (found != string::npos && storedPayString.empty())
{
vector<string> splitMayPaystr = parseBetween(s, "pay(", ")", true);
if(splitMayPaystr.size())
{
storedPayString.append(splitMayPaystr[2]);
s = splitMayPaystr[0];
s.append("pay(");
s.append(splitMayPaystr[1]);
s.append(")");
}
}
//Reveal:x remove the core so we dont build them prematurely
vector<string>transPayfound = parseBetween(s, "newability[pay(", " ");
vector<string>transfound = parseBetween(s,"newability[reveal:"," ");//if we are using reveal inside a newability, let transforms remove the string instead.
vector<string>abilfound = parseBetween(s, "ability$!name(reveal) reveal:", " ");
if(!abilfound.size())
abilfound = parseBetween(s, "ability$!reveal:", " ");//see above. this allows us to nest reveals inside these 2 other master classes. while also allowing us to nest them inside reveals.
found = s.find("pay(");
if (found != string::npos && storedPayString.empty() && !transPayfound.size())
{
vector<string> splitMayPaystr = parseBetween(s, "pay(", ")", true);
if (splitMayPaystr.size())
{
storedPayString.append(splitMayPaystr[2]);
s = splitMayPaystr[0];
s.append("pay(");
s.append(splitMayPaystr[1]);
s.append(")");
}
}
vector<string> splitRevealx = parseBetween(s, "reveal:", " revealend", false);
if (!abilfound.size() && !transfound.size() && splitRevealx.size() && storedAbilityString.empty())
{
storedAbilityString = splitRevealx[1];
s = splitRevealx[0];
s.append("reveal: ");
s.append(splitRevealx[2]);
}
vector<string> splitScryx = parseBetween(s, "scry:", " scryend", false);
if (splitScryx.size() && storedAbilityString.empty())
{
storedAbilityString = splitScryx[1];
s = splitScryx[0];
s.append("scry: ");
s.append(splitScryx[2]);
}
found = s.find("transforms((");
if (found != string::npos && storedString.empty())
{
@@ -1750,15 +1816,25 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
}
if (end != string::npos)
{
ThisDescriptor * td = NULL;
string thisDescriptorString = s.substr(found + header, end - found - header);
ThisDescriptorFactory tdf;
ThisDescriptor * td = tdf.createThisDescriptor(observer, thisDescriptorString);
vector<string> splitRest = parseBetween(s, "restriction{", "}");
if (splitRest.size())
{
if (!td)
{
DebugTrace("MTGABILITY: Parsing Error:" << s);
return NULL;
}
}
else
{
ThisDescriptorFactory tdf;
td = tdf.createThisDescriptor(observer, thisDescriptorString);
if (!td)
{
DebugTrace("MTGABILITY: Parsing Error:" << s);
return NULL;
}
}
MTGAbility * a = parseMagicLine(s1, id, spell, card, 0, activated);
if (!a)
@@ -1795,6 +1871,9 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
case 1:
result = NEW AThisForEach(observer, id, card, _target, td, a);
break;
case 2:
result = NEW AThis(observer, id, card, _target, NULL, a, thisDescriptorString);
break;
default:
result = NULL;
}
@@ -1986,7 +2065,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return NEW APaired(observer,id, card,card->myPair,a);
return NULL;
}
//mana of the listed type doesnt get emptied from the pools.
vector<string>colorType = parseBetween(s,"poolsave(",")",false);
if (colorType.size())
@@ -2269,9 +2347,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
tok->oneShot = 1;
return tok;
}
string tokenDesc = splitToken[1];
vector<string> tokenParameters = split(tokenDesc, ',');
//lets try finding a token by card name.
if (splitToken[1].size() && tokenParameters.size() ==1)
{
string cardName = splitToken[1];
MTGCard * safetycard = MTGCollection()->getCardByName(cardName);
if (safetycard) //lets try constructing it then,we didnt find it by name
{
ATokenCreator * tok = NEW ATokenCreator(observer, id, card, target, NULL, cardName, starfound, multiplier, who);
tok->oneShot = 1;
return tok;
}
}
if (tokenParameters.size() < 3)
{
DebugTrace("incorrect Parameters for Token" << tokenDesc);
@@ -2474,6 +2564,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
bool withRestrictions = splitCastCard[1].find("restricted") != string::npos;
bool asCopy = splitCastCard[1].find("copied") != string::npos;
bool asNormal = splitCastCard[1].find("normal") != string::npos;
bool asNormalMadness = splitCastCard[1].find("madness") != string::npos;
bool sendNoEvent = splitCastCard[1].find("noevent") != string::npos;
bool putinplay = splitCastCard[1].find("putinplay") != string::npos;
string nameCard = "";
@@ -2485,7 +2576,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
nameCard = splitCastName[1];
}
}
MTGAbility *a = NEW AACastCard(observer, id, card, target,withRestrictions,asCopy,asNormal,nameCard,newName,sendNoEvent,putinplay);
MTGAbility *a = NEW AACastCard(observer, id, card, target,withRestrictions,asCopy,asNormal,nameCard,newName,sendNoEvent,putinplay, asNormalMadness);
a->oneShot = false;
if(splitCastCard[1].find("trigger[to]") != string::npos)
{
@@ -2933,6 +3024,16 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a;
}
//bestow
found = s.find("bstw");
if (found != string::npos)
{
MTGAbility * a = NEW ABestow(observer, id, card, target);
a->oneShot = 1;
return a;
}
//no counters on target of optional type
vector<string> splitCounterShroud = parseBetween(s, "countershroud(", ")");
if (splitCounterShroud.size())
@@ -3122,6 +3223,30 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
}
//Reveal:x (activate aility)
vector<string> splitReveal = parseBetween(s, "reveal:", "revealend", false);
if (splitReveal.size())
{
string backup = storedAbilityString;
storedAbilityString = "";//we clear the string here for cards that contain more than 1 reveal.
GenericRevealAbility * a = NEW GenericRevealAbility(observer, id, card, target, backup);
a->oneShot = 1;
a->canBeInterrupted = false;
return a;
}
//scry:x (activate aility)
vector<string> splitScry = parseBetween(s, "scry:", "scryend", false);
if (splitScry.size())
{
string backup = storedAbilityString;
storedAbilityString = "";//we clear the string here for cards that contain more than 1 reveal.
GenericScryAbility * a = NEW GenericScryAbility(observer, id, card, target, backup);
a->oneShot = 1;
a->canBeInterrupted = false;
return a;
}
//flip
vector<string> splitFlipStat = parseBetween(s, "flip(", ")", true);
if(splitFlipStat.size())
@@ -3291,11 +3416,20 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
found = s.find("frozen");
if (found != string::npos)
{
MTGAbility * a = NEW AAFrozen(observer, id, card, target);
MTGAbility * a = NEW AAFrozen(observer, id, card, target,false);
a->oneShot = 1;
return a;
}
//frozen, next untap this does not untap.
found = s.find("freeze");
if (found != string::npos)
{
MTGAbility * a = NEW AAFrozen(observer, id, card, target,true);
a->oneShot = 1;
return a;
}
//get a new target - retarget and newtarget makes the card refreshed - from exile to play...
if ((s.find("retarget") != string::npos) || s.find("newtarget") != string::npos)
{
@@ -3330,6 +3464,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a;
}
vector<string> splitCountObject = parseBetween(s, "count(", ")", false);
if (splitCountObject.size())
{
MTGAbility * a = NEW AACountObject(observer, id, card, card, NULL, splitCountObject[1]);
a->oneShot = 1;
return a;
}
//switch targest power with toughness
found = s.find("swap");
if (found != string::npos)
@@ -4625,6 +4767,7 @@ MTGAbility::MTGAbility(const MTGAbility& a): ActionElement(a)
BuyBack = a.BuyBack; //? NEW ManaCost(a.BuyBack) : NULL;
FlashBack = a.FlashBack; // ? NEW ManaCost(a.FlashBack) : NULL;
Retrace = a.Retrace;// ? NEW ManaCost(a.Retrace) : NULL;
Bestow = a.Bestow;
morph = a.morph; //? NEW ManaCost(a.morph) : NULL;
suspend = a.suspend;// ? NEW ManaCost(a.suspend) : NULL;
@@ -5101,7 +5244,7 @@ int TargetAbility::reactToClick(MTGCardInstance * card)
}
else
{
if (tc->toggleTarget(card) == TARGET_OK_FULL)
if (tc->toggleTarget(card) == TARGET_OK_FULL && tc->targetsReadyCheck() == TARGET_OK_FULL)
{
int result = ActivatedAbility::reactToClick(source);
if (result)
@@ -5360,8 +5503,8 @@ void ListMaintainerAbility::updateTargets()
for (int i = 0; i < 2; i++)
{
Player * p = game->players[i];
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile };
for (int k = 0; k < 6; k++)
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile ,p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * zone = zones[k];
if (canTarget(zone))
@@ -5432,8 +5575,8 @@ void ListMaintainerAbility::checkTargets()
for (int i = 0; i < 2; i++)
{
Player * p = game->players[i];
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile };
for (int k = 0; k < 6; k++)
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile, p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * zone = zones[k];
if (canTarget(zone))
@@ -5772,7 +5915,7 @@ int AManaProducer::resolve()
Player * player = getPlayerFromTarget(_target);
if (!player)
return 0;
player->getManaPool()->add(output, source);
if(DoesntEmpty)
player->doesntEmpty->add(output);

View File

@@ -69,6 +69,8 @@ MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to
cardistargetted = 0;
cardistargetter = 0;
myconvertedcost = getManaCost()->getConvertedCost();
revealedLast = NULL;
MadnessPlay = false;
}
MTGCardInstance * MTGCardInstance::createSnapShot()
@@ -194,6 +196,7 @@ void MTGCardInstance::initMTGCI()
wasDealtDamage = false;
isDualWielding = false;
suspended = false;
isBestowed = false;
castMethod = Constants::NOT_CAST;
mPropertiesChangedSinceLastUpdate = false;
stillNeeded = true;
@@ -222,6 +225,7 @@ void MTGCardInstance::initMTGCI()
imprintW = 0;
currentimprintName = "";
imprintedNames.clear();
CountedObjects = 0;
for (int i = 0; i < ManaCost::MANA_PAID_WITH_SUSPEND +1; i++)
alternateCostPaid[i] = 0;
@@ -870,7 +874,7 @@ int MTGCardInstance::canBlock(MTGCardInstance * opponent)
return 0;
if (opponent->basicAbilities[(int)Constants::ONEBLOCKER] && opponent->blocked)
return 0;
if(opponent->basicAbilities[(int)Constants::EVADEBIGGER] && power > opponent->power)
if((opponent->basicAbilities[(int)Constants::EVADEBIGGER]|| opponent->basicAbilities[(int)Constants::SKULK]) && power > opponent->power)
return 0;
if(opponent->basicAbilities[(int)Constants::STRONG] && power < opponent->power)
return 0;
@@ -1266,7 +1270,7 @@ int MTGCardInstance::setDefenser(MTGCardInstance * opponent)
if (defenser)
{
if (observer->players[0]->game->battlefield->hasCard(defenser) || observer->players[1]->game->battlefield->hasCard(defenser))
{
{//remove blocker "this" from the attackers list of blockers.
defenser->removeBlocker(this);
}
}

View File

@@ -105,8 +105,19 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
}
break;
case 'b': //buyback
case 'b': //buyback/Bestow
if (!primitive) primitive = NEW CardPrimitive();
if (key[1] == 'e' && key[2] == 's')
{ //bestow
if (!primitive) primitive = NEW CardPrimitive();
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
cost->setBestow(ManaCost::parseManaCost(value));
}
}
else//buyback
if (ManaCost * cost = primitive->getManaCost())
{
string value = val;

View File

@@ -26,6 +26,7 @@ const string Constants::kFlashBackKeyword = "flashback";
const string Constants::kRetraceKeyword = "retrace";
const string Constants::kKickerKeyword = "kicker";
const string Constants::kMorphKeyword = "facedown";
const string Constants::kBestowKeyword = "bestow";
int Constants::NB_Colors = 0; //Store the Max number of colors.
@@ -157,7 +158,11 @@ const char* Constants::MTGBasicAbilities[] = {
"cantchangelife",
"combattoughness",
"cantpaylife",
"cantbesacrified"
"cantbesacrified",
"skulk",
"menace",
"nosolo",
"mustblock"
};
map<string,int> Constants::MTGBasicAbilitiesMap;

View File

@@ -9,6 +9,7 @@ MTGGamePhase::MTGGamePhase(GameObserver* g, int id) :
animation = 0;
currentState = -1;
mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
if(mFont)
mFont->SetBase(0); // using 2nd font
}

View File

@@ -74,6 +74,7 @@ MTGPlayerCards::~MTGPlayerCards()
SAFE_DELETE(stack);
SAFE_DELETE(removedFromGame);
SAFE_DELETE(garbage);
SAFE_DELETE(reveal);
SAFE_DELETE(temp);
SAFE_DELETE(playRestrictions);
}
@@ -91,6 +92,7 @@ void MTGPlayerCards::beforeBeginPhase()
stack->beforeBeginPhase();
removedFromGame->beforeBeginPhase();
garbage->beforeBeginPhase();
reveal->beforeBeginPhase();
temp->beforeBeginPhase();
}
@@ -105,6 +107,7 @@ void MTGPlayerCards::setOwner(Player * player)
stack->setOwner(player);
garbage->setOwner(player);
garbageLastTurn->setOwner(player);
reveal->setOwner(player);
temp->setOwner(player);
}
@@ -272,6 +275,7 @@ void MTGPlayerCards::init()
exile = removedFromGame;
garbage = NEW MTGGameZone();
garbageLastTurn = garbage;
reveal = NEW MTGGameZone();
temp = NEW MTGGameZone();
playRestrictions = NEW PlayRestrictions();
@@ -360,6 +364,12 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
to = g->players[i]->game->exile;
}
}
//all cards that go from the hand to the graveyard is ALWAYS a discard.
if ((to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard) && (from == g->players[0]->game->hand || from
== g->players[1]->game->hand))
{
card->discarded = true;
}
//When a card is moved from inPlay to inPlay (controller change, for example), it is still the same object
if ((to == g->players[0]->game->inPlay || to == g->players[1]->game->inPlay) && (from == g->players[0]->game->inPlay || from
== g->players[1]->game->inPlay))
@@ -371,6 +381,7 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
if (!(copy = from->removeCard(card, doCopy)))
return NULL; //ERROR
if (card->miracle)
{
copy->miracle = true;
@@ -435,11 +446,12 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
previous->next = NULL;
SAFE_DELETE(previous);
}
}
if(!asCopy)
{
if(shufflelibrary)
copy->owner->game->library->shuffle();
copy->owner->game->library->shuffle();//shouldnt we only ever do this if you clicked close on your library gui??????
WEvent * e = NEW WEventZoneChange(copy, from, to);
g->receiveEvent(e);
@@ -995,6 +1007,14 @@ MTGGameZone * MTGGameZone::intToZone(int zoneId, Player * p, Player * p2)
return p->opponent()->game->stack;
case STACK:
return p->game->stack;
case MY_REVEAL:
return p->game->reveal;
case OPPONENT_REVEAL:
return p->opponent()->game->reveal;
case REVEAL:
return p->game->reveal;
}
if (!p2) return NULL;
switch (zoneId)
@@ -1017,6 +1037,9 @@ MTGGameZone * MTGGameZone::intToZone(int zoneId, Player * p, Player * p2)
case TARGET_CONTROLLER_STACK:
return p2->game->stack;
case TARGET_CONTROLLER_REVEAL:
return p2->game->reveal;
default:
return NULL;
}
@@ -1114,6 +1137,18 @@ MTGGameZone * MTGGameZone::intToZone(GameObserver *g, int zoneId, MTGCardInstanc
if(source->playerTarget)
return source->playerTarget->game->stack;
else return source->controller()->game->stack;
case TARGET_OWNER_REVEAL:
return target->owner->game->reveal;
case REVEAL:
return target->owner->game->reveal;
case OWNER_REVEAL:
return target->owner->game->reveal;
case TARGETED_PLAYER_REVEAL:
if (source->playerTarget)
return source->playerTarget->game->reveal;
else return source->controller()->game->reveal;
default:
return NULL;
}
@@ -1141,6 +1176,8 @@ int MTGGameZone::zoneStringToId(string zoneName)
"mystack", "opponentstack", "targetownerstack", "targetcontrollerstack", "ownerstack", "stack","targetedpersonsstack",
"myreveal", "opponentreveal", "targetownerreveal", "targetcontrollerreveal", "ownerreveal", "reveal","targetedpersonsreveal",
};
int values[] = { MY_GRAVEYARD, OPPONENT_GRAVEYARD, TARGET_OWNER_GRAVEYARD, TARGET_CONTROLLER_GRAVEYARD, OWNER_GRAVEYARD,
@@ -1160,7 +1197,9 @@ int MTGGameZone::zoneStringToId(string zoneName)
MY_EXILE, OPPONENT_EXILE, TARGET_OWNER_EXILE, TARGET_CONTROLLER_EXILE, OWNER_EXILE, EXILE,TARGETED_PLAYER_EXILE,
MY_STACK, OPPONENT_STACK, TARGET_OWNER_STACK, TARGET_CONTROLLER_STACK, OWNER_STACK, STACK,TARGETED_PLAYER_STACK };
MY_STACK, OPPONENT_STACK, TARGET_OWNER_STACK, TARGET_CONTROLLER_STACK, OWNER_STACK, STACK,TARGETED_PLAYER_STACK,
MY_REVEAL, OPPONENT_REVEAL, TARGET_OWNER_REVEAL, TARGET_CONTROLLER_REVEAL, OWNER_REVEAL, REVEAL,TARGETED_PLAYER_REVEAL };
int max = sizeof(values) / sizeof *(values);

View File

@@ -367,9 +367,7 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card)
return 0;
Player * player = game->currentlyActing();
ManaCost * cost = card->getManaCost();
//this handles extra cost payments at the moment a card is played.
if (cost->isExtraPaymentSet())
{
if (!game->targetListIsSet(card))
@@ -383,7 +381,7 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card)
game->mExtraPayment = cost->extraCosts;
return 0;
}
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
int payResult = player->getManaPool()->pay(card->getManaCost());
if (card->getManaCost()->getKicker() && (OptionKicker::KICKER_ALWAYS == options[Options::KICKERPAYMENT].number || card->controller()->isAI()))
@@ -497,6 +495,9 @@ int MTGKickerRule::isReactingToClick(MTGCardInstance * card, ManaCost *)
ManaCost * withKickerCost= NEW ManaCost(card->getManaCost());
withKickerCost->add(card->getManaCost()->getKicker());
//cost reduction/recalculation must be here or outside somehow...
//no recalculations beyound this point, reactToClick is the function that
//happens only with the assumption that you could actually pay for it, any calculations after will
//have negitive effects. this function is basically "can i play this card?"
#ifdef WIN32
withKickerCost->Dump();
#endif
@@ -532,7 +533,7 @@ int MTGKickerRule::reactToClick(MTGCardInstance * card)
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
int payResult = player->getManaPool()->pay(card->getManaCost());
if (card->getManaCost()->getKicker())
{ //cost reduction/recalculation must be here or outside somehow...
{
ManaCost * withKickerCost= NEW ManaCost(card->getManaCost());
withKickerCost->add(withKickerCost->getKicker());
if (card->getManaCost()->getKicker()->isMulti)
@@ -1345,7 +1346,68 @@ MTGOverloadRule * MTGOverloadRule::clone() const
{
return NEW MTGOverloadRule(*this);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//bestow
MTGBestowRule::MTGBestowRule(GameObserver* observer, int _id) :
MTGAlternativeCostRule(observer, _id)
{
aType = MTGAbility::BESTOW_COST;
}
int MTGBestowRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
if (!card->model)
return 0;
Player * player = game->currentlyActing();
if (!card->model->data->getManaCost()->getBestow())
return 0;
if (card->isInPlay(game))
return 0;
ManaCost * cost = NEW ManaCost(card->model->data->getManaCost()->getBestow());
ManaCost * newCost = card->computeNewCost(card, cost, cost);
if (newCost->extraCosts)
for (unsigned int i = 0; i < newCost->extraCosts->costs.size(); i++)
{
newCost->extraCosts->costs[i]->setSource(card);
}
SAFE_DELETE(cost);
if (card->isLand())
return 0;
if (!card->controller()->inPlay()->hasType("creature") && !card->controller()->opponent()->inPlay()->hasType("creature"))
return 0;
return MTGAlternativeCostRule::isReactingToClick(card, mana, newCost);
}
int MTGBestowRule::reactToClick(MTGCardInstance * card)
{
if (!isReactingToClick(card))
return 0;
//this new method below in all alternative cost type causes a memleak, however, you cant safedelete the cost here as it cause a crash
//TODO::::we need to get to the source of this leak and fix it.
ManaCost * cost = NEW ManaCost(card->model->data->getManaCost()->getBestow());
ManaCost * newCost = card->computeNewCost(card, cost, cost);
if (newCost->extraCosts)
for (unsigned int i = 0; i < newCost->extraCosts->costs.size(); i++)
{
newCost->extraCosts->costs[i]->setSource(card);
}
card->paymenttype = MTGAbility::BESTOW_COST;
card->spellTargetType = "creature|battlefield";
return MTGAlternativeCostRule::reactToClick(card, newCost, ManaCost::MANA_PAID_WITH_BESTOW, false);
}
ostream& MTGBestowRule::toString(ostream& out) const
{
out << "MTGBestowRule ::: (";
return MTGAbility::toString(out) << ")";
}
MTGBestowRule * MTGBestowRule::clone() const
{
return NEW MTGBestowRule(*this);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//ATTACK COST
@@ -1425,7 +1487,6 @@ MTGBlockCostRule::MTGBlockCostRule(GameObserver* observer, int _id) :
aType = MTGAbility::BLOCK_COST;
scost = "Pay to block";
}
int MTGBlockCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *)
{
if (currentPhase == MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting
@@ -1536,6 +1597,14 @@ int MTGAttackRule::receiveEvent(WEvent *e)
for (int i = 0; i < z->nb_cards; i++)
{
MTGCardInstance * card = z->cards[i];
if (card->isAttacker() && card->has(Constants::NOSOLO))
{
TargetChooserFactory tf(game);
TargetChooser * tc = tf.createTargetChooser("creature[attacking]", NULL);
int Check = card->controller()->game->battlefield->countByCanTarget(tc);
if (Check <2)
card->initAttackersDefensers();
}
if (!card->isAttacker() && !event->from->isExtra && card->has(Constants::MUSTATTACK))//cards are only required to attack in the real attack phase of a turn.
reactToClick(card);
if (!card->isAttacker() && card->has(Constants::TREASON) && p->isAI())
@@ -1848,6 +1917,50 @@ PermanentAbility(observer, _id)
int MTGBlockRule::receiveEvent(WEvent *e)
{
if (dynamic_cast<WEventBlockersChosen*>(e))
{//do not refactor, these are keep seperate for readability.
Player * p = game->currentPlayer;
vector<MTGCardInstance *> Attacker;
MTGGameZone * k = p->game->inPlay;
for (int i = 0; i < k->nb_cards; i++)
{
MTGCardInstance * card = k->cards[i];
if (card->isAttacker())
{
Attacker.push_back(card);
}
}
//force cards that must block, to block whatever is first found. players have a chance to set thier own
//but if ignored we do it for them.
if (Attacker.size())
{
MTGGameZone * tf = p->opponent()->game->inPlay;
for (size_t i = 0; i < tf->cards.size(); i++)
{
MTGCardInstance * card = tf->cards[i];
if (card->has(Constants::MUSTBLOCK) && !card->defenser && card->canBlock())
{//force mustblockers to block the first thing theyre allowed to block if player leaves blockers with them
//unassigned as a block.
for (size_t i = 0; i < Attacker.size(); i++)
{
if (card->canBlock(Attacker[i]) && !card->defenser)
{
blocker = NEW AABlock(card->getObserver(), -1, card, NULL);
blocker->oneShot = true;
blocker->forceDestroy = 1;
blocker->canBeInterrupted = false;
blocker->target = Attacker[i];
blocker->resolve();
SAFE_DELETE(blocker);
}
}
}
}
}
if (dynamic_cast<WEventBlockersChosen*>(e))
{
@@ -1866,6 +1979,25 @@ int MTGBlockRule::receiveEvent(WEvent *e)
//but this action can not be ignored.
}
}
//if a card with menace is not blocked by 2 or more, remove any known blockers and attacking as normal.
MTGGameZone * z = p->game->inPlay;
for (int i = 0; i < z->nb_cards; i++)
{
MTGCardInstance * card = z->cards[i];
if (card->has(Constants::MENACE) && card->blockers.size() < 2)
{
while (card->blockers.size())
{
MTGCardInstance * blockingCard = card->blockers.front();
blockingCard->toggleDefenser(NULL);
}
}
}
}
return 1;
}

View File

@@ -152,7 +152,8 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
manaCost->addExtraCost(NEW SacrificeCost(tc));
}
break;
case 'e': //Exile
case 'e':
//Exile
manaCost->addExtraCost(NEW ExileTargetCost(tc));
break;
case 'h': //bounce (move to Hand)
@@ -387,6 +388,7 @@ ManaCost::ManaCost(ManaCost * manaCost)
FlashBack = NEW ManaCost( manaCost->FlashBack );
morph = NEW ManaCost( manaCost->morph );
suspend = NEW ManaCost( manaCost->suspend );
Bestow = NEW ManaCost(manaCost->Bestow);
extraCosts = manaCost->extraCosts ? manaCost->extraCosts->clone() : NULL;
manaUsedToCast = NULL;
@@ -415,7 +417,8 @@ ManaCost::ManaCost(const ManaCost& manaCost)
FlashBack = NEW ManaCost( manaCost.FlashBack );
morph = NEW ManaCost( manaCost.morph );
suspend = NEW ManaCost( manaCost.suspend );
Bestow = NEW ManaCost(manaCost.Bestow);
extraCosts = manaCost.extraCosts ? manaCost.extraCosts->clone() : NULL;
manaUsedToCast = NULL;
xColor = manaCost.xColor;
@@ -438,6 +441,7 @@ ManaCost & ManaCost::operator= (const ManaCost & manaCost)
FlashBack = manaCost.FlashBack;
morph = manaCost.morph;
suspend = manaCost.suspend;
Bestow = manaCost.Bestow;
manaUsedToCast = manaCost.manaUsedToCast;
xColor = manaCost.xColor;
}
@@ -454,6 +458,7 @@ ManaCost::~ManaCost()
SAFE_DELETE(Retrace);
SAFE_DELETE(morph);
SAFE_DELETE(suspend);
SAFE_DELETE(Bestow);
SAFE_DELETE(manaUsedToCast);
cost.erase(cost.begin() ,cost.end());
@@ -539,6 +544,7 @@ void ManaCost::init()
Retrace = NULL;
morph = NULL;
suspend = NULL;
Bestow = NULL;
manaUsedToCast = NULL;
isMulti = false;
xColor = -1;
@@ -563,6 +569,7 @@ void ManaCost::resetCosts()
SAFE_DELETE(Retrace);
SAFE_DELETE(morph);
SAFE_DELETE(suspend);
SAFE_DELETE(Bestow);
}
void ManaCost::copy(ManaCost * _manaCost)
@@ -628,6 +635,12 @@ void ManaCost::copy(ManaCost * _manaCost)
suspend = NEW ManaCost();
suspend->copy(_manaCost->suspend);
}
SAFE_DELETE(Bestow);
if (_manaCost->Bestow)
{
Bestow = NEW ManaCost();
Bestow->copy(_manaCost->Bestow);
}
xColor = _manaCost->xColor;
}
@@ -1092,6 +1105,7 @@ void ManaPool::Empty()
SAFE_DELETE(Retrace);
SAFE_DELETE(morph);
SAFE_DELETE(suspend);
SAFE_DELETE(Bestow);
SAFE_DELETE(manaUsedToCast);
init();
WEvent * e = NEW WEventEmptyManaPool(this);

View File

@@ -413,12 +413,13 @@ void Rules::initGame(GameObserver *g, bool currentPlayerSet)
{
p->mAvatarName = initState.playerData[i].player->mAvatarName;
}
MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay, p->game->exile };
MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay, p->game->exile , p->game->reveal };
MTGGameZone * loadedPlayerZones[] = { initState.playerData[i].player->game->graveyard,
initState.playerData[i].player->game->library,
initState.playerData[i].player->game->hand,
initState.playerData[i].player->game->inPlay,
initState.playerData[i].player->game->exile };
initState.playerData[i].player->game->exile,
initState.playerData[i].player->game->reveal };
for (int j = 0; j < 5; j++)
{
MTGGameZone * zone = playerZones[j];

View File

@@ -156,6 +156,11 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
{
zones[nbzones++] = MTGGameZone::ALL_ZONES;
}
else if (zoneName.compare("reveal") == 0)
{
zones[nbzones++] = MTGGameZone::MY_REVEAL;
zones[nbzones++] = MTGGameZone::OPPONENT_REVEAL;
}
else if (zoneName.compare("graveyard") == 0)
{
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
@@ -637,15 +642,15 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
}
}
if (attribute.find("iscolorless") != string::npos)
{
attributefound = 1;
for (int cid = 1; cid < Constants::NB_Colors; cid++)
{
cd->SetExclusionColor(cid);
}
cd->mode = CardDescriptor::CD_OR;
}
if (attribute.find("colorless") != string::npos)
{
attributefound = 1;
for (int cid = 1; cid < Constants::NB_Colors; cid++)
{
cd->SetExclusionColor(cid);
}
cd->mode = CardDescriptor::CD_OR;
}
if (attribute.find("chosencolor") != string::npos)
{
@@ -817,6 +822,7 @@ TargetChooser::TargetChooser(GameObserver *observer, MTGCardInstance * card, int
TargetsList(), observer(observer)
{
forceTargetListReady = 0;
forceTargetListReadyByPlayer = 0;
source = card;
targetter = card;
maxtargets = _maxtargets;
@@ -899,6 +905,10 @@ int TargetChooser::ForceTargetListReady()
int TargetChooser::targetsReadyCheck()
{
if (targetMin == false && !targets.size() && forceTargetListReadyByPlayer)
{
return TARGET_OK_FULL;//we have no min amount for targets and 0 targets is a valid amount player called for a forced finish.
}
if (!targets.size())
{
return TARGET_NOK;
@@ -931,8 +941,8 @@ bool TargetChooser::validTargetsExist(int maxTargets)
int maxAmount = 0;
Player *p = observer->players[i];
if (canTarget(p)) return true;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack };
for (int k = 0; k < 6; k++)
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * z = zones[k];
if (targetsZone(z))
@@ -965,8 +975,8 @@ int TargetChooser::countValidTargets(bool withoutProtections)
Player *p = observer->players[i];
if(canTarget(p))
result++;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack };
for (int k = 0; k < 6; k++)
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * z = zones[k];
if (targetsZone(z))

View File

@@ -123,6 +123,7 @@ WEventTarget::WEventTarget(MTGCardInstance * card,MTGCardInstance * source) :
WEventCardUpdate(card),card(card),source(source)
{
card->cardistargetted = 1;
if(source)
source->cardistargetter = 1;
}