Skip to content

Commit 496b3a5

Browse files
committed
StaticAbilityCantSearchLibrary
1 parent e2fd821 commit 496b3a5

12 files changed

Lines changed: 73 additions & 16 deletions

File tree

docs/Card-scripting-API/Card-scripting-API.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ CARDNAME is replaced by the card's name ingame.
144144
- CARDNAME must be blocked if able.
145145
- Remove CARDNAME from your deck before playing if you're not playing for ante.
146146
- You may choose not to untap CARDNAME during your untap step.
147-
- CantSearchLibrary
148147

149148
# General SVars
150149
* `SoundEffect:<file.mp3>`

forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import forge.game.replacement.ReplacementType;
2121
import forge.game.spellability.SpellAbility;
2222
import forge.game.spellability.SpellAbilityStackInstance;
23+
import forge.game.staticability.StaticAbilityCantSearchLibrary;
2324
import forge.game.trigger.TriggerType;
2425
import forge.game.zone.Zone;
2526
import forge.game.zone.ZoneType;
@@ -1015,9 +1016,9 @@ else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
10151016
if (origin.contains(ZoneType.Library) && !sa.hasParam("NoLooking")) {
10161017
searchedLibrary = true;
10171018

1018-
if (decider.hasKeyword("LimitSearchLibrary")) { // Aven Mindcensor
1019+
Integer fetchNum = StaticAbilityCantSearchLibrary.limitSearchLibraryConsideringSize(decider);
1020+
if (fetchNum != null) {
10191021
fetchList.removeAll(player.getCardsIn(ZoneType.Library));
1020-
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
10211022
if (fetchNum == 0) {
10221023
searchedLibrary = false;
10231024
} else {
@@ -1040,9 +1041,9 @@ else if (!origin.contains(ZoneType.Library) && !origin.contains(ZoneType.Hand)
10401041
Set<ZoneType> revealZones = Sets.newHashSet();
10411042
Iterable<Card> toReveal = null;
10421043
if (origin.contains(ZoneType.Library) && searchedLibrary) {
1043-
final int fetchNum = Math.min(player.getCardsIn(ZoneType.Library).size(), 4);
1044+
Integer fetchNum = StaticAbilityCantSearchLibrary.limitSearchLibraryConsideringSize(decider);
10441045
// Look at whole library before moving onto choosing a card
1045-
toReveal = !decider.hasKeyword("LimitSearchLibrary") ? player.getCardsIn(ZoneType.Library) : player.getCardsIn(ZoneType.Library, fetchNum);
1046+
toReveal = fetchNum != null ? player.getCardsIn(ZoneType.Library, fetchNum) : player.getCardsIn(ZoneType.Library);
10461047
revealZones.add(ZoneType.Library);
10471048
}
10481049
if (origin.contains(ZoneType.Hand) && player.isOpponentOf(decider)) {

forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import forge.game.player.PlayerActionConfirmMode;
2121
import forge.game.player.PlayerCollection;
2222
import forge.game.spellability.SpellAbility;
23+
import forge.game.staticability.StaticAbilityCantSearchLibrary;
2324
import forge.game.zone.ZoneType;
2425
import forge.util.Aggregates;
2526
import forge.util.Lang;
@@ -251,9 +252,8 @@ public void resolve(SpellAbility sa) {
251252
}
252253

253254
final Player searched = AbilityUtils.getDefinedPlayers(host, sa.getParam("QuasiLibrarySearch"), sa).get(0);
254-
final int fetchNum = Math.min(searched.getCardsIn(ZoneType.Library).size(), 4);
255-
CardCollectionView shown = !p.hasKeyword("LimitSearchLibrary")
256-
? searched.getCardsIn(ZoneType.Library) : searched.getCardsIn(ZoneType.Library, fetchNum);
255+
final Integer fetchNum = StaticAbilityCantSearchLibrary.limitSearchLibraryConsideringSize(p);
256+
final CardCollectionView shown = fetchNum != null ? searched.getCardsIn(ZoneType.Library, fetchNum) : searched.getCardsIn(ZoneType.Library);
257257
DelayedReveal delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(searched),
258258
host.getTranslatedName() + " - " +
259259
Localizer.getInstance().getMessage("lblLookingCardIn") + " ");

forge-game/src/main/java/forge/game/player/Player.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3723,11 +3723,11 @@ public boolean canSearchLibraryWith(SpellAbility sa, Player targetPlayer) {
37233723
return true;
37243724
}
37253725

3726-
if (hasKeyword("CantSearchLibrary")) {
3726+
if (StaticAbilityCantSearchLibrary.cantSearchLibrary(this)) {
37273727
return false;
37283728
}
37293729
return targetPlayer == null || !targetPlayer.equals(sa.getActivatingPlayer())
3730-
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
3730+
|| !StaticAbilityCantSearchLibrary.cantCauseToSearchLibrary(this);
37313731
}
37323732

37333733
public void addAdditionalVote(long timestamp, int value) {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package forge.game.staticability;
2+
3+
import forge.game.player.Player;
4+
import forge.game.zone.ZoneType;
5+
6+
import java.util.Optional;
7+
8+
import static forge.game.staticability.StaticAbilityMode.CantSearchLibrary;
9+
import static forge.game.staticability.StaticAbilityMode.LimitSearchLibrary;
10+
import static forge.game.staticability.StaticAbilityMode.CantCauseToSearchLibrary;
11+
12+
13+
public class StaticAbilityCantSearchLibrary {
14+
15+
/**
16+
* @return maximum number of cards which can be fetched from a library considering its size and search limit or null if there is no limit
17+
*/
18+
public static Integer limitSearchLibraryConsideringSize(Player player) {
19+
Integer limit = limitSearchLibrary(player);
20+
if (limit != null) {
21+
return Math.min(player.getCardsIn(ZoneType.Library).size(), limit);
22+
} else {
23+
return null;
24+
}
25+
}
26+
27+
/**
28+
* @return maximum number of cards which can be revealed from a library or null if there is no limit
29+
*/
30+
public static Integer limitSearchLibrary(Player player) {
31+
return findStaticAbilityForValidPlayer(player, LimitSearchLibrary)
32+
.map(stAb -> Integer.valueOf(stAb.getParam("LimitNum")))
33+
.orElse(null);
34+
}
35+
36+
public static boolean cantSearchLibrary(Player player) {
37+
return findStaticAbilityForValidPlayer(player, CantSearchLibrary).isPresent();
38+
}
39+
40+
public static boolean cantCauseToSearchLibrary(Player player) {
41+
return findStaticAbilityForValidPlayer(player, CantCauseToSearchLibrary).isPresent();
42+
}
43+
44+
private static Optional<StaticAbility> findStaticAbilityForValidPlayer(final Player player, final StaticAbilityMode mode) {
45+
return player.getGame()
46+
.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)
47+
.stream()
48+
.flatMap(card -> card.getStaticAbilities().stream())
49+
.filter(stAb -> stAb.checkConditions(mode) && stAb.matchesValidParam("ValidPlayer", player))
50+
.findAny();
51+
}
52+
}

forge-game/src/main/java/forge/game/staticability/StaticAbilityMode.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ public enum StaticAbilityMode {
200200

201201
// StaticAbilityCountersRemain
202202
CountersRemain,
203+
204+
// StaticAbilityCantSearchLibrary
205+
LimitSearchLibrary,
206+
CantSearchLibrary,
207+
CantCauseToSearchLibrary
203208
;
204209

205210
public static StaticAbilityMode smartValueOf(final String value) {

forge-gui/res/cardsfolder/a/ashiok_dream_render.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Name:Ashiok, Dream Render
22
ManaCost:1 UB UB
33
Types:Legendary Planeswalker Ashiok
44
Loyalty:5
5-
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ Spells and abilities you control can't cause you to search your library. | Description$ Spells and abilities your opponents control can't cause their controller to search their library.
5+
S:Mode$ CantCauseToSearchLibrary | ValidPlayer$ Opponent | Description$ Spells and abilities your opponents control can't cause their controller to search their library.
66
A:AB$ Mill | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 4 | ValidTgts$ Player | SubAbility$ DBExileGrave | SpellDescription$ Target player mills four cards. Then exile each opponent's graveyard.
77
SVar:DBExileGrave:DB$ ChangeZoneAll | Origin$ Graveyard | Destination$ Exile | Defined$ Opponent | ChangeType$ Card
88
Oracle:Spells and abilities your opponents control can't cause their controller to search their library.\n[-1]: Target player mills four cards. Then exile each opponent's graveyard.

forge-gui/res/cardsfolder/a/aven_mindcensor.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ Types:Creature Bird Wizard
44
PT:2/1
55
K:Flash
66
K:Flying
7-
S:Mode$ Continuous | Affected$ Player.Opponent | AddKeyword$ LimitSearchLibrary | Description$ If an opponent would search a library, that player searches the top four cards of that library instead.
7+
S:Mode$ LimitSearchLibrary | ValidPlayer$ Player.Opponent | LimitNum$ 4 | Description$ If an opponent would search a library, that player searches the top four cards of that library instead.
88
Oracle:Flash\nFlying\nIf an opponent would search a library, that player searches the top four cards of that library instead.

forge-gui/res/cardsfolder/l/leonin_arbiter.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Name:Leonin Arbiter
22
ManaCost:1 W
33
Types:Creature Cat Cleric
44
PT:2/2
5-
S:Mode$ Continuous | Affected$ Player | AddKeyword$ CantSearchLibrary | IgnoreEffectCost$ 2 | Description$ Players can't search libraries. Any player may pay {2} for that player to ignore this effect until end of turn.
5+
S:Mode$ CantSearchLibrary | ValidPlayer$ Player | IgnoreEffectCost$ 2 | Description$ Players can't search libraries. Any player may pay {2} for that player to ignore this effect until end of turn.
66
# TODO: The AI won't activate the effect yet, but then again, it won't activate it even if the human is playing with this card, so it doesn't affect specifically the AI playability of this card.
77
AI:RemoveDeck:Random
88
Oracle:Players can't search libraries. Any player may pay {2} for that player to ignore this effect until end of turn.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Name:Mindlock Orb
22
ManaCost:3 U
33
Types:Artifact
4-
S:Mode$ Continuous | Affected$ Player | AddKeyword$ CantSearchLibrary | Description$ Players can't search libraries.
4+
S:Mode$ CantSearchLibrary | ValidPlayer$ Player | Description$ Players can't search libraries.
55
Oracle:Players can't search libraries.

0 commit comments

Comments
 (0)