mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Add Noble Banneret
This commit is contained in:
@@ -2107,6 +2107,12 @@ public class CardProperty {
|
|||||||
(colors.contains("black") && card.getColor().hasBlack()) ||
|
(colors.contains("black") && card.getColor().hasBlack()) ||
|
||||||
(colors.contains("red") && card.getColor().hasRed()) ||
|
(colors.contains("red") && card.getColor().hasRed()) ||
|
||||||
(colors.contains("green") && card.getColor().hasGreen());
|
(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")) {
|
} else if (property.startsWith("Triggered")) {
|
||||||
if (spellAbility instanceof SpellAbility) {
|
if (spellAbility instanceof SpellAbility) {
|
||||||
final String key = property.substring(9);
|
final String key = property.substring(9);
|
||||||
|
|||||||
8
forge-gui/res/cardsfolder/n/noble_banneret.txt
Normal file
8
forge-gui/res/cardsfolder/n/noble_banneret.txt
Normal 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.
|
||||||
@@ -248,6 +248,7 @@ Hold the Perimeter
|
|||||||
Hymn of the Wilds
|
Hymn of the Wilds
|
||||||
Incendiary Dissent
|
Incendiary Dissent
|
||||||
Natural Unity
|
Natural Unity
|
||||||
|
Noble Banneret
|
||||||
Pyretic Hunter
|
Pyretic Hunter
|
||||||
Sovereign's Realm
|
Sovereign's Realm
|
||||||
Summoner's Bond
|
Summoner's Bond
|
||||||
|
|||||||
@@ -23,15 +23,16 @@ public class LimitedPlayer {
|
|||||||
protected Queue<List<PaperCard>> unopenedPacks;
|
protected Queue<List<PaperCard>> unopenedPacks;
|
||||||
protected List<PaperCard> removedFromCardPool = new ArrayList<>();
|
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 SpyNextCardDrafted = 1 << 1;
|
||||||
private static final int ReceiveLastCard = 1 << 2;
|
private static final int ReceiveLastCard = 1 << 2;
|
||||||
private static final int CanRemoveAfterDraft = 1 << 3;
|
private static final int CanRemoveAfterDraft = 1 << 3;
|
||||||
private static final int CanTradeAfterDraft = 1 << 4;
|
private static final int CanTradeAfterDraft = 1 << 4;
|
||||||
private static final int AnimusRemoveFromPool = 1 << 5;
|
private static final int AnimusRemoveFromPool = 1 << 5;
|
||||||
|
private static final int NobleBanneretActive = 1 << 6;
|
||||||
|
|
||||||
private static final int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
|
private static final int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
|
||||||
| CanTradeAfterDraft | AnimusRemoveFromPool;
|
| CanTradeAfterDraft | AnimusRemoveFromPool | NobleBanneretActive;
|
||||||
|
|
||||||
private int playerFlags = 0;
|
private int playerFlags = 0;
|
||||||
|
|
||||||
@@ -90,68 +91,20 @@ public class LimitedPlayer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean alreadyRevealed = false;
|
||||||
|
|
||||||
chooseFrom.remove(bestPick);
|
chooseFrom.remove(bestPick);
|
||||||
|
|
||||||
draftedThisRound++;
|
draftedThisRound++;
|
||||||
|
|
||||||
if ((playerFlags & AnimusRemoveFromPool) == AnimusRemoveFromPool &&
|
if (!handleAnimusOfPredation(bestPick)) {
|
||||||
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 {
|
|
||||||
CardPool pool = deck.getOrCreate(section);
|
CardPool pool = deck.getOrCreate(section);
|
||||||
pool.add(bestPick);
|
pool.add(bestPick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alreadyRevealed |= handleNobleBanneret(bestPick);
|
||||||
|
|
||||||
|
|
||||||
if (bestPick.getRules().getMainPart().getDraftActions() == null) {
|
if (bestPick.getRules().getMainPart().getDraftActions() == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -159,8 +112,10 @@ public class LimitedPlayer {
|
|||||||
// Draft Actions
|
// Draft Actions
|
||||||
Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions();
|
Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions();
|
||||||
if (Iterables.contains(draftActions, "Reveal CARDNAME as you draft it.")) {
|
if (Iterables.contains(draftActions, "Reveal CARDNAME as you draft it.")) {
|
||||||
revealed.add(bestPick);
|
if (!alreadyRevealed) {
|
||||||
showRevealedCard(bestPick);
|
revealed.add(bestPick);
|
||||||
|
showRevealedCard(bestPick);
|
||||||
|
}
|
||||||
|
|
||||||
if (Iterables.contains(draftActions, "Note how many cards you've drafted this draft round, including CARDNAME.")) {
|
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());
|
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.")) {
|
if (Iterables.contains(draftActions, "Draft CARDNAME face up.")) {
|
||||||
faceUp.add(bestPick);
|
faceUp.add(bestPick);
|
||||||
addLog(name() + " drafted " + bestPick.getName() + " face up.");
|
addLog(name() + " drafted " + bestPick.getName() + " face up.");
|
||||||
showRevealedCard(bestPick);
|
if (!alreadyRevealed) {
|
||||||
|
showRevealedCard(bestPick);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Noble Banneret
|
|
||||||
// TODO Paliano Vanguard
|
// TODO Paliano Vanguard
|
||||||
// As you draft a VALID, you may Note its [name/type/], and turn this face down
|
// 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 isn’t in your card pool.)")) {
|
if (Iterables.contains(draftActions, "As you draft a card, you may remove it from the draft face up. (It isn’t in your card pool.)")) {
|
||||||
// Animus of Predation
|
// Animus of Predation
|
||||||
playerFlags |= AnimusRemoveFromPool;
|
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)
|
// 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?
|
// 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");
|
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() {
|
public String name() {
|
||||||
if (this instanceof LimitedPlayerAI) {
|
if (this instanceof LimitedPlayerAI) {
|
||||||
return "Player[" + order + "]";
|
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) {
|
public void addSingleBoosterPack(boolean random) {
|
||||||
// TODO Lore Seeker
|
// TODO Lore Seeker
|
||||||
|
|||||||
@@ -79,4 +79,16 @@ public class LimitedPlayerAI extends LimitedPlayer {
|
|||||||
// We should verify we don't already have the keyword bonus that card would grant
|
// We should verify we don't already have the keyword bonus that card would grant
|
||||||
return false;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user