Merge remote-tracking branch 'upstream/master'

This commit is contained in:
CCTV-1
2020-04-04 16:47:07 +08:00
51 changed files with 316 additions and 127 deletions

View File

@@ -984,7 +984,7 @@ public class GameAction {
for (final Card c : game.getCardsIn(ZoneType.Battlefield)) { for (final Card c : game.getCardsIn(ZoneType.Battlefield)) {
if (c.isCreature()) { if (c.isCreature()) {
// Rule 704.5f - Put into grave (no regeneration) for toughness <= 0 // Rule 704.5f - Put into grave (no regeneration) for toughness <= 0
if (c.getNetToughness() <= 0) { if (c.getLethal() <= 0) {
if (noRegCreats == null) { if (noRegCreats == null) {
noRegCreats = new CardCollection(); noRegCreats = new CardCollection();
} }
@@ -992,7 +992,7 @@ public class GameAction {
checkAgain = true; checkAgain = true;
} else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) { } else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) {
for (final Integer dmg : c.getReceivedDamageFromThisTurn().values()) { for (final Integer dmg : c.getReceivedDamageFromThisTurn().values()) {
if (c.getNetToughness() <= dmg.intValue()) { if (c.getLethal() <= dmg.intValue()) {
if (desCreats == null) { if (desCreats == null) {
desCreats = new CardCollection(); desCreats = new CardCollection();
} }
@@ -1004,7 +1004,7 @@ public class GameAction {
} }
// Rule 704.5g - Destroy due to lethal damage // Rule 704.5g - Destroy due to lethal damage
// Rule 704.5h - Destroy due to deathtouch // Rule 704.5h - Destroy due to deathtouch
else if (c.getNetToughness() <= c.getDamage() || c.hasBeenDealtDeathtouchDamage()) { else if (c.getLethal() <= c.getDamage() || c.hasBeenDealtDeathtouchDamage()) {
if (desCreats == null) { if (desCreats == null) {
desCreats = new CardCollection(); desCreats = new CardCollection();
} }

View File

@@ -4731,9 +4731,21 @@ public class Card extends GameEntity implements Comparable<Card> {
return false; return false;
} }
// this is the amount of damage a creature needs to receive before it dies
public final int getLethal() {
if (getAmountOfKeyword("Lethal damage dealt to CARDNAME is determined by its power rather than its toughness.") % 2 !=0) {
return getNetPower(); }
else {
return getNetToughness(); }
}
// this is the minimal damage a trampling creature has to assign to a blocker // this is the minimal damage a trampling creature has to assign to a blocker
public final int getLethalDamage() { public final int getLethalDamage() {
return getNetToughness() - getDamage() - getTotalAssignedDamage(); if (getAmountOfKeyword("Lethal damage dealt to CARDNAME is determined by its power rather than its toughness.") % 2 !=0) {
return getNetPower() - getDamage() - getTotalAssignedDamage();
}
else {
return getNetToughness() - getDamage() - getTotalAssignedDamage();}
} }
public final int getDamage() { public final int getDamage() {

View File

@@ -7,6 +7,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="19" android:minSdkVersion="19"
android:targetSdkVersion="26" /> android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ -->
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>

Binary file not shown.

View File

@@ -105,22 +105,11 @@
<version>1.9.10</version> <version>1.9.10</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.cache2k</groupId> <groupId>com.android.support</groupId>
<artifactId>cache2k-base-bom</artifactId> <artifactId>support-v4</artifactId>
<version>1.2.4.Final</version> <version>23.1.1</version>
<type>pom</type> <scope>system</scope>
</dependency> <systemPath>${pom.basedir}/libs/android-support-v4.jar</systemPath>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -29,20 +29,8 @@
-dontwarn javax.** -dontwarn javax.**
-dontwarn org.apache.logging.log4j.** -dontwarn org.apache.logging.log4j.**
-dontwarn module-info -dontwarn module-info
## Support library
# mandatory proguard rules for cache2k to keep the core implementation -dontwarn android.support.**
-dontwarn org.cache2k.impl.xmlConfiguration.**
-dontwarn org.cache2k.impl.serverSide.**
-keep interface org.cache2k.spi.Cache2kCoreProvider
-keep public class * extends org.cache2k.spi.Cache2kCoreProvider
# optional proguard rules for cache2k, to keep XML configuration code
# if only programmatic configuration is used, these rules may be ommitted
-keep interface org.cache2k.core.spi.CacheConfigurationProvider
-keep public class * extends org.cache2k.core.spi.CacheConfigurationProvider
-keepclassmembers public class * extends org.cache2k.configuration.ConfigurationBean {
public void set*(...);
public ** get*();
}
-keep class forge.** { *; } -keep class forge.** { *; }
-keep class com.thoughtworks.xstream.** { *; } -keep class com.thoughtworks.xstream.** { *; }

View File

@@ -1,16 +1,22 @@
package forge.app; package forge.app;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
@@ -18,8 +24,18 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.PowerManager; import android.os.PowerManager;
import android.provider.Settings;
import android.support.v4.content.ContextCompat;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication; import com.badlogic.gdx.backends.android.AndroidApplication;
import forge.Forge; import forge.Forge;
@@ -35,13 +51,136 @@ import java.io.OutputStream;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class Main extends AndroidApplication { public class Main extends AndroidApplication {
AndroidAdapter Gadapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
AndroidAdapter adapter = new AndroidAdapter(this.getContext()); boolean permissiongranted = checkPermission();
Gadapter = new AndroidAdapter(this.getContext());
initForge(Gadapter, permissiongranted);
//permission
if(!permissiongranted){
//requestPermission();
displayMessage(Gadapter);
}
}
private void displayMessage(AndroidAdapter adapter){
TableLayout TL = new TableLayout(this);
TableRow row = new TableRow(this);
TableRow row2 = new TableRow(this);
TextView text = new TextView(this);
text.setGravity(Gravity.LEFT);
text.setTypeface(Typeface.SERIF);
String title="Forge needs Storage Permission to run properly...\n" +
"Follow this simple steps below:\n\n";
String steps = " 1) Tap \"Open App Details\" Button.\n" +
" 2) Tap Permissions\n"+
" 3) Turn on the Storage Permission.\n\n"+
"(You can tap anywhere to exit and restart the app)\n\n";
SpannableString ss1= new SpannableString(title);
ss1.setSpan(new StyleSpan(Typeface.BOLD), 0, ss1.length(), 0);
text.append(ss1);
text.append(steps);
row.addView(text);
row.setGravity(Gravity.CENTER);
int[] colors = {Color.TRANSPARENT,Color.TRANSPARENT};
int[] pressed = {Color.GREEN,Color.GREEN};
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, colors);
gd.setStroke(3, Color.DKGRAY);
gd.setCornerRadius(100);
GradientDrawable gd2 = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM, pressed);
gd2.setStroke(3, Color.DKGRAY);
gd2.setCornerRadius(100);
Button button = new Button(this);
button.setText("Open App Details");
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed}, gd2);
states.addState(new int[] { }, gd);
button.setBackground(states);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
});
row2.addView(button);
row2.setGravity(Gravity.CENTER);
TL.addView(row, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.addView(row2, new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
TL.setGravity(Gravity.CENTER);
TL.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.exit();
}
});
setContentView(TL);
}
@Override
public void onBackPressed() {
if (Gadapter!=null)
Gadapter.exit();
super.onBackPressed();
}
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
private void requestPermission() {
//Show Information about why you need the permission
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Storage Permission Denied...");
builder.setMessage("This app needs storage permission to run properly.\n\n\n\n");
builder.setPositiveButton("Open App Details", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
//ActivityCompat crashes... maybe it needs the appcompat v7???
//ActivityCompat.requestPermissions(Main.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
});
/*builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
}
});*/
builder.show();
}
private void initForge(AndroidAdapter adapter, boolean permissiongranted){
//establish assets directory //establish assets directory
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
Gdx.app.error("Forge", "Can't access external storage"); Gdx.app.error("Forge", "Can't access external storage");
@@ -65,15 +204,22 @@ public class Main extends AndroidApplication {
//enforce orientation based on whether device is a tablet and user preference //enforce orientation based on whether device is a tablet and user preference
adapter.switchOrientationFile = assetsDir + "switch_orientation.ini"; adapter.switchOrientationFile = assetsDir + "switch_orientation.ini";
boolean landscapeMode = adapter.isTablet == !FileUtil.doesFileExist(adapter.switchOrientationFile); boolean landscapeMode = adapter.isTablet == !FileUtil.doesFileExist(adapter.switchOrientationFile);
if (landscapeMode) { if (permissiongranted){
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); if (landscapeMode) {
} Main.this.setRequestedOrientation(Build.VERSION.SDK_INT >= 26 ?
else { ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : //Oreo and above has virtual back/menu buttons
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
} else {
//set current orientation
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
} }
boolean value = Build.VERSION.SDK_INT >= 26; ForgePreferences prefs = FModel.getPreferences();
initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir, value)); boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_USE_ELSA);
initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir, propertyConfig));
} }
/*@Override /*@Override

View File

@@ -40,6 +40,7 @@ import javax.swing.WindowConstants;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.GuiBase;
import forge.ImageCache; import forge.ImageCache;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.Singletons; import forge.Singletons;
@@ -219,6 +220,10 @@ public enum FControl implements KeyEventDispatcher {
final ForgePreferences prefs = FModel.getPreferences(); final ForgePreferences prefs = FModel.getPreferences();
//set ElsaSerializer from preference
boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_USE_ELSA);
GuiBase.enablePropertyConfig(propertyConfig);
closeAction = CloseAction.valueOf(prefs.getPref(FPref.UI_CLOSE_ACTION)); closeAction = CloseAction.valueOf(prefs.getPref(FPref.UI_CLOSE_ACTION));
final Localizer localizer = Localizer.getInstance(); final Localizer localizer = Localizer.getInstance();

View File

@@ -115,6 +115,7 @@ public enum CSubmenuPreferences implements ICDoc {
lstControls.add(Pair.of(view.getCbSingletons(), FPref.DECKGEN_SINGLETONS)); lstControls.add(Pair.of(view.getCbSingletons(), FPref.DECKGEN_SINGLETONS));
lstControls.add(Pair.of(view.getCbEnableAICheats(), FPref.UI_ENABLE_AI_CHEATS)); lstControls.add(Pair.of(view.getCbEnableAICheats(), FPref.UI_ENABLE_AI_CHEATS));
lstControls.add(Pair.of(view.getCbEnableUnknownCards(), FPref.UI_LOAD_UNKNOWN_CARDS)); lstControls.add(Pair.of(view.getCbEnableUnknownCards(), FPref.UI_LOAD_UNKNOWN_CARDS));
lstControls.add(Pair.of(view.getCbUseElsa(), FPref.UI_USE_ELSA));
lstControls.add(Pair.of(view.getCbImageFetcher(), FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER)); lstControls.add(Pair.of(view.getCbImageFetcher(), FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER));
lstControls.add(Pair.of(view.getCbDisplayFoil(), FPref.UI_OVERLAY_FOIL_EFFECT)); lstControls.add(Pair.of(view.getCbDisplayFoil(), FPref.UI_OVERLAY_FOIL_EFFECT));
lstControls.add(Pair.of(view.getCbRandomFoil(), FPref.UI_RANDOM_FOIL)); lstControls.add(Pair.of(view.getCbRandomFoil(), FPref.UI_RANDOM_FOIL));

View File

@@ -108,6 +108,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final JCheckBox cbRemindOnPriority = new OptionsCheckBox(localizer.getMessage("cbRemindOnPriority")); private final JCheckBox cbRemindOnPriority = new OptionsCheckBox(localizer.getMessage("cbRemindOnPriority"));
private final JCheckBox cbUseSentry = new OptionsCheckBox(localizer.getMessage("cbUseSentry")); private final JCheckBox cbUseSentry = new OptionsCheckBox(localizer.getMessage("cbUseSentry"));
private final JCheckBox cbEnableUnknownCards = new OptionsCheckBox(localizer.getMessage("lblEnableUnknownCards")); private final JCheckBox cbEnableUnknownCards = new OptionsCheckBox(localizer.getMessage("lblEnableUnknownCards"));
private final JCheckBox cbUseElsa = new OptionsCheckBox("Use ELSA Serializer");
private final Map<FPref, KeyboardShortcutField> shortcutFields = new HashMap<>(); private final Map<FPref, KeyboardShortcutField> shortcutFields = new HashMap<>();
@@ -291,6 +292,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbEnableUnknownCards, titleConstraints); pnlPrefs.add(cbEnableUnknownCards, titleConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableUnknownCards")), descriptionConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableUnknownCards")), descriptionConstraints);
/*pnlPrefs.add(cbUseElsa, titleConstraints);
pnlPrefs.add(new NoteLabel("Use ELSA Serializer for Network (EXPERIMENTAL Option, Requires restart)"), descriptionConstraints);*/
// Graphic Options // Graphic Options
pnlPrefs.add(new SectionLabel(localizer.getMessage("GraphicOptions")), sectionConstraints + ", gaptop 2%"); pnlPrefs.add(new SectionLabel(localizer.getMessage("GraphicOptions")), sectionConstraints + ", gaptop 2%");
@@ -589,6 +593,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbEnableUnknownCards; return cbEnableUnknownCards;
} }
/** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbUseElsa() {
return cbUseElsa;
}
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbImageFetcher() { public JCheckBox getCbImageFetcher() {
return cbImageFetcher; return cbImageFetcher;

View File

@@ -49,9 +49,6 @@ public final class Main {
//setup GUI interface //setup GUI interface
GuiBase.setInterface(new GuiDesktop()); GuiBase.setInterface(new GuiDesktop());
//set PropertyConfig log4j to true
GuiBase.enablePropertyConfig(true);
//install our error handler //install our error handler
ExceptionHandler.registerErrorHandling(); ExceptionHandler.registerErrorHandling();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -75,23 +75,5 @@
<artifactId>gdx-backend-robovm</artifactId> <artifactId>gdx-backend-robovm</artifactId>
<version>1.9.10</version> <version>1.9.10</version>
</dependency> </dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-base-bom</artifactId>
<version>1.2.4.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -8,6 +8,8 @@ import com.badlogic.gdx.backends.iosrobovm.IOSFiles;
import forge.Forge; import forge.Forge;
import forge.assets.AssetsDownloader; import forge.assets.AssetsDownloader;
import forge.interfaces.IDeviceAdapter; import forge.interfaces.IDeviceAdapter;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.util.FileUtil; import forge.util.FileUtil;
import org.robovm.apple.foundation.NSAutoreleasePool; import org.robovm.apple.foundation.NSAutoreleasePool;
import org.robovm.apple.uikit.UIApplication; import org.robovm.apple.uikit.UIApplication;
@@ -29,7 +31,9 @@ public class Main extends IOSApplication.Delegate {
final IOSApplicationConfiguration config = new IOSApplicationConfiguration(); final IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.useAccelerometer = false; config.useAccelerometer = false;
config.useCompass = false; config.useCompass = false;
final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir, false); ForgePreferences prefs = FModel.getPreferences();
boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_USE_ELSA);
final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir, propertyConfig);
final IOSApplication iosApp = new IOSApplication(app, config); final IOSApplication iosApp = new IOSApplication(app, config);
return iosApp; return iosApp;
} }

View File

@@ -80,23 +80,5 @@
<artifactId>commons-cli</artifactId> <artifactId>commons-cli</artifactId>
<version>1.4</version> <version>1.4</version>
</dependency> </dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-base-bom</artifactId>
<version>1.2.4.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -7,6 +7,8 @@ import com.badlogic.gdx.backends.lwjgl.LwjglClipboard;
import forge.Forge; import forge.Forge;
import forge.assets.AssetsDownloader; import forge.assets.AssetsDownloader;
import forge.interfaces.IDeviceAdapter; import forge.interfaces.IDeviceAdapter;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.OperatingSystem; import forge.util.OperatingSystem;
import forge.util.RestartUtil; import forge.util.RestartUtil;
@@ -92,8 +94,10 @@ public class Main {
config.title = "Forge"; config.title = "Forge";
config.useHDPI = desktopMode; // enable HiDPI on Mac OS config.useHDPI = desktopMode; // enable HiDPI on Mac OS
ForgePreferences prefs = FModel.getPreferences();
boolean propertyConfig = prefs != null && prefs.getPrefBoolean(ForgePreferences.FPref.UI_USE_ELSA);
new LwjglApplication(Forge.getApp(new LwjglClipboard(), new DesktopAdapter(switchOrientationFile), new LwjglApplication(Forge.getApp(new LwjglClipboard(), new DesktopAdapter(switchOrientationFile),
desktopMode ? desktopModeAssetsDir : assetsDir, true), config); desktopMode ? desktopModeAssetsDir : assetsDir, propertyConfig), config);
} }
private static class DesktopAdapter implements IDeviceAdapter { private static class DesktopAdapter implements IDeviceAdapter {

Binary file not shown.

View File

@@ -70,24 +70,6 @@
<artifactId>gdx-freetype</artifactId> <artifactId>gdx-freetype</artifactId>
<version>1.9.10</version> <version>1.9.10</version>
</dependency> </dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-base-bom</artifactId>
<version>1.2.4.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-api</artifactId>
<version>1.2.4.Final</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -22,6 +22,8 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import forge.ImageKeys; import forge.ImageKeys;
import forge.card.CardEdition; import forge.card.CardEdition;
import forge.game.card.CardView; import forge.game.card.CardView;
@@ -32,11 +34,11 @@ import forge.model.FModel;
import forge.properties.ForgeConstants; import forge.properties.ForgeConstants;
import forge.util.ImageUtil; import forge.util.ImageUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.cache2k.Cache;
import org.cache2k.Cache2kBuilder;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/** /**
* This class stores ALL card images in a cache with soft values. this means * This class stores ALL card images in a cache with soft values. this means
@@ -56,13 +58,10 @@ public class ImageCache {
// short prefixes to save memory // short prefixes to save memory
private static final Set<String> missingIconKeys = new HashSet<>(); private static final Set<String> missingIconKeys = new HashSet<>();
private static final Cache<String, Texture> cache = new Cache2kBuilder<String, Texture>() {} private static final LoadingCache<String, Texture> cache = CacheBuilder.newBuilder()
.name("cache") .maximumSize(400)
.eternal(true) .expireAfterAccess(15, TimeUnit.MINUTES)
.permitNullValues(true) .build(new ImageLoader());
.disableStatistics(true)
.loader(new ImageLoader())
.build();
public static final Texture defaultImage; public static final Texture defaultImage;
public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK; public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK;
public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE; public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE;
@@ -85,7 +84,7 @@ public class ImageCache {
} }
public static void clear() { public static void clear() {
cache.clear(); cache.invalidateAll();
missingIconKeys.clear(); missingIconKeys.clear();
} }
@@ -134,7 +133,7 @@ public class ImageCache {
Texture image; Texture image;
if (useDefaultIfNotFound) { if (useDefaultIfNotFound) {
// Load from file and add to cache if not found in cache initially. // Load from file and add to cache if not found in cache initially.
image = cache.get(imageKey); image = cache.getIfPresent(imageKey);
if (image != null) { return image; } if (image != null) { return image; }
@@ -165,7 +164,11 @@ public class ImageCache {
return image; return image;
} }
public static void preloadCache(Iterable<String> keys) { public static void preloadCache(Iterable<String> keys) {
cache.getAll(keys); try {
cache.getAll(keys);
} catch (ExecutionException e) {
e.printStackTrace();
}
} }
public static TextureRegion croppedBorderImage(Texture image, boolean fullborder) { public static TextureRegion croppedBorderImage(Texture image, boolean fullborder) {
if (!fullborder) if (!fullborder)

View File

@@ -8,8 +8,8 @@ import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData; import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.google.common.cache.CacheLoader;
import forge.FThreads; import forge.FThreads;
import org.cache2k.integration.CacheLoader;
import forge.Forge; import forge.Forge;
import forge.ImageKeys; import forge.ImageKeys;

View File

@@ -232,6 +232,14 @@ public class SettingsPage extends TabPage<SettingsScreen> {
localizer.getMessage("cbLoadHistoricFormats"), localizer.getMessage("cbLoadHistoricFormats"),
localizer.getMessage("nlLoadHistoricFormats")), localizer.getMessage("nlLoadHistoricFormats")),
3); 3);
lstSettings.addItem(new BooleanSetting(FPref.UI_LOAD_UNKNOWN_CARDS,
localizer.getMessage("lblEnableUnknownCards"),
localizer.getMessage("nlEnableUnknownCards")),
3);
/*lstSettings.addItem(new BooleanSetting(FPref.UI_USE_ELSA,
"Use ELSA Serializer",
"Use ELSA Serializer for Network (EXPERIMENTAL Option, Requires restart)"),
3);*/
//Graphic Options //Graphic Options
lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER, lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER,
@@ -331,10 +339,6 @@ public class SettingsPage extends TabPage<SettingsScreen> {
Forge.showFPS = FModel.getPreferences().getPrefBoolean(FPref.UI_SHOW_FPS); Forge.showFPS = FModel.getPreferences().getPrefBoolean(FPref.UI_SHOW_FPS);
} }
},4); },4);
lstSettings.addItem(new BooleanSetting(FPref.UI_LOAD_UNKNOWN_CARDS,
localizer.getMessage("lblEnableUnknownCards"),
localizer.getMessage("nlEnableUnknownCards")),
4);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE, lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE,
localizer.getMessage("cbpCounterDisplayType"), localizer.getMessage("cbpCounterDisplayType"),
localizer.getMessage("nlCounterDisplayType"), localizer.getMessage("nlCounterDisplayType"),

