Merge pull request #5401 from kevlahnota/newmaster2

Add Backup/Restore Data Adventure Mode
This commit is contained in:
kevlahnota
2024-06-10 06:10:41 +08:00
committed by GitHub
30 changed files with 403 additions and 41 deletions

View File

@@ -27,7 +27,7 @@ public class RewardSprite extends CharacterSprite {
if (data != null) {
rewards = JSONStringLoader.parse(RewardData[].class, data, default_reward);
} else { //Shouldn't happen, but make sure it doesn't fly by.
System.err.printf("Reward data is null. Using a default reward.");
System.err.print("Reward data is null. Using a default reward.");
rewards = JSONStringLoader.parse(RewardData[].class, default_reward, default_reward);
}
}

View File

@@ -599,7 +599,7 @@ public class AdventureEventData implements Serializable {
} else {
description += "\n";
}
description += String.format("Prizes\n3 round wins: 500 gold\n2 round wins: 200 gold\n1 round win: 100 gold\n");
description += "Prizes\n3 round wins: 500 gold\n2 round wins: 200 gold\n1 round win: 100 gold\n";
description += "Finishing event will award an unsellable copy of each card in your Jumpstart deck.";
}
return description;

View File

@@ -1106,10 +1106,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
if (canOnlyBePartnerCommander(card)) {
return; //don't auto-change commander unexpectedly
}
DeckSectionPage main = getMainDeckPage();
if (main == null)
return;
if (!cardManager.isInfinite()) {
removeCard(card);
}
getMainDeckPage().addCard(card);
main.addCard(card);
}
@Override

View File

@@ -238,12 +238,18 @@ public class ArenaScene extends UIScene implements IAfterMatch {
arenaPlane.addActor(lost);
}
boolean started = false;
private void startRound() {
if (started)
return;
started = true;
DuelScene duelScene = DuelScene.instance();
EnemySprite enemy = enemies.get(enemies.size - 1);
FThreads.invokeInEdtNowOrLater(() -> {
Forge.setTransitionScreen(new TransitionScreen(() -> {
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy);
started = false;
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy, true, null);
Forge.switchScene(duelScene);
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), enemy.getAtlasPath(), Current.player().getName(), enemy.getName()));
});

View File

@@ -127,7 +127,7 @@ public class NewGameScene extends MenuScene {
modeNames[i] = modes.get(i).getName();
mode.setTextList(modeNames);
gender.setTextList(new String[]{Forge.getLocalizer().getInstance().getMessage("lblMale"), Forge.getLocalizer().getInstance().getMessage("lblFemale")});
gender.setTextList(new String[]{Forge.getLocalizer().getMessage("lblMale"), Forge.getLocalizer().getMessage("lblFemale")});
gender.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
@@ -217,7 +217,7 @@ public class NewGameScene extends MenuScene {
}
Forge.switchScene(GameScene.instance());
};
Forge.setTransitionScreen(new TransitionScreen(runnable, null, false, true, "Generating World..."));
Forge.setTransitionScreen(new TransitionScreen(runnable, null, false, true, Forge.getLocalizer().getMessage("lblGeneratingWorld")));
return true;
}

View File

@@ -273,6 +273,7 @@ public class PlayerStatisticScene extends UIScene {
if (g != null) //skip variants
continue;
}
a.updateTrophyImage();
TextureRegion textureRegion = new TextureRegion(((FBufferedImage) a.getImage()).getTexture());
textureRegion.flip(false, true);
Image image = new Image(textureRegion);

View File

