diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 3e05accf9..43bf5947b 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -21,6 +21,7 @@ ascendant_evincar2.txt brass_man.txt castle.txt circle_of_protection.txt +composite_golem.txt control_magic.txt control_magic2.txt counsel_of_the_soratami.txt diff --git a/projects/mtg/bin/Res/test/composite_golem.txt b/projects/mtg/bin/Res/test/composite_golem.txt new file mode 100644 index 000000000..a3c897a72 --- /dev/null +++ b/projects/mtg/bin/Res/test/composite_golem.txt @@ -0,0 +1,16 @@ +#Composite golem sacrifice ability subject to summoning Sickness ? +SummoningSickness +[INIT] +FIRSTMAIN +[PLAYER1] +inplay:135275 +[PLAYER2] +[DO] +135275 +[ASSERT] +FIRSTMAIN +[PLAYER1] +graveyard:135275 +manapool:{W}{U}{B}{R}{G} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index f28193d41..e7b6bd289 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -616,195 +616,7 @@ class ASpellCounterEnchantment:public TargetAbility{ }; -/*Mana Producers (lands) -//These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other -//That means the player has to choose one. although that is perfect for cards such as birds of paradise or badlands, -other solutions need to be provided for abilities that add mana (ex: mana flare) -*/ -/* - Currently the mana is added to the pool AFTER the animation - This is VERY BAD, since we don't have any control on the duration of the animation. This can lead to bugs with - the AI, who is expecting to have the mana in its manapool right after clicking the land card !!! - The sum of "dt" has to be 0.25 for the mana to be in the manapool currently -*/ -class AManaProducer: public MTGAbility{ - protected: - static int currentlyTapping; - ManaCost * cost; - ManaCost * output; - string menutext; - float x0,y0,x1,y1,x,y; - float animation; - Player * controller; - - hgeParticleSystem * mParticleSys; - public: - AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL ):MTGAbility(id, card){ - LOG("==Creating ManaProducer Object"); - if (!_cost) OutputDebugString("NO COST???\n"); - cost = _cost; - output=_output; - x1 = 10; - y1 = 220; - Player * player = card->controller(); - if (player == game->players[1]) y1 = 100; - x = x1; - y = y1; - animation = 0.f; - mParticleSys = NULL; - menutext = ""; - - int landColor = output->getMainColor(); - - if (landColor == Constants::MTG_COLOR_RED){ - mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_BLUE){ - mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_GREEN){ - mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_BLACK){ - mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == Constants::MTG_COLOR_WHITE){ - mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); - }else{ - mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); - } - - - - LOG("==ManaProducer Object Creation successful !"); - } - - void Update(float dt){ - if (mParticleSys) mParticleSys->Update(dt); - if (animation){ - x = (1.f - animation)*x1 + animation * x0; - y = (1.f - animation)*y1 + animation * y0; - if (mParticleSys) mParticleSys->MoveTo(x, y); - if (mParticleSys && animation == 1.f) mParticleSys->Fire(); - animation -= 4 *dt; - if (!animation) animation = -1; - if (animation < 0){ - animation = 0; - currentlyTapping--; - resolve(); - if (mParticleSys) mParticleSys->Stop(); - } - } - - } - - void Render(){ - JRenderer * renderer = JRenderer::GetInstance(); - if (animation){ - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); - if (mParticleSys) mParticleSys->Render(); - // set normal blending - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); - } - - } - - int isReactingToClick(MTGCardInstance * _card){ - int result = 0; - if (_card == source && !source->isTapped() && game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType("land") || !source->hasSummoningSickness()) ){ - if (!cost || game->currentlyActing()->getManaPool()->canAfford(cost)) result = 1; - } - return result; - } - - int resolve(){ - controller = source->controller(); - controller->getManaPool()->add(output); - return 1; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - OutputDebugString("React To click 1\n"); - if (cost){ - cost->setExtraCostsAction(this, _card); - OutputDebugString("React To click 2\n"); - if (!cost->isExtraPaymentSet()){ - OutputDebugString("React To click 3\n"); - - GameObserver::GetInstance()->waitForExtraPayment = cost->extraCosts; - return 0; - } - GameObserver::GetInstance()->currentlyActing()->getManaPool()->pay(cost); - cost->doPayExtra(); - } - source->tapped = 1; - currentlyTapping++; - - animation = 1.f; - CardGui * cardg = game->mLayers->playLayer()->getByCard(source); - if (cardg){ - x0 = cardg->x + 15; - y0 = cardg->y + 20; - } - - - if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME].getIntValue() > 0 && currentlyTapping < 3){ - JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/mana.wav"); - if (sample) JSoundSystem::GetInstance()->PlaySample(sample); - } - return 1; - } - - const char * getMenuText(){ - if (menutext.size())return menutext.c_str(); - menutext = "Add "; - char buffer[128]; - int alreadyHasOne = 0; - for (int i= 0; i < 6; i++){ - int value = output->getCost(i); - if (value){ - if (alreadyHasOne) menutext.append(","); - sprintf(buffer, "%i ", value); - menutext.append(buffer); - switch (i){ - case Constants::MTG_COLOR_RED: - menutext.append("red"); - break; - case Constants::MTG_COLOR_BLUE: - menutext.append("blue"); - break; - case Constants::MTG_COLOR_GREEN: - menutext.append("green"); - break; - case Constants::MTG_COLOR_WHITE: - menutext.append("white"); - break; - case Constants::MTG_COLOR_BLACK: - menutext.append("black"); - break; - default: - break; - } - alreadyHasOne = 1; - } - } - menutext.append(" mana"); - return menutext.c_str(); - } - - int testDestroy(){ - if (animation >0) return 0; - return MTGAbility::testDestroy(); - } - - ~AManaProducer(){ - LOG("==Destroying ManaProducer Object"); - SAFE_DELETE(cost); - SAFE_DELETE(output); - SAFE_DELETE(mParticleSys); - LOG("==Destroying ManaProducer Object Successful!"); - } - -}; -int AManaProducer::currentlyTapping = 0; /* Lifelink Ability */ class ALifeLink:public MTGAbility{ diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 3c15eff7d..aa7f675d1 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -12,10 +12,12 @@ class TargetChooser; class ManaCost; class MTGGameZone; class Player; +class AManaProducer; #include "ActionElement.h" #include #include +#include using std::string; using std::map; @@ -207,6 +209,31 @@ 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: + static int currentlyTapping; + AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 1 ); + void Update(float dt); + void Render(); + int isReactingToClick(MTGCardInstance * _card); + int resolve(); + int reactToClick(MTGCardInstance * _card); + const char * getMenuText(); + int testDestroy(); + ~AManaProducer(); +}; + #include "MTGCardInstance.h" #endif diff --git a/projects/mtg/include/TestSuiteAI.h b/projects/mtg/include/TestSuiteAI.h index 4434922b3..d18e0cbe1 100644 --- a/projects/mtg/include/TestSuiteAI.h +++ b/projects/mtg/include/TestSuiteAI.h @@ -47,6 +47,7 @@ class TestSuiteState{ }; class TestSuite{ public: + int summoningSickness; float timerLimit; int currentAction; TestSuiteState initState; diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index ff195373c..f09b569cf 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -518,7 +518,7 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ if (input->isNull()){ SAFE_DELETE(input); } - MTGAbility * a = NEW AManaProducer(id, target, output, input); + MTGAbility * a = NEW AManaProducer(id, target, output, input,doTap); if (multi){ multi->Add(a); }else{ @@ -1973,3 +1973,181 @@ GenericTriggeredAbility::~GenericTriggeredAbility(){ delete te; SAFE_DELETE(dc); } + + +/*Mana Producers (lands) +//These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other +//That means the player has to choose one. although that is perfect for cards such as birds of paradise or badlands, +other solutions need to be provided for abilities that add mana (ex: mana flare) +*/ +/* + Currently the mana is added to the pool AFTER the animation + This is VERY BAD, since we don't have any control on the duration of the animation. This can lead to bugs with + the AI, who is expecting to have the mana in its manapool right after clicking the land card !!! + The sum of "dt" has to be 0.25 for the mana to be in the manapool currently +*/ + + + AManaProducer::AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost , int doTap):MTGAbility(id, card), tap(doTap){ + LOG("==Creating ManaProducer Object"); + cost = _cost; + output=_output; + x1 = 10; + y1 = 220; + Player * player = card->controller(); + if (player == game->players[1]) y1 = 100; + x = x1; + y = y1; + animation = 0.f; + mParticleSys = NULL; + menutext = ""; + + int landColor = output->getMainColor(); + + if (landColor == Constants::MTG_COLOR_RED){ + mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == Constants::MTG_COLOR_BLUE){ + mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == Constants::MTG_COLOR_GREEN){ + mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == Constants::MTG_COLOR_BLACK){ + mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == Constants::MTG_COLOR_WHITE){ + mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); + }else{ + mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); + } + + + + LOG("==ManaProducer Object Creation successful !"); + } + + void AManaProducer::Update(float dt){ + if (mParticleSys) mParticleSys->Update(dt); + if (animation){ + x = (1.f - animation)*x1 + animation * x0; + y = (1.f - animation)*y1 + animation * y0; + if (mParticleSys) mParticleSys->MoveTo(x, y); + if (mParticleSys && animation == 1.f) mParticleSys->Fire(); + animation -= 4 *dt; + if (!animation) animation = -1; + if (animation < 0){ + animation = 0; + currentlyTapping--; + resolve(); + if (mParticleSys) mParticleSys->Stop(); + } + } + + } + + void AManaProducer::Render(){ + JRenderer * renderer = JRenderer::GetInstance(); + if (animation){ + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); + if (mParticleSys) mParticleSys->Render(); + // set normal blending + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); + } + + } + + int AManaProducer::isReactingToClick(MTGCardInstance * _card){ + int result = 0; + if (_card == source && (!tap || !source->isTapped()) && game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType("land") || !tap || !source->hasSummoningSickness()) ){ + if (!cost || game->currentlyActing()->getManaPool()->canAfford(cost)) result = 1; + } + return result; + } + + int AManaProducer::resolve(){ + controller = source->controller(); + controller->getManaPool()->add(output); + return 1; + } + + int AManaProducer::reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + OutputDebugString("React To click 1\n"); + if (cost){ + cost->setExtraCostsAction(this, _card); + OutputDebugString("React To click 2\n"); + if (!cost->isExtraPaymentSet()){ + OutputDebugString("React To click 3\n"); + + GameObserver::GetInstance()->waitForExtraPayment = cost->extraCosts; + return 0; + } + GameObserver::GetInstance()->currentlyActing()->getManaPool()->pay(cost); + cost->doPayExtra(); + } + if (tap) source->tapped = 1; + currentlyTapping++; + + animation = 1.f; + CardGui * cardg = game->mLayers->playLayer()->getByCard(source); + if (cardg){ + x0 = cardg->x + 15; + y0 = cardg->y + 20; + } + + + if (GameOptions::GetInstance()->values[OPTIONS_SFXVOLUME].getIntValue() > 0 && currentlyTapping < 3){ + JSample * sample = SampleCache::GetInstance()->getSample("sound/sfx/mana.wav"); + if (sample) JSoundSystem::GetInstance()->PlaySample(sample); + } + return 1; + } + + const char * AManaProducer::getMenuText(){ + if (menutext.size())return menutext.c_str(); + menutext = "Add "; + char buffer[128]; + int alreadyHasOne = 0; + for (int i= 0; i < 6; i++){ + int value = output->getCost(i); + if (value){ + if (alreadyHasOne) menutext.append(","); + sprintf(buffer, "%i ", value); + menutext.append(buffer); + switch (i){ + case Constants::MTG_COLOR_RED: + menutext.append("red"); + break; + case Constants::MTG_COLOR_BLUE: + menutext.append("blue"); + break; + case Constants::MTG_COLOR_GREEN: + menutext.append("green"); + break; + case Constants::MTG_COLOR_WHITE: + menutext.append("white"); + break; + case Constants::MTG_COLOR_BLACK: + menutext.append("black"); + break; + default: + break; + } + alreadyHasOne = 1; + } + } + menutext.append(" mana"); + return menutext.c_str(); + } + + int AManaProducer::testDestroy(){ + if (animation >0) return 0; + return MTGAbility::testDestroy(); + } + + AManaProducer::~AManaProducer(){ + LOG("==Destroying ManaProducer Object"); + SAFE_DELETE(cost); + SAFE_DELETE(output); + SAFE_DELETE(mParticleSys); + LOG("==Destroying ManaProducer Object Successful!"); + } + +int AManaProducer::currentlyTapping = 0; \ No newline at end of file diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index eea792192..94100de5d 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -1,5 +1,6 @@ #include "../include/TestSuiteAI.h" #include "../include/config.h" +#include "../include/MTGAbility.h" #include using std::string; @@ -45,7 +46,7 @@ int TestSuiteAI::Act(float dt){ GameObserver * g = GameObserver::GetInstance(); g->gameOver = NULL; // Prevent draw rule from losing the game timer+= dt; - if (timer < suite->timerLimit) return 1; + if (AManaProducer::currentlyTapping || timer < suite->timerLimit) return 1; timer = 0; string action = suite->getNextAction(); @@ -212,7 +213,7 @@ void TestSuite::initGame(){ if (!timerLimit){ timerLimit = 0.3; }else{ - timerLimit = 0.26; + timerLimit = 0.1; } //Put the GameObserver in the initial state GameObserver * g = GameObserver::GetInstance(); @@ -237,7 +238,7 @@ void TestSuite::initGame(){ Spell * spell = NEW Spell(card); p->game->putInZone(card, p->game->hand, p->game->stack); spell->resolve(); - card->summoningSickness = 0; + if (!summoningSickness) card->summoningSickness = 0; delete spell; }else{ if (!p->game->library->hasCard(card)){ @@ -358,6 +359,7 @@ TestSuite::TestSuite(const char * filename){ } int TestSuite::loadNext(){ + summoningSickness = 0; if (!nbfiles) return 0; if (currentfile >= nbfiles) return 0; load(files[currentfile].c_str()); @@ -430,6 +432,10 @@ void TestSuite::load(const char * _filename){ if (s[s.size()-1] == '\r') s.erase(s.size()-1); //Handle DOS files if (s[0] == '#') continue; std::transform( s.begin(), s.end(), s.begin(),::tolower ); + if (s.compare("summoningsickness") == 0) { + summoningSickness = 1; + continue; + } switch(state){ case -1: if (s.compare("[init]") == 0) state++;