View File

@@ -54,7 +54,7 @@
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <artifactId>netty-all</artifactId>
<version>4.1.43.Final</version> <version>4.1.48.Final</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -0,0 +1,9 @@
Name:Colossification
ManaCost:5 G G
Types:Enchantment Aura
K:Enchant creature
A:SP$ Attach | Cost$ 5 G G | ValidTgts$ Creature | AILogic$ Pump
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTap | TriggerDescription$ When CARDNAME enters the battlefield, tap enchanted creature.
SVar:TrigTap:DB$ Tap | Defined$ Enchanted
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 20 | AddToughness$ 20 | Description$ Enchanted creature gets +20/+20.
Oracle:Enchant creature\nWhen Colossification enters the battlefield, tap enchanted creature.\nEnchanted creature gets +20/+20.

View File

@@ -0,0 +1,8 @@
Name:Drannith Stinger
ManaCost:1 R
Types:Creature Human Wizard
PT:2/2
T:Mode$ Cycled | ValidCard$ Card.Other+YouOwn | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever you cycle another card, CARDNAME deals 1 damage to each opponent.
SVar:TrigDamage:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 1
K:Cycling:1
Oracle:Whenever you cycle another card, Drannith Stinger deals 1 damage to each opponent.\nCycling {1} ({1}, Discard this card: Draw a card.)

