mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Merge branch 'master' into Attractions
# Conflicts: # forge-game/src/main/java/forge/game/player/Player.java
This commit is contained in:
@@ -1,42 +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;
|
||||
|
||||
/**
|
||||
* The Enum GlobalRuleChange.
|
||||
*/
|
||||
public enum GlobalRuleChange {
|
||||
|
||||
attackerChoosesBlockers ("The attacking player chooses how each creature blocks each combat.");
|
||||
|
||||
private final String ruleText;
|
||||
|
||||
GlobalRuleChange(String text) {
|
||||
ruleText = text;
|
||||
}
|
||||
|
||||
public static GlobalRuleChange fromString(String text) {
|
||||
for (final GlobalRuleChange v : GlobalRuleChange.values()) {
|
||||
if (v.ruleText.compareToIgnoreCase(text) == 0) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Element " + text + " not found in GlobalRuleChange enum");
|
||||
}
|
||||
}
|
||||
@@ -198,6 +198,9 @@ public class StaticEffect {
|
||||
p.removeAdditionalVote(getTimestamp());
|
||||
p.removeAdditionalOptionalVote(getTimestamp());
|
||||
p.removeAdditionalVillainousChoices(getTimestamp());
|
||||
|
||||
p.removeDeclaresAttackers(getTimestamp());
|
||||
p.removeDeclaresBlockers(getTimestamp());
|
||||
}
|
||||
|
||||
// modify the affected card
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -39,12 +38,8 @@ public class StaticEffects {
|
||||
|
||||
// **************** StaticAbility system **************************
|
||||
private final Map<StaticAbility, StaticEffect> staticEffects = Maps.newHashMap();
|
||||
//Global rule changes
|
||||
private final Set<GlobalRuleChange> ruleChanges = EnumSet.noneOf(GlobalRuleChange.class);
|
||||
|
||||
public final void clearStaticEffects(final Set<Card> affectedCards) {
|
||||
ruleChanges.clear();
|
||||
|
||||
// remove all static effects
|
||||
for (final StaticEffect se : staticEffects.values()) {
|
||||
Iterables.addAll(affectedCards, se.remove());
|
||||
@@ -52,14 +47,6 @@ public class StaticEffects {
|
||||
this.staticEffects.clear();
|
||||
}
|
||||
|
||||
public void setGlobalRuleChange(final GlobalRuleChange change) {
|
||||
this.ruleChanges.add(change);
|
||||
}
|
||||
|
||||
public boolean getGlobalRuleChange(final GlobalRuleChange change) {
|
||||
return this.ruleChanges.contains(change);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a static effect to the list of static effects.
|
||||
*
|
||||
|
||||
@@ -67,7 +67,6 @@ public enum ApiType {
|
||||
DealDamage (DamageDealEffect.class),
|
||||
DayTime (DayTimeEffect.class),
|
||||
Debuff (DebuffEffect.class),
|
||||
DeclareCombatants (DeclareCombatantsEffect.class),
|
||||
DelayedTrigger (DelayedTriggerEffect.class),
|
||||
Destroy (DestroyEffect.class),
|
||||
DestroyAll (DestroyAllEffect.class),
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public class DeclareCombatantsEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
boolean attackers = sa.hasParam("DeclareAttackers");
|
||||
boolean blockers = sa.hasParam("DeclareBlockers");
|
||||
String what = Lang.joinHomogenous(
|
||||
attackers
|
||||
? "which creatures attack"
|
||||
: null,
|
||||
blockers
|
||||
? "which creatures block this turn and how those creatures block"
|
||||
: null
|
||||
);
|
||||
String duration = "EndOfTurn".equals(sa.getParam("Until")) ? "turn" : "combat";
|
||||
return TextUtil.concatWithSpace(Lang.joinHomogenous(tgtPlayers),Lang.joinVerb(tgtPlayers, "choose"),what,"this",TextUtil.addSuffix(duration,"."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
|
||||
final boolean attackers = sa.hasParam("DeclareAttackers");
|
||||
final boolean blockers = sa.hasParam("DeclareBlockers");
|
||||
|
||||
String until = sa.getParam("Until");
|
||||
boolean untilEoT = "EndOfTurn".equals(until);
|
||||
|
||||
for (Player p : tgtPlayers) { // Obviously the last player will be applied
|
||||
final PhaseHandler ph = p.getGame().getPhaseHandler();
|
||||
if (attackers) ph.setPlayerDeclaresAttackers(p);
|
||||
if (blockers) ph.setPlayerDeclaresBlockers(p);
|
||||
|
||||
GameCommand removeOverrides = new GameCommand() {
|
||||
private static final long serialVersionUID = -8064627517852651016L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (attackers) ph.setPlayerDeclaresAttackers(null);
|
||||
if (blockers) ph.setPlayerDeclaresBlockers(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (untilEoT)
|
||||
p.getGame().getEndOfTurn().addUntil(removeOverrides);
|
||||
else
|
||||
p.getGame().getEndOfCombat().addUntil(removeOverrides);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,8 +44,6 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
trigHandler.suppressMode(TriggerType.Shuffled);
|
||||
|
||||
game.getPhaseHandler().restart();
|
||||
game.getPhaseHandler().setPlayerDeclaresAttackers(null);
|
||||
game.getPhaseHandler().setPlayerDeclaresBlockers(null);
|
||||
game.getUntap().clearCommands();
|
||||
game.getUpkeep().clearCommands();
|
||||
game.getEndOfCombat().clearCommands();
|
||||
|
||||
@@ -42,6 +42,8 @@ import forge.util.CollectionSuppliers;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.maps.HashMapOfLists;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
|
||||
import java.util.*;
|
||||
@@ -81,9 +83,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
private transient Combat combat = null;
|
||||
private boolean bRepeatCleanup = false;
|
||||
|
||||
private transient Player playerDeclaresBlockers = null;
|
||||
private transient Player playerDeclaresAttackers = null;
|
||||
|
||||
/** The need to next phase. */
|
||||
private boolean givePriorityToPlayer = false;
|
||||
|
||||
@@ -524,9 +523,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
}
|
||||
|
||||
private void declareAttackersTurnBasedAction() {
|
||||
final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost()
|
||||
? playerTurn
|
||||
: playerDeclaresAttackers;
|
||||
final Player whoDeclares = ObjectUtils.firstNonNull(playerTurn.getDeclaresAttackers(), playerTurn);
|
||||
|
||||
if (CombatUtil.canAttack(playerTurn)) {
|
||||
boolean success = false;
|
||||
@@ -654,10 +651,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
do {
|
||||
p = game.getNextPlayerAfter(p);
|
||||
// Apply Odric's effect here
|
||||
Player whoDeclaresBlockers = playerDeclaresBlockers == null || playerDeclaresBlockers.hasLost() ? p : playerDeclaresBlockers;
|
||||
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.attackerChoosesBlockers)) {
|
||||
whoDeclaresBlockers = combat.getAttackingPlayer();
|
||||
}
|
||||
Player whoDeclaresBlockers = ObjectUtils.firstNonNull(p.getDeclaresBlockers(), p);
|
||||
if (combat.isPlayerAttacked(p)) {
|
||||
if (CombatUtil.canBlock(p, combat)) {
|
||||
// Replacement effects (for Camouflage)
|
||||
@@ -1236,14 +1230,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
givePriorityToPlayer = true;
|
||||
}
|
||||
|
||||
public final void setPlayerDeclaresAttackers(Player player) {
|
||||
playerDeclaresAttackers = player;
|
||||
}
|
||||
|
||||
public final void setPlayerDeclaresBlockers(Player player) {
|
||||
playerDeclaresBlockers = player;
|
||||
}
|
||||
|
||||
public void endCombat() {
|
||||
game.getEndOfCombat().executeUntil();
|
||||
game.getEndOfCombat().executeUntilEndOfPhase(playerTurn);
|
||||
|
||||
@@ -196,6 +196,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private SortedSet<Long> controlVotes = Sets.newTreeSet();
|
||||
private Map<Long, Integer> additionalVillainousChoices = Maps.newHashMap();
|
||||
|
||||
private NavigableMap<Long, Player> declaresAttackers = Maps.newTreeMap();
|
||||
private NavigableMap<Long, Player> declaresBlockers = Maps.newTreeMap();
|
||||
|
||||
private final AchievementTracker achievementTracker = new AchievementTracker();
|
||||
private final PlayerView view;
|
||||
|
||||
@@ -906,7 +909,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
setCounters(counterName, newValue, null, true);
|
||||
|
||||
getGame().addCounterRemovedThisTurn(counterName, this, delta);
|
||||
|
||||
|
||||
/* TODO Run triggers when something cares
|
||||
int curCounters = oldValue;
|
||||
for (int i = 0; i < delta && curCounters != 0; i++) {
|
||||
@@ -2303,7 +2306,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void addSpellCastSinceBegOfYourLastTurn(List<Card> spells) {
|
||||
spellsCastSinceBeginningOfLastTurn.addAll(spells);
|
||||
}
|
||||
|
||||
|
||||
public final int getSpellsCastThisTurn() {
|
||||
return spellsCastThisTurn;
|
||||
}
|
||||
@@ -3894,4 +3897,30 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
this.visitAttractions(total);
|
||||
}
|
||||
|
||||
public void addDeclaresAttackers(long ts, Player p) {
|
||||
this.declaresAttackers.put(ts, p);
|
||||
}
|
||||
|
||||
public void removeDeclaresAttackers(long ts) {
|
||||
this.declaresAttackers.remove(ts);
|
||||
}
|
||||
|
||||
public Player getDeclaresAttackers() {
|
||||
Map.Entry<Long, Player> e = declaresAttackers.lastEntry();
|
||||
return e == null ? null : e.getValue();
|
||||
}
|
||||
|
||||
public void addDeclaresBlockers(long ts, Player p) {
|
||||
this.declaresBlockers.put(ts, p);
|
||||
}
|
||||
|
||||
public void removeDeclaresBlockers(long ts) {
|
||||
this.declaresBlockers.remove(ts);
|
||||
}
|
||||
|
||||
public Player getDeclaresBlockers() {
|
||||
Map.Entry<Long, Player> e = declaresBlockers.lastEntry();
|
||||
return e == null ? null : e.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,10 @@ public class PlayerProperty {
|
||||
if (!source.getDamageHistory().hasAttackedThisTurn(player)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("Attacking")) {
|
||||
if (game.getCombat() == null || !player.equals(game.getCombat().getAttackingPlayer())) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("Defending")) {
|
||||
if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(player)) {
|
||||
return false;
|
||||
|
||||
@@ -165,7 +165,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
||||
|
||||
if (hasParam("AddHiddenKeyword") || hasParam("MayPlay")
|
||||
|| hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")
|
||||
|| hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")) {
|
||||
|| hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")
|
||||
|| hasParam("DeclaresAttackers") || hasParam("DeclaresBlockers")) {
|
||||
layers.add(StaticAbilityLayer.RULES);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.google.common.collect.Maps;
|
||||
import forge.GameCommand;
|
||||
import forge.card.*;
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.StaticEffect;
|
||||
import forge.game.StaticEffects;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -142,11 +141,6 @@ public final class StaticAbilityContinuous {
|
||||
boolean mayPlayGrantZonePermissions = true;
|
||||
Integer mayPlayLimit = null;
|
||||
|
||||
//Global rules changes
|
||||
if (layer == StaticAbilityLayer.RULES && params.containsKey("GlobalRule")) {
|
||||
effects.setGlobalRuleChange(GlobalRuleChange.fromString(params.get("GlobalRule")));
|
||||
}
|
||||
|
||||
if (layer == StaticAbilityLayer.SETPT || layer == StaticAbilityLayer.CHARACTERISTIC) {
|
||||
if (params.containsKey("SetPower")) {
|
||||
setP = params.get("SetPower");
|
||||
@@ -599,6 +593,17 @@ public final class StaticAbilityContinuous {
|
||||
int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb);
|
||||
p.addAdditionalVillainousChoices(se.getTimestamp(), add);
|
||||
}
|
||||
|
||||
if (params.containsKey("DeclaresAttackers")) {
|
||||
PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresAttackers"), stAb);
|
||||
if (!players.isEmpty())
|
||||
p.addDeclaresAttackers(se.getTimestamp(), players.getFirst());
|
||||
}
|
||||
if (params.containsKey("DeclaresBlockers")) {
|
||||
PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresBlockers"), stAb);
|
||||
if (!players.isEmpty())
|
||||
p.addDeclaresBlockers(se.getTimestamp(), players.getFirst());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user