mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Merge branch 'moraug' into 'master'
Moraug: improve AI See merge request core-developers/forge!5878
This commit is contained in:
@@ -1622,6 +1622,7 @@ public class AiController {
|
||||
Map<String, String> params = t.getMapParams();
|
||||
if ("ChangesZone".equals(params.get("Mode"))
|
||||
&& params.containsKey("ValidCard")
|
||||
&& (!params.containsKey("AILogic") || !params.get("AILogic").equals("SafeToHold"))
|
||||
&& !params.get("ValidCard").contains("nonLand")
|
||||
&& ((params.get("ValidCard").contains("Land")) || (params.get("ValidCard").contains("Permanent")))
|
||||
&& "Battlefield".equals(params.get("Destination"))) {
|
||||
|
||||
@@ -14,8 +14,7 @@ public class ChooseEvenOddAi extends SpellAbilityAi {
|
||||
if (!sa.hasParam("AILogic")) {
|
||||
return false;
|
||||
}
|
||||
TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
sa.resetTargets();
|
||||
Player opp = AiAttackController.choosePreferredDefenderPlayer(aiPlayer);
|
||||
if (sa.canTarget(opp)) {
|
||||
@@ -34,4 +33,3 @@ public class ChooseEvenOddAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,7 @@ public class ChooseNumberAi extends SpellAbilityAi {
|
||||
return ownCreatureCount > oppMaxCreatureCount + 2 || ownCreatureCount < Math.min(oppMaxCreatureCount, maxChoiceLimit);
|
||||
}
|
||||
|
||||
TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
sa.resetTargets();
|
||||
Player opp = AiAttackController.choosePreferredDefenderPlayer(aiPlayer);
|
||||
if (sa.canTarget(opp)) {
|
||||
|
||||
@@ -52,8 +52,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
sa.resetTargets();
|
||||
Player opp = AiAttackController.choosePreferredDefenderPlayer(ai);
|
||||
if (sa.canTarget(opp)) {
|
||||
|
||||
@@ -58,8 +58,7 @@ public class CopySpellAbilityAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
// Filter AI-specific targets if provided
|
||||
if ("OnlyOwned".equals(sa.getParam("AITgts"))) {
|
||||
if (!top.getActivatingPlayer().equals(aiPlayer)) {
|
||||
|
||||
@@ -63,8 +63,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
final SpellAbility topSA = ComputerUtilAbility.getTopSpellAbilityOnStack(game, sa);
|
||||
if (!CardFactoryUtil.isCounterableBy(topSA.getHostCard(), sa) || topSA.getActivatingPlayer() == ai
|
||||
|| ai.getAllies().contains(topSA.getActivatingPlayer())) {
|
||||
@@ -246,10 +245,9 @@ public class CounterAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final Game game = ai.getGame();
|
||||
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
if (game.getStack().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,7 @@ public class DebuffAi extends SpellAbilityAi {
|
||||
@Override
|
||||
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
||||
if (!sa.usesTargeting()) {
|
||||
// TODO - copied from AF_Pump.pumpDrawbackAI() - what should be
|
||||
// here?
|
||||
// TODO - copied from AF_Pump.pumpDrawbackAI() - what should be here?
|
||||
} else {
|
||||
return debuffTgtAI(ai, sa, sa.hasParam("Keywords") ? Arrays.asList(sa.getParam("Keywords").split(" & ")) : null, false);
|
||||
}
|
||||
|
||||
@@ -57,19 +57,20 @@ public class PumpAllAi extends PumpAiBase {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final Player opp = ai.getStrongestOpponent();
|
||||
|
||||
if (tgt != null && sa.canTarget(opp) && sa.isCurse()) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(opp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tgt != null && sa.canTarget(ai) && !sa.isCurse()) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(ai);
|
||||
return true;
|
||||
if (sa.usesTargeting()) {
|
||||
if (sa.canTarget(opp) && sa.isCurse()) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(opp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sa.canTarget(ai) && !sa.isCurse()) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(ai);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
final int power = AbilityUtils.calculateAmount(source, sa.getParam("NumAtt"), sa);
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TapAllAi extends SpellAbilityAi {
|
||||
// or during upkeep/begin combat?
|
||||
|
||||
final Card source = sa.getHostCard();
|
||||
final Player opp = ai.getWeakestOpponent();
|
||||
final Player opp = ai.getStrongestOpponent();
|
||||
final Game game = ai.getGame();
|
||||
|
||||
if (game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_BEGIN)) {
|
||||
|
||||
@@ -28,8 +28,7 @@ public class TwoPilesAi extends SpellAbilityAi {
|
||||
|
||||
final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai);
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
if (sa.usesTargeting()) {
|
||||
sa.resetTargets();
|
||||
if (sa.canTarget(opp)) {
|
||||
sa.getTargets().add(opp);
|
||||
|
||||
@@ -48,7 +48,6 @@ public class UnattachAllAi extends SpellAbilityAi {
|
||||
return chance;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)
|
||||
*/
|
||||
@@ -57,8 +56,7 @@ public class UnattachAllAi extends SpellAbilityAi {
|
||||
final Card card = sa.getHostCard();
|
||||
// Check if there are any valid targets
|
||||
List<GameObject> targets = new ArrayList<>();
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt == null) {
|
||||
if (!sa.usesTargeting()) {
|
||||
targets = AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam("Defined"), sa);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,11 +125,11 @@ public class UntapAi extends SpellAbilityAi {
|
||||
private static boolean untapPrefTargeting(final Player ai, final SpellAbility sa, final boolean mandatory) {
|
||||
final Card source = sa.getHostCard();
|
||||
|
||||
Player targetController = ai;
|
||||
|
||||
final PlayerCollection targetController = new PlayerCollection();
|
||||
if (sa.isCurse()) {
|
||||
// TODO search through all opponents, may need to check if different controllers allowed
|
||||
targetController = AiAttackController.choosePreferredDefenderPlayer(ai);
|
||||
targetController.addAll(ai.getOpponents());
|
||||
} else {
|
||||
targetController.add(ai);
|
||||
}
|
||||
|
||||
CardCollection list = CardLists.getTargetableCards(targetController.getCardsIn(ZoneType.Battlefield), sa);
|
||||
|
||||
@@ -1689,10 +1689,6 @@ public class AbilityUtils {
|
||||
// accept straight numbers
|
||||
if (l[0].startsWith("Number$")) {
|
||||
final String number = l[0].substring(7);
|
||||
if (number.equals("ChosenNumber")) { // TODO remove in favor of Count ChosenNumber
|
||||
int x = c.getChosenNumber() == null ? 0 : c.getChosenNumber();
|
||||
return doXMath(x, expr, c, ctb);
|
||||
}
|
||||
return doXMath(Integer.parseInt(number), expr, c, ctb);
|
||||
}
|
||||
|
||||
|
||||
@@ -272,8 +272,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
sb.append(".");
|
||||
} else if (origin.equals("Battlefield")) {
|
||||
// TODO Expand on this Description as more cards use it
|
||||
// for the non-targeted SAs when you choose what is returned on
|
||||
// resolution
|
||||
// for the non-targeted SAs when you choose what is returned on resolution
|
||||
sb.append("Return ").append(num).append(" ").append(type).append(" card(s) ");
|
||||
sb.append(" to your ").append(destination);
|
||||
}
|
||||
@@ -361,8 +360,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
sb.append(fromGraveyard);
|
||||
}
|
||||
|
||||
// this needs to be zero indexed. Top = 0, Third = 2, -1 =
|
||||
// Bottom
|
||||
// this needs to be zero indexed. Top = 0, Third = 2, -1 = Bottom
|
||||
final int libraryPosition = sa.hasParam("LibraryPosition") ? AbilityUtils.calculateAmount(host, sa.getParam("LibraryPosition"), sa) : 0;
|
||||
|
||||
if (libraryPosition == -1) {
|
||||
|
||||
@@ -9,7 +9,7 @@ SVar:DBShuffle:DB$ Shuffle | Defined$ ParentTarget | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:TargetedPlayer$CardsInLibrary
|
||||
SVar:Y:Remembered$Valid Card.NamedCard
|
||||
SVar:Z:Number$ChosenNumber
|
||||
SVar:Z:Count$ChosenNumber
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mindblaze.jpg
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Minotaur Warrior
|
||||
PT:6/6
|
||||
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ AffectedX | Description$ Each creature you control gets +1/+0 for each time it has attacked this turn.
|
||||
SVar:AffectedX:Count$CardNumAttacksThisTurn
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | PlayerTurn$ True | Phase$ Main1,Main2 | Execute$ TrigAddPhase | TriggerDescription$ Landfall - Whenever a land enters the battlefield under your control, if it's your main phase, there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | AILogic$ SafeToHold | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | PlayerTurn$ True | Phase$ Main1,Main2 | Execute$ TrigAddPhase | TriggerDescription$ Landfall - Whenever a land enters the battlefield under your control, if it's your main phase, there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control.
|
||||
SVar:TrigAddPhase:DB$ AddPhase | ExtraPhase$ Combat | ConditionPhases$ Main1,Main2 | ExtraPhaseDelayedTrigger$ DelTrigUntap | ExtraPhaseDelayedTriggerExcute$ TrigUntapAll
|
||||
SVar:DelTrigUntap:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerDescription$ At the beginning of that combat, untap all creatures you control.
|
||||
SVar:TrigUntapAll:DB$ UntapAll | ValidCards$ Creature.YouCtrl
|
||||
|
||||
@@ -5,7 +5,7 @@ PT:2/2
|
||||
K:ETBReplacement:Other:ChooseNumber
|
||||
SVar:ChooseNumber:DB$ ChooseNumber | Defined$ You | SpellDescription$ As CARDNAME enters the battlefield, choose a number.
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonCreature+cmcEQX | Description$ Noncreature spells with mana value equal to the chosen number can't be cast.
|
||||
SVar:X:Number$ChosenNumber
|
||||
SVar:X:Count$ChosenNumber
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/sanctum_prelate.jpg
|
||||
Oracle:As Sanctum Prelate enters the battlefield, choose a number.\nNoncreature spells with mana value equal to the chosen number can't be cast.
|
||||
|
||||
@@ -10,7 +10,7 @@ SVar:IncrementLoss:DB$ StoreSVar | SVar$ Loss | Type$ CountSVar | Expression$ Lo
|
||||
SVar:SetFilpsDone:DB$ StoreSVar | SVar$ FlipsDone | Type$ CountSVar | Expression$ TimesToFlip
|
||||
# Draw Cards
|
||||
SVar:DrawIfWin:DB$ Draw | Defined$ You | NumCards$ CardsToDraw | ConditionCheckSVar$ Loss | ConditionSVarCompare$ EQ0
|
||||
SVar:TimesToFlip:Number$ChosenNumber
|
||||
SVar:TimesToFlip:Count$ChosenNumber
|
||||
SVar:FlipsDone:Number$0
|
||||
SVar:Loss:Number$0
|
||||
SVar:CardsToDraw:Count$ChosenNumber/Times.2
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Sorcery
|
||||
A:SP$ ChooseNumber | Cost$ 3 B R | SubAbility$ DBVoidDestroyAll | SpellDescription$ Choose a number. Destroy all artifacts and creatures with mana value equal to that number. Then target player reveals their hand and discards all nonland cards with mana value equal to the number.
|
||||
SVar:DBVoidDestroyAll:DB$ DestroyAll | ValidCards$ Artifact.cmcEQX,Creature.cmcEQX | SubAbility$ DBVoidRevealDiscard
|
||||
SVar:DBVoidRevealDiscard:DB$ Discard | ValidTgts$ Player | TgtPrompt$ Select target player | Mode$ RevealDiscardAll | DiscardValid$ Card.nonLand+cmcEQX
|
||||
SVar:X:Number$ChosenNumber
|
||||
SVar:X:Count$ChosenNumber
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/void.jpg
|
||||
Oracle:Choose a number. Destroy all artifacts and creatures with mana value equal to that number. Then target player reveals their hand and discards all nonland cards with mana value equal to the number.
|
||||
|
||||
@@ -11,7 +11,7 @@ SVar:DBDamage:DB$ DealDamage | NumDmg$ Damage | Defined$ You
|
||||
SVar:DBEffect:DB$ Effect | StaticAbilities$ MayPlay | Stackable$ False | ConditionCheckSVar$ Y | ConditionSVarCompare$ EQ5 | SubAbility$ DBCleanup
|
||||
SVar:MayPlay:Mode$ Continuous | EffectZone$ Command | Affected$ Card.nonLand+YouOwn | MayPlay$ True | MayPlayWithoutManaCost$ True | AffectedZone$ Hand | Description$ You may cast spells from your hand this turn without paying their mana costs.
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Number$ChosenNumber
|
||||
SVar:X:Count$ChosenNumber
|
||||
SVar:Y:Count$RememberedNumber
|
||||
SVar:Damage:SVar$Losses/Times.2
|
||||
Oracle:Flying\nWhenever Yusri, Fortune's Flame attacks, choose a number between 1 and 5. Flip that many coins. For each flip you win, draw a card. For each flip you lose, Yusri deals 2 damage to you. If you won five flips this way, you may cast spells from your hand this turn without paying their mana costs.
|
||||
|
||||
Reference in New Issue
Block a user