View File

@@ -0,0 +1,5 @@
Name:Gloom Pangolin
ManaCost:2 B
Types:Creature Nightmare Pangolin
PT:1/5
Oracle:

View File

@@ -0,0 +1,11 @@
Name:Kogla, the Titan Ape
ManaCost:3 G G G
Types:Legendary Creature Ape
PT:7/6
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigFight | TriggerDescription$ When CARDNAME enters the battlefield, it fights up to one target creature you don't control.
SVar:TrigFight:DB$ Fight | Defined$ TriggeredCardLKICopy | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Choose target creature you don't control | TargetMin$ 0 | TargetMax$ 1
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME attacks, destroy target artifact or enchantment defending player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.DefenderCtrl,Enchantment.DefenderCtrl | TgtPrompt$ Select target artifact or enchantment defending player controls
A:AB$ ChangeZone | Cost$ 1 G | ValidTgts$ Human.YouCtrl | TgtPrompt$ Choose target Human you control | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBPump | SpellDescription$ Return target Human you control to its owner's hand. CARDNAME gains indestructible until end of turn.
SVar:DBPump:DB$ Pump | Defined$ Self | KW$ Indestructible
Oracle:When Kogla, the Titan Ape enters the battlefield, it fights up to one target creature you don't control.\nWhenever Kogla attacks, destroy target artifact or enchantment defending player controls.\n{1}{G}: Return target Human you control to its owner's hand. Kogla gains indestructible until end of turn.

