mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Goodbye MustAttackEffect
This commit is contained in:
@@ -58,6 +58,9 @@ import forge.util.Expressions;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import forge.util.maps.LinkedHashMapToAmount;
|
||||
import forge.util.maps.MapToAmount;
|
||||
import forge.util.maps.MapToAmountUtil;
|
||||
|
||||
|
||||
/**
|
||||
@@ -689,33 +692,18 @@ public class AiAttackController {
|
||||
}
|
||||
GameEntity prefDefender = defs.contains(defendingOpponent) ? defendingOpponent : defs.get(0);
|
||||
|
||||
// Attempt to see if there's a defined entity that must be attacked strictly this turn...
|
||||
GameEntity entity = ai.getMustAttackEntityThisTurn();
|
||||
if (nextTurn || entity == null) {
|
||||
// ...or during the attacking creature controller's turn
|
||||
entity = ai.getMustAttackEntity();
|
||||
// 1. assault the opponent if you can kill him
|
||||
if (bAssault) {
|
||||
return prefDefender;
|
||||
}
|
||||
if (null != entity) {
|
||||
int n = defs.indexOf(entity);
|
||||
if (-1 == n) {
|
||||
System.out.println("getMustAttackEntity() or getMustAttackEntityThisTurn() returned something not in defenders.");
|
||||
return prefDefender;
|
||||
}
|
||||
return entity;
|
||||
} else {
|
||||
// 1. assault the opponent if you can kill him
|
||||
if (bAssault) {
|
||||
return prefDefender;
|
||||
}
|
||||
// 2. attack planeswalkers
|
||||
List<Card> pwDefending = c.getDefendingPlaneswalkers();
|
||||
if (!pwDefending.isEmpty()) {
|
||||
final Card pwNearUlti = ComputerUtilCard.getBestPlaneswalkerToDamage(pwDefending);
|
||||
return pwNearUlti != null ? pwNearUlti : ComputerUtilCard.getBestPlaneswalkerAI(pwDefending);
|
||||
} else {
|
||||
return prefDefender;
|
||||
}
|
||||
// 2. attack planeswalkers
|
||||
List<Card> pwDefending = c.getDefendingPlaneswalkers();
|
||||
if (!pwDefending.isEmpty()) {
|
||||
final Card pwNearUlti = ComputerUtilCard.getBestPlaneswalkerToDamage(pwDefending);
|
||||
return pwNearUlti != null ? pwNearUlti : ComputerUtilCard.getBestPlaneswalkerAI(pwDefending);
|
||||
}
|
||||
|
||||
return prefDefender;
|
||||
}
|
||||
|
||||
final boolean LOG_AI_ATTACKS = false;
|
||||
@@ -786,30 +774,41 @@ public class AiAttackController {
|
||||
// because creatures not chosen can't attack.
|
||||
if (!nextTurn) {
|
||||
for (final Card attacker : this.attackers) {
|
||||
boolean mustAttack = false;
|
||||
// TODO this might result into trying to attack the wrong player
|
||||
GameEntity mustAttackDef = null;
|
||||
if (attacker.isGoaded()) {
|
||||
mustAttack = true;
|
||||
// TODO this might result into trying to attack the wrong player
|
||||
mustAttackDef = defender;
|
||||
} else if (attacker.getSVar("MustAttack").equals("True")) {
|
||||
mustAttack = true;
|
||||
mustAttackDef = defender;
|
||||
} else if (attacker.hasSVar("EndOfTurnLeavePlay")
|
||||
&& isEffectiveAttacker(ai, attacker, combat, defender)) {
|
||||
mustAttack = true;
|
||||
mustAttackDef = defender;
|
||||
} else if (seasonOfTheWitch) {
|
||||
//TODO: if there are other ways to tap this creature (like mana creature), then don't need to attack
|
||||
mustAttack = true;
|
||||
mustAttackDef = defender;
|
||||
} else {
|
||||
final List<GameEntity> e = StaticAbilityMustAttack.entitiesMustAttack(attacker);
|
||||
if (!e.isEmpty()) {
|
||||
mustAttack = true;
|
||||
// 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;
|
||||
final List<GameEntity> attackRequirements = StaticAbilityMustAttack.entitiesMustAttack(attacker);
|
||||
if (attackRequirements.contains(attacker)) {
|
||||
// TODO add cost check here and switch defender if there's one without a cost
|
||||
// must attack anything
|
||||
mustAttackDef = defender;
|
||||
// next check if there's also a specific defender to attack, so don't count them
|
||||
attackRequirements.removeAll(new CardCollection(attacker));
|
||||
}
|
||||
final MapToAmount<GameEntity> amounts = new LinkedHashMapToAmount<>();
|
||||
amounts.addAll(attackRequirements);
|
||||
while (!amounts.isEmpty()) {
|
||||
// check defenders in order of maximum requirements
|
||||
GameEntity mustAttackDefMaybe = MapToAmountUtil.max(amounts).getKey();
|
||||
if (canAttackWrapper(attacker, mustAttackDefMaybe) && CombatUtil.getAttackCost(ai.getGame(), attacker, mustAttackDefMaybe) == null) {
|
||||
mustAttackDef = mustAttackDefMaybe;
|
||||
break;
|
||||
}
|
||||
amounts.remove(mustAttackDefMaybe);
|
||||
}
|
||||
}
|
||||
if (mustAttack) {
|
||||
combat.addAttacker(attacker, defender);
|
||||
if (mustAttackDef != null) {
|
||||
combat.addAttacker(attacker, mustAttackDef);
|
||||
attackersLeft.remove(attacker);
|
||||
numForcedAttackers++;
|
||||
}
|
||||
|
||||
@@ -114,12 +114,11 @@ public class ComputerUtilCombat {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<GameEntity> mustAttackEnts = StaticAbilityMustAttack.entitiesMustAttack(attacker);
|
||||
final List<GameEntity> mustAttack = 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;
|
||||
}
|
||||
mustAttack.removeAll(new CardCollection(attacker));
|
||||
if (!mustAttack.isEmpty() && !mustAttack.contains(defender)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO this should be a factor but needs some alignment with AttachAi
|
||||
|
||||
@@ -111,7 +111,6 @@ public enum SpellApiToAi {
|
||||
.put(ApiType.MoveCounter, CountersMoveAi.class)
|
||||
.put(ApiType.MultiplePiles, CannotPlayAi.class)
|
||||
.put(ApiType.MultiplyCounter, CountersMultiplyAi.class)
|
||||
.put(ApiType.MustAttack, MustAttackAi.class)
|
||||
.put(ApiType.MustBlock, MustBlockAi.class)
|
||||
.put(ApiType.Mutate, MutateAi.class)
|
||||
.put(ApiType.NameCard, ChooseCardNameAi.class)
|
||||
|
||||
@@ -1635,8 +1635,6 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (keyword.endsWith("CARDNAME can't attack.") || keyword.equals("Defender")
|
||||
|| keyword.endsWith("CARDNAME can't attack or block.")) {
|
||||
return card.getNetCombatDamage() >= 1 && ComputerUtilCombat.canAttackNextTurn(card);
|
||||
} else if (keyword.endsWith("CARDNAME attacks each turn if able.") || keyword.endsWith("CARDNAME attacks each combat if able.")) {
|
||||
return !ai.getCreaturesInPlay().isEmpty() && ComputerUtilCombat.canAttackNextTurn(card) && CombatUtil.canBlock(card, true);
|
||||
} else if (keyword.endsWith("CARDNAME can't block.")) {
|
||||
return CombatUtil.canBlock(card, true);
|
||||
} else if (keyword.endsWith("CARDNAME's activated abilities can't be activated.")) {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class MustAttackAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
|
||||
// disabled for the AI for now. Only for Gideon Jura at this time.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chkAIDrawback(SpellAbility sa, Player aiPlayer) {
|
||||
// AI should only activate this during Human's turn
|
||||
// TODO - implement AI
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)
|
||||
*/
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
|
||||
boolean chance;
|
||||
|
||||
// TODO - implement AI
|
||||
chance = false;
|
||||
|
||||
return chance;
|
||||
}
|
||||
}
|
||||
@@ -166,10 +166,6 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
return ph.isPlayerTurn(ai) || (combat != null && combat.isAttacking(card) && card.getNetCombatDamage() > 0);
|
||||
} else if (keyword.endsWith("CARDNAME attacks each turn if able.")
|
||||
|| keyword.endsWith("CARDNAME attacks each combat if able.")) {
|
||||
return !ph.isPlayerTurn(ai) && CombatUtil.canAttack(card, ai) && CombatUtil.canBeBlocked(card, ai)
|
||||
&& !ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS);
|
||||
} else if (keyword.endsWith("CARDNAME can't be regenerated.")) {
|
||||
if (card.getShieldCount() > 0) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user