- Updated Parser mechanism. Right now this doesn't change functionalities much, but should be more readable, and make it easier to code some new abilities in the future
- Fixed regenerate, broken with r532
- Death Ward now works
- I think "&&" now works with all abilities, needs to be tested...
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-07-11 15:59:51 +00:00
parent 307c41c563
commit c8333e76b1
34 changed files with 2157 additions and 1816 deletions
+6 -83
View File
@@ -15,13 +15,13 @@ AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * _deck, char * file, char * fileSma
}
int AIMomirPlayer::getEfficiency(AIAction * action){
MTGAbility * ability = action->ability;
if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet
int efficiency = AIPlayerBaka::getEfficiency(action);
int efficiency = AIPlayerBaka::getEfficiency(action);
GameObserver * g = GameObserver::GetInstance();
if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0;
return efficiency;
GameObserver * g = GameObserver::GetInstance();
if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0;
return efficiency;
}
MTGAbility * AIMomirPlayer::getMomirAbility(){
@@ -113,81 +113,4 @@ the general rule is this: if you want to get to Eight, you have to skip two drop
return AIPlayerBaka::computeActions();
}
/*
int AIPlayerBaka::computeActions(){
GameObserver * g = GameObserver::GetInstance();
Player * p = g->currentPlayer;
if (!(g->currentlyActing() == this)) return 0;
if (chooseTarget()) return 1;
int currentGamePhase = g->getCurrentGamePhase();
if (g->isInterrupting == this){ // interrupting
selectAbility();
return 1;
}else if (p == this && g->mLayers->stackLayer()->count(0,NOT_RESOLVED) == 0){ //standard actions
CardDescriptor cd;
MTGCardInstance * card = NULL;
switch(currentGamePhase){
case Constants::MTG_PHASE_FIRSTMAIN:
case Constants::MTG_PHASE_SECONDMAIN:
if (canPutLandsIntoPlay){
//Attempt to put land into play
cd.init();
cd.setColor(Constants::MTG_COLOR_LAND);
card = cd.match(game->hand);
if (card){
AIAction * a = NEW AIAction(card);
clickstream.push(a);
return 1;
}
}
//No mana, try to get some
getPotentialMana();
if (potentialMana->getConvertedCost() > 0){
//look for the most expensive creature we can afford
nextCardToPlay = FindCardToPlay(potentialMana, "creature");
//Let's Try an enchantment maybe ?
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery");
if (nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
char buffe[4096];
sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName());
OutputDebugString(buffe);
#endif
tapLandsForMana(potentialMana,nextCardToPlay->getManaCost());
AIAction * a = NEW AIAction(nextCardToPlay);
clickstream.push(a);
return 1;
}else{
selectAbility();
}
}else{
selectAbility();
}
break;
case Constants::MTG_PHASE_COMBATATTACKERS:
chooseAttackers();
break;
default:
selectAbility();
break;
}
}else{
switch(currentGamePhase){
case Constants::MTG_PHASE_COMBATBLOCKERS:
chooseBlockers();
break;
default:
break;
}
return 1;
}
return 1;
};
*/
+22 -142
View File
@@ -135,17 +135,29 @@ int AIAction::getEfficiency(){
ActionStack * s = g->mLayers->stackLayer();
Player * p = g->currentlyActing();
if (s->has(ability)) return 0;
if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet
switch (ability->aType){
MTGAbility * a = ability;
GenericTargetAbility * gta = dynamic_cast<GenericTargetAbility*>(a);
if (gta) a = gta->ability;
GenericActivatedAbility * gaa = dynamic_cast<GenericActivatedAbility*>(a);
if (gaa) a = gaa->ability;
if (!a){
OutputDebugString("FATAL: Ability is NULL in AIAction::getEfficiency()");
return 0;
}
switch (a->aType){
case MTGAbility::DAMAGER:
{
ADamager * a = (ADamager *) ability;
AADamager * aad = (AADamager *) a;
if ( p == target->controller()){
efficiency = 0;
}else if (a->damage >= target->toughness){
}else if (aad->damage >= target->toughness){
efficiency = 100;
}else if (target->toughness){
efficiency = (100 * a->damage) / target->toughness;
efficiency = (50 * aad->damage) / target->toughness;
}else{
efficiency = 0;
}
@@ -153,22 +165,12 @@ int AIAction::getEfficiency(){
}
case MTGAbility::STANDARD_REGENERATE:
{
MTGCardInstance * _target = (MTGCardInstance *)(ability->target);
PutInGraveyard * action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED));
int i = 0;
while(action){
i++;
if (action->card == _target){
efficiency = 95;
action = NULL;
}else{
action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED));
}
MTGCardInstance * _target = (MTGCardInstance *)(a->target);
efficiency = 0;
if (!_target->regenerateTokens && g->getCurrentGamePhase()< Constants::MTG_PHASE_COMBATDAMAGE && (_target->defenser || _target->blockers.size())){
efficiency = 95;
}
char buf[4096];
sprintf(buf,"Graveyard : %i\n", i);
OutputDebugString(buf);
if (efficiency == -1) efficiency = 0;
//TODO If the card is the target of a damage spell
break;
}
case MTGAbility::MANA_PRODUCER: //can't use mana producers right now :/
@@ -741,125 +743,3 @@ int AIPlayerBaka::Act(float dt){
return 1;
};
/*
int AIPlayerBaka::Act(float dt){
GameObserver * gameObs = GameObserver::GetInstance();
int currentGamePhase = gameObs->getCurrentGamePhase();
if (currentGamePhase == Constants::MTG_PHASE_CLEANUP && currentGamePhase != oldGamePhase){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("updating stats\n");
#endif
if (getStats()) getStats()->updateStats();
}
oldGamePhase = currentGamePhase;
//if (checkInterrupt()) return 0;
timer-= dt;
if (AManaProducer::currentlyTapping || timer>0){
return 0;
}
initTimer();
checkInterrupt();
if (currentAbility) return (useAbility());
if (combatDamages()) return 0;
if (chooseTarget()) return 0;
Player * currentPlayer = gameObs->currentPlayer;
CardDescriptor cd;
if (currentPlayer == this){
MTGCardInstance * card = NULL;
switch(currentGamePhase){
case Constants::MTG_PHASE_FIRSTMAIN:
case Constants::MTG_PHASE_SECONDMAIN:
if (canPutLandsIntoPlay){
//Attempt to put land into play
cd.init();
cd.setColor(Constants::MTG_COLOR_LAND);
card = cd.match(game->hand);
if (card){
gameObs->cardClick(card);
}
}
if(NULL == card){
//Attempt to put creature into play
if (manaPool->getConvertedCost()==0){
//No mana, try to get some
getPotentialMana();
if (potentialMana->getConvertedCost() > 0){
//look for the most expensive creature we can afford
nextCardToPlay = FindCardToPlay(potentialMana, "creature");
//Let's Try an enchantment maybe ?
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant");
if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery");
if (nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
char buffe[4096];
sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName());
OutputDebugString(buffe);
#endif
tapLandsForMana(potentialMana,nextCardToPlay->getManaCost());
}
}
SAFE_DELETE(potentialMana);
}else{
//We have mana, we can try to put the card into play
#if defined (WIN32) || defined (LINUX)
OutputDebugString("Mana paid, ready to put card into play\n");
#endif
if (nextCardToPlay){
gameObs->cardClick(nextCardToPlay);
nextCardToPlay = NULL;
}else{
//ERROR, WE PAID MANA WITHOUT ANY WILL TO PLAY
}
}
}
if (NULL == card && NULL == nextCardToPlay){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("Switching to next phase\n");
#endif
gameObs->userRequestNextGamePhase();
}
break;
case Constants::MTG_PHASE_COMBATATTACKERS:
chooseAttackers();
gameObs->userRequestNextGamePhase();
break;
default:
gameObs->userRequestNextGamePhase();
break;
}
}else{
switch(currentGamePhase){
case Constants::MTG_PHASE_COMBATBLOCKERS:
chooseBlockers();
gameObs->userRequestNextGamePhase();
break;
default:
break;
}
return 1;
}
return 1;
}
*/
+4 -1
View File
@@ -10,10 +10,13 @@ ActionElement::ActionElement(int id):JGuiObject(id){
currentPhase = -1;
newPhase = -1;
tc = NULL;
isClone = 0;
}
ActionElement::~ActionElement(){
SAFE_DELETE(tc);
if (!isClone){
SAFE_DELETE(tc);
}
}
int ActionElement::getActivity(){
+1 -2
View File
@@ -71,8 +71,7 @@ void ActionLayer::Update(float dt){
if (mObjects[i]!= NULL){
ActionElement * currentAction = (ActionElement *)mObjects[i];
if (currentAction->testDestroy()){
currentAction->destroy();
Remove(currentAction);
game->removeObserver(currentAction);
}
}
}
+6
View File
@@ -24,6 +24,12 @@ void UntapBlocker::init(ManaCost * _cost){
manaCost = _cost;
}
UntapBlocker * UntapBlocker::clone() const{
UntapBlocker * a = NEW UntapBlocker(*this);
a->isClone = 1;
return a;
}
//Default behaviour for blockers : they block the card they're attached to
void UntapBlocker::Update(float dt){
+5 -4
View File
@@ -152,7 +152,6 @@ int GameObserver::cancelCurrentAction(){
}
void GameObserver::userRequestNextGamePhase(){
OutputDebugString("requesting Next Phase\n");
if (mLayers->stackLayer()->getNext(NULL,0,NOT_RESOLVED)) return;
if (getCurrentTargetChooser()) return;
if (mLayers->combatLayer()->isDisplayed()) return;
@@ -164,7 +163,6 @@ void GameObserver::userRequestNextGamePhase(){
return;
}
}
OutputDebugString("Next Phase Accepted\n");
if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS ||
opponent()->isAI() ||
GameOptions::GetInstance()->values[GameOptions::phaseInterrupts[currentGamePhase]].getIntValue()){
@@ -241,11 +239,14 @@ void GameObserver::addObserver(MTGAbility * observer){
void GameObserver::removeObserver(ActionElement * observer){
if (observer){
observer->destroy();
if (mLayers->actionLayer()->getIndexOf(observer) != -1){
observer->destroy();
mLayers->actionLayer()->Remove(observer);
}
}else{
//TODO log error
}
mLayers->actionLayer()->Remove(observer);
}
GameObserver::~GameObserver(){
+3 -2
View File
@@ -21,7 +21,7 @@ void GuiLayer::Add(JGuiObject *object){
mCount++;
}
void GuiLayer::Remove(JGuiObject *object){
int GuiLayer::Remove(JGuiObject *object){
for (int i=0;i<mCount;i++){
if (mObjects[i]==object){
delete mObjects[i];
@@ -29,9 +29,10 @@ void GuiLayer::Remove(JGuiObject *object){
mCount--;
if (mCurr == mCount)
mCurr = 0;
return;
return 1;
}
}
return 0;
}
int GuiLayer::getMaxId(){
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -135,7 +135,7 @@ int MTGCardInstance::afterDamage(){
if (!doDamageTest) return 0;
doDamageTest = 0;
if (!isACreature()) return 0;
if (life <=0 && isInPlay() && !basicAbilities[Constants::INDESTRUCTIBLE]){
if (life <=0 && isInPlay()){
return destroy();
}
return 0;
@@ -145,11 +145,12 @@ int MTGCardInstance::bury(){
Player * p = controller();
if (!basicAbilities[Constants::INDESTRUCTIBLE]){
p->game->putInZone(this,p->game->inPlay,owner->game->graveyard);
return 1;
}
return 1;
return 0;
}
int MTGCardInstance::destroy(){
if (!triggerRegenerate() || !basicAbilities[Constants::INDESTRUCTIBLE]) return bury();
if (!triggerRegenerate()) return bury();
return 0;
}
+6
View File
@@ -54,6 +54,12 @@ bool MTGGamePhase::CheckUserInput(u32 key){
return false;
}
MTGGamePhase * MTGGamePhase::clone() const{
MTGGamePhase * a = NEW MTGGamePhase(*this);
a->isClone = 1;
return a;
}
ostream& MTGGamePhase::toString(ostream& out) const
{
return out << "MTGGamePhase ::: animation " << animation << " ; currentState : " << currentState;
+146 -2
View File
@@ -84,6 +84,12 @@ ostream& MTGPutInPlayRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGPutInPlayRule * MTGPutInPlayRule::clone() const{
MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this);
a->isClone = 1;
return a;
}
MTGAttackRule::MTGAttackRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_ATTACK_RULE;
@@ -126,6 +132,13 @@ ostream& MTGAttackRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGAttackRule * MTGAttackRule::clone() const{
MTGAttackRule * a = NEW MTGAttackRule(*this);
a->isClone = 1;
return a;
}
MTGBlockRule::MTGBlockRule(int _id):MTGAbility(_id,NULL){
aType=MTGAbility::MTG_BLOCK_RULE;
}
@@ -167,7 +180,11 @@ ostream& MTGBlockRule::toString(ostream& out) const
return MTGAbility::toString(out) << ")";
}
MTGBlockRule * MTGBlockRule::clone() const{
MTGBlockRule * a = NEW MTGBlockRule(*this);
a->isClone = 1;
return a;
}
//
// Attacker chooses blockers order
//
@@ -295,6 +312,12 @@ ostream& MTGMomirRule::toString(ostream& out) const
}
MTGMomirRule * MTGMomirRule::clone() const{
MTGMomirRule * a = NEW MTGMomirRule(*this);
a->isClone = 1;
return a;
}
//HUDDisplay
int HUDDisplay::testDestroy(){
return 0;
@@ -383,4 +406,125 @@ HUDDisplay::~HUDDisplay(){
delete hs;
}
events.clear();
}
}
HUDDisplay * HUDDisplay::clone() const{
HUDDisplay * a = NEW HUDDisplay(*this);
a->isClone = 1;
return a;
}
/* Persist */
MTGPersistRule::MTGPersistRule(int _id):MTGAbility(_id,NULL){};
int MTGPersistRule::receiveEvent(WEvent * event){
if (event->type == WEvent::CHANGE_ZONE){
WEventZoneChange * e = (WEventZoneChange *) event;
MTGCardInstance * card = e->card->previous;
if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){
int ok = 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->from == p->game->inPlay) ok = 1;
}
if (!ok) return 0;
for (int i = 0; i < 2 ; i++){
Player * p = game->players[i];
if (e->to == p->game->graveyard){
//p->game->putInZone(card, p->game->graveyard, card->owner->game->hand);
MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack);
Spell * spell = NEW Spell(copy);
spell->resolve();
spell->source->counters->addCounter(-1,-1);
game->mLayers->playLayer()->forceUpdateCards();
delete spell;
return 1;
}
}
}
}
return 0;
}
ostream& MTGPersistRule::toString(ostream& out) const
{
out << "MTGPersistRule ::: (";
return MTGAbility::toString(out) << ")";
}
int MTGPersistRule::testDestroy(){return 0;}
MTGPersistRule * MTGPersistRule::clone() const{
MTGPersistRule * a = NEW MTGPersistRule(*this);
a->isClone = 1;
return a;
}
/* Legend Rule */
MTGLegendRule::MTGLegendRule(int _id):ListMaintainerAbility(_id){};
int MTGLegendRule::canBeInList(MTGCardInstance * card){
if (card->basicAbilities[Constants::LEGENDARY] && game->isInPlay(card)){
return 1;
}
return 0;
}
int MTGLegendRule::added(MTGCardInstance * card){
map<MTGCardInstance *,bool>::iterator it;
int destroy = 0;
for ( it=cards.begin() ; it != cards.end(); it++ ){
MTGCardInstance * comparison = (*it).first;
if (comparison!= card && !strcmp(comparison->getName(), card->getName())){
comparison->owner->game->putInGraveyard(comparison);
destroy = 1;
}
}
if (destroy){
card->owner->game->putInGraveyard(card);
}
return 1;
}
int MTGLegendRule::removed(MTGCardInstance * card){return 0;}
int MTGLegendRule::testDestroy(){return 0;}
ostream& MTGLegendRule::toString(ostream& out) const
{
return out << "MTGLegendRule :::";
}
MTGLegendRule * MTGLegendRule::clone() const{
MTGLegendRule * a = NEW MTGLegendRule(*this);
a->isClone = 1;
return a;
}
/* Lifelink */
MTGLifelinkRule::MTGLifelinkRule(int _id):MTGAbility(_id,NULL){};
int MTGLifelinkRule::receiveEvent(WEvent * event){
if (event->type == WEvent::DAMAGE){
WEventDamage * e = (WEventDamage *) event;
Damage * d = e->damage;
MTGCardInstance * card = d->source;
if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){
card->controller()->life+= d->damage;
return 1;
}
}
return 0;
}
int MTGLifelinkRule::testDestroy(){return 0;}
ostream& MTGLifelinkRule::toString(ostream& out) const
{
out << "MTGLifelinkRule ::: (";
return MTGAbility::toString(out) << ")";
}
MTGLifelinkRule * MTGLifelinkRule::clone() const{
MTGLifelinkRule * a = NEW MTGLifelinkRule(*this);
a->isClone = 1;
return a;
}
-3
View File
@@ -282,9 +282,6 @@ int ManaCost::canAfford(ManaCost * _cost){
int positive = diff->isPositive();
delete diff;
if (positive){
#if defined (WIN32) || defined (LINUX)
OutputDebugString("can afford\n");
#endif
return 1;
}
return 0;
+2 -2
View File
@@ -58,11 +58,11 @@ int TargetsList::toggleTarget(Targetable * target){
}
Targetable * TargetsList::getNextTarget(Targetable * previous, int type){
Targetable * TargetsList::getNextTarget(Targetable * previous , int type){
int found = 0;
if (!previous) found = 1;
for (int i = 0; i < cursor; i++){
if (found && targets[i]->typeAsTarget() == type){
if (found && (type == -1 || targets[i]->typeAsTarget() == type)){
return (targets[i]);
}
if (targets[i] == previous) found = 1;
+5
View File
@@ -119,6 +119,11 @@ int TestSuiteAI::Act(float dt){
MTGMomirRule * a = ((MTGMomirRule *)g->mLayers->actionLayer()->getAbility(MTGAbility::MOMIR));
a->reactToClick(suite->getCardByMTGId(cardIdHand), cardId);
g->mLayers->actionLayer()->stuffHappened = 1;
}else if(action.find("p1")!=string::npos || action.find("p2")!=string::npos){
Player * p = g->players[1];
int start = action.find("p1");
if (start != string::npos) p = g->players[0];
g->cardClick(NULL, p);
}else{
int mtgid = suite->getMTGId(action);
if (mtgid){