Merge pull request #2253 from tool4ever/costTweaks

Cost tweaks
This commit is contained in:
Anthony Calosa
2023-01-18 18:11:43 +08:00
committed by GitHub
10 changed files with 44 additions and 42 deletions

View File

@@ -782,15 +782,9 @@ public class AiController {
return AiPlayDecision.CantAfford;
}
}
if (wardCost.hasSpecificCostType(CostPayLife.class)) {
int lifeToPay = wardCost.getCostPartByType(CostPayLife.class).convertAmount();
if (lifeToPay > player.getLife() || (lifeToPay == player.getLife() && !player.cantLoseForZeroOrLessLife())) {
return AiPlayDecision.CantAfford;
}
}
if (wardCost.hasSpecificCostType(CostDiscard.class)
&& wardCost.getCostPartByType(CostDiscard.class).convertAmount() > player.getCardsIn(ZoneType.Hand).size()) {
return AiPlayDecision.CantAfford;
SpellAbilityAi topAI = new SpellAbilityAi() {};
if (!topAI.willPayCosts(player, sa , wardCost, host)) {
return AiPlayDecision.CostNotAcceptable;
}
}
}

View File

@@ -620,6 +620,9 @@ public abstract class GameState {
game.getAction().checkStateEffects(true); //ensure state based effects and triggers are updated
// prevent interactions with objects from old state
game.copyLastState();
// Set negative or zero life after state effects if need be, important for some puzzles that rely on
// pre-setting negative life (e.g. PS_NEO4).
for (int i = 0; i < playerStates.size(); i++) {

View File

@@ -64,16 +64,13 @@ public class SacrificeEffect extends SpellAbilityEffect {
table.replaceCounterEffect(game, sa, true);
Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true);
Cost payCost = new Cost(ManaCost.ZERO, true);
int n = card.getCounters(CounterEnumType.AGE);
// multiply cost
for (int i = 0; i < n; ++i) {
payCost.add(cumCost);
if (n > 0) {
Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true);
payCost.mergeTo(cumCost, n);
}
sa.setCumulativeupkeep(true);
game.updateLastStateForCard(card);
StringBuilder sb = new StringBuilder();

View File

@@ -883,7 +883,24 @@ public class Cost implements Serializable {
return sb.toString();
}
public void mergeTo(Cost source, int amt) {
// multiply to create the full cost
if (amt > 1) {
// to double itself we need to work on a copy
Cost sourceCpy = source.copy();
for (int i = 1; i < amt; ++i) {
// in theory setAmount could be used instead but it depends on the cost complexity (probably not worth trying to determine that first)
source.add(sourceCpy);
}
}
// combine costs (these shouldn't mix together)
this.add(source, false);
}
public Cost add(Cost cost1) {
return add(cost1, true);
}
public Cost add(Cost cost1, boolean mergeAdditional) {
CostPartMana costPart2 = this.getCostMana();
List<CostPart> toRemove = Lists.newArrayList();
for (final CostPart part : cost1.getCostParts()) {
@@ -906,10 +923,10 @@ public class Cost implements Serializable {
} else {
costParts.add(0, new CostPartMana(oldManaCost.toManaCost(), r));
}
} else if (part instanceof CostDiscard || part instanceof CostDraw
|| part instanceof CostAddMana || part instanceof CostPayLife
|| part instanceof CostPutCounter || part instanceof CostTapType
|| part instanceof CostExile) {
} else if (part instanceof CostPutCounter || (mergeAdditional && // below usually not desired because they're from different causes
(part instanceof CostDiscard || part instanceof CostDraw ||
part instanceof CostAddMana || part instanceof CostPayLife ||
part instanceof CostSacrifice || part instanceof CostTapType))) {
boolean alreadyAdded = false;
for (final CostPart other : costParts) {
if ((other.getClass().equals(part.getClass()) || (part instanceof CostPutCounter && ((CostPutCounter)part).getCounter().is(CounterEnumType.LOYALTY))) &&
@@ -917,7 +934,7 @@ public class Cost implements Serializable {
StringUtils.isNumeric(part.getAmount()) &&
StringUtils.isNumeric(other.getAmount())) {
String amount = String.valueOf(part.convertAmount() + other.convertAmount());
if (part instanceof CostPutCounter) { // path for Carth & Cumulative Upkeep
if (part instanceof CostPutCounter) { // CR 606.5 path for Carth
if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().equals(((CostPutCounter) part).getCounter())) {
costParts.add(new CostPutCounter(amount, ((CostPutCounter) part).getCounter(), part.getType(), part.getTypeDescription()));
} else if (other instanceof CostRemoveCounter && ((CostRemoveCounter)other).counter.is(CounterEnumType.LOYALTY)) {
@@ -931,6 +948,8 @@ public class Cost implements Serializable {
} else {
continue;
}
} else if (part instanceof CostSacrifice) {
costParts.add(new CostSacrifice(amount, part.getType(), part.getTypeDescription()));
} else if (part instanceof CostDiscard) {
costParts.add(new CostDiscard(amount, part.getType(), part.getTypeDescription()));
} else if (part instanceof CostDraw) {
@@ -942,12 +961,6 @@ public class Cost implements Serializable {
costParts.add(new CostAddMana(amount, part.getType(), part.getTypeDescription()));
} else if (part instanceof CostPayLife) {
costParts.add(new CostPayLife(amount, part.getTypeDescription()));
} else if (part instanceof CostExile) {
ZoneType z = ((CostExile) part).getFrom();
if (((CostExile) other).getFrom() != z) {
continue;
}
costParts.add(new CostExile(amount, part.getType(), part.getTypeDescription(), z));
}
toRemove.add(other);
alreadyAdded = true;

View File

@@ -112,7 +112,6 @@ public class CostAdjustment {
}
final String scost = st.getParamOrDefault("Cost", "1");
Cost part = new Cost(scost, sa.isAbility());
int count = 0;
if (st.hasParam("ForEachShard")) {
@@ -155,8 +154,9 @@ public class CostAdjustment {
// Amount 1 as default
count = 1;
}
for (int i = 0; i < count; ++i) {
cost.add(part);
if (count > 0) {
Cost part = new Cost(scost, sa.isAbility());
cost.mergeTo(part, count);
}
}
@@ -177,7 +177,7 @@ public class CostAdjustment {
originalCard.turnFaceDownNoUpdate();
isStateChangeToFaceDown = true;
}
} // isSpell
}
CardCollection cardsOnBattlefield = new CardCollection(game.getCardsIn(ZoneType.Battlefield));
cardsOnBattlefield.addAll(game.getCardsIn(ZoneType.Stack));

View File

@@ -127,7 +127,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private boolean aftermath = false;
private boolean cumulativeupkeep = false;
private boolean blessing = false;
private Integer chapter = null;
private boolean lastChapter = false;
@@ -516,6 +515,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return this.hasParam("Ninjutsu");
}
public boolean isCumulativeupkeep() {
return hasParam("CumulativeUpkeep");
}
public boolean isEpic() {
AbilitySub sub = this.getSubAbility();
while (sub != null && !sub.hasParam("Epic")) {
@@ -2140,13 +2143,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return ForgeScript.spellAbilityHasProperty(this, property, sourceController, source, spellAbility);
}
public boolean isCumulativeupkeep() {
return cumulativeupkeep;
}
public void setCumulativeupkeep(boolean cumulativeupkeep0) {
cumulativeupkeep = cumulativeupkeep0;
}
// Return whether this spell tracks what color mana is spent to cast it for the sake of the effect
public boolean tracksManaSpent() {
if (hostCard == null || hostCard.getRules() == null) { return false; }

View File

@@ -72,7 +72,7 @@ public class StaticAbilityCantGainLosePayLife {
}
if (!stAb.matchesValidParam("ValidCause", cause)) {
return false;
continue;
}
if (applyCommonAbility(stAb, player)) {

View File

@@ -1,7 +1,7 @@
Name:Land Grant
ManaCost:1 G
Types:Sorcery
S:Mode$ Continuous | CharacteristicDefining$ True | AddKeyword$ Alternative Cost:Reveal<1/Hand> | CheckSVar$ X | SVarCompare$ EQ0 | Description$ If you have no land cards in hand, you may reveal your hand rather than pay Land Grant's mana cost.
S:Mode$ Continuous | CharacteristicDefining$ True | AddKeyword$ Alternative Cost:Reveal<1/Hand> | CheckSVar$ X | SVarCompare$ EQ0 | Description$ If you have no land cards in hand, you may reveal your hand rather than pay this spell's mana cost.
SVar:X:Count$TypeInYourHand.Land
A:SP$ ChangeZone | Cost$ 1 G | Origin$ Library | Destination$ Hand | ChangeType$ Forest | ChangeNum$ 1 | SpellDescription$ Search your library for a Forest card, reveal that card, put it into your hand, then shuffle.
Oracle:If you have no land cards in hand, you may reveal your hand rather than pay this spell's mana cost.\nSearch your library for a Forest card, reveal that card, put it into your hand, then shuffle.

View File

@@ -2,7 +2,7 @@ Name:The Lady of Otaria
ManaCost:3 R G
Types:Legendary Creature Avatar
PT:5/5
SVar:AltCost:Cost$ tapXType<3/Creature.Dwarf> | Description$ You may tap three untapped Dwarves you control rather than pay this spell's mana cost.
SVar:AltCost:Cost$ tapXType<3/Dwarf> | Description$ You may tap three untapped Dwarves you control rather than pay this spell's mana cost.
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | Execute$ TrigDig | CheckSVar$ X | TriggerDescription$ At the beginning of each end step, if a land you controlled was put into your graveyard from the battlefield this turn, reveal the top four cards of your library. Put any number of Dwarf cards from among them into your hand and the rest on the bottom of your library in a random order.
SVar:TrigDig:DB$ Dig | DigNum$ 4 | ChangeValid$ Dwarf | DestinationZone$ Hand | RestRandomOrder$ True | AnyNumber$ True
SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Land.YouCtrl+YouOwn

View File

@@ -452,7 +452,6 @@ public class HumanPlay {
return false;
}
}
return true;
}
else if (part instanceof CostGainControl) {
int amount = Integer.parseInt(part.getAmount());