Merge branch 'aicleanup' into 'master'

Minor cleanup

See merge request core-developers/forge!4705
This commit is contained in:
Michael Kamensky
2021-05-16 12:43:17 +00:00
33 changed files with 61 additions and 152 deletions

View File

@@ -427,8 +427,7 @@ public class AiAttackController {
// total attack = biggest creature + exalted, *2 if Rafiq is in play // total attack = biggest creature + exalted, *2 if Rafiq is in play
int humanBasePower = getAttack(this.oppList.get(0)) + humanExaltedBonus; int humanBasePower = getAttack(this.oppList.get(0)) + humanExaltedBonus;
if (finestHour) { if (finestHour) {
// For Finest Hour, one creature could attack and get the // For Finest Hour, one creature could attack and get the bonus TWICE
// bonus TWICE
humanBasePower = humanBasePower + humanExaltedBonus; humanBasePower = humanBasePower + humanExaltedBonus;
} }
final int totalExaltedAttack = opp.isCardInPlay("Rafiq of the Many") ? 2 * humanBasePower final int totalExaltedAttack = opp.isCardInPlay("Rafiq of the Many") ? 2 * humanBasePower
@@ -935,12 +934,9 @@ public class AiAttackController {
// ********************* // *********************
// if outnumber and superior ratio work out whether attritional all out // if outnumber and superior ratio work out whether attritional all out
// attacking will work // attacking will work attritional attack will expect some creatures to die but to achieve
// attritional attack will expect some creatures to die but to achieve // victory by sheer weight of numbers attacking turn after turn. It's not calculate very
// victory by sheer weight // carefully, the accuracy can probably be improved
// of numbers attacking turn after turn. It's not calculate very
// carefully, the accuracy
// can probably be improved
// ********************* // *********************
boolean doAttritionalAttack = false; boolean doAttritionalAttack = false;
// get list of attackers ordered from low power to high // get list of attackers ordered from low power to high
@@ -974,7 +970,6 @@ public class AiAttackController {
doAttritionalAttack = true; doAttritionalAttack = true;
} }
} }
// System.out.println(doAttritionalAttack + " = do attritional attack");
// ********************* // *********************
// end attritional attack calculation // end attritional attack calculation
// ********************* // *********************
@@ -1024,11 +1019,9 @@ public class AiAttackController {
// end see how long until unblockable attackers will be fatal // end see how long until unblockable attackers will be fatal
// ***************** // *****************
// decide on attack aggression based on a comparison of forces, life // decide on attack aggression based on a comparison of forces, life
// totals and other considerations // totals and other considerations some bad "magic numbers" here
// some bad "magic numbers" here, TODO replace with nice descriptive // TODO replace with nice descriptive variable names
// variable names
if (ratioDiff > 0 && doAttritionalAttack) { if (ratioDiff > 0 && doAttritionalAttack) {
this.aiAggression = 5; // attack at all costs this.aiAggression = 5; // attack at all costs
} else if ((ratioDiff >= 1 && this.attackers.size() > 1 && (humanLifeToDamageRatio < 2 || outNumber > 0)) } else if ((ratioDiff >= 1 && this.attackers.size() > 1 && (humanLifeToDamageRatio < 2 || outNumber > 0))
@@ -1223,9 +1216,8 @@ public class AiAttackController {
} }
// look at the attacker in relation to the blockers to establish a // look at the attacker in relation to the blockers to establish a
// number of factors about the attacking // number of factors about the attacking context that will be relevant
// context that will be relevant to the attackers decision according to // to the attackers decision according to the selected strategy
// the selected strategy
for (final Card defender : validBlockers) { for (final Card defender : validBlockers) {
// if both isWorthLessThanAllKillers and canKillAllDangerous are false there's nothing more to check // if both isWorthLessThanAllKillers and canKillAllDangerous are false there's nothing more to check
if (isWorthLessThanAllKillers || canKillAllDangerous || numberOfPossibleBlockers < 2) { if (isWorthLessThanAllKillers || canKillAllDangerous || numberOfPossibleBlockers < 2) {
@@ -1303,10 +1295,7 @@ public class AiAttackController {
|| (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, combat))) { || (numberOfPossibleBlockers == 2 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 2, combat))) {
canBeBlocked = true; canBeBlocked = true;
} }
/*System.out.println(attacker + " canBeKilledByOne: " + canBeKilledByOne + " canKillAll: " // decide if the creature should attack based on the prevailing strategy choice in aiAggression
+ canKillAll + " isWorthLessThanAllKillers: " + isWorthLessThanAllKillers + " canBeBlocked: " + canBeBlocked);*/
// decide if the creature should attack based on the prevailing strategy
// choice in aiAggression
switch (this.aiAggression) { switch (this.aiAggression) {
case 6: // Exalted: expecting to at least kill a creature of equal value or not be blocked case 6: // Exalted: expecting to at least kill a creature of equal value or not be blocked
if ((canKillAll && isWorthLessThanAllKillers) || !canBeBlocked) { if ((canKillAll && isWorthLessThanAllKillers) || !canBeBlocked) {
@@ -1441,7 +1430,7 @@ public class AiAttackController {
public String toProtectAttacker(SpellAbility sa) { public String toProtectAttacker(SpellAbility sa) {
//AiAttackController is created with the selected attacker as the only entry in "attackers" //AiAttackController is created with the selected attacker as the only entry in "attackers"
if (sa.getApi() != ApiType.Protection || oppList.isEmpty() || getPossibleBlockers(oppList, attackers).isEmpty()) { if (sa.getApi() != ApiType.Protection || oppList.isEmpty() || getPossibleBlockers(oppList, attackers).isEmpty()) {
return null; //not protection sa or attacker is already unblockable return null; //not protection sa or attacker is already unblockable
} }
final List<String> choices = ProtectEffect.getProtectionList(sa); final List<String> choices = ProtectEffect.getProtectionList(sa);
String color = ComputerUtilCard.getMostProminentColor(getPossibleBlockers(oppList, attackers)), artifact = null; String color = ComputerUtilCard.getMostProminentColor(getPossibleBlockers(oppList, attackers)), artifact = null;
@@ -1451,7 +1440,7 @@ public class AiAttackController {
if (!choices.contains(color)) { if (!choices.contains(color)) {
color = null; color = null;
} }
for (Card c : oppList) { //find a blocker that ignores the currently selected protection for (Card c : oppList) { //find a blocker that ignores the currently selected protection
if (artifact != null && !c.isArtifact()) { if (artifact != null && !c.isArtifact()) {
artifact = null; artifact = null;
} }
@@ -1484,7 +1473,7 @@ public class AiAttackController {
break; break;
} }
} }
if (color == null && artifact == null) { //nothing can make the attacker unblockable if (color == null && artifact == null) { //nothing can make the attacker unblockable
return null; return null;
} }
} }
@@ -1562,4 +1551,4 @@ public class AiAttackController {
return true; return true;
} }
} // end class ComputerUtil_Attack2 }

View File

@@ -366,8 +366,7 @@ public class AiBlockController {
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker) final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false); + ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
// if the total damage of the blockgang was not enough // if the total damage of the blockgang was not enough
// without but is enough with this blocker finish the // without but is enough with this blocker finish the blockgang
// blockgang
if (ComputerUtilCombat.totalFirstStrikeDamageOfBlockers(attacker, blockGang) < damageNeeded if (ComputerUtilCombat.totalFirstStrikeDamageOfBlockers(attacker, blockGang) < damageNeeded
|| CombatUtil.needsBlockers(attacker) > blockGang.size()) { || CombatUtil.needsBlockers(attacker) > blockGang.size()) {
blockGang.add(blocker); blockGang.add(blocker);
@@ -454,8 +453,7 @@ public class AiBlockController {
|| (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat))) || (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)))
// or life is in danger // or life is in danger
&& CombatUtil.canBlock(attacker, blocker, combat)) { && CombatUtil.canBlock(attacker, blocker, combat)) {
// this is needed for attackers that can't be blocked by // this is needed for attackers that can't be blocked by more than 1
// more than 1
currentAttackers.remove(attacker); currentAttackers.remove(attacker);
combat.addBlocker(attacker, blocker); combat.addBlocker(attacker, blocker);
if (CombatUtil.canBlock(attacker, leader, combat)) { if (CombatUtil.canBlock(attacker, leader, combat)) {
@@ -510,8 +508,7 @@ public class AiBlockController {
// or life is in danger // or life is in danger
&& CombatUtil.canBlock(attacker, secondBlocker, combat) && CombatUtil.canBlock(attacker, secondBlocker, combat)
&& CombatUtil.canBlock(attacker, thirdBlocker, combat)) { && CombatUtil.canBlock(attacker, thirdBlocker, combat)) {
// this is needed for attackers that can't be blocked by // this is needed for attackers that can't be blocked by more than 1
// more than 1
currentAttackers.remove(attacker); currentAttackers.remove(attacker);
combat.addBlocker(attacker, thirdBlocker); combat.addBlocker(attacker, thirdBlocker);
if (CombatUtil.canBlock(attacker, secondBlocker, combat)) { if (CombatUtil.canBlock(attacker, secondBlocker, combat)) {
@@ -736,8 +733,7 @@ public class AiBlockController {
List<Card> tramplingAttackers = CardLists.getKeyword(attackers, Keyword.TRAMPLE); List<Card> tramplingAttackers = CardLists.getKeyword(attackers, Keyword.TRAMPLE);
tramplingAttackers = CardLists.filter(tramplingAttackers, Predicates.not(rampagesOrNeedsManyToBlock)); tramplingAttackers = CardLists.filter(tramplingAttackers, Predicates.not(rampagesOrNeedsManyToBlock));
// TODO - should check here for a "rampage-like" trigger that replaced // TODO - should check here for a "rampage-like" trigger that replaced the keyword:
// the keyword:
// "Whenever CARDNAME becomes blocked, it gets +1/+1 until end of turn for each creature blocking it." // "Whenever CARDNAME becomes blocked, it gets +1/+1 until end of turn for each creature blocking it."
for (final Card attacker : tramplingAttackers) { for (final Card attacker : tramplingAttackers) {
@@ -1036,27 +1032,21 @@ public class AiBlockController {
} else { } else {
lifeInDanger = false; lifeInDanger = false;
} }
// if life is still in danger // Reinforce blockers blocking attackers with trample if life is still in danger
// Reinforce blockers blocking attackers with trample if life is
// still
// in danger
if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) { if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) {
reinforceBlockersAgainstTrample(combat); reinforceBlockersAgainstTrample(combat);
} else { } else {
lifeInDanger = false; lifeInDanger = false;
} }
// Support blockers not destroying the attacker with more blockers // Support blockers not destroying the attacker with more blockers
// to // to try to kill the attacker
// try to kill the attacker
if (!lifeInDanger) { if (!lifeInDanger) {
reinforceBlockersToKill(combat); reinforceBlockersToKill(combat);
} }
// == 2. If the AI life would still be in danger make a safer // == 2. If the AI life would still be in danger make a safer approach ==
// approach ==
if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) { if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) {
clearBlockers(combat, possibleBlockers); // reset every block clearBlockers(combat, possibleBlockers); // reset every block assignment
// assignment
makeTradeBlocks(combat); // choose necessary trade blocks makeTradeBlocks(combat); // choose necessary trade blocks
// if life is in danger // if life is in danger
makeGoodBlocks(combat); makeGoodBlocks(combat);
@@ -1066,8 +1056,7 @@ public class AiBlockController {
} else { } else {
lifeInDanger = false; lifeInDanger = false;
} }
// Reinforce blockers blocking attackers with trample if life is // Reinforce blockers blocking attackers with trample if life is still in danger
// still in danger
if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) { if (lifeInDanger && ComputerUtilCombat.lifeInDanger(ai, combat)) {
reinforceBlockersAgainstTrample(combat); reinforceBlockersAgainstTrample(combat);
} else { } else {
@@ -1077,11 +1066,9 @@ public class AiBlockController {
reinforceBlockersToKill(combat); reinforceBlockersToKill(combat);
} }
// == 3. If the AI life would be in serious danger make an even // == 3. If the AI life would be in serious danger make an even safer approach ==
// safer approach ==
if (lifeInDanger && ComputerUtilCombat.lifeInSeriousDanger(ai, combat)) { if (lifeInDanger && ComputerUtilCombat.lifeInSeriousDanger(ai, combat)) {
clearBlockers(combat, possibleBlockers); // reset every block clearBlockers(combat, possibleBlockers); // reset every block assignment
// assignment
makeChumpBlocks(combat); // choose chump blocks makeChumpBlocks(combat); // choose chump blocks
if (ComputerUtilCombat.lifeInDanger(ai, combat)) { if (ComputerUtilCombat.lifeInDanger(ai, combat)) {
makeTradeBlocks(combat); // choose necessary trade makeTradeBlocks(combat); // choose necessary trade
@@ -1090,15 +1077,13 @@ public class AiBlockController {
if (!ComputerUtilCombat.lifeInDanger(ai, combat)) { if (!ComputerUtilCombat.lifeInDanger(ai, combat)) {
makeGoodBlocks(combat); makeGoodBlocks(combat);
} }
// Reinforce blockers blocking attackers with trample if life is // Reinforce blockers blocking attackers with trample if life is still in danger
// still in danger
else { else {
reinforceBlockersAgainstTrample(combat); reinforceBlockersAgainstTrample(combat);
} }
makeGangBlocks(combat); makeGangBlocks(combat);
// Support blockers not destroying the attacker with more // Support blockers not destroying the attacker with more
// blockers // blockers to try to kill the attacker
// to try to kill the attacker
reinforceBlockersToKill(combat); reinforceBlockersToKill(combat);
} }
} }

View File

@@ -1422,8 +1422,6 @@ public class AiController {
private List<SpellAbility> singleSpellAbilityList(SpellAbility sa) { private List<SpellAbility> singleSpellAbilityList(SpellAbility sa) {
if (sa == null) { return null; } if (sa == null) { return null; }
// System.out.println("Chosen to play: " + sa);
final List<SpellAbility> abilities = Lists.newArrayList(); final List<SpellAbility> abilities = Lists.newArrayList();
abilities.add(sa); abilities.add(sa);
return abilities; return abilities;

View File

@@ -2253,10 +2253,8 @@ public class ComputerUtil {
String chosen = ""; String chosen = "";
if (kindOfType.equals("Card")) { if (kindOfType.equals("Card")) {
// TODO // TODO
// computer will need to choose a type // computer will need to choose a type based on whether it needs a creature or land,
// based on whether it needs a creature or land, // otherwise, lib search for most common type left then, reveal chosenType to Human
// otherwise, lib search for most common type left
// then, reveal chosenType to Human
if (game.getPhaseHandler().is(PhaseType.UNTAP) && logic == null) { // Storage Matrix if (game.getPhaseHandler().is(PhaseType.UNTAP) && logic == null) { // Storage Matrix
double amount = 0; double amount = 0;
for (String type : CardType.getAllCardTypes()) { for (String type : CardType.getAllCardTypes()) {
@@ -2477,8 +2475,7 @@ public class ComputerUtil {
return opponent ? "Numbers" : "Strength"; return opponent ? "Numbers" : "Strength";
} }
// TODO check for ETB to +1/+1 counters // TODO check for ETB to +1/+1 counters or over another trigger like lifegain
// or over another trigger like lifegain
int tokenScore = ComputerUtilCard.evaluateCreature(token); int tokenScore = ComputerUtilCard.evaluateCreature(token);
@@ -2556,8 +2553,7 @@ public class ComputerUtil {
return "Taxes"; return "Taxes";
} else { } else {
// ai is first voter or ally of controller // ai is first voter or ally of controller
// both are not affected, but if opponents controll creatures, // both are not affected, but if opponents control creatures, sacrifice is worse
// sacrifice is worse
return controller.getOpponents().getCreaturesInPlay().isEmpty() ? "Taxes" : "Death"; return controller.getOpponents().getCreaturesInPlay().isEmpty() ? "Taxes" : "Death";
} }
default: default:

View File

@@ -265,16 +265,14 @@ public class ComputerUtilCard {
* @return a {@link forge.game.card.Card} object. * @return a {@link forge.game.card.Card} object.
*/ */
public static Card getBestAI(final Iterable<Card> list) { public static Card getBestAI(final Iterable<Card> list) {
// Get Best will filter by appropriate getBest list if ALL of the list // Get Best will filter by appropriate getBest list if ALL of the list is of that type
// is of that type
if (Iterables.all(list, CardPredicates.Presets.CREATURES)) { if (Iterables.all(list, CardPredicates.Presets.CREATURES)) {
return ComputerUtilCard.getBestCreatureAI(list); return ComputerUtilCard.getBestCreatureAI(list);
} }
if (Iterables.all(list, CardPredicates.Presets.LANDS)) { if (Iterables.all(list, CardPredicates.Presets.LANDS)) {
return getBestLandAI(list); return getBestLandAI(list);
} }
// TODO - Once we get an EvaluatePermanent this should call // TODO - Once we get an EvaluatePermanent this should call getBestPermanent()
// getBestPermanent()
return ComputerUtilCard.getMostExpensivePermanentAI(list); return ComputerUtilCard.getMostExpensivePermanentAI(list);
} }
@@ -410,8 +408,7 @@ public class ComputerUtilCard {
return getWorstCreatureAI(CardLists.filter(list, CardPredicates.Presets.CREATURES)); return getWorstCreatureAI(CardLists.filter(list, CardPredicates.Presets.CREATURES));
} }
// Planeswalkers fall through to here, lands will fall through if there // Planeswalkers fall through to here, lands will fall through if there aren't very many
// aren't very many
return getCheapestPermanentAI(list, null, false); return getCheapestPermanentAI(list, null, false);
} }
@@ -1198,7 +1195,7 @@ public class ComputerUtilCard {
} }
String kws = params.get("AddKeyword"); String kws = params.get("AddKeyword");
if (kws != null) { if (kws != null) {
bonusPT += 4 * (1 + StringUtils.countMatches(kws, "&")); //treat each added keyword as a +2/+2 for now bonusPT += 4 * (1 + StringUtils.countMatches(kws, "&")); //treat each added keyword as a +2/+2 for now
} }
if (bonusPT > 0) { if (bonusPT > 0) {
threat = bonusPT * (1 + opp.getCreaturesInPlay().size()) / 10.0f; threat = bonusPT * (1 + opp.getCreaturesInPlay().size()) / 10.0f;
@@ -1212,7 +1209,7 @@ public class ComputerUtilCard {
} }
final float valueNow = Math.max(valueTempo, threat); final float valueNow = Math.max(valueTempo, threat);
if (valueNow < 0.2) { //hard floor to reduce ridiculous odds for instants over time if (valueNow < 0.2) { //hard floor to reduce ridiculous odds for instants over time
return false; return false;
} }
final float chance = MyRandom.getRandom().nextFloat(); final float chance = MyRandom.getRandom().nextFloat();
@@ -1310,7 +1307,7 @@ public class ComputerUtilCard {
threat *= 2; threat *= 2;
} }
if (c.getNetPower() == 0 && c == sa.getHostCard() && power > 0 ) { if (c.getNetPower() == 0 && c == sa.getHostCard() && power > 0 ) {
threat *= 4; //over-value self +attack for 0 power creatures which may be pumped further after attacking threat *= 4; //over-value self +attack for 0 power creatures which may be pumped further after attacking
} }
chance += threat; chance += threat;

View File

@@ -609,7 +609,6 @@ public class ComputerUtilMana {
String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay); String manaProduced = predictManafromSpellAbility(saPayment, ai, toPay);
//System.out.println(manaProduced);
payMultipleMana(cost, manaProduced, ai); payMultipleMana(cost, manaProduced, ai);
// remove from available lists // remove from available lists

View File

@@ -649,7 +649,6 @@ public class PlayerControllerAi extends PlayerController {
@Override @Override
public boolean playChosenSpellAbility(SpellAbility sa) { public boolean playChosenSpellAbility(SpellAbility sa) {
// System.out.println("Playing sa: " + sa);
if (sa instanceof LandAbility) { if (sa instanceof LandAbility) {
if (sa.canPlay()) { if (sa.canPlay()) {
sa.resolve(); sa.resolve();

View File

@@ -31,8 +31,7 @@ public class ControlExchangeAi extends SpellAbilityAi {
CardCollection list = CardCollection list =
CardLists.getValidCards(AiAttackController.choosePreferredDefenderPlayer(ai).getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa); CardLists.getValidCards(AiAttackController.choosePreferredDefenderPlayer(ai).getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, sa.getHostCard(), sa);
// AI won't try to grab cards that are filtered out of AI decks on // AI won't try to grab cards that are filtered out of AI decks on purpose
// purpose
list = CardLists.filter(list, new Predicate<Card>() { list = CardLists.filter(list, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { public boolean apply(final Card c) {

View File

@@ -110,8 +110,7 @@ public class ControlGainAi extends SpellAbilityAi {
} }
} }
// Don't steal something if I can't Attack without, or prevent it from // Don't steal something if I can't Attack without, or prevent it from blocking at least
// blocking at least
if (lose.contains("EOT") if (lose.contains("EOT")
&& ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& !sa.isTrigger()) { && !sa.isTrigger()) {
@@ -211,6 +210,7 @@ public class ControlGainAi extends SpellAbilityAi {
} }
} }
// TODO check life of controller and consider stealing from another opponent so the risk of your army disappearing is spread out
while (t == null) { while (t == null) {
// filter by MustTarget requirement // filter by MustTarget requirement
CardCollection originalList = new CardCollection(list); CardCollection originalList = new CardCollection(list);
@@ -264,7 +264,6 @@ public class ControlGainAi extends SpellAbilityAi {
} }
return true; return true;
} }
@Override @Override

View File

@@ -120,8 +120,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
// pre filter targetable cards with counters and can receive one of // pre filter targetable cards with counters and can receive one of them
// them
list = CardLists.filter(list, new Predicate<Card>() { list = CardLists.filter(list, new Predicate<Card>() {
@Override @Override

View File

@@ -40,7 +40,6 @@ import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.AbilitySub; import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetChoices; import forge.game.spellability.TargetChoices;
@@ -795,8 +794,7 @@ public class DamageDealAi extends DamageAiBase {
} }
} }
} }
// TODO: Improve Damage, we shouldn't just target the player just // TODO: Improve Damage, we shouldn't just target the player just because we can
// because we can
if (sa.canTarget(enemy) && tcs.size() < tgt.getMaxTargets(source, sa)) { if (sa.canTarget(enemy) && tcs.size() < tgt.getMaxTargets(source, sa)) {
if (((phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai)) if (((phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai))
|| (SpellAbilityAi.isSorcerySpeed(sa) && phase.is(PhaseType.MAIN2)) || (SpellAbilityAi.isSorcerySpeed(sa) && phase.is(PhaseType.MAIN2))
@@ -1041,7 +1039,7 @@ public class DamageDealAi extends DamageAiBase {
saTgt = saTgt.getParent(); saTgt = saTgt.getParent();
} }
Player opponent = ai.getOpponents().min(PlayerPredicates.compareByLife()); Player opponent = ai.getWeakestOpponent();
// TODO: somehow account for the possible cost reduction? // TODO: somehow account for the possible cost reduction?
int dmg = ComputerUtilMana.determineLeftoverMana(sa, ai, saTgt.getParam("XColor")); int dmg = ComputerUtilMana.determineLeftoverMana(sa, ai, saTgt.getParam("XColor"));

View File

@@ -45,9 +45,8 @@ public class DigAi extends SpellAbilityAi {
sa.resetTargets(); sa.resetTargets();
if (!opp.canBeTargetedBy(sa)) { if (!opp.canBeTargetedBy(sa)) {
return false; return false;
} else {
sa.getTargets().add(opp);
} }
sa.getTargets().add(opp);
libraryOwner = opp; libraryOwner = opp;
} }

View File

@@ -30,9 +30,8 @@ public class DigMultipleAi extends SpellAbilityAi {
sa.resetTargets(); sa.resetTargets();
if (!opp.canBeTargetedBy(sa)) { if (!opp.canBeTargetedBy(sa)) {
return false; return false;
} else {
sa.getTargets().add(opp);
} }
sa.getTargets().add(opp);
libraryOwner = opp; libraryOwner = opp;
} }

View File

@@ -61,9 +61,8 @@ public class DigUntilAi extends SpellAbilityAi {
sa.resetTargets(); sa.resetTargets();
if (!sa.canTarget(opp)) { if (!sa.canTarget(opp)) {
return false; return false;
} else {
sa.getTargets().add(opp);
} }
sa.getTargets().add(opp);
libraryOwner = opp; libraryOwner = opp;
} else { } else {
if (sa.hasParam("Valid")) { if (sa.hasParam("Valid")) {

View File

@@ -443,7 +443,7 @@ public class DrawAi extends SpellAbilityAi {
continue; continue;
} }
// use xPaid abilties only for itself // use xPaid abilities only for itself
if (xPaid) { if (xPaid) {
continue; continue;
} }

View File

@@ -13,8 +13,7 @@ public class GameLossAi extends SpellAbilityAi {
return false; return false;
} }
// Only one SA Lose the Game card right now, which is Door to // Only one SA Lose the Game card right now, which is Door to Nothingness
// Nothingness
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null) { if (tgt != null) {

View File

@@ -266,8 +266,7 @@ public class LifeGainAi extends SpellAbilityAi {
} }
if (!hasTgt && mandatory) { if (!hasTgt && mandatory) {
// need to target something but its neither negative against // need to target something but its neither negative against
// opponents, // opponents, nor positive against allies
// nor posive against allies
// hurting ally is probably better than healing opponent // hurting ally is probably better than healing opponent
// look for Lifegain not Negative (case of lifegain negated) // look for Lifegain not Negative (case of lifegain negated)
@@ -295,8 +294,7 @@ public class LifeGainAi extends SpellAbilityAi {
sa.getTargets().add(ally); sa.getTargets().add(ally);
hasTgt = true; hasTgt = true;
} }
// better heal opponent which most life then the one with the // better heal opponent which most life then the one with the lowest
// lowest
if (!hasTgt) { if (!hasTgt) {
Player opp = opps.max(PlayerPredicates.compareByLife()); Player opp = opps.max(PlayerPredicates.compareByLife());
sa.getTargets().add(opp); sa.getTargets().add(opp);

View File

@@ -60,7 +60,6 @@ public class LifeLoseAi extends SpellAbilityAi {
return true; return true;
} }
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@@ -123,12 +122,11 @@ public class LifeLoseAi extends SpellAbilityAi {
return false; return false;
} }
final PlayerCollection tgtPlayers = getPlayers(ai, sa);
if (ComputerUtil.playImmediately(ai, sa)) { if (ComputerUtil.playImmediately(ai, sa)) {
return true; return true;
} }
final PlayerCollection tgtPlayers = getPlayers(ai, sa);
PlayerCollection filteredPlayer = tgtPlayers PlayerCollection filteredPlayer = tgtPlayers
.filter(Predicates.and(PlayerPredicates.isOpponentOf(ai), PlayerPredicates.lifeLessOrEqualTo(amount))); .filter(Predicates.and(PlayerPredicates.isOpponentOf(ai), PlayerPredicates.lifeLessOrEqualTo(amount)));
// killing opponents asap // killing opponents asap

View File

@@ -21,6 +21,7 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -214,13 +215,7 @@ public class MillAi extends SpellAbilityAi {
} }
// get targeted or defined Player with largest library // get targeted or defined Player with largest library
// TODO in Java 8 find better way final Player m = Collections.max(list, PlayerPredicates.compareByZoneSize(ZoneType.Library));
final Player m = Collections.max(list, new Comparator<Player>() {
@Override
public int compare(Player arg0, Player arg1) {
return arg0.getCardsIn(ZoneType.Library).size() - arg1.getCardsIn(ZoneType.Library).size();
}
});
int cardsToDiscard = m.getCardsIn(ZoneType.Library).size(); int cardsToDiscard = m.getCardsIn(ZoneType.Library).size();

View File

@@ -49,14 +49,6 @@ import forge.game.zone.ZoneType;
*/ */
public class RegenerateAi extends SpellAbilityAi { public class RegenerateAi extends SpellAbilityAi {
// Ex: A:SP$Regenerate | Cost$W | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$Regenerate
// target creature.
// http://www.slightlymagic.net/wiki/Forge_AbilityFactory#Regenerate
// **************************************************************
// ********************* Regenerate ****************************
// **************************************************************
@Override @Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
final Game game = ai.getGame(); final Game game = ai.getGame();
@@ -65,8 +57,7 @@ public class RegenerateAi extends SpellAbilityAi {
boolean chance = false; boolean chance = false;
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt == null) { if (tgt == null) {
// As far as I can tell these Defined Cards will only have one of // As far as I can tell these Defined Cards will only have one of them
// them
final List<Card> list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("Defined"), sa); final List<Card> list = AbilityUtils.getDefinedCards(hostCard, sa.getParam("Defined"), sa);
if (!game.getStack().isEmpty()) { if (!game.getStack().isEmpty()) {
@@ -105,8 +96,7 @@ public class RegenerateAi extends SpellAbilityAi {
} }
if (!game.getStack().isEmpty()) { if (!game.getStack().isEmpty()) {
// check stack for something on the stack will kill anything i // check stack for something on the stack will kill anything i control
// control
final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true); final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true);
final List<Card> threatenedTargets = new ArrayList<>(); final List<Card> threatenedTargets = new ArrayList<>();
@@ -191,8 +181,7 @@ public class RegenerateAi extends SpellAbilityAi {
} }
} }
// TODO see if something on the stack is about to kill something i // TODO see if something on the stack is about to kill something i can target
// can target
// choose my best X without regen // choose my best X without regen
if (CardLists.getNotType(compTargetables, "Creature").isEmpty()) { if (CardLists.getNotType(compTargetables, "Creature").isEmpty()) {

View File

@@ -121,11 +121,9 @@ public class ScryAi extends SpellAbilityAi {
return false; return false;
} }
double chance = .4; // 40 percent chance of milling with instant speed double chance = .4; // 40 percent chance of milling with instant speed stuff
// stuff
if (SpellAbilityAi.isSorcerySpeed(sa)) { if (SpellAbilityAi.isSorcerySpeed(sa)) {
chance = .667; // 66.7% chance for sorcery speed (since it will chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT)
// never activate EOT)
} }
boolean randomReturn = MyRandom.getRandom().nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1); boolean randomReturn = MyRandom.getRandom().nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);

View File

@@ -54,8 +54,7 @@ public class SetStateAi extends SpellAbilityAi {
@Override @Override
public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) { public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) {
// Gross generalization, but this always considers alternate // Gross generalization, but this always considers alternate states more powerful
// states more powerful
return !sa.getHostCard().isInAlternateState(); return !sa.getHostCard().isInAlternateState();
} }

View File

@@ -19,8 +19,7 @@ public class ShuffleAi extends SpellAbilityAi {
return aiPlayer.getGame().getPhaseHandler().is(PhaseType.MAIN2, aiPlayer); return aiPlayer.getGame().getPhaseHandler().is(PhaseType.MAIN2, aiPlayer);
} }
// not really sure when the compy would use this; maybe only after a // not really sure when the compy would use this; maybe only after a human
// human
// deliberately put a card on top of their library // deliberately put a card on top of their library
return false; return false;
/* /*

View File

@@ -19,8 +19,7 @@ public class TapOrUntapAi extends TapAiBase {
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
// assume we are looking to tap human's stuff // assume we are looking to tap human's stuff
// TODO - check for things with untap abilities, and don't tap // TODO - check for things with untap abilities, and don't tap those.
// those.
boolean bFlag = false; boolean bFlag = false;
for (final Card c : AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)) { for (final Card c : AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)) {

View File

@@ -544,7 +544,6 @@ public final class CardRules implements ICardCharacteristics {
@Override @Override
public final ManaCostShard next() { public final ManaCostShard next() {
final String unparsed = st.nextToken(); final String unparsed = st.nextToken();
// System.out.println(unparsed);
if (StringUtils.isNumeric(unparsed)) { if (StringUtils.isNumeric(unparsed)) {
this.genericCost += Integer.parseInt(unparsed); this.genericCost += Integer.parseInt(unparsed);
return null; return null;
@@ -560,7 +559,7 @@ public final class CardRules implements ICardCharacteristics {
*/ */
@Override @Override
public void remove() { public void remove() {
} // unsuported } // unsupported
} }
} }

View File

@@ -30,7 +30,6 @@ public class ManaCostParser implements IParserManaCost {
*/ */
public ManaCostParser(final String cost) { public ManaCostParser(final String cost) {
this.cost = cost.split(" "); this.cost = cost.split(" ");
// System.out.println(cost);
this.nextToken = 0; this.nextToken = 0;
this.genericCost = 0; this.genericCost = 0;
} }
@@ -66,7 +65,6 @@ public class ManaCostParser implements IParserManaCost {
@Override @Override
public final ManaCostShard next() { public final ManaCostShard next() {
final String unparsed = this.cost[this.nextToken++]; final String unparsed = this.cost[this.nextToken++];
// System.out.println(unparsed);
if (StringUtils.isNumeric(unparsed)) { if (StringUtils.isNumeric(unparsed)) {
this.genericCost += Integer.parseInt(unparsed); this.genericCost += Integer.parseInt(unparsed);
return null; return null;

View File

@@ -1233,7 +1233,6 @@ public class AbilityUtils {
} }
else if (defined.startsWith("PlayerNamed_")) { else if (defined.startsWith("PlayerNamed_")) {
for (Player p : game.getPlayersInTurnOrder()) { for (Player p : game.getPlayersInTurnOrder()) {
//System.out.println("Named player " + defined.substring(12));
if (p.getName().equals(defined.substring(12))) { if (p.getName().equals(defined.substring(12))) {
players.add(p); players.add(p);
} }

View File

@@ -220,7 +220,6 @@ public class CardFactory {
return getCard(cp, owner, owner == null ? -1 : owner.getGame().nextCardId(), game); return getCard(cp, owner, owner == null ? -1 : owner.getGame().nextCardId(), game);
} }
public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId, final Game game) { public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId, final Game game) {
//System.out.println(cardName);
CardRules cardRules = cp.getRules(); CardRules cardRules = cp.getRules();
final Card c = readCard(cardRules, cp, cardId, game); final Card c = readCard(cardRules, cp, cardId, game);
c.setRules(cardRules); c.setRules(cardRules);

View File

@@ -2681,11 +2681,6 @@ public class Player extends GameEntity implements Comparable<Player> {
//getZone(ZoneType.Command).add(c); //getZone(ZoneType.Command).add(c);
} }
//DBG
//System.out.println("CurrentPlanes: " + currentPlanes);
//System.out.println("ActivePlanes: " + game.getActivePlanes());
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
game.setActivePlanes(currentPlanes); game.setActivePlanes(currentPlanes);
//Run PlaneswalkedTo triggers here. //Run PlaneswalkedTo triggers here.
final Map<AbilityKey, Object> runParams = AbilityKey.newMap(); final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
@@ -2710,11 +2705,6 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getAction().moveTo(ZoneType.PlanarDeck, plane,-1, null); game.getAction().moveTo(ZoneType.PlanarDeck, plane,-1, null);
} }
currentPlanes.clear(); currentPlanes.clear();
//DBG
//System.out.println("CurrentPlanes: " + currentPlanes);
//System.out.println("ActivePlanes: " + game.getActivePlanes());
//System.out.println("CommandPlanes: " + getZone(ZoneType.Command).getCards());
} }
/** /**

View File

@@ -40,7 +40,6 @@ public class SealedDeckBuilder extends LimitedDeckBuilder {
for (int i = 0; i < limit; i++) { for (int i = 0; i < limit; i++) {
PaperCard cp = initialRanked.get(i); PaperCard cp = initialRanked.get(i);
colorChooserList.add(cp); colorChooserList.add(cp);
//System.out.println(cp.getName() + " " + cp.getRules().getManaCost().toString());
} }
Iterable<CardRules> rules = Iterables.transform(colorChooserList, PaperCard.FN_GET_RULES); Iterable<CardRules> rules = Iterables.transform(colorChooserList, PaperCard.FN_GET_RULES);

View File

@@ -154,7 +154,6 @@ public class QuestBazaarManager {
for (int iSlot = 0; iSlot < QuestController.MAX_PET_SLOTS; iSlot++) { for (int iSlot = 0; iSlot < QuestController.MAX_PET_SLOTS; iSlot++) {
for (final QuestPetController pet : qCtrl.getPetsStorage().getAllPets(iSlot)) { for (final QuestPetController pet : qCtrl.getPetsStorage().getAllPets(iSlot)) {
//System.out.println("Pet: " + pet.getName());
itemSet.put(pet.getName(), pet); itemSet.put(pet.getName(), pet);
} }
} }
@@ -168,7 +167,6 @@ public class QuestBazaarManager {
for (final String itemName : thisStall.getItems()) { for (final String itemName : thisStall.getItems()) {
final IQuestBazaarItem item = itemSet.get(itemName); final IQuestBazaarItem item = itemSet.get(itemName);
//System.out.println(itemName);
set.add(item); set.add(item);
} }
itemsOnStalls.put(thisStall.getName(), set); itemsOnStalls.put(thisStall.getName(), set);

View File

@@ -413,7 +413,6 @@ public abstract class GuiDownloadService implements Runnable {
protected static void addMissingItems(Map<String, String> list, String nameUrlFile, String dir, boolean includeParent) { protected static void addMissingItems(Map<String, String> list, String nameUrlFile, String dir, boolean includeParent) {
for (Pair<String, String> nameUrlPair : FileUtil.readNameUrlFile(nameUrlFile)) { for (Pair<String, String> nameUrlPair : FileUtil.readNameUrlFile(nameUrlFile)) {
File f = new File(includeParent? dir+FileUtil.getParent(nameUrlPair.getRight()) : dir , decodeURL(nameUrlPair.getLeft())); File f = new File(includeParent? dir+FileUtil.getParent(nameUrlPair.getRight()) : dir , decodeURL(nameUrlPair.getLeft()));
//System.out.println(f.getAbsolutePath());
if (!f.exists()) { if (!f.exists()) {
list.put(f.getAbsolutePath(), nameUrlPair.getRight()); list.put(f.getAbsolutePath(), nameUrlPair.getRight());
} }

View File

@@ -95,7 +95,6 @@ public class GuiDownloadSetPicturesLQ extends GuiDownloadService {
if (fullborder.exists()) if (fullborder.exists())
return; //don't add on download if you have an existing fullborder image in this set... return; //don't add on download if you have an existing fullborder image in this set...
// System.out.println(filename);
if (!destFile.exists()) { if (!destFile.exists()) {
downloads.put(destFile.getAbsolutePath(), ForgeConstants.URL_PIC_DOWNLOAD + urlPath); downloads.put(destFile.getAbsolutePath(), ForgeConstants.URL_PIC_DOWNLOAD + urlPath);
} }