- Updated Parser mechanism. Right now this doesn't change functionalities much, but should be more readable, and make it easier to code some new abilities in the future
- Fixed regenerate, broken with r532
- Death Ward now works
- I think "&&" now works with all abilities, needs to be tested...
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-07-11 15:59:51 +00:00
parent 307c41c563
commit c8333e76b1
34 changed files with 2157 additions and 1816 deletions

View File

@@ -501,6 +501,7 @@ mana={W}
text={B}{B}: Counter target green spell.
id=1151
name=Deathgrip
auto={B}{B}:fizzle target(*[green]|stack)
rarity=U
type=Enchantment
mana={B}{B}
@@ -1251,6 +1252,7 @@ toughness=1
text={G}{G}: Counter target black spell.
id=1256
name=Lifeforce
auto={G}{G}:fizzle target(*[black]|stack)
rarity=U
type=Enchantment
mana={G}{G}

View File

@@ -13,6 +13,8 @@ generic/legendary.txt
generic/lifelink.txt
generic/persist.txt
generic/persist2.txt
generic/rampage.txt
generic/regenerate.txt
generic/sacrifice.txt
generic/wither.txt
########################
@@ -22,6 +24,7 @@ afflict.txt
akron_legionnaire.txt
Amugaba.txt
anarchy.txt
ancestors_chosen.txt
animate_dead.txt
animate_dead2.txt
animate_dead3.txt
@@ -57,6 +60,7 @@ counterspell3.txt
counterspell4.txt
creature_bond.txt
dauthi_embrace.txt
death_ward.txt
deja_vu.txt
dingus_egg.txt
doomed_necromancer.txt
@@ -76,12 +80,14 @@ fountain_of_youth.txt
ghost_warden.txt
giant_growth.txt
giant_growth2.txt
glimpse_the_unthinkable.txt
goblin_balloon_brigade.txt
goblin_balloon_brigade2.txt
goblin_king.txt
gravedigger.txt
#hammerfist_giant.txt
hannas_custody.txt
howl_of_the_night_pack.txt
hymn_of_rebirth.txt
icatian_priest.txt
keldon_warlord.txt
@@ -95,6 +101,8 @@ living_lands.txt
lord_of_the_pit.txt
lord_of_the_pit2.txt
master_of_etherium.txt
millstone.txt
mind_rot.txt
nantuko_husk.txt
Nevinyrrals_Disk.txt
Nevinyrrals_Disk2.txt
@@ -118,8 +126,10 @@ siege_gang_commander.txt
shivan_hellkite.txt
shock.txt
sphinx_summoner.txt
spitting_earth.txt
spark_elemental.txt
spirit_link.txt
spoils_of_evil.txt
stasis.txt
steelclad_serpent1.txt
steelclad_serpent2.txt

View File

@@ -0,0 +1,21 @@
#Testing Ancestors chosen
[INIT]
FIRSTMAIN
[PLAYER1]
hand:Ancestor's chosen
graveyard:swamp,grizzly bears,dragon engine
manapool:{5}{W}{W}
[PLAYER2]
graveyard:black knight
[DO]
Ancestor's chosen
[ASSERT]
FIRSTMAIN
[PLAYER1]
inplay:Ancestor's chosen
life:23
graveyard:swamp,grizzly bears,dragon engine
manapool:{0}
[PLAYER2]
graveyard:black knight
[END]

View File

@@ -0,0 +1,26 @@
#Testing Regenerate (Death Ward)
[INIT]
COMBATATTACKERS
[PLAYER1]
hand:Death Ward
manapool:{W}
inplay:raging goblin
[PLAYER2]
inplay:grizzly bears
[DO]
Death Ward
raging goblin
raging goblin
next
grizzly bears
next
next
[ASSERT]
COMBATEND
[PLAYER1]
inplay:raging goblin
graveyard:Death Ward
manapool:{0}
[PLAYER2]
inplay:grizzly bears
[END]

View File

@@ -0,0 +1,20 @@
#Testing Rampage
[INIT]
COMBATATTACKERS
[PLAYER1]
inplay:Elvish Berserker
[PLAYER2]
inplay:raging goblin
[DO]
Elvish Berserker
next
raging goblin
next
next
[ASSERT]
COMBATEND
[PLAYER1]
inplay:Elvish Berserker
[PLAYER2]
graveyard:raging goblin
[END]

View File

@@ -0,0 +1,22 @@
#Testing Regenerate
[INIT]
COMBATATTACKERS
[PLAYER1]
inplay:Drudge Skeletons,swamp
[PLAYER2]
inplay:raging goblin
[DO]
Drudge skeletons
swamp
Drudge skeletons
next
raging goblin
next
next
[ASSERT]
COMBATEND
[PLAYER1]
inplay:Drudge Skeletons,swamp
[PLAYER2]
graveyard:raging goblin
[END]

View File