@@ -196,14 +196,19 @@ public class SaveLoadScene extends UIScene {
return true;
}
boolean loaded = false;
public void loadSave() {
if (loaded)
return;
loaded = true;
switch (mode) {
case Save:
if (TileMapScene.instance().currentMap().isInMap()) {
//Access to screen should be disabled, but stop the process just in case.
//Saving needs to be disabled inside maps until we can capture and load exact map state
//Otherwise location based events for quests can be skipped by saving and then loading outside the map
Dialog noSave = createGenericDialog("", "!!GAME NOT SAVED!!\nManual saving is only available on the world map","OK",null, null, null);
Dialog noSave = createGenericDialog("", Forge.getLocalizer().getMessage("lblGameNotSaved"), Forge.getLocalizer().getMessage("lblOK"),null, null, null);
showDialog(noSave);
return;
}
@@ -226,17 +231,19 @@ public class SaveLoadScene extends UIScene {
showDialog(saveDialog);
stage.setKeyboardFocus(textInput);
}
loaded = false;
break;
case Load:
try {
Forge.setTransitionScreen(new TransitionScreen(() -> {
loaded = false;
if (WorldSave.load(currentSlot)) {
SoundSystem.instance.changeBackgroundTrack();
Forge.switchScene(GameScene.instance());
} else {
Forge.clearTransitionScreen();
}
}, null, false, true, "Loading World..."));
}, null, false, true, Forge.getLocalizer().getMessage("lblLoadingWorld")));
} catch (Exception e) {
Forge.clearTransitionScreen();
}
@@ -244,6 +251,7 @@ public class SaveLoadScene extends UIScene {
case NewGamePlus:
try {
Forge.setTransitionScreen(new TransitionScreen(() -> {
loaded = false;
if (WorldSave.load(currentSlot)) {
WorldSave.getCurrentSave().clearChanges();
WorldSave.getCurrentSave().getWorld().generateNew(0);
@@ -261,8 +269,9 @@ public class SaveLoadScene extends UIScene {
} else {
Forge.clearTransitionScreen();
}
}, null, false, true, "Generating World..."));
}, null, false, true, Forge.getLocalizer().getMessage("lblGeneratingWorld")));
} catch (Exception e) {
loaded = false;
Forge.clearTransitionScreen();
}
break;

View File

