Compare commits

..

52 Commits

Author SHA1 Message Date
Nut.andor
32c3fe063e fix diamond 2022-10-19 20:58:36 +02:00
Nut.andor
cbe6678ed6 compress 2022-10-18 00:11:32 +02:00
Nut.andor
63bc7c3a4e whatsnew and translation status 2022-10-17 23:44:05 +02:00
Nut.andor
9310d53362 potc 2022-10-17 23:15:48 +02:00
Nut.andor
a71dcc13a3 content 0.8.2 2022-10-17 23:06:34 +02:00
Nut.andor
ea95f4ff87 actual translations generated 2022-10-17 22:33:03 +02:00
Nut.andor
f35167d112 Merge remote-tracking branch 'hosted.weblate/master' 2022-10-17 22:27:58 +02:00
Daniel Stasiak
9f935190f2 Translated using Weblate (Polish)
Currently translated at 92.5% (13884 of 14995 strings)
2022-10-16 00:53:44 +02:00
Nut.andor
c11430cf6b beta icon and fileprovider 2022-10-15 22:46:16 +02:00
Daniel Stasiak
8f97a27ab7 Translated using Weblate (Polish)
Currently translated at 92.5% (13884 of 14995 strings)
2022-10-13 15:56:19 +02:00
Anupam Malhotra
9e36f848dc Translated using Weblate (Hindi)
Currently translated at 0.1% (4 of 14994 strings)
2022-10-12 08:50:37 +02:00
ilya
b24d52b1da Translated using Weblate (Russian)
Currently translated at 100.0% (14995 of 14995 strings)
2022-10-12 08:50:34 +02:00
Daniel Stasiak
e2a9307560 Translated using Weblate (Polish)
Currently translated at 92.5% (13884 of 14995 strings)
2022-10-12 08:50:31 +02:00
Nut.andor
e3ac804f61 Merge branch 'pulls/1829009049/47' 2022-10-11 19:20:06 +02:00
Nut.andor
fd504d2df5 Automated copying of files for build as gradle task 2022-10-11 18:58:05 +02:00
OMGeeky
0e615d3f11 Revert accidental wrong branch stuff 2022-10-11 18:31:01 +02:00
Nut.andor
47646457ab (Pull Request #46:) Fixed problems with older Android versions (below Android 7) 2022-10-11 00:00:00 +02:00
OMGeeky
8e393b93d8 Changed lint.xml to include StringFormatMatches and StringFormatInvalid 2022-10-10 15:43:34 +02:00
OMGeeky
3289bd6fb1 Configured lint-baseline file (for automatic builds on github) 2022-10-10 15:32:21 +02:00
OMGeeky
23a331d655 Merge remote-tracking branch 'origin/fix-older-android-versions' into gradle_copy_v1 2022-10-10 15:09:01 +02:00
OMGeeky
112301c444 Create build Action
(cherry picked from commit 462b6059218b1bdc1efa582ea2463d5eb3af1c22)
2022-10-10 15:05:01 +02:00
OMGeeky
f50e4f1d38 Migrate to AndroidX 2022-10-10 14:54:08 +02:00
OMGeeky
d623c22b38 Removed ignored files 2022-10-10 14:45:01 +02:00
OMGeeky
d11bf5b0aa Automated copying of files for build as gradle task 2022-10-10 09:22:18 +02:00
Nut.andor
e30f67e327 fix Master Ale bug 2022-10-09 02:43:01 +02:00
OMGeeky
6946b1f2b3 Fixed problems with older Android versions (below Android 7) 2022-10-09 02:00:52 +02:00
Nut Andor
96a1a5760a Translated using Weblate (German)
Currently translated at 94.0% (14096 of 14995 strings)
2022-10-09 01:15:46 +02:00
Nut.andor
58b802e911 whatsnew 2022-10-08 03:41:50 +02:00
Nut.andor
f9b095565b languages 2022-10-08 03:22:32 +02:00
Nut.andor
19817eb97d Merge branch 'v0.8.2' 2022-10-08 02:58:18 +02:00
Nut.andor
f46d2aedbf content v082 (Sullengard fixes) 2022-10-08 02:56:10 +02:00
Nut.andor
913b651953 Merge remote-tracking branch 'hosted.weblate/master' into v0.8.2 2022-10-08 01:04:59 +02:00
Nut Andor
5283eed28e Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (15016 of 15016 strings)
2022-10-08 01:04:14 +02:00
Nut Andor
deb824d50e Translated using Weblate (German)
Currently translated at 93.8% (14095 of 15016 strings)
2022-10-08 01:04:12 +02:00
Nut.andor
6841d862e4 Merge remote-tracking branch 'hosted.weblate/master' into v0.8.2 2022-10-08 00:43:26 +02:00
saoloer
f94723b0cd Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (15016 of 15016 strings)
2022-10-07 18:18:35 +02:00
Jr
ab41168736 Translated using Weblate (German)
Currently translated at 93.8% (14095 of 15016 strings)
2022-10-07 18:18:33 +02:00
Jr
2d73c4687a Translated using Weblate (German)
Currently translated at 100.0% (582 of 582 strings)
2022-10-07 18:18:30 +02:00
aircqsj
e454deb8b1 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.9% (15015 of 15016 strings)
2022-10-05 20:56:26 +02:00
Lucas Araujo
074891805a Translated using Weblate (Portuguese (Brazil))
Currently translated at 92.7% (13928 of 15016 strings)
2022-10-05 20:56:21 +02:00
Daniel Stasiak
d2d32bc4ed Translated using Weblate (Polish)
Currently translated at 92.4% (13884 of 15016 strings)
2022-10-05 20:56:20 +02:00
Daniel Stasiak
22daeb0c33 Translated using Weblate (Polish)
Currently translated at 100.0% (582 of 582 strings)
2022-10-05 20:56:17 +02:00
Nut.andor
db30253baf v0.8.2 66 2022-10-03 00:47:11 +02:00
Nut.andor
312cb7dec7 ignore workspace.xml 2022-10-03 00:44:00 +02:00
Nut.andor
7befd27951 whatsnew release version 2022-10-02 21:05:38 +02:00
aircqsj
c1e3bfa7ed Translated using Weblate (Chinese (Simplified))
Currently translated at 94.0% (14128 of 15016 strings)
2022-10-02 07:56:33 +02:00
ilya
ddec991082 Translated using Weblate (Russian)
Currently translated at 100.0% (15016 of 15016 strings)
2022-10-02 07:56:02 +02:00
ilya
25e36dc535 Translated using Weblate (Russian)
Currently translated at 100.0% (15016 of 15016 strings)
2022-09-30 18:31:04 +02:00
Jiri Zizkin Zizka
83c579a929 Translated using Weblate (Czech)
Currently translated at 100.0% (582 of 582 strings)
2022-09-29 23:16:22 +02:00
Jiri Zizkin Zizka
0c694115ee Translated using Weblate (Czech)
Currently translated at 92.7% (13932 of 15016 strings)
2022-09-29 23:16:22 +02:00
ilya
bf9723b0c1 Translated using Weblate (Russian)
Currently translated at 96.2% (14449 of 15016 strings)
2022-09-29 23:16:20 +02:00
ilya
b81bacb1fe Translated using Weblate (Russian)
Currently translated at 100.0% (582 of 582 strings)
2022-09-29 23:16:17 +02:00
2034 changed files with 92385 additions and 3369048 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/AndorsTrail/.idea/workspace.xml

View File

@@ -1,166 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="NONE" />
</component>
<component name="ChangeListManager">
<list default="true" id="fb7bf33b-30cf-40b9-a238-3e2f6f604a8f" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[C:\Users\chris\.android\avd\Nexus_5_API_30.avd]" />
<component name="ExternalProjectsData">
<projectState path="$PROJECT_DIR$">
<ProjectState />
</projectState>
</component>
<component name="ExternalProjectsManager">
<system id="GRADLE">
<state>
<projects_view>
<tree_state>
<expand>
<path>
<item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
<item name="AndorsTrail" type="f1a62948:ProjectNode" />
</path>
</expand>
<select />
</tree_state>
</projects_view>
</state>
</system>
</component>
<component name="GenerateSignedApkSettings">
<option name="KEY_STORE_PATH" value="C:\AT\sec\AndorsTrail.keystore" />
<option name="KEY_ALIAS" value="andorstrail" />
<option name="REMEMBER_PASSWORDS" value="true" />
<option name="BUILD_TARGET_KEY" value="apk" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="ProjectId" id="2FG0LqADbxm6Q1t3yQ9BlX5APzJ" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="ApkExportedModule" value="AndorsTrail.app" />
<property name="ExportApk.ApkPath" value="C:\AT\AndorsTrailRelease\andors-trail\AndorsTrail\app" />
<property name="ExportApk.BuildVariants" value="release" />
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="RunOnceActivity.cidr.known.project.marker" value="true" />
<property name="android.sdk.path" value="$USER_HOME$/AppData/Local/Android/Sdk" />
<property name="cidr.known.project.marker" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../../../sec/AndorsTrail.keystore" />
<property name="settings.editor.selected.configurable" value="device.file.explorer" />
<property name="show.inlinked.gradle.project.popup" value="false" />
</component>
<component name="RunManager">
<configuration name="&lt;template&gt;" type="Applet" default="true" selected="false">
<option name="MAIN_CLASS_NAME" />
<option name="HTML_FILE_NAME" />
<option name="HTML_USED" value="false" />
<option name="WIDTH" value="400" />
<option name="HEIGHT" value="300" />
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
<option name="VM_PARAMETERS" />
</configuration>
<configuration name="&lt;template&gt;" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" default="true" selected="false">
<option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
</configuration>
<configuration name="app" type="AndroidRunConfigurationType" factoryName="Android App">
<module name="AndorsTrail.app" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="DEPLOY_AS_INSTANT" value="false" />
<option name="ARTIFACT_NAME" value="" />
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="ALL_USERS" value="false" />
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
<option name="DEBUGGER_TYPE" value="Auto" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Hybrid>
<Java />
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Java/Kotlin Method Sample (legacy)" />
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY_CLASS" value="" />
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
<method v="2" />
</configuration>
<configuration default="true" type="Application" factoryName="Application">
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="JUnit" factoryName="JUnit">
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="TestNG">
<option name="TEST_OBJECT" value="CLASS" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<properties />
<listeners />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="fb7bf33b-30cf-40b9-a238-3e2f6f604a8f" name="Changes" comment="" />
<created>1664103080085</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1664103080085</updated>
</task>
<servers />
</component>
</project>

View File

@@ -12,12 +12,41 @@ android {
buildTypes {
release {
manifestPlaceholders icon_name: 'icon', fileproviderPath: 'AndorsTrail'
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
manifestPlaceholders icon_name: 'icon_beta', fileproviderPath: 'AndorsTrail.beta2'
applicationIdSuffix 'beta2'
}
}
}
dependencies {
implementation 'com.android.support:support-v4:28.0.0'
}
task copyRes(type: Copy) {
description "Copies the res folder to the modules res folder (& renames .tmx to .xml)"
from "${rootDir}/res"
into "${projectDir}/src/main/res"
rename "(.*)\\.tmx", "\$1.xml"
}
task copyTranslation(type: Copy) {
description("Copies the translation files to the modules translations folder")
from "${rootDir}/assets/translation"
into "${projectDir}/src/main/assets/translation"
}
task cleanup(type: Delete) {
description("Deletes the assets/translation and the res folder from the modules folder")
delete "${projectDir}/src/main/res", "${projectDir}/src/main/assets/translation"
}
afterEvaluate {
preBuild.dependsOn project.tasks.copyRes
preBuild.dependsOn project.tasks.copyTranslation
clean.dependsOn project.tasks.cleanup
}

View File

@@ -25,9 +25,9 @@
<application
android:name=".AndorsTrailApplication"
android:name="com.gpl.rpg.AndorsTrail.AndorsTrailApplication"
android:label="@string/app_name"
android:icon="@drawable/icon"
android:icon="@drawable/${icon_name}"
android:description="@string/app_description"
android:allowBackup="true"
android:theme="@style/AndorsTrailTheme_Blue"
@@ -36,37 +36,38 @@
android:preserveLegacyExternalStorage="true"
>
<activity
android:name=".activity.StartScreenActivity"
android:clearTaskOnLaunch="true">
android:name="com.gpl.rpg.AndorsTrail.activity.StartScreenActivity"
android:clearTaskOnLaunch="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.MainActivity"
android:name="com.gpl.rpg.AndorsTrail.activity.MainActivity"
android:label="@string/app_name"
android:theme="@style/AndorsTrailTheme_Blue.NoBackground"
/>
<activity android:name=".activity.HeroinfoActivity" />
<activity android:name=".activity.MonsterInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.ItemInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.LevelUpActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.MonsterEncounterActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.ConversationActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.ShopActivity" />
<activity android:name=".activity.AboutActivity" />
<activity android:name=".activity.LoadingActivity" />
<activity android:name=".activity.Preferences" />
<activity android:name=".activity.LoadSaveActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.ActorConditionInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.BulkSelectionInterface" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.SkillInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name=".activity.DisplayWorldMapActivity" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.MonsterInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.ItemInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.LevelUpActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.MonsterEncounterActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.ConversationActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.ShopActivity" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.AboutActivity" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.LoadingActivity" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.Preferences" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.LoadSaveActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.ActorConditionInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.BulkSelectionInterface" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.SkillInfoActivity" android:theme="@style/AndorsTrailDialogTheme_Blue" />
<activity android:name="com.gpl.rpg.AndorsTrail.activity.DisplayWorldMapActivity" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.gpl.rpg.AndorsTrail.fileprovider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data

View File

@@ -2,7 +2,6 @@ package com.gpl.rpg.AndorsTrail;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
public final class AndorsTrailPreferences {
@@ -62,8 +61,6 @@ public final class AndorsTrailPreferences {
public boolean showQuickslotsWhenToolboxIsVisible = false;
public String language = "default";
public Uri exportImportFolderPath;
public int selectedTheme = 0;
public void read(final Context androidContext) {

View File

@@ -1,26 +1,16 @@
package com.gpl.rpg.AndorsTrail.activity;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v4.provider.DocumentFile;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -32,653 +22,241 @@ import android.widget.Toast;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
import com.gpl.rpg.AndorsTrail.savegames.Savegames.FileHeader;
import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
public final class LoadSaveActivity extends AndorsTrailBaseActivity implements OnClickListener {
private boolean isLoading = true;
//region special slot numbers
private static final int SLOT_NUMBER_CREATE_NEW_SLOT = -1;
public static final int SLOT_NUMBER_EXPORT_SAVEGAMES = -2;
public static final int SLOT_NUMBER_IMPORT_SAVEGAMES = -3;
public static final int SLOT_NUMBER_IMPORT_WORLDMAP = -4;
private static final int SLOT_NUMBER_FIRST_SLOT = 1;
//endregion
private ModelContainer model;
private TileManager tileManager;
private AndorsTrailPreferences preferences;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getDialogTheme());
super.onCreate(savedInstanceState);
final AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setWindowParameters(this);
this.model = app.getWorld().model;
this.preferences = app.getPreferences();
this.tileManager = app.getWorld().tileManager;
String loadsave = getIntent().getData().getLastPathSegment();
isLoading = (loadsave.equalsIgnoreCase("load"));
setContentView(R.layout.loadsave);
TextView tv = (TextView) findViewById(R.id.loadsave_title);
if (isLoading) {
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_search, 0, 0, 0);
tv.setText(R.string.loadsave_title_load);
} else {
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_save, 0, 0, 0);
tv.setText(R.string.loadsave_title_save);
}
ViewGroup slotList = (ViewGroup) findViewById(R.id.loadsave_slot_list);
Button slotTemplateButton = (Button) findViewById(R.id.loadsave_slot_n);
LayoutParams params = slotTemplateButton.getLayoutParams();
slotList.removeView(slotTemplateButton);
ViewGroup newSlotContainer = (ViewGroup) findViewById(R.id.loadsave_save_to_new_slot_container);
Button createNewSlot = (Button) findViewById(R.id.loadsave_save_to_new_slot);
Button exportSaves = (Button) findViewById(R.id.loadsave_export_save);
Button importSaves = (Button) findViewById(R.id.loadsave_import_save);
Button importWorldmap = (Button) findViewById(R.id.loadsave_import_worldmap);
exportSaves.setTag(SLOT_NUMBER_EXPORT_SAVEGAMES);
importSaves.setTag(SLOT_NUMBER_IMPORT_SAVEGAMES);
importWorldmap.setTag(SLOT_NUMBER_IMPORT_WORLDMAP);
ViewGroup exportContainer = (ViewGroup) findViewById(R.id.loadsave_export_save_container);
ViewGroup importContainer = (ViewGroup) findViewById(R.id.loadsave_import_save_container);
ViewGroup importWorldmapContainer = (ViewGroup) findViewById(R.id.loadsave_import_worldmap_container);
addSavegameSlotButtons(slotList, params, Savegames.getUsedSavegameSlots(this));
checkAndRequestPermissions();
if (!isLoading) {
createNewSlot.setTag(SLOT_NUMBER_CREATE_NEW_SLOT);
createNewSlot.setOnClickListener(this);
newSlotContainer.setVisibility(View.VISIBLE);
exportContainer.setVisibility(View.GONE);
importContainer.setVisibility(View.GONE);
importWorldmapContainer.setVisibility(View.GONE);
} else {
newSlotContainer.setVisibility(View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
exportSaves.setOnClickListener(this);
importSaves.setOnClickListener(this);
importWorldmap.setOnClickListener(this);
exportContainer.setVisibility(View.VISIBLE);
importContainer.setVisibility(View.VISIBLE);
importWorldmapContainer.setVisibility(View.VISIBLE);
}
}
}
private static final int READ_EXTERNAL_STORAGE_REQUEST = 1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 2;
@TargetApi(23)
private void checkAndRequestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
}
if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, R.string.storage_permissions_mandatory, Toast.LENGTH_LONG).show();
((AndorsTrailApplication) getApplication()).discardWorld();
finish();
}
}
private void addSavegameSlotButtons(ViewGroup parent, LayoutParams params, List<Integer> usedSavegameSlots) {
int unused = 1;
for (int slot : usedSavegameSlots) {
final FileHeader header = Savegames.quickload(this, slot);
if (header == null) continue;
while (unused < slot) {
Button b = new Button(this);
b.setLayoutParams(params);
b.setTag(unused);
b.setOnClickListener(this);
b.setText(getString(R.string.loadsave_empty_slot, unused));
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
parent.addView(b, params);
unused++;
}
unused++;
Button b = new Button(this);
b.setLayoutParams(params);
b.setTag(slot);
b.setOnClickListener(this);
b.setText(slot + ". " + header.describe());
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
parent.addView(b, params);
}
}
private void completeLoadSaveActivity(int slot) {
Intent i = new Intent();
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) {
List<Integer> usedSlots = Savegames.getUsedSavegameSlots(this);
if (usedSlots.isEmpty())
slot = SLOT_NUMBER_FIRST_SLOT;
else slot = Collections.max(usedSlots) + 1;
} else if (slot == SLOT_NUMBER_EXPORT_SAVEGAMES
|| slot == SLOT_NUMBER_IMPORT_SAVEGAMES
|| slot == SLOT_NUMBER_IMPORT_WORLDMAP) {
i.putExtra("import_export", true);
} else if (slot < SLOT_NUMBER_FIRST_SLOT)
slot = SLOT_NUMBER_FIRST_SLOT;
i.putExtra("slot", slot);
setResult(Activity.RESULT_OK, i);
LoadSaveActivity.this.finish();
}
private String getConfirmOverwriteQuestion(int slot) {
if (isLoading)
return null;
return getConfirmOverwriteQuestionIgnoringLoading(slot);
}
private String getConfirmOverwriteQuestionIgnoringLoading(int slot) {
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT)
return null;//creating a new savegame
if (!Savegames.getSlotFile(slot, this).exists())
return null;//nothing in slot to overwrite
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_ALWAYS) {
return getString(R.string.loadsave_save_overwrite_confirmation_all);
}
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_NEVER) {
return null;
}
final String currentPlayerName = model.player.getName();
final FileHeader header = Savegames.quickload(this, slot);
if (header == null) return null;
final String savedPlayerName = header.playerName;
if (currentPlayerName.equals(savedPlayerName)) return null; //if the names match
return getString(R.string.loadsave_save_overwrite_confirmation, savedPlayerName, currentPlayerName);
}
@Override
public void onClick(View view) {
final int slot = (Integer) view.getTag();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switch (slot) {
case SLOT_NUMBER_IMPORT_WORLDMAP:
clickImportWorldmap();
return;
case SLOT_NUMBER_IMPORT_SAVEGAMES:
clickImportSaveGames();
return;
case SLOT_NUMBER_EXPORT_SAVEGAMES:
clickExportSaveGames();
return;
}
}
if (!isLoading
&& slot != SLOT_NUMBER_CREATE_NEW_SLOT
&& AndorsTrailApplication.CURRENT_VERSION == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
if (!isOverwriteTargetInIncompatibleVersion(slot)) {
saveOrOverwriteSavegame(slot);
}
} else if (isLoading) {
loadSaveGame(slot);
} else {
saveOrOverwriteSavegame(slot);
}
}
private void saveOrOverwriteSavegame(int slot) {
final String message = getConfirmOverwriteQuestion(slot);
if (message != null) {
showConfirmoverwriteQuestion(slot, message);
} else {
completeLoadSaveActivity(slot);
}
}
private boolean isOverwriteTargetInIncompatibleVersion(int slot) {
final FileHeader header = Savegames.quickload(this, slot);
if (header != null && header.fileversion != AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
final Dialog d = CustomDialogFactory.createErrorDialog(this, "Overwriting not allowed", "You are currently using a development version of Andor's trail. Overwriting a regular savegame is not allowed in development mode.");
CustomDialogFactory.show(d);
return true;
}
return false;
}
//region Imports/Exports
private void exportSaveGames(Intent data) {
Uri uri = data.getData();
Context context = getApplicationContext();
ContentResolver resolver = AndorsTrailApplication.getApplicationFromActivity(this).getContentResolver();
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
DocumentFile source = DocumentFile.fromFile(storageDir);
DocumentFile target = DocumentFile.fromTreeUri(context, uri);
if (target == null) {
return;
}
DocumentFile[] files = source.listFiles();
boolean hasExistingFiles = false;
for (DocumentFile file :
files) {
String fileName = file.getName();
if (fileName == null)
continue;
DocumentFile existingFile = target.findFile(fileName);
if (existingFile != null) {
hasExistingFiles = true;
break;
}
}
if (hasExistingFiles) {
showConfirmOverwriteByExportQuestion(resolver, target, files);
} else {
exportSaveGamesFolderContentToFolder(resolver, target, files);
}
}
private void exportSaveGamesFolderContentToFolder(ContentResolver resolver, DocumentFile target, DocumentFile[] files) {
for (DocumentFile file : files) {
String fileName = file.getName();
DocumentFile existingFile = target.findFile(fileName);
boolean hasExistingFile = existingFile != null && existingFile.exists();
if (file.isFile()) {
try {
if (hasExistingFile)
existingFile.delete();
AndroidStorage.copyDocumentFileToNewOrExistingFile(file, resolver, target);
} catch (IOException e) {
e.printStackTrace();
}
} else if (file.isDirectory()) {
DocumentFile targetWorlmap = existingFile;
//if the folder exists already, put the files in the existing folder. (should not happen because of check earlier)
if (!hasExistingFile)
//create a new folder for the worldmap-files
targetWorlmap = target.createDirectory(Constants.FILENAME_WORLDMAP_DIRECTORY);
if (targetWorlmap == null)//Unable to create worldmap folder for some reason
continue;
DocumentFile[] worldmapFiles = file.listFiles();
for (DocumentFile f : worldmapFiles) {
try {
AndroidStorage.copyDocumentFileToNewOrExistingFile(f, resolver, targetWorlmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
completeLoadSaveActivity(SLOT_NUMBER_EXPORT_SAVEGAMES);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void importSaveGames(Intent data) {
Uri uri = data.getData();
ClipData uris = data.getClipData();
if (uri == null && uris == null) {
//no file was selected
return;
}
Context context = getApplicationContext();
ContentResolver resolver = context.getContentResolver();
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
DocumentFile appSavegameFolder = DocumentFile.fromFile(storageDir);
List<Uri> uriList = new ArrayList<>();
if (uri != null) {
uriList.add(uri);
} else {
for (int i = 0; i < uris.getItemCount(); i++)
uriList.add(uris.getItemAt(i).getUri());
}
importSaveGamesFromUris(context, resolver, appSavegameFolder, uriList);
}
private void importSaveGamesFromUris(Context context, ContentResolver resolver, DocumentFile appSavegameFolder, List<Uri> uriList) {
int count = uriList.size();
ArrayList<DocumentFile> alreadyExistingFiles = new ArrayList<>();
ArrayList<DocumentFile> newFiles = new ArrayList<>();
for (int i = 0; i < count; i++) {
Uri item = uriList.get(i);
DocumentFile itemFile = DocumentFile.fromSingleUri(context, item);
boolean fileAlreadyExists = getExistsSavegameInOwnFiles(itemFile, appSavegameFolder);
if (fileAlreadyExists)
alreadyExistingFiles.add(itemFile);
else
newFiles.add(itemFile);
}
if (alreadyExistingFiles.size() > 0) {
showConfirmOverwriteByImportQuestion(resolver, appSavegameFolder, alreadyExistingFiles, newFiles);
} else {
importSaveGames(resolver, appSavegameFolder, newFiles);
}
}
private void importSaveGames(ContentResolver resolver, DocumentFile appSavegameFolder, List<DocumentFile> saveFiles) {
for (DocumentFile file : saveFiles) {
int slot = getSlotFromSavegameFileName(file.getName());
importSaveGameFile(resolver, appSavegameFolder, file, slot);
}
}
private void completeSavegameImportAndCheckIfDone(List<Integer> importsNeedingConfirmation, int slot) {
importsNeedingConfirmation.remove((Object) slot);
if (importsNeedingConfirmation.isEmpty()) {
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_SAVEGAMES);
}
}
private boolean getExistsSavegameInOwnFiles(DocumentFile savegameFile, DocumentFile appSavegameFolder) {
if (savegameFile == null)
return false;
DocumentFile foundFile = appSavegameFolder.findFile(Objects.requireNonNull(savegameFile.getName()));
return foundFile != null && foundFile.exists();
}
private int getSlotFromSavegameFileName(String fileName) {
if (fileName == null || !fileName.startsWith(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX)) {
//TODO: Maybe output a message that the file didn't have the right name?
return -1;
}
String slotStr = fileName.substring(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX.length());
int slot;
try {
slot = Integer.parseInt(slotStr);
return slot;
} catch (NumberFormatException e) {
//TODO: Maybe output a message that the file didn't have the right name?
return -1;
}
}
private void importSaveGameFile(ContentResolver resolver, DocumentFile appSavegameFolder, DocumentFile itemFile, int slot) {
String targetName = Savegames.getSlotFileName(slot);
DocumentFile targetFile = getOrCreateDocumentFile(appSavegameFolder, targetName);
if (targetFile == null || !targetName.equals(targetFile.getName())) {
showErrorImportingSaveGameUnknown();//TODO: maybe replace with a more specific error message
return;
}
try {
AndroidStorage.copyDocumentFile(itemFile, resolver, targetFile);
} catch (IOException e) {
showErrorImportingSaveGameUnknown();
e.printStackTrace();
}
}
private DocumentFile getOrCreateDocumentFile(DocumentFile folder, String targetName) {
DocumentFile targetFile = folder.findFile(targetName);//try finding the file
if (targetFile == null)//no file found, creating new one
targetFile = folder.createFile(Constants.NO_FILE_EXTENSION_MIME_TYPE, targetName);
return targetFile;
}
private void importWorldmap(Intent data) {
Uri uri = data.getData();
Context context = getApplicationContext();
ContentResolver resolver = AndorsTrailApplication.getApplicationFromActivity(this).getContentResolver();
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
DocumentFile storageFolder = DocumentFile.fromFile(storageDir);
DocumentFile ownWorldmapFolder = storageFolder.findFile(Constants.FILENAME_WORLDMAP_DIRECTORY);
if (ownWorldmapFolder == null) {
ownWorldmapFolder = storageFolder.createDirectory(Constants.FILENAME_WORLDMAP_DIRECTORY);
}
DocumentFile chosenFolder = DocumentFile.fromTreeUri(context, uri);
if (chosenFolder == null || !chosenFolder.isDirectory()) {
showErrorImportingWorldmapWrongDirectory();
return;
}
if (!Constants.FILENAME_WORLDMAP_DIRECTORY.equals(chosenFolder.getName())) {
//user did not select the worldmap folder directly
DocumentFile file = chosenFolder.findFile(Constants.FILENAME_WORLDMAP_DIRECTORY);
if (file == null || !file.isDirectory() || !Constants.FILENAME_WORLDMAP_DIRECTORY.equals(file.getName())) {
//could not find a worldmap folder in the users selection
showErrorImportingWorldmapWrongDirectory();
return;
}
chosenFolder = file;
}
DocumentFile[] files = chosenFolder.listFiles();
for (DocumentFile file : files) {
if (file.isFile()) {
try {
AndroidStorage.copyDocumentFileToNewOrExistingFile(file, resolver, ownWorldmapFolder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_WORLDMAP);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void clickExportSaveGames() {
startActivityForResult(AndroidStorage.getNewOpenDirectoryIntent(), -SLOT_NUMBER_EXPORT_SAVEGAMES);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void clickImportSaveGames() {
startActivityForResult(AndroidStorage.getNewSelectMultipleSavegameFilesIntent(), -SLOT_NUMBER_IMPORT_SAVEGAMES);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void clickImportWorldmap() {
startActivityForResult(AndroidStorage.getNewOpenDirectoryIntent(), -SLOT_NUMBER_IMPORT_WORLDMAP);
}
private void showConfirmOverwriteByExportQuestion(ContentResolver resolver, DocumentFile targetFolder, DocumentFile[] files) {
final Dialog d = CustomDialogFactory.createDialog(this,
getString(R.string.loadsave_export_overwrite_confirmation_title),
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.loadsave_export_overwrite_confirmation),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, v -> exportSaveGamesFolderContentToFolder(resolver, targetFolder, files));
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
private void showConfirmOverwriteByImportQuestion(ContentResolver resolver,
DocumentFile appSavegameFolder,
List<DocumentFile> alreadyExistingFiles,
List<DocumentFile> newFiles) {
final String title = getString(R.string.loadsave_import_overwrite_confirmation_title);
String message = getString(R.string.loadsave_import_overwrite_confirmation);
StringBuilder sb = new StringBuilder();
sb.append('\n');
int amount = alreadyExistingFiles.size();
Context context = AndorsTrailApplication.getApplicationFromActivity(this).getApplicationContext();
for (int i = 0; i < amount && i < 3; i++) {
DocumentFile alreadyExistingFile = alreadyExistingFiles.get(i);
String alreadyExistingFileName = alreadyExistingFile.getName();
FileHeader fileHeader = Savegames.quickload(context, getSlotFromSavegameFileName(alreadyExistingFileName));
sb.append('\n');
String fileHeaderDesription = "";
if (fileHeader != null)
fileHeaderDesription = fileHeader.describe();
sb.append(getString(R.string.loadsave_import_overwrite_confirmation_file_pattern, alreadyExistingFileName, fileHeaderDesription));
// sb.append(alreadyExistingFile.getName());
}
if (amount > 3) {
sb.append("\n...");
}
message = message + sb;
final Dialog d = CustomDialogFactory.createDialog(this,
title,
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
message,
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, v -> newFiles.addAll(alreadyExistingFiles));
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.setDismissListener(d, dialog -> {
importSaveGames(resolver, appSavegameFolder, newFiles);
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_SAVEGAMES);
});
CustomDialogFactory.show(d);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK)
return;
// Uri uri = data.getData();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switch (-requestCode) {
case SLOT_NUMBER_EXPORT_SAVEGAMES:
exportSaveGames(data);
return;
case SLOT_NUMBER_IMPORT_SAVEGAMES:
importSaveGames(data);
return;
case SLOT_NUMBER_IMPORT_WORLDMAP:
importWorldmap(data);
return;
}
}
}
//endregion
private void loadSaveGame(int slot) {
if (!Savegames.getSlotFile(slot, this).exists()) {
showErrorLoadingEmptySlot();
} else {
final FileHeader header = Savegames.quickload(this, slot);
if (header != null && !header.hasUnlimitedSaves) {
showSlotGetsDeletedOnLoadWarning(slot);
} else {
completeLoadSaveActivity(slot);
}
}
}
//region show Dialogs
private void showErrorImportingWorldmapWrongDirectory() {
final Dialog d = CustomDialogFactory.createErrorDialog(this,
getString(R.string.loadsave_import_worldmap_unsuccessfull),
getString(R.string.loadsave_import_worldmap_unsuccessfull_wrong_directory));
CustomDialogFactory.show(d);
}
private void showErrorImportingSaveGameUnknown() {
final Dialog d = CustomDialogFactory.createErrorDialog(this,
getString(R.string.loadsave_import_save_unsuccessfull),
getString(R.string.loadsave_import_save_unsuccessfull_unknown));
CustomDialogFactory.show(d);
}
private void showErrorLoadingEmptySlot() {
final Dialog d = CustomDialogFactory.createErrorDialog(this,
getString(R.string.startscreen_error_loading_game),
getString(R.string.startscreen_error_loading_empty_slot));
CustomDialogFactory.show(d);
}
private void showSlotGetsDeletedOnLoadWarning(final int slot) {
final Dialog d = CustomDialogFactory.createDialog(this,
getString(R.string.startscreen_attention_slot_gets_delete_on_load),
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_attention_message_slot_gets_delete_on_load),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, v -> completeLoadSaveActivity(slot));
CustomDialogFactory.show(d);
}
private void showConfirmoverwriteQuestion(final int slot, String message) {
final String title =
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
final Dialog d = CustomDialogFactory.createDialog(this,
title,
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
message,
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, v -> completeLoadSaveActivity(slot));
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
//endregion
private boolean isLoading = true;
private static final int SLOT_NUMBER_CREATE_NEW_SLOT = -1;
private static final int SLOT_NUMBER_FIRST_SLOT = 1;
private ModelContainer model;
private TileManager tileManager;
private AndorsTrailPreferences preferences;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getDialogTheme());
super.onCreate(savedInstanceState);
final AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setWindowParameters(this);
this.model = app.getWorld().model;
this.preferences = app.getPreferences();
this.tileManager = app.getWorld().tileManager;
String loadsave = getIntent().getData().getLastPathSegment();
isLoading = (loadsave.equalsIgnoreCase("load"));
setContentView(R.layout.loadsave);
TextView tv = (TextView) findViewById(R.id.loadsave_title);
if (isLoading) {
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_search, 0, 0, 0);
tv.setText(R.string.loadsave_title_load);
} else {
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_save, 0, 0, 0);
tv.setText(R.string.loadsave_title_save);
}
ViewGroup slotList = (ViewGroup) findViewById(R.id.loadsave_slot_list);
Button slotTemplateButton = (Button) findViewById(R.id.loadsave_slot_n);
LayoutParams params = slotTemplateButton.getLayoutParams();
slotList.removeView(slotTemplateButton);
ViewGroup newSlotContainer = (ViewGroup) findViewById(R.id.loadsave_save_to_new_slot_container);
Button createNewSlot = (Button) findViewById(R.id.loadsave_save_to_new_slot);
addSavegameSlotButtons(slotList, params, Savegames.getUsedSavegameSlots(this));
checkAndRequestPermissions();
if (!isLoading) {
createNewSlot.setTag(SLOT_NUMBER_CREATE_NEW_SLOT);
createNewSlot.setOnClickListener(this);
newSlotContainer.setVisibility(View.VISIBLE);
} else {
newSlotContainer.setVisibility(View.GONE);
}
}
private static final int READ_EXTERNAL_STORAGE_REQUEST=1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST=2;
@TargetApi(23)
private void checkAndRequestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
}
if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
this.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, R.string.storage_permissions_mandatory, Toast.LENGTH_LONG).show();
((AndorsTrailApplication)getApplication()).discardWorld();
finish();
}
}
private void addSavegameSlotButtons(ViewGroup parent, LayoutParams params, List<Integer> usedSavegameSlots) {
int unused = 1;
for (int slot : usedSavegameSlots) {
final FileHeader header = Savegames.quickload(this, slot);
if (header == null) continue;
while (unused < slot){
Button b = new Button(this);
b.setLayoutParams(params);
b.setTag(unused);
b.setOnClickListener(this);
b.setText(getString(R.string.loadsave_empty_slot, unused));
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
parent.addView(b, params);
unused++;
}
unused++;
Button b = new Button(this);
b.setLayoutParams(params);
b.setTag(slot);
b.setOnClickListener(this);
b.setText(slot + ". " + header.describe());
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
parent.addView(b, params);
}
}
public void loadsave(int slot) {
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) {
List<Integer> usedSlots = Savegames.getUsedSavegameSlots(this);
if (usedSlots.isEmpty()) slot = SLOT_NUMBER_FIRST_SLOT;
else slot = Collections.max(usedSlots) + 1;
}
if (slot < SLOT_NUMBER_FIRST_SLOT) slot = SLOT_NUMBER_FIRST_SLOT;
Intent i = new Intent();
i.putExtra("slot", slot);
setResult(Activity.RESULT_OK, i);
LoadSaveActivity.this.finish();
}
private String getConfirmOverwriteQuestion(int slot) {
if (isLoading) return null;
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) return null; // if we're creating a new slot
if (!Savegames.getSlotFile(slot, this).exists()) return null;
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_ALWAYS) {
return getString(R.string.loadsave_save_overwrite_confirmation_all);
}
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_NEVER) {
return null;
}
final String currentPlayerName = model.player.getName();
final FileHeader header = Savegames.quickload(this, slot);
if (header == null) return null;
final String savedPlayerName = header.playerName;
if (currentPlayerName.equals(savedPlayerName)) return null; // if the names match
return getString(R.string.loadsave_save_overwrite_confirmation, savedPlayerName, currentPlayerName);
}
@Override
public void onClick(View view) {
final int slot = (Integer) view.getTag();
if (!isLoading && slot != SLOT_NUMBER_CREATE_NEW_SLOT && AndorsTrailApplication.CURRENT_VERSION == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
final FileHeader header = Savegames.quickload(this, slot);
if (header != null && header.fileversion != AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
final Dialog d = CustomDialogFactory.createDialog(this,
"Overwriting not allowed",
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
"You are currently using a development version of Andor's trail. Overwriting a regular savegame is not allowed in development mode.",
null,
true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
CustomDialogFactory.show(d);
return;
}
}
if (isLoading) {
if(!Savegames.getSlotFile(slot, this).exists()) {
showErrorLoadingEmptySlot();
} else {
final FileHeader header = Savegames.quickload(this, slot);
if (header != null && !header.hasUnlimitedSaves) {
showSlotGetsDeletedOnLoadWarning(slot);
} else {
loadsave(slot);
}
}
} else {
final String message = getConfirmOverwriteQuestion(slot);
if (message != null) {
showConfirmoverwriteQuestion(slot, message);
} else {
loadsave(slot);
}
}
}
private void showErrorLoadingEmptySlot() {
final Dialog d = CustomDialogFactory.createDialog(this,
getString(R.string.startscreen_error_loading_game),
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_error_loading_empty_slot),
null,
true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
CustomDialogFactory.show(d);
}
private void showSlotGetsDeletedOnLoadWarning(final int slot) {
final Dialog d = CustomDialogFactory.createDialog(this,
getString(R.string.startscreen_attention_slot_gets_delete_on_load),
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_attention_message_slot_gets_delete_on_load),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
loadsave(slot);
}
});
CustomDialogFactory.show(d);
}
private void showConfirmoverwriteQuestion(final int slot, String message) {
final String title =
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
final Dialog d = CustomDialogFactory.createDialog(this,
title,
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
message,
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, new View.OnClickListener() {
@Override
public void onClick(View v) {
loadsave(slot);
}
});
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
}

