Erwan
- Added the possibility to narrow a spell/ability target according to color,tapped status, attacker/blocker, abilities... - Changed the games phase system to become a phaseRing. This allows to add cards that have an impact on the phases, such as stasis - Added a few cards - Fixed a (windows) bug in gatherer tool - Adding stdint.h for VC++ (see wikipedia->stdint.h) - deleting the compiled PSP lib to avoid confusion. People who work from the sourcehave to compile the lib by themselves.
This commit is contained in:
@@ -27,7 +27,7 @@ MTGCardInstance * AIPlayer::chooseCard(TargetChooser * tc, MTGCardInstance * sou
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AIPlayer::Act(){
|
||||
int AIPlayer::Act(float dt){
|
||||
GameObserver * gameObs = GameObserver::GetInstance();
|
||||
if (gameObs->currentPlayer == this){
|
||||
gameObs->userRequestNextGamePhase();
|
||||
@@ -486,7 +486,7 @@ void AIPlayerBaka::initTimer(){
|
||||
timer = 20;
|
||||
}
|
||||
|
||||
int AIPlayerBaka::Act(){
|
||||
int AIPlayerBaka::Act(float dt){
|
||||
GameObserver * gameObs = GameObserver::GetInstance();
|
||||
int currentGamePhase = gameObs->getCurrentGamePhase();
|
||||
|
||||
|
||||
@@ -3,30 +3,107 @@
|
||||
|
||||
CardDescriptor::CardDescriptor(): MTGCardInstance(){
|
||||
init();
|
||||
mode = CD_AND;
|
||||
}
|
||||
|
||||
int CardDescriptor::init(){
|
||||
return MTGCardInstance::init();
|
||||
}
|
||||
|
||||
MTGCardInstance * CardDescriptor::match(MTGCardInstance * card){
|
||||
MTGCardInstance * CardDescriptor::match_or(MTGCardInstance * card){
|
||||
int found = 1;
|
||||
for (int i = 0; i< nb_types; i++){
|
||||
found = 0;
|
||||
if (card->hasSubtype(types[i])){
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return NULL;
|
||||
|
||||
for (int i = 0; i< MTG_NB_COLORS; i++){
|
||||
found = 0;
|
||||
if (colors[i] == 1 && card->hasColor(i)){
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return NULL;
|
||||
return card;
|
||||
}
|
||||
|
||||
MTGCardInstance * CardDescriptor::match_and(MTGCardInstance * card){
|
||||
#ifdef WIN32
|
||||
OutputDebugString("Match AND\n");
|
||||
#endif
|
||||
|
||||
MTGCardInstance * match = card;
|
||||
for (int i = 0; i< nb_types; i++){
|
||||
|
||||
if (!card->hasSubtype(types[i])){
|
||||
|
||||
#ifdef WIN32
|
||||
OutputDebugString(card->name.c_str());
|
||||
OutputDebugString("Subtype No Match\n");
|
||||
#endif
|
||||
match = NULL;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i< MTG_NB_COLORS; i++){
|
||||
if ((colors[i] == 1 && !card->hasColor(i))||(colors[i] == -1 && card->hasColor(i))){
|
||||
match = NULL;
|
||||
#ifdef WIN32
|
||||
OutputDebugString(card->name.c_str());
|
||||
OutputDebugString("Color No Match\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
MTGCardInstance * CardDescriptor::match(MTGCardInstance * card){
|
||||
|
||||
MTGCardInstance * match = card;
|
||||
|
||||
if (mode == CD_AND){
|
||||
match = match_and(card);
|
||||
}else{
|
||||
match=match_or(card);
|
||||
}
|
||||
|
||||
//Abilities
|
||||
for (int j = 0; j < NB_BASIC_ABILITIES; j++){
|
||||
if ((basicAbilities[j] == 1 && !card->basicAbilities[j]) || (basicAbilities[j] == -1 && card->basicAbilities[j])){
|
||||
match = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tapped == -1 && card->isTapped()) || (tapped == 1 && !card->isTapped())){
|
||||
match = NULL;
|
||||
}
|
||||
|
||||
if (attacker == 1){
|
||||
if ((int)defenser == 1){
|
||||
if (!card->attacker && !card->defenser) match = NULL;
|
||||
}else{
|
||||
if (!card->attacker) match = NULL;
|
||||
}
|
||||
}else if (attacker == -1){
|
||||
if ((int)defenser == -1){
|
||||
if (card->attacker || card->defenser) match = NULL;
|
||||
}else{
|
||||
if (card->attacker) match = NULL;
|
||||
}
|
||||
}else{
|
||||
if ((int)defenser == -1){
|
||||
if (card->defenser) match = NULL;
|
||||
}else if ((int)defenser == 1){
|
||||
if (!card->defenser) match = NULL;
|
||||
}else{
|
||||
// we don't care about the attack/blocker state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ GameObserver::GameObserver(Player * _players[], int _nb_players){
|
||||
cardWaitingForTargets = NULL;
|
||||
reaction = 0;
|
||||
gameOver = NULL;
|
||||
phaseRing = NEW PhaseRing(_players,_nb_players);
|
||||
}
|
||||
|
||||
void GameObserver::setGamePhaseManager(MTGGamePhase * _phases){
|
||||
@@ -73,11 +74,21 @@ void GameObserver::nextPlayer(){
|
||||
currentPlayerId = (currentPlayerId+1)%nbPlayers;
|
||||
currentPlayer = players[currentPlayerId];
|
||||
currentActionPlayer = currentPlayer;
|
||||
currentPlayer->canPutLandsIntoPlay = 1; //TODO more useful function
|
||||
|
||||
}
|
||||
void GameObserver::nextGamePhase(){
|
||||
currentGamePhase++;
|
||||
phaseRing->forward();
|
||||
Phase * cPhase = phaseRing->getCurrentPhase();
|
||||
currentGamePhase = cPhase->id;
|
||||
if (currentPlayer != cPhase->player) nextPlayer();
|
||||
|
||||
//init begin of turn
|
||||
if (currentGamePhase == MTG_PHASE_BEFORE_BEGIN){
|
||||
cleanupPhase();
|
||||
currentPlayer->canPutLandsIntoPlay = 1;
|
||||
mLayers->actionLayer()->Update(0);
|
||||
return nextGamePhase();
|
||||
}
|
||||
//manaBurn
|
||||
if (currentGamePhase == MTG_PHASE_UNTAP ||
|
||||
currentGamePhase == MTG_PHASE_FIRSTMAIN ||
|
||||
@@ -88,21 +99,20 @@ void GameObserver::nextGamePhase(){
|
||||
currentPlayer->manaBurn();
|
||||
}
|
||||
|
||||
//Next Player ?
|
||||
if (currentGamePhase > MTG_PHASE_CLEANUP){
|
||||
//After End of turn
|
||||
if (currentGamePhase == MTG_PHASE_AFTER_EOT){
|
||||
//Auto Hand cleaning, in case the player didn't do it himself
|
||||
while(currentPlayer->game->hand->nb_cards > 7){
|
||||
currentPlayer->game->putInGraveyard(currentPlayer->game->hand->cards[0]);
|
||||
}
|
||||
mLayers->stackLayer()->garbageCollect(); //clean stack history for this turn;
|
||||
nextPlayer();
|
||||
currentGamePhase = MTG_PHASE_UNTAP;
|
||||
mLayers->actionLayer()->Update(0);
|
||||
return nextGamePhase();
|
||||
}
|
||||
|
||||
//Phase Specific actions
|
||||
switch(currentGamePhase){
|
||||
case MTG_PHASE_UNTAP:
|
||||
cleanupPhase();
|
||||
untapPhase();
|
||||
break;
|
||||
case MTG_PHASE_DRAW:
|
||||
@@ -137,7 +147,8 @@ void GameObserver::startGame(int shuffle, int draw){
|
||||
for (i=0; i<nbPlayers; i++){
|
||||
players[i]->game->initGame(shuffle, draw);
|
||||
}
|
||||
currentGamePhase = MTG_PHASE_FIRSTMAIN;
|
||||
phaseRing->goToPhase(MTG_PHASE_FIRSTMAIN, players[0]);
|
||||
currentGamePhase = MTG_PHASE_FIRSTMAIN;
|
||||
}
|
||||
|
||||
void GameObserver::addObserver(MTGAbility * observer){
|
||||
@@ -158,6 +169,7 @@ GameObserver::~GameObserver(){
|
||||
LOG("==Destroying GameObserver==");
|
||||
SAFE_DELETE(targetChooser);
|
||||
SAFE_DELETE(mLayers);
|
||||
SAFE_DELETE(phaseRing);
|
||||
LOG("==GameObserver Destroyed==");
|
||||
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ void GuiLayers::Update(float dt, Player * currentPlayer){
|
||||
}
|
||||
}
|
||||
if (isAI){
|
||||
currentPlayer->Act();
|
||||
currentPlayer->Act(dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -223,8 +223,8 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){
|
||||
continue;
|
||||
}
|
||||
|
||||
//gainlife
|
||||
found = s.find("gainlife");
|
||||
//gain/lose life
|
||||
found = s.find("life");
|
||||
if (found != string::npos){
|
||||
unsigned int start = s.find(":",found);
|
||||
unsigned int end = s.find(" ",start);
|
||||
@@ -861,11 +861,6 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){
|
||||
MTGPlayerCards * zones = game->currentlyActing()->game;
|
||||
zones->putInZone(card->target,zones->graveyard,zones->hand);
|
||||
}
|
||||
case 1175: //Royal Assassin
|
||||
{
|
||||
game->addObserver(NEW ARoyalAssassin(_id, card));
|
||||
break;
|
||||
}
|
||||
case 1176: //Sacrifice
|
||||
{
|
||||
ASacrifice * ability = NEW ASacrifice(_id, card, card->target);
|
||||
@@ -1215,6 +1210,12 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1225: //Stasis
|
||||
{
|
||||
game->addObserver(NEW AStasis(_id, card));
|
||||
break;
|
||||
}
|
||||
|
||||
case 1367: //Sword to Plowshares
|
||||
{
|
||||
card->target->controller()->life+= card->target->power;
|
||||
|
||||
@@ -12,10 +12,6 @@ MTGGamePhase::MTGGamePhase(int id):ActionElement(id){
|
||||
|
||||
|
||||
void MTGGamePhase::Render(){
|
||||
/*if (animation){
|
||||
RenderMessageBackground(10, 100);
|
||||
mFont->DrawString(MTGPhaseNames[currentState], SCREEN_WIDTH_F/2, 30, JGETEXT_CENTER);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +33,7 @@ void MTGGamePhase::Update(float dt){
|
||||
|
||||
if (animation > 0){
|
||||
fprintf(stderr, "animation = %f", animation);
|
||||
animation -= 0.05;
|
||||
animation -= dt *5 ;
|
||||
}else{
|
||||
activeState = INACTIVE;
|
||||
animation = 0;
|
||||
|
||||
@@ -306,7 +306,7 @@ void MTGGuiPlay::RenderPhaseBar(){
|
||||
int currentPhase = game->getCurrentGamePhase();
|
||||
for (int i=0; i < 12; i++){
|
||||
int index = 2*i + 1 ;
|
||||
if (i==currentPhase){
|
||||
if (i==currentPhase-1){
|
||||
index-=1;
|
||||
}
|
||||
renderer->RenderQuad(phaseIcons[index], 200 + 14*i,0,0,0.5,0.5);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../include/debug.h"
|
||||
#include "../include/TargetChooser.h"
|
||||
|
||||
#include "../include/CardDescriptor.h"
|
||||
#include "../include/MTGGameZones.h"
|
||||
#include "../include/GameObserver.h"
|
||||
#include "../include/Subtypes.h"
|
||||
@@ -75,8 +75,9 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
zones[1]= game->players[1]->game->inPlay;
|
||||
}
|
||||
|
||||
TypeTargetChooser * tc = NULL;
|
||||
TargetChooser * tc = NULL;
|
||||
int maxtargets = 1;
|
||||
CardDescriptor * cd = NULL;
|
||||
|
||||
while(s1.size()){
|
||||
found = s1.find(",");
|
||||
@@ -88,20 +89,128 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
typeName = s1;
|
||||
s1 = "";
|
||||
}
|
||||
|
||||
//Advanced cards caracteristics ?
|
||||
found = typeName.find("[");
|
||||
if (found != string::npos){
|
||||
int nbminuses = 0;
|
||||
int end = typeName.find("]");
|
||||
#ifdef WIN32
|
||||
OutputDebugString("Advanced Attributes 1 \n");
|
||||
#endif
|
||||
string attributes = typeName.substr(found+1,end-found-1);
|
||||
#ifdef WIN32
|
||||
OutputDebugString(attributes.c_str());
|
||||
OutputDebugString("\n");
|
||||
#endif
|
||||
cd = NEW CardDescriptor();
|
||||
while(attributes.size()){
|
||||
int found2 = attributes.find(";");
|
||||
string attribute;
|
||||
if (found2 != string::npos){
|
||||
attribute = attributes.substr(0,found2);
|
||||
attributes = attributes.substr(found2+1);
|
||||
}else{
|
||||
attribute = attributes;
|
||||
attributes = "";
|
||||
}
|
||||
int minus = 0;
|
||||
if (attribute[0] == '-'){
|
||||
#ifdef WIN32
|
||||
OutputDebugString("MINUS\n");
|
||||
#endif
|
||||
minus = 1;
|
||||
nbminuses++;
|
||||
}
|
||||
#ifdef WIN32
|
||||
OutputDebugString(attribute.c_str());
|
||||
OutputDebugString("\n");
|
||||
#endif
|
||||
//Attacker
|
||||
if (attribute.find("attacking") != string::npos){
|
||||
if (minus){
|
||||
cd->attacker = -1;
|
||||
}else{
|
||||
cd->attacker = 1;
|
||||
}
|
||||
|
||||
//Blocker
|
||||
}else if (attribute.find("blocking") != string::npos){
|
||||
if (minus){
|
||||
cd->defenser = (MTGCardInstance *)-1; //Oh yeah, that's ugly....
|
||||
}else{
|
||||
cd->defenser = (MTGCardInstance *)1;
|
||||
}
|
||||
|
||||
//Tapped, untapped
|
||||
}else if (attribute.find("tapped") != string::npos){
|
||||
if (minus){
|
||||
cd->tapped = -1;
|
||||
}else{
|
||||
cd->tapped = 1;
|
||||
}
|
||||
}else{
|
||||
int attributefound = 0;
|
||||
//Colors
|
||||
for (int cid = 0; cid < MTG_NB_COLORS; cid++){
|
||||
if (attribute.find(MTGColorStrings[cid]) != string::npos){
|
||||
attributefound = 1;
|
||||
if (minus){
|
||||
cd->colors[cid] = -1;
|
||||
}else{
|
||||
cd->colors[cid] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!attributefound){
|
||||
//Abilities
|
||||
for (int j = 0; j < NB_BASIC_ABILITIES; j++){
|
||||
if (attribute.find(MTGBasicAbilities[j]) != string::npos){
|
||||
attributefound = 1;
|
||||
if (minus){
|
||||
cd->basicAbilities[j] = -1;
|
||||
}else{
|
||||
cd->basicAbilities[j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nbminuses < 2){
|
||||
#ifdef WIN32
|
||||
OutputDebugString("Switching to OR\n");
|
||||
#endif
|
||||
cd->mode = CD_OR;
|
||||
}
|
||||
typeName = typeName.substr(0,found);
|
||||
}
|
||||
//X targets allowed ?
|
||||
if (typeName.at(typeName.length()-1) == 's'){
|
||||
typeName = typeName.substr(0,typeName.length()-1);
|
||||
maxtargets = -1;
|
||||
}
|
||||
if (!tc){
|
||||
if (typeName.compare("*")==0){
|
||||
return NEW TargetZoneChooser(zones, nbzones,card, maxtargets);
|
||||
if (cd){
|
||||
if (!tc){
|
||||
if (typeName.compare("*")!=0) cd->setSubtype(typeName);
|
||||
tc = NEW DescriptorTargetChooser(cd,zones,nbzones,card,maxtargets);
|
||||
#ifdef WIN32
|
||||
OutputDebugString("Advanced Attributes 2 \n");
|
||||
#endif
|
||||
}else{
|
||||
tc = NEW TypeTargetChooser(typeName.c_str(), zones, nbzones, card,maxtargets);
|
||||
return NULL;
|
||||
}
|
||||
}else{
|
||||
tc->addType(typeName.c_str());
|
||||
tc->maxtargets = maxtargets;
|
||||
if (!tc){
|
||||
if (typeName.compare("*")==0){
|
||||
return NEW TargetZoneChooser(zones, nbzones,card, maxtargets);
|
||||
}else{
|
||||
tc = NEW TypeTargetChooser(typeName.c_str(), zones, nbzones, card,maxtargets);
|
||||
}
|
||||
}else{
|
||||
((TypeTargetChooser *)tc)->addType(typeName.c_str());
|
||||
tc->maxtargets = maxtargets;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tc;
|
||||
@@ -275,8 +384,41 @@ int TypeTargetChooser::canTarget(Targetable * target ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
A Target Chooser associated to a Card Descriptor object, for fine tuning of targets description
|
||||
**/
|
||||
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
|
||||
GameObserver * game = GameObserver::GetInstance();
|
||||
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
|
||||
init(default_zones,2);
|
||||
cd = _cd;
|
||||
}
|
||||
|
||||
DescriptorTargetChooser::DescriptorTargetChooser(CardDescriptor * _cd, MTGGameZone ** _zones, int nbzones, MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
|
||||
GameObserver * game = GameObserver::GetInstance();
|
||||
if (nbzones == 0){
|
||||
MTGGameZone * default_zones[] = {game->players[0]->game->inPlay, game->players[1]->game->inPlay};
|
||||
init(default_zones,2);
|
||||
}else{
|
||||
init(_zones, nbzones);
|
||||
}
|
||||
cd = _cd;
|
||||
}
|
||||
|
||||
int DescriptorTargetChooser::canTarget(Targetable * target){
|
||||
if (target->typeAsTarget() == TARGET_CARD){
|
||||
MTGCardInstance * card = (MTGCardInstance *) target;
|
||||
if (!TargetZoneChooser::canTarget(card)) return 0;
|
||||
if (cd->match(card)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Choose a creature anywhere. This is actually not enough as a zone should be selected
|
||||
Choose a creature
|
||||
**/
|
||||
|
||||
CreatureTargetChooser::CreatureTargetChooser( MTGCardInstance * card, int _maxtargets):TargetZoneChooser(card, _maxtargets){
|
||||
|
||||
@@ -41,11 +41,14 @@ Interruptible * TestSuite::getActionByMTGId(int mtgid){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int TestSuiteAI::Act(){
|
||||
int TestSuiteAI::Act(float dt){
|
||||
GameObserver * g = GameObserver::GetInstance();
|
||||
g->gameOver = NULL; // Prevent draw rule from losing the game
|
||||
timer++;
|
||||
if (timer < 20) return 1;
|
||||
timer+= dt;
|
||||
char buf[4096];
|
||||
sprintf(buf, "%f\n", timer);
|
||||
OutputDebugString (buf);
|
||||
if (timer < suite->timerLimit) return 1;
|
||||
timer = 0;
|
||||
string action = suite->getNextAction();
|
||||
if (g->mLayers->stackLayer()->askIfWishesToInterrupt == this){
|
||||
@@ -193,9 +196,19 @@ MTGPlayerCards * TestSuite::buildDeck(MTGAllCards * collection, int playerId){
|
||||
}
|
||||
|
||||
void TestSuite::initGame(){
|
||||
//The first test runs slowly, the other ones run faster.
|
||||
//This way a human can see what happens when testing a specific file,
|
||||
// or go faster when it comes to the whole test suite.
|
||||
//Warning, putting this value too low (< 0.25) will give unexpected results
|
||||
if (!timerLimit){
|
||||
timerLimit = 0.3;
|
||||
}else{
|
||||
timerLimit = 0.26;
|
||||
}
|
||||
//Put the GameObserver in the initial state
|
||||
GameObserver * g = GameObserver::GetInstance();
|
||||
OutputDebugString("Init Game\n");
|
||||
g->phaseRing->goToPhase(initState.phase, g->players[0]);
|
||||
g->currentGamePhase = initState.phase;
|
||||
for (int i = 0; i < 2; i++){
|
||||
Player * p = g->players[i];
|
||||
@@ -296,6 +309,7 @@ int TestSuite::assertGame(){
|
||||
}
|
||||
|
||||
TestSuite::TestSuite(const char * filename){
|
||||
timerLimit = 0;
|
||||
std::ifstream file(filename);
|
||||
std::string s;
|
||||
nbfiles = 0;
|
||||
|
||||
Reference in New Issue
Block a user