Erwan
- Adding equipments. They work like auras, except you have to add an "auto={cost}:equip" line. See Behemoth sledge in ARB for an example. Please test a lot before committing, thanks :)
This commit is contained in:
@@ -1,4 +1,17 @@
|
|||||||
[card]
|
[card]
|
||||||
|
id=179545
|
||||||
|
name=Behemoth Sledge
|
||||||
|
mana={1}{G}{W}
|
||||||
|
type=Artifact
|
||||||
|
subtype=Equipment
|
||||||
|
text=Equipped creature gets +2/+2 and has lifelink and trample. Equip {3}
|
||||||
|
auto={3}:equip
|
||||||
|
auto=2/2
|
||||||
|
auto=lifelink
|
||||||
|
auto=trample
|
||||||
|
rarity=U
|
||||||
|
[/card]
|
||||||
|
[card]
|
||||||
text=Trample, haste At end of turn, Blitz Hellion's owner shuffles it into his or her library.
|
text=Trample, haste At end of turn, Blitz Hellion's owner shuffles it into his or her library.
|
||||||
auto=@next my endofturn:moveto(myLibrary) && shuffle
|
auto=@next my endofturn:moveto(myLibrary) && shuffle
|
||||||
id=179406
|
id=179406
|
||||||
|
|||||||
@@ -72,15 +72,7 @@ toughness=1
|
|||||||
text=As long as you control another multicolored permanent, Bant Sureblade gets +1/+1 and has first strike.
|
text=As long as you control another multicolored permanent, Bant Sureblade gets +1/+1 and has first strike.
|
||||||
rarity=C
|
rarity=C
|
||||||
[/card]
|
[/card]
|
||||||
[card]
|
|
||||||
id=179545
|
|
||||||
name=Behemoth Sledge
|
|
||||||
mana={1}{G}{W}
|
|
||||||
type=Artifact
|
|
||||||
subtype=Equipment
|
|
||||||
text=Equipped creature gets +2/+2 and has lifelink and trample. Equip {3}
|
|
||||||
rarity=U
|
|
||||||
[/card]
|
|
||||||
[card]
|
[card]
|
||||||
id=185057
|
id=185057
|
||||||
name=Bituminous Blast
|
name=Bituminous Blast
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ basal_sliver.txt
|
|||||||
beacon_of_creation.txt
|
beacon_of_creation.txt
|
||||||
beacon_of_destruction.txt
|
beacon_of_destruction.txt
|
||||||
beacon_of_unrest.txt
|
beacon_of_unrest.txt
|
||||||
|
behemoth_sledge.txt
|
||||||
|
behemoth_sledge2.txt
|
||||||
|
behemoth_sledge3.txt
|
||||||
|
behemoth_sledge4.txt
|
||||||
belligerent_hatchling.txt
|
belligerent_hatchling.txt
|
||||||
benalish_knight.txt
|
benalish_knight.txt
|
||||||
black_vise.txt
|
black_vise.txt
|
||||||
@@ -355,4 +359,5 @@ momir/overcost.txt
|
|||||||
########################
|
########################
|
||||||
#AI Tests
|
#AI Tests
|
||||||
########################
|
########################
|
||||||
ai/goblin_artillery.txt
|
#Removed until we can have these tests work on all machines :(
|
||||||
|
#ai/goblin_artillery.txt
|
||||||
|
|||||||
31
projects/mtg/bin/Res/test/behemoth_sledge.txt
Normal file
31
projects/mtg/bin/Res/test/behemoth_sledge.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#Test:equipment
|
||||||
|
[INIT]
|
||||||
|
FIRSTMAIN
|
||||||
|
[PLAYER1]
|
||||||
|
hand:behemoth sledge
|
||||||
|
manapool:{4}{G}{W}
|
||||||
|
inplay:grizzly bears
|
||||||
|
[PLAYER2]
|
||||||
|
[DO]
|
||||||
|
behemoth sledge
|
||||||
|
behemoth sledge
|
||||||
|
grizzly bears
|
||||||
|
next
|
||||||
|
#begin
|
||||||
|
next
|
||||||
|
#attackers
|
||||||
|
grizzly bears
|
||||||
|
next
|
||||||
|
#blockers
|
||||||
|
next
|
||||||
|
#damage
|
||||||
|
next
|
||||||
|
#end combat
|
||||||
|
[ASSERT]
|
||||||
|
COMBATEND
|
||||||
|
[PLAYER1]
|
||||||
|
life:24
|
||||||
|
inplay:grizzly bears,behemoth sledge
|
||||||
|
[PLAYER2]
|
||||||
|
life:16
|
||||||
|
[END]
|
||||||
34
projects/mtg/bin/Res/test/behemoth_sledge2.txt
Normal file
34
projects/mtg/bin/Res/test/behemoth_sledge2.txt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#Test:equipment
|
||||||
|
[INIT]
|
||||||
|
FIRSTMAIN
|
||||||
|
[PLAYER1]
|
||||||
|
hand:behemoth sledge
|
||||||
|
manapool:{7}{G}{W}
|
||||||
|
inplay:grizzly bears,raging goblin
|
||||||
|
[PLAYER2]
|
||||||
|
[DO]
|
||||||
|
behemoth sledge
|
||||||
|
behemoth sledge
|
||||||
|
grizzly bears
|
||||||
|
behemoth sledge
|
||||||
|
raging goblin
|
||||||
|
next
|
||||||
|
#begin
|
||||||
|
next
|
||||||
|
#attackers
|
||||||
|
grizzly bears
|
||||||
|
raging goblin
|
||||||
|
next
|
||||||
|
#blockers
|
||||||
|
next
|
||||||
|
#damage
|
||||||
|
next
|
||||||
|
#end combat
|
||||||
|
[ASSERT]
|
||||||
|
COMBATEND
|
||||||
|
[PLAYER1]
|
||||||
|
life:23
|
||||||
|
inplay:grizzly bears,raging goblin,behemoth sledge
|
||||||
|
[PLAYER2]
|
||||||
|
life:15
|
||||||
|
[END]
|
||||||
33
projects/mtg/bin/Res/test/behemoth_sledge3.txt
Normal file
33
projects/mtg/bin/Res/test/behemoth_sledge3.txt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#Test:equipment
|
||||||
|
[INIT]
|
||||||
|
FIRSTMAIN
|
||||||
|
[PLAYER1]
|
||||||
|
hand:behemoth sledge
|
||||||
|
manapool:{4}{G}{W}
|
||||||
|
inplay:raging goblin
|
||||||
|
[PLAYER2]
|
||||||
|
inplay:mountain
|
||||||
|
hand:lightning bolt
|
||||||
|
[DO]
|
||||||
|
behemoth sledge
|
||||||
|
behemoth sledge
|
||||||
|
raging goblin
|
||||||
|
eot
|
||||||
|
next
|
||||||
|
#upkeeep
|
||||||
|
next
|
||||||
|
#draw
|
||||||
|
next
|
||||||
|
#firstmain
|
||||||
|
mountain
|
||||||
|
lightning bolt
|
||||||
|
raging goblin
|
||||||
|
[ASSERT]
|
||||||
|
FIRSTMAIN
|
||||||
|
[PLAYER1]
|
||||||
|
inplay:behemoth sledge
|
||||||
|
graveyard:raging goblin
|
||||||
|
[PLAYER2]
|
||||||
|
inplay:mountain
|
||||||
|
graveyard:lightning bolt
|
||||||
|
[END]
|
||||||
54
projects/mtg/bin/Res/test/behemoth_sledge4.txt
Normal file
54
projects/mtg/bin/Res/test/behemoth_sledge4.txt
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#Test:equipment
|
||||||
|
[INIT]
|
||||||
|
FIRSTMAIN
|
||||||
|
[PLAYER1]
|
||||||
|
hand:behemoth sledge
|
||||||
|
manapool:{4}{G}{W}
|
||||||
|
inplay:raging goblin
|
||||||
|
[PLAYER2]
|
||||||
|
inplay:mountain,island,forest
|
||||||
|
hand:smash
|
||||||
|
[DO]
|
||||||
|
behemoth sledge
|
||||||
|
behemoth sledge
|
||||||
|
raging goblin
|
||||||
|
eot
|
||||||
|
next
|
||||||
|
#upkeeep
|
||||||
|
next
|
||||||
|
#draw
|
||||||
|
next
|
||||||
|
#firstmain
|
||||||
|
mountain
|
||||||
|
island
|
||||||
|
forest
|
||||||
|
smash
|
||||||
|
behemoth sledge
|
||||||
|
eot
|
||||||
|
next
|
||||||
|
#upkeeep
|
||||||
|
next
|
||||||
|
#draw
|
||||||
|
next
|
||||||
|
#firstmain
|
||||||
|
next
|
||||||
|
#begin
|
||||||
|
next
|
||||||
|
#attackers
|
||||||
|
raging goblin
|
||||||
|
next
|
||||||
|
#blocker
|
||||||
|
next
|
||||||
|
#damage
|
||||||
|
next
|
||||||
|
#end
|
||||||
|
[ASSERT]
|
||||||
|
COMBATEND
|
||||||
|
[PLAYER1]
|
||||||
|
graveyard:behemoth sledge
|
||||||
|
inplay:raging goblin
|
||||||
|
[PLAYER2]
|
||||||
|
inplay:mountain,island,forest
|
||||||
|
graveyard:smash
|
||||||
|
life:19
|
||||||
|
[END]
|
||||||
@@ -945,6 +945,76 @@ class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AEquip:public TargetAbility{
|
||||||
|
public:
|
||||||
|
vector<MTGAbility *> currentAbilities;
|
||||||
|
AEquip(int _id, MTGCardInstance * _source, ManaCost * _cost=NULL, int doTap=0, int myturnOnly = 1):TargetAbility(_id,_source,NULL,_cost,myturnOnly,doTap){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int unequip(){
|
||||||
|
source->target = NULL;
|
||||||
|
for (size_t i = 0; i < currentAbilities.size(); ++i){
|
||||||
|
MTGAbility * a = currentAbilities[i];
|
||||||
|
if(dynamic_cast<AEquip *>(a)){
|
||||||
|
SAFE_DELETE(a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GameObserver::GetInstance()->removeObserver(currentAbilities[i]);
|
||||||
|
}
|
||||||
|
currentAbilities.clear();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int equip(MTGCardInstance * equipped){
|
||||||
|
source->target = equipped;
|
||||||
|
AbilityFactory af;
|
||||||
|
af.getAbilities(¤tAbilities,NULL,source);
|
||||||
|
for (size_t i = 0; i < currentAbilities.size(); ++i){
|
||||||
|
MTGAbility * a = currentAbilities[i];
|
||||||
|
if(dynamic_cast<AEquip *>(a)) continue;
|
||||||
|
a->addToGame();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int resolve(){
|
||||||
|
MTGCardInstance * mTarget = tc->getNextCardTarget();
|
||||||
|
if (!mTarget) return 0;
|
||||||
|
if (mTarget == source) return 0;
|
||||||
|
unequip();
|
||||||
|
equip(mTarget);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * getMenuText(){
|
||||||
|
return "Equip";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int testDestroy(){
|
||||||
|
if (source->target && !game->isInPlay(source->target))
|
||||||
|
unequip();
|
||||||
|
return TargetAbility::testDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
int destroy(){
|
||||||
|
unequip();
|
||||||
|
return TargetAbility::destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
AEquip * clone() const{
|
||||||
|
AEquip * a = NEW AEquip(*this);
|
||||||
|
a->isClone = 1;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*Gives life each time a spell matching CardDescriptor's criteria are match . Optionnal manacost*/
|
/*Gives life each time a spell matching CardDescriptor's criteria are match . Optionnal manacost*/
|
||||||
class ASpellCastLife:public MTGAbility{
|
class ASpellCastLife:public MTGAbility{
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ class AbilityFactory{
|
|||||||
int parsePowerToughness(string s, int *power, int *toughness);
|
int parsePowerToughness(string s, int *power, int *toughness);
|
||||||
TriggeredAbility * parseTrigger(string s, int id, Spell * spell, MTGCardInstance *card, Targetable * target);
|
TriggeredAbility * parseTrigger(string s, int id, Spell * spell, MTGCardInstance *card, Targetable * target);
|
||||||
public:
|
public:
|
||||||
|
int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0);
|
||||||
MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0);
|
MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0);
|
||||||
int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY, TargetChooser * tc = NULL);
|
int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY, TargetChooser * tc = NULL);
|
||||||
int magicText(int id, Spell * spell, MTGCardInstance * card = NULL, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL);
|
int magicText(int id, Spell * spell, MTGCardInstance * card = NULL, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL);
|
||||||
|
|||||||
@@ -264,6 +264,9 @@ ActionLayer::ActionLayer(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
ActionLayer::~ActionLayer(){
|
ActionLayer::~ActionLayer(){
|
||||||
|
for (int i=mCount-1;i>=0;i--){
|
||||||
|
moveToGarbage((ActionElement *)mObjects[i]);
|
||||||
|
}
|
||||||
SAFE_DELETE(abilitiesMenu);
|
SAFE_DELETE(abilitiesMenu);
|
||||||
cleanGarbage();
|
cleanGarbage();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,12 @@ ActionLayer * DuelLayers::actionLayer(){
|
|||||||
DuelLayers::DuelLayers() : nbitems(0) {}
|
DuelLayers::DuelLayers() : nbitems(0) {}
|
||||||
|
|
||||||
DuelLayers::~DuelLayers(){
|
DuelLayers::~DuelLayers(){
|
||||||
for (int i = 0; i < nbitems; ++i) delete objects[i];
|
int _nbitems = nbitems;
|
||||||
|
nbitems = 0;
|
||||||
|
for (int i = 0; i < _nbitems; ++i){
|
||||||
|
delete objects[i];
|
||||||
|
objects[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < waiters.size(); ++i)
|
for (size_t i = 0; i < waiters.size(); ++i)
|
||||||
delete(waiters[i]);
|
delete(waiters[i]);
|
||||||
|
|||||||
@@ -215,6 +215,15 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
return amp;
|
return amp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AEquip *ae = dynamic_cast<AEquip*>(a);
|
||||||
|
if (ae){
|
||||||
|
ae->cost = cost;
|
||||||
|
TargetChooserFactory tcf;
|
||||||
|
ae->tc = tcf.createTargetChooser("creature|myBattlefield", card);
|
||||||
|
return ae;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int limit = 0;
|
int limit = 0;
|
||||||
unsigned int limit_str = s.find("limit:");
|
unsigned int limit_str = s.find("limit:");
|
||||||
if (limit_str != string::npos){
|
if (limit_str != string::npos){
|
||||||
@@ -405,6 +414,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
|||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Equipment
|
||||||
|
found = s.find("equip");
|
||||||
|
if (found != string::npos){
|
||||||
|
MTGAbility * a = NEW AEquip(id,card);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//MoveTo Move a card from a zone to another
|
//MoveTo Move a card from a zone to another
|
||||||
found = s.find("moveto(");
|
found = s.find("moveto(");
|
||||||
@@ -825,19 +841,9 @@ int AbilityFactory::computeX(Spell * spell, MTGCardInstance * card){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Some basic functionalities that can be added automatically in the text file
|
|
||||||
/*
|
|
||||||
* Several objects are computed from the text string, and have a direct influence on what action we should take
|
|
||||||
* (direct impact on the game such as draw a card immediately, or create a New GameObserver and add it to the Abilities,etc..)
|
|
||||||
* These objects are:
|
|
||||||
* - trigger (if there is an "@" in the string, this is a triggered ability)
|
|
||||||
* - target (if there ie a "target(" in the string, then this is a TargetAbility)
|
|
||||||
* - doTap (a dirty way to know if tapping is included in the cost...
|
|
||||||
*/
|
|
||||||
int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int mode, TargetChooser * tc){
|
|
||||||
int dryMode = 0;
|
|
||||||
if (!spell) dryMode = 1;
|
|
||||||
|
|
||||||
|
int AbilityFactory::getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card, int id){
|
||||||
|
|
||||||
if (!card && spell) card = spell->source;
|
if (!card && spell) card = spell->source;
|
||||||
if (!card) return 0;
|
if (!card) return 0;
|
||||||
MTGCardInstance * target = card->target;
|
MTGCardInstance * target = card->target;
|
||||||
@@ -854,7 +860,6 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
|
|||||||
unsigned int found;
|
unsigned int found;
|
||||||
int result = id;
|
int result = id;
|
||||||
|
|
||||||
|
|
||||||
while (magicText.size()){
|
while (magicText.size()){
|
||||||
found = magicText.find("\n");
|
found = magicText.find("\n");
|
||||||
if (found != string::npos){
|
if (found != string::npos){
|
||||||
@@ -866,6 +871,34 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
MTGAbility * a = parseMagicLine(line, result, spell, card);
|
MTGAbility * a = parseMagicLine(line, result, spell, card);
|
||||||
|
if (a){
|
||||||
|
v->push_back(a);
|
||||||
|
result++;
|
||||||
|
}else{
|
||||||
|
OutputDebugString("ABILITYFACTORY ERROR: Parser returned NULL\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Some basic functionalities that can be added automatically in the text file
|
||||||
|
/*
|
||||||
|
* Several objects are computed from the text string, and have a direct influence on what action we should take
|
||||||
|
* (direct impact on the game such as draw a card immediately, or create a New GameObserver and add it to the Abilities,etc..)
|
||||||
|
* These objects are:
|
||||||
|
* - trigger (if there is an "@" in the string, this is a triggered ability)
|
||||||
|
* - target (if there ie a "target(" in the string, then this is a TargetAbility)
|
||||||
|
* - doTap (a dirty way to know if tapping is included in the cost...
|
||||||
|
*/
|
||||||
|
int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int mode, TargetChooser * tc){
|
||||||
|
int dryMode = 0;
|
||||||
|
if (!spell) dryMode = 1;
|
||||||
|
|
||||||
|
vector<MTGAbility *> v;
|
||||||
|
int result = getAbilities(&v,spell,card,id);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < v.size(); ++i){
|
||||||
|
MTGAbility * a = v[i];
|
||||||
if (dryMode){
|
if (dryMode){
|
||||||
result = abilityEfficiency(a, card->controller(),mode,tc);
|
result = abilityEfficiency(a, card->controller(),mode,tc);
|
||||||
SAFE_DELETE(a);
|
SAFE_DELETE(a);
|
||||||
@@ -879,7 +912,6 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
|
|||||||
}else{
|
}else{
|
||||||
a->addToGame();
|
a->addToGame();
|
||||||
}
|
}
|
||||||
result++;
|
|
||||||
}else{
|
}else{
|
||||||
OutputDebugString("ABILITYFACTORY ERROR: Parser returned NULL\n");
|
OutputDebugString("ABILITYFACTORY ERROR: Parser returned NULL\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user