View File

@@ -1,14 +1,7 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.content.Context;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
@@ -39,7 +32,5 @@ public final class Preferences extends PreferenceActivity {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
}

View File

@@ -28,10 +28,8 @@ import com.gpl.rpg.AndorsTrail.Dialogs;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.WorldSetup;
import com.gpl.rpg.AndorsTrail.activity.AboutActivity;
import com.gpl.rpg.AndorsTrail.activity.LoadSaveActivity;
import com.gpl.rpg.AndorsTrail.activity.LoadingActivity;
import com.gpl.rpg.AndorsTrail.activity.Preferences;
import com.gpl.rpg.AndorsTrail.activity.StartScreenActivity;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
@@ -43,253 +41,253 @@ import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
public class StartScreenActivity_MainMenu extends Fragment {
private static final int INTENTREQUEST_PREFERENCES = 7;
public static final int INTENTREQUEST_LOADGAME = 9;
public static final int INTENTREQUEST_EXPORT_SAVE = 11;
public static final int INTENTREQUEST_IMPORT_SAVE = 13;
private static final int INTENTREQUEST_PREFERENCES = 7;
public static final int INTENTREQUEST_LOADGAME = 9;
private boolean hasExistingGame = false;
private Button startscreen_continue;
private Button startscreen_newgame;
private Button startscreen_load;
private Button startscreen_import;
private Button startscreen_export;
private ViewGroup save_preview_holder;
private ImageView save_preview_hero_icon;
private TextView save_preview_hero_desc;
private boolean hasExistingGame = false;
private Button startscreen_continue;
private Button startscreen_newgame;
private Button startscreen_load;
private ViewGroup save_preview_holder;
private ImageView save_preview_hero_icon;
private TextView save_preview_hero_desc;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
updatePreferences(false);
super.onCreateView(inflater, container, savedInstanceState);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
updatePreferences(false);
super.onCreateView(inflater, container, savedInstanceState);
if (container != null) {
container.removeAllViews();
}
View root = inflater.inflate(R.layout.startscreen_mainmenu, container, false);
save_preview_holder = (ViewGroup) root.findViewById(R.id.save_preview_holder);
save_preview_hero_icon = (ImageView) root.findViewById(R.id.save_preview_hero_icon);
save_preview_hero_desc = (TextView) root.findViewById(R.id.save_preview_hero_desc);
startscreen_continue = (Button) root.findViewById(R.id.startscreen_continue);
startscreen_continue.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
continueGame(false, Savegames.SLOT_QUICKSAVE, null);
}
});
if (container != null) {
container.removeAllViews();
}
startscreen_newgame = (Button) root.findViewById(R.id.startscreen_newgame);
startscreen_newgame.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (hasExistingGame) {
comfirmNewGame();
} else {
createNewGame();
}
}
});
View root = inflater.inflate(R.layout.startscreen_mainmenu, container, false);
Button b = (Button) root.findViewById(R.id.startscreen_about);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
startActivity(new Intent(getActivity(), AboutActivity.class));
}
});
save_preview_holder = (ViewGroup) root.findViewById(R.id.save_preview_holder);
save_preview_hero_icon = (ImageView) root.findViewById(R.id.save_preview_hero_icon);
save_preview_hero_desc = (TextView) root.findViewById(R.id.save_preview_hero_desc);
b = (Button) root.findViewById(R.id.startscreen_preferences);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(getActivity(), Preferences.class);
StartScreenActivity_MainMenu.this.startActivityForResult(intent, INTENTREQUEST_PREFERENCES);
}
});
startscreen_load = (Button) root.findViewById(R.id.startscreen_load);
startscreen_load.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
if (hasExistingGame && app != null && app.getWorld() != null && app.getWorld().model != null
&& app.getWorld().model.statistics != null && !app.getWorld().model.statistics.hasUnlimitedSaves()) {
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
getString(R.string.startscreen_load_game),
getResources().getDrawable(android.R.drawable.ic_delete),
getString(R.string.startscreen_load_game_confirm),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
}
});
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
CustomDialogFactory.show(d);
startscreen_continue = (Button) root.findViewById(R.id.startscreen_continue);
startscreen_continue.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
continueGame(false, Savegames.SLOT_QUICKSAVE, null);
}
});
} else {
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
}
}
});
startscreen_newgame = (Button) root.findViewById(R.id.startscreen_newgame);
startscreen_newgame.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (hasExistingGame) {
comfirmNewGame();
} else {
createNewGame();
}
}
});
if (AndorsTrailApplication.DEVELOPMENT_FORCE_STARTNEWGAME) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGRESOURCES) {
continueGame(true, 0, "Debug player");
} else {
continueGame(true, 0, "Player");
}
} else if (AndorsTrailApplication.DEVELOPMENT_FORCE_CONTINUEGAME) {
continueGame(false, Savegames.SLOT_QUICKSAVE, null);
}
Button b = (Button) root.findViewById(R.id.startscreen_about);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
startActivity(new Intent(getActivity(), AboutActivity.class));
}
});
// if it is a new version we first fire a welcome screen in onResume
// and afterwards check the permissions
if (!isNewVersion()) {
checkAndRequestPermissions(getActivity());
migrateDataOnDemand(getActivity());
}
return root;
}
@Override
public void onResume() {
super.onResume();
String playerName;
String displayInfo = null;
int iconID = TileManager.CHAR_HERO;
boolean isDead = false;
b = (Button) root.findViewById(R.id.startscreen_preferences);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(getActivity(), Preferences.class);
StartScreenActivity_MainMenu.this.startActivityForResult(intent, INTENTREQUEST_PREFERENCES);
}
});
FileHeader header = Savegames.quickload(getActivity(), Savegames.SLOT_QUICKSAVE);
if (header != null && header.playerName != null) {
playerName = header.playerName;
displayInfo = header.displayInfo;
iconID = header.iconID;
isDead = header.isDead;
} else {
// Before fileversion 14 (v0.6.7), quicksave was stored in Shared preferences
SharedPreferences p = getActivity().getSharedPreferences("quicksave", Activity.MODE_PRIVATE);
playerName = p.getString("playername", null);
if (playerName != null) {
displayInfo = "level " + p.getInt("level", -1);
}
}
hasExistingGame = (playerName != null);
setButtonState(playerName, displayInfo, iconID, isDead);
startscreen_load = (Button) root.findViewById(R.id.startscreen_load);
startscreen_load.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
if (hasExistingGame && app != null && app.getWorld() != null && app.getWorld().model != null
&& app.getWorld().model.statistics != null && !app.getWorld().model.statistics.hasUnlimitedSaves()) {
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
getString(R.string.startscreen_load_game),
getResources().getDrawable(android.R.drawable.ic_delete),
getString(R.string.startscreen_load_game_confirm),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
}
});
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
CustomDialogFactory.show(d);
if (isNewVersion()) {
Dialogs.showNewVersion(getActivity(), new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface arg0) {
setCurrentVersionForVersionCheck();
checkAndRequestPermissions(getActivity());
migrateDataOnDemand(getActivity());
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
startscreen_load.setEnabled(hasSavegames);
}
});
}
} else {
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
}
}
});
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
startscreen_load.setEnabled(hasSavegames);
}
if (AndorsTrailApplication.DEVELOPMENT_FORCE_STARTNEWGAME) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGRESOURCES) {
continueGame(true, 0, "Debug player");
} else {
continueGame(true, 0, "Player");
}
} else if (AndorsTrailApplication.DEVELOPMENT_FORCE_CONTINUEGAME) {
continueGame(false, Savegames.SLOT_QUICKSAVE, null);
}
@TargetApi(29)
public void migrateDataOnDemand(final Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (AndroidStorage.shouldMigrateToInternalStorage(activity.getApplicationContext())) {
final Dialog d = CustomDialogFactory.createDialog(activity,
getString(R.string.startscreen_migration_title),
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_migration_text),
null,
true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface arg0) {
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
startscreen_load.setEnabled(hasSavegames);
}
});
CustomDialogFactory.show(d);
if (!AndroidStorage.migrateToInternalStorage(activity.getApplicationContext())) {
final Dialog errorDlg = CustomDialogFactory.createDialog(activity,
getString(R.string.startscreen_migration_title),
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_migration_failure),
null,
true);
CustomDialogFactory.addDismissButton(errorDlg, android.R.string.ok);
d.cancel();
CustomDialogFactory.show(errorDlg);
}
} else {
L.log("INFO: No external files or destination folder ist not empty. No data migration.");
}
} else {
L.log("INFO: No read permission on external folder. No data migration.");
}
}
}
// if it is a new version we first fire a welcome screen in onResume
// and afterwards check the permissions
if (!isNewVersion()) {
checkAndRequestPermissions(getActivity());
migrateDataOnDemand(getActivity());
}
private static final int READ_EXTERNAL_STORAGE_REQUEST=1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST=2;
return root;
}
@TargetApi(23)
public static void checkAndRequestPermissions(final Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
}
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
}
}
}
@Override
public void onResume() {
super.onResume();
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
listener = (OnNewGameRequestedListener) activity;
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
private void setButtonState(final String playerName, final String displayInfo, int iconID, boolean isDead) {
startscreen_continue.setEnabled(hasExistingGame && !isDead);
startscreen_newgame.setEnabled(true);
if (hasExistingGame) {
TileManager tm = AndorsTrailApplication.getApplicationFromActivity(getActivity()).getWorld().tileManager;
tm.setImageViewTileForPlayer(getResources(), save_preview_hero_icon, iconID);
save_preview_hero_desc.setText((isDead ? getString(R.string.rip_startscreen) : "") + playerName + ", " + displayInfo);
save_preview_holder.setVisibility(View.VISIBLE);
} else {
save_preview_holder.setVisibility(View.GONE);
}
}
String playerName;
String displayInfo = null;
int iconID = TileManager.CHAR_HERO;
boolean isDead = false;
private void continueGame(boolean createNewCharacter, int loadFromSlot, String name) {
final WorldSetup setup = AndorsTrailApplication.getApplicationFromActivity(getActivity()).getWorldSetup();
setup.createNewCharacter = createNewCharacter;
setup.loadFromSlot = loadFromSlot;
setup.newHeroName = name;
startActivity(new Intent(getActivity(), LoadingActivity.class));
}
FileHeader header = Savegames.quickload(getActivity(), Savegames.SLOT_QUICKSAVE);
if (header != null && header.playerName != null) {
playerName = header.playerName;
displayInfo = header.displayInfo;
iconID = header.iconID;
isDead = header.isDead;
} else {
// Before fileversion 14 (v0.6.7), quicksave was stored in Shared preferences
SharedPreferences p = getActivity().getSharedPreferences("quicksave", Activity.MODE_PRIVATE);
playerName = p.getString("playername", null);
if (playerName != null) {
displayInfo = "level " + p.getInt("level", -1);
}
}
hasExistingGame = (playerName != null);
setButtonState(playerName, displayInfo, iconID, isDead);
if (isNewVersion()) {
Dialogs.showNewVersion(getActivity(), new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface arg0) {
setCurrentVersionForVersionCheck();
checkAndRequestPermissions(getActivity());
migrateDataOnDemand(getActivity());
startscreen_load.setEnabled(true);
}
});
}
startscreen_load.setEnabled(true);
}
@TargetApi(29)
public void migrateDataOnDemand(final Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (AndroidStorage.shouldMigrateToInternalStorage(activity.getApplicationContext())) {
final Dialog d = CustomDialogFactory.createDialog(activity,
getString(R.string.startscreen_migration_title),
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_migration_text),
null,
true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface arg0) {
startscreen_load.setEnabled(true);
}
});
CustomDialogFactory.show(d);
if (!AndroidStorage.migrateToInternalStorage(activity.getApplicationContext())) {
final Dialog errorDlg = CustomDialogFactory.createDialog(activity,
getString(R.string.startscreen_migration_title),
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
getString(R.string.startscreen_migration_failure),
null,
true);
CustomDialogFactory.addDismissButton(errorDlg, android.R.string.ok);
d.cancel();
CustomDialogFactory.show(errorDlg);
}
} else {
L.log("INFO: No external files or destination folder ist not empty. No data migration.");
}
} else {
L.log("INFO: No read permission on external folder. No data migration.");
}
}
}
private static final int READ_EXTERNAL_STORAGE_REQUEST = 1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 2;
@TargetApi(23)
public static void checkAndRequestPermissions(final Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
}
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
}
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
listener = (OnNewGameRequestedListener) activity;
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
private void setButtonState(final String playerName, final String displayInfo, int iconID, boolean isDead) {
startscreen_continue.setEnabled(hasExistingGame && !isDead);
startscreen_newgame.setEnabled(true);
if (hasExistingGame) {
TileManager tm = AndorsTrailApplication.getApplicationFromActivity(getActivity()).getWorld().tileManager;
tm.setImageViewTileForPlayer(getResources(), save_preview_hero_icon, iconID);
save_preview_hero_desc.setText((isDead ? getString(R.string.rip_startscreen) : "") + playerName + ", " + displayInfo);
save_preview_holder.setVisibility(View.VISIBLE);
} else {
save_preview_holder.setVisibility(View.GONE);
}
}
private void continueGame(boolean createNewCharacter, int loadFromSlot, String name) {
final WorldSetup setup = AndorsTrailApplication.getApplicationFromActivity(getActivity()).getWorldSetup();
setup.createNewCharacter = createNewCharacter;
setup.loadFromSlot = loadFromSlot;
setup.newHeroName = name;
startActivity(new Intent(getActivity(), LoadingActivity.class));
}
private void comfirmNewGame() {
private void comfirmNewGame() {
// new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AndorsTrailStyle_Dialog))
// .setTitle(R.string.startscreen_newgame)
// .setMessage(R.string.startscreen_newgame_confirm)
@@ -307,108 +305,96 @@ public class StartScreenActivity_MainMenu extends Fragment {
// .create().show();
//
//
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
getString(R.string.startscreen_newgame),
getResources().getDrawable(android.R.drawable.ic_delete),
getResources().getString(R.string.startscreen_newgame_confirm),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
createNewGame();
}
});
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
getString(R.string.startscreen_newgame),
getResources().getDrawable(android.R.drawable.ic_delete),
getResources().getString(R.string.startscreen_newgame_confirm),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View v) {
createNewGame();
}
});
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
CustomDialogFactory.show(d);
}
CustomDialogFactory.show(d);
private static final String versionCheck = "lastversion";
private boolean isNewVersion() {
SharedPreferences s = getActivity().getSharedPreferences(Constants.PREFERENCE_MODEL_LASTRUNVERSION, Activity.MODE_PRIVATE);
int lastversion = s.getInt(versionCheck, 0);
if (lastversion >= AndorsTrailApplication.CURRENT_VERSION) return false;
return true;
}
}
private void setCurrentVersionForVersionCheck() {
SharedPreferences s = getActivity().getSharedPreferences(Constants.PREFERENCE_MODEL_LASTRUNVERSION, Activity.MODE_PRIVATE);
Editor e = s.edit();
e.putInt(versionCheck, AndorsTrailApplication.CURRENT_VERSION);
e.commit();
}
private static final String versionCheck = "lastversion";
private boolean isNewVersion() {
SharedPreferences s = getActivity().getSharedPreferences(Constants.PREFERENCE_MODEL_LASTRUNVERSION, Activity.MODE_PRIVATE);
int lastversion = s.getInt(versionCheck, 0);
if (lastversion >= AndorsTrailApplication.CURRENT_VERSION) return false;
return true;
}
private void setCurrentVersionForVersionCheck() {
SharedPreferences s = getActivity().getSharedPreferences(Constants.PREFERENCE_MODEL_LASTRUNVERSION, Activity.MODE_PRIVATE);
Editor e = s.edit();
e.putInt(versionCheck, AndorsTrailApplication.CURRENT_VERSION);
e.commit();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case INTENTREQUEST_LOADGAME:
if (resultCode != Activity.RESULT_OK) break;
final boolean wasImportOrExport = data.getBooleanExtra("import_export", false);
final int slot = data.getIntExtra("slot", 1);
if (wasImportOrExport) {
if(slot == LoadSaveActivity.SLOT_NUMBER_EXPORT_SAVEGAMES)
Toast.makeText(getActivity(),R.string.loadsave_export_save_successfull, Toast.LENGTH_LONG).show();
else if(slot == LoadSaveActivity.SLOT_NUMBER_IMPORT_SAVEGAMES)
Toast.makeText(getActivity(),R.string.loadsave_import_save_successfull, Toast.LENGTH_LONG).show();
else if(slot == LoadSaveActivity.SLOT_NUMBER_IMPORT_WORLDMAP)
Toast.makeText(getActivity(),R.string.loadsave_import_worldmap_successfull, Toast.LENGTH_LONG).show();
break;
}
continueGame(false, slot, null);
break;
case INTENTREQUEST_PREFERENCES:
updatePreferences(true);
break;
}
}
private void updatePreferences(boolean alreadyStartedLoadingResources) {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
AndorsTrailPreferences preferences = app.getPreferences();
preferences.read(getActivity());
if (app.setLocale(getActivity())) {
if (alreadyStartedLoadingResources) {
// Changing the locale after having loaded the game requires resources to
// be re-loaded. Therefore, we just exit here.
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
doFinish();
return;
}
}
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
// Changing the theme requires a restart to re-create all activities.
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
doFinish();
return;
}
app.getWorld().tileManager.updatePreferences(preferences);
}
@SuppressLint("NewApi")
private void doFinish() {
//For Lollipop and above
((AndorsTrailApplication) getActivity().getApplication()).discardWorld();
getActivity().finish();
}
public interface OnNewGameRequestedListener {
public void onNewGameRequested();
}
private OnNewGameRequestedListener listener = null;
private void createNewGame() {
if (listener != null) {
listener.onNewGameRequested();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case INTENTREQUEST_LOADGAME:
if (resultCode != Activity.RESULT_OK) break;
final int slot = data.getIntExtra("slot", 1);
continueGame(false, slot, null);
break;
case INTENTREQUEST_PREFERENCES:
updatePreferences(true);
break;
}
}
private void updatePreferences(boolean alreadyStartedLoadingResources) {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
AndorsTrailPreferences preferences = app.getPreferences();
preferences.read(getActivity());
if (app.setLocale(getActivity())) {
if (alreadyStartedLoadingResources) {
// Changing the locale after having loaded the game requires resources to
// be re-loaded. Therefore, we just exit here.
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
doFinish();
return;
}
}
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
// Changing the theme requires a restart to re-create all activities.
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
doFinish();
return;
}
app.getWorld().tileManager.updatePreferences(preferences);
}
@SuppressLint("NewApi")
private void doFinish() {
//For Lollipop and above
((AndorsTrailApplication)getActivity().getApplication()).discardWorld();
getActivity().finish();
}
public interface OnNewGameRequestedListener {
public void onNewGameRequested();
}
private OnNewGameRequestedListener listener = null;
private void createNewGame() {
if (listener != null) {
listener.onNewGameRequested();
}
}
}

