CStack updates are also driven by events. CStack no longer observable

This commit is contained in:
Maxmtg
2013-06-01 23:58:25 +00:00
parent f137ac390f
commit 84a9732541
10 changed files with 90 additions and 71 deletions

View File

@@ -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;
}
/**

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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; }

View File

@@ -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

View File

@@ -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);
}
}