- Fix a memory leak in AI "payTheManaCost"

- Minor fixes in AI code
- Attempt at preventing the AI from interrupting itself while it's selecting targets. I don't know why this happens, and my fix didn't work. I believe it shouldn't be possible to interrupt when there is an active targetChooser, please let me know if this is an incorrect assumption.
This commit is contained in:
wagic.the.homebrew
2011-09-21 03:54:47 +00:00
parent 206f3b4d3f
commit e9ce574bca
5 changed files with 748 additions and 113 deletions

View File

@@ -270,9 +270,11 @@ int OrderedAIAction::getEfficiency()
{
if(_target->defenser || _target->blockers.size())
{
if(!_target->getNextOpponent()->typeAsTarget() == TARGET_CARD)
MTGCardInstance * opponent = _target->getNextOpponent();
if (!opponent)
break;
if (_target->power < _target->getNextOpponent()->toughness ||(_target->getNextOpponent() && _target->toughness < _target->getNextOpponent()->power) || (_target->has(Constants::TRAMPLE)))
if (_target->power < opponent->toughness ||( _target->toughness < opponent->power) || (_target->has(Constants::TRAMPLE)))
{
//this pump is based on a start eff. of 20 multiplied by how good the creature is.
efficiency = 20 * _target->DangerRanking();
@@ -659,82 +661,83 @@ MTGCardInstance * AIPlayerBaka::chooseCard(TargetChooser * tc, MTGCardInstance *
bool AIPlayerBaka::payTheManaCost(ManaCost * cost, MTGCardInstance * target,vector<MTGAbility*>gotPayments)
{
DebugTrace(" AI attempting to pay a mana cost." << endl
DebugTrace("AIPlayerBaka: AI attempting to pay a mana cost." << endl
<< "- Target: " << (target ? target->name : "None" ) << endl
<< "- Cost: " << (cost ? cost->toString() : "NULL") );
if(cost && !cost->getConvertedCost())
{
DebugTrace("Card or Ability was free to play. ");
if(!cost->hasX())//don't return true if it contains {x} but no cost, locks ai in a loop. ie oorchi hatchery cost {x}{x} to play.
return true;
//return true if cost does not contain "x" becuase we don't need to do anything with a cost of 0;
}
if (!cost)
{
DebugTrace("Mana cost is NULL. ");
DebugTrace("AIPlayerBaka: Mana cost is NULL. ");
return false;
}
ManaCost * pMana = NULL;
if(!gotPayments.size())
if(!cost->getConvertedCost())
{
pMana = target ? getPotentialMana(target) : getPotentialMana();
pMana->add(this->getManaPool());
}
if(cost && pMana && !cost->getConvertedCost() && cost->hasX())
{
cost = pMana;//{x}:effect, set x to max.
DebugTrace("AIPlayerBaka: Card or Ability was free to play. ");
if(!cost->hasX())//don't return true if it contains {x} but no cost, locks ai in a loop. ie oorchi hatchery cost {x}{x} to play.
return true;
//return true if cost does not contain "x" becuase we don't need to do anything with a cost of 0;
}
if(gotPayments.size())
{
DebugTrace(" Ai had a payment in mind.");
DebugTrace("AIPlayerBaka: Ai had a payment in mind.");
ManaCost * paid = NEW ManaCost();
vector<AIAction*>clicks = vector<AIAction*>();
vector<AIAction*>clicks;
paid->init();
for(int k = 0;k < int(gotPayments.size());k++)
for(size_t k = 0; k < gotPayments.size(); ++k)
{
AManaProducer * amp = dynamic_cast<AManaProducer*> (gotPayments[k]);
GenericActivatedAbility * gmp = dynamic_cast<GenericActivatedAbility*>(gotPayments[k]);
if (amp)
if ( AManaProducer * amp = dynamic_cast<AManaProducer*> (gotPayments[k]))
{
AIAction * action = NEW AIAction(amp,amp->source);
clicks.push_back(action);
paid->add(amp->output);
}
else if(gmp)
else if(GenericActivatedAbility * gmp = dynamic_cast<GenericActivatedAbility*>(gotPayments[k]))
{
AIAction * action = NEW AIAction(gmp,gmp->source);
clicks.push_back(action);
AForeach * fmp = dynamic_cast<AForeach*>(gmp->ability);
if(fmp)
if(AForeach * fmp = dynamic_cast<AForeach*>(gmp->ability))
{
amp = dynamic_cast<AManaProducer*> (fmp->ability);
int outPut = fmp->checkActivation();
for(int k = 0;k < outPut;k++)
for(int k = 0; k < outPut; ++k)
paid->add(amp->output);
}
}
paid->add(this->getManaPool());//incase some of our payments were mana already in the pool/.
if(paid->canAfford(cost) && !cost->hasX())
if(paid->canAfford(cost) && (!cost->hasX() || k == gotPayments.size()))
{
SAFE_DELETE(paid);
for(int clicking = 0; clicking < int(clicks.size()); clicking++)
clickstream.push(clicks[clicking]);
return true;
}
if(cost->hasX() && k == int(gotPayments.size()) && paid->canAfford(cost))
{
SAFE_DELETE(paid);
for(int clicking = 0; clicking < int(clicks.size()); clicking++)
for(size_t clicking = 0; clicking < clicks.size(); ++clicking)
clickstream.push(clicks[clicking]);
return true;
}
//clean up temporary "clicks" structure if its content wasn't used above
for(size_t i = 0; i< clicks.size(); ++i)
SAFE_DELETE(clicks[i]);
clicks.clear();
}
SAFE_DELETE(paid);
return false;
}
// Didn't have a payment in mind if we reach this point
//pMana is our main payment form, it is far faster then direct search.
DebugTrace(" the Mana was already in the manapool or could be Paid with potential mana, using potential Mana now.");
DebugTrace("AIPlayerBaka: the Mana was already in the manapool or could be Paid with potential mana, using potential Mana now.");
ManaCost * pMana = getPotentialMana(target);
if (!pMana)
return false;
pMana->add(this->getManaPool());
if(!cost->getConvertedCost() && cost->hasX())
{
cost = pMana;//{x}:effect, set x to max.
}
if(!pMana->canAfford(cost))
{
delete pMana;
@@ -745,7 +748,7 @@ bool AIPlayerBaka::payTheManaCost(ManaCost * cost, MTGCardInstance * target,vect
GameObserver * g = GameObserver::GetInstance();
map<MTGCardInstance *, bool> used;
for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); i++)
for (size_t i = 1; i < g->mLayers->actionLayer()->mObjects.size(); ++i)
{ //0 is not a mtgability...hackish
//Make sure we can use the ability
MTGAbility * a = ((MTGAbility *) g->mLayers->actionLayer()->mObjects[i]);
@@ -1730,7 +1733,7 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * ty
void AIPlayerBaka::initTimer()
{
if (mFastTimerMode)
timer = 0;
timer = 0; //0 or 1 is as fast as possible and will generate bad side effects in the game engine (phases getting skipped...), use wisely
else
timer = 0.1f;
}
@@ -1745,9 +1748,9 @@ int AIPlayerBaka::computeActions()
the 2nd else is run about 90% of the time over the third, this was causing ai to miss the chance to chooseblockers()
when it could have blocked almost 90% of the time.*/
GameObserver * g = GameObserver::GetInstance();
Player * p = (Player*)this;
Player * p = this;
Player * currentP = g->currentlyActing();
if (!(g->currentlyActing() == p))
if (!(currentP == p))
return 0;
ActionLayer * object = g->mLayers->actionLayer();
if (object->menuObject)
@@ -1786,7 +1789,7 @@ int AIPlayerBaka::computeActions()
Player * lastStackActionController = NULL;
if(spell && spell->type == ACTION_SPELL)
lastStackActionController = spell->source->controller();
if ((interruptIfICan() || g->isInterrupting == this)
if (g->isInterrupting == this
&& this == currentP
//and i am the currentlyActivePlayer
&& ((lastStackActionController && lastStackActionController != this) || (g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)))
@@ -1834,7 +1837,7 @@ int AIPlayerBaka::computeActions()
findingCard = false;
return 1;
}
else if(p == this && g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)
else if(g->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)
{ //standard actions
switch (g->getCurrentGamePhase())
{