@@ -0,0 +1,20 @@
#Testing Deplete (sorcery
[INIT]
FIRSTMAIN
[PLAYER1]
hand:Glimpse the Unthinkable
manapool:{U}{B}
[PLAYER2]
library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin
[DO]
Glimpse the Unthinkable
p2
[ASSERT]
FIRSTMAIN
[PLAYER1]
graveyard:Glimpse the Unthinkable
manapool:{0}
[PLAYER2]
library:swamp
graveyard:plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin
[END]

View File

@@ -0,0 +1,18 @@
#Testing Howl of the night pack
[INIT]
FIRSTMAIN
[PLAYER1]
hand:153996
inplay:1386,1387,1388
manapool:{6}{G}
[PLAYER2]
[DO]
153996
[ASSERT]
FIRSTMAIN
[PLAYER1]
inplay:1386,1387,1388,*,*,*
graveyard:153996
manapool:{0}
[PLAYER2]
[END]

View File

@@ -0,0 +1,20 @@
#Testing Deplete
[INIT]
FIRSTMAIN
[PLAYER1]
inplay:Millstone
manapool:{2}}
[PLAYER2]
library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin
[DO]
Millstone
p2
[ASSERT]
FIRSTMAIN
[PLAYER1]
inplay:Millstone
manapool:{0}
[PLAYER2]
library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight
graveyard:grizzly bears,raging goblin
[END]

View File

@@ -0,0 +1,20 @@
#Testing Random discard
[INIT]
FIRSTMAIN
[PLAYER1]
hand:Mind Rot
manapool:{2}{B}
[PLAYER2]
hand:swamp,plains,mountain
[DO]
Mind Rot
p2
[ASSERT]
FIRSTMAIN
[PLAYER1]
graveyard:Mind Rot
manapool:{0}
[PLAYER2]
hand:*
graveyard:*,*
[END]

View File

@@ -0,0 +1,22 @@
#Testing Spitting Earth on Dragon engine
[INIT]
FIRSTMAIN
[PLAYER1]
hand:Spitting Earth
inplay:129652,129651,129650
[PLAYER2]
inplay:Dragon Engine
[DO]
129652
129651
Spitting Earth
Dragon Engine
[ASSERT]
FIRSTMAIN
[PLAYER1]
inplay:129652,129651,129650
graveyard:Spitting Earth
manapool:{0}
[PLAYER2]
graveyard:Dragon Engine
[END]

View File

@@ -0,0 +1,20 @@
#Testing Spoils of Evil
[INIT]
FIRSTMAIN
[PLAYER1]
hand:Spoils Of Evil
graveyard:black knight
manapool:{2}{B}
[PLAYER2]
graveyard:swamp,grizzly bears,dragon engine
[DO]
Spoils Of Evil
[ASSERT]
FIRSTMAIN
[PLAYER1]
graveyard:black knight,Spoils Of Evil
life:22
manapool:{2}
[PLAYER2]
graveyard:swamp,grizzly bears,dragon engine
[END]

View File

