From 6902491797b889e03e13b6e34531052a54d44dbf Mon Sep 17 00:00:00 2001 From: Agetian Date: Tue, 10 Jan 2017 19:17:19 +0000 Subject: [PATCH] - Added AI for Living Death. Marked Living Death as RemRandomDeck instead of RemAIDeck. AILogic$ LivingDeath can probably be used for other similar cards too, possibly with some adaptation. --- .../src/main/java/forge/ai/SpecialCardAi.java | 45 +++++++++++++++++++ .../forge/ai/ability/ChangeZoneAllAi.java | 7 ++- forge-gui/res/cardsfolder/l/living_death.txt | 4 +- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index ec1ee0fb7a8..f17af411c68 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -38,6 +38,7 @@ import forge.game.player.Player; import forge.game.player.PlayerPredicates; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.item.IPaperCard; import java.util.Collections; import java.util.List; @@ -153,6 +154,50 @@ public class SpecialCardAi { } } + // Living Death (and possibly other similar cards using AILogic LivingDeath) + public static class LivingDeath { + public static boolean consider(Player ai, SpellAbility sa) { + int aiBattlefieldPower = 0, aiGraveyardPower = 0; + CardCollection aiCreaturesInGY = CardLists.filter(ai.getZone(ZoneType.Graveyard).getCards(), CardPredicates.Presets.CREATURES); + + if (aiCreaturesInGY.isEmpty()) { + // nothing in graveyard, so cut short + return false; + } + + for (Card c : ai.getCreaturesInPlay()) { + if (!SpellAbilityAi.isUselessCreature(ai, c)) { + aiBattlefieldPower += ComputerUtilCard.evaluateCreature(c); + } + } + for (Card c : aiCreaturesInGY) { + aiGraveyardPower += ComputerUtilCard.evaluateCreature(c); + } + + int oppBattlefieldPower = 0, oppGraveyardPower = 0; //TODO: not used yet (see below) + List opponents = ai.getOpponents(); // TODO: not used yet (see below) + for (Player p : opponents) { + int playerPower = 0; + int tempGraveyardPower = 0; + for (Card c : p.getCreaturesInPlay()) { + playerPower += ComputerUtilCard.evaluateCreature(c); + } + for (Card c : CardLists.filter(p.getZone(ZoneType.Graveyard).getCards(), CardPredicates.Presets.CREATURES)) { + tempGraveyardPower += ComputerUtilCard.evaluateCreature(c); + } + if (playerPower > oppBattlefieldPower) { + oppBattlefieldPower = playerPower; + } + if (tempGraveyardPower > oppGraveyardPower) { + oppGraveyardPower = tempGraveyardPower; + } + } + + // if we get more value out of this than our opponent does (hopefully), go for it + return (aiGraveyardPower - aiBattlefieldPower) > (oppGraveyardPower - oppBattlefieldPower); + } + } + // Necropotence public static class Necropotence { public static boolean consider(Player ai, SpellAbility sa) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAllAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAllAi.java index dd53638c91c..ee840877c29 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAllAi.java @@ -67,8 +67,13 @@ public class ChangeZoneAllAi extends SpellAbilityAi { CardCollectionView computerType = ai.getCardsIn(origin); computerType = AbilityUtils.filterListByType(computerType, sa.getParam("ChangeType"), sa); + // Living Death AI + if ("LivingDeath".equals(sa.getParam("AILogic"))) { + return SpecialCardAi.LivingDeath.consider(ai, sa); + } + // Timetwister AI - if (source.getName().equals("Timetwister")) { + if ("Timetwister".equals(sa.getParam("AILogic"))) { return SpecialCardAi.Timetwister.consider(ai, sa); } diff --git a/forge-gui/res/cardsfolder/l/living_death.txt b/forge-gui/res/cardsfolder/l/living_death.txt index a4c16fb1a8e..6155c23f15d 100644 --- a/forge-gui/res/cardsfolder/l/living_death.txt +++ b/forge-gui/res/cardsfolder/l/living_death.txt @@ -1,10 +1,10 @@ Name:Living Death ManaCost:3 B B Types:Sorcery -A:SP$ ChangeZoneAll | Cost$ 3 B B | ChangeType$ Creature | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | ForgetOtherRemembered$ True | SubAbility$ DBSacrifice | SpellDescription$ Each player exiles all creature cards from his or her graveyard, then sacrifices all creatures he or she controls, then puts all cards he or she exiled this way onto the battlefield. +A:SP$ ChangeZoneAll | Cost$ 3 B B | ChangeType$ Creature | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | ForgetOtherRemembered$ True | SubAbility$ DBSacrifice | AILogic$ LivingDeath | SpellDescription$ Each player exiles all creature cards from his or her graveyard, then sacrifices all creatures he or she controls, then puts all cards he or she exiled this way onto the battlefield. SVar:DBSacrifice:DB$SacrificeAll | ValidCards$ Creature | SubAbility$ DBReturn SVar:DBReturn:DB$ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True -SVar:RemAIDeck:True +SVar:RemRandomDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/living_death.jpg Oracle:Each player exiles all creature cards from his or her graveyard, then sacrifices all creatures he or she controls, then puts all cards he or she exiled this way onto the battlefield.