mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
CStack updates are also driven by events. CStack no longer observable
This commit is contained in:
@@ -3918,8 +3918,8 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @param n
|
||||
* a int.
|
||||
*/
|
||||
public final void setReplicateMagnitude(final int n) {
|
||||
this.replicateMagnitude = n;
|
||||
public final void resetReplicateMagnitude() {
|
||||
this.replicateMagnitude = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,6 @@ public class EndTurnEffect extends SpellAbilityEffect {
|
||||
game.getPhaseHandler().endTurnByEffect();
|
||||
|
||||
// Update observers
|
||||
game.getStack().updateObservers();
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.updateObservers();
|
||||
p.updateLabelObservers();
|
||||
|
||||
@@ -13,6 +13,9 @@ import forge.game.event.GameEventAnteCardsSelected;
|
||||
import forge.game.event.GameEventGameFinished;
|
||||
import forge.game.event.GameEventGameOutcome;
|
||||
import forge.game.event.GameEventPlayerControl;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTurnBegan;
|
||||
import forge.game.event.GameEventTurnPhase;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
@@ -24,6 +27,7 @@ import forge.gui.match.CMatchUI;
|
||||
import forge.gui.match.VMatchUI;
|
||||
import forge.gui.match.ViewWinLose;
|
||||
import forge.gui.match.controllers.CMessage;
|
||||
import forge.gui.match.controllers.CStack;
|
||||
import forge.gui.match.nonsingleton.VHand;
|
||||
import forge.gui.match.nonsingleton.VField.PhaseLabel;
|
||||
|
||||
@@ -113,4 +117,30 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
} });
|
||||
return null;
|
||||
}
|
||||
|
||||
private final AtomicBoolean stackUpdPlanned = new AtomicBoolean(false);
|
||||
private final Runnable updStack = new Runnable() { @Override public void run() {
|
||||
stackUpdPlanned.set(false);
|
||||
CStack.SINGLETON_INSTANCE.update();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventSpellAbilityCast event) {
|
||||
if ( !stackUpdPlanned.getAndSet(true) )
|
||||
FThreads.invokeInEdtNowOrLater(updStack);
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Void visit(GameEventSpellResolved event) {
|
||||
if ( !stackUpdPlanned.getAndSet(true) )
|
||||
FThreads.invokeInEdtNowOrLater(updStack);
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Void visit(GameEventSpellRemovedFromStack event) {
|
||||
if ( !stackUpdPlanned.getAndSet(true) )
|
||||
FThreads.invokeInEdtNowOrLater(updStack);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ import forge.util.TextUtil;
|
||||
*/
|
||||
public final class GameActionUtil {
|
||||
|
||||
private static final class CascadeAbility extends Ability {
|
||||
public static final class CascadeAbility extends Ability {
|
||||
private final Player controller;
|
||||
private final Card cascCard;
|
||||
|
||||
@@ -132,7 +132,7 @@ public final class GameActionUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CascadeExecutor implements Command {
|
||||
public static final class CascadeExecutor implements Command {
|
||||
private final Card c;
|
||||
private final Game game;
|
||||
private final Player controller;
|
||||
@@ -144,7 +144,7 @@ public final class GameActionUtil {
|
||||
* @param controller
|
||||
* @param c
|
||||
*/
|
||||
private CascadeExecutor(Player controller, Card c, final Game game) {
|
||||
public CascadeExecutor(Player controller, Card c, final Game game) {
|
||||
this.controller = controller;
|
||||
this.c = c;
|
||||
this.game = game;
|
||||
@@ -187,7 +187,7 @@ public final class GameActionUtil {
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
private static final class RippleAbility extends Ability {
|
||||
public static final class RippleAbility extends Ability {
|
||||
private final Player controller;
|
||||
private final int rippleCount;
|
||||
private final Card rippleCard;
|
||||
@@ -263,7 +263,7 @@ public final class GameActionUtil {
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
private static final class RippleExecutor implements Command {
|
||||
public static final class RippleExecutor implements Command {
|
||||
private final Player controller;
|
||||
private final Card c;
|
||||
private static final long serialVersionUID = -845154812215847505L;
|
||||
@@ -273,7 +273,7 @@ public final class GameActionUtil {
|
||||
* @param controller
|
||||
* @param c
|
||||
*/
|
||||
private RippleExecutor(Player controller, Card c) {
|
||||
public RippleExecutor(Player controller, Card c) {
|
||||
this.controller = controller;
|
||||
this.c = c;
|
||||
}
|
||||
@@ -316,24 +316,6 @@ public final class GameActionUtil {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* executePlayCardEffects.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public static void executePlayCardEffects(final SpellAbility sa) {
|
||||
// (called from MagicStack.java)
|
||||
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
final Command cascade = new CascadeExecutor(sa.getActivatingPlayer(), sa.getSourceCard(), game);
|
||||
cascade.run();
|
||||
final Command ripple = new RippleExecutor(sa.getActivatingPlayer(), sa.getSourceCard());
|
||||
ripple.run();
|
||||
}
|
||||
|
||||
// this is for cards like Sengir Vampire
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -9,9 +9,11 @@ import forge.card.spellability.SpellAbility;
|
||||
public class GameEventSpellAbilityCast extends GameEvent {
|
||||
|
||||
public final SpellAbility sa;
|
||||
public final boolean replicate;
|
||||
|
||||
public GameEventSpellAbilityCast(SpellAbility sp) {
|
||||
public GameEventSpellAbilityCast(SpellAbility sp, boolean replicate) {
|
||||
sa = sp;
|
||||
this.replicate = replicate;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package forge.game.event;
|
||||
|
||||
import forge.card.spellability.SpellAbility;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class GameEventSpellRemovedFromStack extends GameEvent {
|
||||
public final SpellAbility sa;
|
||||
|
||||
public GameEventSpellRemovedFromStack(SpellAbility spellAbility) {
|
||||
sa = spellAbility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
// TODO Auto-generated method stub
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public interface IGameEventVisitor<T> {
|
||||
T visit(GameEventShuffle event);
|
||||
T visit(GameEventSpellAbilityCast gameEventSpellAbilityCast);
|
||||
T visit(GameEventSpellResolved event);
|
||||
T visit(GameEventSpellRemovedFromStack event);
|
||||
T visit(GameEventTokenCreated event);
|
||||
T visit(GameEventTurnBegan gameEventTurnBegan);
|
||||
T visit(GameEventTurnEnded event);
|
||||
@@ -68,6 +69,7 @@ public interface IGameEventVisitor<T> {
|
||||
public T visit(GameEventShuffle event) { return null; }
|
||||
public T visit(GameEventSpellResolved event) { return null; }
|
||||
public T visit(GameEventSpellAbilityCast event) { return null; }
|
||||
public T visit(GameEventSpellRemovedFromStack event) { return null; }
|
||||
public T visit(GameEventTokenCreated event) { return null; }
|
||||
public T visit(GameEventTurnBegan event) { return null; }
|
||||
public T visit(GameEventTurnEnded event) { return null; }
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.esotericsoftware.minlog.Log;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.Command;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.CardPredicates.Presets;
|
||||
@@ -51,11 +52,13 @@ import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetChoices;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil.CascadeExecutor;
|
||||
import forge.game.GameActionUtil.RippleExecutor;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.player.HumanPlay;
|
||||
import forge.game.player.Player;
|
||||
@@ -63,7 +66,6 @@ import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.input.InputSelectCards;
|
||||
import forge.gui.input.InputSelectCardsFromList;
|
||||
import forge.util.MyObservable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -73,7 +75,7 @@ import forge.util.MyObservable;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MagicStack extends MyObservable implements Iterable<SpellAbilityStackInstance> {
|
||||
public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbilityStackInstance> {
|
||||
private final List<SpellAbility> simultaneousStackEntryList = new ArrayList<SpellAbility>();
|
||||
|
||||
// They don't provide a LIFO queue, so had to use a deque
|
||||
@@ -133,7 +135,6 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
this.thisTurnCast.clear();
|
||||
this.curResolvingCard = null;
|
||||
this.frozenStack.clear();
|
||||
this.updateObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +300,6 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
return;
|
||||
}
|
||||
|
||||
game.fireEvent(new GameEventSpellAbilityCast(sp));
|
||||
|
||||
// if activating player slips through the cracks, assign activating
|
||||
// Player to the controller here
|
||||
@@ -341,12 +341,12 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
if (sp.isReplicate()) {
|
||||
// TODO: convert multikicker/replicate support in abCost so this
|
||||
// doesn't happen here
|
||||
// X and multi and replicate are not supported yet
|
||||
|
||||
final Player activating = sp.getActivatingPlayer();
|
||||
final Cost costMultikicker = new Cost(sp.getMultiKickerManaCost(), false);
|
||||
|
||||
final Cost costMultikicker = new Cost(sp.getReplicateManaCost(), false);
|
||||
sp.getSourceCard().resetReplicateMagnitude();
|
||||
boolean hasPaid = false;
|
||||
|
||||
do {
|
||||
int rMagnitude = sp.getSourceCard().getReplicateMagnitude();
|
||||
String prompt = String.format("Replicate for %s\r\nTimes Replicated: %d\r\n", sp.getSourceCard(), rMagnitude);
|
||||
@@ -464,6 +464,7 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
final SpellAbilityStackInstance si = new SpellAbilityStackInstance(sp);
|
||||
|
||||
this.stack.addFirst(si);
|
||||
game.fireEvent(new GameEventSpellAbilityCast(sp, false));
|
||||
|
||||
// 2012-07-21 the following comparison needs to move below the pushes but somehow screws up priority
|
||||
// When it's down there. That makes absolutely no sense to me, so i'm putting it back for now
|
||||
@@ -472,12 +473,14 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
game.getPhaseHandler().setPriority(sp.getActivatingPlayer());
|
||||
}
|
||||
|
||||
this.updateObservers();
|
||||
|
||||
if (sp.isSpell() && !sp.getSourceCard().isCopiedSpell()) {
|
||||
this.thisTurnCast.add(sp.getSourceCard());
|
||||
|
||||
GameActionUtil.executePlayCardEffects(sp);
|
||||
final Game game = sp.getActivatingPlayer().getGame();
|
||||
final Command cascade = new CascadeExecutor(sp.getActivatingPlayer(), sp.getSourceCard(), game);
|
||||
cascade.run();
|
||||
final Command ripple = new RippleExecutor(sp.getActivatingPlayer(), sp.getSourceCard());
|
||||
ripple.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,6 +519,7 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
sa.resolve();
|
||||
// do creatures ETB from here?
|
||||
}
|
||||
|
||||
this.finishResolving(sa, thisHasFizzled);
|
||||
|
||||
game.fireEvent(new GameEventSpellResolved(sa, thisHasFizzled));
|
||||
@@ -572,20 +576,17 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
if (si != null) {
|
||||
this.remove(si);
|
||||
}
|
||||
|
||||
|
||||
// After SA resolves we have to do a handful of things
|
||||
this.setResolving(false);
|
||||
this.unfreezeStack();
|
||||
sa.resetOnceResolved();
|
||||
|
||||
|
||||
game.getAction().checkStateEffects();
|
||||
|
||||
game.getPhaseHandler().onStackResolved();
|
||||
|
||||
|
||||
this.curResolvingCard = null;
|
||||
|
||||
this.updateObservers();
|
||||
|
||||
|
||||
// TODO: this is a huge hack. Why is this necessary?
|
||||
// hostCard in AF is not the same object that's on the battlefield
|
||||
// verified by System.identityHashCode(card);
|
||||
@@ -728,7 +729,7 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
public final void remove(final SpellAbilityStackInstance si) {
|
||||
this.stack.remove(si);
|
||||
this.frozenStack.remove(si);
|
||||
this.updateObservers();
|
||||
game.fireEvent(new GameEventSpellRemovedFromStack(si.getSpellAbility()));
|
||||
}
|
||||
|
||||
public final SpellAbilityStackInstance getInstanceFromSpellAbility(final SpellAbility sa) {
|
||||
@@ -901,6 +902,7 @@ public class MagicStack extends MyObservable implements Iterable<SpellAbilitySta
|
||||
*/
|
||||
public void clear() {
|
||||
stack.clear();
|
||||
game.fireEvent(new GameEventSpellRemovedFromStack(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package forge.gui.match.controllers;
|
||||
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import forge.Command;
|
||||
import forge.FThreads;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.game.zone.MagicStack;
|
||||
import forge.gui.framework.EDocID;
|
||||
@@ -18,7 +14,7 @@ import forge.gui.match.views.VStack;
|
||||
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
|
||||
*
|
||||
*/
|
||||
public enum CStack implements ICDoc, Observer {
|
||||
public enum CStack implements ICDoc {
|
||||
/** */
|
||||
SINGLETON_INSTANCE;
|
||||
|
||||
@@ -40,32 +36,15 @@ public enum CStack implements ICDoc, Observer {
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
private final Runnable upd = new Runnable() { @Override public void run() {
|
||||
SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
|
||||
VStack.SINGLETON_INSTANCE.updateStack(model, viewer);
|
||||
} };
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void update(final Observable arg0, Object arg1) {
|
||||
update();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.gui.framework.ICDoc#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
FThreads.invokeInEdtNowOrLater(upd);
|
||||
SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
|
||||
VStack.SINGLETON_INSTANCE.updateStack(model, viewer);
|
||||
}
|
||||
|
||||
public void setModel(MagicStack model, LobbyPlayer guiPlayer) {
|
||||
this.model = model;
|
||||
this.viewer = guiPlayer;
|
||||
|
||||
model.addObserver(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user