@@ -22,10 +22,11 @@ class WEvent;
class ActionElement: public JGuiObject{
protected:
int activeState;
public:
int isClone;
TargetChooser * tc;
int currentPhase;
int newPhase;
@@ -46,6 +47,7 @@ class ActionElement: public JGuiObject{
virtual int receiveEvent(WEvent * event){return 0;};
virtual int reactToClick(MTGCardInstance * card){return 0;};
virtual const char * getMenuText(){return "Ability";};
virtual ActionElement * clone() const = 0;
};

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@ class UntapBlocker : public MTGAbility {
~UntapBlocker();
virtual void Update(float dt);
virtual int destroy();
virtual UntapBlocker * clone() const;
};

View File

@@ -25,7 +25,7 @@ class GuiLayer{
int mCurr;
vector<JGuiObject *>mObjects;
void Add(JGuiObject * object);
void Remove(JGuiObject * object);
int Remove(JGuiObject * object);
int modal;
bool hasFocus;
virtual void resetObjects();

View File

@@ -19,15 +19,18 @@ class WEvent;
#include <string>
#include <map>
#include <hge/hgeparticle.h>
#include "../include/Damage.h"
using std::string;
using std::map;
//Two stupid variables used to give a hint to the AI:
//stupid variables used to give a hint to the AI:
// Should I cast a spell on an enemy or friendly unit ?
#define BAKA_EFFECT_GOOD 1
#define BAKA_EFFECT_BAD -1
#define BAKA_EFFECT_DONTKNOW 0
#define MODE_PUTINTOPLAY 1
#define MODE_ABILITY 2
#define COUNT_POWER 1
@@ -38,16 +41,17 @@ using std::map;
class MTGAbility: public ActionElement{
protected:
char menuText[25];
GameObserver * game;
public:
int oneShot;
int forceDestroy;
ManaCost * cost;
Damageable * target;
Targetable * target;
int aType;
MTGCardInstance * source;
MTGAbility(int id, MTGCardInstance * card);
MTGAbility(int id, MTGCardInstance * _source, Damageable * _target);
MTGAbility(int id, MTGCardInstance * _source, Targetable * _target);
virtual int testDestroy();
virtual ~MTGAbility();
virtual void Render(){};
@@ -58,7 +62,10 @@ class MTGAbility: public ActionElement{
virtual int fireAbility();
virtual int stillInUse(MTGCardInstance * card){if (card==source) return 1; return 0;};
virtual int resolve(){return 0;};
virtual MTGAbility* clone() const = 0;
virtual ostream& toString(ostream& out) const;
virtual int addToGame();
virtual int removeFromGame();
/*Poor man's casting */
/* Todo replace that crap with dynamic casting */
@@ -78,11 +85,12 @@ class MTGAbility: public ActionElement{
class TriggeredAbility:public MTGAbility{
public:
TriggeredAbility(int id, MTGCardInstance * card);
TriggeredAbility(int id, MTGCardInstance * _source, Damageable * _target);
TriggeredAbility(int id, MTGCardInstance * _source, Targetable * _target);
virtual void Update(float dt);
virtual void Render(){};
virtual int trigger()=0;
virtual int resolve() = 0;
virtual TriggeredAbility* clone() const = 0;
virtual ostream& toString(ostream& out) const;
};
@@ -96,18 +104,24 @@ class ActivatedAbility:public MTGAbility{
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
virtual int reactToTargetClick(Targetable * object);
virtual int resolve() = 0;
virtual ActivatedAbility* clone() const = 0;
virtual ostream& toString(ostream& out) const;
};
class TargetAbility:public ActivatedAbility{
public:
MTGAbility * ability;
TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1);
TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1);
virtual void Update(float dt);
virtual int reactToClick(MTGCardInstance * card);
virtual int reactToTargetClick(Targetable * object);
virtual TargetAbility* clone() const = 0;
virtual void Render();
virtual int resolve();
virtual const char * getMenuText();
virtual ostream& toString(ostream& out) const;
~TargetAbility();
};
class InstantAbility:public MTGAbility{
@@ -118,6 +132,7 @@ class InstantAbility:public MTGAbility{
InstantAbility(int _id, MTGCardInstance * source);
InstantAbility(int _id, MTGCardInstance * source,Damageable * _target);
virtual int resolve(){return 0;};
virtual InstantAbility* clone() const = 0;
virtual ostream& toString(ostream& out) const;
};
@@ -125,26 +140,32 @@ class InstantAbility:public MTGAbility{
class ListMaintainerAbility:public MTGAbility{
public:
map<MTGCardInstance *,bool> cards;
map<Player *,bool> players;
ListMaintainerAbility(int _id):MTGAbility(_id,NULL){};
ListMaintainerAbility(int _id, MTGCardInstance *_source):MTGAbility(_id, _source){};
ListMaintainerAbility(int _id, MTGCardInstance *_source,Damageable * _target):MTGAbility(_id, _source, _target){};
virtual void Update(float dt);
void updateTargets();
virtual int canBeInList(MTGCardInstance * card) = 0;
virtual int added(MTGCardInstance * card) = 0;
virtual int removed(MTGCardInstance * card) = 0;
virtual int canBeInList(Player * p){return 0;};
virtual int added(Player * p){return 0;};
virtual int removed(Player * p){return 0;};
virtual int destroy();
virtual ListMaintainerAbility* clone() const = 0;
virtual ostream& toString(ostream& out) const;
};
/* An attempt to globalize triggered abilities as much as possible */
class MTGAbilityBasicFeatures{
public:
Damageable * target;
Targetable * target;
GameObserver * game;
MTGCardInstance * source;
MTGAbilityBasicFeatures();
MTGAbilityBasicFeatures(MTGCardInstance * _source, Damageable * _target = NULL);
void init(MTGCardInstance * _source, Damageable * _target = NULL);
MTGAbilityBasicFeatures(MTGCardInstance * _source, Targetable * _target = NULL);
void init(MTGCardInstance * _source, Targetable * _target = NULL);
};
class Trigger:public MTGAbilityBasicFeatures{
@@ -176,7 +197,7 @@ class TriggerNextPhase:public TriggerAtPhase{
class TriggeredEvent:public MTGAbilityBasicFeatures{
public:
TriggeredEvent();
TriggeredEvent(MTGCardInstance * source, Damageable * target = NULL);
TriggeredEvent(MTGCardInstance * source, Targetable * target = NULL);
virtual int resolve()=0;
};
@@ -213,21 +234,22 @@ class GenericTriggeredAbility:public TriggeredAbility{
Trigger * t;
TriggeredEvent * te;
DestroyCondition * dc;
GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc = NULL, Damageable * _target = NULL);
GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc = NULL, Targetable * _target = NULL);
virtual int trigger();
virtual int resolve();
virtual int testDestroy();
virtual GenericTriggeredAbility* clone() const;
~GenericTriggeredAbility();
};
/* Ability Factory */
class AbilityFactory{
private:
int countCards(TargetChooser * tc, Player * player = NULL, int option = 0);
int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p);
int countCards(TargetChooser * tc, Player * player = NULL, int option = 0);
int parsePowerToughness(string s, int *power, int *toughness);
Trigger * parseTrigger(string magicText);
Damageable * parseCollateralTarget(MTGCardInstance * card, string s);
MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0);
int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY);
public:
int magicText(int id, Spell * spell, MTGCardInstance * card = NULL);
int destroyAllInPlay(TargetChooser * tc, int bury = 0);
@@ -243,16 +265,16 @@ class AbilityFactory{
class AManaProducer: public MTGAbility{
protected:
ManaCost * cost;
ManaCost * output;
string menutext;
float x0,y0,x1,y1,x,y;
float animation;
Player * controller;
int tap;
hgeParticleSystem * mParticleSys;
public:
int tap;
static int currentlyTapping;
AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 1 );
void Update(float dt);
@@ -263,6 +285,7 @@ class AManaProducer: public MTGAbility{
const char * getMenuText();
int testDestroy();
~AManaProducer();
virtual AManaProducer * clone() const;
virtual ostream& toString(ostream& out) const;
};

View File

@@ -18,6 +18,7 @@ class MTGGamePhase: public ActionElement {
virtual void Render();
virtual void Update(float dt);
bool CheckUserInput(u32 key);
virtual MTGGamePhase * clone() const;
virtual ostream& toString(ostream& out) const;
};

View File

@@ -16,6 +16,7 @@ class MTGPutInPlayRule:public MTGAbility{
virtual ostream& toString(ostream& out) const;
MTGPutInPlayRule(int _id);
const char * getMenuText(){return "Put into play";}
virtual MTGPutInPlayRule * clone() const;
};
class MTGAttackRule:public MTGAbility{
@@ -27,6 +28,7 @@ class MTGAttackRule:public MTGAbility{
MTGAttackRule(int _id);
const char * getMenuText(){return "Attacker";}
void Update(float dt);
virtual MTGAttackRule * clone() const;
};
class MTGBlockRule:public MTGAbility{
@@ -37,49 +39,18 @@ class MTGBlockRule:public MTGAbility{
virtual ostream& toString(ostream& out) const;
MTGBlockRule(int _id);
const char * getMenuText(){return "Blocker";}
virtual MTGBlockRule * clone() const;
};
/* Persist Rule */
class MTGPersistRule:public MTGAbility{
public:
MTGPersistRule(int _id):MTGAbility(_id,NULL){};
int receiveEvent(WEvent * event){
if (event->type == WEvent::CHANGE_ZONE){
WEventZoneChange * e = (WEventZoneChange *) event;
MTGCardInstance * card = e->card->previous;
if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){
int ok = 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->from == p->game->inPlay) ok = 1;
}
if (!ok) return 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->to == p->game->graveyard){
//p->game->putInZone(card, p->game->graveyard, card->owner->game->hand);
MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack);
Spell * spell = NEW Spell(copy);
spell->resolve();
spell->source->counters->addCounter(-1,-1);
game->mLayers->playLayer()->forceUpdateCards();
delete spell;
return 1;
}
}
}
}
return 0;
}
virtual ostream& toString(ostream& out) const
{
out << "MTGPersistRule ::: (";
return MTGAbility::toString(out) << ")";
}
int testDestroy(){return 0;}
MTGPersistRule(int _id);
int receiveEvent(WEvent * event);
virtual ostream& toString(ostream& out) const;
int testDestroy();
virtual MTGPersistRule * clone() const;
};
@@ -91,39 +62,13 @@ class MTGPersistRule:public MTGAbility{
*/
class MTGLegendRule:public ListMaintainerAbility{
public:
MTGLegendRule(int _id):ListMaintainerAbility(_id){};
int canBeInList(MTGCardInstance * card){
if (card->basicAbilities[Constants::LEGENDARY] && game->isInPlay(card)){
return 1;
}
return 0;
}
int added(MTGCardInstance * card){
map<MTGCardInstance *,bool>::iterator it;
int destroy = 0;
for ( it=cards.begin() ; it != cards.end(); it++ ){
MTGCardInstance * comparison = (*it).first;
if (comparison!= card && !strcmp(comparison->getName(), card->getName())){
comparison->owner->game->putInGraveyard(comparison);
destroy = 1;
}
}
if (destroy){
card->owner->game->putInGraveyard(card);
}
return 1;
}
int removed(MTGCardInstance * card){return 0;}
int testDestroy(){return 0;}
virtual ostream& toString(ostream& out) const
{
return out << "MTGLegendRule :::";
}
MTGLegendRule(int _id);
int canBeInList(MTGCardInstance * card);
int added(MTGCardInstance * card);
int removed(MTGCardInstance * card);
int testDestroy();
virtual ostream& toString(ostream& out) const;
virtual MTGLegendRule * clone() const;
};
@@ -149,34 +94,22 @@ public:
int reactToClick(MTGCardInstance * card, int id);
const char * getMenuText(){return "Momir";}
virtual ostream& toString(ostream& out) const;
virtual MTGMomirRule * clone() const;
};
/* LifeLink */
class MTGLifelinkRule:public MTGAbility{
public:
MTGLifelinkRule(int _id):MTGAbility(_id,NULL){};
MTGLifelinkRule(int _id);
int receiveEvent(WEvent * event){
if (event->type == WEvent::DAMAGE){
WEventDamage * e = (WEventDamage *) event;
Damage * d = e->damage;
MTGCardInstance * card = d->source;
if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){
card->controller()->life+= d->damage;
return 1;
}
}
return 0;
}
int receiveEvent(WEvent * event);
int testDestroy(){return 0;}
int testDestroy();
virtual ostream& toString(ostream& out) const
{
out << "MTGLifelinkRule ::: (";
return MTGAbility::toString(out) << ")";
}
virtual ostream& toString(ostream& out) const;
virtual MTGLifelinkRule * clone() const;
};
@@ -205,6 +138,7 @@ public:
void Render();
HUDDisplay(int _id);
~HUDDisplay();
virtual HUDDisplay * clone() const;
};

