- Fixed a Bug where AI would not correctly assign blockers if the first attacker is super strong. - Added a hack to prevent AI from an infinite loop while choosing a target. There are edge cases where the AI gets to choose the targets for a TargetChooser that doesn't belong to it. I couldn't dig too long for the root cause, so I added a "return 0" when the case happens. Should probably open a ticket - Added a "Hint" System in AI decks, to help the AI with its strategy. This is not really usable yet, it only works with abilities (not cards to play), and I only added some basic code for counters and tokens. This can probably be extended, but let's wait until we see it working on that other game I'm working on, before rushing into adding hints to all AI decks... - minor cleanup of AI Code
140 lines
3.9 KiB
C++
140 lines
3.9 KiB
C++
/*
|
|
* Wagic, The Homebrew ?! is licensed under the BSD license
|
|
* See LICENSE in the Folder's root
|
|
* http://wololo.net/wagic/
|
|
*/
|
|
|
|
#ifndef _IAPLAYER_H
|
|
#define _IAPLAYER_H
|
|
|
|
#include "Player.h"
|
|
|
|
#include <queue>
|
|
using std::queue;
|
|
|
|
#define INFO_NBCREATURES 0
|
|
#define INFO_CREATURESPOWER 1
|
|
#define INFO_CREATURESRANK 2
|
|
#define INFO_CREATURESTOUGHNESS 3
|
|
#define INFO_CREATURESATTACKINGPOWER 4
|
|
|
|
|
|
class AIStats;
|
|
class AIHints;
|
|
|
|
class AIAction
|
|
{
|
|
protected:
|
|
int efficiency;
|
|
static int currentId;
|
|
public:
|
|
MTGAbility * ability;
|
|
NestedAbility * nability;
|
|
Player * player;
|
|
int id;
|
|
MTGCardInstance * click;
|
|
MTGCardInstance * target; // TODO Improve
|
|
|
|
AIAction(MTGAbility * a, MTGCardInstance * c, MTGCardInstance * t = NULL)
|
|
: efficiency(-1), ability(a), player(NULL), click(c), target(t)
|
|
{
|
|
id = currentId++;
|
|
};
|
|
|
|
AIAction(MTGCardInstance * c, MTGCardInstance * t = NULL);
|
|
|
|
AIAction(Player * p)
|
|
: efficiency(-1), ability(NULL), player(p), click(NULL), target(NULL)
|
|
{
|
|
};
|
|
|
|
int getEfficiency();
|
|
int Act();
|
|
};
|
|
|
|
// compares Abilities efficiency
|
|
class CmpAbilities
|
|
{
|
|
public:
|
|
bool operator()(const AIAction& a1, const AIAction& a2) const
|
|
{
|
|
AIAction* a1Ptr = const_cast<AIAction*>(&a1);
|
|
AIAction* a2Ptr = const_cast<AIAction*>(&a2);
|
|
int e1 = a1Ptr->getEfficiency();
|
|
int e2 = a2Ptr->getEfficiency();
|
|
if (e1 == e2) return a1Ptr->id < a2Ptr->id;
|
|
return (e1 > e2);
|
|
}
|
|
};
|
|
|
|
typedef std::map<AIAction, int, CmpAbilities> RankingContainer;
|
|
|
|
class AIPlayer: public Player{
|
|
protected:
|
|
//Variables used by Test suite
|
|
MTGCardInstance * nextCardToPlay;
|
|
AIHints * hints;
|
|
queue<AIAction *> clickstream;
|
|
bool tapLandsForMana(ManaCost * cost, MTGCardInstance * card = NULL);
|
|
int orderBlockers();
|
|
int combatDamages();
|
|
int interruptIfICan();
|
|
int chooseAttackers();
|
|
int chooseBlockers();
|
|
int canFirstStrikeKill(MTGCardInstance * card, MTGCardInstance *ennemy);
|
|
int effectBadOrGood(MTGCardInstance * card, int mode = MODE_PUTINTOPLAY, TargetChooser * tc = NULL);
|
|
int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0);
|
|
AIStats * getStats();
|
|
|
|
// returns 1 if the AI algorithm supports a given cost (ex:simple mana cost), 0 otherwise (ex: cost involves Sacrificing a target)
|
|
int CanHandleCost(ManaCost * cost);
|
|
|
|
//Tries to play an ability recommended by the deck creator
|
|
int selectHintAbility();
|
|
|
|
public:
|
|
AIStats * stats;
|
|
int agressivity;
|
|
bool forceBestAbilityUse;
|
|
void End(){};
|
|
virtual int displayStack() {return 0;};
|
|
int receiveEvent(WEvent * event);
|
|
void Render();
|
|
ManaCost * getPotentialMana(MTGCardInstance * card = NULL);
|
|
AIPlayer(string deckFile, string deckFileSmall, MTGDeck * deck = NULL);
|
|
virtual ~AIPlayer();
|
|
virtual MTGCardInstance * chooseCard(TargetChooser * tc, MTGCardInstance * source, int random = 0);
|
|
virtual int chooseTarget(TargetChooser * tc = NULL, Player * forceTarget =NULL,MTGCardInstance * Choosencard = NULL);
|
|
virtual int Act(float dt);
|
|
virtual int affectCombatDamages(CombatStep);
|
|
int isAI(){return 1;};
|
|
int canHandleCost(MTGAbility * ability);
|
|
int selectAbility();
|
|
int createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingContainer& ranking);
|
|
int useAbility();
|
|
virtual int getEfficiency(AIAction * action);
|
|
|
|
};
|
|
|
|
|
|
class AIPlayerBaka: public AIPlayer{
|
|
protected:
|
|
int oldGamePhase;
|
|
float timer;
|
|
MTGCardInstance * FindCardToPlay(ManaCost * potentialMana, const char * type);
|
|
public:
|
|
int deckId;
|
|
AIPlayerBaka(string deckFile, string deckfileSmall, string avatarFile, MTGDeck * deck = NULL);
|
|
virtual int Act(float dt);
|
|
void initTimer();
|
|
virtual int computeActions();
|
|
};
|
|
|
|
class AIPlayerFactory{
|
|
public:
|
|
AIPlayer * createAIPlayer(MTGAllCards * collection, Player * opponent, int deckid = 0);
|
|
};
|
|
|
|
|
|
#endif
|