Erwan
- the AI can now use activated abilities (stupidly though...) - a few card bugfixes
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "Player.h"
|
||||
|
||||
#include <queue>
|
||||
using std::queue;
|
||||
|
||||
#define INFO_NBCREATURES 0
|
||||
#define INFO_CREATURESPOWER 1
|
||||
@@ -16,13 +18,40 @@
|
||||
|
||||
class AIStats;
|
||||
|
||||
class AIAction{
|
||||
protected:
|
||||
int efficiency;
|
||||
public:
|
||||
MTGAbility * ability;
|
||||
Player * player;
|
||||
MTGCardInstance * click;
|
||||
MTGCardInstance * target; // TODO Improve
|
||||
AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL):ability(a),click(c),target(t){player = NULL; efficiency = -1;};
|
||||
AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL):click(c),target(t){player = NULL; ability = NULL; efficiency = -1;};
|
||||
AIAction(Player * p):player(p){ability = NULL; target = NULL; click = NULL; efficiency = -1;};
|
||||
int getEfficiency();
|
||||
int Act();
|
||||
|
||||
};
|
||||
|
||||
class CmpAbilities { // compares Abilities efficiency
|
||||
public:
|
||||
bool operator()(AIAction * a1, AIAction * a2) const {
|
||||
int e1 = a1->getEfficiency();
|
||||
int e2 = a2->getEfficiency();
|
||||
if (e1 == e2) return a1 > a2; //TODO improve
|
||||
return (e1 > e2);
|
||||
}
|
||||
};
|
||||
|
||||
class AIPlayer: public Player{
|
||||
protected:
|
||||
MTGCardInstance * nextCardToPlay;
|
||||
ManaCost * potentialMana;
|
||||
queue<AIAction *> clickstream;
|
||||
void tapLandsForMana(ManaCost * potentialMana, ManaCost * cost);
|
||||
int checkInterrupt();
|
||||
int combatDamages();
|
||||
int interruptIfICan();
|
||||
int chooseAttackers();
|
||||
int chooseBlockers();
|
||||
int effectBadOrGood(MTGCardInstance * card);
|
||||
@@ -30,7 +59,7 @@ class AIPlayer: public Player{
|
||||
AIStats * getStats();
|
||||
public:
|
||||
void End(){};
|
||||
virtual int displayStack(){return 0;};
|
||||
virtual int displayStack(){return 1;};
|
||||
AIStats * stats;
|
||||
ManaCost * getPotentialMana();
|
||||
AIPlayer(MTGPlayerCards * _deck, string deckFile);
|
||||
@@ -39,6 +68,9 @@ class AIPlayer: public Player{
|
||||
virtual int chooseTarget(TargetChooser * tc = NULL);
|
||||
virtual int Act(float dt);
|
||||
int isAI(){return 1;};
|
||||
int selectAbility();
|
||||
int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, map<AIAction *, int,CmpAbilities> * ranking);
|
||||
int useAbility();
|
||||
|
||||
};
|
||||
|
||||
@@ -52,6 +84,7 @@ class AIPlayerBaka: public AIPlayer{
|
||||
AIPlayerBaka(MTGPlayerCards * _deck, char * deckFile, char * avatarFile);
|
||||
virtual int Act(float dt);
|
||||
void initTimer();
|
||||
int computeActions();
|
||||
};
|
||||
|
||||
class AIPlayerFactory{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
|
||||
class MTGCardInstance;
|
||||
class ManaCost;
|
||||
class Targetable;
|
||||
class TargetChooser;
|
||||
class WEvent;
|
||||
@@ -37,9 +38,10 @@ class ActionElement: public JGuiObject{
|
||||
virtual int destroy(){return 0;};
|
||||
virtual bool CheckUserInput(u32 key){return false;};
|
||||
ActionElement(int id);
|
||||
virtual ~ActionElement();
|
||||
virtual int isReactingToTargetClick(Targetable * card);
|
||||
virtual int reactToTargetClick(Targetable * card);
|
||||
virtual int isReactingToClick(MTGCardInstance * card){return 0;};
|
||||
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * man = NULL){return 0;};
|
||||
virtual int stillInUse(MTGCardInstance * card){return 0;};
|
||||
virtual int receiveEvent(WEvent * event){return 0;};
|
||||
virtual int reactToClick(MTGCardInstance * card){return 0;};
|
||||
|
||||
@@ -396,7 +396,7 @@ class ASpellCastLife:public MTGAbility{
|
||||
trigger.setColor(color);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){
|
||||
if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){
|
||||
if (game->currentlyActing()->getManaPool()->canAfford(cost)){
|
||||
Interruptible * laststackitem = game->mLayers->stackLayer()->_(-1);
|
||||
@@ -430,7 +430,7 @@ class AUnBlocker:public MTGAbility{
|
||||
}
|
||||
|
||||
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card,ManaCost * mana = NULL){
|
||||
if (_card == target && game->currentlyActing()->game->inPlay->hasCard(source) && (MTGCardInstance *) _card->isTapped()){
|
||||
if (game->currentlyActing()->getManaPool()->canAfford(cost)){
|
||||
return 1;
|
||||
@@ -462,10 +462,10 @@ class AUntaperOnceDuringTurn:public AUnBlocker{
|
||||
AUnBlocker::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0;
|
||||
if (untappedThisTurn) return 0;
|
||||
return AUnBlocker::isReactingToClick(card);
|
||||
return AUnBlocker::isReactingToClick(card,mana);
|
||||
}
|
||||
|
||||
int reactToClick(MTGCardInstance * card){
|
||||
@@ -578,8 +578,8 @@ class APowerToughnessModifierUntilEndOfTurn: public ActivatedAbility{
|
||||
return resolve();
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
if (!ActivatedAbility::isReactingToClick(card)) return 0;
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (!ActivatedAbility::isReactingToClick(card,mana)) return 0;
|
||||
return (!maxcounters || (counters < maxcounters));
|
||||
}
|
||||
|
||||
@@ -694,6 +694,7 @@ class AStandardRegenerate:public ActivatedAbility{
|
||||
public:
|
||||
AStandardRegenerate(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):ActivatedAbility(_id,_source,_cost,0,0){
|
||||
target = _target;
|
||||
aType = MTGAbility::STANDARD_REGENERATE;
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
@@ -933,6 +934,7 @@ class ADamager:public TargetAbility{
|
||||
int damage;
|
||||
ADamager(int id, MTGCardInstance * card, ManaCost * _cost, int _damage, TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(id,card, _tc, _cost,0,_tap),damage(_damage){
|
||||
if (!tc) tc = NEW DamageableTargetChooser(card);
|
||||
aType = MTGAbility::DAMAGER;
|
||||
}
|
||||
int resolve(){
|
||||
Damageable * _target = tc->getNextDamageableTarget();
|
||||
@@ -1271,7 +1273,7 @@ class AArmageddonClock:public MTGAbility{
|
||||
}
|
||||
}
|
||||
}
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){
|
||||
if (counters > 0 && _card == source && currentPhase == Constants::MTG_PHASE_UPKEEP){
|
||||
if (game->currentlyActing()->getManaPool()->canAfford( & cost)){
|
||||
return 1;
|
||||
@@ -1357,7 +1359,7 @@ class AClockworkBeast:public MTGAbility{
|
||||
}
|
||||
}
|
||||
}
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){
|
||||
if (counters < 7 && _card == source && currentPhase == Constants::MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){
|
||||
if (game->currentlyActing()->getManaPool()->canAfford( & cost)){
|
||||
return 1;
|
||||
@@ -1423,7 +1425,7 @@ class AConservator: public MTGAbility{
|
||||
alterDamage();
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){
|
||||
if ( _card == source && game->currentlyActing()->game->inPlay->hasCard(source) && !_card->isTapped()){
|
||||
if (game->currentlyActing()->getManaPool()->canAfford( & cost)){
|
||||
return 1;
|
||||
@@ -1560,8 +1562,8 @@ class AFarmstead:public ActivatedAbility{
|
||||
target = _target;
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
if (!ActivatedAbility::isReactingToClick(card)) return 0;
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (!ActivatedAbility::isReactingToClick(card,mana)) return 0;
|
||||
if (currentPhase == Constants::MTG_PHASE_UPKEEP) return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -1605,7 +1607,7 @@ class AGlassesOfUrza:public MTGAbility{
|
||||
}
|
||||
|
||||
}
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if ( card == source){
|
||||
if (game->currentlyActing()->game->isInPlay(card) && !source->isTapped()){
|
||||
return 1;
|
||||
@@ -1674,7 +1676,7 @@ class ALivingArtifact:public MTGAbility{
|
||||
}
|
||||
}
|
||||
|
||||
int isReactingtoclick(MTGCardInstance * card){
|
||||
int isReactingtoclick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (currentPhase == Constants::MTG_PHASE_UPKEEP && card == source && game->currentPlayer == source->controller() && counters && !usedThisTurn){
|
||||
return 1;
|
||||
}
|
||||
@@ -1709,9 +1711,9 @@ class ALordOfThePit: public TargetAbility{
|
||||
TargetAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0;
|
||||
return TargetAbility::isReactingToClick(card);
|
||||
return TargetAbility::isReactingToClick(card,mana);
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
@@ -1867,9 +1869,9 @@ class AJandorsRing:public ActivatedAbility{
|
||||
cost->add(Constants::MTG_COLOR_ARTIFACT, 2);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0;
|
||||
return ActivatedAbility::isReactingToClick(card);
|
||||
return ActivatedAbility::isReactingToClick(card,mana);
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
@@ -1909,7 +1911,7 @@ class AKudzu: public TargetAbility{
|
||||
TargetAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
MTGCardInstance * _target = (MTGCardInstance *)target;
|
||||
if (card == source && (!_target || !_target->isInPlay())){
|
||||
#if defined (WIN32) || defined (LINUX)
|
||||
@@ -2073,7 +2075,7 @@ class APowerLeak:public TriggeredAbility{
|
||||
TriggeredAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
MTGCardInstance * _target = (MTGCardInstance *) target;
|
||||
if (damagesToDealThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && card==source && _target->controller() == game->currentPlayer){
|
||||
if (game->currentPlayer->getManaPool()->canAfford(& cost)) return 1;
|
||||
@@ -2186,7 +2188,7 @@ class AScavengingGhoul:public MTGAbility{
|
||||
//TODO
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * _card){
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){
|
||||
if (counters > 0 && _card == source && game->currentlyActing()->game->inPlay->hasCard(source)){
|
||||
return 1;
|
||||
}
|
||||
@@ -2391,8 +2393,8 @@ class AForceOfNature:public ActivatedAbility{
|
||||
ActivatedAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
return (dealDamageThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card));
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
return (dealDamageThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana));
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
@@ -2509,7 +2511,7 @@ class AIslandSanctuary:public MTGAbility{
|
||||
}
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (card==source && game->currentPlayer == card->controller() && currentPhase == Constants::MTG_PHASE_DRAW){
|
||||
Interruptible * action = game->mLayers->stackLayer()->_(-1);
|
||||
if (action->type == ACTION_DRAW) return 1;
|
||||
@@ -2582,10 +2584,10 @@ class ASoulNet:public ActivatedAbility{
|
||||
newDead = latest;
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK));
|
||||
if (newDead && newDead != latest && newDead->card->isACreature())
|
||||
return ActivatedAbility::isReactingToClick(card);
|
||||
return ActivatedAbility::isReactingToClick(card,mana);
|
||||
return 0;
|
||||
}
|
||||
int resolve(){
|
||||
@@ -2624,8 +2626,8 @@ class AStasis:public ActivatedAbility{
|
||||
ActivatedAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
return (!paidThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card));
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
return (!paidThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana));
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
@@ -2769,9 +2771,9 @@ class AMinionofLeshrac: public TargetAbility{
|
||||
TargetAbility::Update(dt);
|
||||
}
|
||||
|
||||
int isReactingToClick(MTGCardInstance * card){
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){
|
||||
if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0;
|
||||
return TargetAbility::isReactingToClick(card);
|
||||
return TargetAbility::isReactingToClick(card,mana);
|
||||
}
|
||||
|
||||
int resolve(){
|
||||
|
||||
@@ -37,14 +37,16 @@ class MTGAbility: public ActionElement{
|
||||
|
||||
GameObserver * game;
|
||||
public:
|
||||
ManaCost * cost;
|
||||
Damageable * target;
|
||||
int aType;
|
||||
MTGCardInstance * source;
|
||||
MTGAbility(int id, MTGCardInstance * card);
|
||||
MTGAbility(int id, MTGCardInstance * _source, Damageable * _target);
|
||||
virtual int testDestroy();
|
||||
virtual ~MTGAbility();
|
||||
virtual void Render(){};
|
||||
virtual int isReactingToClick(MTGCardInstance * card){return 0;};
|
||||
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){return 0;};
|
||||
virtual int reactToClick(MTGCardInstance * card){return 0;};
|
||||
virtual int receiveEvent(WEvent * event){return 0;};
|
||||
virtual void Update(float dt){};
|
||||
@@ -52,7 +54,15 @@ class MTGAbility: public ActionElement{
|
||||
virtual int stillInUse(MTGCardInstance * card){if (card==source) return 1; return 0;};
|
||||
virtual int resolve(){return 0;};
|
||||
|
||||
/*Poor man's casting */
|
||||
enum {
|
||||
UNKNOWN = 0,
|
||||
MANA_PRODUCER = 1,
|
||||
MTG_ATTACK_RULE = 2,
|
||||
DAMAGER = 3,
|
||||
STANDARD_REGENERATE = 4,
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -69,12 +79,11 @@ class TriggeredAbility:public MTGAbility{
|
||||
|
||||
class ActivatedAbility:public MTGAbility{
|
||||
public:
|
||||
ManaCost * cost;
|
||||
int playerturnonly;
|
||||
int needsTapping;
|
||||
ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1);
|
||||
virtual int reactToClick(MTGCardInstance * card);
|
||||
virtual int isReactingToClick(MTGCardInstance * card);
|
||||
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
virtual int reactToTargetClick(Targetable * object);
|
||||
virtual int resolve() = 0;
|
||||
virtual ~ActivatedAbility();
|
||||
@@ -230,7 +239,7 @@ class AManaProducer: public MTGAbility{
|
||||
AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 1 );
|
||||
void Update(float dt);
|
||||
void Render();
|
||||
int isReactingToClick(MTGCardInstance * _card);
|
||||
int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL);
|
||||
int resolve();
|
||||
int reactToClick(MTGCardInstance * _card);
|
||||
const char * getMenuText();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
class MTGPutInPlayRule:public MTGAbility{
|
||||
public:
|
||||
int isReactingToClick(MTGCardInstance * card);
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
int reactToClick(MTGCardInstance * card);
|
||||
int testDestroy();
|
||||
MTGPutInPlayRule(int _id);
|
||||
@@ -20,7 +20,7 @@ class MTGPutInPlayRule:public MTGAbility{
|
||||
|
||||
class MTGAttackRule:public MTGAbility{
|
||||
public:
|
||||
int isReactingToClick(MTGCardInstance * card);
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
int reactToClick(MTGCardInstance * card);
|
||||
int testDestroy();
|
||||
MTGAttackRule(int _id);
|
||||
@@ -30,7 +30,7 @@ class MTGAttackRule:public MTGAbility{
|
||||
|
||||
class MTGBlockRule:public MTGAbility{
|
||||
public:
|
||||
int isReactingToClick(MTGCardInstance * card);
|
||||
int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
|
||||
int reactToClick(MTGCardInstance * card);
|
||||
int testDestroy();
|
||||
MTGBlockRule(int _id);
|
||||
|
||||
Reference in New Issue
Block a user