View File

@@ -0,0 +1,10 @@
Name:Labyrinth Raptor
ManaCost:B R
Types:Creature Nightmare Dinosaur
PT:2/2
K:Menace
T:Mode$ AttackerBlocked | ValidCard$ Creature.YouCtrl+withMenace | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ Whenever a creature you control with menace becomes blocked, defending player sacrifices a creature blocking it.
SVar:TrigSac:DB$ Sacrifice | Defined$ DefendingPlayer | SacValid$ Creature.blockingSource | ChangeNum$ 1
A:AB$ PumpAll | Cost$ B R | ValidCards$ Creature.YouCtrl+withMenace | NumAtt$ 1 | SpellDescription$ Creatures you control with menace get +1/+0 until end of turn.
SVar:PlayMain1:TRUE
Oracle:Menace\nWhenever a creature you control with menace becomes blocked, defending player sacrifices a creature blocking it.\n{B}{R}: Creatures you control with menace get +1/+0 until end of turn.

View File

@@ -0,0 +1,6 @@
Name:Mosscoat Goriak
ManaCost:2 G
Types:Creature Beast
PT:2/4
K:Vigilance
Oracle:Vigilance

View File

@@ -0,0 +1,13 @@
Name:Primal Empathy
ManaCost:1 G U
Types:Enchantment
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ At the beginning of your upkeep, draw a card if you control a creature with the greatest power among creatures on the battlefield. Otherwise, put a +1/+1 counter on a creature you control.
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 | ConditionPresent$ Creature | ConditionCompare$ GE1 | ConditionPresent$ Creature | ConditionCompare$ GE1 | ConditionCheckSVar$ Z | ConditionSVarCompare$ GEY | References$ Y,Z | RememberDrawn$ True | SubAbility$ DBChoose
SVar:DBChoose:DB$ ChooseCard | Defined$ You | Choices$ Creature.YouCtrl | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | References$ X | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$ PutCounter | Defined$ ChosenCard | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True
SVar:X:Count$RememberedSize
SVar:Y:Count$GreatestPower_Creature.YouDontCtrl
SVar:Z:Count$GreatestPower_Creature.YouCtrl
DeckHas:Ability$Counters
Oracle:At the beginning of your upkeep, draw a card if you control a creature with the greatest power among creatures on the battlefield. Otherwise, put a +1/+1 counter on a creature you control.

