mirror of
https://github.com/Relintai/mtg-forge-ios.git
synced 2024-11-14 04:17:19 +01:00
- Some refactoring in AiBlockController related to random trades.
- Enabling random trades for favorable gang double and triple blocks. git-svn-id: http://svn.slightlymagic.net/forge/trunk@35778 269b9781-a132-4a9b-9d4e-f004f1b56b58
This commit is contained in:
parent
ad6c9ea55e
commit
258c46868a
@ -415,7 +415,8 @@ public class AiBlockController {
|
|||||||
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
|
&& !ComputerUtilCombat.dealsFirstStrikeDamage(c, false, combat)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return lifeInDanger || ComputerUtilCard.evaluateCreature(c) + diff < ComputerUtilCard.evaluateCreature(attacker);
|
final boolean randomTrade = wouldLikeToRandomlyTrade(attacker, c, combat);
|
||||||
|
return lifeInDanger || ComputerUtilCard.evaluateCreature(c) + diff < ComputerUtilCard.evaluateCreature(attacker) || randomTrade;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (usableBlockers.size() < 2) {
|
if (usableBlockers.size() < 2) {
|
||||||
@ -586,39 +587,6 @@ public class AiBlockController {
|
|||||||
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
List<Card> currentAttackers = new ArrayList<>(attackersLeft);
|
||||||
List<Card> killingBlockers;
|
List<Card> killingBlockers;
|
||||||
|
|
||||||
// Parameters related to randomly trading when blocking (need to be enabled in the AI profile)
|
|
||||||
boolean enableRandomTrades = false;
|
|
||||||
boolean randomTradeIfBehindOnBoard = false;
|
|
||||||
boolean randomTradeIfCreatInHand = false;
|
|
||||||
int chanceToTradeToSaveWalker = 0;
|
|
||||||
int chanceToTradeDownToSaveWalker = 0;
|
|
||||||
int minRandomTradeChance = 0;
|
|
||||||
int maxRandomTradeChance = 0;
|
|
||||||
int maxCreatDiff = 0;
|
|
||||||
int maxCreatDiffWithRepl = 0;
|
|
||||||
int aiCreatureCount = 0;
|
|
||||||
int oppCreatureCount = 0;
|
|
||||||
if (ai.getController().isAI()) {
|
|
||||||
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
|
||||||
enableRandomTrades = aic.getBooleanProperty(AiProps.ENABLE_RANDOM_FAVORABLE_TRADES_ON_BLOCK);
|
|
||||||
randomTradeIfBehindOnBoard = aic.getBooleanProperty(AiProps.RANDOMLY_TRADE_EVEN_WHEN_HAVE_LESS_CREATS);
|
|
||||||
randomTradeIfCreatInHand = aic.getBooleanProperty(AiProps.ALSO_TRADE_WHEN_HAVE_A_REPLACEMENT_CREAT);
|
|
||||||
minRandomTradeChance = aic.getIntProperty(AiProps.MIN_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK);
|
|
||||||
maxRandomTradeChance = aic.getIntProperty(AiProps.MAX_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK);
|
|
||||||
maxCreatDiff = aic.getIntProperty(AiProps.MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE);
|
|
||||||
maxCreatDiffWithRepl = aic.getIntProperty(AiProps.MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE_WITH_REPL);
|
|
||||||
chanceToTradeToSaveWalker = aic.getIntProperty(AiProps.CHANCE_TO_TRADE_TO_SAVE_PLANESWALKER);
|
|
||||||
chanceToTradeDownToSaveWalker = aic.getIntProperty(AiProps.CHANCE_TO_TRADE_DOWN_TO_SAVE_PLANESWALKER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableRandomTrades) {
|
|
||||||
aiCreatureCount = ComputerUtil.countUsefulCreatures(ai);
|
|
||||||
|
|
||||||
if (!attackersLeft.isEmpty()) {
|
|
||||||
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Card attacker : attackersLeft) {
|
for (final Card attacker : attackersLeft) {
|
||||||
|
|
||||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")
|
||||||
@ -640,47 +608,9 @@ public class AiBlockController {
|
|||||||
if (ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
if (ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||||
// Always trade when life in danger
|
// Always trade when life in danger
|
||||||
doTrade = true;
|
doTrade = true;
|
||||||
} else if (enableRandomTrades) {
|
} else {
|
||||||
// Randomly trade creatures with lower power and [hopefully] worse abilities, if enabled in profile
|
// Randomly trade creatures with lower power and [hopefully] worse abilities, if enabled in profile
|
||||||
|
doTrade = wouldLikeToRandomlyTrade(attacker, blocker, combat);
|
||||||
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
|
|
||||||
// Temporarily controlled object - don't trade with it
|
|
||||||
// TODO: find a more reliable way to figure out that control will be reestablished next turn
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numSteps = ai.getStartingLife() - 5; // e.g. 15 steps between 5 life and 20 life
|
|
||||||
float chanceStep = (maxRandomTradeChance - minRandomTradeChance) / numSteps;
|
|
||||||
int chance = (int)Math.max(minRandomTradeChance, (maxRandomTradeChance - (Math.max(5, ai.getLife() - 5)) * chanceStep));
|
|
||||||
if (chance > maxRandomTradeChance) {
|
|
||||||
chance = maxRandomTradeChance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int evalAtk = ComputerUtilCard.evaluateCreature(attacker, false, false);
|
|
||||||
int evalBlk = ComputerUtilCard.evaluateCreature(blocker, false, false);
|
|
||||||
if (blocker.isFaceDown() && blocker.getState(CardStateName.Original).getType().isCreature()) {
|
|
||||||
// if the blocker is a face-down creature (e.g. cast via Morph, Manifest), evaluate it
|
|
||||||
// in relation to the original state, not to the Morph state
|
|
||||||
evalBlk = ComputerUtilCard.evaluateCreature(Card.fromPaperCard(blocker.getPaperCard(), ai), false, true);
|
|
||||||
}
|
|
||||||
int chanceToSavePW = chanceToTradeDownToSaveWalker > 0 && evalAtk + 1 < evalBlk ? chanceToTradeDownToSaveWalker : chanceToTradeToSaveWalker;
|
|
||||||
boolean powerParityOrHigher = blocker.getNetPower() <= attacker.getNetPower();
|
|
||||||
boolean creatureParityOrAllowedDiff = aiCreatureCount
|
|
||||||
+ (randomTradeIfBehindOnBoard ? maxCreatDiff : 0) >= oppCreatureCount;
|
|
||||||
boolean wantToTradeWithCreatInHand = randomTradeIfCreatInHand
|
|
||||||
&& !CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.CREATURES).isEmpty()
|
|
||||||
&& aiCreatureCount + maxCreatDiffWithRepl >= oppCreatureCount;
|
|
||||||
boolean wantToSavePlaneswalker = MyRandom.percentTrue(chanceToSavePW)
|
|
||||||
&& combat.getDefenderByAttacker(attacker) instanceof Card
|
|
||||||
&& ((Card) combat.getDefenderByAttacker(attacker)).isPlaneswalker();
|
|
||||||
boolean wantToTradeDownToSavePW = chanceToTradeDownToSaveWalker > 0;
|
|
||||||
|
|
||||||
if (((evalBlk <= evalAtk + 1) || (wantToSavePlaneswalker && wantToTradeDownToSavePW)) // "1" accounts for tapped.
|
|
||||||
&& powerParityOrHigher
|
|
||||||
&& (creatureParityOrAllowedDiff || wantToTradeWithCreatInHand)
|
|
||||||
&& (MyRandom.percentTrue(chance) || wantToSavePlaneswalker)) {
|
|
||||||
doTrade = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doTrade) {
|
if (doTrade) {
|
||||||
@ -1297,4 +1227,81 @@ public class AiBlockController {
|
|||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean wouldLikeToRandomlyTrade(Card attacker, Card blocker, Combat combat) {
|
||||||
|
// Determines if the AI would like to randomly trade its blocker for the attacker in given combat
|
||||||
|
boolean enableRandomTrades = false;
|
||||||
|
boolean randomTradeIfBehindOnBoard = false;
|
||||||
|
boolean randomTradeIfCreatInHand = false;
|
||||||
|
int chanceToTradeToSaveWalker = 0;
|
||||||
|
int chanceToTradeDownToSaveWalker = 0;
|
||||||
|
int minRandomTradeChance = 0;
|
||||||
|
int maxRandomTradeChance = 0;
|
||||||
|
int maxCreatDiff = 0;
|
||||||
|
int maxCreatDiffWithRepl = 0;
|
||||||
|
int aiCreatureCount = 0;
|
||||||
|
int oppCreatureCount = 0;
|
||||||
|
if (ai.getController().isAI()) {
|
||||||
|
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
||||||
|
enableRandomTrades = aic.getBooleanProperty(AiProps.ENABLE_RANDOM_FAVORABLE_TRADES_ON_BLOCK);
|
||||||
|
randomTradeIfBehindOnBoard = aic.getBooleanProperty(AiProps.RANDOMLY_TRADE_EVEN_WHEN_HAVE_LESS_CREATS);
|
||||||
|
randomTradeIfCreatInHand = aic.getBooleanProperty(AiProps.ALSO_TRADE_WHEN_HAVE_A_REPLACEMENT_CREAT);
|
||||||
|
minRandomTradeChance = aic.getIntProperty(AiProps.MIN_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK);
|
||||||
|
maxRandomTradeChance = aic.getIntProperty(AiProps.MAX_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK);
|
||||||
|
maxCreatDiff = aic.getIntProperty(AiProps.MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE);
|
||||||
|
maxCreatDiffWithRepl = aic.getIntProperty(AiProps.MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE_WITH_REPL);
|
||||||
|
chanceToTradeToSaveWalker = aic.getIntProperty(AiProps.CHANCE_TO_TRADE_TO_SAVE_PLANESWALKER);
|
||||||
|
chanceToTradeDownToSaveWalker = aic.getIntProperty(AiProps.CHANCE_TO_TRADE_DOWN_TO_SAVE_PLANESWALKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enableRandomTrades) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aiCreatureCount = ComputerUtil.countUsefulCreatures(ai);
|
||||||
|
|
||||||
|
if (!attackersLeft.isEmpty()) {
|
||||||
|
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
|
||||||
|
// Temporarily controlled object - don't trade with it
|
||||||
|
// TODO: find a more reliable way to figure out that control will be reestablished next turn
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numSteps = ai.getStartingLife() - 5; // e.g. 15 steps between 5 life and 20 life
|
||||||
|
float chanceStep = (maxRandomTradeChance - minRandomTradeChance) / numSteps;
|
||||||
|
int chance = (int)Math.max(minRandomTradeChance, (maxRandomTradeChance - (Math.max(5, ai.getLife() - 5)) * chanceStep));
|
||||||
|
if (chance > maxRandomTradeChance) {
|
||||||
|
chance = maxRandomTradeChance;
|
||||||
|
}
|
||||||
|
|
||||||
|
int evalAtk = ComputerUtilCard.evaluateCreature(attacker, true, false);
|
||||||
|
int evalBlk = ComputerUtilCard.evaluateCreature(blocker, true, false);
|
||||||
|
if (blocker.isFaceDown() && blocker.getState(CardStateName.Original).getType().isCreature()) {
|
||||||
|
// if the blocker is a face-down creature (e.g. cast via Morph, Manifest), evaluate it
|
||||||
|
// in relation to the original state, not to the Morph state
|
||||||
|
evalBlk = ComputerUtilCard.evaluateCreature(Card.fromPaperCard(blocker.getPaperCard(), ai), false, true);
|
||||||
|
}
|
||||||
|
int chanceToSavePW = chanceToTradeDownToSaveWalker > 0 && evalAtk + 1 < evalBlk ? chanceToTradeDownToSaveWalker : chanceToTradeToSaveWalker;
|
||||||
|
boolean powerParityOrHigher = blocker.getNetPower() <= attacker.getNetPower();
|
||||||
|
boolean creatureParityOrAllowedDiff = aiCreatureCount
|
||||||
|
+ (randomTradeIfBehindOnBoard ? maxCreatDiff : 0) >= oppCreatureCount;
|
||||||
|
boolean wantToTradeWithCreatInHand = randomTradeIfCreatInHand
|
||||||
|
&& !CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.CREATURES).isEmpty()
|
||||||
|
&& aiCreatureCount + maxCreatDiffWithRepl >= oppCreatureCount;
|
||||||
|
boolean wantToSavePlaneswalker = MyRandom.percentTrue(chanceToSavePW)
|
||||||
|
&& combat.getDefenderByAttacker(attacker) instanceof Card
|
||||||
|
&& ((Card) combat.getDefenderByAttacker(attacker)).isPlaneswalker();
|
||||||
|
boolean wantToTradeDownToSavePW = chanceToTradeDownToSaveWalker > 0;
|
||||||
|
|
||||||
|
if (((evalBlk <= evalAtk + 1) || (wantToSavePlaneswalker && wantToTradeDownToSavePW)) // "1" accounts for tapped.
|
||||||
|
&& powerParityOrHigher
|
||||||
|
&& (creatureParityOrAllowedDiff || wantToTradeWithCreatInHand)
|
||||||
|
&& (MyRandom.percentTrue(chance) || wantToSavePlaneswalker)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user