Add Noble Banneret

This commit is contained in:
Chris H
2024-05-27 21:32:32 -04:00
parent 66bd484f27
commit edb85a18c4
5 changed files with 160 additions and 60 deletions

View File

@@ -2107,6 +2107,12 @@ public class CardProperty {
(colors.contains("black") && card.getColor().hasBlack()) ||
(colors.contains("red") && card.getColor().hasRed()) ||
(colors.contains("green") && card.getColor().hasGreen());
} else if (property.equals("NotedName")) {
String names = sourceController.getDraftNotes().get(spellAbility.getHostCard().getName());
if (names == null || names.isEmpty()) {
return false;
}
return names.contains(card.getName());
} else if (property.startsWith("Triggered")) {
if (spellAbility instanceof SpellAbility) {
final String key = property.substring(9);

View File

@@ -0,0 +1,8 @@
Name:Noble Banneret
ManaCost:2 W W
Types:Creature Human Knight
PT:3/3
Draft:Draft CARDNAME face up.
Draft:As you draft a creature card, you may reveal it, note its name, then turn CARDNAME face down.
S:Mode$ Continuous | Affected$ Card.Self,Creature.NotedName+YouCtrl | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Lifelink | IsPresent$ Creature.NotedName+YouCtrl | PresentCompare$ GE1 | Description$ As long as you control one or more creatures with a name you noted for cards named Noble Banneret, CARDNAME and those creatures get +1/+1 and have lifelink.
Oracle:Draft Noble Banneret face up.\nAs you draft a creature card, you may reveal it, note its name, then turn Noble Banneret face down.\nAs long as you control one or more creatures with a name you noted for cards named Noble Banneret, Noble Banneret and those creatures get +1/+1 and have lifelink.

View File

@@ -248,6 +248,7 @@ Hold the Perimeter
Hymn of the Wilds
Incendiary Dissent
Natural Unity
Noble Banneret
Pyretic Hunter
Sovereign's Realm
Summoner's Bond

View File

@@ -23,15 +23,16 @@ public class LimitedPlayer {
protected Queue<List<PaperCard>> unopenedPacks;
protected List<PaperCard> removedFromCardPool = new ArrayList<>();
private static final int CantDraftThisRound = 1;
private static final int CantDraftThisRound = 1;
private static final int SpyNextCardDrafted = 1 << 1;
private static final int ReceiveLastCard = 1 << 2;
private static final int CanRemoveAfterDraft = 1 << 3;
private static final int CanTradeAfterDraft = 1 << 4;
private static final int AnimusRemoveFromPool = 1 << 5;
private static final int NobleBanneretActive = 1 << 6;
private static final int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
| CanTradeAfterDraft | AnimusRemoveFromPool;
| CanTradeAfterDraft | AnimusRemoveFromPool | NobleBanneretActive;
private int playerFlags = 0;
@@ -90,68 +91,20 @@ public class LimitedPlayer {
return false;
}
boolean alreadyRevealed = false;
chooseFrom.remove(bestPick);
draftedThisRound++;
if ((playerFlags & AnimusRemoveFromPool) == AnimusRemoveFromPool &&
removeWithAnimus(bestPick)) {
removedFromCardPool.add(bestPick);
addLog(name() + " removed " + bestPick.getName() + " from the draft for Animus of Predation.");
List<String> keywords = new ArrayList<String>();
if (bestPick.getRules().getType().isCreature()) {
for (String keyword : bestPick.getRules().getMainPart().getKeywords()) {
switch (keyword) {
case "Flying":
keywords.add("Flying");
break;
case "First strike":
keywords.add("First Strike");
break;
case "Double strike":
keywords.add("Double Strike");
break;
case "Deathtouch":
keywords.add("Deathtouch");
break;
case "Haste":
keywords.add("Haste");
break;
case "Hexproof":
keywords.add("Hexproof");
break;
case "Indestructible":
keywords.add("Indestructible");
break;
case "Lifelink":
keywords.add("Lifelink");
break;
case "Menace":
keywords.add("Menace");
break;
case "Reach":
keywords.add("Reach");
break;
case "Vigilance":
keywords.add("Vigilance");
break;
}
}
if (!keywords.isEmpty()) {
List<String> note = noted.computeIfAbsent("Animus of Predation", k -> Lists.newArrayList());
note.add(String.join(",", keywords));
addLog(name() + " added " + String.join(",", keywords) + " for Animus of Predation.");
}
}
return true;
} else {
if (!handleAnimusOfPredation(bestPick)) {
CardPool pool = deck.getOrCreate(section);
pool.add(bestPick);
}
alreadyRevealed |= handleNobleBanneret(bestPick);
if (bestPick.getRules().getMainPart().getDraftActions() == null) {
return true;
}
@@ -159,8 +112,10 @@ public class LimitedPlayer {
// Draft Actions
Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions();
if (Iterables.contains(draftActions, "Reveal CARDNAME as you draft it.")) {
revealed.add(bestPick);
showRevealedCard(bestPick);
if (!alreadyRevealed) {
revealed.add(bestPick);
showRevealedCard(bestPick);
}
if (Iterables.contains(draftActions, "Note how many cards you've drafted this draft round, including CARDNAME.")) {
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
@@ -198,15 +153,18 @@ public class LimitedPlayer {
if (Iterables.contains(draftActions, "Draft CARDNAME face up.")) {
faceUp.add(bestPick);
addLog(name() + " drafted " + bestPick.getName() + " face up.");
showRevealedCard(bestPick);
if (!alreadyRevealed) {
showRevealedCard(bestPick);
}
// TODO Noble Banneret
// TODO Paliano Vanguard
// As you draft a VALID, you may Note its [name/type/], and turn this face down
if (Iterables.contains(draftActions, "As you draft a card, you may remove it from the draft face up. (It isnt in your card pool.)")) {
// Animus of Predation
playerFlags |= AnimusRemoveFromPool;
} else if (Iterables.contains(draftActions, "As you draft a creature card, you may reveal it, note its name, then turn CARDNAME face down.")) {
playerFlags |= NobleBanneretActive;
}
// As you draft a VALID, you may remove it face up. (It's no longer in your draft pool)
// TODO We need a deck section that's not your sideboard but is your cardpool?
@@ -267,6 +225,10 @@ public class LimitedPlayer {
return SGuiChoose.one("Remove this " + bestPick + " from the draft for ANnimus of Predation?", Lists.newArrayList("Yes", "No")).equals("Yes");
}
protected boolean revealWithBanneret(PaperCard bestPick) {
return SGuiChoose.one("Reveal this " + bestPick + " for Noble Banneret?", Lists.newArrayList("Yes", "No")).equals("Yes");
}
public String name() {
if (this instanceof LimitedPlayerAI) {
return "Player[" + order + "]";
@@ -280,6 +242,117 @@ public class LimitedPlayer {
}
public boolean handleAnimusOfPredation(PaperCard bestPick) {
if ((playerFlags & AnimusRemoveFromPool) != AnimusRemoveFromPool) {
return false;
}
if (!removeWithAnimus(bestPick)) {
return false;
}
removedFromCardPool.add(bestPick);
addLog(name() + " removed " + bestPick.getName() + " from the draft for Animus of Predation.");
List<String> keywords = new ArrayList<String>();
if (bestPick.getRules().getType().isCreature()) {
for (String keyword : bestPick.getRules().getMainPart().getKeywords()) {
switch (keyword) {
case "Flying":
keywords.add("Flying");
break;
case "First strike":
keywords.add("First Strike");
break;
case "Double strike":
keywords.add("Double Strike");
break;
case "Deathtouch":
keywords.add("Deathtouch");
break;
case "Haste":
keywords.add("Haste");
break;
case "Hexproof":
keywords.add("Hexproof");
break;
case "Indestructible":
keywords.add("Indestructible");
break;
case "Lifelink":
keywords.add("Lifelink");
break;
case "Menace":
keywords.add("Menace");
break;
case "Reach":
keywords.add("Reach");
break;
case "Vigilance":
keywords.add("Vigilance");
break;
}
}
if (!keywords.isEmpty()) {
List<String> note = noted.computeIfAbsent("Animus of Predation", k -> Lists.newArrayList());
note.add(String.join(",", keywords));
addLog(name() + " added " + String.join(",", keywords) + " for Animus of Predation.");
}
}
return true;
}
public boolean handleNobleBanneret(PaperCard bestPick) {
boolean alreadyRevealed = false;
if ((playerFlags & NobleBanneretActive) != NobleBanneretActive) {
return false;
}
if (!bestPick.getRules().getType().isCreature()) {
return false;
}
boolean remaining = false;
PaperCard found = null;
for(PaperCard c : faceUp) {
if (c.getName().equals("Noble Banneret")) {
if (found == null) {
found = c;
} else {
remaining = true;
break;
}
}
}
if (found == null) {
playerFlags &= ~NobleBanneretActive;
return false;
}
if (!revealWithBanneret(bestPick)) {
return false;
}
// As you draft a creature card, you may reveal it, note its name, then turn CARDNAME face down.
List<String> note = noted.computeIfAbsent(found.getName(), k -> Lists.newArrayList());
revealed.add(bestPick);
note.add(bestPick.getName());
addLog(name() + " revealed " + bestPick.getName() + " and noted its name for Noble Banneret.");
addLog(name() + " has flipped Noble Banneret face down.");
alreadyRevealed = true;
faceUp.remove(found);
if (!remaining) {
playerFlags &= ~NobleBanneretActive;
}
return alreadyRevealed;
}
/*
public void addSingleBoosterPack(boolean random) {
// TODO Lore Seeker

View File

@@ -79,4 +79,16 @@ public class LimitedPlayerAI extends LimitedPlayer {
// We should verify we don't already have the keyword bonus that card would grant
return false;
}
@Override
protected boolean revealWithBanneret(PaperCard bestPick) {
// Just choose the first creature that we haven't noted yet.
// This is a very simple heuristic, but it's good enough for now.
if (!bestPick.getRules().getType().isCreature()) {
return false;
}
List<String> nobleBanneret = getDraftNotes().getOrDefault("Noble Banneret", null);
return nobleBanneret == null || !nobleBanneret.contains(bestPick.getName());
}
}