View File

@@ -27,7 +27,7 @@ class TargetsList{
Interruptible * getNextInterruptible(Interruptible * previous, int type);
Spell * getNextSpellTarget(Spell * previous = 0);
Damage * getNextDamageTarget(Damage * previous = 0);
Targetable * getNextTarget(Targetable * previous, int type);
Targetable * getNextTarget(Targetable * previous = 0, int type = -1);
void initTargets(){cursor = 0;};
};

View File

@@ -15,13 +15,13 @@ AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * _deck, char * file, char * fileSma
}
int AIMomirPlayer::getEfficiency(AIAction * action){
MTGAbility * ability = action->ability;
if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet
int efficiency = AIPlayerBaka::getEfficiency(action);
int efficiency = AIPlayerBaka::getEfficiency(action);
GameObserver * g = GameObserver::GetInstance();
if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0;
return efficiency;
GameObserver * g = GameObserver::GetInstance();
if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0;
return efficiency;
}
MTGAbility * AIMomirPlayer::getMomirAbility(){
@@ -113,81 +113,4 @@ the general rule is this: if you want to get to Eight, you have to skip two drop
return AIPlayerBaka::computeActions();
}
/*
int AIPlayerBaka::computeActions(){
GameObserver * g = GameObserver::GetInstance();
Player * p = g->currentPlayer;
if (!(g->currentlyActing() == this)) return 0;
if (chooseTarget()) return 1;
int currentGamePhase = g->getCurrentGamePhase();
if (g->isInterrupting == this){ // interrupting
selectAbility();
return 1;
}else if (p == this && g->mLayers->stackLayer()->count(0,NOT_RESOLVED) == 0){ //standard actions
CardDescriptor cd;
MTGCardInstance * card = NULL;
switch(currentGamePhase){
case Constants::MTG_PHASE_FIRSTMAIN:
case Constants::MTG_PHASE_SECONDMAIN:
if (canPutLandsIntoPlay){
//Attempt to put land into play
cd.init();
cd.setColor(Constants::MTG_COLOR_LAND);
card = cd.match(game->hand);
if (card){
AIAction * a = NEW AIAction(card);
clickstream.push(a);
return 1;
}
}
//No mana, try to get some
getPotentialMana();
if (potentialMana->getConvertedCost() > 0){
//look for the most expensive creature we can afford
nextCardToPlay = FindCardToPlay(potentialMana, "creature");
//Let's Try an enchantment maybe ?
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery");
if (nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
char buffe[4096];
sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName());
OutputDebugString(buffe);
#endif
tapLandsForMana(potentialMana,nextCardToPlay->getManaCost());
AIAction * a = NEW AIAction(nextCardToPlay);
clickstream.push(a);
return 1;
}else{
selectAbility();
}
}else{
selectAbility();
}
break;
case Constants::MTG_PHASE_COMBATATTACKERS:
chooseAttackers();
break;
default:
selectAbility();
break;
}
}else{
switch(currentGamePhase){
case Constants::MTG_PHASE_COMBATBLOCKERS:
chooseBlockers();
break;
default:
break;
}
return 1;
}
return 1;
};
*/