View File

@@ -51,10 +51,6 @@ public final class Constants {
public static final String CHEAT_DETECTION_FOLDER = "dEAGyGE3YojqXjI3x4x7";
public static final String PASSIVE_ACHIEVEMENT_CHECK_PHRASE = "passive_achievement_check";
public static final String SAVEGAME_FILE_MIME_TYPE = "application/octet-stream";
public static final String WORLDMAP_FILE_MIME_TYPE = "image/png";
public static final String NO_FILE_EXTENSION_MIME_TYPE = "application/no_file_extension_mime_type";
public static final Random rnd = new Random();
public static int rollValue(final ConstRange r) { return rollValue(r.max, r.current); }
public static int rollValue(final ConstRange r, int bias) { return rollValue((r.max + 1) * 100 -1, r.current * 100 + bias)/100; }

View File

@@ -2,6 +2,7 @@ package com.gpl.rpg.AndorsTrail.controller;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.View;
@@ -98,28 +99,36 @@ public final class InputController implements OnClickListener, OnLongClickListen
// Keys mapping to UP_LEFT
key = KEY_MOVE_UP_LEFT;
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_LEFT, key);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_LEFT, key);
}
keyMap.put(KeyEvent.KEYCODE_NUMPAD_7, key);
keyMap.put(KeyEvent.KEYCODE_7, key);
keyMap.put(KeyEvent.KEYCODE_MOVE_HOME, key);
// Keys mapping to UP_RIGHT
key = KEY_MOVE_UP_RIGHT;
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_RIGHT, key);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_RIGHT, key);
}
keyMap.put(KeyEvent.KEYCODE_NUMPAD_9, key);
keyMap.put(KeyEvent.KEYCODE_9, key);
keyMap.put(KeyEvent.KEYCODE_PAGE_UP, key);
// Keys mapping to DOWN_LEFT
key = KEY_MOVE_DOWN_LEFT;
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_LEFT, key);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_LEFT, key);
}
keyMap.put(KeyEvent.KEYCODE_NUMPAD_1, key);
keyMap.put(KeyEvent.KEYCODE_1, key);
keyMap.put(KeyEvent.KEYCODE_MOVE_END, key);
// Keys mapping to DOWN_RIGHT
key = KEY_MOVE_DOWN_RIGHT;
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, key);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, key);
}
keyMap.put(KeyEvent.KEYCODE_NUMPAD_3, key);
keyMap.put(KeyEvent.KEYCODE_3, key);
keyMap.put(KeyEvent.KEYCODE_PAGE_DOWN, key);

