mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
Add localization strings, draw markers, and updated Oubliette room
This commit is contained in:
@@ -58,6 +58,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
p.onCleanupPhase();
|
||||
p.setLandsPlayedLastTurn(0);
|
||||
p.resetCommanderStats();
|
||||
p.resetCompletedDungeons();
|
||||
|
||||
CardCollection newLibrary = new CardCollection(p.getCardsIn(restartZones, false));
|
||||
List<Card> filteredCards = null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -90,6 +91,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
||||
final List<Player> tgts = getTargetPlayers(sa);
|
||||
final boolean devour = sa.hasParam("Devour");
|
||||
final boolean exploit = sa.hasParam("Exploit");
|
||||
final boolean sacEachValid = sa.hasParam("SacEachValid");
|
||||
|
||||
String valid = sa.getParam("SacValid");
|
||||
if (valid == null) {
|
||||
@@ -118,32 +120,63 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
CardCollectionView choosenToSacrifice = null;
|
||||
for (final Player p : tgts) {
|
||||
CardCollectionView battlefield = p.getCardsIn(ZoneType.Battlefield);
|
||||
CardCollectionView validTargets = AbilityUtils.filterListByType(battlefield, valid, sa);
|
||||
if (!destroy) {
|
||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa));
|
||||
}
|
||||
|
||||
if (sa.hasParam("Random")) {
|
||||
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()), new CardCollection());
|
||||
} else if (sa.hasParam("OptionalSacrifice") && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSacrifice"))) {
|
||||
choosenToSacrifice = CardCollection.EMPTY;
|
||||
if (sacEachValid) { // Sacrifice maximum permanents in any combination of types specified by SacValid
|
||||
String [] validArray = valid.split(" & ");
|
||||
String [] msgArray = msg.split(" & ");
|
||||
List<CardCollection> validTargetsList = new ArrayList<>(validArray.length);
|
||||
for (String subValid : validArray) {
|
||||
CardCollectionView validTargets = AbilityUtils.filterListByType(battlefield, subValid, sa);
|
||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa));
|
||||
validTargetsList.add(new CardCollection(validTargets));
|
||||
}
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
for (int i = 0; i < validArray.length; ++i) {
|
||||
CardCollection validTargets = validTargetsList.get(i);
|
||||
if (validTargets.isEmpty()) continue;
|
||||
if (validTargets.size() > 1 && i < validArray.length - 1) {
|
||||
// remove candidates that must be chosen for later types
|
||||
CardCollection union = new CardCollection();
|
||||
for (int j = i + 1; j < validArray.length; ++j) {
|
||||
union.addAll(validTargetsList.get(j));
|
||||
if (union.size() == (j - i) * amount) {
|
||||
validTargets.removeAll(union);
|
||||
}
|
||||
}
|
||||
}
|
||||
choosenToSacrifice = p.getController().choosePermanentsToSacrifice(sa, amount, amount, validTargets, msgArray[i]);
|
||||
for (int j = i + 1; j < validArray.length; ++j) {
|
||||
validTargetsList.get(j).removeAll(choosenToSacrifice);
|
||||
}
|
||||
chosenCards.addAll(choosenToSacrifice);
|
||||
}
|
||||
choosenToSacrifice = chosenCards;
|
||||
} else {
|
||||
boolean isOptional = sa.hasParam("Optional");
|
||||
boolean isStrict = sa.hasParam("StrictAmount");
|
||||
int minTargets = isOptional ? 0 : amount;
|
||||
boolean notEnoughTargets = isStrict && validTargets.size() < minTargets;
|
||||
CardCollectionView validTargets = AbilityUtils.filterListByType(battlefield, valid, sa);
|
||||
if (!destroy) {
|
||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa));
|
||||
}
|
||||
|
||||
if (!notEnoughTargets) {
|
||||
choosenToSacrifice = destroy ?
|
||||
p.getController().choosePermanentsToDestroy(sa, minTargets, amount, validTargets, msg) :
|
||||
p.getController().choosePermanentsToSacrifice(sa, minTargets, amount, validTargets, msg);
|
||||
} else {
|
||||
if (sa.hasParam("Random")) {
|
||||
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()), new CardCollection());
|
||||
} else if (sa.hasParam("OptionalSacrifice") && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSacrifice"))) {
|
||||
choosenToSacrifice = CardCollection.EMPTY;
|
||||
} else {
|
||||
boolean isOptional = sa.hasParam("Optional");
|
||||
boolean isStrict = sa.hasParam("StrictAmount");
|
||||
int minTargets = isOptional ? 0 : amount;
|
||||
boolean notEnoughTargets = isStrict && validTargets.size() < minTargets;
|
||||
|
||||
if (!notEnoughTargets) {
|
||||
choosenToSacrifice = destroy ?
|
||||
p.getController().choosePermanentsToDestroy(sa, minTargets, amount, validTargets, msg) :
|
||||
p.getController().choosePermanentsToSacrifice(sa, minTargets, amount, validTargets, msg);
|
||||
} else {
|
||||
choosenToSacrifice = CardCollection.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class VentureEffect extends SpellAbilityEffect {
|
||||
for (PaperCard pc : dungeonCards) {
|
||||
faces.add(pc.getRules().getMainPart());
|
||||
}
|
||||
String message = Localizer.getInstance().getMessage("lblChooseACardName");
|
||||
String message = Localizer.getInstance().getMessage("lblChooseDungeon");
|
||||
String chosen = player.getController().chooseCardName(sa, faces, message);
|
||||
Card dungeon = Card.fromPaperCard(StaticData.instance().getVariantCards().getUniqueByName(chosen), player);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class VentureEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
final String title = Localizer.getInstance().getMessage("lblChooseAbilityForObject", dungeon.toString());
|
||||
final String title = Localizer.getInstance().getMessage("lblChooseRoom");
|
||||
SpellAbility chosen = player.getController().chooseSingleSpellForEffect(candidates, sa, title, null);
|
||||
return chosen.getParam("RoomName");
|
||||
} else {
|
||||
|
||||
@@ -1954,6 +1954,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void addCompletedDungeon(Card dungeon) {
|
||||
completedDungeons.add(dungeon);
|
||||
}
|
||||
public void resetCompletedDungeons() {
|
||||
completedDungeons.clear();
|
||||
}
|
||||
|
||||
public final void altWinBySpellEffect(final String sourceName) {
|
||||
if (cantWin()) {
|
||||
|
||||
@@ -510,6 +510,13 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
||||
|
||||
}
|
||||
|
||||
if (card.getCurrentRoom() != null && !card.getCurrentRoom().isEmpty()) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("In Room:");
|
||||
markers.add(card.getCurrentRoom());
|
||||
drawMarkersTabs(g, markers);
|
||||
}
|
||||
|
||||
final int combatXSymbols = (cardXOffset + (cardWidth / 4)) - 16;
|
||||
final int stateXSymbols = (cardXOffset + (cardWidth / 2)) - 16;
|
||||
final int ySymbols = (cardYOffset + cardHeight) - (cardHeight / 8) - 16;
|
||||
@@ -840,6 +847,57 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
||||
|
||||
}
|
||||
|
||||
private void drawMarkersTabs(final Graphics g, List<String> markers) {
|
||||
|
||||
final Dimension imgSize = calculateImageSize();
|
||||
final int titleY = Math.round(imgSize.height * (54f / 640)) - 15;
|
||||
|
||||
final int spaceFromTopOfCard = titleY + 60;
|
||||
final int markerBoxHeight = 24;
|
||||
final int markerBoxBaseWidth = 14;
|
||||
final int markerBoxSpacing = 2;
|
||||
|
||||
int currentMarker = 0;
|
||||
|
||||
FontMetrics smallFontMetrics = g.getFontMetrics(smallCounterFont);
|
||||
|
||||
for (String marker : markers) {
|
||||
|
||||
final int markerBoxRealWidth = markerBoxBaseWidth + smallFontMetrics.stringWidth(marker);
|
||||
final int markerYOffset;
|
||||
|
||||
if (ForgeConstants.CounterDisplayLocation.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_LOCATION)) == ForgeConstants.CounterDisplayLocation.TOP) {
|
||||
markerYOffset = cardYOffset + spaceFromTopOfCard - markerBoxHeight + currentMarker++ * (markerBoxHeight + markerBoxSpacing);
|
||||
} else {
|
||||
markerYOffset = cardYOffset + cardHeight - spaceFromTopOfCard / 2 - markerBoxHeight + currentMarker++ * (markerBoxHeight + markerBoxSpacing);
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
g.setColor(new Color(0, 0, 0, 255));
|
||||
} else {
|
||||
g.setColor(new Color(0, 0, 0, 200));
|
||||
}
|
||||
|
||||
RoundRectangle2D markerArea = new RoundRectangle2D.Float(cardXOffset, markerYOffset, markerBoxRealWidth, markerBoxHeight, 9, 9);
|
||||
((Graphics2D) g).fill(markerArea);
|
||||
|
||||
g.fillRect(cardXOffset, markerYOffset, 9, markerBoxHeight);
|
||||
|
||||
if (isSelected) {
|
||||
g.setColor(new Color(200, 200, 200));
|
||||
} else {
|
||||
g.setColor(new Color(200, 200, 200, 180));
|
||||
}
|
||||
|
||||
Rectangle nameBounds = markerArea.getBounds();
|
||||
nameBounds.x += 8;
|
||||
nameBounds.y -= 1;
|
||||
nameBounds.width = 43;
|
||||
drawVerticallyCenteredString(g, marker, nameBounds, smallCounterFont, smallFontMetrics);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a String justified to the left of the rectangle, centered vertically.
|
||||
*
|
||||
|
||||
@@ -113,7 +113,7 @@ public class CardRenderer {
|
||||
|
||||
static {
|
||||
try {
|
||||
for (int fontSize = 11; fontSize <= 22; fontSize++) {
|
||||
for (int fontSize = 8; fontSize <= 22; fontSize++) {
|
||||
generateFontForCounters(fontSize);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -603,6 +603,13 @@ public class CardRenderer {
|
||||
|
||||
}
|
||||
|
||||
if (card.getCurrentRoom() != null && !card.getCurrentRoom().isEmpty()) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("In Room:");
|
||||
markers.add(card.getCurrentRoom());
|
||||
drawMarkersTabs(markers, g, x, y, w, h);
|
||||
}
|
||||
|
||||
float otherSymbolsSize = w / 4f;
|
||||
final float combatXSymbols = (x + (w / 4)) - otherSymbolsSize / 2 - 10;
|
||||
final float stateXSymbols = (x + (w / 2)) - otherSymbolsSize / 2 - 10;
|
||||
@@ -1073,6 +1080,38 @@ public class CardRenderer {
|
||||
|
||||
}
|
||||
|
||||
private static void drawMarkersTabs(final List<String> markers, final Graphics g, final float x, final float y, final float w, final float h) {
|
||||
|
||||
int fontSize = Math.max(8, Math.min(22, (int) (h * 0.05)));
|
||||
BitmapFont font = counterFonts.get(fontSize);
|
||||
|
||||
final float additionalXOffset = 3f * ((fontSize - 8) / 8f);
|
||||
|
||||
float otherSymbolsSize = w / 3.5f;
|
||||
final float ySymbols = (h / 12) - otherSymbolsSize / 2;
|
||||
|
||||
final float markerBoxHeight = 9 + fontSize;
|
||||
final float markerBoxBaseWidth = 8 + additionalXOffset * 2;
|
||||
final float markerBoxSpacing = -4;
|
||||
|
||||
final float spaceFromTopOfCard = y + h - markerBoxHeight - markerBoxSpacing - otherSymbolsSize + ySymbols;
|
||||
|
||||
int markerCounter = markers.size() - 1;
|
||||
|
||||
for (String marker : markers) {
|
||||
layout.setText(font, marker);
|
||||
final float markerBoxRealWidth = markerBoxBaseWidth + layout.width + 4;
|
||||
|
||||
final float markerYOffset = spaceFromTopOfCard - (markerCounter-- * (markerBoxHeight + markerBoxSpacing));
|
||||
|
||||
g.fillRect(counterBackgroundColor, x - 3, markerYOffset, markerBoxRealWidth, markerBoxHeight);
|
||||
|
||||
Color markerColor = new Color(200.0f / 255.0f, 200.0f / 255.0f, 200.0f / 255.0f, 1.0f);
|
||||
|
||||
drawText(g, marker, font, markerColor, x + 2 + additionalXOffset, markerYOffset, markerBoxRealWidth, markerBoxHeight, Align.left);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawPtBox(Graphics g, CardView card, CardStateView details, Color color, float x, float y, float w, float h) {
|
||||
//use array of strings to render separately with a tiny amount of space in between
|
||||
//instead of using actual spaces which are too wide
|
||||
@@ -1202,7 +1241,7 @@ public class CardRenderer {
|
||||
int pageSize = 128;
|
||||
|
||||
//only generate images for characters that could be used by Forge
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890/-+";
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-+:'";
|
||||
|
||||
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
|
||||
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
|
||||
|
||||
@@ -6,9 +6,7 @@ SVar:DBEntry:DB$ LoseLife | Defined$ Player | LifeAmount$ 1 | RoomName$ Trapped
|
||||
SVar:DBVeilsOfFear:DB$ RepeatEach | RepeatSubAbility$ DBLoseLife1 | RepeatPlayers$ Player | RoomName$ Veils of Fear | SpellDescription$ Each player loses 2 life unless they discard a card. | NextRoom$ DBSandfallCell
|
||||
SVar:DBLoseLife1:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ 2 | UnlessCost$ Discard<1/Card> | UnlessPayer$ Remembered
|
||||
SVar:DBOubliette:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose | SubAbility$ DBSacArtifact | RoomName$ Oubliette | SpellDescription$ Discard a card and sacrifice an artifact, a creature, and a land. | NextRoom$ DBCradleDeathGod
|
||||
SVar:DBSacArtifact:DB$ Sacrifice | Defined$ You | SacValid$ Artifact | SubAbility$ DBSacCreature
|
||||
SVar:DBSacCreature:DB$ Sacrifice | Defined$ You | SacValid$ Creature | SubAbility$ DBSacLand
|
||||
SVar:DBSacLand:DB$ Sacrifice | Defined$ You | SacValid$ Land
|
||||
SVar:DBSacArtifact:DB$ Sacrifice | Defined$ You | SacValid$ Artifact & Creature & Land | SacEachValid$ True
|
||||
SVar:DBSandfallCell:DB$ RepeatEach | RepeatSubAbility$ DBLoseLife2 | RepeatPlayers$ Player | RoomName$ Sandfall Cell | SpellDescription$ Each player loses 2 life unless they sacrifice an artifact, a creature, or a land. | NextRoom$ DBCradleDeathGod
|
||||
SVar:DBLoseLife2:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ 2 | UnlessCost$ Sac<1/Artifact;Creature;Land/an artifact, a creature, or a land> | UnlessPayer$ Remembered
|
||||
SVar:DBCradleDeathGod:DB$ Token | TokenScript$ b_4_4_the_atropal_deathtouch | TokenOwner$ You | RoomName$ Cradle of the Death God | SpellDescription$ Create The Atropal, a legendary 4/4 black God Horror creature token with deathtouch.
|
||||
|
||||
@@ -1960,6 +1960,9 @@ lblChoosesPile=Wähle Stapel
|
||||
lblEmptyPile=Leerer Stapel
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=Wähle Karten zum Enttappen
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=Which dungeon do you want to venture into?
|
||||
lblChooseRoom=Which room do you want to venture into?
|
||||
#VoteEffect.java
|
||||
lblVote=Abstimmung
|
||||
lblCurrentVote=Aktuelle Stimmen
|
||||
|
||||
@@ -1960,6 +1960,9 @@ lblChoosesPile=chooses Pile
|
||||
lblEmptyPile=Empty pile
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=Select cards to untap
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=Which dungeon do you want to venture into?
|
||||
lblChooseRoom=Which room do you want to venture into?
|
||||
#VoteEffect.java
|
||||
lblVote=Vote
|
||||
lblCurrentVote=Current Votes
|
||||
|
||||
@@ -1960,6 +1960,9 @@ lblChoosesPile=elige Montón
|
||||
lblEmptyPile=Montón vacío
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=Selecciona las cartas que quieres enderezar
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=Which dungeon do you want to venture into?
|
||||
lblChooseRoom=Which room do you want to venture into?
|
||||
#VoteEffect.java
|
||||
lblVote=Votar
|
||||
lblCurrentVote=Votos actuales
|
||||
|
||||
@@ -1960,6 +1960,9 @@ lblChoosesPile=sceglie la Pila
|
||||
lblEmptyPile=Pila vuota
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=Scegli le carte da Stappare
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=Which dungeon do you want to venture into?
|
||||
lblChooseRoom=Which room do you want to venture into?
|
||||
#VoteEffect.java
|
||||
lblVote=Voto
|
||||
lblCurrentVote=Voti attuali
|
||||
|
||||
@@ -1961,6 +1961,9 @@ lblChoosesPile=束を選んだ
|
||||
lblEmptyPile=空っぽの束
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=アンタップするカードを選ぶ
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=どのダンジョンを探索しますか?
|
||||
lblChooseRoom=どの部屋を探索しますか?
|
||||
#VoteEffect.java
|
||||
lblVote=投票
|
||||
lblCurrentVote=現在の投票
|
||||
|
||||
@@ -1961,6 +1961,9 @@ lblChoosesPile=选择堆
|
||||
lblEmptyPile=空堆
|
||||
#UntapEffect.java
|
||||
lblSelectCardToUntap=选择要重置的牌
|
||||
#VentureEffect.java
|
||||
lblChooseDungeon=Which dungeon do you want to venture into?
|
||||
lblChooseRoom=Which room do you want to venture into?
|
||||
#VoteEffect.java
|
||||
lblVote=投票
|
||||
lblCurrentVote=当前投票
|
||||
|
||||
Reference in New Issue
Block a user