View File

@@ -135,17 +135,29 @@ int AIAction::getEfficiency(){
ActionStack * s = g->mLayers->stackLayer();
Player * p = g->currentlyActing();
if (s->has(ability)) return 0;
if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet
switch (ability->aType){
MTGAbility * a = ability;
GenericTargetAbility * gta = dynamic_cast<GenericTargetAbility*>(a);
if (gta) a = gta->ability;
GenericActivatedAbility * gaa = dynamic_cast<GenericActivatedAbility*>(a);
if (gaa) a = gaa->ability;
if (!a){
OutputDebugString("FATAL: Ability is NULL in AIAction::getEfficiency()");
return 0;
}
switch (a->aType){
case MTGAbility::DAMAGER:
{
ADamager * a = (ADamager *) ability;
AADamager * aad = (AADamager *) a;
if ( p == target->controller()){
efficiency = 0;
}else if (a->damage >= target->toughness){
}else if (aad->damage >= target->toughness){
efficiency = 100;
}else if (target->toughness){
efficiency = (100 * a->damage) / target->toughness;
efficiency = (50 * aad->damage) / target->toughness;
}else{
efficiency = 0;
}
@@ -153,22 +165,12 @@ int AIAction::getEfficiency(){
}
case MTGAbility::STANDARD_REGENERATE:
{
MTGCardInstance * _target = (MTGCardInstance *)(ability->target);
PutInGraveyard * action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED));
int i = 0;
while(action){
i++;
if (action->card == _target){
efficiency = 95;
action = NULL;
}else{
action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED));
}
MTGCardInstance * _target = (MTGCardInstance *)(a->target);
efficiency = 0;
if (!_target->regenerateTokens && g->getCurrentGamePhase()< Constants::MTG_PHASE_COMBATDAMAGE && (_target->defenser || _target->blockers.size())){
efficiency = 95;
}
char buf[4096];
sprintf(buf,"Graveyard : %i\n", i);
OutputDebugString(buf);
if (efficiency == -1) efficiency = 0;
//TODO If the card is the target of a damage spell
break;
}
case MTGAbility::MANA_PRODUCER: //can't use mana producers right now :/
@@ -741,125 +743,3 @@ int AIPlayerBaka::Act(float dt){
return 1;
};
/*
int AIPlayerBaka::Act(float dt){
GameObserver * gameObs = GameObserver::GetInstance();
int currentGamePhase = gameObs->getCurrentGamePhase();
if (currentGamePhase == Constants::MTG_PHASE_CLEANUP && currentGamePhase != oldGamePhase){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("updating stats\n");
#endif
if (getStats()) getStats()->updateStats();
}
oldGamePhase = currentGamePhase;
//if (checkInterrupt()) return 0;
timer-= dt;
if (AManaProducer::currentlyTapping || timer>0){
return 0;
}
initTimer();
checkInterrupt();
if (currentAbility) return (useAbility());
if (combatDamages()) return 0;
if (chooseTarget()) return 0;
Player * currentPlayer = gameObs->currentPlayer;
CardDescriptor cd;
if (currentPlayer == this){
MTGCardInstance * card = NULL;
switch(currentGamePhase){
case Constants::MTG_PHASE_FIRSTMAIN:
case Constants::MTG_PHASE_SECONDMAIN:
if (canPutLandsIntoPlay){
//Attempt to put land into play
cd.init();
cd.setColor(Constants::MTG_COLOR_LAND);
card = cd.match(game->hand);
if (card){
gameObs->cardClick(card);
}
}
if(NULL == card){
//Attempt to put creature into play
if (manaPool->getConvertedCost()==0){
//No mana, try to get some
getPotentialMana();
if (potentialMana->getConvertedCost() > 0){
//look for the most expensive creature we can afford
nextCardToPlay = FindCardToPlay(potentialMana, "creature");
//Let's Try an enchantment maybe ?
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery");
if (nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
char buffe[4096];
sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName());
OutputDebugString(buffe);
#endif
tapLandsForMana(potentialMana,nextCardToPlay->getManaCost());
}
}
SAFE_DELETE(potentialMana);
}else{
//We have mana, we can try to put the card into play
#if defined (WIN32) || defined (LINUX)
OutputDebugString("Mana paid, ready to put card into play\n");
#endif
if (nextCardToPlay){
gameObs->cardClick(nextCardToPlay);
nextCardToPlay = NULL;
}else{
//ERROR, WE PAID MANA WITHOUT ANY WILL TO PLAY
}
}
}
if (NULL == card && NULL == nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("Switching to next phase\n");
#endif
gameObs->userRequestNextGamePhase();
}
break;
case Constants::MTG_PHASE_COMBATATTACKERS:
chooseAttackers();
gameObs->userRequestNextGamePhase();
break;
default:
gameObs->userRequestNextGamePhase();
break;
}
}else{
switch(currentGamePhase){
case Constants::MTG_PHASE_COMBATBLOCKERS:
chooseBlockers();
gameObs->userRequestNextGamePhase();
break;
default:
break;
}
return 1;
}
return 1;
}
*/

View File

@@ -10,10 +10,13 @@ ActionElement::ActionElement(int id):JGuiObject(id){
currentPhase = -1;
newPhase = -1;
tc = NULL;
isClone = 0;
}
ActionElement::~ActionElement(){
SAFE_DELETE(tc);
if (!isClone){
SAFE_DELETE(tc);
}
}
int ActionElement::getActivity(){

View File

@@ -71,8 +71,7 @@ void ActionLayer::Update(float dt){
if (mObjects[i]!= NULL){
ActionElement * currentAction = (ActionElement *)mObjects[i];
if (currentAction->testDestroy()){
currentAction->destroy();
Remove(currentAction);
game->removeObserver(currentAction);
}
}
}

View File

@@ -24,6 +24,12 @@ void UntapBlocker::init(ManaCost * _cost){
manaCost = _cost;
}
UntapBlocker * UntapBlocker::clone() const{
UntapBlocker * a = NEW UntapBlocker(*this);
a->isClone = 1;
return a;
}
//Default behaviour for blockers : they block the card they're attached to
void UntapBlocker::Update(float dt){

View File

@@ -152,7 +152,6 @@ int GameObserver::cancelCurrentAction(){
}
void GameObserver::userRequestNextGamePhase(){
OutputDebugString("requesting Next Phase\n");
if (mLayers->stackLayer()->getNext(NULL,0,NOT_RESOLVED)) return;
if (getCurrentTargetChooser()) return;
if (mLayers->combatLayer()->isDisplayed()) return;
@@ -164,7 +163,6 @@ void GameObserver::userRequestNextGamePhase(){
return;
}
}
OutputDebugString("Next Phase Accepted\n");
if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS ||
opponent()->isAI() ||
GameOptions::GetInstance()->values[GameOptions::phaseInterrupts[currentGamePhase]].getIntValue()){
@@ -241,11 +239,14 @@ void GameObserver::addObserver(MTGAbility * observer){
void GameObserver::removeObserver(ActionElement * observer){
if (observer){
observer->destroy();
if (mLayers->actionLayer()->getIndexOf(observer) != -1){
observer->destroy();
mLayers->actionLayer()->Remove(observer);
}
}else{
//TODO log error
}
mLayers->actionLayer()->Remove(observer);
}
GameObserver::~GameObserver(){

View File

@@ -21,7 +21,7 @@ void GuiLayer::Add(JGuiObject *object){
mCount++;
}
void GuiLayer::Remove(JGuiObject *object){
int GuiLayer::Remove(JGuiObject *object){
for (int i=0;i<mCount;i++){
if (mObjects[i]==object){
delete mObjects[i];
@@ -29,9 +29,10 @@ void GuiLayer::Remove(JGuiObject *object){
mCount--;
if (mCurr == mCount)
mCurr = 0;
return;
return 1;
}
}
return 0;
}
int GuiLayer::getMaxId(){

File diff suppressed because it is too large Load Diff

View File

@@ -135,7 +135,7 @@ int MTGCardInstance::afterDamage(){
if (!doDamageTest) return 0;
doDamageTest = 0;
if (!isACreature()) return 0;
if (life <=0 && isInPlay() && !basicAbilities[Constants::INDESTRUCTIBLE]){
if (life <=0 && isInPlay()){
return destroy();
}
return 0;
@@ -145,11 +145,12 @@ int MTGCardInstance::bury(){
Player * p = controller();
if (!basicAbilities[Constants::INDESTRUCTIBLE]){
p->game->putInZone(this,p->game->inPlay,owner->game->graveyard);
return 1;
}
return 1;
return 0;
}
int MTGCardInstance::destroy(){
if (!triggerRegenerate() || !basicAbilities[Constants::INDESTRUCTIBLE]) return bury();
if (!triggerRegenerate()) return bury();
return 0;
}

View File

@@ -54,6 +54,12 @@ bool MTGGamePhase::CheckUserInput(u32 key){
return false;
}
MTGGamePhase * MTGGamePhase::clone() const{
MTGGamePhase * a = NEW MTGGamePhase(*this);
a->isClone = 1;
return a;
}
ostream& MTGGamePhase::toString(ostream& out) const
{
return out << "MTGGamePhase ::: animation " << animation << " ; currentState : " << currentState;

View File

@@ -84,6 +84,12 @@ ostream& MTGPutInPlayRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGPutInPlayRule * MTGPutInPlayRule::clone() const{
MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this);
a->isClone = 1;
return a;
}
MTGAttackRule::MTGAttackRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_ATTACK_RULE;
@@ -126,6 +132,13 @@ ostream& MTGAttackRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGAttackRule * MTGAttackRule::clone() const{
MTGAttackRule * a = NEW MTGAttackRule(*this);
a->isClone = 1;
return a;
}
MTGBlockRule::MTGBlockRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_BLOCK_RULE;
}
@@ -167,7 +180,11 @@ ostream& MTGBlockRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGBlockRule * MTGBlockRule::clone() const{
MTGBlockRule * a = NEW MTGBlockRule(*this);
a->isClone = 1;
return a;
}
//
// Attacker chooses blockers order
//
@@ -295,6 +312,12 @@ ostream& MTGMomirRule::toString(ostream& out) const
}
MTGMomirRule * MTGMomirRule::clone() const{
MTGMomirRule * a = NEW MTGMomirRule(*this);
a->isClone = 1;
return a;
}
//HUDDisplay
int HUDDisplay::testDestroy(){
return 0;
@@ -383,4 +406,125 @@ HUDDisplay::~HUDDisplay(){
delete hs;
}
events.clear();
}
}
HUDDisplay * HUDDisplay::clone() const{
HUDDisplay * a = NEW HUDDisplay(*this);
a->isClone = 1;
return a;
}
/* Persist */
MTGPersistRule::MTGPersistRule(int _id):MTGAbility(_id,NULL){};
int MTGPersistRule::receiveEvent(WEvent * event){
if (event->type == WEvent::CHANGE_ZONE){
WEventZoneChange * e = (WEventZoneChange *) event;
MTGCardInstance * card = e->card->previous;
if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){
int ok = 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->from == p->game->inPlay) ok = 1;
}
if (!ok) return 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->to == p->game->graveyard){
//p->game->putInZone(card, p->game->graveyard, card->owner->game->hand);
MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack);
Spell * spell = NEW Spell(copy);
spell->resolve();
spell->source->counters->addCounter(-1,-1);
game->mLayers->playLayer()->forceUpdateCards();
delete spell;
return 1;
}
}
}
}
return 0;
}
ostream& MTGPersistRule::toString(ostream& out) const
{
out << "MTGPersistRule ::: (";
return MTGAbility::toString(out) << ")";
}
int MTGPersistRule::testDestroy(){return 0;}
MTGPersistRule * MTGPersistRule::clone() const{
MTGPersistRule * a = NEW MTGPersistRule(*this);
a->isClone = 1;
return a;
}
/* Legend Rule */
MTGLegendRule::MTGLegendRule(int _id):ListMaintainerAbility(_id){};
int MTGLegendRule::canBeInList(MTGCardInstance * card){
if (card->basicAbilities[Constants::LEGENDARY] && game->isInPlay(card)){
return 1;
}
return 0;
}
int MTGLegendRule::added(MTGCardInstance * card){
map<MTGCardInstance *,bool>::iterator it;
int destroy = 0;
for ( it=cards.begin() ; it != cards.end(); it++ ){
MTGCardInstance * comparison = (*it).first;
if (comparison!= card && !strcmp(comparison->getName(), card->getName())){
comparison->owner->game->putInGraveyard(comparison);
destroy = 1;
}
}
if (destroy){
card->owner->game->putInGraveyard(card);
}
return 1;
}
int MTGLegendRule::removed(MTGCardInstance * card){return 0;}
int MTGLegendRule::testDestroy(){return 0;}
ostream& MTGLegendRule::toString(ostream& out) const
{
return out << "MTGLegendRule :::";
}
MTGLegendRule * MTGLegendRule::clone() const{
MTGLegendRule * a = NEW MTGLegendRule(*this);
a->isClone = 1;
return a;
}
/* Lifelink */
MTGLifelinkRule::MTGLifelinkRule(int _id):MTGAbility(_id,NULL){};
int MTGLifelinkRule::receiveEvent(WEvent * event){
if (event->type == WEvent::DAMAGE){
WEventDamage * e = (WEventDamage *) event;
Damage * d = e->damage;
MTGCardInstance * card = d->source;
if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){
card->controller()->life+= d->damage;
return 1;
}
}
return 0;
}
int MTGLifelinkRule::testDestroy(){return 0;}
ostream& MTGLifelinkRule::toString(ostream& out) const
{
out << "MTGLifelinkRule ::: (";
return MTGAbility::toString(out) << ")";
}
MTGLifelinkRule * MTGLifelinkRule::clone() const{
MTGLifelinkRule * a = NEW MTGLifelinkRule(*this);
a->isClone = 1;
return a;
}