View File

@@ -19,6 +19,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.model.quest.Quest;
import com.gpl.rpg.AndorsTrail.util.HashMapHelper;
public final class GameStatistics {
private int deaths = 0;
@@ -36,10 +37,10 @@ public final class GameStatistics {
public void addMonsterKill(MonsterType monsterType) {
// Track monster kills by type ID, for savegame file
killedMonstersByTypeID.put(monsterType.id, killedMonstersByTypeID.getOrDefault((monsterType.id), 0) + 1);
killedMonstersByTypeID.put(monsterType.id, getNumberOfKillsForMonsterType(monsterType.id) + 1);
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
killedMonstersByName.put(monsterType.name, killedMonstersByName.getOrDefault(monsterType.name, 0) + 1);
killedMonstersByName.put(monsterType.name, getNumberOfKillsForMonsterName(monsterType.name) + 1);
}
public void addPlayerDeath(int lostExp) {
@@ -50,8 +51,7 @@ public final class GameStatistics {
}
public void addItemUsage(ItemType type) {
final String n = type.id;
if (!usedItems.containsKey(n)) usedItems.put(n, 1);
else usedItems.put(n, usedItems.get(n) + 1);
usedItems.put(n, HashMapHelper.getOrDefault(usedItems, n,0) + 1);
}
public int getDeaths() {
@@ -73,15 +73,11 @@ public final class GameStatistics {
public boolean isDead() { return !hasUnlimitedLives() && getLivesLeft() < 1; }
public int getNumberOfKillsForMonsterType(String monsterTypeID) {
Integer v = killedMonstersByTypeID.get(monsterTypeID);
if (v == null) return 0;
return v;
return HashMapHelper.getOrDefault(killedMonstersByTypeID, monsterTypeID, 0);
}
public int getNumberOfKillsForMonsterName(String monsterName) {
Integer v = killedMonstersByName.get(monsterName);
if (v == null) return 0;
return v;
return HashMapHelper.getOrDefault(killedMonstersByName, monsterName, 0);
}
public String getTop5MostCommonlyKilledMonsters(WorldContext world, Resources res) {
@@ -144,20 +140,15 @@ public final class GameStatistics {
}
public int getNumberOfUsedItems() {
int result = 0;
for (int v : usedItems.values()) result += v;
return result;
return HashMapHelper.sumIntegerValues(usedItems);
}
public int getNumberOfTimesItemHasBeenUsed(String itemId) {
if (!usedItems.containsKey(itemId)) return 0;
return usedItems.get(itemId);
return HashMapHelper.getOrDefault(usedItems, itemId, 0);
}
public int getNumberOfKilledMonsters() {
int result = 0;
for (int v : killedMonstersByTypeID.values()) result += v;
return result;
return HashMapHelper.sumIntegerValues(killedMonstersByTypeID);
}
private static final Comparator<Entry<String, Integer>> descendingValueComparator = new Comparator<Entry<String, Integer>>() {
@@ -186,7 +177,7 @@ public final class GameStatistics {
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
MonsterType t = world.monsterTypes.getMonsterType(id);
if (t != null) killedMonstersByName.put(t.name, killedMonstersByName.getOrDefault(t.name, 0) + value);
if (t != null) killedMonstersByName.put(t.name, getNumberOfKillsForMonsterName(t.name) + value);
}
if (fileversion <= 17) return;

View File

@@ -274,168 +274,83 @@ public final class ResourceLoader {
loader.prepareTileset(R.drawable.ui_icon_immunity, "ui_icon_immunity", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_dynamic_placeholders, "map_dynamic_placeholders", new Size(10, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.actorconditions_1, "actorconditions_1", new Size(14, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.actorconditions_2, "actorconditions_2", sz3x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.actorconditions_japozero, "actorconditions_japozero", new Size(16, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.actorconditions_omi1, "actorconditions_omi1", sz2x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.actorconditions_omi2, "actorconditions_omi2", sz5x1, sz1x1, mTileSize);
/*INSERT_ACTORCONDITIONS_TILESETS_HERE*/
loader.prepareTileset(R.drawable.items_armours, "items_armours", new Size(14, 3), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_weapons, "items_weapons", new Size(14, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_jewelry, "items_jewelry", new Size(14, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_consumables, "items_consumables", new Size(14, 5), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_books, "items_books", new Size(11, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc, "items_misc", new Size(14, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc_2, "items_misc_2", sz20x12, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc_3, "items_misc_3", sz20x12, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc_4, "items_misc_4", new Size(20, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc_5, "items_misc_5", new Size(9, 5), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_misc_6, "items_misc_6", new Size(9, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_reterski_1, "items_reterski_1", new Size(3, 10), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_tometik1, "items_tometik1", new Size(6, 10), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_tometik2, "items_tometik2", new Size(10, 10), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_tometik3, "items_tometik3", new Size(8, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_necklaces_1, "items_necklaces_1", new Size(10, 3), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_weapons_2, "items_weapons_2", new Size(7, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_weapons_3, "items_weapons_3", new Size(13, 5), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_armours_2, "items_armours_2", sz7x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_armours_3, "items_armours_3", new Size(10, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_rings_1, "items_rings_1", new Size(10, 3), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_japozero, "items_japozero", new Size(16, 37), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_rijackson_1, "items_rijackson_1", new Size(5, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_g03_package_omi1, "items_g03_package_omi1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_consumables_omi1, "items_consumables_omi1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_feygard1, "items_feygard1", new Size(6, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.items_omi2, "items_omi2", new Size(6, 5), sz1x1, mTileSize);
/*INSERT_ITEMS_TILESETS_HERE*/
loader.prepareTileset(R.drawable.monsters_armor1, "monsters_armor1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_cyclops, "monsters_cyclops", sz1x1, sz2x3, mTileSize);
loader.prepareTileset(R.drawable.monsters_demon1, "monsters_demon1", sz1x1, sz2x2, mTileSize);
loader.prepareTileset(R.drawable.monsters_demon2, "monsters_demon2", sz1x1, sz2x2, mTileSize);
loader.prepareTileset(R.drawable.monsters_dogs, "monsters_dogs", sz7x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_eye1, "monsters_eye1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_eye2, "monsters_eye2", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_eye3, "monsters_eye3", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_eye4, "monsters_eye4", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_ghost1, "monsters_ghost1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_hydra1, "monsters_hydra1", sz1x1, sz2x2, mTileSize);
loader.prepareTileset(R.drawable.monsters_insects, "monsters_insects", sz6x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_karvis1, "monsters_karvis1", sz2x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_karvis2, "monsters_karvis2", new Size(9, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_ld1, "monsters_ld1", new Size(20, 12), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_ld2, "monsters_ld2", new Size(20, 12), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_liches, "monsters_liches", new Size(4, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_mage, "monsters_mage", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_mage2, "monsters_mage2", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_man1, "monsters_man1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_men, "monsters_men", new Size(9, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_men2, "monsters_men2", new Size(10, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_misc, "monsters_misc", new Size(13, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rats, "monsters_rats", new Size(5, 1), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_redshrike1, "monsters_redshrike1", sz7x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rltiles1, "monsters_rltiles1", new Size(20, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rltiles2, "monsters_rltiles2", new Size(20, 9), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rltiles3, "monsters_rltiles3", new Size(10, 3), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rltiles4, "monsters_rltiles4", new Size(12, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_rogue1, "monsters_rogue1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_skeleton1, "monsters_skeleton1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_skeleton2, "monsters_skeleton2", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_snakes, "monsters_snakes", sz6x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik1, "monsters_tometik1", new Size(10, 9), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik2, "monsters_tometik2", new Size(8, 10), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik3, "monsters_tometik3", new Size(6, 13), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik4, "monsters_tometik4", new Size(6, 13), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik5, "monsters_tometik5", new Size(6, 16), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik6, "monsters_tometik6", new Size(7, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik7, "monsters_tometik7", new Size(8, 11), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik8, "monsters_tometik8", new Size(7, 9), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik9, "monsters_tometik9", new Size(8, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_tometik10, "monsters_tometik10", new Size(6, 13), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_wraiths, "monsters_wraiths", sz3x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_zombie1, "monsters_zombie1", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_zombie2, "monsters_zombie2", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_guynmart, "monsters_guynmart", new Size(8, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_maksiu1, "monsters_maksiu1", new Size(4, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_omi1, "monsters_omi1", sz2x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_omi1_b, "monsters_omi1_b", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_unknown, "monsters_unknown", sz1x1, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_arulirs, "monsters_arulirs", new Size(8, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_fatboy73, "monsters_fatboy73", new Size(20, 12), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_giantbasilisk, "monsters_giantbasilisk", sz1x1, sz2x2, mTileSize);
loader.prepareTileset(R.drawable.monsters_gisons, "monsters_gisons", new Size(8, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.monsters_bosses_2x2, "monsters_bosses_2x2", sz1x1, sz2x2, mTileSize);
loader.prepareTileset(R.drawable.monsters_omi2, "monsters_omi2", sz8x3, sz1x1, mTileSize);
/*INSERT_NPCS_TILESETS_HERE*/
loader.prepareTileset(R.drawable.map_bed_1, "map_bed_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_border_1, "map_border_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_bridge_1, "map_bridge_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_bridge_2, "map_bridge_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_broken_1, "map_broken_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cavewall_1, "map_cavewall_1", new Size(18, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cavewall_2, "map_cavewall_2", new Size(18, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cavewall_3, "map_cavewall_3", new Size(18, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cavewall_4, "map_cavewall_4", new Size(18, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_chair_table_1, "map_chair_table_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_chair_table_2, "map_chair_table_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_crate_1, "map_crate_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cupboard_1, "map_cupboard_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_curtain_1, "map_curtain_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_entrance_1, "map_entrance_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_entrance_2, "map_entrance_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_fence_1, "map_fence_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_fence_2, "map_fence_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_fence_3, "map_fence_3", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_fence_4, "map_fence_4", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_1, "map_ground_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_2, "map_ground_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_3, "map_ground_3", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_4, "map_ground_4", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_5, "map_ground_5", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_6, "map_ground_6", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_7, "map_ground_7", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_ground_8, "map_ground_8", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_house_1, "map_house_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_house_2, "map_house_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_indoor_1, "map_indoor_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_indoor_2, "map_indoor_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_kitchen_1, "map_kitchen_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_outdoor_1, "map_outdoor_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_pillar_1, "map_pillar_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_pillar_2, "map_pillar_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_plant_1, "map_plant_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_plant_2, "map_plant_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_rock_1, "map_rock_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_rock_2, "map_rock_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_roof_1, "map_roof_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_roof_2, "map_roof_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_roof_3, "map_roof_3", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_shop_1, "map_shop_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_sign_ladder_1, "map_sign_ladder_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_table_1, "map_table_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_table_2, "map_table_2", new Size(14, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_trail_1, "map_trail_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_1, "map_transition_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_2, "map_transition_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_3, "map_transition_3", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_4, "map_transition_4", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_5, "map_transition_5", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_tree_1, "map_tree_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_tree_2, "map_tree_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_wall_1, "map_wall_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_wall_2, "map_wall_2", new Size(15, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_wall_3, "map_wall_3", new Size(15, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_wall_4, "map_wall_4", new Size(15, 8), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_window_1, "map_window_1", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_window_2, "map_window_2", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_guynmart, "map_guynmart", mapTileSize, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_cavewall_5, "map_cavewall_5", new Size(6, 6), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_rock_3, "map_rock_3", new Size(6, 5), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_sign_ladder_omi2, "map_sign_ladder_omi2", new Size(8, 4), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_transition_6, "map_transition_6", new Size(18, 8), sz1x1, mTileSize);
/*INSERT_MAP_TILESETS_HERE*/
loader.prepareTileset(R.drawable.map_0, "map_0", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_1, "map_1", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_10, "map_10", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_11, "map_11", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_12, "map_12", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_13, "map_13", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_14, "map_14", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_15, "map_15", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_16, "map_16", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_17, "map_17", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_18, "map_18", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_19, "map_19", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_2, "map_2", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_20, "map_20", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_21, "map_21", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_22, "map_22", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_23, "map_23", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_24, "map_24", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_25, "map_25", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_26, "map_26", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_27, "map_27", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_28, "map_28", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_29, "map_29", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_3, "map_3", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_30, "map_30", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_31, "map_31", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_32, "map_32", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_33, "map_33", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_34, "map_34", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_35, "map_35", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_36, "map_36", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_37, "map_37", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_38, "map_38", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_39, "map_39", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_4, "map_4", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_40, "map_40", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_41, "map_41", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_42, "map_42", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_43, "map_43", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_44, "map_44", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_45, "map_45", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_46, "map_46", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_47, "map_47", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_48, "map_48", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_49, "map_49", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_5, "map_5", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_50, "map_50", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_51, "map_51", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_52, "map_52", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_53, "map_53", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_54, "map_54", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_6, "map_6", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_7, "map_7", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_8, "map_8", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.map_9, "map_9", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_0, "obj_0", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_1, "obj_1", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_10, "obj_10", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_11, "obj_11", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_12, "obj_12", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_13, "obj_13", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_14, "obj_14", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_2, "obj_2", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_3, "obj_3", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_4, "obj_4", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_5, "obj_5", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_6, "obj_6", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_7, "obj_7", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_8, "obj_8", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.obj_9, "obj_9", sz8x8, sz1x1, mTileSize);
loader.prepareTileset(R.drawable.effect_blood4, "effect_blood4", new Size(7, 2), sz1x1, mTileSize);
loader.prepareTileset(R.drawable.effect_heal2, "effect_heal2", new Size(8, 2), sz1x1, mTileSize);

View File

@@ -1,7 +1,6 @@
package com.gpl.rpg.AndorsTrail.savegames;
import java.io.ByteArrayOutputStream;
import java.io.Console;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -34,358 +33,345 @@ import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
import com.gpl.rpg.AndorsTrail.util.L;
public final class Savegames {
public static final int SLOT_QUICKSAVE = 0;
public static final long DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED = -1;
public static final int SLOT_QUICKSAVE = 0;
public static final long DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED = -1;
private static long lastBackup = 0;
private static long lastBackup = 0;
public static enum LoadSavegameResult {
success, unknownError, savegameIsFromAFutureVersion, cheatingDetected
}
public static boolean saveWorld(WorldContext world, Context androidContext, int slot) {
try {
final String displayInfo = androidContext.getString(R.string.savegame_currenthero_displayinfo, world.model.player.getLevel(), world.model.player.getTotalExperience(), world.model.player.getGold());
if (slot != SLOT_QUICKSAVE && !world.model.statistics.hasUnlimitedSaves()) {
world.model.player.savedVersion++;
}
String id = world.model.player.id;
long savedVersion = world.model.player.savedVersion;
public static enum LoadSavegameResult {
success
, unknownError
, savegameIsFromAFutureVersion
, cheatingDetected
}
// Create the savegame in a temporary memorystream first to ensure that the savegame can
// be created correctly. We don't want to trash the user's file unneccessarily if there is an error.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
saveWorld(world, bos, displayInfo);
byte[] savegame = bos.toByteArray();
bos.close();
public static boolean saveWorld(WorldContext world, Context androidContext, int slot) {
try {
final String displayInfo = androidContext.getString(R.string.savegame_currenthero_displayinfo, world.model.player.getLevel(), world.model.player.getTotalExperience(), world.model.player.getGold());
if (slot != SLOT_QUICKSAVE && !world.model.statistics.hasUnlimitedSaves()) {
world.model.player.savedVersion++;
}
String id = world.model.player.id;
long savedVersion = world.model.player.savedVersion;
FileOutputStream fos = getOutputFile(androidContext, slot);
fos.write(savegame);
fos.close();
// Create the savegame in a temporary memorystream first to ensure that the savegame can
// be created correctly. We don't want to trash the user's file unneccessarily if there is an error.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
saveWorld(world, bos, displayInfo);
byte[] savegame = bos.toByteArray();
bos.close();
if (!world.model.statistics.hasUnlimitedSaves()) {
if (slot != SLOT_QUICKSAVE) {
androidContext.deleteFile(Constants.FILENAME_SAVEGAME_QUICKSAVE);
writeCheatCheck(androidContext, savedVersion, id);
} else if (SystemClock.uptimeMillis() > lastBackup + 120000) {
writeBackup(androidContext, savegame, id);
lastBackup = SystemClock.uptimeMillis();
}
}
FileOutputStream fos = getOutputFile(androidContext, slot);
fos.write(savegame);
fos.close();
return true;
} catch (IOException e) {
L.log("Error saving world: " + e.toString());
return false;
}
}
if (!world.model.statistics.hasUnlimitedSaves()) {
if (slot != SLOT_QUICKSAVE) {
androidContext.deleteFile(Constants.FILENAME_SAVEGAME_QUICKSAVE);
writeCheatCheck(androidContext, savedVersion, id);
} else if (SystemClock.uptimeMillis() > lastBackup + 120000) {
writeBackup(androidContext, savegame, id);
lastBackup = SystemClock.uptimeMillis();
}
}
private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException {
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
ensureDirExists(cheatDetectionFolder);
File backupFile = new File(cheatDetectionFolder, playerId + "X");
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
fileOutputStream.write(savegame);
fileOutputStream.close();
}
return true;
} catch (IOException e) {
L.log("Error saving world: " + e.toString());
return false;
}
}
public static LoadSavegameResult loadWorld(WorldContext world, ControllerContext controllers, Context androidContext, int slot) {
try {
FileHeader fh = quickload(androidContext, slot);
if (fh == null) {
return LoadSavegameResult.unknownError;
}
if (!fh.hasUnlimitedSaves && slot != SLOT_QUICKSAVE && triedToCheat(androidContext, fh)) {
return LoadSavegameResult.cheatingDetected;
}
private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException {
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
File backupFile = new File(cheatDetectionFolder, playerId + "X");
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
fileOutputStream.write(savegame);
fileOutputStream.close();
}
FileInputStream fos = getInputFile(androidContext, slot);
LoadSavegameResult result = loadWorld(androidContext.getResources(), world, controllers, fos, fh);
fos.close();
if (result == LoadSavegameResult.success && slot != SLOT_QUICKSAVE && !world.model.statistics.hasUnlimitedSaves()) {
public static LoadSavegameResult loadWorld(WorldContext world, ControllerContext controllers, Context androidContext, int slot) {
try {
FileHeader fh = quickload(androidContext, slot);
if(fh == null) {
return LoadSavegameResult.unknownError;
}
if (!fh.hasUnlimitedSaves && slot != SLOT_QUICKSAVE && triedToCheat(androidContext, fh)) {
return LoadSavegameResult.cheatingDetected;
}
FileInputStream fos = getInputFile(androidContext, slot);
LoadSavegameResult result = loadWorld(androidContext.getResources(), world, controllers, fos, fh);
fos.close();
if (result == LoadSavegameResult.success && slot != SLOT_QUICKSAVE && !world.model.statistics.hasUnlimitedSaves()) {
// save to the quicksave slot before deleting the file
if (!saveWorld(world, androidContext, SLOT_QUICKSAVE)) {
return LoadSavegameResult.unknownError;
}
getSlotFile(slot, androidContext).delete();
writeCheatCheck(androidContext, DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED, fh.playerId);
}
return result;
} catch (IOException e) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Error loading world: " + e.toString());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
L.log("Load error: " + sw.toString());
}
return LoadSavegameResult.unknownError;
}
}
return LoadSavegameResult.unknownError;
}
getSlotFile(slot, androidContext).delete();
writeCheatCheck(androidContext, DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED, fh.playerId);
}
return result;
} catch (IOException e) {
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Error loading world: " + e.toString());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
L.log("Load error: " + sw.toString());
}
return LoadSavegameResult.unknownError;
}
}
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
long savedVersionToCheck = 0;
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
ensureDirExists(cheatDetectionFolder);
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
if (cheatDetectionFile.exists()) {
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
savedVersionToCheck = cheatDetection.savedVersion;
dataInputStream.close();
fileInputStream.close();
}
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
long savedVersionToCheck = 0;
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
if (cheatDetectionFile.exists()) {
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
savedVersionToCheck = cheatDetection.savedVersion;
dataInputStream.close();
fileInputStream.close();
}
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
return true;
}
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
return true;
}
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
} else if (cheatDetection.savedVersion > savedVersionToCheck) {
savedVersionToCheck = cheatDetection.savedVersion;
}
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
}
else if (cheatDetection.savedVersion > savedVersionToCheck) {
savedVersionToCheck = cheatDetection.savedVersion;
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
}
dataInputStream.close();
fileInputStream.close();
}
dataInputStream.close();
fileInputStream.close();
}
return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck);
}
return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck);
}
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
if (slot == SLOT_QUICKSAVE) {
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
} else {
ensureSavegameDirectoryExists(androidContext);
return new FileOutputStream(getSlotFile(slot, androidContext));
}
}
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
if (slot == SLOT_QUICKSAVE) {
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
} else {
ensureSavegameDirectoryExists(androidContext);
return new FileOutputStream(getSlotFile(slot, androidContext));
}
}
private static void ensureSavegameDirectoryExists(Context context) {
File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
if (!dir.exists()) dir.mkdir();
}
private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException {
if (slot == SLOT_QUICKSAVE) {
return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE);
} else {
return new FileInputStream(getSlotFile(slot, androidContext));
}
}
private static void ensureSavegameDirectoryExists(Context context) {
File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
ensureDirExists(dir);
}
public static boolean ensureDirExists(File dir) {
if (!dir.exists()) {
boolean worked = dir.mkdir();
return worked;
}
return true;
}
private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException {
if (slot == SLOT_QUICKSAVE) {
return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE);
} else {
return new FileInputStream(getSlotFile(slot, androidContext));
}
}
public static File getSlotFile(int slot, Context context) {
File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
return getSlotFile(slot, root);
}
public static File getSlotFile(int slot, File directory) {
return new File(directory, getSlotFileName(slot));
}
public static String getSlotFileName(int slot) {
return Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot;
}
public static File getSlotFile(int slot, Context context) {
File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
return new File(root, Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot);
}
public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException {
DataOutputStream dest = new DataOutputStream(outStream);
FileHeader.writeToParcel(dest, world.model.player.getName(),
displayInfo, world.model.player.iconID,
world.model.statistics.isDead(),
world.model.statistics.hasUnlimitedSaves(),
world.model.player.id,
world.model.player.savedVersion);
world.maps.writeToParcel(dest, world);
world.model.writeToParcel(dest);
dest.close();
}
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
DataInputStream src = new DataInputStream(inState);
final FileHeader header = new FileHeader(src, fh.skipIcon);
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION)
return LoadSavegameResult.savegameIsFromAFutureVersion;
public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException {
DataOutputStream dest = new DataOutputStream(outStream);
FileHeader.writeToParcel(dest, world.model.player.getName(),
displayInfo, world.model.player.iconID,
world.model.statistics.isDead(),
world.model.statistics.hasUnlimitedSaves(),
world.model.player.id,
world.model.player.savedVersion);
world.maps.writeToParcel(dest, world);
world.model.writeToParcel(dest);
dest.close();
}
world.maps.readFromParcel(src, world, controllers, header.fileversion);
world.model = new ModelContainer(src, world, controllers, header.fileversion);
src.close();
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
DataInputStream src = new DataInputStream(inState);
final FileHeader header = new FileHeader(src, fh.skipIcon);
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION) return LoadSavegameResult.savegameIsFromAFutureVersion;
if (header.fileversion < 45) {
LegacySavegamesContentAdaptations.adaptToNewContentForVersion45(world, controllers, res);
}
world.maps.readFromParcel(src, world, controllers, header.fileversion);
world.model = new ModelContainer(src, world, controllers, header.fileversion);
src.close();
if (header.fileversion < 45) {
LegacySavegamesContentAdaptations.adaptToNewContentForVersion45(world, controllers, res);
}
onWorldLoaded(res, world, controllers);
onWorldLoaded(res, world, controllers);
return LoadSavegameResult.success;
}
return LoadSavegameResult.success;
}
private static void onWorldLoaded(Resources res, WorldContext world, ControllerContext controllers) {
controllers.actorStatsController.recalculatePlayerStats(world.model.player);
controllers.mapController.resetMapsNotRecentlyVisited();
controllers.movementController.prepareMapAsCurrentMap(world.model.currentMaps.map, res, false);
controllers.gameRoundController.resetRoundTimers();
}
private static void onWorldLoaded(Resources res, WorldContext world, ControllerContext controllers) {
controllers.actorStatsController.recalculatePlayerStats(world.model.player);
controllers.mapController.resetMapsNotRecentlyVisited();
controllers.movementController.prepareMapAsCurrentMap(world.model.currentMaps.map, res, false);
controllers.gameRoundController.resetRoundTimers();
}
public static FileHeader quickload(Context androidContext, int slot) {
try {
if (slot != SLOT_QUICKSAVE) {
File f = getSlotFile(slot, androidContext);
if (!f.exists()) return null;
}
FileInputStream fos = getInputFile(androidContext, slot);
DataInputStream src = new DataInputStream(fos);
final FileHeader header = new FileHeader(src, false);
src.close();
fos.close();
return header;
} catch (Exception e) {
return null;
}
}
public static FileHeader quickload(Context androidContext, int slot) {
try {
if (slot != SLOT_QUICKSAVE) {
File f = getSlotFile(slot, androidContext);
if (!f.exists()) return null;
}
FileInputStream fos = getInputFile(androidContext, slot);
DataInputStream src = new DataInputStream(fos);
final FileHeader header = new FileHeader(src, false);
src.close();
fos.close();
return header;
} catch (Exception e) {
return null;
}
}
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
dataOutputStream.close();
fileOutputStream.close();
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
ensureDirExists(cheatDetectionFolder);
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
dataOutputStream.close();
fileOutputStream.close();
fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE);
dataOutputStream = new DataOutputStream(fileOutputStream);
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
dataOutputStream.close();
fileOutputStream.close();
}
fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE);
dataOutputStream = new DataOutputStream(fileOutputStream);
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
dataOutputStream.close();
fileOutputStream.close();
}
private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)");
private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)");
public static List<Integer> getUsedSavegameSlots(Context context) {
try {
final List<Integer> result = new ArrayList<Integer>();
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
@Override
public boolean accept(File f, String filename) {
Matcher m = savegameFilenamePattern.matcher(filename);
if (m != null && m.matches()) {
result.add(Integer.parseInt(m.group(1)));
return true;
}
return false;
}
});
Collections.sort(result);
return result;
} catch (Exception e) {
return null;
}
}
public static List<Integer> getUsedSavegameSlots(Context context) {
try {
final List<Integer> result = new ArrayList<Integer>();
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
@Override
public boolean accept(File f, String filename) {
Matcher m = savegameFilenamePattern.matcher(filename);
if (m != null && m.matches()) {
result.add(Integer.parseInt(m.group(1)));
return true;
}
return false;
}
});
Collections.sort(result);
return result;
} catch (Exception e) {
return new ArrayList<Integer>();
}
}
private static final class CheatDetection {
public final int fileversion;
public final long savedVersion;
private static final class CheatDetection {
public final int fileversion;
public final long savedVersion;
// ====== PARCELABLE ===================================================================
// ====== PARCELABLE ===================================================================
public CheatDetection(DataInputStream src) throws IOException {
this.fileversion = src.readInt();
this.savedVersion = src.readLong();
}
public CheatDetection(DataInputStream src) throws IOException {
this.fileversion = src.readInt();
this.savedVersion = src.readLong();
}
public static void writeToParcel(DataOutputStream dest, long savedVersion) throws IOException {
dest.writeInt(AndorsTrailApplication.CURRENT_VERSION);
dest.writeLong(savedVersion);
}
}
public static void writeToParcel(DataOutputStream dest, long savedVersion) throws IOException {
dest.writeInt(AndorsTrailApplication.CURRENT_VERSION);
dest.writeLong(savedVersion);
}
}
public static final class FileHeader {
public final int fileversion;
public final String playerName;
public final String displayInfo;
public final int iconID;
public boolean skipIcon = false;
public final boolean isDead;
public final boolean hasUnlimitedSaves;
public final String playerId;
public final long savedVersion;
public String describe() {
return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo;
}
public static final class FileHeader {
public final int fileversion;
public final String playerName;
public final String displayInfo;
public final int iconID;
public boolean skipIcon = false;
public final boolean isDead;
public final boolean hasUnlimitedSaves;
public final String playerId;
public final long savedVersion;
public String describe() {
return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo;
}
// ====== PARCELABLE ===================================================================
// ====== PARCELABLE ===================================================================
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
int fileversion = src.readInt();
if (fileversion == 11)
fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
this.fileversion = fileversion;
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
this.playerName = src.readUTF();
this.displayInfo = src.readUTF();
} else {
this.playerName = null;
this.displayInfo = null;
}
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
int fileversion = src.readInt();
if (fileversion == 11) fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
this.fileversion = fileversion;
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
this.playerName = src.readUTF();
this.displayInfo = src.readUTF();
} else {
this.playerName = null;
this.displayInfo = null;
}
if (fileversion >= 43) {
int id = src.readInt();
if (skipIcon || id > TileManager.LAST_HERO) {
this.iconID = TileManager.CHAR_HERO_0;
this.skipIcon = true;
} else {
this.iconID = id;
}
} else {
this.iconID = TileManager.CHAR_HERO_0;
}
if (fileversion >= 43) {
int id = src.readInt();
if (skipIcon || id > TileManager.LAST_HERO) {
this.iconID = TileManager.CHAR_HERO_0;
this.skipIcon = true;
} else {
this.iconID = id;
}
} else {
this.iconID = TileManager.CHAR_HERO_0;
}
if (fileversion >= 49) {
this.isDead = src.readBoolean();
this.hasUnlimitedSaves = src.readBoolean();
this.playerId = src.readUTF();
this.savedVersion = src.readLong();
} else {
this.isDead = false;
this.hasUnlimitedSaves = true;
this.playerId = "";
this.savedVersion = 0;
}
}
if (fileversion >= 49) {
this.isDead = src.readBoolean();
this.hasUnlimitedSaves = src.readBoolean();
this.playerId = src.readUTF();
this.savedVersion = src.readLong();
} else {
this.isDead = false;
this.hasUnlimitedSaves = true;
this.playerId = "";
this.savedVersion = 0;
}
}
public static void writeToParcel(DataOutputStream dest, String playerName, String displayInfo, int iconID, boolean isDead, boolean hasUnlimitedSaves, String playerId, long savedVersion) throws IOException {
dest.writeInt(AndorsTrailApplication.CURRENT_VERSION);
dest.writeUTF(playerName);
dest.writeUTF(displayInfo);
dest.writeInt(iconID);
dest.writeBoolean(isDead);
dest.writeBoolean(hasUnlimitedSaves);
dest.writeUTF(playerId);
dest.writeLong(savedVersion);
}
}
public static void writeToParcel(DataOutputStream dest, String playerName, String displayInfo, int iconID, boolean isDead, boolean hasUnlimitedSaves, String playerId, long savedVersion) throws IOException {
dest.writeInt(AndorsTrailApplication.CURRENT_VERSION);
dest.writeUTF(playerName);
dest.writeUTF(displayInfo);
dest.writeInt(iconID);
dest.writeBoolean(isDead);
dest.writeBoolean(hasUnlimitedSaves);
dest.writeUTF(playerId);
dest.writeLong(savedVersion);
}
}
}

