Fixed potential NPE errors in getPhase usage (fixed Berserker's Frenzy, etc)

This commit is contained in:
Oleg Agafonov 2023-03-25 16:01:27 +04:00
parent cfd7464b49
commit a15a0daa04
81 changed files with 162 additions and 130 deletions

View file

@ -23,13 +23,13 @@ public class DealsDamageToOneOrMoreCreaturesTriggeredAbility extends DealsDamage
public boolean checkTrigger(GameEvent event, Game game) {
if (super.checkTrigger(event, game)) {
// check that combat damage does only once trigger also if multiple creatures were damaged because they block or were blocked by source
if (game.getTurn().getStepType() == PhaseStep.COMBAT_DAMAGE
|| game.getTurn().getStepType() == PhaseStep.FIRST_COMBAT_DAMAGE) {
if (game.getTurnStepType() == PhaseStep.COMBAT_DAMAGE
|| game.getTurnStepType() == PhaseStep.FIRST_COMBAT_DAMAGE) {
String stepHash = (String) game.getState().getValue("damageStep" + getOriginalId());
String newStepHash = game.getStep().getType().toString() + game.getTurnNum();
String newStepHash = game.getTurnStepType().toString() + game.getTurnNum();
if (!newStepHash.equals(stepHash)) {
// this ability did not trigger during this damage step
game.getState().setValue("damageStep" + getOriginalId(), game.getStep().getType().toString() + game.getTurnNum());
game.getState().setValue("damageStep" + getOriginalId(), game.getTurnStepType().toString() + game.getTurnNum());
return true;
}
} else {

View file

@ -18,7 +18,7 @@ public enum AddendumCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
if (!game.isActivePlayer(source.getControllerId()) ||
!game.getPhase().getType().isMain()) {
!game.getTurnPhaseType().isMain()) {
return false;
}
if (CastFromEverywhereSourceCondition.instance.apply(game, source)) {

View file

@ -18,8 +18,8 @@ public enum AfterBlockersAreDeclaredCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return !(game.getStep().getType() == PhaseStep.BEGIN_COMBAT
|| game.getStep().getType() == PhaseStep.DECLARE_ATTACKERS);
return !(game.getTurnStepType() == PhaseStep.BEGIN_COMBAT
|| game.getTurnStepType() == PhaseStep.DECLARE_ATTACKERS);
}
@Override

View file

@ -15,7 +15,7 @@ public enum AfterCombatCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return game.getStep().getType().isAfter(PhaseStep.END_COMBAT);
return game.getTurnStepType().isAfter(PhaseStep.END_COMBAT);
}
@Override

View file

@ -14,7 +14,7 @@ public enum AfterUpkeepStepCondtion implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return game.getStep().getType().isAfter(PhaseStep.UPKEEP);
return game.getTurnStepType().isAfter(PhaseStep.UPKEEP);
}
@Override

View file

@ -17,7 +17,7 @@ public enum BeforeBlockersAreDeclaredCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return game.getStep().getType().isBefore(PhaseStep.DECLARE_BLOCKERS);
return game.getTurnStepType().isBefore(PhaseStep.DECLARE_BLOCKERS);
}
@Override

View file

@ -28,7 +28,7 @@ public class IsPhaseCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return turnPhase == game.getTurn().getPhaseType() && (!yourTurn || game.getActivePlayerId().equals(source.getControllerId()));
return turnPhase == game.getTurnPhaseType() && (!yourTurn || game.getActivePlayerId().equals(source.getControllerId()));
}
@Override

View file

@ -26,7 +26,7 @@ public class IsStepCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return phaseStep == game.getStep().getType() && (!onlyDuringYourSteps || game.isActivePlayer(source.getControllerId()));
return phaseStep == game.getTurnStepType() && (!onlyDuringYourSteps || game.isActivePlayer(source.getControllerId()));
}
@Override

View file

