Merged changes from trunk to GuiRefactoring: 27266-27293; plus some minor fixes.

This commit is contained in:
elcnesh
2014-09-12 11:07:11 +00:00
parent 1ba2cb498b
commit c3e9ff7e5b
25 changed files with 487 additions and 31 deletions

View File

@@ -51,7 +51,7 @@ public class AiCardMemory {
*/
public enum MemorySet {
MANDATORY_ATTACKERS,
HELD_MANA_SOURCES, // stub, not linked to AI code yet
HELD_MANA_SOURCES,
//REVEALED_CARDS // stub, not linked to AI code yet
}

View File

@@ -68,6 +68,7 @@ import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.Ability;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilityStatic;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.Spell;
@@ -740,6 +741,7 @@ public class AiController {
&& !ComputerUtil.castPermanentInMain1(player, sa)) {
return AiPlayDecision.WaitForMain2;
}
// save cards with flash for surprise blocking
if (card.hasKeyword("Flash")
&& (player.isUnlimitedHandSize() || player.getCardsIn(ZoneType.Hand).size() <= player.getMaxHandSize())
@@ -750,6 +752,20 @@ public class AiController {
&& !ComputerUtil.castPermanentInMain1(player, sa)) {
return AiPlayDecision.AnotherTime;
}
// don't play cards without being able to pay the upkeep for
for (String ability : card.getKeyword()) {
if (ability.startsWith("At the beginning of your upkeep, sacrifice CARDNAME unless you pay")) {
final String[] k = ability.split(" pay ");
final String costs = k[1].replaceAll("[{]", "").replaceAll("[}]", " ");
Cost cost = new Cost(costs, true);
final Ability emptyAbility = new AbilityStatic(card, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } };
emptyAbility.setActivatingPlayer(player);
if (!ComputerUtilCost.canPayCost(emptyAbility, player)) {
return AiPlayDecision.AnotherTime;
}
}
}
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
} else if( sa instanceof Spell ) {
@@ -759,7 +775,7 @@ public class AiController {
}
private AiPlayDecision canPlaySpellBasic(final Card card) {
if (card.getSVar("NeedsToPlay").length() > 0) {
if (card.hasSVar("NeedsToPlay")) {
final String needsToPlay = card.getSVar("NeedsToPlay");
List<Card> list = game.getCardsIn(ZoneType.Battlefield);

View File

@@ -29,7 +29,8 @@ public enum AiProps { /** */
DEFAULT_PLANAR_DIE_ROLL_CHANCE ("50"), /** */
MULLIGAN_THRESHOLD ("5"), /** */
PLANAR_DIE_ROLL_HESITATION_CHANCE ("10"),
CHEAT_WITH_MANA_ON_SHUFFLE ("FALSE"); /** */
CHEAT_WITH_MANA_ON_SHUFFLE ("false"),
MOVE_EQUIPMENT_TO_BETTER_CREATURES ("always"); /** */
private final String strDefaultVal;

View File

@@ -985,8 +985,8 @@ public class AttachAi extends SpellAbilityAi {
// TODO AttachSource is currently set for the Source of the Spell, but
// at some point can support attaching a different card
// Don't equip if already equipping
if (attachSource.getEquippingCard() != null && attachSource.getEquippingCard().getController() == aiPlayer || attachSource.hasSVar("DontEquip")) {
// Don't equip if DontEquip SVar is set
if (attachSource.hasSVar("DontEquip")) {
return null;
}
// Don't fortify if already fortifying
@@ -1017,6 +1017,35 @@ public class AttachAi extends SpellAbilityAi {
Card c = attachGeneralAI(aiPlayer, sa, prefList, mandatory, attachSource, sa.getParam("AILogic"));
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi();
if (c != null && attachSource.getType().contains("Equipment")
&& attachSource.getEquippingCard() != null
&& attachSource.getEquippingCard().getController() == aiPlayer) {
if (c.equals(attachSource.getEquippingCard())) {
// Do not equip if equipping the same card already
return null;
}
if (aic.getProperty(AiProps.MOVE_EQUIPMENT_TO_BETTER_CREATURES).equals("never")) {
// Do not equip other creatures if the AI profile does not allow moving equipment around
return null;
} else if (aic.getProperty(AiProps.MOVE_EQUIPMENT_TO_BETTER_CREATURES).equals("from_useless_only")) {
// Do not equip other creatures if the AI profile only allows moving equipment from useless creatures
// and the equipped creature is still useful (not non-untapping+tapped and not set to can't attack/block)
if (!isUselessCreature(aiPlayer, attachSource.getEquippingCard())) {
return null;
}
}
// make sure to prioritize casting spells in main 2 (creatures, other equipment, etc.) rather than moving equipment around
if (aic.getCardMemory().isMemorySetEmpty(AiCardMemory.MemorySet.HELD_MANA_SOURCES)) {
SpellAbility futureSpell = aic.predictSpellToCastInMain2(ApiType.Attach);
if (futureSpell != null && futureSpell.getHostCard() != null) {
aic.reserveManaSourcesForMain2(futureSpell);
}
}
}
if ((c == null) && mandatory) {
CardLists.shuffle(list);
c = list.get(0);
@@ -1086,7 +1115,7 @@ public class AttachAi extends SpellAbilityAi {
}
// Consider exceptional cases which break the normal evaluation rules
if (!isUsefulAttachAction(c, sa)) {
if (!isUsefulAttachAction(ai, c, sa)) {
return null;
}
@@ -1279,7 +1308,7 @@ public class AttachAi extends SpellAbilityAi {
* @param sa SpellAbility
* @return true, if the action is useful (beneficial) in the current minimal context (Card vs. Attach SpellAbility)
*/
private static boolean isUsefulAttachAction(Card c, SpellAbility sa) {
private static boolean isUsefulAttachAction(Player ai, Card c, SpellAbility sa) {
if (c == null) {
return false;
}
@@ -1292,17 +1321,28 @@ public class AttachAi extends SpellAbilityAi {
ArrayList<String> cardTypes = sa.getHostCard().getType();
if (cardTypes.contains("Equipment") && c.hasKeyword("CARDNAME can't attack or block.")) {
if (cardTypes.contains("Equipment") && isUselessCreature(ai, c)) {
// useless to equip a creature that can't attack or block.
return false;
} else if (cardTypes.contains("Equipment") && c.isTapped() && c.hasKeyword("CARDNAME doesn't untap during your untap step.")) {
// useless to equip a creature that won't untap and is tapped.
return false;
}
return true;
}
private static boolean isUselessCreature(Player ai, Card c) {
if (c == null) {
return true;
}
if (c.hasKeyword("CARDNAME can't attack or block.")
|| (c.hasKeyword("CARDNAME doesn't untap during your untap step.") && c.isTapped())
|| (c.getOwner() == ai && ai.getOpponents().contains(c.getController()))) {
return true;
}
return false;
}
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true;