Log uses GameEvent to recieve 'damaged' information

DeckChooser allows decks from quest shop
This commit is contained in:
Maxmtg
2013-05-29 21:53:47 +00:00
parent b798eef761
commit 77a319deac
13 changed files with 222 additions and 88 deletions

3
.gitattributes vendored
View File

@@ -14240,7 +14240,8 @@ src/main/java/forge/game/event/GameEventLifeLoss.java -text
src/main/java/forge/game/event/GameEventManaBurn.java -text
src/main/java/forge/game/event/GameEventMulligan.java -text
src/main/java/forge/game/event/GameEventPlayerControl.java -text
src/main/java/forge/game/event/GameEventPoisonCounter.java -text
src/main/java/forge/game/event/GameEventPlayerDamaged.java -text
src/main/java/forge/game/event/GameEventPlayerPoisoned.java -text
src/main/java/forge/game/event/GameEventShuffle.java -text
src/main/java/forge/game/event/GameEventSpellResolved.java -text
src/main/java/forge/game/event/GameEventTokenCreated.java -text

View File

@@ -65,6 +65,7 @@ import forge.card.trigger.ZCTrigger;
import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardDamaged.DamageType;
import forge.game.event.GameEventCardEquipped;
import forge.game.event.GameEventCounterAdded;
import forge.game.event.GameEventCounterRemoved;
@@ -7354,39 +7355,41 @@ public class Card extends GameEntity implements Comparable<Card> {
runParams.put("IsCombatDamage", isCombat);
getGame().getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
String additionalLog = "";
GameEventCardDamaged.DamageType damageType = DamageType.Normal;
if (this.isPlaneswalker()) {
this.subtractCounter(CounterType.LOYALTY, damageToAdd);
additionalLog = String.format("(Removing %d Loyalty Counters)", damageToAdd);
damageType = DamageType.LoyaltyLoss;
} else {
final Game game = source.getGame();
final String s = this + " - destroy";
final String s = this + " - destroy";
final int amount = this.getAmountOfKeyword("When CARDNAME is dealt damage, destroy it.");
if(amount > 0) {
final Ability abDestroy = new Ability(source, ManaCost.ZERO){
@Override public void resolve() { game.getAction().destroy(Card.this, this); }
};
abDestroy.setStackDescription(s + ", it cannot be regenerated.");
final int amount = this.getAmountOfKeyword("When CARDNAME is dealt damage, destroy it.");
if(amount > 0) {
final Ability abDestroy = new Ability(source, ManaCost.ZERO){
@Override public void resolve() { game.getAction().destroy(Card.this, this); }
};
abDestroy.setStackDescription(s + ", it cannot be regenerated.");
for (int i = 0; i < amount; i++) {
game.getStack().addSimultaneousStackEntry(abDestroy);
}
for (int i = 0; i < amount; i++) {
game.getStack().addSimultaneousStackEntry(abDestroy);
}
}
final int amount2 = this.getAmountOfKeyword("When CARDNAME is dealt damage, destroy it. It can't be regenerated.");
if( amount2 > 0 ) {
final Ability abDestoryNoRegen = new Ability(source, ManaCost.ZERO){
@Override public void resolve() { game.getAction().destroyNoRegeneration(Card.this, this); }
};
abDestoryNoRegen.setStackDescription(s);
final int amount2 = this.getAmountOfKeyword("When CARDNAME is dealt damage, destroy it. It can't be regenerated.");
if( amount2 > 0 ) {
final Ability abDestoryNoRegen = new Ability(source, ManaCost.ZERO){
@Override public void resolve() { game.getAction().destroyNoRegeneration(Card.this, this); }
};
abDestoryNoRegen.setStackDescription(s);
for (int i = 0; i < amount2; i++) {
game.getStack().addSimultaneousStackEntry(abDestoryNoRegen);
}
for (int i = 0; i < amount2; i++) {
game.getStack().addSimultaneousStackEntry(abDestoryNoRegen);
}
}
boolean wither = (getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.alwaysWither)
@@ -7395,21 +7398,20 @@ public class Card extends GameEntity implements Comparable<Card> {
if (this.isInPlay()) {
if (wither) {
this.addCounter(CounterType.M1M1, damageToAdd, true);
additionalLog = "(As -1/-1 Counters)";
damageType = DamageType.M1M1Counters;
} else
this.damage += damageToAdd;
}
if (source.hasKeyword("Deathtouch") && this.isCreature()) {
getGame().getAction().destroy(this, null);
additionalLog = "(Deathtouch)";
damageType = DamageType.Deathtouch;
}
// Play the Damage sound
game.fireEvent(new GameEventCardDamaged());
game.fireEvent(new GameEventCardDamaged(this, source, damageToAdd, damageType));
}
getGame().getGameLog().add(GameLogEntryType.DAMAGE, String.format("Dealing %d damage to %s. %s", damageToAdd, this.getName(), additionalLog));
return true;
}

View File

@@ -13,7 +13,6 @@ public enum GameLogEntryType {
STACK_RESOLVE("Resolve stack"),
STACK_ADD("Add to stack"),
DAMAGE("Damage"),
DAMAGE_POISON("Poison"),
MANA("Mana"),
PHASE("Phase");

View File

@@ -7,6 +7,10 @@ import java.util.Map.Entry;
import com.google.common.eventbus.Subscribe;
import forge.game.GameOutcome;
import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardDamaged.DamageType;
import forge.game.event.GameEventPlayerDamaged;
import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.IGameEventVisitor;
import forge.game.event.GameEventDuelOutcome;
import forge.game.event.GameEvent;
@@ -88,6 +92,30 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
}
@Override
public GameLogEntry visit(GameEventCardDamaged event) {
String additionalLog = "";
if( event.type == DamageType.Deathtouch ) additionalLog = " (Deathtouch)";
if( event.type == DamageType.M1M1Counters ) additionalLog = " (As -1/-1 Counters)";
if( event.type == DamageType.LoyaltyLoss ) additionalLog = " (Removing " + Lang.nounWithAmount(event.amount, "loyalty counter") + ")";
String message = String.format("%s deals %d damage%s to %s.", event.source, event.amount, event.damaged, additionalLog);
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override
public GameLogEntry visit(GameEventPlayerDamaged ev) {
String extra = ev.infect ? " (as poison counters)" : "";
String message = String.format("%s deals %d %s damage to %s%s.", ev.source, ev.amount, ev.combat ? "combat" : "non-combat", ev.target, extra );
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
@Override
public GameLogEntry visit(GameEventPlayerPoisoned ev) {
String message = String.format("%s receives %s from %s", ev.receiver, Lang.nounWithAmount(ev.amount, "posion counter"), ev.source);
return new GameLogEntry(GameLogEntryType.DAMAGE, message);
}
static GameLogEntry describeAttack(final Combat combat) {

View File

@@ -24,6 +24,7 @@ import forge.deck.generate.GenerateThemeDeck;
import forge.item.CardDb;
import forge.item.CardPrinted;
import forge.item.ItemPoolView;
import forge.item.PreconDeck;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.quest.QuestEventChallenge;
@@ -32,6 +33,7 @@ import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.MyRandom;
import forge.util.storage.IStorage;
import forge.util.storage.IStorageView;
/**
* Utility collection for various types of decks.
@@ -47,7 +49,8 @@ public class DeckgenUtil {
COLORS,
THEMES,
CUSTOM,
QUESTEVENTS
QUESTEVENTS,
PRECON
}
/**
@@ -106,6 +109,10 @@ public class DeckgenUtil {
return Singletons.getModel().getDecks().getConstructed().get(selection[0]);
}
public static Deck getPreconDeck(String[] selection) {
return QuestController.getPrecons().get(selection[0]).getDeck();
}
public static QuestEvent getQuestEvent(final String name) {
QuestController qCtrl = Singletons.getModel().getQuest();
for(QuestEventChallenge challenge : qCtrl.getChallenges()) {
@@ -147,6 +154,13 @@ public class DeckgenUtil {
return allDecks.get(name);
}
public static Deck getRandomPreconDeck() {
final IStorageView<PreconDeck> allDecks = QuestController.getPrecons();
final int rand = (int) (Math.floor(Math.random() * allDecks.size()));
final String name = allDecks.getNames().toArray(new String[0])[rand];
return allDecks.get(name).getDeck();
}
/** @return {@link forge.deck.Deck} */
public static Deck getRandomQuestDeck() {
final List<Deck> allQuestDecks = new ArrayList<Deck>();

View File

@@ -1,7 +1,28 @@
package forge.game.event;
import forge.Card;
public class GameEventCardDamaged extends GameEvent {
public enum DamageType {
Normal,
M1M1Counters,
Deathtouch,
LoyaltyLoss;
}
public final Card damaged;
public final Card source;
public final int amount;
public final DamageType type;
public GameEventCardDamaged(Card card, Card src, int damageToAdd, DamageType damageType) {
damaged = card;
source = src;
amount = damageToAdd;
type = damageType;
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);

View File

@@ -0,0 +1,42 @@
package forge.game.event;
import forge.Card;
import forge.game.player.Player;
/**
* TODO: Write javadoc for this type.
*
*/
public class GameEventPlayerDamaged extends GameEvent {
public final Player target;
public final Card source;
public final int amount;
final public boolean infect;
public final boolean combat;
/**
* TODO: Write javadoc for Constructor.
* @param player
* @param source
* @param amount
* @param isCombat
* @param infect
*/
public GameEventPlayerDamaged(Player player, Card source, int amount, boolean isCombat, boolean infect) {
target = player;
this.source = source;
this.amount = amount;
combat = isCombat;
this.infect = infect;
}
/* (non-Javadoc)
* @see forge.game.event.GameEvent#visit(forge.game.event.IGameEventVisitor)
*/
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -0,0 +1,30 @@
package forge.game.event;
import forge.Card;
import forge.game.player.Player;
/**
*
*
*/
public class GameEventPlayerPoisoned extends GameEvent {
public final Player receiver;
public final Card source;
public final int amount;
public GameEventPlayerPoisoned(Player recv, Card src, int n) {
receiver = recv;
source = src;
amount = n;
}
public GameEventPlayerPoisoned(Player recv, Card src) {
this(recv, src, 1);
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -1,30 +0,0 @@
package forge.game.event;
import forge.Card;
import forge.game.player.Player;
/**
*
*
*/
public class GameEventPoisonCounter extends GameEvent {
public final Player Receiver;
public final Card Source;
public final int Amount;
public GameEventPoisonCounter(Player recv, Card src, int n) {
Receiver = recv;
Source = src;
Amount = n;
}
public GameEventPoisonCounter(Player recv, Card src) {
this(recv, src, 1);
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -27,7 +27,8 @@ public interface IGameEventVisitor<T> {
T visit(GameEventManaBurn event);
T visit(GameEventMulligan event);
T visit(GameEventPlayerControl event);
T visit(GameEventPoisonCounter event);
T visit(GameEventPlayerDamaged gameEventPlayerDamaged);
T visit(GameEventPlayerPoisoned event);
T visit(GameEventShuffle event);
T visit(GameEventSpellResolved event);
T visit(GameEventTokenCreated event);
@@ -58,11 +59,12 @@ public interface IGameEventVisitor<T> {
public T visit(GameEventManaBurn event) { return null; }
public T visit(GameEventMulligan event) { return null; }
public T visit(GameEventPlayerControl event) { return null; }
public T visit(GameEventPoisonCounter event) { return null; }
public T visit(GameEventPlayerPoisoned event) { return null; }
public T visit(GameEventShuffle event) { return null; }
public T visit(GameEventSpellResolved event) { return null; }
public T visit(GameEventTokenCreated event) { return null; }
public T visit(GameEventTurnPhase event) { return null; }
public T visit(GameEventPlayerDamaged event) { return null; }
}
}

View File

@@ -63,7 +63,8 @@ import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventLifeLoss;
import forge.game.event.GameEventMulligan;
import forge.game.event.GameEventPlayerControl;
import forge.game.event.GameEventPoisonCounter;
import forge.game.event.GameEventPlayerDamaged;
import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventShuffle;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -622,38 +623,34 @@ public class Player extends GameEntity implements Comparable<Player> {
* @return whether or not damage was dealt
*/
@Override
public final boolean addDamageAfterPrevention(final int damage, final Card source, final boolean isCombat) {
final int damageToDo = damage;
if (damageToDo <= 0) {
public final boolean addDamageAfterPrevention(final int amount, final Card source, final boolean isCombat) {
if (amount <= 0) {
return false;
}
String additionalLog = "";
source.addDealtDamageToPlayerThisTurn(this.getName(), damageToDo);
//String additionalLog = "";
source.addDealtDamageToPlayerThisTurn(this.getName(), amount);
boolean infect = source.hasKeyword("Infect")
|| this.hasKeyword("All damage is dealt to you as though its source had infect.");
if (infect) {
this.addPoisonCounters(damageToDo, source);
additionalLog = "(as Poison Counters)";
this.addPoisonCounters(amount, source);
} else {
// Worship does not reduce the damage dealt but changes the effect
// of the damage
if (this.hasKeyword("Damage that would reduce your life total to less than 1 reduces it to 1 instead.")
&& this.life <= damageToDo) {
this.loseLife(Math.min(damageToDo, this.life - 1));
additionalLog = "(would reduce life total to less than 1, reduced to 1 instead.)";
&& this.life <= amount) {
this.loseLife(Math.min(amount, this.life - 1));
} else {
// rule 118.2. Damage dealt to a player normally causes that
// player to lose that much life.
this.loseLife(damageToDo);
this.loseLife(amount);
}
}
this.assignedDamage.put(source, damageToDo);
this.assignedDamage.put(source, amount);
if (source.hasKeyword("Lifelink")) {
source.getController().gainLife(damageToDo, source);
source.getController().gainLife(amount, source);
}
source.getDamageHistory().registerDamage(this);
this.getGame().fireEvent(new GameEventLifeLoss());
@@ -669,11 +666,11 @@ public class Player extends GameEntity implements Comparable<Player> {
final HashMap<String, Object> runParams = new HashMap<String, Object>();
runParams.put("DamageSource", source);
runParams.put("DamageTarget", this);
runParams.put("DamageAmount", damageToDo);
runParams.put("DamageAmount", amount);
runParams.put("IsCombatDamage", isCombat);
game.getTriggerHandler().runTrigger(TriggerType.DamageDone, runParams, false);
game.getGameLog().add(GameLogEntryType.DAMAGE, String.format("Dealing %d damage to %s. %s", damageToDo, this.getName(), additionalLog));
game.fireEvent(new GameEventPlayerDamaged(this, source, amount, isCombat, infect));
return true;
}
@@ -1020,9 +1017,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (!this.hasKeyword("You can't get poison counters")) {
this.poisonCounters += num;
game.fireEvent(new GameEventPoisonCounter(this, source, num));
game.getGameLog().add(GameLogEntryType.DAMAGE_POISON, this + " receives a poison counter from " + source);
game.fireEvent(new GameEventPlayerPoisoned(this, source, num));
this.updateObservers();
}
}

View File

@@ -26,11 +26,13 @@ import forge.deck.Deck;
import forge.deck.DeckgenUtil;
import forge.deck.generate.GenerateThemeDeck;
import forge.game.RegisteredPlayer;
import forge.item.PreconDeck;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.quest.QuestEventChallenge;
import forge.quest.QuestUtil;
import forge.util.storage.IStorage;
import forge.util.storage.IStorageView;
@SuppressWarnings("serial")
public class FDeckChooser extends JPanel {
@@ -38,6 +40,7 @@ public class FDeckChooser extends JPanel {
private final JRadioButton radThemes = new FRadioButton("Semi-random theme deck");
private final JRadioButton radCustom = new FRadioButton("Custom user deck");
private final JRadioButton radQuests = new FRadioButton("Quest opponent deck");
private final JRadioButton radPrecons = new FRadioButton("Decks from quest shop");
private final JList lstDecks = new FList();
private final FLabel btnRandom = new FLabel.ButtonBuilder().text("Random").fontSize(16).build();
@@ -101,6 +104,7 @@ public class FDeckChooser extends JPanel {
JXButtonPanel grpRadios = new JXButtonPanel();
grpRadios.add(radCustom, strRadioConstraints);
grpRadios.add(radQuests, strRadioConstraints);
grpRadios.add(radPrecons, strRadioConstraints);
grpRadios.add(radColors, strRadioConstraints);
grpRadios.add(radThemes, strRadioConstraints);
@@ -122,6 +126,7 @@ public class FDeckChooser extends JPanel {
_listen(getRadThemes(), new Runnable() { @Override public void run() { updateThemes(); } });
_listen(getRadCustom(), new Runnable() { @Override public void run() { updateCustom(); } });
_listen(getRadQuests(), new Runnable() { @Override public void run() { updateQuestEvents(); } });
_listen(getRadPrecons(), new Runnable() { @Override public void run() { updatePrecons(); } });
// First run: colors
getRadColors().setSelected(true);
@@ -138,6 +143,7 @@ public class FDeckChooser extends JPanel {
private JRadioButton getRadThemes() { return radThemes; }
private JRadioButton getRadCustom() { return radCustom; }
private JRadioButton getRadQuests() { return radQuests; }
private JRadioButton getRadPrecons() { return radPrecons; }
/** Handles all control for "colors" radio button click. */
private void updateColors() {
@@ -202,6 +208,28 @@ public class FDeckChooser extends JPanel {
lst.setSelectedIndex(0);
}
/** Handles all control for "custom" radio button click. */
private void updatePrecons() {
final JList lst = getLstDecks();
lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final List<String> customNames = new ArrayList<String>();
final IStorageView<PreconDeck> allDecks = QuestController.getPrecons();
for (final PreconDeck d : allDecks) { customNames.add(d.getName()); }
lst.setListData(customNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
lst.setName(DeckgenUtil.DeckTypes.PRECON.toString());
lst.removeMouseListener(madDecklist);
lst.addMouseListener(madDecklist);
getBtnRandom().setText("Random deck");
getBtnRandom().setCommand(new Command() {
@Override public void run() { DeckgenUtil.randomSelect(lst); } });
// Init first in list
lst.setSelectedIndex(0);
}
/** Handles all control for "quest event" radio button click. */
private void updateQuestEvents() {
final JList lst = getLstDecks();
@@ -258,6 +286,8 @@ public class FDeckChooser extends JPanel {
deck = DeckgenUtil.buildThemeDeck(selection);
} else if (lst0.getName().equals(DeckgenUtil.DeckTypes.CUSTOM.toString())) {
deck = DeckgenUtil.getConstructedDeck(selection);
} else if (lst0.getName().equals(DeckgenUtil.DeckTypes.PRECON.toString())) {
deck = DeckgenUtil.getPreconDeck(selection);
}
return RegisteredPlayer.fromDeck(deck);

View File

@@ -19,7 +19,7 @@ import forge.game.event.GameEvent;
import forge.game.event.GameEventFlipCoin;
import forge.game.event.GameEventLandPlayed;
import forge.game.event.GameEventLifeLoss;
import forge.game.event.GameEventPoisonCounter;
import forge.game.event.GameEventPlayerPoisoned;
import forge.game.event.GameEventCardTapped;
import forge.game.event.GameEventShuffle;
import forge.game.event.GameEventSpellResolved;
@@ -46,7 +46,7 @@ public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> {
public SoundEffectType visit(GameEventEndOfTurn event) { return SoundEffectType.EndOfTurn; }
public SoundEffectType visit(GameEventFlipCoin event) { return SoundEffectType.FlipCoin; }
public SoundEffectType visit(GameEventLifeLoss event) { return SoundEffectType.LifeLoss; }
public SoundEffectType visit(GameEventPoisonCounter event) { return SoundEffectType.Poison; }
public SoundEffectType visit(GameEventPlayerPoisoned event) { return SoundEffectType.Poison; }
public SoundEffectType visit(GameEventShuffle event) { return SoundEffectType.Shuffle; }
public SoundEffectType visit(GameEventTokenCreated event) { return SoundEffectType.Token; }