@ -201,7 +201,7 @@ public class ContinuousEffects implements Serializable {
updateTimestamps(timestampGroupName, layerEffects);
layerEffects.sort(Comparator.comparingLong(ContinuousEffect::getOrder));
/* debug effects apply order:
if (game.getStep() != null) System.out.println("layr - " + game.getTurnNum() + "." + game.getStep().getType() + ": layers " + layerEffects.size()
if (game.getStep() != null) System.out.println("layr - " + game.getTurnNum() + "." + game.getTurnStepType() + ": layers " + layerEffects.size()
+ " - " + layerEffects.stream().map(l -> l.getClass().getSimpleName()).collect(Collectors.joining(", "))
+ " - " + callName);
//*/

View file

@ -35,8 +35,8 @@ public class AddCombatAndMainPhaseEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// 15.07.2006 If it's somehow not a main phase when Fury of the Horde resolves, all it does is untap all creatures that attacked that turn. No new phases are created.
if (game.getTurn().getPhaseType() == TurnPhase.PRECOMBAT_MAIN
|| game.getTurn().getPhaseType() == TurnPhase.POSTCOMBAT_MAIN) {
if (game.getTurnPhaseType() == TurnPhase.PRECOMBAT_MAIN
|| game.getTurnPhaseType() == TurnPhase.POSTCOMBAT_MAIN) {
// we can't add two turn modes at once, will add additional post combat on delayed trigger resolution
TurnMod combat = new TurnMod(source.getControllerId(), TurnPhase.COMBAT, TurnPhase.POSTCOMBAT_MAIN, false);
game.getState().getTurnMods().add(combat);

View file

@ -68,7 +68,7 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR
validForTurnNum = game.getTurnNum();
}
// skip untap action
if (game.getTurn().getStepType() == PhaseStep.UNTAP
if (game.getTurnStepType() == PhaseStep.UNTAP
&& event.getType() == GameEvent.EventType.UNTAP
&& game.isActivePlayer(source.getControllerId())
&& event.getTargetId().equals(source.getSourceId())) {

View file

@ -120,7 +120,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR
}
}
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (game.getTurnStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (handledTargetsDuringTurn.containsKey(event.getTargetId())
&& !handledTargetsDuringTurn.get(event.getTargetId())
&& getTargetPointer().getTargets(game, source).contains(event.getTargetId())) {

View file

@ -55,7 +55,7 @@ public class DontUntapInControllersUntapStepAllEffect extends ContinuousRuleModi
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
if (game.getTurnStepType() == PhaseStep.UNTAP) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
switch(targetController) {

View file

@ -56,7 +56,7 @@ public class DontUntapInControllersUntapStepEnchantedEffect extends ContinuousRu
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
if (game.getTurnStepType() == PhaseStep.UNTAP) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null && enchantment.getAttachedTo() != null && event.getTargetId().equals(enchantment.getAttachedTo())) {
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());

View file

@ -47,7 +47,7 @@ public class DontUntapInControllersUntapStepSourceEffect extends ContinuousRuleM
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getTurn().getStepType() == PhaseStep.UNTAP
if (game.getTurnStepType() == PhaseStep.UNTAP
&& event.getTargetId().equals(source.getSourceId())) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && permanent.isControlledBy(game.getActivePlayerId())) {

View file

@ -50,7 +50,7 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getTurn().getStepType() != PhaseStep.UNTAP) {
if (game.getTurnStepType() != PhaseStep.UNTAP) {
return false;
}
for (UUID targetId : targetPointer.getTargets(game, source)) {

View file

@ -89,7 +89,7 @@ public class DontUntapInPlayersNextUntapStepAllEffect extends ContinuousRuleModi
}
}
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (game.getTurnStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
Player controller = game.getPlayer(source.getControllerId());

View file

@ -33,7 +33,7 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
if (layer == Layer.RulesEffects && game.getStep().getType() == PhaseStep.UNTAP && !source.isControlledBy(game.getActivePlayerId())) {
if (layer == Layer.RulesEffects && game.getTurnStepType() == PhaseStep.UNTAP && !source.isControlledBy(game.getActivePlayerId())) {
Integer appliedTurn = (Integer) game.getState().getValue(source.getSourceId() + "appliedTurn");
if (appliedTurn == null) {
appliedTurn = 0;

View file

@ -32,7 +32,7 @@ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends Continuous
if (!applied && layer == Layer.RulesEffects) {
if (!source.isControlledBy(game.getActivePlayerId())
&& game.getStep() != null
&& game.getStep().getType() == PhaseStep.UNTAP) {
&& game.getTurnStepType() == PhaseStep.UNTAP) {
game.getState().setValue(source.getSourceId() + "applied", true);
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
@ -46,7 +46,7 @@ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends Continuous
}
}
} else if (applied && layer == Layer.RulesEffects) {
if (game.getStep() != null && game.getStep().getType() == PhaseStep.END_TURN) {
if (game.getStep() != null && game.getTurnStepType() == PhaseStep.END_TURN) {
game.getState().setValue(source.getSourceId() + "applied", false);
}
}

View file

@ -46,8 +46,8 @@ public class CastOnlyDuringPhaseStepSourceEffect extends ContinuousRuleModifying
public boolean applies(GameEvent event, Ability source, Game game) {
// has to return true, if the spell cannot be cast in the current phase / step
if (event.getSourceId().equals(source.getSourceId())) {
if ((turnPhase != null && game.getPhase().getType() != turnPhase)
|| (phaseStep != null && (game.getTurn().getStepType() != phaseStep))
if ((turnPhase != null && game.getTurnPhaseType() != turnPhase)
|| (phaseStep != null && (game.getTurnStepType() != phaseStep))
|| (condition != null && !condition.apply(game, source))) {
return true;
}

View file

@ -30,7 +30,7 @@ public class ArtificialScoringSystem implements ScoringSystem {
if (game.getStep() == null) {
return 0;
}
return ScoringConstants.LOSE_GAME_SCORE + game.getTurnNum() * 2500 + game.getStep().getType().getIndex() * 200;
return ScoringConstants.LOSE_GAME_SCORE + game.getTurnNum() * 2500 + game.getTurnStepType().getIndex() * 200;
}
@Override

View file

@ -180,6 +180,19 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
Turn getTurn();
/**
* @return can return null in non started games
*/
PhaseStep getTurnStepType();
/**
* @return can return null in non started games
*/
TurnPhase getTurnPhaseType();
/**
* @return can return null in non started games
*/
Phase getPhase();
Step getStep();

View file

@ -2882,6 +2882,16 @@ public abstract class GameImpl implements Game {
return state.getTurn();
}
@Override
public PhaseStep getTurnStepType() {
return state.getTurnStepType();
}
@Override
public TurnPhase getTurnPhaseType() {
return state.getTurnPhaseType();
}
@Override
public Phase getPhase() {
return state.getTurn().getPhase();
@ -2919,7 +2929,7 @@ public abstract class GameImpl implements Game {
@Override
public boolean isMainPhase() {
return state.getTurn().getStepType() == PhaseStep.PRECOMBAT_MAIN || state.getTurn().getStepType() == PhaseStep.POSTCOMBAT_MAIN;
return state.getTurnStepType() == PhaseStep.PRECOMBAT_MAIN || state.getTurnStepType() == PhaseStep.POSTCOMBAT_MAIN;
}
@Override

View file

@ -7,6 +7,8 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousEffects;
import mage.abilities.effects.Effect;
import mage.cards.*;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.constants.Zone;
import mage.designations.Designation;
import mage.filter.common.FilterCreaturePermanent;
@ -22,6 +24,8 @@ import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken;
import mage.game.stack.SpellStack;
import mage.game.stack.StackObject;
import mage.game.turn.Phase;
import mage.game.turn.Step;
import mage.game.turn.Turn;
import mage.game.turn.TurnMods;
import mage.players.Player;
@ -572,6 +576,19 @@ public class GameState implements Serializable, Copyable<GameState> {
return turn;
}
public PhaseStep getTurnStepType() {
Turn turn = this.getTurn();
Phase phase = turn != null ? turn.getPhase() : null;
Step step = phase != null ? phase.getStep() : null;
return step != null ? step.getType() : null;
}
public TurnPhase getTurnPhaseType() {
Turn turn = this.getTurn();
Phase phase = turn != null ? turn.getPhase() : null;
return phase != null ? phase.getType() : null;
}
public Combat getCombat() {
return combat;
}

View file

@ -41,7 +41,7 @@ class LukeSkywalkerEmblemEffect extends PreventionEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getPhase().getType() == TurnPhase.COMBAT
if (game.getTurnPhaseType() == TurnPhase.COMBAT
&& super.applies(event, source, game)
&& event.getType() == GameEvent.EventType.DAMAGE_PLAYER) {
Player controller = game.getPlayer(source.getControllerId());

View file

@ -90,7 +90,7 @@ class EdgeOfMalacolEffect extends ContinuousRuleModifyingEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Prevent untap event of creatures of target player
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
if (game.getTurnStepType() == PhaseStep.UNTAP) {
Plane cPlane = game.getState().getCurrentPlane();
if (cPlane == null) {
return false;

View file

@ -84,13 +84,6 @@ public class Turn implements Serializable {
return null;
}
public PhaseStep getStepType() {
if (currentPhase != null && currentPhase.getStep() != null) {
return currentPhase.getStep().getType();
}
return null;
}
/**
* @param game
* @param activePlayer
@ -148,8 +141,8 @@ public class Turn implements Serializable {
public void resumePlay(Game game, boolean wasPaused) {
activePlayerId = game.getActivePlayerId();
UUID priorityPlayerId = game.getPriorityPlayerId();
TurnPhase phaseType = game.getPhase().getType();
PhaseStep stepType = game.getStep().getType();
TurnPhase phaseType = game.getTurnPhaseType();
PhaseStep stepType = game.getTurnStepType();
Iterator<Phase> it = phases.iterator();
Phase phase;

View file

@ -271,7 +271,7 @@ public class ManaPool implements Serializable {
private int emptyItem(ManaPoolItem item, Emptiable toEmpty, Game game, ManaType manaType) {
if (item.getDuration() == Duration.EndOfTurn
&& game.getPhase().getType() != TurnPhase.END) {
&& game.getTurnPhaseType() != TurnPhase.END) {
return 0;
}
if (!manaBecomesColorless) {

View file

@ -2407,7 +2407,7 @@ public abstract class PlayerImpl implements Player, Serializable {
case PASS_PRIORITY_UNTIL_TURN_END_STEP: // F5
resetPlayerPassedActions();
passedUntilEndOfTurn = true;
skippedAtLeastOnce = PhaseStep.END_TURN != game.getTurn().getStepType();
skippedAtLeastOnce = PhaseStep.END_TURN != game.getTurnStepType();
this.skip();
break;
case PASS_PRIORITY_UNTIL_NEXT_TURN: // F4
@ -2423,8 +2423,8 @@ public abstract class PlayerImpl implements Player, Serializable {
case PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE: //F7
resetPlayerPassedActions();
passedUntilNextMain = true;
skippedAtLeastOnce = !(game.getTurn().getStepType() == PhaseStep.POSTCOMBAT_MAIN
|| game.getTurn().getStepType() == PhaseStep.PRECOMBAT_MAIN);
skippedAtLeastOnce = !(game.getTurnStepType() == PhaseStep.POSTCOMBAT_MAIN
|| game.getTurnStepType() == PhaseStep.PRECOMBAT_MAIN);
this.skip();
break;
case PASS_PRIORITY_UNTIL_STACK_RESOLVED: // Default F10 - Skips until the current stack is resolved