View File

@@ -282,9 +282,6 @@ int ManaCost::canAfford(ManaCost * _cost){
int positive = diff->isPositive();
delete diff;
if (positive){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("can afford\n");
#endif
return 1;
}
return 0;

View File

@@ -58,11 +58,11 @@ int TargetsList::toggleTarget(Targetable * target){
}
Targetable * TargetsList::getNextTarget(Targetable * previous, int type){
Targetable * TargetsList::getNextTarget(Targetable * previous , int type){
int found = 0;
if (!previous) found = 1;
for (int i = 0; i < cursor; i++){
if (found && targets[i]->typeAsTarget() == type){
if (found && (type == -1 || targets[i]->typeAsTarget() == type)){
return (targets[i]);
}
if (targets[i] == previous) found = 1;

View File

@@ -119,6 +119,11 @@ int TestSuiteAI::Act(float dt){
MTGMomirRule * a = ((MTGMomirRule *)g->mLayers->actionLayer()->getAbility(MTGAbility::MOMIR));
a->reactToClick(suite->getCardByMTGId(cardIdHand), cardId);
g->mLayers->actionLayer()->stuffHappened = 1;
}else if(action.find("p1")!=string::npos || action.find("p2")!=string::npos){
Player * p = g->players[1];
int start = action.find("p1");
if (start != string::npos) p = g->players[0];
g->cardClick(NULL, p);
}else{
int mtgid = suite->getMTGId(action);
if (mtgid){