Merge pull request #113 from Northmoc/mustattack

Must attack keywords -> static ability
This commit is contained in:
Agetian
2022-04-24 07:48:31 +03:00
committed by GitHub
136 changed files with 345 additions and 244 deletions

View File

@@ -20,6 +20,7 @@ package forge.ai;
import java.util.ArrayList;
import java.util.List;
import forge.game.staticability.StaticAbilityMustAttack;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
@@ -795,14 +796,15 @@ public class AiAttackController {
&& isEffectiveAttacker(ai, attacker, combat, defender)) {
mustAttack = true;
} else if (seasonOfTheWitch) {
// TODO: if there are other ways to tap this creature (like mana creature), then don't need to attack
//TODO: if there are other ways to tap this creature (like mana creature), then don't need to attack
mustAttack = true;
} else {
// TODO move to static Ability
if (attacker.hasKeyword("CARDNAME attacks each combat if able.") || attacker.hasStartOfKeyword("CARDNAME attacks specific player each combat if able")) {
// TODO switch defender if there's one without a cost or it's not the specific player
final List<GameEntity> e = StaticAbilityMustAttack.entitiesMustAttack(attacker);
if (!e.isEmpty()) {
mustAttack = true;
} else if (attacker.getController().getMustAttackEntityThisTurn() != null && CombatUtil.getAttackCost(ai.getGame(), attacker, defender) == null) {
// TODO switch defender if there's one without a cost or it's not the specific player
} else if (attacker.getController().getMustAttackEntityThisTurn() != null &&
CombatUtil.getAttackCost(ai.getGame(), attacker, defender) == null) {
mustAttack = true;
}
}

View File

@@ -41,7 +41,6 @@ import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.CostPayment;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
import forge.game.phase.Untap;
import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
@@ -49,6 +48,7 @@ import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityMustAttack;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
@@ -114,24 +114,11 @@ public class ComputerUtilCombat {
return false;
}
// TODO replace with Static Ability
for (final String keyword : attacker.getHiddenExtrinsicKeywords()) {
if (keyword.startsWith("CARDNAME attacks specific player each combat if able")) {
final String defined = keyword.split(":")[1];
final Player player = AbilityUtils.getDefinedPlayers(attacker, defined, null).get(0);
if (!defender.equals(player)) {
return false;
}
}
}
for (final KeywordInterface inst : attacker.getKeywords(Keyword.UNDEFINED)) {
final String keyword = inst.getOriginal();
if (keyword.startsWith("CARDNAME attacks specific player each combat if able")) {
final String defined = keyword.split(":")[1];
final Player player = AbilityUtils.getDefinedPlayers(attacker, defined, null).get(0);
if (!defender.equals(player)) {
return false;
}
final List<GameEntity> mustAttackEnts = StaticAbilityMustAttack.entitiesMustAttack(attacker);
//if it contains only attacker, it only has a non-specific must attack
if (mustAttackEnts.size() > 1 || (mustAttackEnts.size() == 1 && mustAttackEnts.get(0) != attacker)) {
if (!mustAttackEnts.contains(defender)) {
return false;
}
}

View File

@@ -2,6 +2,7 @@ package forge.ai;
import com.google.common.base.Function;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
@@ -9,6 +10,9 @@ import forge.game.card.CounterEnumType;
import forge.game.cost.CostPayEnergy;
import forge.game.keyword.Keyword;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbilityMustAttack;
import java.util.List;
public class CreatureEvaluator implements Function<Card, Integer> {
@Override
@@ -174,13 +178,16 @@ public class CreatureEvaluator implements Function<Card, Integer> {
value = addValue(50 + (c.getCMC() * 5), "useless"); // reset everything - useless
} else if (c.hasKeyword("CARDNAME can't block.")) {
value -= subValue(10, "cant-block");
} else if (c.hasKeyword("CARDNAME attacks each combat if able.")) {
value -= subValue(10, "must-attack");
} else if (c.hasStartOfKeyword("CARDNAME attacks specific player each combat if able")) {
value -= subValue(10, "must-attack-player");
}/* else if (c.hasKeyword("CARDNAME can block only creatures with flying.")) {
} else {
List<GameEntity> mAEnt = StaticAbilityMustAttack.entitiesMustAttack(c);
if (mAEnt.contains(c)) {
value -= subValue(10, "must-attack");
} else if (!mAEnt.isEmpty()) {
value -= subValue(10, "must-attack-player");
}/* else if (c.hasKeyword("CARDNAME can block only creatures with flying.")) {
value -= subValue(toughness * 5, "reverse-reach");
}//*/
}
if (c.hasSVar("DestroyWhenDamaged")) {
value -= subValue((toughness - 1) * 9, "dies-to-dmg");