Improved freeze checks and canRespond/isInGame usage

This commit is contained in:
Oleg Agafonov 2020-07-01 13:48:22 +04:00
parent 3b19e3db35
commit adbe84c540
17 changed files with 54 additions and 77 deletions

View file

@ -1964,7 +1964,7 @@ public class HumanPlayer extends PlayerImpl {
} }
waitForResponse(game); waitForResponse(game);
if (response.getUUID() != null && isInGame()) { if (response.getUUID() != null) {
if (abilities.containsKey(response.getUUID())) { if (abilities.containsKey(response.getUUID())) {
activateAbility(abilities.get(response.getUUID()), game); activateAbility(abilities.get(response.getUUID()), game);
} }

View file

@ -326,7 +326,7 @@ public class GameController implements GameCallback {
private void sendInfoAboutPlayersNotJoinedYetAndTryToFixIt() { private void sendInfoAboutPlayersNotJoinedYetAndTryToFixIt() {
// runs every 5 secs untill all players join // runs every 5 secs untill all players join
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
if (player.isInGame() && player.isHuman()) { if (player.canRespond() && player.isHuman()) {
Optional<User> requestedUser = getUserByPlayerId(player.getId()); Optional<User> requestedUser = getUserByPlayerId(player.getId());
if (requestedUser.isPresent()) { if (requestedUser.isPresent()) {
User user = requestedUser.get(); User user = requestedUser.get();

View file

@ -123,7 +123,7 @@ class CovetedJewelControlEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
Player newControllingPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); Player newControllingPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (permanent == null || newControllingPlayer == null || !newControllingPlayer.isInGame()) { if (permanent == null || newControllingPlayer == null || !newControllingPlayer.canRespond()) {
this.discard(); this.discard();
return false; return false;
} }

View file

@ -1,14 +1,8 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; import mage.cards.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
@ -18,8 +12,9 @@ import mage.players.Player;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author TheElk801 & L_J * @author TheElk801 & L_J
*/ */
public final class CruelFate extends CardImpl { public final class CruelFate extends CardImpl {
@ -71,7 +66,7 @@ class CruelFateEffect extends OneShotEffect {
// card to put into opponent's graveyard // card to put into opponent's graveyard
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard")); TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard"));
if (targetOpponent.isInGame()) { if (targetOpponent.canRespond()) {
if (cards.size() > 1) { if (cards.size() > 1) {
controller.choose(Outcome.Detriment, cards, target, game); controller.choose(Outcome.Detriment, cards, target, game);
Card card = cards.get(target.getFirstTarget(), game); Card card = cards.get(target.getFirstTarget(), game);

View file

@ -137,7 +137,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect {
} }
boolean continueCasting = true; boolean continueCasting = true;
while (spellController.isInGame() && continueCasting) { while (spellController.canRespond() && continueCasting) {
continueCasting = copiedCards.size() > 1 && spellController.chooseUse(outcome, "Cast one of the copied cards without paying its mana cost?", source, game); continueCasting = copiedCards.size() > 1 && spellController.chooseUse(outcome, "Cast one of the copied cards without paying its mana cost?", source, game);
Card cardToCopy; Card cardToCopy;

View file

@ -1,8 +1,5 @@
package mage.cards.k; package mage.cards.k;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
@ -26,6 +23,10 @@ import mage.target.TargetPlayer;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* @author bunchOfDevs * @author bunchOfDevs
*/ */
@ -100,7 +101,7 @@ class KarnLiberatedEffect extends OneShotEffect {
game.getState().addCard(card); game.getState().addCard(card);
} }
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
if (player.isInGame()) { // only players alive are in the restarted game if (player.canRespond()) { // only players alive are in the restarted game
player.getGraveyard().clear(); player.getGraveyard().clear();
player.getHand().clear(); player.getHand().clear();
player.getLibrary().clear(); player.getLibrary().clear();

View file

@ -1,7 +1,5 @@
package mage.cards.k; package mage.cards.k;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageAllEffect;
@ -15,8 +13,9 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class KindleTheCarnage extends CardImpl { public final class KindleTheCarnage extends CardImpl {
@ -62,7 +61,6 @@ class KindleTheCarnageEffect extends OneShotEffect {
Cards hand = controller.getHand(); Cards hand = controller.getHand();
while (hand != null while (hand != null
&& hand.size() > 0 && hand.size() > 0
&& controller.isInGame()
&& controller.chooseUse(Outcome.AIDontUseIt, "Discard a card randomly from your hand?", source, game)) { && controller.chooseUse(Outcome.AIDontUseIt, "Discard a card randomly from your hand?", source, game)) {
Card discardedCard = controller.discardOne(true, source, game); Card discardedCard = controller.discardOne(true, source, game);
if (discardedCard != null) { if (discardedCard != null) {

View file

@ -1,4 +1,3 @@
package mage.cards.n; package mage.cards.n;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -24,7 +23,6 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author Rene - bugisemail at gmail dot com * @author Rene - bugisemail at gmail dot com
*/ */
public final class NaturalBalance extends CardImpl { public final class NaturalBalance extends CardImpl {
@ -100,10 +98,8 @@ public final class NaturalBalance extends CardImpl {
} }
} }
for (Player player : toShuffle) { for (Player player : toShuffle) {
if (player.isInGame()) {
player.shuffleLibrary(source, game); player.shuffleLibrary(source, game);
} }
}
return true; return true;
} }
return false; return false;

View file

@ -96,8 +96,7 @@ class ScourgeOfValkasDamageEffect extends OneShotEffect {
permanent.damage(dragons, enteringDragon.getId(), game, false, true); permanent.damage(dragons, enteringDragon.getId(), game, false, true);
} else { } else {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player != null if (player != null) {
&& player.isInGame()) {
player.damage(dragons, enteringDragon.getId(), game); player.damage(dragons, enteringDragon.getId(), game);
} }
} }

View file

@ -1,7 +1,5 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
@ -17,8 +15,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author ciaccona007 * @author ciaccona007
*/ */
public final class SkySwallower extends CardImpl { public final class SkySwallower extends CardImpl {
@ -68,7 +67,7 @@ class GainControlAllPermanentsEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source));
if (targetPlayer != null && targetPlayer.isInGame()) { if (targetPlayer != null) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
if (permanent != null && !permanent.getId().equals(source.getSourceId())) { if (permanent != null && !permanent.getId().equals(source.getSourceId())) {
permanent.changeControllerId(targetPlayer.getId(), game); permanent.changeControllerId(targetPlayer.getId(), game);

View file

@ -1,4 +1,3 @@
package mage.cards.s; package mage.cards.s;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -70,7 +69,7 @@ class SlaughterTheStrongEffect extends OneShotEffect {
if (player != null) { if (player != null) {
boolean selectionDone = false; boolean selectionDone = false;
Set<UUID> selectedCreatures = new HashSet<>(); Set<UUID> selectedCreatures = new HashSet<>();
while (selectionDone == false && player.isInGame()) { while (player.canRespond() && selectionDone == false) {
int powerSum = 0; int powerSum = 0;
for (UUID creatureId : selectedCreatures) { for (UUID creatureId : selectedCreatures) {
Permanent creature = game.getPermanent(creatureId); Permanent creature = game.getPermanent(creatureId);

View file

@ -1,6 +1,5 @@
package mage.cards.u; package mage.cards.u;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
@ -15,10 +14,10 @@ import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*
*/ */
public final class UndyingFlames extends CardImpl { public final class UndyingFlames extends CardImpl {
@ -60,7 +59,7 @@ class UndyingFlamesEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
while (controller.getLibrary().hasCards() && controller.isInGame()) { while (controller.canRespond() && controller.getLibrary().hasCards()) {
Card card = controller.getLibrary().getFromTop(game); Card card = controller.getLibrary().getFromTop(game);
if (card != null) { if (card != null) {
controller.moveCards(card, Zone.EXILED, source, game); controller.moveCards(card, Zone.EXILED, source, game);

View file

@ -122,8 +122,7 @@ public class DamageTargetEffect extends OneShotEffect {
permanent.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable); permanent.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable);
} }
Player player = game.getPlayer(targetId); Player player = game.getPlayer(targetId);
if (player != null if (player != null) {
&& player.isInGame()) {
player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable); player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable);
} }
} }
@ -136,8 +135,7 @@ public class DamageTargetEffect extends OneShotEffect {
permanent.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable); permanent.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable);
} else { } else {
Player player = game.getPlayer(targetId); Player player = game.getPlayer(targetId);
if (player != null if (player != null) {
&& player.isInGame()) {
player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable); player.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable);
} }
} }

View file

@ -1,6 +1,5 @@
package mage.abilities.effects.common.continuous; package mage.abilities.effects.common.continuous;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.ActivatedAbility; import mage.abilities.ActivatedAbility;
import mage.abilities.Mode; import mage.abilities.Mode;
@ -16,8 +15,9 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class GainControlTargetEffect extends ContinuousEffectImpl { public class GainControlTargetEffect extends ContinuousEffectImpl {
@ -31,7 +31,6 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
} }
/** /**
*
* @param duration * @param duration
* @param fixedControl Controlling player is fixed even if the controller of * @param fixedControl Controlling player is fixed even if the controller of
* the ability changes later * the ability changes later
@ -41,7 +40,6 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
} }
/** /**
*
* @param duration * @param duration
* @param controllingPlayerId Player that controls the target creature * @param controllingPlayerId Player that controls the target creature
*/ */
@ -112,8 +110,7 @@ public class GainControlTargetEffect extends ContinuousEffectImpl {
} }
} }
// no valid target exists and the controller is no longer in the game, effect can be discarded // no valid target exists and the controller is no longer in the game, effect can be discarded
if (!oneTargetStillExists if (!oneTargetStillExists || !controller.isInGame()) {
|| !controller.isInGame()) {
discard(); discard();
} }
firstControlChange = false; firstControlChange = false;

View file

@ -982,7 +982,7 @@ public abstract class GameImpl implements Game, Serializable {
targetPlayer.setTargetName("starting player"); targetPlayer.setTargetName("starting player");
if (choosingPlayerId != null) { if (choosingPlayerId != null) {
choosingPlayer = this.getPlayer(choosingPlayerId); choosingPlayer = this.getPlayer(choosingPlayerId);
if (choosingPlayer != null && !choosingPlayer.isInGame()) { if (choosingPlayer != null && !choosingPlayer.canRespond()) {
choosingPlayer = null; choosingPlayer = null;
} }
} }
@ -1007,7 +1007,7 @@ public abstract class GameImpl implements Game, Serializable {
if (startingPlayerId == null) { if (startingPlayerId == null) {
// choose any available player as starting player // choose any available player as starting player
for (Player player : state.getPlayers().values()) { for (Player player : state.getPlayers().values()) {
if (player.isInGame()) { if (player.canRespond()) {
startingPlayerId = player.getId(); startingPlayerId = player.getId();
break; break;
} }
@ -1161,7 +1161,7 @@ public abstract class GameImpl implements Game, Serializable {
while (!hasEnded()) { while (!hasEnded()) {
playerId = players[RandomUtil.nextInt(players.length)]; playerId = players[RandomUtil.nextInt(players.length)];
Player player = getPlayer(playerId); Player player = getPlayer(playerId);
if (player != null && player.isInGame()) { if (player != null && player.canRespond()) {
fireInformEvent(state.getPlayer(playerId).getLogName() + " won the toss"); fireInformEvent(state.getPlayer(playerId).getLogName() + " won the toss");
return player.getId(); return player.getId();
} }
@ -3281,7 +3281,7 @@ public abstract class GameImpl implements Game, Serializable {
gameStatesRollBack.put(getTurnNum(), state.copy()); gameStatesRollBack.put(getTurnNum(), state.copy());
executingRollback = true; executingRollback = true;
for (Player playerObject : getPlayers().values()) { for (Player playerObject : getPlayers().values()) {
if (playerObject.isHuman() && playerObject.isInGame()) { if (playerObject.isHuman() && playerObject.canRespond()) {
playerObject.resetStoredBookmark(this); playerObject.resetStoredBookmark(this);
playerObject.abort(); playerObject.abort();
playerObject.resetPlayerPassedActions(); playerObject.resetPlayerPassedActions();

View file

@ -1,17 +1,10 @@
package mage.game.combat; package mage.game.combat;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility; import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility;
import mage.abilities.common.ControllerDivideCombatDamageAbility; import mage.abilities.common.ControllerDivideCombatDamageAbility;
import mage.abilities.common.DamageAsThoughNotBlockedAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility;
import mage.abilities.keyword.BandingAbility; import mage.abilities.keyword.*;
import mage.abilities.keyword.BandsWithOtherAbility;
import mage.abilities.keyword.CantBlockAloneAbility;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.constants.AsThoughEffectType; import mage.constants.AsThoughEffectType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -27,7 +20,6 @@ import java.util.*;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class CombatGroup implements Serializable, Copyable<CombatGroup> { public class CombatGroup implements Serializable, Copyable<CombatGroup> {
@ -409,7 +401,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
} }
if (damage > 0) { if (damage > 0) {
Player defendingPlayer = game.getPlayer(defendingPlayerId); Player defendingPlayer = game.getPlayer(defendingPlayerId);
if (defendingPlayer.isInGame()) { if (defendingPlayer != null) {
defendingPlayer.damage(damage, attacker.getId(), game, true, true); defendingPlayer.damage(damage, attacker.getId(), game, true, true);
} }
} }
@ -466,9 +458,9 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
* Damages attacking creatures by a creature that blocked several ones * Damages attacking creatures by a creature that blocked several ones
* Damages only attackers as blocker was damage in * Damages only attackers as blocker was damage in
* {@link #singleBlockerDamage}. * {@link #singleBlockerDamage}.
* * <p>
* Handles abilities like "{this} an block any number of creatures.". * Handles abilities like "{this} an block any number of creatures.".
* * <p>
* Blocker damage for blockers blocking single creatures is handled in the * Blocker damage for blockers blocking single creatures is handled in the
* single/multi blocker methods, so this shouldn't be used anymore. * single/multi blocker methods, so this shouldn't be used anymore.
* *
@ -492,7 +484,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
* Damages attacking creatures by a creature that blocked several ones * Damages attacking creatures by a creature that blocked several ones
* Damages only attackers as blocker was damage in either * Damages only attackers as blocker was damage in either
* {@link #singleBlockerDamage} or {@link #multiBlockerDamage}. * {@link #singleBlockerDamage} or {@link #multiBlockerDamage}.
* * <p>
* Handles abilities like "{this} an block any number of creatures.". * Handles abilities like "{this} an block any number of creatures.".
* *
* @param first * @param first
@ -552,7 +544,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
} }
} else { } else {
Player defender = game.getPlayer(defenderId); Player defender = game.getPlayer(defenderId);
if (defender.isInGame()) { if (defender != null) {
defender.damage(amount, attacker.getId(), game, true, true); defender.damage(amount, attacker.getId(), game, true, true);
} }
} }
@ -572,7 +564,6 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
} }
/** /**
*
* @param blockerId * @param blockerId
* @param playerId controller of the blocking creature * @param playerId controller of the blocking creature
* @param game * @param game
@ -645,7 +636,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
attackerPerms.add(game.getPermanent(attackerId)); attackerPerms.add(game.getPermanent(attackerId));
} }
UUID attackerId = player.chooseAttackerOrder(attackerPerms, game); UUID attackerId = player.chooseAttackerOrder(attackerPerms, game);
if (!player.isInGame()) { if (attackerId == null) {
break; break;
} }
attackerOrder.add(attackerId); attackerOrder.add(attackerId);
@ -791,7 +782,7 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
/** /**
* There are effects, that set an attacker to be blocked. Therefore this * There are effects, that set an attacker to be blocked. Therefore this
* setter can be used. * setter can be used.
* * <p>
* This method lacks a band check, use setBlocked(blocked, game) instead. * This method lacks a band check, use setBlocked(blocked, game) instead.
* *
* @param blocked * @param blocked

View file

@ -53,6 +53,7 @@ public class PlayerList extends CircularList<UUID> {
player.setReachedNextTurnAfterLeaving(true); player.setReachedNextTurnAfterLeaving(true);
} }
} }
if (player.getId().equals(start)) { if (player.getId().equals(start)) {
return null; return null;
} }
@ -63,11 +64,15 @@ public class PlayerList extends CircularList<UUID> {
public Player getPrevious(Game game) { public Player getPrevious(Game game) {
Player player; Player player;
UUID start = this.get(); UUID start = this.get();
if (start == null) {
return null;
}
while (true) { while (true) {
player = game.getPlayer(super.getPrevious()); player = game.getPlayer(super.getPrevious());
if (player.isInGame()) { if (player.isInGame()) {
break; break;
} }
if (player.getId().equals(start)) { if (player.getId().equals(start)) {
return null; return null;
} }