Multiple fixes.

- Make determination of card viewing permissions much faster;
- A general fix related to choosing a fixed amount of options from a list;
- Improve display of card's names;
- Reduce card flickering when changing phases.
This commit is contained in:
elcnesh
2014-09-28 15:43:34 +00:00
parent 6969aaad91
commit e44b4b3cbc
20 changed files with 111 additions and 120 deletions

View File

@@ -809,12 +809,17 @@ public class GameAction {
* <p>
* checkStateEffects.
* </p>
*
* @param runEvents
* {@code true} to have this method run
* {@link GameEventCardStatsChanged} events.
* @return a set of affected cards.
*/
public final void checkStateEffects() {
public final Set<Card> checkStateEffects(final boolean runEvents) {
// sol(10/29) added for Phase updates, state effects shouldn't be
// checked during Spell Resolution (except when persist-returning
if (game.getStack().isResolving()) {
return;
return Collections.emptySet();
}
// final JFrame frame = Singletons.getView().getFrame();
@@ -823,7 +828,7 @@ public class GameAction {
// }
if (game.isGameOver()) {
return;
return Collections.emptySet();
}
// Max: I don't know where to put this! - but since it's a state based action, it must be in check state effects
@@ -835,8 +840,8 @@ public class GameAction {
final boolean refreeze = game.getStack().isFrozen();
game.getStack().setFrozen(true);
// do this twice, sometimes creatures/permanents will survive when they
// shouldn't
// do this multiple times, sometimes creatures/permanents will survive
// when they shouldn't
final Set<Card> allAffectedCards = Sets.newHashSet();
for (int q = 0; q < 9; q++) {
final Set<Card> affectedCards = this.checkStaticAbilities(false);
@@ -923,18 +928,22 @@ public class GameAction {
if (!checkAgain) {
break; // do not continue the loop
}
} // for q=0;q<2
} // for q=0;q<9
game.fireEvent(new GameEventCardStatsChanged(allAffectedCards));
if (runEvents) {
game.fireEvent(new GameEventCardStatsChanged(allAffectedCards));
}
checkGameOverCondition();
if (game.getAge() != GameStage.Play)
return;
return Collections.emptySet();
game.getTriggerHandler().resetActiveTriggers();
if (!refreeze) {
game.getStack().unfreezeStack();
}
return allAffectedCards;
} // checkStateEffects()
/**
@@ -1561,7 +1570,7 @@ public class GameAction {
}
runOpeningHandActions(first);
checkStateEffects(); // why?
checkStateEffects(true); // why?
// Run Trigger beginning of the game
final HashMap<String, Object> runParams = new HashMap<String, Object>();

View File

@@ -86,6 +86,7 @@ public class StaticEffects implements IGameStateObject {
final List<Card> affectedCards = se.getAffectedCards();
final ArrayList<Player> affectedPlayers = se.getAffectedPlayers();
final Map<String, String> params = se.getParams();
final Player controller = se.getSource().getController();
String changeColorWordsTo = null;
@@ -97,6 +98,7 @@ public class StaticEffects implements IGameStateObject {
boolean setPT = false;
String[] addHiddenKeywords = null;
String addColors = null;
boolean removeMayLookAt = false;
if (params.containsKey("ChangeColorWordsTo")) {
changeColorWordsTo = params.get("ChangeColorWordsTo");
@@ -159,6 +161,10 @@ public class StaticEffects implements IGameStateObject {
}
}
if (params.containsKey("MayLookAt")) {
removeMayLookAt = true;
}
if (params.containsKey("IgnoreEffectCost")) {
for (final SpellAbility s : se.getSource().getSpellAbilities()) {
if (s instanceof AbilityStatic && s.isTemporary()) {
@@ -249,6 +255,11 @@ public class StaticEffects implements IGameStateObject {
affectedCard.removeColor(addColors, affectedCard, !se.isOverwriteColors(),
se.getTimestamp(affectedCard));
}
// remove may look at
if (removeMayLookAt) {
affectedCard.setMayLookAt(controller, false);
}
}
se.clearTimestamps();
return affectedCards;

View File

@@ -33,7 +33,7 @@ public class EndTurnEffect extends SpellAbilityEffect {
// 3) State-based actions are checked. No player gets priority, and no
// triggered abilities are put onto the stack.
game.getAction().checkStateEffects();
game.getAction().checkStateEffects(true);
// 4) The current phase and/or step ends. The game skips straight to the
// cleanup step. The cleanup step happens in its entirety.

View File

@@ -210,6 +210,7 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
private Player controller = null;
private long controllerTimestamp = 0;
private TreeMap<Long, Player> tempControllers = new TreeMap<Long, Player>();
private final Set<Player> mayLookAt = Sets.newHashSet();
private String originalText = "", text = "";
private String echoCost = "";
@@ -3256,6 +3257,14 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
this.owner = player;
}
public final void setMayLookAt(final Player player, final boolean mayLookAt) {
if (mayLookAt) {
this.mayLookAt.add(player);
} else {
this.mayLookAt.remove(player);
}
}
/**
* <p>
* Getter for the field <code>equippedBy</code>.
@@ -4013,7 +4022,7 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
* left and right values of a {@link Pair}, respectively. A value of -1
* means that particular property has not been set.
*/
private final Pair<Integer, Integer> getLatestPT() {
private final synchronized Pair<Integer, Integer> getLatestPT() {
// Find latest set power
long maxPowerTimestamp = -2;
int latestPower = -1;
@@ -6336,9 +6345,13 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
final SpellAbility root = sa.getRootAbility();
if (root != null && (root.getPaidList("MovedToGrave") != null)
&& !root.getPaidList("MovedToGrave").isEmpty()) {
List<Card> list = root.getPaidList("MovedToGrave");
for (Card card : list) {
if (this.getName().equals(card.getName())) {
final List<Card> list = root.getPaidList("MovedToGrave");
for (final Card card : list) {
String name = card.getName();
if (StringUtils.isEmpty(name)) {
name = card.getPaperCard().getName();
}
if (this.getName().equals(name)) {
return true;
}
}
@@ -8933,15 +8946,9 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
return true;
}
//one last check to see if card can be shown
final Game game = this.getGame();
for (Card host : game.getCardsIn(ZoneType.Battlefield)) {
final ArrayList<StaticAbility> staticAbilities = host.getStaticAbilities();
for (final StaticAbility stAb : staticAbilities) {
if (stAb.applyAbility("MayLookAt", this, viewer)) {
return true;
}
}
// special viewing permissions for viewer
if (this.mayLookAt.contains(viewer)) {
return true;
}
//if viewer is controlled by another player, also check if card can be shown to that player
@@ -8959,6 +8966,12 @@ public class Card extends GameEntity implements Comparable<Card>, IIdentifiable
if (viewer.hasKeyword("CanSeeOpponentsFaceDownCards")) {
return true;
}
// special viewing permissions for viewer
if (this.mayLookAt.contains(viewer)) {
return true;
}
//if viewer is controlled by another player, also check if face can be shown to that player
if (viewer.isMindSlaved() && canCardFaceBeShownTo(viewer.getMindSlaveMaster())) {
return true;

View File

@@ -19,6 +19,7 @@ package forge.game.phase;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import forge.card.mana.ManaCost;
import forge.game.*;
@@ -384,7 +385,7 @@ public class PhaseHandler implements java.io.Serializable, IGameStateObject {
givePriorityToPlayer = false;
// Rule 514.3a - state-based actions
game.getAction().checkStateEffects();
game.getAction().checkStateEffects(true);
break;
default:
@@ -1001,17 +1002,19 @@ public class PhaseHandler implements java.io.Serializable, IGameStateObject {
int loopCount = 0;
do {
final Set<Card> allAffectedCards = Sets.newHashSet();
boolean addedAnythingToStack = false;
do {
// Rule 704.3 Whenever a player would get priority, the game checks ... for state-based actions,
game.getAction().checkStateEffects();
allAffectedCards.addAll(game.getAction().checkStateEffects(false));
if (game.isGameOver())
return; // state-based effects check could lead to game over
addedAnythingToStack = game.getStack().addAllTriggeredAbilitiesToStack();
} while(addedAnythingToStack);
game.fireEvent(new GameEventCardStatsChanged(allAffectedCards));
if (playerTurn.hasLost() && pPlayerPriority.equals(playerTurn) && pFirstPriority.equals(playerTurn)) {
// If the active player has lost, and they have priority, set the next player to have priority
System.out.println("Active player is no longer in the game...");

View File

@@ -288,10 +288,6 @@ public class StaticAbility extends CardTraitBase {
return StaticAbilityCantBeCast.applyCantPlayLandAbility(this, card, player);
}
if (mode.equals("MayLookAt")) {
return StaticAbilityMayLookAt.applyMayLookAtAbility(this, card, player);
}
return false;
}

View File

@@ -69,6 +69,7 @@ public class StaticAbilityContinuous {
public static List<Card> applyContinuousAbility(final StaticAbility stAb, List<Card> affectedCards) {
final Map<String, String> params = stAb.getMapParams();
final Card hostCard = stAb.getHostCard();
final Player controller = hostCard.getController();
final StaticEffect se = new StaticEffect(hostCard);
final ArrayList<Player> affectedPlayers = StaticAbilityContinuous.getAffectedPlayers(stAb);
@@ -109,6 +110,7 @@ public class StaticAbilityContinuous {
boolean removeCardTypes = false;
boolean removeSubTypes = false;
boolean removeCreatureTypes = false;
boolean controllerMayLookAt = false;
//Global rules changes
if (params.containsKey("GlobalRule")) {
@@ -326,6 +328,10 @@ public class StaticAbilityContinuous {
}
}
if (params.containsKey("MayLookAt")) {
controllerMayLookAt = true;
}
if (params.containsKey("IgnoreEffectCost")) {
String cost = params.get("IgnoreEffectCost");
buildIgnorEffectAbility(stAb, cost, affectedPlayers, affectedCards);
@@ -551,6 +557,10 @@ public class StaticAbilityContinuous {
rE.setTemporarilySuppressed(true);
}
}
if (controllerMayLookAt) {
affectedCard.setMayLookAt(controller, true);
}
}
return affectedCards;

View File

@@ -1,65 +0,0 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.staticability;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import java.util.Map;
/**
* The Class StaticAbility_CantBeCast.
*/
public class StaticAbilityMayLookAt {
/**
* TODO Write javadoc for this method.
*
* @param stAb
* a StaticAbility
* @param card
* the card
* @param activator
* the player
* @return true, if successful
*/
public static boolean applyMayLookAtAbility(final StaticAbility stAb, final Card card, final Player player) {
final Map<String, String> params = stAb.getMapParams();
final Card hostCard = stAb.getHostCard();
if (params.containsKey("Affected")
&& !card.isValid(params.get("Affected").split(","), hostCard.getController(), hostCard)) {
return false;
}
if (params.containsKey("Player") && player != null
&& !player.isValid(params.get("Player"), hostCard.getController(), hostCard)) {
return false;
}
if (params.containsKey("AffectedZone")) {
ZoneType zone = card.getGame().getZoneOf(card).getZoneType();
if (!ZoneType.listValueOf(params.get("AffectedZone")).contains(zone)) {
return false;
}
}
return true;
}
}