mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 09:48:02 +00:00
GameActionUtil: store OptionalKeywordAmount in CastSA (#5853)
* GameActionUtil: store OptionalKeywordAmount in CastSA * ~ rename and make into a Table
This commit is contained in:
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import forge.card.MagicColor;
|
||||
@@ -41,7 +40,6 @@ import forge.game.spellability.*;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.staticability.StaticAbilityAlternativeCost;
|
||||
import forge.game.staticability.StaticAbilityLayer;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
@@ -572,112 +570,87 @@ public final class GameActionUtil {
|
||||
for (KeywordInterface ki : host.getKeywords()) {
|
||||
final String o = ki.getOriginal();
|
||||
if (o.startsWith("Casualty")) {
|
||||
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
|
||||
if (tr != null) {
|
||||
String n = o.split(":")[1];
|
||||
if (host.wasCast() && n.equals("X")) {
|
||||
CardCollectionView creatures = activator.getCreaturesInPlay();
|
||||
int max = Aggregates.max(creatures, Card::getNetPower);
|
||||
n = Integer.toString(pc.chooseNumber(sa, "Choose X for Casualty", 0, max));
|
||||
}
|
||||
final String casualtyCost = "Sac<1/Creature.powerGE" + n + "/creature with power " + n +
|
||||
" or greater>";
|
||||
final Cost cost = new Cost(casualtyCost, false);
|
||||
String str = "Pay for Casualty? " + cost.toSimpleString();
|
||||
boolean v = pc.addKeywordCost(sa, cost, ki, str);
|
||||
String n = o.split(":")[1];
|
||||
if (host.wasCast() && n.equals("X")) {
|
||||
CardCollectionView creatures = activator.getCreaturesInPlay();
|
||||
int max = Aggregates.max(creatures, Card::getNetPower);
|
||||
n = Integer.toString(pc.chooseNumber(sa, "Choose X for Casualty", 0, max));
|
||||
}
|
||||
final String casualtyCost = "Sac<1/Creature.powerGE" + n + "/creature with power " + n +
|
||||
" or greater>";
|
||||
final Cost cost = new Cost(casualtyCost, false);
|
||||
String str = "Pay for Casualty? " + cost.toSimpleString();
|
||||
boolean v = pc.addKeywordCost(sa, cost, ki, str);
|
||||
|
||||
tr.setSVar("CasualtyPaid", v ? "1" : "0");
|
||||
tr.getOverridingAbility().setSVar("CasualtyPaid", v ? "1" : "0");
|
||||
tr.setSVar("Casualty", v ? n : "0");
|
||||
tr.getOverridingAbility().setSVar("Casualty", v ? n : "0");
|
||||
|
||||
if (v) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
if (v) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
result.setOptionalKeywordAmount(ki, Integer.valueOf(n));
|
||||
}
|
||||
} else if (o.equals("Conspire")) {
|
||||
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
|
||||
if (tr != null) {
|
||||
final String conspireCost = "tapXType<2/Creature.SharesColorWith/" +
|
||||
"creature that shares a color with " + host.getName() + ">";
|
||||
final Cost cost = new Cost(conspireCost, false);
|
||||
String str = "Pay for Conspire? " + cost.toSimpleString();
|
||||
final String conspireCost = "tapXType<2/Creature.SharesColorWith/" +
|
||||
"creature that shares a color with " + host.getName() + ">";
|
||||
final Cost cost = new Cost(conspireCost, false);
|
||||
String str = "Pay for Conspire? " + cost.toSimpleString();
|
||||
|
||||
boolean v = pc.addKeywordCost(sa, cost, ki, str);
|
||||
tr.setSVar("Conspire", v ? "1" : "0");
|
||||
|
||||
if (v) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
if (pc.addKeywordCost(sa, cost, ki, str)) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
result.setOptionalKeywordAmount(ki, 1);
|
||||
reset = true;
|
||||
}
|
||||
} else if (o.startsWith("Offspring")) {
|
||||
String[] k = o.split(":");
|
||||
final Cost cost = new Cost(k[1], false);
|
||||
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
|
||||
if (tr != null) {
|
||||
String str = "Pay for Offspring? " + cost.toSimpleString();
|
||||
String str = "Pay for Offspring? " + cost.toSimpleString();
|
||||
|
||||
boolean v = pc.addKeywordCost(sa, cost, ki, str);
|
||||
tr.setSVar("Offspring", v ? "1" : "0");
|
||||
boolean v = pc.addKeywordCost(sa, cost, ki, str);
|
||||
|
||||
if (v) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
if (v) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
result.setOptionalKeywordAmount(ki, 1);
|
||||
}
|
||||
} else if (o.startsWith("Replicate")) {
|
||||
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
|
||||
if (tr != null) {
|
||||
String costStr = o.split(":")[1];
|
||||
final Cost cost = new Cost(costStr, false);
|
||||
String costStr = o.split(":")[1];
|
||||
final Cost cost = new Cost(costStr, false);
|
||||
|
||||
String str = "Choose Amount for Replicate: " + cost.toSimpleString();
|
||||
String str = "Choose Amount for Replicate: " + cost.toSimpleString();
|
||||
|
||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||
|
||||
tr.setSVar("ReplicateAmount", String.valueOf(v));
|
||||
tr.getOverridingAbility().setSVar("ReplicateAmount", String.valueOf(v));
|
||||
|
||||
for (int i = 0; i < v; i++) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
for (int i = 0; i < v; i++) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
}
|
||||
result.setOptionalKeywordAmount(ki, v);
|
||||
} else if (o.startsWith("Squad")) {
|
||||
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
|
||||
if (tr != null) {
|
||||
String costStr = o.split(":")[1];
|
||||
final Cost cost = new Cost(costStr, false);
|
||||
String costStr = o.split(":")[1];
|
||||
final Cost cost = new Cost(costStr, false);
|
||||
|
||||
String str = "Choose amount for Squad: " + cost.toSimpleString();
|
||||
String str = "Choose amount for Squad: " + cost.toSimpleString();
|
||||
|
||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||
|
||||
tr.setSVar("SquadAmount", String.valueOf(v));
|
||||
tr.getOverridingAbility().setSVar("SquadAmount", String.valueOf(v));
|
||||
|
||||
for (int i = 0; i < v; i++) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
for (int i = 0; i < v; i++) {
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
result.getPayCosts().add(cost);
|
||||
reset = true;
|
||||
}
|
||||
result.setOptionalKeywordAmount(ki, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1893,6 +1893,13 @@ public class AbilityUtils {
|
||||
}
|
||||
return doXMath(v, expr, c, ctb);
|
||||
}
|
||||
if (sq[0].equals("hasOptionalKeywordAmount")) {
|
||||
return doXMath(c.getCastSA() != null && c.getCastSA().hasOptionalKeywordAmount(ctb.getKeyword()) ? 1 : 0, expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("OptionalKeywordAmount")) {
|
||||
return doXMath(c.getCastSA() != null ? c.getCastSA().getOptionalKeywordAmount(ctb.getKeyword()) : 0, expr, c, ctb);
|
||||
}
|
||||
|
||||
// Count$DevotionDual.<color name>.<color name>
|
||||
// Count$Devotion.<color name>
|
||||
|
||||
@@ -907,13 +907,16 @@ public class CardFactoryUtil {
|
||||
String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True";
|
||||
String[] k = keyword.split(":");
|
||||
if (k.length > 2) {
|
||||
abString = abString + " | " + k[2];
|
||||
abString += " | " + k[2];
|
||||
}
|
||||
|
||||
final Trigger casualtyTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
|
||||
casualtyTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card));
|
||||
casualtyTrigger.setSVar("Casualty", "0");
|
||||
casualtyTrigger.setSVar("CasualtyPaid", "0");
|
||||
SpellAbility sa = AbilityFactory.getAbility(abString, card);
|
||||
sa.setSVar("CasualtyPaid", "Count$hasOptionalKeywordAmount");
|
||||
sa.setSVar("Casualty", "Count$OptionalKeywordAmount");
|
||||
casualtyTrigger.setOverridingAbility(sa);
|
||||
casualtyTrigger.setSVar("CasualtyPaid", "Count$hasOptionalKeywordAmount");
|
||||
casualtyTrigger.setSVar("Casualty", "Count$OptionalKeywordAmount");
|
||||
|
||||
inst.addTrigger(casualtyTrigger);
|
||||
} else if (keyword.startsWith("Chapter")) {
|
||||
@@ -960,7 +963,7 @@ public class CardFactoryUtil {
|
||||
|
||||
final Trigger conspireTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
|
||||
conspireTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card));
|
||||
conspireTrigger.setSVar("Conspire", "0");
|
||||
conspireTrigger.setSVar("Conspire", "Count$OptionalKeywordAmount");
|
||||
|
||||
inst.addTrigger(conspireTrigger);
|
||||
} else if (keyword.startsWith("Cumulative upkeep")) {
|
||||
@@ -1585,14 +1588,14 @@ public class CardFactoryUtil {
|
||||
costDesc = "—" + costDesc;
|
||||
}
|
||||
|
||||
final String trigStr = "Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self+linkedCastTrigger | CheckSVar$ Offspring | Secondary$ True " +
|
||||
final String trigStr = "Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ Offspring | Secondary$ True " +
|
||||
"| TriggerDescription$ Offspring " + costDesc + " (" + inst.getReminderText() + ")";
|
||||
|
||||
final String effect = "DB$ CopyPermanent | Defined$ TriggeredCardLKICopy | NumCopies$ 1 | SetPower$ 1 | SetToughness$ 1";
|
||||
|
||||
final Trigger trigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
|
||||
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
|
||||
trigger.setSVar("Offspring", "0");
|
||||
trigger.setSVar("Offspring", "Count$OptionalKeywordAmount");
|
||||
|
||||
inst.addTrigger(trigger);
|
||||
} else if (keyword.startsWith("Partner:")) {
|
||||
@@ -1743,9 +1746,9 @@ public class CardFactoryUtil {
|
||||
|
||||
final Trigger replicateTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
|
||||
final SpellAbility replicateAbility = AbilityFactory.getAbility(abString, card);
|
||||
replicateAbility.setSVar("ReplicateAmount", "0");
|
||||
replicateAbility.setSVar("ReplicateAmount", "Count$OptionalKeywordAmount");
|
||||
replicateTrigger.setOverridingAbility(replicateAbility);
|
||||
replicateTrigger.setSVar("ReplicateAmount", "0");
|
||||
replicateTrigger.setSVar("ReplicateAmount", "Count$OptionalKeywordAmount");
|
||||
inst.addTrigger(replicateTrigger);
|
||||
} else if (keyword.startsWith("Ripple")) {
|
||||
final String[] k = keyword.split(":");
|
||||
@@ -1825,9 +1828,9 @@ public class CardFactoryUtil {
|
||||
|
||||
final Trigger squadTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
|
||||
final SpellAbility squadAbility = AbilityFactory.getAbility(abString, card);
|
||||
squadAbility.setSVar("SquadAmount", "0");
|
||||
squadAbility.setSVar("SquadAmount", "Count$OptionalKeywordAmount");
|
||||
squadTrigger.setOverridingAbility(squadAbility);
|
||||
squadTrigger.setSVar("SquadAmount", "0");
|
||||
squadTrigger.setSVar("SquadAmount", "Count$OptionalKeywordAmount");
|
||||
inst.addTrigger(squadTrigger);
|
||||
} else if (keyword.equals("Storm")) {
|
||||
final String actualTrigger = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerZones$ Stack | Secondary$ True"
|
||||
|
||||
@@ -20,7 +20,6 @@ import forge.game.combat.AttackRequirement;
|
||||
import forge.game.combat.AttackingBand;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.mana.Mana;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.OptionalCost;
|
||||
@@ -1801,25 +1800,6 @@ public class CardProperty {
|
||||
if (AbilityUtils.isUnlinkedFromCastSA(spellAbility, card)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("linkedCastTrigger")) {
|
||||
if (card.getCastSA() == null) {
|
||||
return false;
|
||||
}
|
||||
List<Card> spellCast = game.getStack().getSpellsCastThisTurn();
|
||||
int idx = spellCast.lastIndexOf(source);
|
||||
if (idx == -1) {
|
||||
return false;
|
||||
}
|
||||
boolean found = false;
|
||||
for (KeywordInterface kw: spellCast.get(idx).getUnhiddenKeywords()) {
|
||||
if (!Collections.disjoint(kw.getTriggers(), spellAbility.getKeyword().getTriggers())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("kicked")) {
|
||||
// CR 607.2i check cost is linked
|
||||
if (AbilityUtils.isUnlinkedFromCastSA(spellAbility, card)) {
|
||||
|
||||
@@ -127,6 +127,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
private List<Object> triggerRemembered = Lists.newArrayList();
|
||||
|
||||
private AlternativeCost altCost = null;
|
||||
private EnumSet<OptionalCost> optionalCosts = EnumSet.noneOf(OptionalCost.class);
|
||||
private Table<Keyword, Pair<Long, Long>, Integer> optionalKeywordAmount = HashBasedTable.create();
|
||||
|
||||
private boolean aftermath = false;
|
||||
|
||||
@@ -166,7 +168,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
private boolean isCastFromPlayEffect = false;
|
||||
|
||||
private EnumSet<OptionalCost> optionalCosts = EnumSet.noneOf(OptionalCost.class);
|
||||
private TargetRestrictions targetRestrictions;
|
||||
private TargetChoices targetChosen = new TargetChoices();
|
||||
|
||||
@@ -1196,6 +1197,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
clone.manaPart = new AbilityManaPart(clone, mapParams);
|
||||
}
|
||||
|
||||
clone.optionalKeywordAmount = HashBasedTable.create(optionalKeywordAmount);
|
||||
|
||||
// need to copy the damage tables
|
||||
if (damageMap != null) {
|
||||
clone.damageMap = new CardDamageMap(damageMap);
|
||||
@@ -2594,4 +2597,21 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
public boolean isCounterableBy(SpellAbility sa) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasOptionalKeywordAmount(KeywordInterface kw) {
|
||||
return this.optionalKeywordAmount.contains(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId()));
|
||||
}
|
||||
public boolean hasOptionalKeywordAmount(Keyword kw) {
|
||||
return this.optionalKeywordAmount.containsRow(kw);
|
||||
}
|
||||
public Set<Keyword> getOptionalKeywords() {
|
||||
return this.optionalKeywordAmount.rowKeySet();
|
||||
}
|
||||
|
||||
public int getOptionalKeywordAmount(KeywordInterface kw) {
|
||||
return ObjectUtils.firstNonNull(this.optionalKeywordAmount.get(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId())), 0);
|
||||
}
|
||||
public void setOptionalKeywordAmount(KeywordInterface kw, int amount) {
|
||||
this.optionalKeywordAmount.put(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId()), amount);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user