mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Improve Ward checking
This commit is contained in:
@@ -733,20 +733,6 @@ public class AiController {
|
|||||||
|
|
||||||
AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc.
|
AiPlayDecision canPlay = canPlaySa(sa); // this is the "heaviest" check, which also sets up targets, defines X, etc.
|
||||||
|
|
||||||
// Account for possible Ward after the spell is fully targeted
|
|
||||||
// TODO: ideally, this should be done while targeting, so that a different target can be preferred if the best
|
|
||||||
// one is warded and can't be paid for.
|
|
||||||
if (sa.usesTargeting()) {
|
|
||||||
for (Card tgt : sa.getTargets().getTargetCards()) {
|
|
||||||
if (tgt.hasKeyword(Keyword.WARD)) {
|
|
||||||
int amount = tgt.getKeywordMagnitude(Keyword.WARD);
|
|
||||||
if (amount > 0 && !ComputerUtilCost.canPayCost(sa, player)) {
|
|
||||||
return AiPlayDecision.CantAfford;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sa.getCardState() != null && !sa.getHostCard().isInPlay() && sa.getCardState().getStateName() == CardStateName.Modal) {
|
if (sa.getCardState() != null && !sa.getHostCard().isInPlay() && sa.getCardState().getStateName() == CardStateName.Modal) {
|
||||||
sa.getHostCard().setState(CardStateName.Original, false);
|
sa.getHostCard().setState(CardStateName.Original, false);
|
||||||
}
|
}
|
||||||
@@ -755,6 +741,20 @@ public class AiController {
|
|||||||
return canPlay;
|
return canPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account for possible Ward after the spell is fully targeted
|
||||||
|
// TODO: ideally, this should be done while targeting, so that a different target can be preferred if the best
|
||||||
|
// one is warded and can't be paid for.
|
||||||
|
if (sa.usesTargeting()) {
|
||||||
|
for (Card tgt : sa.getTargets().getTargetCards()) {
|
||||||
|
if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
||||||
|
int amount = tgt.getKeywordMagnitude(Keyword.WARD);
|
||||||
|
if (amount > 0 && !ComputerUtilCost.canPayCost(sa, player)) {
|
||||||
|
return AiPlayDecision.CantAfford;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check if some target raised cost
|
// check if some target raised cost
|
||||||
if (oldCMC > -1) {
|
if (oldCMC > -1) {
|
||||||
int finalCMC = CostAdjustment.adjust(sa.getPayCosts(), sa).getTotalMana().getCMC();
|
int finalCMC = CostAdjustment.adjust(sa.getPayCosts(), sa).getTotalMana().getCMC();
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
final Card source = newSA.getHostCard();
|
final Card source = newSA.getHostCard();
|
||||||
if (newSA.isSpell() && !source.isCopiedSpell()) {
|
if (newSA.isSpell() && !source.isCopiedSpell()) {
|
||||||
newSA.setHostCard(game.getAction().moveToStack(source, sa));
|
newSA.setHostCard(game.getAction().moveToStack(source, newSA));
|
||||||
|
|
||||||
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
|
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
|
||||||
if (!CharmEffect.makeChoices(newSA)) {
|
if (!CharmEffect.makeChoices(newSA)) {
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ public class ComputerUtilCost {
|
|||||||
// Ward - will be accounted for when rechecking a targeted ability
|
// Ward - will be accounted for when rechecking a targeted ability
|
||||||
if (sa.usesTargeting()) {
|
if (sa.usesTargeting()) {
|
||||||
for (Card tgt : sa.getTargets().getTargetCards()) {
|
for (Card tgt : sa.getTargets().getTargetCards()) {
|
||||||
if (tgt.hasKeyword(Keyword.WARD)) {
|
if (tgt.hasKeyword(Keyword.WARD) && tgt.getController().isOpponentOf(sa.getHostCard().getController())) {
|
||||||
extraManaNeeded += tgt.getKeywordMagnitude(Keyword.WARD);
|
extraManaNeeded += tgt.getKeywordMagnitude(Keyword.WARD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -492,4 +492,10 @@ public class CountersMoveAi extends SpellAbilityAi {
|
|||||||
// like keeping the last counter on a 0/0 creature
|
// like keeping the last counter on a 0/0 creature
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, Map<String, Object> params) {
|
||||||
|
// TODO
|
||||||
|
return super.chooseCounterType(options, sa, params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
|||||||
sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList));
|
sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type.matches("Any")) {
|
} else if (type.matches("Any")) {
|
||||||
// variable amount for Hex Parasite
|
// variable amount for Hex Parasite
|
||||||
int amount;
|
int amount;
|
||||||
@@ -264,7 +263,6 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
|||||||
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiList));
|
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(aiList));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type.equals("P1P1")) {
|
} else if (type.equals("P1P1")) {
|
||||||
// no special amount for that one yet
|
// no special amount for that one yet
|
||||||
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
|
||||||
@@ -298,7 +296,6 @@ public class CountersRemoveAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type.equals("TIME")) {
|
} else if (type.equals("TIME")) {
|
||||||
int amount;
|
int amount;
|
||||||
boolean xPay = false;
|
boolean xPay = false;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class PumpAi extends PumpAiBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN);
|
return SpellAbilityAi.isSorcerySpeed(sa) || (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN));
|
||||||
} else if (logic.equals("Aristocrat")) {
|
} else if (logic.equals("Aristocrat")) {
|
||||||
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
|
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
|
||||||
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
|
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ public final class GameActionUtil {
|
|||||||
lkicheck = true;
|
lkicheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 601.3e
|
||||||
if (lkicheck) {
|
if (lkicheck) {
|
||||||
// double freeze tracker, so it doesn't update view
|
// double freeze tracker, so it doesn't update view
|
||||||
game.getTracker().freeze();
|
game.getTracker().freeze();
|
||||||
@@ -377,6 +378,7 @@ public final class GameActionUtil {
|
|||||||
lkicheck = true;
|
lkicheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 601.3e
|
||||||
if (lkicheck) {
|
if (lkicheck) {
|
||||||
// double freeze tracker, so it doesn't update view
|
// double freeze tracker, so it doesn't update view
|
||||||
game.getTracker().freeze();
|
game.getTracker().freeze();
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ public class TriggerTokenCreated extends Trigger {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
|
||||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player);
|
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.Card);
|
||||||
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc}
|
/** {@inheritDoc}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Human Warrior
|
|||||||
PT:0/0
|
PT:0/0
|
||||||
K:Vigilance
|
K:Vigilance
|
||||||
K:etbCounter:P1P1:4
|
K:etbCounter:P1P1:4
|
||||||
A:AB$ Pump | Cost$ 1 BG BG | ValidTgts$ Creature | TgtPrompt$ Select target creature to remove a +1/+1 counter from | SubAbility$ DBMove | StackDescription$ None | SpellDescription$ Move a +1/+1 counter from target creature onto a second target creature.
|
A:AB$ Pump | Cost$ 1 BG BG | ValidTgts$ Creature | TgtPrompt$ Select target creature to remove a +1/+1 counter from | AILogic$ MoveCounter | SubAbility$ DBMove | StackDescription$ None | SpellDescription$ Move a +1/+1 counter from target creature onto a second target creature.
|
||||||
SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Creature | TgtPrompt$ Select target creature to move a +1/+1 counter to | TargetUnique$ True | CounterType$ P1P1 | CounterNum$ 1
|
SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Creature | TgtPrompt$ Select target creature to move a +1/+1 counter to | TargetUnique$ True | CounterType$ P1P1 | CounterNum$ 1
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/daghatar_the_adamant.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/daghatar_the_adamant.jpg
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ Types:Land
|
|||||||
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||||
A:AB$ Pump | Cost$ 1 T | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | SubAbility$ DBMove | SorcerySpeed$ True | StackDescription$ SpellDescription | SpellDescription$ Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery.
|
A:AB$ Pump | Cost$ 1 T | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | SubAbility$ DBMove | SorcerySpeed$ True | StackDescription$ SpellDescription | SpellDescription$ Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery.
|
||||||
SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent to move counter to | TargetUnique$ True | CounterType$ Any | CounterNum$ 1 | StackDescription$ None
|
SVar:DBMove:DB$ MoveCounter | Source$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent to move counter to | TargetUnique$ True | CounterType$ Any | CounterNum$ 1 | StackDescription$ None
|
||||||
|
AI:RemoveDeck:All
|
||||||
Oracle:{T}: Add {C}.\n{1}, {T}: Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery.
|
Oracle:{T}: Add {C}.\n{1}, {T}: Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery.
|
||||||
|
|||||||
@@ -19,5 +19,4 @@ T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescripti
|
|||||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment defending player controls
|
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment defending player controls
|
||||||
K:Nightbound
|
K:Nightbound
|
||||||
SVar:HasAttackEffect:TRUE
|
SVar:HasAttackEffect:TRUE
|
||||||
Oracle:{1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment.
|
Oracle:{1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment.\nWhenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)
|
||||||
Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user