- Move the chance-based logic out of AiController, implement several AI logic flags for cards.

This commit is contained in:
Agetian
2018-11-27 11:34:41 +03:00
parent ed556ba2a7
commit 2c106e9f04
3 changed files with 26 additions and 27 deletions

View File

@@ -1400,29 +1400,17 @@ public class AiController {
final boolean topOwnedByAI = top != null && top.getActivatingPlayer().equals(player); final boolean topOwnedByAI = top != null && top.getActivatingPlayer().equals(player);
if (topOwnedByAI) { if (topOwnedByAI) {
// AI's own spell: should probably let my stuff resolve first, but may want to copy the SA or respond to it
// in a scripted timed fashion.
final boolean mustRespond = top.hasParam("AIRespondsToOwnAbility"); final boolean mustRespond = top.hasParam("AIRespondsToOwnAbility");
final int chanceToCopy = getIntProperty(AiProps.CHANCE_TO_COPY_OWN_SPELL_WHILE_ON_STACK);
if (!mustRespond) { if (!mustRespond) {
if (chanceToCopy == 0) { saList = ComputerUtilAbility.getSpellAbilities(cards, player); // get the SA list early to check for copy SAs
// The AI profile asks not to respond to own spells on stack (MustRespond is a script-defined exception). if (ComputerUtilAbility.getFirstCopySASpell(saList) == null) {
// Nothing to copy the spell with, so do nothing.
return null; return null;
} else {
saList = ComputerUtilAbility.getSpellAbilities(cards, player); // get the SA list early to check for copy SAs
if (ComputerUtilAbility.getFirstCopySASpell(saList) == null) {
// The AI currently responds to its own spell on stack only with copy spells (e.g. Twincast).
// If there are none, don't respond.
return null;
}
} }
} }
// if top of the stack is owned by me, probably should let my stuff resolve unless I want to copy my spell on stack
// or if there are special considerations (e.g. scripted response for Sensei's Divining Top)
boolean wantToRespondToStack = mustRespond || MyRandom.percentTrue(chanceToCopy);
if (!wantToRespondToStack) {
return null;
}
} }
if (!game.getStack().isEmpty()) { if (!game.getStack().isEmpty()) {

View File

@@ -1,9 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.AiPlayDecision; import forge.ai.*;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -12,6 +9,7 @@ import forge.game.spellability.AbilityActivated;
import forge.game.spellability.Spell; import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.util.MyRandom;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -21,14 +19,27 @@ public class CopySpellAbilityAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
Game game = aiPlayer.getGame(); Game game = aiPlayer.getGame();
if (game.getStack().isEmpty()) { final int chance = ((PlayerControllerAi)aiPlayer.getController()).getAi().getIntProperty(AiProps.CHANCE_TO_COPY_OWN_SPELL_WHILE_ON_STACK);
return sa.isMandatory(); // FIXME: Are mandatory activations possible in the canPlayAI code path?
if (game.getStack().isEmpty()
|| (!MyRandom.percentTrue(chance) && !"AlwaysIfViable".equals(sa.getParam("AILogic")))
&& !"OnceIfViable".equals(sa.getParam("AILogic"))) {
return false;
}
if ("OnceIfViable".equals(sa.getParam("AILogic"))) {
if (AiCardMemory.isRememberedCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ACTIVATED_THIS_TURN)) {
return false;
}
} }
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null) { if (tgt != null) {
final SpellAbility top = game.getStack().peekAbility(); final SpellAbility top = game.getStack().peekAbility();
if (top.getApi() == ApiType.CopySpellAbility) { if (top.isWrapper() || !(top instanceof SpellAbility || top instanceof AbilityActivated)) {
// Should even try with triggered or wrapped abilities first, will crash
return false;
} else if (top.getApi() == ApiType.CopySpellAbility) {
// Don't try to copy a copy ability, too complex for the AI to handle // Don't try to copy a copy ability, too complex for the AI to handle
return false; return false;
} }
@@ -47,6 +58,7 @@ public class CopySpellAbilityAi extends SpellAbilityAi {
} }
if (decision == AiPlayDecision.WillPlay) { if (decision == AiPlayDecision.WillPlay) {
sa.getTargets().add(top); sa.getTargets().add(top);
AiCardMemory.rememberCard(aiPlayer, sa.getHostCard(), AiCardMemory.MemorySet.ACTIVATED_THIS_TURN);
return true; return true;
} }
} }

View File

@@ -2,8 +2,7 @@ Name:Izzet Guildmage
ManaCost:UR UR ManaCost:UR UR
Types:Creature Human Wizard Types:Creature Human Wizard
PT:2/2 PT:2/2
A:AB$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant.YouCtrl+cmcLE2 | TargetType$ Spell | SpellDescription$ Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy. A:AB$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
A:AB$ CopySpellAbility | Cost$ 2 R | ValidTgts$ Sorcery.YouCtrl+cmcLE2 | TargetType$ Spell | SpellDescription$ Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy. A:AB$ CopySpellAbility | Cost$ 2 R | ValidTgts$ Sorcery.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_guildmage.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_guildmage.jpg
Oracle:{2}{U}: Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.\n{2}{R}: Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy. Oracle:{2}{U}: Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.\n{2}{R}: Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy.