mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Opposition Agent: use timestamp for controlledBy effects
This commit is contained in:
@@ -421,7 +421,7 @@ public class Game {
|
|||||||
public synchronized void setGameOver(GameEndReason reason) {
|
public synchronized void setGameOver(GameEndReason reason) {
|
||||||
age = GameStage.GameOver;
|
age = GameStage.GameOver;
|
||||||
for (Player p : allPlayers) {
|
for (Player p : allPlayers) {
|
||||||
p.setMindSlaveMaster(null); // for correct totals
|
p.clearController();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Player p : getPlayers()) {
|
for (Player p : getPlayers()) {
|
||||||
@@ -949,19 +949,6 @@ public class Game {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getControlOppSearchLib() {
|
|
||||||
Player result = null;
|
|
||||||
long maxValue = 0;
|
|
||||||
for (Player p : getPlayers()) {
|
|
||||||
Long v = p.getHighestControlOppSearchLib();
|
|
||||||
if (v != null && v > maxValue) {
|
|
||||||
maxValue = v;
|
|
||||||
result = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onCleanupPhase() {
|
public void onCleanupPhase() {
|
||||||
clearCounterAddedThisTurn();
|
clearCounterAddedThisTurn();
|
||||||
for (Player player : getPlayers()) {
|
for (Player player : getPlayers()) {
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ public class StaticEffect {
|
|||||||
p.removeMaxLandPlays(getTimestamp());
|
p.removeMaxLandPlays(getTimestamp());
|
||||||
p.removeMaxLandPlaysInfinite(getTimestamp());
|
p.removeMaxLandPlaysInfinite(getTimestamp());
|
||||||
|
|
||||||
|
p.removeControlledWhileSearching(getTimestamp());
|
||||||
p.removeControlVote(getTimestamp());
|
p.removeControlVote(getTimestamp());
|
||||||
p.removeAdditionalVote(getTimestamp());
|
p.removeAdditionalVote(getTimestamp());
|
||||||
p.removeAdditionalOptionalVote(getTimestamp());
|
p.removeAdditionalOptionalVote(getTimestamp());
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChangeZoneEffect extends SpellAbilityEffect {
|
public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
private boolean isHidden(SpellAbility sa) {
|
private boolean isHidden(SpellAbility sa) {
|
||||||
boolean hidden = sa.hasParam("Hidden");
|
boolean hidden = sa.hasParam("Hidden");
|
||||||
if (!hidden && sa.hasParam("Origin")) {
|
if (!hidden && sa.hasParam("Origin")) {
|
||||||
@@ -484,7 +484,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
final boolean optional = sa.hasParam("Optional");
|
final boolean optional = sa.hasParam("Optional");
|
||||||
final long ts = game.getNextTimestamp();
|
final long ts = game.getNextTimestamp();
|
||||||
boolean combatChanged = false;
|
boolean combatChanged = false;
|
||||||
|
|
||||||
for (final Card tgtC : tgtCards) {
|
for (final Card tgtC : tgtCards) {
|
||||||
final Card gameCard = game.getCardState(tgtC, null);
|
final Card gameCard = game.getCardState(tgtC, null);
|
||||||
// gameCard is LKI in that case, the card is not in game anymore
|
// gameCard is LKI in that case, the card is not in game anymore
|
||||||
@@ -644,7 +644,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
combatChanged = true;
|
combatChanged = true;
|
||||||
}
|
}
|
||||||
if (sa.hasParam("Ninjutsu")) {
|
if (sa.hasParam("Ninjutsu")) {
|
||||||
// Ninjutsu need to get the Defender of the Returned Creature
|
// Ninjutsu need to get the Defender of the Returned Creature
|
||||||
final Card returned = sa.getPaidList("Returned").getFirst();
|
final Card returned = sa.getPaidList("Returned").getFirst();
|
||||||
final GameEntity defender = game.getCombat().getDefenderByAttacker(returned);
|
final GameEntity defender = game.getCombat().getDefenderByAttacker(returned);
|
||||||
game.getCombat().addAttacker(movedCard, defender);
|
game.getCombat().addAttacker(movedCard, defender);
|
||||||
@@ -870,11 +870,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String changeType = sa.getParam("ChangeType");
|
String changeType = sa.getParam("ChangeType");
|
||||||
|
|
||||||
CardCollection fetchList;
|
CardCollection fetchList;
|
||||||
Player originalDecider = decider;
|
|
||||||
Player deciderControl = game.getControlOppSearchLib();
|
|
||||||
boolean shuffleMandatory = true;
|
boolean shuffleMandatory = true;
|
||||||
boolean searchedLibrary = false;
|
boolean searchedLibrary = false;
|
||||||
if (defined) {
|
if (defined) {
|
||||||
@@ -891,14 +889,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
fetchList = new CardCollection(player.getCardsIn(origin));
|
fetchList = new CardCollection(player.getCardsIn(origin));
|
||||||
if (origin.contains(ZoneType.Library) && !sa.hasParam("NoLooking")) {
|
if (origin.contains(ZoneType.Library) && !sa.hasParam("NoLooking")) {
|
||||||
searchedLibrary = true;
|
searchedLibrary = true;
|
||||||
if (deciderControl != null) { decider = deciderControl; }
|
|
||||||
|
|
||||||
if (decider.hasKeyword("LimitSearchLibrary")) { // Aven Mindcensor
|
if (decider.hasKeyword("LimitSearchLibrary")) { // Aven Mindcensor
|
||||||
fetchList.removeAll(player.getCardsIn(ZoneType.Library));
|
fetchList.removeAll(player.getCardsIn(ZoneType.Library));
|
||||||
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
|
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
|
||||||
if (fetchNum == 0) {
|
if (fetchNum == 0) {
|
||||||
searchedLibrary = false;
|
searchedLibrary = false;
|
||||||
if (deciderControl != null) { decider = originalDecider; }
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fetchList.addAll(player.getCardsIn(ZoneType.Library, fetchNum));
|
fetchList.addAll(player.getCardsIn(ZoneType.Library, fetchNum));
|
||||||
@@ -906,11 +902,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
if (!decider.canSearchLibraryWith(sa, player)) {
|
if (!decider.canSearchLibraryWith(sa, player)) {
|
||||||
fetchList.removeAll(player.getCardsIn(ZoneType.Library));
|
fetchList.removeAll(player.getCardsIn(ZoneType.Library));
|
||||||
// "if you do/sb does, shuffle" is not mandatory (usually a triggered ability), should has this param.
|
// "if you do/sb does, shuffle" is not mandatory (usually a triggered ability), should has this param.
|
||||||
// "then shuffle" is mandatory
|
// "then shuffle" is mandatory
|
||||||
shuffleMandatory = !sa.hasParam("ShuffleNonMandatory");
|
shuffleMandatory = !sa.hasParam("ShuffleNonMandatory");
|
||||||
searchedLibrary = false;
|
searchedLibrary = false;
|
||||||
if (deciderControl != null) { decider = originalDecider; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -919,7 +914,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
DelayedReveal delayedReveal = null;
|
DelayedReveal delayedReveal = null;
|
||||||
if (!defined && !sa.hasParam("AlreadyRevealed")) {
|
if (!defined && !sa.hasParam("AlreadyRevealed")) {
|
||||||
if (origin.contains(ZoneType.Library) && searchedLibrary) {
|
if (origin.contains(ZoneType.Library) && searchedLibrary) {
|
||||||
if (deciderControl != null) { decider = deciderControl; }
|
|
||||||
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
|
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
|
||||||
CardCollectionView shown = !decider.hasKeyword("LimitSearchLibrary") ? player.getCardsIn(ZoneType.Library) : player.getCardsIn(ZoneType.Library, fetchNum);
|
CardCollectionView shown = !decider.hasKeyword("LimitSearchLibrary") ? player.getCardsIn(ZoneType.Library) : player.getCardsIn(ZoneType.Library, fetchNum);
|
||||||
// Look at whole library before moving onto choosing a card
|
// Look at whole library before moving onto choosing a card
|
||||||
@@ -930,11 +924,17 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Long controlTimestamp = null;
|
||||||
if (searchedLibrary) {
|
if (searchedLibrary) {
|
||||||
if (deciderControl != null) { decider = deciderControl; }
|
|
||||||
if (decider.equals(player)) {
|
if (decider.equals(player)) {
|
||||||
// should only count the number of searching player's own library
|
Map.Entry<Long, Player> searchControlPlayer = player.getControlledWhileSearching();
|
||||||
|
if (searchControlPlayer != null) {
|
||||||
|
controlTimestamp = searchControlPlayer.getKey();
|
||||||
|
player.addController(controlTimestamp, searchControlPlayer.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
decider.incLibrarySearched();
|
decider.incLibrarySearched();
|
||||||
|
// should only count the number of searching player's own library
|
||||||
// Panglacial Wurm
|
// Panglacial Wurm
|
||||||
CardCollection canCastWhileSearching = CardLists.getKeyword(fetchList,
|
CardCollection canCastWhileSearching = CardLists.getKeyword(fetchList,
|
||||||
"While you're searching your library, you may cast CARDNAME from your library.");
|
"While you're searching your library, you may cast CARDNAME from your library.");
|
||||||
@@ -1113,7 +1113,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
Player newController = sa.getActivatingPlayer();
|
Player newController = sa.getActivatingPlayer();
|
||||||
if (sa.hasParam("NewController")) {
|
if (sa.hasParam("NewController")) {
|
||||||
newController = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("NewController"), sa).get(0);
|
newController = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("NewController"), sa).get(0);
|
||||||
}
|
}
|
||||||
c.setController(newController, game.getNextTimestamp());
|
c.setController(newController, game.getNextTimestamp());
|
||||||
}
|
}
|
||||||
if (sa.hasParam("WithCounters")) {
|
if (sa.hasParam("WithCounters")) {
|
||||||
@@ -1235,7 +1235,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
else {
|
else {
|
||||||
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, cause, moveParams);
|
movedCard = game.getAction().moveTo(c.getController().getZone(destination), c, cause, moveParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
movedCards.add(movedCard);
|
movedCards.add(movedCard);
|
||||||
|
|
||||||
if (originZone != null) {
|
if (originZone != null) {
|
||||||
@@ -1247,7 +1247,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
runParams.put(AbilityKey.Championed, c);
|
runParams.put(AbilityKey.Championed, c);
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.Championed, runParams, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remember) {
|
if (remember) {
|
||||||
source.addRemembered(movedCard);
|
source.addRemembered(movedCard);
|
||||||
// addRememberedFromCardState ?
|
// addRememberedFromCardState ?
|
||||||
@@ -1271,7 +1271,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
|| (sa.hasParam("Reveal") && !movedCards.isEmpty())) && !sa.hasParam("NoReveal")) {
|
|| (sa.hasParam("Reveal") && !movedCards.isEmpty())) && !sa.hasParam("NoReveal")) {
|
||||||
game.getAction().reveal(movedCards, player);
|
game.getAction().reveal(movedCards, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((origin.contains(ZoneType.Library) && !destination.equals(ZoneType.Library) && !defined && shuffleMandatory)
|
if ((origin.contains(ZoneType.Library) && !destination.equals(ZoneType.Library) && !defined && shuffleMandatory)
|
||||||
|| (sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle")))) {
|
|| (sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle")))) {
|
||||||
player.shuffle(sa);
|
player.shuffle(sa);
|
||||||
@@ -1282,6 +1282,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
game.fireEvent(new GameEventCombatChanged());
|
game.fireEvent(new GameEventCombatChanged());
|
||||||
}
|
}
|
||||||
triggerList.triggerChangesZoneAll(game);
|
triggerList.triggerChangesZoneAll(game);
|
||||||
|
|
||||||
|
// remove Controlled While Searching
|
||||||
|
if (controlTimestamp != null) {
|
||||||
|
player.removeController(controlTimestamp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean allowMultiSelect(Player decider, SpellAbility sa) {
|
private static boolean allowMultiSelect(Player decider, SpellAbility sa) {
|
||||||
@@ -1307,13 +1312,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
* @param si
|
* @param si
|
||||||
* a {@link forge.game.spellability.SpellAbilityStackInstance}
|
* a {@link forge.game.spellability.SpellAbilityStackInstance}
|
||||||
* object.
|
* object.
|
||||||
* @param game
|
* @param game
|
||||||
*/
|
*/
|
||||||
private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si, final Game game, CardZoneTable triggerList) {
|
private static void removeFromStack(final SpellAbility tgtSA, final SpellAbility srcSA, final SpellAbilityStackInstance si, final Game game, CardZoneTable triggerList) {
|
||||||
final Card tgtHost = tgtSA.getHostCard();
|
final Card tgtHost = tgtSA.getHostCard();
|
||||||
final Zone originZone = tgtHost.getZone();
|
final Zone originZone = tgtHost.getZone();
|
||||||
game.getStack().remove(si);
|
game.getStack().remove(si);
|
||||||
|
|
||||||
Map<AbilityKey,Object> params = AbilityKey.newMap();
|
Map<AbilityKey,Object> params = AbilityKey.newMap();
|
||||||
params.put(AbilityKey.StackSa, tgtSA);
|
params.put(AbilityKey.StackSa, tgtSA);
|
||||||
params.put(AbilityKey.StackSi, si);
|
params.put(AbilityKey.StackSi, si);
|
||||||
|
|||||||
@@ -36,13 +36,14 @@ public class ControlPlayerEffect extends SpellAbilityEffect {
|
|||||||
game.getUntap().addUntil(pTarget, new GameCommand() {
|
game.getUntap().addUntil(pTarget, new GameCommand() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
pTarget.setMindSlaveMaster(activator);
|
long ts = game.getNextTimestamp();
|
||||||
|
pTarget.addController(ts, activator);
|
||||||
|
|
||||||
// on following cleanup release control
|
// on following cleanup release control
|
||||||
game.getEndOfTurn().addUntil(new GameCommand() {
|
game.getEndOfTurn().addUntil(new GameCommand() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
pTarget.setMindSlaveMaster(null);
|
pTarget.removeController(ts);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import forge.util.*;
|
|||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -144,8 +145,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
private PlayerStatistics stats = new PlayerStatistics();
|
private PlayerStatistics stats = new PlayerStatistics();
|
||||||
private PlayerController controller;
|
private PlayerController controller;
|
||||||
private PlayerController controllerCreator = null;
|
|
||||||
private Player mindSlaveMaster = null;
|
private NavigableMap<Long, Pair<Player, PlayerController>> controlledBy = Maps.newTreeMap();
|
||||||
|
|
||||||
|
private NavigableMap<Long, Player> controlledWhileSearching = Maps.newTreeMap();
|
||||||
|
|
||||||
private int teamNumber = -1;
|
private int teamNumber = -1;
|
||||||
private Card activeScheme = null;
|
private Card activeScheme = null;
|
||||||
@@ -165,8 +168,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
private Map<Long, Integer> additionalOptionalVotes = Maps.newHashMap();
|
private Map<Long, Integer> additionalOptionalVotes = Maps.newHashMap();
|
||||||
private SortedSet<Long> controlVotes = Sets.newTreeSet();
|
private SortedSet<Long> controlVotes = Sets.newTreeSet();
|
||||||
|
|
||||||
private SortedSet<Long> controlOppSearchLib = Sets.newTreeSet();
|
|
||||||
|
|
||||||
private final AchievementTracker achievementTracker = new AchievementTracker();
|
private final AchievementTracker achievementTracker = new AchievementTracker();
|
||||||
private final PlayerView view;
|
private final PlayerView view;
|
||||||
|
|
||||||
@@ -1683,7 +1684,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
// Replacement effects
|
// Replacement effects
|
||||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
||||||
repRunParams.put(AbilityKey.Number, n);
|
repRunParams.put(AbilityKey.Number, n);
|
||||||
|
|
||||||
if (destination == ZoneType.Graveyard && !bottom) {
|
if (destination == ZoneType.Graveyard && !bottom) {
|
||||||
switch (getGame().getReplacementHandler().run(ReplacementType.Mill, repRunParams)) {
|
switch (getGame().getReplacementHandler().run(ReplacementType.Mill, repRunParams)) {
|
||||||
case NotReplaced:
|
case NotReplaced:
|
||||||
@@ -2413,40 +2414,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final LobbyPlayer getOriginalLobbyPlayer() {
|
public final LobbyPlayer getOriginalLobbyPlayer() {
|
||||||
return controllerCreator.getLobbyPlayer();
|
return controller.getLobbyPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final RegisteredPlayer getRegisteredPlayer() {
|
public final RegisteredPlayer getRegisteredPlayer() {
|
||||||
return game.getMatch().getPlayers().get(game.getRegisteredPlayers().indexOf(this));
|
return game.getMatch().getPlayers().get(game.getRegisteredPlayers().indexOf(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isMindSlaved() {
|
|
||||||
return mindSlaveMaster != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Player getMindSlaveMaster() {
|
|
||||||
return mindSlaveMaster;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setMindSlaveMaster(final Player mindSlaveMaster0) {
|
|
||||||
if (mindSlaveMaster == mindSlaveMaster0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mindSlaveMaster = mindSlaveMaster0;
|
|
||||||
view.updateMindSlaveMaster(this);
|
|
||||||
|
|
||||||
if (mindSlaveMaster != null) {
|
|
||||||
final LobbyPlayer oldLobbyPlayer = getLobbyPlayer();
|
|
||||||
final PlayerController oldController = getController();
|
|
||||||
final IGameEntitiesFactory master = (IGameEntitiesFactory)mindSlaveMaster.getLobbyPlayer();
|
|
||||||
controller = master.createMindSlaveController(mindSlaveMaster, this);
|
|
||||||
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), controller));
|
|
||||||
} else {
|
|
||||||
controller = controllerCreator;
|
|
||||||
game.fireEvent(new GameEventPlayerControl(this, getLobbyPlayer(), controller, null, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setOutcome(PlayerOutcome outcome) {
|
private void setOutcome(PlayerOutcome outcome) {
|
||||||
stats.setOutcome(outcome);
|
stats.setOutcome(outcome);
|
||||||
}
|
}
|
||||||
@@ -2548,14 +2522,73 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final PlayerController getController() {
|
public final PlayerController getController() {
|
||||||
|
if (!controlledBy.isEmpty()) {
|
||||||
|
return controlledBy.lastEntry().getValue().getValue();
|
||||||
|
}
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Player getControllingPlayer() {
|
||||||
|
if (!controlledBy.isEmpty()) {
|
||||||
|
return controlledBy.lastEntry().getValue().getKey();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addController(long timestamp, Player pl) {
|
||||||
|
final IGameEntitiesFactory master = (IGameEntitiesFactory)pl.getLobbyPlayer();
|
||||||
|
addController(timestamp, master.createMindSlaveController(pl, this), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addController(long timestamp, PlayerController pc, boolean event) {
|
||||||
|
final LobbyPlayer oldLobbyPlayer = getLobbyPlayer();
|
||||||
|
final PlayerController oldController = getController();
|
||||||
|
|
||||||
|
controlledBy.put(timestamp, Pair.of(pc.getPlayer(), pc));
|
||||||
|
getView().updateMindSlaveMaster(this);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), getController()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeController(long timestamp) {
|
||||||
|
removeController(timestamp, true);
|
||||||
|
}
|
||||||
|
public void removeController(long timestamp, boolean event) {
|
||||||
|
final LobbyPlayer oldLobbyPlayer = getLobbyPlayer();
|
||||||
|
final PlayerController oldController = getController();
|
||||||
|
|
||||||
|
controlledBy.remove(timestamp);
|
||||||
|
if (event) {
|
||||||
|
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), getController()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearController() {
|
||||||
|
controlledBy.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map.Entry<Long, Player> getControlledWhileSearching() {
|
||||||
|
if (controlledWhileSearching.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return controlledWhileSearching.lastEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addControlledWhileSearching(long timestamp, Player pl) {
|
||||||
|
controlledWhileSearching.put(timestamp, pl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeControlledWhileSearching(long timestamp) {
|
||||||
|
controlledWhileSearching.remove(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
public final void setFirstController(PlayerController ctrlr) {
|
public final void setFirstController(PlayerController ctrlr) {
|
||||||
if (controllerCreator != null) {
|
if (controller != null) {
|
||||||
throw new IllegalStateException("Controller creator already assigned");
|
throw new IllegalStateException("Controller creator already assigned");
|
||||||
}
|
}
|
||||||
controllerCreator = ctrlr;
|
|
||||||
controller = ctrlr;
|
controller = ctrlr;
|
||||||
updateAvatar();
|
updateAvatar();
|
||||||
updateSleeve();
|
updateSleeve();
|
||||||
@@ -2576,12 +2609,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
* Run a procedure using a different controller
|
* Run a procedure using a different controller
|
||||||
*/
|
*/
|
||||||
public void runWithController(Runnable proc, PlayerController tempController) {
|
public void runWithController(Runnable proc, PlayerController tempController) {
|
||||||
PlayerController oldController = controller;
|
long ts = game.getNextTimestamp();
|
||||||
controller = tempController;
|
this.addController(ts, tempController, false);
|
||||||
try {
|
try {
|
||||||
proc.run();
|
proc.run();
|
||||||
} finally {
|
} finally {
|
||||||
controller = oldController;
|
this.removeController(ts, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3020,7 +3053,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
CardCollectionView view = CardCollection.getView(legalCompanions);
|
CardCollectionView view = CardCollection.getView(legalCompanions);
|
||||||
|
|
||||||
SpellAbility fakeSa = new SpellAbility.EmptySa(ApiType.CompanionChoose, legalCompanions.get(0), this);
|
SpellAbility fakeSa = new SpellAbility.EmptySa(ApiType.CompanionChoose, legalCompanions.get(0), this);
|
||||||
return controller.chooseSingleEntityForEffect(view, fakeSa, Localizer.getInstance().getMessage("lblChooseACompanion"), true, null);
|
return player.chooseSingleEntityForEffect(view, fakeSa, Localizer.getInstance().getMessage("lblChooseACompanion"), true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean deckMatchesDeckRestriction(Card source, String restriction) {
|
public boolean deckMatchesDeckRestriction(Card source, String restriction) {
|
||||||
@@ -3414,33 +3447,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return controlVotes.last();
|
return controlVotes.last();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addControlOppSearchLib(long timestamp) {
|
|
||||||
if (controlOppSearchLib.add(timestamp)) {
|
|
||||||
updateControlOppSearchLib();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateControlOppSearchLib() { // needs to update all players
|
|
||||||
Player control = getGame().getControlOppSearchLib();
|
|
||||||
for (Player pl : getGame().getPlayers()) {
|
|
||||||
pl.getView().updateControlOppSearchLib(pl.equals(control));
|
|
||||||
getGame().fireEvent(new GameEventPlayerStatsChanged(pl, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Long> getControlOppSearchLib() {
|
|
||||||
return controlOppSearchLib;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getHighestControlOppSearchLib() {
|
|
||||||
if (controlOppSearchLib.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return controlOppSearchLib.last();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addCycled(SpellAbility sp) {
|
public void addCycled(SpellAbility sp) {
|
||||||
cycledThisTurn++;
|
cycledThisTurn++;
|
||||||
|
|
||||||
|
|||||||
@@ -296,9 +296,6 @@ public class PlayerView extends GameEntityView {
|
|||||||
set(TrackableProperty.ControlVotes, val);
|
set(TrackableProperty.ControlVotes, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getControlOppSearchLib() { return get(TrackableProperty.ControlOppSearchLib); }
|
|
||||||
public void updateControlOppSearchLib(boolean val) { set(TrackableProperty.ControlOppSearchLib, val); }
|
|
||||||
|
|
||||||
public ImmutableMultiset<String> getKeywords() {
|
public ImmutableMultiset<String> getKeywords() {
|
||||||
return get(TrackableProperty.Keywords);
|
return get(TrackableProperty.Keywords);
|
||||||
}
|
}
|
||||||
@@ -358,7 +355,7 @@ public class PlayerView extends GameEntityView {
|
|||||||
return get(TrackableProperty.MindSlaveMaster);
|
return get(TrackableProperty.MindSlaveMaster);
|
||||||
}
|
}
|
||||||
void updateMindSlaveMaster(Player p) {
|
void updateMindSlaveMaster(Player p) {
|
||||||
set(TrackableProperty.MindSlaveMaster, PlayerView.get(p.getMindSlaveMaster()));
|
set(TrackableProperty.MindSlaveMaster, PlayerView.get(p.getControllingPlayer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public FCollectionView<CardView> getAnte() {
|
public FCollectionView<CardView> getAnte() {
|
||||||
|
|||||||
@@ -552,11 +552,9 @@ public final class StaticAbilityContinuous {
|
|||||||
p.addMaxLandPlays(se.getTimestamp(), add);
|
p.addMaxLandPlays(se.getTimestamp(), add);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (params.containsKey("ControlOpponentsWhile")) {
|
if (params.containsKey("ControlOpponentsSearchingLibrary")) {
|
||||||
String cow = params.get("ControlOpponentsWhile");
|
Player cntl = Iterables.getFirst(AbilityUtils.getDefinedPlayers(hostCard, params.get("ControlOpponentsSearchingLibrary"), null), null);
|
||||||
if (cow.equals("SearchingLibrary")) {
|
p.addControlledWhileSearching(se.getTimestamp(), cntl);
|
||||||
p.addControlOppSearchLib(se.getTimestamp());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.containsKey("ControlVote")) {
|
if (params.containsKey("ControlVote")) {
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ public enum TrackableProperty {
|
|||||||
AdditionalVote(TrackableTypes.IntegerType),
|
AdditionalVote(TrackableTypes.IntegerType),
|
||||||
OptionalAdditionalVote(TrackableTypes.IntegerType),
|
OptionalAdditionalVote(TrackableTypes.IntegerType),
|
||||||
ControlVotes(TrackableTypes.BooleanType),
|
ControlVotes(TrackableTypes.BooleanType),
|
||||||
ControlOppSearchLib(TrackableTypes.BooleanType),
|
|
||||||
Keywords(TrackableTypes.KeywordCollectionViewType, FreezeMode.IgnoresFreeze),
|
Keywords(TrackableTypes.KeywordCollectionViewType, FreezeMode.IgnoresFreeze),
|
||||||
Commander(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
|
Commander(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
|
||||||
CommanderCast(TrackableTypes.IntegerMapType),
|
CommanderCast(TrackableTypes.IntegerMapType),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:2 B
|
|||||||
Types:Creature Human Rogue
|
Types:Creature Human Rogue
|
||||||
PT:3/2
|
PT:3/2
|
||||||
K:Flash
|
K:Flash
|
||||||
S:Mode$ Continuous | Affected$ You | ControlOpponentsWhile$ SearchingLibrary | Description$ You control your opponents while they're searching their libraries.
|
S:Mode$ Continuous | Affected$ Opponent | ControlOpponentsSearchingLibrary$ You | Description$ You control your opponents while they're searching their libraries.
|
||||||
R:Event$ Moved | ValidCard$ Card.OppOwn | FoundSearchingLibrary$ True | Origin$ Library | ReplaceWith$ RepExile | ActiveZones$ Battlefield | Description$ While an opponent is searching their library, they exile each card they find. You may play those cards for as long as they remain exiled, and you may spend mana as though it were mana of any color to cast them.
|
R:Event$ Moved | ValidCard$ Card.OppOwn | FoundSearchingLibrary$ True | Origin$ Library | ReplaceWith$ RepExile | ActiveZones$ Battlefield | Description$ While an opponent is searching their library, they exile each card they find. You may play those cards for as long as they remain exiled, and you may spend mana as though it were mana of any color to cast them.
|
||||||
SVar:RepExile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard | SubAbility$ DBEffect
|
SVar:RepExile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard | SubAbility$ DBEffect
|
||||||
SVar:DBEffect:DB$ Effect | Duration$ Permanent | StaticAbilities$ MayPlay | RememberObjects$ ReplacedCard | ForgetOnMoved$ Exile
|
SVar:DBEffect:DB$ Effect | Duration$ Permanent | StaticAbilities$ MayPlay | RememberObjects$ ReplacedCard | ForgetOnMoved$ Exile
|
||||||
|
|||||||
Reference in New Issue
Block a user