Merge pull request #2100 from tool4ever/somefixes

Improve damage check logic for losing + performance
This commit is contained in:
Anthony Calosa
2022-12-15 07:38:42 +08:00
committed by GitHub
7 changed files with 44 additions and 53 deletions

View File

@@ -814,9 +814,6 @@ public class AiController {
}
public AiPlayDecision canPlaySa(SpellAbility sa) {
final Card card = sa.getHostCard();
final boolean isRightTiming = sa.canCastTiming(player);
if (!checkAiSpecificRestrictions(sa)) {
return AiPlayDecision.CantPlayAi;
}
@@ -824,6 +821,12 @@ public class AiController {
return canPlaySa(((WrappedAbility) sa).getWrappedAbility());
}
if (!sa.canCastTiming(player)) {
return AiPlayDecision.AnotherTime;
}
final Card card = sa.getHostCard();
// Trying to play a card that has Buyback without a Buyback cost, look for possible additional considerations
if (getBooleanProperty(AiProps.TRY_TO_PRESERVE_BUYBACK_SPELLS)) {
if (card.hasKeyword(Keyword.BUYBACK) && !sa.isBuyBackAbility() && !canPlaySpellWithoutBuyback(card, sa)) {
@@ -898,9 +901,6 @@ public class AiController {
return AiPlayDecision.AnotherTime;
}
if (sa instanceof SpellPermanent) {
if (!isRightTiming) {
return AiPlayDecision.AnotherTime;
}
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
}
if (sa.usesTargeting()) {
@@ -912,18 +912,13 @@ public class AiController {
}
}
if (sa instanceof Spell) {
if (ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()
&& !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()) {
return AiPlayDecision.CurseEffects;
}
if (!isRightTiming) {
return AiPlayDecision.AnotherTime;
}
return canPlaySpellBasic(card, sa);
}
if (!isRightTiming) {
return AiPlayDecision.AnotherTime;
}
return AiPlayDecision.WillPlay;
}
@@ -1411,8 +1406,8 @@ public class AiController {
if (!checkETBEffects(card, spell, null)) {
return AiPlayDecision.BadEtbEffects;
}
if (damage + ComputerUtil.getDamageFromETB(player, card) >= player.getLife()
&& !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife()
&& damage + ComputerUtil.getDamageFromETB(player, card) >= player.getLife()) {
return AiPlayDecision.BadEtbEffects;
}
}
@@ -1496,35 +1491,33 @@ public class AiController {
if (landsWannaPlay != null && !landsWannaPlay.isEmpty()) {
// TODO search for other land it might want to play?
Card land = chooseBestLandToPlay(landsWannaPlay);
if (ComputerUtil.getDamageFromETB(player, land) < player.getLife() || !player.canLoseLife()
|| player.cantLoseForZeroOrLessLife() ) {
if (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land)) {
final List<SpellAbility> abilities = Lists.newArrayList();
if ((!player.canLoseLife() || player.cantLoseForZeroOrLessLife() || ComputerUtil.getDamageFromETB(player, land) < player.getLife())
&& (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land))) {
final List<SpellAbility> abilities = Lists.newArrayList();
// TODO extend this logic to evaluate MDFC with both sides land
// this can only happen if its a MDFC land
if (!land.isLand()) {
land.setState(CardStateName.Modal, true);
land.setBackSide(true);
}
// TODO extend this logic to evaluate MDFC with both sides land
// this can only happen if its a MDFC land
if (!land.isLand()) {
land.setState(CardStateName.Modal, true);
land.setBackSide(true);
}
LandAbility la = new LandAbility(land, player, null);
LandAbility la = new LandAbility(land, player, null);
la.setCardState(land.getCurrentState());
if (la.canPlay()) {
abilities.add(la);
}
// add mayPlay option
for (CardPlayOption o : land.mayPlay(player)) {
la = new LandAbility(land, player, o.getAbility());
la.setCardState(land.getCurrentState());
if (la.canPlay()) {
abilities.add(la);
}
// add mayPlay option
for (CardPlayOption o : land.mayPlay(player)) {
la = new LandAbility(land, player, o.getAbility());
la.setCardState(land.getCurrentState());
if (la.canPlay()) {
abilities.add(la);
}
}
if (!abilities.isEmpty()) {
return abilities;
}
}
if (!abilities.isEmpty()) {
return abilities;
}
}
}

View File

@@ -100,20 +100,19 @@ public abstract class DamageAiBase extends SpellAbilityAi {
return false;
}
if (!enemy.canLoseLife()) {
return false;
}
if (!noPrevention) {
restDamage = ComputerUtilCombat.predictDamageTo(enemy, restDamage, hostcard, false);
} else {
restDamage = enemy.staticReplaceDamage(restDamage, hostcard, false);
}
if (restDamage == 0) {
return false;
}
if (!enemy.canLoseLife()) {
return false;
}
final CardCollectionView hand = comp.getCardsIn(ZoneType.Hand);
if ((enemy.getLife() - restDamage) < 5) {

View File

@@ -1420,10 +1420,8 @@ public class GameAction {
checkAgain = true;
}
}
if (!spaceSculptors.isEmpty()) {
for (Player p : spaceSculptors) {
checkAgain |= stateBasedAction704_5u(p);
}
for (Player p : spaceSculptors) {
checkAgain |= stateBasedAction704_5u(p);
}
// 704.5m World rule
checkAgain |= handleWorldRule(noRegCreats);

View File

@@ -80,8 +80,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
}
// special handling for Karn to filter out non-cards
CardCollection cmdCards = new CardCollection(p.getCardsIn(ZoneType.Command));
for (Card c : cmdCards) {
for (Card c : p.getCardsIn(ZoneType.Command)) {
if (c.isCommander()) {
newLibrary.add(c);
}

View File

@@ -124,13 +124,15 @@ public class RollDiceEffect extends SpellAbilityEffect {
total += modifier;
// Run triggers
int rollNum = 1;
for (Integer roll : rolls) {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(player);
runParams.put(AbilityKey.Sides, sides);
runParams.put(AbilityKey.Modifier, modifier);
runParams.put(AbilityKey.Result, roll);
runParams.put(AbilityKey.Number, player.getNumRollsThisTurn() + 1 - amount + rolls.indexOf(roll));
runParams.put(AbilityKey.Number, player.getNumRollsThisTurn() - amount + rollNum);
player.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false);
rollNum++;
}
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(player);
runParams.put(AbilityKey.Sides, sides);

View File

@@ -1921,7 +1921,7 @@ public class Player extends GameEntity implements Comparable<Player> {
}
public final boolean cantLoseForZeroOrLessLife() {
return hasKeyword("You don't lose the game for having 0 or less life.");
return cantLose() || hasKeyword("You don't lose the game for having 0 or less life.");
}
public final boolean cantWin() {

View File

@@ -585,7 +585,7 @@ public class TargetRestrictions {
final Card srcCard = sa.getHostCard(); // should there be OrginalHost at any moment?
for (final Card c : game.getCardsIn(this.tgtZone)) {
if (c.isValid(this.validTgts, srcCard.getController(), srcCard, sa)
if (c.isValid(this.validTgts, sa.getActivatingPlayer(), srcCard, sa)
&& (!isTargeted || sa.canTarget(c))
&& !sa.getTargets().contains(c)) {
candidates.add(c);