refactor: simpler processAction syntax (#12458)

* game.processAction() instead of game.getState().processAction(game)

* add simpler method name and docs

* find/replace to new method

* remove old method

* deprecate applyEffects
This commit is contained in:
xenohedron 2024-06-11 22:55:43 -04:00 committed by GitHub
parent e2b1d980b6
commit d61de05eb8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
163 changed files with 218 additions and 217 deletions

View file

@ -248,7 +248,7 @@ public abstract class AbilityImpl implements Ability {
* abilities with replacement effects deactivated too late Example:
* {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy}
*/
game.getState().processAction(game);
game.processAction();
}
return result;
}

View file

@ -190,7 +190,7 @@ class AnimateDeadPutOntoBattlefieldEffect extends OneShotEffect {
}
// Put card onto the battlefield under your control...
player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null);
game.getState().processAction(game);
game.processAction();
Permanent creature = game.getPermanent(CardUtil.getDefaultCardSideForBattlefield(game, card).getId());
if (creature == null) {

View file

@ -114,7 +114,7 @@ public class DevourEffect extends ReplacementEffectImpl {
+ filterDevoured.getMessage() + (devouredCreatures > 1 ? "s" : "")
);
game.getState().processAction(game); // need for multistep effects
game.processAction(); // need for multistep effects
int amountCounters;
if (devourFactor == Integer.MAX_VALUE) {

View file

@ -62,7 +62,7 @@ public class ExileThenReturnTargetEffect extends OneShotEffect {
return false;
}
controller.moveCards(toFlicker, Zone.EXILED, source, game);
game.getState().processAction(game);
game.processAction();
for (Card card : toFlicker) {
putCards.moveCard(
yourControl ? controller : game.getPlayer(card.getOwnerId()),

View file

@ -47,14 +47,14 @@ public class LivingDeathEffect extends OneShotEffect {
}
}
}
game.getState().processAction(game);
game.processAction();
// Sacrifice all creatures
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game)) {
permanent.sacrifice(source, game);
}
game.getState().processAction(game);
game.processAction();
// Exiled cards are put onto the battlefield at the same time under their owner's control
Set<Card> cardsToReturnFromExile = new HashSet<>();

View file

@ -35,7 +35,7 @@ public class ShuffleHandIntoLibraryDrawThatManySourceEffect extends OneShotEffec
if (cardsHand > 0) {
controller.moveCards(controller.getHand(), Zone.LIBRARY, source, game);
controller.shuffleLibrary(source, game);
game.getState().processAction(game); // then
game.processAction(); // then
controller.drawCards(cardsHand, source, game);
}
return true;

View file

@ -48,7 +48,7 @@ public class GainControlAllUntapGainHasteEffect extends OneShotEffect {
FilterPermanent affectedFilter = new FilterPermanent();
affectedFilter.add(new PermanentReferenceInCollectionPredicate(affectedObjects, game));
new GainControlAllEffect(Duration.EndOfTurn, affectedFilter).apply(game, source);
game.getState().processAction(game);
game.processAction();
new UntapAllEffect(affectedFilter).apply(game, source);
game.addEffect(new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, affectedFilter), source);
return true;

View file

