mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
- Added a full advanced Flash Attach Ai infrastructure and the basic logic and toggles for it.
This commit is contained in:
@@ -120,7 +120,10 @@ public enum AiProps { /** */
|
||||
FLASH_CHANCE_TO_CAST_FOR_ETB_BEFORE_MAIN1("10"), /** */
|
||||
FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB("0"), /** */
|
||||
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER("100"),
|
||||
FLASH_CHANCE_TO_USE_AURAS_AS_COMBAT_TRICKS("80"); /** */
|
||||
FLASH_USE_AURAS_AS_COMBAT_TRICKS("true"),
|
||||
FLASH_AURA_CHANCE_TO_CAST_EARLY("0"),
|
||||
FLASH_AURA_CHANCE_CAST_AT_EOT("10"),
|
||||
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK("0"); /** */
|
||||
// Experimental features, must be promoted or removed after extensive testing and, ideally, defaulting
|
||||
// <-- There are no experimental options here -->
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.game.staticability.StaticAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
@@ -53,15 +54,8 @@ public class AttachAi extends SpellAbilityAi {
|
||||
if (ai.getController().isAI()) {
|
||||
advancedFlash = ((PlayerControllerAi)ai.getController()).getAi().getBooleanProperty(AiProps.FLASH_ENABLE_ADVANCED_LOGIC);
|
||||
}
|
||||
if (source.withFlash(ai) && source.isAura()) {
|
||||
if (advancedFlash) {
|
||||
Game game = ai.getGame();
|
||||
Combat combat = game.getCombat();
|
||||
|
||||
if (combat == null || game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (source.withFlash(ai) && source.isAura() && advancedFlash && !doAdvancedFlashAuraLogic(ai)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (abCost != null) {
|
||||
@@ -134,6 +128,44 @@ public class AttachAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean doAdvancedFlashAuraLogic(Player ai) {
|
||||
Game game = ai.getGame();
|
||||
Combat combat = game.getCombat();
|
||||
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
|
||||
boolean canRespondToStack = false;
|
||||
if (!game.getStack().isEmpty()) {
|
||||
SpellAbility peekSa = game.getStack().peekAbility();
|
||||
Player activator = peekSa.getActivatingPlayer();
|
||||
if (activator != null && activator.isOpponentOf(ai) && peekSa.getApi() != ApiType.DestroyAll &&
|
||||
peekSa.getApi() != ApiType.Destroy) {
|
||||
// TODO: improve this so that the AI predicts how much damage will be dealt to the creature
|
||||
// so that it can try to save it (and won't bother targeting it if it can't be saved)
|
||||
canRespondToStack = true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean useAurasAsTricks = aic.getBooleanProperty(AiProps.FLASH_USE_AURAS_AS_COMBAT_TRICKS);
|
||||
int chanceToCastAtEOT = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_CAST_AT_EOT);
|
||||
int chanceToCastEarly = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_TO_CAST_EARLY);
|
||||
int chanceToRespondToStack = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK);
|
||||
|
||||
boolean hasFloatMana = ai.getManaPool().totalMana() > 0;
|
||||
boolean willDiscardNow = game.getPhaseHandler().is(PhaseType.END_OF_TURN, ai)
|
||||
&& ai.getCardsIn(ZoneType.Hand).size() > ai.getMaxHandSize();
|
||||
boolean willRespondToStack = canRespondToStack && MyRandom.percentTrue(chanceToRespondToStack);
|
||||
boolean willCastEarly = MyRandom.percentTrue(chanceToCastEarly);
|
||||
boolean willCastAtEOT = game.getPhaseHandler().is(PhaseType.END_OF_TURN)
|
||||
&& game.getPhaseHandler().getNextTurn().equals(ai) && MyRandom.percentTrue(chanceToCastAtEOT) || !useAurasAsTricks;
|
||||
|
||||
boolean alternativeConsiderations = hasFloatMana || willDiscardNow || willRespondToStack || willCastAtEOT || willCastEarly;
|
||||
|
||||
if (!alternativeConsiderations && (combat == null || game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acceptable choice.
|
||||
*
|
||||
|
||||
@@ -118,14 +118,12 @@ public class PermanentCreatureAi extends PermanentAi {
|
||||
boolean isOwnEOT = ph.is(PhaseType.END_OF_TURN, ai);
|
||||
boolean isEOTBeforeMyTurn = ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai);
|
||||
boolean isOppDeclareAttackers = ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS) && isOppTurn && ai.getGame().getCombat() != null;
|
||||
boolean isMyDeclareAttackers = ph.is(PhaseType.COMBAT_DECLARE_ATTACKERS, ai) && ai.getGame().getCombat() != null;
|
||||
boolean isMyMain1OrLater = ph.is(PhaseType.MAIN1, ai) || (ph.getPhase().isAfter(PhaseType.MAIN1) && ph.getPlayerTurn().equals(ai));
|
||||
boolean canRespondToStack = false;
|
||||
if (!game.getStack().isEmpty()) {
|
||||
SpellAbility peekSa = game.getStack().peekAbility();
|
||||
Player activator = peekSa.getActivatingPlayer();
|
||||
if (activator != null && activator.isOpponentOf(ai)
|
||||
&& (peekSa.getApi() != ApiType.DestroyAll || peekSa.getApi() == ApiType.Counter)) {
|
||||
if (activator != null && activator.isOpponentOf(ai) && peekSa.getApi() != ApiType.DestroyAll) {
|
||||
canRespondToStack = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user