diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 96c5c5d8d69..f0f7d4d37ee 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -949,6 +949,19 @@ public class Game { 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() { clearCounterAddedThisTurn(); for (Player player : getPlayers()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 3249bbec24e..3169e495b47 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -797,6 +797,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } private static void changeZonePlayerInvariant(Player decider, SpellAbility sa, Player player) { + final Game game = player.getGame(); + if (sa.usesTargeting()) { final List players = Lists.newArrayList(sa.getTargets().getTargetPlayers()); player = sa.hasParam("DefinedPlayer") ? player : players.get(0); @@ -872,20 +874,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { CardCollection fetchList; Player originalDecider = decider; - Player deciderControl = null; - PlayerCollection opps = decider.getOpponents(); - long dcts = 0; - for (Player o : opps) { - for (String k : o.getKeywords()) { - if (k.equals("You control your opponents while they're searching their libraries.")) { - long ts = o.getKeywordCard().getTimestamp(); - if (deciderControl == null || ts > (dcts)) { - deciderControl = o; - dcts = ts; - } - } - } - } + Player deciderControl = game.getControlOppSearchLib(); boolean shuffleMandatory = true; boolean searchedLibrary = false; if (defined) { @@ -978,7 +967,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect { shuffleMandatory = false; } - final Game game = player.getGame(); if (sa.hasParam("Unimprint")) { source.clearImprintedCards(); } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 2fb3783d30d..babac61ed42 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -165,6 +165,8 @@ public class Player extends GameEntity implements Comparable { private Map additionalOptionalVotes = Maps.newHashMap(); private SortedSet controlVotes = Sets.newTreeSet(); + private SortedSet controlOppSearchLib = Sets.newTreeSet(); + private final AchievementTracker achievementTracker = new AchievementTracker(); private final PlayerView view; @@ -3412,6 +3414,33 @@ public class Player extends GameEntity implements Comparable { 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 getControlOppSearchLib() { + return controlOppSearchLib; + } + + public Long getHighestControlOppSearchLib() { + if (controlOppSearchLib.isEmpty()) { + return null; + } + return controlOppSearchLib.last(); + } + public void addCycled(SpellAbility sp) { cycledThisTurn++; diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index fed3de925ef..e042df95cbb 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -296,6 +296,9 @@ public class PlayerView extends GameEntityView { set(TrackableProperty.ControlVotes, val); } + public boolean getControlOppSearchLib() { return get(TrackableProperty.ControlOppSearchLib); } + public void updateControlOppSearchLib(boolean val) { set(TrackableProperty.ControlOppSearchLib, val); } + public ImmutableMultiset getKeywords() { return get(TrackableProperty.Keywords); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 3f73cc9db33..c5eab42e25a 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -552,6 +552,12 @@ public final class StaticAbilityContinuous { p.addMaxLandPlays(se.getTimestamp(), add); } } + if (params.containsKey("ControlOpponentsWhile")) { + String cow = params.get("ControlOpponentsWhile"); + if (cow.equals("SearchingLibrary")) { + p.addControlOppSearchLib(se.getTimestamp()); + } + } if (params.containsKey("ControlVote")) { p.addControlVote(se.getTimestamp()); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index c1c1c09f676..1d892fe2db3 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -149,6 +149,7 @@ public enum TrackableProperty { AdditionalVote(TrackableTypes.IntegerType), OptionalAdditionalVote(TrackableTypes.IntegerType), ControlVotes(TrackableTypes.BooleanType), + ControlOppSearchLib(TrackableTypes.BooleanType), Keywords(TrackableTypes.KeywordCollectionViewType, FreezeMode.IgnoresFreeze), Commander(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze), CommanderCast(TrackableTypes.IntegerMapType), diff --git a/forge-gui/res/cardsfolder/upcoming/opposition_agent.txt b/forge-gui/res/cardsfolder/upcoming/opposition_agent.txt index a99bbf8dff2..04ff29fea0b 100755 --- a/forge-gui/res/cardsfolder/upcoming/opposition_agent.txt +++ b/forge-gui/res/cardsfolder/upcoming/opposition_agent.txt @@ -3,7 +3,7 @@ ManaCost:2 B Types:Creature Human Rogue PT:3/2 K:Flash -S:Mode$ Continuous | Affected$ You | AddKeyword$ You control your opponents while they're searching their libraries. | Description$ You control your opponents while they're searching their libraries. +S:Mode$ Continuous | Affected$ You | ControlOpponentsWhile$ SearchingLibrary | 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. 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