@ -68,7 +68,7 @@ public class DiscoverEffect extends OneShotEffect {
for (Card card : player.getLibrary().getCards(game)) {
cards.add(card);
player.moveCards(card, Zone.EXILED, source, game);
game.getState().processAction(game);
game.processAction();
if (filter.match(card, game)) {
return card;
}

View file

@ -116,7 +116,7 @@ public class ExploreSourceEffect extends OneShotEffect {
// the exploring creature receives a +1/+1 counter.
addCounter(game, permanent, source);
}
game.getState().processAction(game);
game.processAction();
// 701.40b A permanent explores after the process described in rule 701.40a is complete, even if some or all of
// those actions were impossible.
game.fireEvent(new ExploredEvent(permanent, source, card));

View file

@ -124,7 +124,7 @@ class CascadeEffect extends OneShotEffect {
cardsToExile.add(card);
// the card move is sequential, not all at once.
controller.moveCards(card, Zone.EXILED, source, game);
game.getState().processAction(game); // Laelia, the Blade Reforged
game.processAction(); // Laelia, the Blade Reforged
if (!card.isLand(game)
&& card.getManaValue() < sourceCost) {
cardToCast = card;

View file

@ -136,7 +136,7 @@ class MadnessReplacementEffect extends ReplacementEffectImpl {
}
// needed to add Madness ability to cards (e.g. by Falkenrath Gorger)
game.getState().processAction(game);
game.processAction();
GameEvent gameEvent = new MadnessCardExiledEvent(card.getId(), source, controller.getId());
game.fireEvent(gameEvent);

View file

@ -610,7 +610,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
// This is somewhat a band-aid on the special action nature of turning a permanent face up.
// 708.8. As a face-down permanent is turned face up, its copiable values revert to its normal copiable values.
// Any effects that have been applied to the face-down permanent still apply to the face-up permanent.
game.getState().processAction(game);
game.processAction();
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.TURNED_FACE_UP, getId(), source, playerId));
return true;
}

View file

@ -505,14 +505,30 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
UUID fireReflexiveTriggeredAbility(ReflexiveTriggeredAbility reflexiveAbility, Ability source, boolean fireAsSimultaneousEvent);
/**
* Inner game engine call to reset game objects to actual versions
* (reset all objects and apply all effects due layer system)
* <p>
* Warning, if you need to process object moves in the middle of the effect/ability
* then call game.getState().processAction(game) instead
* Inner engine call to reset all game objects and re-apply all layered continuous effects.
* Do NOT use indiscriminately. See processAction() instead.
*/
@Deprecated
void applyEffects();
/**
* Handles simultaneous events for triggers and then re-applies all layered continuous effects.
* Must be called between sequential steps of a resolving one-shot effect.
* <p>
* 608.2e. Some spells and abilities have multiple steps or actions, denoted by separate sentences or clauses,
* that involve multiple players. In these cases, the choices for the first action are made in APNAP order,
* and then the first action is processed simultaneously. Then the choices for the second action are made in
* APNAP order, and then that action is processed simultaneously, and so on. See rule 101.4.
* <p>
* 608.2f. Some spells and abilities include actions taken on multiple players and/or objects. In most cases,
* each such action is processed simultaneously. If the action can't be processed simultaneously, it's instead
* processed considering each affected player or object individually. APNAP order is used to make the primary
* determination of the order of those actions. Secondarily, if the action is to be taken on both a player
* and an object they control or on multiple objects controlled by the same player, the player who controls
* the resolving spell or ability chooses the relative order of those actions.
*/
void processAction();
@Deprecated // TODO: must research usage and remove it from all non engine code (example: Bestow ability, ProcessActions must be used instead)
boolean checkStateAndTriggered();

View file

@ -1927,6 +1927,14 @@ public abstract class GameImpl implements Game {
state.applyEffects(this);
}
@Override
public void processAction() {
state.handleSimultaneousEvent(this);
resetShortLivingLKI();
applyEffects();
state.getTriggers().checkStateTriggers(this);
}
@Override
public void addEffect(ContinuousEffect continuousEffect, Ability source) {
Ability newAbility = source.copy();
@ -2241,20 +2249,17 @@ public abstract class GameImpl implements Game {
}
/**
* 116.5. Each time a player would get priority, the game first performs all
* 117.5. Each time a player would get priority, the game first performs all
* applicable state-based actions as a single event (see rule 704,
* State-Based Actions), then repeats this process until no state-based
* actions are performed. Then triggered abilities are put on the stack (see
* rule 603, Handling Triggered Abilities). These steps repeat in order
* until no further state-based actions are performed and no abilities
* trigger. Then the player who would have received priority does so.
*
* @return
*/
@Override
public boolean checkStateAndTriggered() {
boolean somethingHappened = false;
//20091005 - 115.5
while (!isPaused() && !checkIfGameIsOver()) {
if (!checkStateBasedActions()) {
// nothing happened so check triggers
@ -2263,7 +2268,7 @@ public abstract class GameImpl implements Game {
break;
}
}
this.getState().processAction(this); // needed e.g if boost effects end and cause creatures to die
processAction(); // needed e.g if boost effects end and cause creatures to die
somethingHappened = true;
}
checkConcede();
@ -2273,10 +2278,8 @@ public abstract class GameImpl implements Game {
/**
* Sets the waiting triggered abilities (if there are any) to the stack in
* the chosen order by player
*
* @return
*/
public boolean checkTriggered() {
boolean checkTriggered() {
boolean played = false;
state.getTriggers().checkStateTriggers(this);
for (UUID playerId : state.getPlayerList(state.getActivePlayerId())) {
@ -2314,15 +2317,13 @@ public abstract class GameImpl implements Game {
}
/**
* 116.5. Each time a player would get priority, the game first performs all
* 117.5. Each time a player would get priority, the game first performs all
* applicable state-based actions as a single event (see rule 704,
* State-Based Actions), then repeats this process until no state-based
* actions are performed. Then triggered abilities are put on the stack (see
* rule 603, Handling Triggered Abilities). These steps repeat in order
* until no further state-based actions are performed and no abilities
* trigger. Then the player who would have received priority does so.
*
* @return
*/
protected boolean checkStateBasedActions() {
boolean somethingHappened = false;

View file

@ -666,22 +666,6 @@ public class GameState implements Serializable, Copyable<GameState> {
this.gameOver = true;
}
/**
* Must be called between effects/steps in the ability's resolve
* <p>
* 608.2e
* Some spells and abilities have multiple steps or actions, denoted by separate sentences or clauses,
* that involve multiple players. In these cases, the choices for the first action are made in APNAP order,
* and then the first action is processed simultaneously. Then the choices for the second action are made in
* APNAP order, and then that action is processed simultaneously, and so on. See rule 101.4.
*/
public void processAction(Game game) {
game.getState().handleSimultaneousEvent(game);
game.resetShortLivingLKI();
game.applyEffects();
game.getState().getTriggers().checkStateTriggers(game);
}
void applyEffects(Game game) {
applyEffectsCounter++;
for (Player player : players.values()) {