View File

@@ -0,0 +1,10 @@
Name:Sprite Dragon
ManaCost:U R
Types:Creature Faerie Dragon
PT:1/1
K:Flying
K:Haste
T:Mode$ SpellCast | ValidCard$ Card.nonCreature | ValidActivatingPlayer$ You | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a noncreature spell, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
SVar:BuffedBy:nonCreature
Oracle:Flying, haste\nWhenever you cast a noncreature spell, put a +1/+1 counter on Sprite Dragon.

View File

@@ -0,0 +1,7 @@
Name:Zilortha, Strength Incarnate
ManaCost:3 R G
Types:Legendary Creature Dinosaur
K:Trample
PT:7/3
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddHiddenKeyword$ Lethal damage dealt to CARDNAME is determined by its power rather than its toughness. | Description$ Lethal damage dealt to creatures you control is determined by their power rather than their toughness.
Oracle:Trample\nLethal damage dealt to creatures you control is determined by their power rather than their toughness.

View File

@@ -1,7 +1,5 @@
package forge.net.client; package forge.net.client;
import forge.net.CustomObjectDecoder;
import forge.net.CustomObjectEncoder;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@@ -28,6 +26,8 @@ import forge.net.event.IdentifiableNetEvent;
import forge.net.event.LobbyUpdateEvent; import forge.net.event.LobbyUpdateEvent;
import forge.net.event.MessageEvent; import forge.net.event.MessageEvent;
import forge.net.event.NetEvent; import forge.net.event.NetEvent;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
public class FGameClient implements IToServer { public class FGameClient implements IToServer {
@@ -58,8 +58,8 @@ public class FGameClient implements IToServer {
public void initChannel(final SocketChannel ch) throws Exception { public void initChannel(final SocketChannel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline(); final ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast( pipeline.addLast(
new CustomObjectEncoder(), new ObjectEncoder(),
new CustomObjectDecoder(CustomObjectDecoder.maxObjectsize, ClassResolvers.cacheDisabled(null)), new ObjectDecoder(9766*1024, ClassResolvers.cacheDisabled(null)),
new MessageHandler(), new MessageHandler(),
new LobbyUpdateHandler(), new LobbyUpdateHandler(),
new GameClientHandler(FGameClient.this)); new GameClientHandler(FGameClient.this));

View File

@@ -6,8 +6,6 @@ import forge.interfaces.IGuiGame;
import forge.interfaces.ILobbyListener; import forge.interfaces.ILobbyListener;
import forge.match.LobbySlot; import forge.match.LobbySlot;
import forge.match.LobbySlotType; import forge.match.LobbySlotType;
import forge.net.CustomObjectDecoder;
import forge.net.CustomObjectEncoder;
import forge.net.event.LobbyUpdateEvent; import forge.net.event.LobbyUpdateEvent;
import forge.net.event.LoginEvent; import forge.net.event.LoginEvent;
import forge.net.event.LogoutEvent; import forge.net.event.LogoutEvent;
@@ -26,6 +24,8 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; import io.netty.handler.logging.LoggingHandler;
@@ -99,8 +99,8 @@ public final class FServerManager {
public final void initChannel(final SocketChannel ch) throws Exception { public final void initChannel(final SocketChannel ch) throws Exception {
final ChannelPipeline p = ch.pipeline(); final ChannelPipeline p = ch.pipeline();
p.addLast( p.addLast(
new CustomObjectEncoder(), new ObjectEncoder(),
new CustomObjectDecoder(CustomObjectDecoder.maxObjectsize, ClassResolvers.cacheDisabled(null)), new ObjectDecoder(9766*1024, ClassResolvers.cacheDisabled(null)),
new MessageHandler(), new MessageHandler(),
new RegisterClientHandler(), new RegisterClientHandler(),
new LobbyInputHandler(), new LobbyInputHandler(),

View File

@@ -139,6 +139,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_ENABLE_PRELOAD_EXTENDED_ART("false"), UI_ENABLE_PRELOAD_EXTENDED_ART("false"),
UI_ENABLE_BORDER_MASKING("false"), UI_ENABLE_BORDER_MASKING("false"),
UI_SHOW_FPS("false"), UI_SHOW_FPS("false"),
UI_USE_ELSA("false"),
UI_LOAD_UNKNOWN_CARDS("true"), UI_LOAD_UNKNOWN_CARDS("true"),
UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"),
UI_DEFAULT_FONT_SIZE("12"), UI_DEFAULT_FONT_SIZE("12"),