- Added Celestial Convergence.

- Added new effect AF GameDrawn that creates an intentional draw situation by game effect.
- Divine Intervention now uses this effect.

git-svn-id: http://svn.slightlymagic.net/forge/trunk@35816 269b9781-a132-4a9b-9d4e-f004f1b56b58
This commit is contained in:
Agetian 2017-09-28 17:31:04 +00:00
parent cf5c145f5e
commit 8e5975e3e9
9 changed files with 92 additions and 5 deletions

View File

@ -143,6 +143,9 @@ public class Match {
public Multiset<RegisteredPlayer> getGamesWon() { public Multiset<RegisteredPlayer> getGamesWon() {
final Multiset<RegisteredPlayer> won = HashMultiset.create(players.size()); final Multiset<RegisteredPlayer> won = HashMultiset.create(players.size());
for (final GameOutcome go : gamesPlayedRo) { for (final GameOutcome go : gamesPlayedRo) {
if (go.getWinningPlayer() == null) {
return won;
}
won.add(go.getWinningPlayer().getRegisteredPlayer()); won.add(go.getWinningPlayer().getRegisteredPlayer());
} }
return won; return won;

View File

@ -1,13 +1,12 @@
package forge.game.ability; package forge.game.ability;
import com.google.common.collect.Maps;
import forge.game.ability.effects.*; import forge.game.ability.effects.*;
import forge.util.ReflectionUtil; import forge.util.ReflectionUtil;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Maps;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
@ -76,6 +75,7 @@ public enum ApiType {
GainControl (ControlGainEffect.class), GainControl (ControlGainEffect.class),
GainLife (LifeGainEffect.class), GainLife (LifeGainEffect.class),
GainOwnership (OwnershipGainEffect.class), GainOwnership (OwnershipGainEffect.class),
GameDrawn (GameDrawEffect.class),
GenericChoice (ChooseGenericEffect.class), GenericChoice (ChooseGenericEffect.class),
Goad (GoadEffect.class), Goad (GoadEffect.class),
Haunt (HauntEffect.class), Haunt (HauntEffect.class),

View File

@ -0,0 +1,27 @@
package forge.game.ability.effects;
import forge.game.GameEndReason;
import forge.game.ability.SpellAbilityEffect;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public class GameDrawEffect extends SpellAbilityEffect {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected String getStackDescription(SpellAbility sa) {
return "The game is a draw.";
}
@Override
public void resolve(SpellAbility sa) {
for (Player p : sa.getHostCard().getGame().getPlayers()) {
p.intentionalDraw();
}
sa.getHostCard().getGame().setGameOver(GameEndReason.Draw);
}
}

View File

@ -467,6 +467,39 @@ public class CardFactoryUtil {
return doXMath(n, m, source); return doXMath(n, m, source);
} }
if (l[0].startsWith("TiedForHighestLife")) {
int maxLife = Integer.MIN_VALUE;
for (final Player player : players) {
int highestTotal = playerXProperty(player, "LifeTotal", source);
if (highestTotal > maxLife) {
maxLife = highestTotal;
}
}
int numTied = 0;
for (final Player player : players) {
if (player.getLife() == maxLife) {
numTied++;
}
}
return doXMath(numTied, m, source);
}
if (l[0].startsWith("TiedForLowestLife")) {
int minLife = Integer.MAX_VALUE;
for (final Player player : players) {
int lowestTotal = playerXProperty(player, "LifeTotal", source);
if (lowestTotal < minLife) {
minLife = lowestTotal;
}
}
int numTied = 0;
for (final Player player : players) {
if (player.getLife() == minLife) {
numTied++;
}
}
return doXMath(numTied, m, source);
}
final String[] sq; final String[] sq;
sq = l[0].split("\\."); sq = l[0].split("\\.");

View File

@ -36,7 +36,9 @@ public enum GameLossReason {
CommanderDamage, CommanderDamage,
OpponentWon OpponentWon,
IntentionalDraw // not a real "game loss" as such
/* /*
* DoorToNothingness, // Door To Nothingness's ability activated * DoorToNothingness, // Door To Nothingness's ability activated

View File

@ -1807,6 +1807,10 @@ public class Player extends GameEntity implements Comparable<Player> {
setOutcome(PlayerOutcome.concede()); setOutcome(PlayerOutcome.concede());
} }
public final void intentionalDraw() {
setOutcome(PlayerOutcome.draw());
}
public final boolean cantLose() { public final boolean cantLose() {
if (getOutcome() != null && getOutcome().lossState == GameLossReason.Conceded) { if (getOutcome() != null && getOutcome().lossState == GameLossReason.Conceded) {
return false; return false;

View File

@ -17,13 +17,16 @@ public class PlayerOutcome {
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @param sourceName
* @return * @return
*/ */
public static PlayerOutcome win() { public static PlayerOutcome win() {
return new PlayerOutcome(null, null, null); return new PlayerOutcome(null, null, null);
} }
public static PlayerOutcome draw() {
return new PlayerOutcome(null, GameLossReason.IntentionalDraw, null);
}
public static PlayerOutcome altWin(String sourceName) { public static PlayerOutcome altWin(String sourceName) {
return new PlayerOutcome(sourceName, null, null); return new PlayerOutcome(sourceName, null, null);
} }
@ -69,6 +72,7 @@ public class PlayerOutcome {
case OpponentWon: return "lost because an opponent has won by spell '" + loseConditionSpell + "'"; case OpponentWon: return "lost because an opponent has won by spell '" + loseConditionSpell + "'";
case SpellEffect: return "lost due to effect of spell '" + loseConditionSpell + "'"; case SpellEffect: return "lost due to effect of spell '" + loseConditionSpell + "'";
case CommanderDamage: return "lost due to accumulation of 21 damage from generals"; case CommanderDamage: return "lost due to accumulation of 21 damage from generals";
case IntentionalDraw: return "accepted that the game is a draw";
} }
return "lost for unknown reason (this is a bug)"; return "lost for unknown reason (this is a bug)";
} }

View File

@ -0,0 +1,14 @@
Name:Celestial Convergence
ManaCost:2 W W
Types:Enchantment
K:etbCounter:OMEN:7
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | ActiveZones$ Battlefield | Execute$ TrigRemoveCtr | TriggerDescription$ At the beginning of your upkeep, remove an omen counter from CARDNAME. If there are no omen counters on CARDNAME, the player with the highest life total wins the game. If two or more players are tied for highest life total, the game is a draw.
SVar:TrigRemoveCtr:DB$ RemoveCounter | Defined$ Self | CounterType$ OMEN | CounterNum$ 1 | SubAbility$ WinnerDecided
SVar:WinnerDecided:DB$ WinsGame | Defined$ Player.LifeEquals_X | References$ X,NumHighestLife | ConditionPresent$ Card.Self+counters_EQ0_OMEN | ConditionCheckSVar$ NumHighestLife | ConditionSVarCompare$ LT2 | SubAbility$ GameIsADraw
SVar:GameIsADraw:DB$ GameDrawn | ConditionPresent$ Card.Self+counters_EQ0_OMEN | References$ NumHighestLife | ConditionCheckSVar$ NumHighestLife | ConditionSVarCompare$ GE2
SVar:Picture:http://www.wizards.com/global/images/magic/general/celestial_convergence.jpg
SVar:X:PlayerCountPlayers$HighestLifeTotal
SVar:NumHighestLife:PlayerCountPlayers$TiedForHighestLife
SVar:RemRandomDeck:True
SVar:RemAIDeck:True
Oracle:Celestial Convergence enters the battlefield with seven omen counters on it.\nAt the beginning of your upkeep, remove an omen counter from Celestial Convergence. If there are no omen counters on Celestial Convergence, the player with the highest life total wins the game. If two or more players are tied for highest life total, the game is a draw.

View File

@ -4,7 +4,7 @@ Types:Enchantment
K:etbCounter:INTERVENTION:2 K:etbCounter:INTERVENTION:2
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | ActiveZones$ Battlefield | Execute$ TrigRemoveCtr | TriggerDescription$ At the beginning of your upkeep, remove an intervention counter from CARDNAME. When you remove the last intervention counter from CARDNAME, the game is a draw. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | ActiveZones$ Battlefield | Execute$ TrigRemoveCtr | TriggerDescription$ At the beginning of your upkeep, remove an intervention counter from CARDNAME. When you remove the last intervention counter from CARDNAME, the game is a draw.
SVar:TrigRemoveCtr:DB$ RemoveCounter | Defined$ Self | CounterType$ INTERVENTION | CounterNum$ 1 | SubAbility$ GameIsADraw SVar:TrigRemoveCtr:DB$ RemoveCounter | Defined$ Self | CounterType$ INTERVENTION | CounterNum$ 1 | SubAbility$ GameIsADraw
SVar:GameIsADraw:DB$ LosesGame | Defined$ Player | ConditionPresent$ Card.Self+counters_EQ0_INTERVENTION SVar:GameIsADraw:DB$ GameDrawn | ConditionPresent$ Card.Self+counters_EQ0_INTERVENTION
SVar:Picture:http://www.wizards.com/global/images/magic/general/divine_intervention.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/divine_intervention.jpg
SVar:RemRandomDeck:True SVar:RemRandomDeck:True
SVar:RemAIDeck:True SVar:RemAIDeck:True