View File

@@ -1,16 +1,10 @@
package com.gpl.rpg.AndorsTrail.util;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.content.FileProvider;
import android.support.v4.provider.DocumentFile;
import android.webkit.MimeTypeMap;
import com.gpl.rpg.AndorsTrail.controller.Constants;
@@ -23,14 +17,14 @@ import java.io.OutputStream;
public final class AndroidStorage {
public static File getStorageDirectory(Context context, String name) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return context.getExternalFilesDir(name);
} else {
}
else {
File root = Environment.getExternalStorageDirectory();
return new File(root, name);
}
}
public static boolean shouldMigrateToInternalStorage(Context context) {
boolean ret = false;
File externalSaveGameDirectory = new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY);
@@ -42,7 +36,7 @@ public final class AndroidStorage {
&& (
!internalSaveGameDirectory.exists()
|| internalSaveGameDirectory.isDirectory() && internalSaveGameDirectory.listFiles().length < 2)
) {
) {
ret = true;
}
return ret;
@@ -82,90 +76,35 @@ public final class AndroidStorage {
}
}
public static void copyFile(File source, File target) throws IOException {
try (InputStream in = new FileInputStream(source); OutputStream out = new FileOutputStream(target)) {
copyStream(in, out);
private static void copyFile(File source, File target) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(source);
out = new FileOutputStream(target);
byte[] buf = new byte[1024];
int length;
while ((length = in.read(buf)) > 0) {
out.write(buf, 0, length);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int length;
while ((length = in.read(buf)) > 0) {
out.write(buf, 0, length);
}
}
public static void copyDocumentFileToNewOrExistingFile(DocumentFile sourceFile, ContentResolver resolver, DocumentFile targetFolder) throws IOException {
copyDocumentFileToNewOrExistingFile(sourceFile, resolver, targetFolder, Constants.NO_FILE_EXTENSION_MIME_TYPE);
}
public static void copyDocumentFileToNewOrExistingFile(DocumentFile sourceFile, ContentResolver resolver, DocumentFile targetFolder, String mimeType) throws IOException {
String fileName = sourceFile.getName();
DocumentFile file = targetFolder.findFile(fileName);
if (file == null)
file = targetFolder.createFile(mimeType, fileName);
if (file == null)
return;
AndroidStorage.copyDocumentFile(sourceFile, resolver, file);
}
public static void copyDocumentFile(DocumentFile sourceFile, ContentResolver resolver, DocumentFile targetFile) throws IOException {
try (OutputStream outputStream = resolver.openOutputStream(targetFile.getUri());
InputStream inputStream = resolver.openInputStream(sourceFile.getUri())) {
copyStream(inputStream, outputStream);
}
}
/**
* Gets the MIME-Type for a file.<p/>
* Fallback value is '* / *' (without spaces) <p/>
* Mostly copied together from: <a href="https://stackoverflow.com/q/8589645/17292289">StackOverflow</a>
*/
@NonNull
public static String getMimeType(ContentResolver resolver, Uri uri) {
String type = null;
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
type = resolver.getType(uri);
return type;
}
final String extension = MimeTypeMap.getFileExtensionFromUrl(uri.getPath());
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
}
if (type == null) {
type = "*/*"; // fallback type.
}
return type;
}
public static String getUrlForFile(Context context, File worldmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Uri uri = FileProvider.getUriForFile(context, "com.gpl.rpg.AndorsTrail_beta2.fileprovider", worldmap);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
String applicationId = context.getPackageName();
// Uri uri = FileProvider.getUriForFile(context, "com.gpl.rpg.AndorsTrail.fileprovider", worldmap);
Uri uri = FileProvider.getUriForFile(context, applicationId + ".fileprovider", worldmap);
return uri.toString();
} else {
return "file://" + worldmap.getAbsolutePath();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static Intent getNewOpenDirectoryIntent() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
return intent;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static Intent getNewSelectMultipleSavegameFilesIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setType(Constants.SAVEGAME_FILE_MIME_TYPE);
return intent;
}
}

