SacrificeOnce Trigger

This commit is contained in:
Hans Mackowiak
2024-07-28 21:34:25 +02:00
parent a58a197945
commit 23d0b05547
11 changed files with 134 additions and 54 deletions

View File

@@ -1442,10 +1442,7 @@ public class GameAction {
sacrificeList = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, sacrificeList, ZoneType.Graveyard, null);
orderedSacrificeList = true;
}
for (Card c : sacrificeList) {
c.updateWasDestroyed(true);
sacrifice(c, null, true, mapParams);
}
sacrifice(sacrificeList, null, true, mapParams);
setHoldCheckingStaticAbilities(false);
table.triggerChangesZoneAll(game, null);
@@ -1891,15 +1888,37 @@ public class GameAction {
return true;
}
public final Card sacrifice(final Card c, final SpellAbility source, final boolean effect, Map<AbilityKey, Object> params) {
if (!c.canBeSacrificedBy(source, effect)) {
return null;
public final CardCollection sacrifice(final Iterable<Card> list, final SpellAbility source, final boolean effect, Map<AbilityKey, Object> params) {
Multimap<Player, Card> lki = MultimapBuilder.hashKeys().arrayListValues().build();
CardCollection result = new CardCollection();
for (Card c : list) {
if (c == null) {
continue;
}
c.getController().addSacrificedThisTurn(c, source);
if (!c.canBeSacrificedBy(source, effect)) {
continue;
}
Card lkiCopy = ((CardCollection) params.get(AbilityKey.LastStateBattlefield)).get(c);
c.getController().addSacrificedThisTurn(lkiCopy, source);
lki.put(c.getController(), lkiCopy);
c.updateWasDestroyed(true);
return sacrificeDestroy(c, source, params);
Card changed = sacrificeDestroy(c, source, params);
if (changed != null) {
result.add(changed);
}
}
for (Map.Entry<Player, Collection<Card>> e : lki.asMap().entrySet()) {
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(e.getKey());
runParams.put(AbilityKey.Cards, new CardCollection(e.getValue()));
runParams.put(AbilityKey.Cause, source);
game.getTriggerHandler().runTrigger(TriggerType.SacrificedOnce, runParams, false);
}
return result;
}
public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate, Map<AbilityKey, Object> params) {

View File

@@ -60,10 +60,8 @@ public class BalanceEffect extends SpellAbilityEffect {
if (zone.equals(ZoneType.Hand)) {
discardedMap.put(p, p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance));
} else { // Battlefield
for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
if (null == card) continue;
game.getAction().sacrifice(card, sa, true, params);
}
CardCollectionView list = p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid);
game.getAction().sacrifice(list, sa, true, params);
}
}

View File

@@ -78,9 +78,8 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
Map<AbilityKey, Object> params = AbilityKey.newMap();
CardZoneTable zoneMovements = AbilityKey.addCardZoneTableParams(params, sa);
for (Card sac : list) {
for (Card sac : game.getAction().sacrifice(list, sa, true, params)) {
final Card lKICopy = zoneMovements.getLastStateBattlefield().get(sac);
if (game.getAction().sacrifice(sac, sa, true, params) != null) {
if (remSacrificed) {
host.addRemembered(lKICopy);
}
@@ -88,7 +87,6 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
host.addImprintedCard(lKICopy);
}
}
}
zoneMovements.triggerChangesZoneAll(game, sa);
}

View File