@@ -1,24 +1,33 @@
package forge.adventure.scene;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.utils.Timer;
import com.github.tommyettinger.textra.TextraButton;
import com.github.tommyettinger.textra.TypingLabel;
import forge.Forge;
import forge.adventure.stage.GameHUD;
import forge.adventure.stage.GameStage;
import forge.adventure.stage.MapStage;
import forge.adventure.util.Config;
import forge.adventure.util.Controls;
import forge.adventure.world.WorldSave;
import forge.localinstance.properties.ForgeProfileProperties;
import forge.screens.TransitionScreen;
import forge.sound.SoundSystem;
import forge.util.ZipUtil;
import java.io.File;
import java.io.IOException;
/**
* First scene after the splash screen
*/
public class StartScene extends UIScene {
private static StartScene object;
Dialog exitDialog;
Dialog exitDialog, backupDialog, zipDialog, unzipDialog;
TextraButton saveButton, resumeButton, continueButton;
TypingLabel version = Controls.newTypingLabel("{GRADIENT}[%80]" + Forge.CURRENT_VERSION + "{ENDGRADIENT}");
public StartScene() {
@@ -30,6 +39,7 @@ public class StartScene extends UIScene {
ui.onButtonPress("Resume", StartScene.this::Resume);
ui.onButtonPress("Continue", StartScene.this::Continue);
ui.onButtonPress("Settings", StartScene.this::settings);
ui.onButtonPress("Backup", StartScene.this::backup);
ui.onButtonPress("Exit", StartScene.this::Exit);
ui.onButtonPress("Switch", StartScene.this::switchToClassic);
@@ -40,6 +50,9 @@ public class StartScene extends UIScene {
saveButton.setVisible(false);
resumeButton.setVisible(false);
version.setHeight(5);
version.skipToTheEnd();
ui.addActor(version);
}
public static StartScene instance() {
@@ -55,7 +68,7 @@ public class StartScene extends UIScene {
public boolean Save() {
if (TileMapScene.instance().currentMap().isInMap()) {
Dialog noSave = createGenericDialog("", "!!GAME NOT SAVED!!\nManual saving is only available on the world map","OK",null, null, null);
Dialog noSave = createGenericDialog("", Forge.getLocalizer().getMessage("lblGameNotSaved"), Forge.getLocalizer().getMessage("lblOK"),null, null, null);
showDialog(noSave);
} else {
SaveLoadScene.instance().setMode(SaveLoadScene.Modes.Save);
@@ -79,20 +92,27 @@ public class StartScene extends UIScene {
return true;
}
boolean loaded = false;
public boolean Continue() {
final String lastActiveSave = Config.instance().getSettingData().lastActiveSave;
if (WorldSave.isSafeFile(lastActiveSave)) {
if (loaded)
return true;
loaded = true;
try {
Forge.setTransitionScreen(new TransitionScreen(() -> {
loaded = false;
if (WorldSave.load(WorldSave.filenameToSlot(lastActiveSave))) {
SoundSystem.instance.changeBackgroundTrack();
Forge.switchScene(GameScene.instance());
} else {
Forge.clearTransitionScreen();
}
}, null, false, true, "Loading World..."));
}, null, false, true, Forge.getLocalizer().getMessage("lblLoadingWorld")));
} catch (Exception e) {
loaded = false;
Forge.clearTransitionScreen();
}
}
@@ -105,6 +125,86 @@ public class StartScene extends UIScene {
return true;
}
public boolean backup() {
if (backupDialog == null) {
backupDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblData"),
null, Forge.getLocalizer().getMessage("lblBackup"),
Forge.getLocalizer().getMessage("lblRestore"),
() -> {
removeDialog();
Timer.schedule(new Timer.Task() {
@Override
public void run() {
generateBackup();
}
}, 0.2f);
},
() -> {
removeDialog();
Timer.schedule(new Timer.Task() {
@Override
public void run() {
restoreBackup();
}
}, 0.2f);
}, true, Forge.getLocalizer().getMessage("lblCancel"));
}
showDialog(backupDialog);
return true;
}
public boolean generateBackup() {
try {
File source = new FileHandle(ForgeProfileProperties.getUserDir() + "/adventure/Shandalar").file();
File target = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir()).file();
ZipUtil.zip(source, target, ZipUtil.backupAdvFile);
zipDialog = createGenericDialog("",
Forge.getLocalizer().getMessage("lblSaveLocation") + "\n" + target.getAbsolutePath() + File.separator + ZipUtil.backupAdvFile,
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null);
} catch (IOException e) {
zipDialog = createGenericDialog("",
Forge.getLocalizer().getMessage("lblErrorSavingFile") + "\n\n" + e.getMessage(),
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null);
} finally {
showDialog(zipDialog);
}
return true;
}
public boolean restoreBackup() {
File source = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir() + ZipUtil.backupAdvFile).file();
File target = new FileHandle(ForgeProfileProperties.getUserDir() + "/adventure/Shandalar").file().getParentFile();
if (unzipDialog == null) {
unzipDialog = createGenericDialog("",
Forge.getLocalizer().getMessage("lblDoYouWantToRestoreBackup"),
Forge.getLocalizer().getMessage("lblYes"), Forge.getLocalizer().getMessage("lblNo"),
() -> {
removeDialog();
Timer.schedule(new Timer.Task() {
@Override
public void run() {
extract(source, target);
}
}, 0.2f);
}, this::removeDialog);
}
showDialog(unzipDialog);
return true;
}
public boolean extract(File source, File target) {
String title = "", val = "";
try {
val = Forge.getLocalizer().getMessage("lblFiles") + ":\n" + ZipUtil.unzip(source, target);
} catch (IOException e) {
title = Forge.getLocalizer().getMessage("lblError");
val = e.getMessage();
} finally {
Config.instance().getSettingData().lastActiveSave = null;
Config.instance().saveSettings();
showDialog(createGenericDialog(title, val,
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null));
}
return true;
}
public boolean Exit() {
if (exitDialog == null) {
exitDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblExitForge"),
@@ -123,16 +223,7 @@ public class StartScene extends UIScene {
Forge.switchToClassic();
}
@Override
public void enter() {
boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null;
if (hasSaveButton) {
TileMapScene scene = TileMapScene.instance();
hasSaveButton = !scene.currentMap().isInMap() || scene.isAutoHealLocation();
}
saveButton.setVisible(hasSaveButton);
saveButton.setDisabled(TileMapScene.instance().currentMap().isInMap());
public void updateResumeContinue() {
boolean hasResumeButton = WorldSave.getCurrentSave().getWorld().getData() != null;
resumeButton.setVisible(hasResumeButton);
@@ -146,7 +237,18 @@ public class StartScene extends UIScene {
} else {
continueButton.setVisible(false);
}
}
@Override
public void enter() {
boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null;
if (hasSaveButton) {
TileMapScene scene = TileMapScene.instance();
hasSaveButton = !scene.currentMap().isInMap() || scene.isAutoHealLocation();
}
saveButton.setVisible(hasSaveButton);
saveButton.setDisabled(TileMapScene.instance().currentMap().isInMap());
updateResumeContinue();
if (Forge.createNewAdventureMap) {
this.NewGame();

View File

@@ -239,6 +239,9 @@ public class UIScene extends Scene {
}
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo) {
return createGenericDialog(title, label, stringYes, stringNo, runnableYes, runnableNo, false, "");
}
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo, boolean cancelButton, String stringCancel) {
Dialog dialog = new Dialog(title == null ? "" : title, Controls.getSkin());
if (label != null)
dialog.text(label);
@@ -248,6 +251,10 @@ public class UIScene extends Scene {
TextraButton no = Controls.newTextButton(stringNo, runnableNo);
dialog.button(no);
}
if (cancelButton) {
TextraButton cancel = Controls.newTextButton(stringCancel, this::removeDialog);
dialog.button(cancel);
}
return dialog;
}

View File

@@ -39,7 +39,7 @@ public class ConsoleCommandInterpreter {
public String complete(String text) {
String[] words = splitOnSpace(text);
Command currentCommand = root;
String completionString = "";
StringBuilder completionString = new StringBuilder();
for (String name : words) {
if (!currentCommand.children.containsKey(name)) {
for (String key : currentCommand.children.keySet()) {
@@ -49,7 +49,7 @@ public class ConsoleCommandInterpreter {
}
break;
}
completionString += name + " ";
completionString.append(name).append(" ");
currentCommand = currentCommand.children.get(name);
}
return text;

View File

@@ -1039,6 +1039,7 @@ public class MapStage extends GameStage {
}
}
boolean started = false;
public void beginDuel(EnemySprite mob) {
if (mob == null) return;
mob.clearCollisionHeight();
@@ -1054,6 +1055,9 @@ public class MapStage extends GameStage {
Forge.restrictAdvMenus = true;
player.clearCollisionHeight();
startPause(0.8f, () -> {
if (started)
return;
started = true;
Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2");
SoundSystem.instance.play(SoundEffectType.ManaBurn, false);
DuelScene duelScene = DuelScene.instance();
@@ -1061,6 +1065,7 @@ public class MapStage extends GameStage {
if (!isLoadingMatch) {
isLoadingMatch = true;
Forge.setTransitionScreen(new TransitionScreen(() -> {
started = false;
duelScene.initDuels(player, mob);
if (isInMap && effect != null && !mob.ignoreDungeonEffect)
duelScene.setDungeonEffect(effect);

View File

@@ -64,6 +64,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
final Rectangle tempBoundingRect = new Rectangle();
final Vector2 enemyMoveVector = new Vector2();
boolean collided = false;
@Override
protected void onActing(float delta) {
if (isPaused() || MapStage.getInstance().isDialogOnlyInput())
@@ -110,6 +111,9 @@ public class WorldStage extends GameStage implements SaveFileContent {
}
if (player.collideWith(mob)) {
if (collided)
return;
collided = true;
player.setAnimation(CharacterSprite.AnimationTypes.Attack);
player.playEffect(Paths.EFFECT_SPARKS, 0.5f);
mob.setAnimation(CharacterSprite.AnimationTypes.Attack);
@@ -126,6 +130,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
DuelScene duelScene = DuelScene.instance();
FThreads.invokeInEdtNowOrLater(() -> {
Forge.setTransitionScreen(new TransitionScreen(() -> {
collided = false;
duelScene.initDuels(player, mob);
Forge.switchScene(duelScene);
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), mob.getAtlasPath(), Current.player().getName(), mob.getName()));

View File

@@ -21,6 +21,7 @@ import com.badlogic.gdx.utils.Timer;
import com.github.tommyettinger.textra.Font;
import com.github.tommyettinger.textra.TextraButton;
import com.github.tommyettinger.textra.TextraLabel;
import com.github.tommyettinger.textra.TypingButton;
import com.github.tommyettinger.textra.TypingLabel;
import forge.Forge;
import forge.adventure.player.AdventurePlayer;
@@ -84,12 +85,53 @@ public class Controls {
}
static class TypingButtonFix extends TypingButton {
public TypingButtonFix(@Null String text) {
super(text == null ? "NULL" : text, Controls.getSkin(), Controls.getTextraFont());
addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
SoundSystem.instance.play(SoundEffectType.ButtonPress, false);
}
});
}
@Override
public void setStyle(Button.ButtonStyle style, boolean makeGridGlyphs) {
super.setStyle(style, makeGridGlyphs);
this.getTextraLabel().setFont(Controls.getTextraFont());
}
@Override
public String getText() {
return this.getTextraLabel().storedText;
}
@Override
public void setText(@Null String text) {
getTextraLabel().storedText = text;
getTextraLabel().layout.setTargetWidth(getTextraLabel().getMaxWidth());
getTextraLabel().getFont().markup(text, getTextraLabel().layout.clear());
getTextraLabel().setWidth(getTextraLabel().layout.getWidth() + (getTextraLabel().style != null && getTextraLabel().style.background != null ? getTextraLabel().style.background.getLeftWidth() + getTextraLabel().style.background.getRightWidth() : 0.0F));
layout();
}
}
static public TextraButton newTextButton(String text) {
TextraButton button = new TextButtonFix(text);
button.getTextraLabel().setWrap(false);
return button;
}
static public TypingButton newTypingButton(String text) {
TypingButton button = new TypingButtonFix(text);
button.getTextraLabel().setWrap(false);
return button;
}
static public Rectangle getBoundingRect(Actor actor) {
return new Rectangle(actor.getX(), actor.getY(), actor.getWidth(), actor.getHeight());
}

View File

@@ -354,11 +354,10 @@ public class SaveFileData extends HashMap<String,byte[]>
final long localSUID = localClassDescriptor.getSerialVersionUID();
final long streamSUID = resultClassDescriptor.getSerialVersionUID();
if (streamSUID != localSUID) { // check for serialVersionUID mismatch.
final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");
s.append("local serialVersionUID = ").append(localSUID);
s.append(" stream serialVersionUID = ").append(streamSUID);
String s = "Overriding serialized class version mismatch: " + "local serialVersionUID = " + localSUID +
" stream serialVersionUID = " + streamSUID;
System.err.println("[Invalid Class Exception]\n"+s);
System.err.println("[Invalid Class Exception]\n"+ s);
resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
}
}

View File

@@ -31,6 +31,8 @@ public class TemplateTmxMapLoader extends TmxMapLoader {
this.root = xml.parse(tmxFile);
parameter.generateMipMaps=true;
parameter.textureMinFilter = Texture.TextureFilter.Nearest;
parameter.textureMagFilter = Texture.TextureFilter.Nearest;
final Array<FileHandle> textureFiles = getDependencyFileHandles(tmxFile);
for (FileHandle textureFile : textureFiles) {
Texture texture = new Texture(textureFile, parameter.generateMipMaps);

View File

@@ -23,13 +23,10 @@ public class NavigationMap {
this.half = spriteSize / 2;
}
RayCastCallback callback = new RayCastCallback() {
@Override
public float reportRayFixture(Fixture fixture, Vector2 vector2, Vector2 vector21, float v) {
RayCastCallback callback = (fixture, vector2, vector21, v) -> {
if (v < 1.0)
rayCollided = true;
return 0;
}
};
// public void initializeOverworldGeometryGraph() {

View File

@@ -20,7 +20,7 @@ import java.util.ArrayList;
public class BiomeTexture implements Serializable {
private final BiomeData data;
private final int tileSize;
public static Pixmap emptyPixmap = null;
public Pixmap emptyPixmap = null;
ArrayList<ArrayList<Pixmap>> images = new ArrayList<>();
ArrayList<ArrayList<Pixmap>> smallImages = new ArrayList<>();
ArrayList<IntMap<Pixmap>> edgeImages = new ArrayList<>();

View File

@@ -25,6 +25,7 @@ public enum AbilityEffect {
if (soundClip == null) {
soundClip = AudioClip.createClip(ForgeConstants.EFFECTS_DIR + wav);
}
if (soundClip != null)
soundClip.play(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_SOUNDS)/100f);
animation.start();
}

View File

@@ -75,11 +75,21 @@
"name": "Settings",
"text": "tr(lblSettings)",
"selectable": true,
"width": 160,
"width": 80,
"height": 30,
"x": 160,
"y": 180
},
{
"type": "TextButton",
"name": "Backup",
"text": "tr(lblData)",
"selectable": true,
"width": 80,
"height": 30,
"x": 240,
"y": 180
},
{
"type": "TextButton",
"name": "Exit",

View File

@@ -64,11 +64,21 @@
"name": "Settings",
"text": "tr(lblSettings)",
"selectable": true,
"width": 238,
"width": 118,
"height": 48,
"x": 16,
"yOffset": 8
},
{
"type": "TextButton",
"name": "Backup",
"text": "tr(lblData)",
"selectable": true,
"width": 118,
"height": 48,
"x": 134,
"yOffset": -48
},
{
"type": "TextButton",
"name": "Switch",

View File

@@ -361,6 +361,14 @@ lblAutoYields=Automatische Bestätigung
lblDeckList=Deckliste
lblClose=Schließen
lblExitForge=Forge verlassen
lblLoadingWorld=Welt wird geladen...
lblGeneratingWorld=Welt erzeugen...
lblGameNotSaved=!!SPIEL NICHT GESPEICHERT!!\nManuelles Speichern ist nur auf der Weltkarte verfügbar
lblBackup=Sicherung
lblRestore=Wiederherstellen
lblData=Daten
lblSaveLocation=Sicherer Ort:
lblDoYouWantToRestoreBackup=Durch das Wiederherstellen des Backups werden alle Ihre Speicherungen überschrieben. Möchtest du fortfahren?
#ConstructedGameMenu.java
lblSelectAvatarFor=Wähle Avatar für %s
lblRemoveSmallCreatures=Entferne 1/1- und 0/X-Kreaturen aus erzeugten Decks

View File

@@ -363,6 +363,14 @@ lblAutoYields=Auto-Yields
lblDeckList=Deck List
lblClose=Close
lblExitForge=Exit Forge
lblLoadingWorld=Loading World...
lblGeneratingWorld=Generating World...
lblGameNotSaved=!!GAME NOT SAVED!!\nManual saving is only available on the world map
lblBackup=Backup
lblRestore=Restore
lblData=Data
lblSaveLocation=Save Location:
lblDoYouWantToRestoreBackup=Restoring backup will overwrite all of your save. Do you want to continue?
#ConstructedGameMenu.java
lblSelectAvatarFor=Select avatar for %s
lblRemoveSmallCreatures=Remove 1/1 and 0/X creatures in generated decks.

View File

@@ -361,6 +361,14 @@ lblAutoYields=Auto-ceder
lblDeckList=Lista del mazo
lblClose=Cerrar
lblExitForge=Salir de Forge
lblLoadingWorld=Cargando mundo...
lblGeneratingWorld=Generando mundo...
lblGameNotSaved=!!JUEGO NO GUARDADO!!\nEl guardado manual solo está disponible en el mapa mundial
lblBackup=Respaldo
lblRestore=Restaurar
lblData=Datos
lblSaveLocation=Guardar dirección:
lblDoYouWantToRestoreBackup=Restaurar la copia de seguridad sobrescribirá todo lo que guardó. ¿Quieres continuar?
#ConstructedGameMenu.java
lblSelectAvatarFor=Seleccionar avatar para %s
lblRemoveSmallCreatures=Elimina 1/1 y 0 /X criaturas en los mazos generados.

View File

@@ -361,6 +361,14 @@ lblAutoYields=Rendements automatiques
lblDeckList=Liste des decks
lblClose=Fermer
lblExitForge=Quitter Forge
lblLoadingWorld=Chargement du monde...
lblGeneratingWorld=Générer le monde...
lblGameNotSaved=!!JEU NON ENREGISTRÉ !!\nLa sauvegarde manuelle n'est disponible que sur la carte du monde
lblBackup=Sauvegarde
lblRestore=Restaurer
lblData=Données
lblSaveLocation=Enregistrer l'emplacement:
lblDoYouWantToRestoreBackup=La restauration de la sauvegarde écrasera toute votre sauvegarde. Voulez-vous continuer?
#ConstructedGameMenu.java
lblSelectAvatarFor=Sélectionner un avatar pour %s
lblRemoveSmallCreatures=Retire les créatures 1/1 et 0/X dans les decks générés.

View File

@@ -360,6 +360,14 @@ lblAutoYields=Consensi automatici
lblDeckList=Lista del mazzo
lblClose=Chiudi
lblExitForge=Esci da Forge
lblLoadingWorld=Caricamento del mondo...
lblGeneratingWorld=Generazione del mondo...
lblGameNotSaved=!!GIOCO NON SALVATO!!\nIl salvataggio manuale è disponibile solo sulla mappa del mondo
lblBackup=Backup
lblRestore=Ristabilire
lblData=Dati
lblSaveLocation=Salva l'indirizzo:
lblDoYouWantToRestoreBackup=Il ripristino del backup sovrascriverà tutti i tuoi salvataggi. Vuoi continuare?
#ConstructedGameMenu.java
lblSelectAvatarFor=Seleziona avatar per %s
lblRemoveSmallCreatures=Rimuovi le creature 1/1 e 0 / X nei mazzi generati.

View File

@@ -361,6 +361,14 @@ lblAutoYields=優先権の自動放棄
lblDeckList=デッキリスト
lblClose=閉じる
lblExitForge=Forge を終了します
lblLoadingWorld=世界を読み込んでいます...
lblGeneratingWorld=ワールドを生成中...
lblGameNotSaved=!!ゲームは保存されていません!!\n手動保存はワールドマップでのみ使用できます
lblBackup=バックアップ
lblRestore=復元する
lblData=データ
lblSaveLocation=位置を保存:
lblDoYouWantToRestoreBackup=バックアップを復元すると、保存内容がすべて上書きされます。続けたいですか?
#ConstructedGameMenu.java
lblSelectAvatarFor=%sアバターのデッキを選択
lblRemoveSmallCreatures=生成されたデッキに 1/1 および 0/X クリーチャーを含まない。

View File

@@ -373,6 +373,14 @@ lblAutoYields=Resolver automático
lblDeckList=Lista de Deck
lblClose=Fechar
lblExitForge=Sair da Forge
lblLoadingWorld=Carregando mundo...
lblGeneratingWorld=Gerando mundo...
lblGameNotSaved=!!JOGO NÃO SALVO!!\nO salvamento manual só está disponível no mapa mundial
lblBackup=Cópia de segurança
lblRestore=Restaurar
lblData=Dados
lblSaveLocation=Salvar localização:
lblDoYouWantToRestoreBackup=A restauração do backup substituirá todos os seus dados salvos. Você quer continuar?
#ConstructedGameMenu.java
lblSelectAvatarFor=Escolha o avatar para %s
lblRemoveSmallCreatures=Remover criaturas 1/1 e 0/X dos decks gerados.

View File

@@ -361,6 +361,14 @@ lblAutoYields=自动让过
lblDeckList=套牌列表
lblClose=关闭
lblExitForge=退出Forge
lblLoadingWorld=正在加载世界...
lblGeneratingWorld=生成世界...
lblGameNotSaved=!!游戏未保存!!\n手动保存仅在世界地图上可用
lblBackup=备份
lblRestore=恢复
lblData=数据
lblSaveLocation=保存位置:
lblDoYouWantToRestoreBackup=恢复备份将覆盖您的所有保存。你想继续吗?
#ConstructedGameMenu.java
lblSelectAvatarFor=为%s选择头像
lblRemoveSmallCreatures=将1/1和0/X生物从生成套牌中移除。

View File

@@ -128,7 +128,7 @@ public abstract class Achievement {
return earnedSpecial() || earnedMythic() || earnedRare() || earnedUncommon() || earnedCommon();
}
private void updateTrophyImage() {
public void updateTrophyImage() {
FSkinProp background;
float opacity = 1;
if (earnedSpecial()) {

View File

@@ -0,0 +1,99 @@
package forge.util;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/*
* https://www.baeldung.com/java-compress-and-uncompress
*/
public class ZipUtil {
public static String backupAdvFile = "forge.adv";
public static void zip(File source, File dest, String name) throws IOException {
FileOutputStream fos = new FileOutputStream(dest.getAbsolutePath() + File.separator + name);
ZipOutputStream zipOut = new ZipOutputStream(fos);
zipFile(source, source.getName(), zipOut);
zipOut.close();
fos.close();
}
private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
if (fileToZip.isHidden()) {
return;
}
if (fileToZip.isDirectory()) {
if (fileName.endsWith("/")) {
zipOut.putNextEntry(new ZipEntry(fileName));
zipOut.closeEntry();
} else {
zipOut.putNextEntry(new ZipEntry(fileName + "/"));
zipOut.closeEntry();
}
File[] children = fileToZip.listFiles();
if (children != null) {
for (File childFile : children) {
zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
}
}
return;
}
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
public static String unzip(File fileZip, File destDir) throws IOException {
StringBuilder val = new StringBuilder();
byte[] buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(destDir, zipEntry);
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
// fix for Windows-created archives
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}
// write file content
val.append(" * "). append(newFile.getName()).append("\n");
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
return val.toString();
}
private static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());
String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();
if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return destFile;
}
}