View File

@@ -0,0 +1,16 @@
package com.gpl.rpg.AndorsTrail.util;
import java.util.HashMap;
public final class HashMapHelper {
public static <K,V> V getOrDefault(HashMap<K,V> map, K key, V defaultValue) {
V v = map.get(key);
return v == null ? defaultValue : v;
}
public static <K> Integer sumIntegerValues(HashMap<K,Integer> map) {
int sum = 0;
for (Integer v : map.values()) sum += v;
return sum;
}
}

View File

@@ -22,167 +22,156 @@ import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
public class CustomDialogFactory {
public static class CustomDialog extends Dialog {
public CustomDialog(Context context) {
super(context);
}
}
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons) {
return createDialog(context, title, icon, desc, content, hasButtons, true);
}
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons, final boolean canDismiss) {
final CustomDialog dialog = new CustomDialog(new ContextThemeWrapper(context, ThemeHelper.getDialogTheme())) {
@Override
public boolean onTouchEvent(MotionEvent event) {
Rect r = new Rect();
this.getWindow().getDecorView().findViewById(R.id.dialog_hitrect).getHitRect(r);
if (r.contains((int) event.getX(), (int) event.getY())) {
return super.onTouchEvent(event);
} else {
if (canDismiss) {
this.dismiss();
return true;
}
return false;
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
TextView title = (TextView) this.getWindow().getDecorView().findViewById(R.id.dialog_title);
if (title != null && title.getCompoundDrawables() != null && title.getCompoundDrawables()[0] != null) {
if (title.getCompoundDrawables()[0] instanceof AnimationDrawable) {
((AnimationDrawable) title.getCompoundDrawables()[0]).start();
}
}
}
};
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.custom_dialog_title_icon);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
if (((AndorsTrailApplication) context.getApplicationContext()).getPreferences().fullscreen) {
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
dialog.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
setTitle(dialog, title, icon);
setDesc(dialog, desc);
setContent(dialog, content);
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
if (hasButtons) {
buttonsHolder.setVisibility(View.VISIBLE);
} else {
buttonsHolder.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog createErrorDialog(final Context context, String title, String description) {
final CustomDialog d = createDialog(context,
title,
context.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
description,
null,
true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
return d;
}
public static CustomDialog setTitle(final CustomDialog dialog, String title, Drawable icon) {
TextView titleView = (TextView) dialog.findViewById(R.id.dialog_title);
if (title != null || icon != null) {
titleView.setText(title);
titleView.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
titleView.setVisibility(View.VISIBLE);
} else {
titleView.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog setDesc(final CustomDialog dialog, String desc) {
TextView descView = (TextView) dialog.findViewById(R.id.dialog_description);
ViewGroup descHolder = (ViewGroup) dialog.findViewById(R.id.dialog_description_container);
if (desc != null) {
descView.setText(desc);
descHolder.setVisibility(View.VISIBLE);
descView.setVisibility(View.VISIBLE);
} else {
descHolder.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog setContent(final CustomDialog dialog, View content) {
ViewGroup contentHolder = (ViewGroup) dialog.findViewById(R.id.dialog_content_container);
if (content != null) {
contentHolder.addView(content);
contentHolder.setVisibility(View.VISIBLE);
} else {
contentHolder.setVisibility(View.GONE);
}
return dialog;
}
public static Dialog addButton(final Dialog dialog, int textId, final OnClickListener listener) {
Button template = (Button) dialog.findViewById(R.id.dialog_template_button);
LayoutParams params = template.getLayoutParams();
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
Button b = new Button(dialog.getContext());
b.setLayoutParams(params);
//Old android versions need this "reminder"
b.setBackgroundDrawable(ThemeHelper.getThemeDrawable(dialog.getContext(), R.attr.ui_theme_textbutton_drawable));
b.setTextColor(ThemeHelper.getThemeColor(dialog.getContext(), R.attr.ui_theme_dialogue_light_color));
b.setText(textId);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(v);
dialog.dismiss();
}
});
buttonsHolder.addView(b, params);
return dialog;
}
public static Dialog addDismissButton(final Dialog dialog, int textId) {
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
public static Dialog setDismissListener(Dialog dialog, OnDismissListener listener) {
dialog.setOnDismissListener(listener);
return dialog;
}
public static void show(Dialog dialog) {
dialog.findViewById(R.id.dialog_template_button).setVisibility(View.GONE);
dialog.show();
}
public static class CustomDialog extends Dialog {
public CustomDialog(Context context) {
super(context);
}
}
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons) {
return createDialog(context, title, icon, desc, content, hasButtons, true);
}
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons, final boolean canDismiss) {
final CustomDialog dialog = new CustomDialog(new ContextThemeWrapper(context, ThemeHelper.getDialogTheme())) {
@Override
public boolean onTouchEvent(MotionEvent event) {
Rect r = new Rect();
this.getWindow().getDecorView().findViewById(R.id.dialog_hitrect).getHitRect(r);
if (r.contains((int)event.getX(), (int)event.getY())) {
return super.onTouchEvent(event);
} else {
if (canDismiss) {
this.dismiss();
return true;
}
return false;
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
TextView title = (TextView) this.getWindow().getDecorView().findViewById(R.id.dialog_title);
if (title != null && title.getCompoundDrawables() != null && title.getCompoundDrawables()[0] != null) {
if (title.getCompoundDrawables()[0] instanceof AnimationDrawable) {
((AnimationDrawable)title.getCompoundDrawables()[0]).start();
}
}
}
};
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.custom_dialog_title_icon);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
if (((AndorsTrailApplication)context.getApplicationContext()).getPreferences().fullscreen) {
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
dialog.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
setTitle(dialog, title, icon);
setDesc(dialog, desc);
setContent(dialog, content);
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
if (hasButtons) {
buttonsHolder.setVisibility(View.VISIBLE);
} else {
buttonsHolder.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog setTitle(final CustomDialog dialog, String title, Drawable icon) {
TextView titleView = (TextView) dialog.findViewById(R.id.dialog_title);
if (title != null || icon != null) {
titleView.setText(title);
titleView.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
titleView.setVisibility(View.VISIBLE);
} else {
titleView.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog setDesc(final CustomDialog dialog, String desc) {
TextView descView = (TextView) dialog.findViewById(R.id.dialog_description);
ViewGroup descHolder = (ViewGroup) dialog.findViewById(R.id.dialog_description_container);
if (desc != null) {
descView.setText(desc);
descHolder.setVisibility(View.VISIBLE);
descView.setVisibility(View.VISIBLE);
} else {
descHolder.setVisibility(View.GONE);
}
return dialog;
}
public static CustomDialog setContent(final CustomDialog dialog, View content) {
ViewGroup contentHolder = (ViewGroup) dialog.findViewById(R.id.dialog_content_container);
if (content != null) {
contentHolder.addView(content);
contentHolder.setVisibility(View.VISIBLE);
} else {
contentHolder.setVisibility(View.GONE);
}
return dialog;
}
public static Dialog addButton(final Dialog dialog, int textId, final OnClickListener listener) {
Button template = (Button) dialog.findViewById(R.id.dialog_template_button);
LayoutParams params = template.getLayoutParams();
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
Button b = new Button(dialog.getContext());
b.setLayoutParams(params);
//Old android versions need this "reminder"
b.setBackgroundDrawable(ThemeHelper.getThemeDrawable(dialog.getContext(), R.attr.ui_theme_textbutton_drawable));
b.setTextColor(ThemeHelper.getThemeColor(dialog.getContext(), R.attr.ui_theme_dialogue_light_color));
b.setText(textId);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(v);
dialog.dismiss();
}
});
buttonsHolder.addView(b, params);
return dialog;
}
public static Dialog addDismissButton(final Dialog dialog, int textId) {
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
public static Dialog setDismissListener(Dialog dialog, OnDismissListener listener) {
dialog.setOnDismissListener(listener);
return dialog;
}
public static void show(Dialog dialog) {
dialog.findViewById(R.id.dialog_template_button).setVisibility(View.GONE);
dialog.show();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,47 @@
I put both (release notes + forum announcement) into this source, so it will be easier to maintain them parallel:
APK 66 (0.8.2) //Sullengard Bugfix
Release notes
=============
* Fix of a lost traveler in certain conditions
Forum announcement //2022-10-09
==================
Hello fellow adventurers,
we fixed a bug in the last Andor's Trail release to ensure the quest "Recovering stolen property" can be completed.
Also some more XP and better loot in Sullengard area.
Here is the link to the productive version: [url]https://andorstrail.com/static/AndorsTrail_v0.8.2.apk[/url]
Google Play and Itch will follow soon, and hopefully this version can also be provided by F-Droid again.
APK 65 (0.8.1) //Engine modernization + Sullengard
Release notes
=============
* New city Sullengard
* 71 new maps and 6 new quests
* Monster kill count
* Controller support
* Translation updates
* Engine changes to support actual Android Studio
Forum beta announcement //2022-09-28
=======================
Hello fellow adventurers,
it took a while - much longer than we planned - but it was worth the wait:
[list]We have a big update with 71 new maps and 6 new quests for you![/list]
[list]3 Additions from Guro-meditation-No42:
[list]3 Additions from Guru-meditation-No42:
[list]Kill count summed up for monsters with same name (a minor irritation)[/list]
[list]Show kills of monsters in monster stat view (often requested)[/list]
[list]Controller support (not yet tested)[/list]
@@ -51,58 +82,6 @@ Google Play and Itch will follow soon, and hopefully this version can also be pr
Thx for your patience - have fun with the new release!
Forum beta announcement //2022-08-27
=======================
Hello fellow adventurers,
it took a while - much longer than we planned - but it was worth the wait:
[list]We have a big update with 71 new maps and 6 new quests for you![/list]
[list]3 Additions from Guro-meditation-No42:
[list]Kill count summed up for monsters with same name (a minor irritation)[/list]
[list]Show kills of monsters in monster stat view (often requested)[/list]
[list]Controller support (not yet tested)[/list]
[/list]
[list]Also we modernized the engine (Many thanks to OMGeeky), so that you can now use the current Android Studio version to create the APK.
This will be easier for new developers, and it should enable F-Droid to publish Andor's Trail again![/list]
Enough reason to start a new release number: v0.8
There is a big new area and a new city called Sullengard to the southeast - follow the Duleian road, you can't miss it. But beware, the beasts are really dangerous!! Don't venture there too early or you'll find yourself waking up in a bed more often than you want...
On your way to Sullengard you may find two quests
[list]"Hunting the hunter" [/list]
[list]"Getting home on time"[/list]
Look for these two quests in Sullengard:
[list]"Pond safety"[/list]
[list]"Recovering stolen property"[/list]
The following two quests are found elsewhere:
[list]"Beer Bootlegging" starts at the Foaming flask[/list]
[list]"Another ruthless Crackshot" not only sounds like thieves affairs, so ask at the Guild.[/list]
I won't tell more about the quests, I trust you to find out yourself - it's more fun after all.
In good tradition we first publish a beta here in the forum.
What do you think of the new parts? What is good and what is not so good? Can you play properly with a console?
Of course let us know if you find any errors or inconsistencies (preferably with a screenshot).
Keep in mind that savegames of a beta version will not work later in any product version!
The beta is a separate APK now, so you can have both (beta and product version) parallel in your device. New Android versions will keep the savegames of beta and prod.version separate too.
Here now is the link to v0.8.1 beta version: [url]https://andorstrail.com/static/AndorsTrail_v0.8.1beta.apk[/url]
As always: Best make a backup of your savegames first to be sure.
Thx for your patience - have fun with the beta!
Forum announcement //2022-02-20
==================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Some files were not shown because too many files have changed in this diff Show More