@@ -99,7 +99,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
if (host.getController().equals(activator) && game.getZoneOf(host).is(ZoneType.Battlefield)) {
if (!optional || activator.getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblDoYouWantSacrificeThis", host.getName()), null)) {
if (game.getAction().sacrifice(host, sa, true, params) != null && remSacrificed) {
if (game.getAction().sacrifice(new CardCollection(host), sa, true, params) != null && remSacrificed) {
host.addRemembered(host);
}
}
@@ -155,10 +155,16 @@ public class SacrificeEffect extends SpellAbilityEffect {
choosenToSacrifice = GameActionUtil.orderCardsByTheirOwners(game, choosenToSacrifice, ZoneType.Graveyard, sa);
if (destroy) {
for (Card sac : choosenToSacrifice) {
Card lKICopy = zoneMovements.getLastStateBattlefield().get(sac);
boolean wasSacrificed = !destroy && game.getAction().sacrifice(sac, sa, true, params) != null;
boolean wasDestroyed = destroy && game.getAction().destroy(sac, sa, true, params);
if (game.getAction().destroy(sac, sa, true, params) && remSacrificed) {
host.addRemembered(lKICopy);
}
}
} else {
for (Card sac : game.getAction().sacrifice(choosenToSacrifice, sa, true, params)) {
Card lKICopy = zoneMovements.getLastStateBattlefield().get(sac);
// Run Devour Trigger
if (devour) {
host.addDevoured(lKICopy);
@@ -172,12 +178,13 @@ public class SacrificeEffect extends SpellAbilityEffect {
runParams.put(AbilityKey.Exploited, lKICopy);
game.getTriggerHandler().runTrigger(TriggerType.Exploited, runParams, false);
}
if ((wasDestroyed || wasSacrificed) && remSacrificed) {
if (remSacrificed) {
host.addRemembered(lKICopy);
}
}
}
}
}
zoneMovements.triggerChangesZoneAll(game, sa);
}

View File

@@ -60,7 +60,7 @@ public class CostForage extends CostPartWithList {
} else if (targetCards.size() == 1) {
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
AbilityKey.addCardZoneTableParams(moveParams, table);
CardCollection result = new CardCollection(game.getAction().sacrifice(targetCards.getFirst(), ability, effect, moveParams));
CardCollection result = game.getAction().sacrifice(targetCards, ability, effect, moveParams);
triggerForage(payer);
return result;
} else {

View File

@@ -32,6 +32,7 @@ import forge.card.mana.ManaCostShard;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -341,7 +342,7 @@ public class CostPayment extends ManaConversionMatrix {
if (test) {
sa.resetSacrificedAsOffering();
} else if (costIsPaid) {
game.getAction().sacrifice(offering, sa, false, params);
game.getAction().sacrifice(new CardCollection(offering), sa, false, params);
}
}
if (sa.isEmerge()) {
@@ -353,7 +354,7 @@ public class CostPayment extends ManaConversionMatrix {
if (test) {
sa.resetSacrificedAsEmerge();
} else if (costIsPaid) {
game.getAction().sacrifice(emerge, sa, false, params);
game.getAction().sacrifice(new CardCollection(emerge), sa, false, params);
sa.setSacrificedAsEmerge(game.getChangeZoneLKIInfo(emerge));
}
}

View File

@@ -162,13 +162,17 @@ public class CostSacrifice extends CostPartWithList {
}
@Override
protected Card doPayment(Player payer, SpellAbility ability, Card targetCard, final boolean effect) {
final Game game = targetCard.getGame();
protected Card doPayment(Player payer, SpellAbility ability, Card targetCard, final boolean effect) { return null; }
@Override
protected boolean canPayListAtOnce() { return true; }
@Override
protected CardCollectionView doListPayment(Player payer, SpellAbility ability, CardCollectionView targetCards, final boolean effect) {
final Game game = ability.getHostCard().getGame();
// no table there, it is already handled by CostPartWithList
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
AbilityKey.addCardZoneTableParams(moveParams, table);
return game.getAction().sacrifice(targetCard, ability, effect, moveParams);
return game.getAction().sacrifice(targetCards, ability, effect, moveParams);
}
/* (non-Javadoc)

View File

@@ -2295,11 +2295,10 @@ public class Player extends GameEntity implements Comparable<Player> {
investigatedThisTurn = 0;
}
public final void addSacrificedThisTurn(final Card c, final SpellAbility source) {
public final void addSacrificedThisTurn(final Card cpy, final SpellAbility source) {
// Play the Sacrifice sound
game.fireEvent(new GameEventCardSacrificed());
final Card cpy = CardCopyService.getLKICopy(c);
sacrificedThisTurn.add(cpy);
// Run triggers

View File

@@ -0,0 +1,53 @@
package forge.game.trigger;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
public class TriggerSacrificedOnce extends Trigger {
public TriggerSacrificedOnce(Map<String, String> params, Card host, boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false;
}
if (!matchesValidParam("ValidCause", runParams.get(AbilityKey.Cause))) {
return false;
}
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Cards))) {
return false;
}
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
CardCollection cards = (CardCollection) runParams.get(AbilityKey.Cards);
if (hasParam("ValidCard")) {
cards = CardLists.getValidCards(cards, getParam("ValidCard"), getHostCard().getController(), getHostCard(), this);
}
sa.setTriggeringObject(AbilityKey.Cards, cards);
sa.setTriggeringObject(AbilityKey.Amount, cards.size());
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.Cause);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", ");
sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount));
return sb.toString();
}
}

View File

@@ -118,6 +118,7 @@ public enum TriggerType {
RolledDieOnce(TriggerRolledDieOnce.class),
RoomEntered(TriggerEnteredRoom.class),
Sacrificed(TriggerSacrificed.class),
SacrificedOnce(TriggerSacrificed.class),
Scry(TriggerScry.class),
SearchedLibrary(TriggerSearchedLibrary.class),
SeekAll(TriggerSeekAll.class),

View File

@@ -534,7 +534,7 @@ public class HumanPlay {
final Card offering = ability.getSacrificedAsOffering();
offering.setUsedToPay(false);
if (!manaInputCancelled) {
game.getAction().sacrifice(offering, ability, false, params);
game.getAction().sacrifice(new CardCollection(offering), ability, false, params);
}
ability.resetSacrificedAsOffering();
}
@@ -542,7 +542,7 @@ public class HumanPlay {
final Card emerge = ability.getSacrificedAsEmerge();
emerge.setUsedToPay(false);
if (!manaInputCancelled) {
game.getAction().sacrifice(emerge, ability, false, params);
game.getAction().sacrifice(new CardCollection(emerge), ability, false, params);
ability.setSacrificedAsEmerge(game.getChangeZoneLKIInfo(emerge));
} else {
ability.resetSacrificedAsEmerge();