Compare commits

..

11 Commits

Author SHA1 Message Date
Zukero
4a4cf36c02 New game objects methods available in scripting language. 2013-12-15 23:17:27 +01:00
Zukero
5886e746b5 Added player.base.ac & player.base.bc variables in scripting language. 2013-12-01 15:59:59 +01:00
Zukero
fc97efdf75 Engine updates.
New in-game hooks : item.onEquip & item.onUnequip
Many new variables accessible in scripting language :
- player.base.[maxAP, maxHP, ad.min, ad.max, equipCost, moveCost,
useCost]
- actor.[hp.cur, hp.max, ap.cur, ap.max, ad.min, ad.max]
2013-12-01 15:56:44 +01:00
Zukero
0d7ab1a710 Forgot to include new package to index in last commit... 2013-11-20 23:21:15 +01:00
Zukero
43e374e5d3 Items usage effects can be impacted (AP, HP), need to add some kind of
array support in the scripting language to add impact on actor
conditions.
ActorConditions can have scripted effects.
New values in the debug data to test it all ! An actor condition makes
your potions give twice as much HP !
2013-11-19 23:54:28 +01:00
Zukero
05dae1bc74 New primitive operator : '%' used for string concatenation. Works using
.toString(), so it's rather type independant.
New in-game hook : item.onUse. Unfinished because it can't impact te
effects of the item, only add more effects (positive or negative)
New local variable scope awareness system. No-more "all-purpose"
Hashmap, but a dedicated object.
2013-11-18 23:26:13 +01:00
Zukero
f592207470 New in-game hook : player.statsUpdated to be used by Actor Conditions,
items (and skills in the future) to impact player's stats (AC, BC, AD,
HP...)
Enhanced local variables handling by script parser. Now scope-aware.
Implemented the public vs private scripts system : some game objects
have private scripts, that get executed only when the object itself is
the cause of the event. Included example is a special case :
player.statsUpdated runs the player's actor condtion and equiped items
private scripts that trigger on plyaer.statsUpdated.
Added scripts reference parsing in JSON parsers, hooked to items and
actor conditions.
2013-11-16 17:19:05 +01:00
Zukero
8a62fb847f Rebased on latest upstream master 2013-11-04 20:49:56 +01:00
Zukero
0028d361c6 Almost full engine rewrite. Only grammar & in-game hooking system kept.
* No script text interpreter anymore
* Scripts are statically compiled to an object AST
* Engine can evaluate the script's AST without reflection, and minimum
casting
* Script local variables are preallocated, but without scope awareness
yet (declare them all at top level scope for max efficiency)
* While loop added
* Boolean AND and OR added.
* Boolean constants true & false added.
* String constants can be used as local variables.
2013-11-04 20:47:50 +01:00
Zukero
57a88f437f Engine updates
* Slightly more efficient interpreter
* ScriptEngine now implements existing listener interface instead of
in-code hooks
Language updates :
* actor references now expose the addActorCondition &
clearActorCondition methods
2013-11-04 20:47:49 +01:00
Zukero
9a8e7d3cb7 First working version of my scripting engine.
* Only two trigger types : map.onEnter & map.onLeave
* Very limited field access : player.ac; player.bc & map.outdoor
However, it is integrated & tested.
2013-11-04 20:44:12 +01:00
2184 changed files with 213265 additions and 4178428 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,14 +0,0 @@
dist: bionic
sudo: required
cache:
directories:
- $HOME/pbuilder-bases
matrix:
include:
- env: TARGET_OS=stretch
before_install:
- "$TRAVIS_BUILD_DIR/travis/$TRAVIS_OS_NAME.$TARGET_OS.before_install"
install:
- "$TRAVIS_BUILD_DIR/travis/$TRAVIS_OS_NAME.$TARGET_OS.install"
script:
- "$TRAVIS_BUILD_DIR/travis/$TRAVIS_OS_NAME.$TARGET_OS.script"

9
AndorsTrail/.classpath Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -1,12 +1,8 @@
# Android ignores
gen/
bin/
target/
local.properties
app/build/intermediates/
build/
debug/
release/
.gradle/
#IntelliJ
.idea/
@@ -18,35 +14,3 @@ out/test/
# Other
.metadata
.svn/
#copied from https://github.com/github/gitignore/blob/main/Gradle.gitignore
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
#copied from https://github.com/github/gitignore/blob/main/Gradle.gitignore
/AndorsTrail/.gradle
/AndorsTrail/gradle/wrapper
/AndorsTrail/app/build/
/AndorsTrail/app/debug/
/AndorsTrail/app/release/

33
AndorsTrail/.project Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>AndorsTrail</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="EclipseModuleManager" forced_jdk="true">
<conelement value="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK" />
<conelement value="com.android.ide.eclipse.adt.LIBRARIES" />
<src_description expected_position="1">
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
<src_folder value="file://$MODULE_DIR$/gen" expected_position="1" />
</src_description>
</component>
<component name="FacetManager">
<facet type="android" name="Android">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/bin/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/libs/android-support-v4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gpl.rpg.AndorsTrail"
android:versionCode="40"
android:versionName="0.7.1dev"
android:installLocation="auto"
>
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="17"
/>
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"
/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
/>
<application
android:name=".AndorsTrailApplication"
android:label="@string/app_name"
android:icon="@drawable/icon"
android:description="@string/app_description"
android:allowBackup="true"
>
<activity
android:name=".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:label="@string/app_name"
android:theme="@style/Theme.NoBackground"
/>
<activity android:name=".activity.HeroinfoActivity" />
<activity android:name=".activity.MonsterInfoActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.ItemInfoActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.LevelUpActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.MonsterEncounterActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.ConversationActivity" android:theme="@android:style/Theme.Dialog" />
<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="@android:style/Theme.Dialog" />
<activity android:name=".activity.ActorConditionInfoActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.BulkSelectionInterface" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.SkillInfoActivity" android:theme="@android:style/Theme.Dialog" />
<activity android:name=".activity.DisplayWorldMapActivity" />
</application>
</manifest>

View File

@@ -1,77 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 34
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.gpl.rpg.AndorsTrail"
minSdkVersion 14
targetSdkVersion 34
}
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'
signingConfig signingConfigs.debug
}
}
namespace 'com.gpl.rpg.AndorsTrail'
sourceSets {
main {
res.srcDirs = ['build/gen-res', 'src/main/res']
assets.srcDirs = ['build/gen-assets', 'src/main/assets']
}
}
}
dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.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}/build/gen-res"
rename "(.*)\\.tmx", "\$1.xml"
}
task copyResValuesIn(type: Copy) {
description "Exception Indonesian language code (Old IN was renamed to now ID)"
from "${rootDir}/res/values-id/"
into "${projectDir}/build/gen-res/values-in/"
}
task copyTranslation(type: Copy) {
description("Copies the translation files to the modules translations folder")
from "${rootDir}/assets/translation"
into "${projectDir}/build/gen-assets/translation"
}
task cleanup(type: Delete) {
description("Deletes the assets/translation and the res folder from the modules folder")
delete "${projectDir}/build/gen-res", "${projectDir}/build/gen-assets/translation"
}
afterEvaluate {
project.tasks.copyRes.dependsOn project.tasks.copyResValuesIn
mergeDebugResources.dependsOn project.tasks.copyRes
extractDeepLinksDebug.dependsOn project.tasks.copyRes
mergeReleaseResources.dependsOn project.tasks.copyRes
extractDeepLinksRelease.dependsOn project.tasks.copyRes
mergeDebugAssets.dependsOn project.tasks.copyTranslation
mergeReleaseAssets.dependsOn project.tasks.copyTranslation
extractDeepLinksDebug.dependsOn project.tasks.copyTranslation
extractDeepLinksRelease.dependsOn project.tasks.copyTranslation
clean.dependsOn project.tasks.cleanup
}

View File

@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gpl.rpg.AndorsTrail"
android:versionCode="74"
android:versionName="0.8.8"
android:installLocation="auto"
>
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"
/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name="com.gpl.rpg.AndorsTrail.AndorsTrailApplication"
android:label="@string/app_name"
android:icon="@drawable/${icon_name}"
android:description="@string/app_description"
android:allowBackup="true"
android:theme="@style/AndorsTrailTheme_Blue"
android:requestLegacyExternalStorage="true"
android:hasFragileUserData="true"
android:preserveLegacyExternalStorage="true"
>
<activity
android:exported="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="com.gpl.rpg.AndorsTrail.activity.MainActivity"
android:label="@string/app_name"
android:theme="@style/AndorsTrailTheme_Blue.NoBackground"
/>
<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="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fileprovider" />
</provider>
</application>
</manifest>

View File

@@ -1,169 +0,0 @@
package com.gpl.rpg.AndorsTrail;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
import com.gpl.rpg.AndorsTrail.util.Pair;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Environment;
import android.view.Window;
import android.view.WindowManager;
public final class AndorsTrailApplication extends Application {
public static final boolean DEVELOPMENT_DEBUGRESOURCES = false;
public static final boolean DEVELOPMENT_FORCE_STARTNEWGAME = false;
public static final boolean DEVELOPMENT_FORCE_CONTINUEGAME = false;
public static final boolean DEVELOPMENT_DEBUGBUTTONS = false;
public static final boolean DEVELOPMENT_FASTSPEED = false;
public static final boolean DEVELOPMENT_VALIDATEDATA = false;
public static final boolean DEVELOPMENT_DEBUGMESSAGES = false;
public static final String CURRENT_VERSION_DISPLAY = "0.8.8";
public static final boolean IS_RELEASE_VERSION = !CURRENT_VERSION_DISPLAY.matches(".*[a-d].*");
public static final boolean DEVELOPMENT_INCOMPATIBLE_SAVEGAMES = DEVELOPMENT_DEBUGRESOURCES || DEVELOPMENT_DEBUGBUTTONS || DEVELOPMENT_FASTSPEED || !IS_RELEASE_VERSION;
public static final int DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION = 999;
public static final int CURRENT_VERSION = DEVELOPMENT_INCOMPATIBLE_SAVEGAMES ? DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION : 74;
private final AndorsTrailPreferences preferences = new AndorsTrailPreferences();
private WorldContext world = new WorldContext();
private ControllerContext controllers = new ControllerContext(this, world);
private WorldSetup setup = new WorldSetup(world, controllers, this);
public WorldContext getWorld() { return world; }
public WorldSetup getWorldSetup() { return setup; }
public AndorsTrailPreferences getPreferences() { return preferences; }
public ControllerContext getControllerContext() { return controllers; }
public static AndorsTrailApplication getApplicationFromActivity(Activity activity) {
return ((AndorsTrailApplication) activity.getApplication());
}
public static AndorsTrailApplication getApplicationFromActivityContext(Context context) {
return getApplicationFromActivity(getActivityFromActivityContext(context));
}
private static Activity getActivityFromActivityContext(Context context) {
return (Activity) context;
}
public boolean isInitialized() { return world.model != null; }
public void setWindowParameters(Activity activity) {
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
if (preferences.fullscreen) {
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
activity.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
//Get default locale at startup, as somehow it seems that changing the app's
//configured locale impacts the value returned by Locale.getDefault() nowadays.
private final Locale defaultLocale = Locale.getDefault();
private Pair<String, Locale> lastLocale = null;
public boolean setLocale(Activity context) {
Resources res = context.getResources();
Configuration conf = res.getConfiguration();
Locale targetLocale;
if (lastLocale != null && lastLocale.first == preferences.language) {
targetLocale = lastLocale.second;
} else {
targetLocale = localeForLanguageTag(preferences.language);
lastLocale = new Pair<String, Locale>(preferences.language, targetLocale);
}
if (targetLocale.equals(conf.locale)) {
return false;
}
conf.locale = targetLocale;
res.updateConfiguration(conf, res.getDisplayMetrics());
this.getResources().updateConfiguration(conf, res.getDisplayMetrics());
return true;
}
// Supports language or language_COUNTRY in short form e.g. "en" or "en_US"
private Locale localeForLanguageTag(String languageTag) {
Locale locale = null;
if (languageTag != null && !languageTag.equalsIgnoreCase("default")) {
final int pos = languageTag.indexOf('-');
if (pos == -1) {
locale = new Locale(languageTag);
}
else locale = new Locale(languageTag.substring(0, pos), languageTag.substring(pos+1));
}
if (locale == null) {
locale = defaultLocale;
}
return locale;
}
/**
* Logging to text file system as found on https://stackoverflow.com/questions/19565685/saving-logcat-to-a-text-file-in-android-device
*/
public void onCreate() {
super.onCreate();
if ( DEVELOPMENT_DEBUGMESSAGES && isExternalStorageWritable() ) {
File appDirectory = AndroidStorage.getStorageDirectory(getApplicationContext(), Constants.FILENAME_SAVEGAME_DIRECTORY);
File logDirectory = new File( appDirectory, "log" );
File logFile = new File( logDirectory, "logcat" + System.currentTimeMillis() + ".txt" );
// create app folder
if ( !appDirectory.exists() ) {
appDirectory.mkdir();
}
// create log folder
if ( !logDirectory.exists() ) {
logDirectory.mkdir();
}
// clear the previous logcat and then write the new one to the file
try {
Process process = Runtime.getRuntime().exec("logcat -c");
process = Runtime.getRuntime().exec("logcat -f " + logFile+" *:W");
} catch ( IOException e ) {
e.printStackTrace();
}
}
}
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals( state ) ) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals( state ) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals( state ) ) {
return true;
}
return false;
}
public void discardWorld() {
world = new WorldContext();
controllers = new ControllerContext(this, world);
setup = new WorldSetup(world, controllers, getApplicationContext());
}
}

View File

@@ -1,23 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.app.Activity;
import android.os.Bundle;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
public abstract class AndorsTrailBaseActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
@Override
protected void onResume() {
super.onResume();
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
}

View File

@@ -1,22 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
public abstract class AndorsTrailBaseFragmentActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
@Override
protected void onResume() {
super.onResume();
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
}

View File

@@ -1,362 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.view.MainView;
import android.content.Context;
import android.content.res.Resources;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.Toast;
public final class DebugInterface {
private final ControllerContext controllerContext;
private final MainActivity mainActivity;
private final Resources res;
private final WorldContext world;
private DebugButton[] buttons;
private List<DebugButton> tpButtons = new ArrayList<DebugButton>();
private List<DebugButton> tpButtons2 = new ArrayList<DebugButton>();
public DebugInterface(ControllerContext controllers, WorldContext world, MainActivity mainActivity) {
this.controllerContext = controllers;
this.world = world;
this.res = mainActivity.getResources();
this.mainActivity = mainActivity;
}
public void addDebugButtons() {
if (!AndorsTrailApplication.DEVELOPMENT_DEBUGBUTTONS) return;
List<DebugButton> buttonList = new ArrayList<DebugButton>();
buttonList.addAll(Arrays.asList(new DebugButton[] {
new DebugButton("dbg", new OnClickListener() {
boolean hidden = false;
@Override
public void onClick(View arg0) {
hidden = !hidden;
for (int i = 1; i < buttons.length; i++) {
buttons[i].b.setVisibility(hidden ? View.GONE : View.VISIBLE);
}
for (DebugButton b : tpButtons) {
b.b.setVisibility(View.GONE);
}
for (DebugButton b : tpButtons2) {
b.b.setVisibility(View.GONE);
}
}
})
,new DebugButton("teleport", new OnClickListener() {
public void onClick(View arg0) {
for (int i = 0; i < buttons.length; i++) {
buttons[i].b.setVisibility(View.GONE);
}
for (DebugButton tpButton : tpButtons) {
tpButton.b.setVisibility(View.VISIBLE);
}
}
})
,new DebugButton("dmg", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.damagePotential.set(500, 500);
world.model.player.attackChance = 500;
world.model.player.attackCost = 1;
showToast(mainActivity, "DEBUG: damagePotential=500, chance=500%, cost=1", Toast.LENGTH_SHORT);
}
})
/*,new DebugButton("dmg=1", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.damagePotential.set(1, 1);
showToast(mainActivity, "DEBUG: damagePotential=1", Toast.LENGTH_SHORT);
}
})*/
,new DebugButton("itm", new OnClickListener() {
@Override
public void onClick(View arg0) {
for (ItemType item : world.itemTypes.UNITTEST_getAllItemTypes().values()) {
world.model.player.inventory.addItem(item, 10);
}
world.model.player.inventory.gold += 50000;
showToast(mainActivity, "DEBUG: added items", Toast.LENGTH_SHORT);
}
})
,new DebugButton("xp", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.actorStatsController.addExperience(10000);
showToast(mainActivity, "DEBUG: given 10000 exp", Toast.LENGTH_SHORT);
}
})
,new DebugButton("rst", new OnClickListener() {
@Override
public void onClick(View arg0) {
for(PredefinedMap map : world.maps.getAllMaps()) {
map.resetTemporaryData();
}
showToast(mainActivity, "DEBUG: maps respawned", Toast.LENGTH_SHORT);
}
})
,new DebugButton("hp", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.baseTraits.maxHP = 500;
world.model.player.health.max = world.model.player.baseTraits.maxHP;
controllerContext.actorStatsController.setActorMaxHealth(world.model.player);
world.model.player.conditions.clear();
showToast(mainActivity, "DEBUG: hp set to max", Toast.LENGTH_SHORT);
}
})
,new DebugButton("skl", new OnClickListener() {
@Override
public void onClick(View arg0) {
world.model.player.availableSkillIncreases += 10;
showToast(mainActivity, "DEBUG: 10 skill points", Toast.LENGTH_SHORT);
}
})
,new DebugButton("spd", new OnClickListener() {
boolean fast = Constants.MINIMUM_INPUT_INTERVAL == Constants.MINIMUM_INPUT_INTERVAL_FAST;
@Override
public void onClick(View arg0) {
fast = !fast;
if (fast) {
Constants.MINIMUM_INPUT_INTERVAL = Constants.MINIMUM_INPUT_INTERVAL_FAST;
} else {
Constants.MINIMUM_INPUT_INTERVAL = Constants.MINIMUM_INPUT_INTERVAL_STD;
}
MainView.SCROLL_DURATION = Constants.MINIMUM_INPUT_INTERVAL;
AndorsTrailApplication.getApplicationFromActivity(mainActivity).getControllerContext().movementController.resetMovementHandler();
}
})
,new DebugButton("map", new OnClickListener() {
@Override
public void onClick(View arg0) {
showToast(mainActivity, "DEBUG: map=" + world.model.currentMaps.map.name , Toast.LENGTH_SHORT);
}
})
}));
tpButtons.addAll(Arrays.asList(new DebugButton[] {
new DebugButton("teleport", new OnClickListener() {
@Override
public void onClick(View arg0) {
for (DebugButton tpButton : tpButtons2) {
tpButton.b.setVisibility(View.VISIBLE);
}
for (DebugButton tpButton : tpButtons) {
tpButton.b.setVisibility(View.GONE);
}
}
})
,new DebugButton("cg", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "crossglen", "hall", 0, 0);
}
})
,new DebugButton("vg", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "vilegard_s", "tavern", 0, 0);
}
})
,new DebugButton("cr", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "houseatcrossroads4", "down", 0, 0);
}
})
,new DebugButton("lf", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "loneford9", "south", 0, 0);
}
})
,new DebugButton("fh", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "fallhaven_ne", "clothes", 0, 0);
}
})
,new DebugButton("prm", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "blackwater_mountain29", "south", 0, 0);
}
})
,new DebugButton("bwm", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "blackwater_mountain43", "south", 0, 0);
}
})
,new DebugButton("rmg", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "remgard0", "east", 0, 0);
}
})
,new DebugButton("chr", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "waytolostmine2", "minerhouse4", 0, 0);
}
})
,new DebugButton("ldr", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "lodarhouse0", "lodarhouse", 0, 0);
}
})
,new DebugButton("sf", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "wild20", "south2", 0, 0);
}
})
,new DebugButton("gm", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "guynmart_wood_1", "farmhouse", 0, 0);
}
})
}));
buttonList.addAll(tpButtons);
tpButtons2.addAll(Arrays.asList(new DebugButton[] {
new DebugButton("teleport", new OnClickListener() {
@Override
public void onClick(View arg0) {
for (int i = 0; i < buttons.length; i++) {
buttons[i].b.setVisibility(View.VISIBLE);
}
for (DebugButton tpButton : tpButtons) {
tpButton.b.setVisibility(View.GONE);
}
for (DebugButton tpButton : tpButtons2) {
tpButton.b.setVisibility(View.GONE);
}
}
})
,new DebugButton("brv", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "brimhaven4", "south2", 0, 0);
}
})
,new DebugButton("aru", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "mountainlake5", "north", 0, 0);
}
})
,new DebugButton("ws", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "woodsettlement0", "east", 0, 0);
}
})
,new DebugButton("sul", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "sullengard2", "south", 0, 0);
}
})
,new DebugButton("gal", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "galmore_19", "south", 0, 0);
}
})
,new DebugButton("apl", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "sullengard_apple_farm_east", "house", 0, 0);
}
})
,new DebugButton("wch", new OnClickListener() {
@Override
public void onClick(View arg0) {
controllerContext.movementController.placePlayerAsyncAt(MapObject.MapObjectType.newmap, "lake_shore_road_0", "west", 0, 0);
}
})
}));
buttonList.addAll(tpButtons2);
buttons = buttonList.toArray(new DebugButton[buttonList.size()]);
addDebugButtons(buttons);
for (DebugButton b : tpButtons) {
b.b.setVisibility(View.GONE);
}
for (DebugButton b : tpButtons2) {
b.b.setVisibility(View.GONE);
}
}
private void showToast(Context context, String msg, int duration) {
Toast.makeText(context, msg, duration).show();
}
private static class DebugButton {
public final String text;
public final OnClickListener listener;
public Button b = null;
public DebugButton(String text, OnClickListener listener) {
this.text = text;
this.listener = listener;
}
public void makeButton(Context c, int id) {
b = new Button(c);
b.setText(text);
b.setTextSize(10);//res.getDimension(R.dimen.actionbar_text));
b.setId(id);
b.setOnClickListener(listener);
}
}
private void addDebugButton(DebugButton button, int id, RelativeLayout layout) {
if (!AndorsTrailApplication.DEVELOPMENT_DEBUGBUTTONS) return;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, res.getDimensionPixelSize(R.dimen.smalltext_buttonheight));
if (id == 1)
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
else
lp.addRule(RelativeLayout.RIGHT_OF, id - 1);
lp.addRule(RelativeLayout.ABOVE, R.id.main_statusview);
button.makeButton(mainActivity, id);
button.b.setLayoutParams(lp);
layout.addView(button.b);
}
private void addDebugButtons(DebugButton[] buttons) {
if (!AndorsTrailApplication.DEVELOPMENT_DEBUGBUTTONS) return;
if (buttons == null || buttons.length <= 0) return;
RelativeLayout layout = (RelativeLayout) mainActivity.findViewById(R.id.main_container);
int id = 1;
for (DebugButton b : buttons) {
addDebugButton(b, id, layout);
++id;
}
}
}

View File

@@ -1,168 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import java.io.File;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.WorldMapController;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment;
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.WorldMapSegmentMap;
import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.L;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.Toast;
public final class DisplayWorldMapActivity extends AndorsTrailBaseActivity {
private WorldContext world;
private WebView displayworldmap_webview;
private String worldMapSegmentName;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getBaseTheme());
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
if (!app.isInitialized()) { finish(); return; }
this.world = app.getWorld();
app.setWindowParameters(this);
setContentView(R.layout.displayworldmap);
displayworldmap_webview = (WebView) findViewById(R.id.displayworldmap_webview);
displayworldmap_webview.setBackgroundColor(ThemeHelper.getThemeColor(this, R.attr.ui_theme_displayworldmap_bg_color));
displayworldmap_webview.getSettings().setBuiltInZoomControls(true);
displayworldmap_webview.getSettings().setUseWideViewPort(true);
displayworldmap_webview.setVerticalScrollBarEnabled(true);
displayworldmap_webview.setHorizontalScrollBarEnabled(true);
displayworldmap_webview.getSettings().setAllowFileAccess(true);
enableJavascript();
Button b = (Button) findViewById(R.id.displayworldmap_close);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
DisplayWorldMapActivity.this.finish();
}
});
b = (Button) findViewById(R.id.displayworldmap_recenter);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
recenter();
}
});
worldMapSegmentName = getIntent().getStringExtra("worldMapSegmentName");
}
@SuppressLint("SetJavaScriptEnabled")
public void enableJavascript() {
displayworldmap_webview.getSettings().setJavaScriptEnabled(true);
}
@Override
public void onResume() {
super.onResume();
update();
}
WorldMapSegmentMap map;
Coord offsetWorldmapTo;
@SuppressLint("NewApi")
private void update() {
File worldmap = WorldMapController.getCombinedWorldMapFile(this, worldMapSegmentName);
if (!worldmap.exists()) {
Toast.makeText(this, getResources().getString(R.string.menu_button_worldmap_failed), Toast.LENGTH_LONG).show();
this.finish();
}
WorldMapSegment segment = world.maps.worldMapSegments.get(worldMapSegmentName);
map = segment.maps.get(world.model.currentMaps.map.name);
if (map == null) {
this.finish();
return;
}
offsetWorldmapTo = new Coord(999999, 999999);
for (WorldMapSegmentMap map : segment.maps.values()) {
PredefinedMap predefinedMap = world.maps.findPredefinedMap(map.mapName);
if (predefinedMap == null) continue;
if (!predefinedMap.visited) continue;
if (!WorldMapController.fileForMapExists(this, predefinedMap)) continue;
offsetWorldmapTo.x = Math.min(offsetWorldmapTo.x, map.worldPosition.x);
offsetWorldmapTo.y = Math.min(offsetWorldmapTo.y, map.worldPosition.y);
}
String url = AndroidStorage.getUrlForFile(this, worldmap) + '?'
+ (world.model.player.position.x + map.worldPosition.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE
+ ','
+ (world.model.player.position.y + map.worldPosition.y-1) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE;
L.log("Showing " + url);
displayworldmap_webview.loadUrl(url);
displayworldmap_webview.setBackgroundColor(ThemeHelper.getThemeColor(this, R.attr.ui_theme_displayworldmap_bg_color));
displayworldmap_webview.setWebViewClient(new WebViewClient() {
@SuppressLint("NewApi")
@Override
public void onPageFinished(WebView view, String url)
{
recenter();
}
});
}
private void recenter() {
displayworldmap_webview.postDelayed(new Runnable() {
@Override
public void run() {
if (map != null) {
//Local map to global worldmap
int x = world.model.player.position.x + map.worldPosition.x - offsetWorldmapTo.x;
//Tile coord to pixel coord
x *= WorldMapController.WORLDMAP_DISPLAY_TILESIZE;
x += WorldMapController.WORLDMAP_DISPLAY_TILESIZE/2;
//Zoom level
x = (int)(x * displayworldmap_webview.getScale());
//Center
x -= displayworldmap_webview.getWidth() / 2;
//Local map to global worldmap
int y = world.model.player.position.y + map.worldPosition.y - offsetWorldmapTo.y;
//Tile coord to pixel coord
y *= WorldMapController.WORLDMAP_DISPLAY_TILESIZE;
y += WorldMapController.WORLDMAP_DISPLAY_TILESIZE/2;
//Zoom level
y = (int)(y * displayworldmap_webview.getScale());
//Center
y -= displayworldmap_webview.getHeight() / 2;
displayworldmap_webview.scrollTo(x, y);
}
}
}, 100);
}
@Override
public void finish() {
ViewGroup view = (ViewGroup) getWindow().getDecorView();
view.removeAllViews();
super.finish();
}
}

View File

@@ -1,97 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.fragment.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.activity.fragment.HeroinfoActivity_Inventory;
import com.gpl.rpg.AndorsTrail.activity.fragment.HeroinfoActivity_Quests;
import com.gpl.rpg.AndorsTrail.activity.fragment.HeroinfoActivity_Skills;
import com.gpl.rpg.AndorsTrail.activity.fragment.HeroinfoActivity_Stats;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
public final class HeroinfoActivity extends AndorsTrailBaseFragmentActivity {
private WorldContext world;
private FragmentTabHost tabHost;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getBaseTheme());
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
if (!app.isInitialized()) { finish(); return; }
this.world = app.getWorld();
app.setWindowParameters(this);
setContentView(R.layout.tabbedlayout);
Resources res = getResources();
tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
LayoutInflater inflater = getLayoutInflater();
ViewGroup v;
v = (ViewGroup) inflater.inflate(R.layout.tabindicator, null);
((TextView)v.findViewById(R.id.tabindicator_text)).setText(res.getString(R.string.heroinfo_char));
((ImageView)v.findViewById(R.id.tabindicator_icon)).setImageDrawable(res.getDrawable(R.drawable.char_hero));
tabHost.addTab(tabHost.newTabSpec("char")
.setIndicator(v)
,HeroinfoActivity_Stats.class, null);
v = (ViewGroup) inflater.inflate(R.layout.tabindicator, null);
((TextView)v.findViewById(R.id.tabindicator_text)).setText(res.getString(R.string.heroinfo_quests));
((ImageView)v.findViewById(R.id.tabindicator_icon)).setImageDrawable(res.getDrawable(R.drawable.ui_icon_quest));
tabHost.addTab(tabHost.newTabSpec("quests")
.setIndicator(v)
,HeroinfoActivity_Quests.class, null);
v = (ViewGroup) inflater.inflate(R.layout.tabindicator, null);
((TextView)v.findViewById(R.id.tabindicator_text)).setText(res.getString(R.string.heroinfo_skill));
((ImageView)v.findViewById(R.id.tabindicator_icon)).setImageDrawable(res.getDrawable(R.drawable.ui_icon_skill));
tabHost.addTab(tabHost.newTabSpec("skills")
.setIndicator(v)
,HeroinfoActivity_Skills.class, null);
v = (ViewGroup) inflater.inflate(R.layout.tabindicator, null);
((TextView)v.findViewById(R.id.tabindicator_text)).setText(res.getString(R.string.heroinfo_inv));
((ImageView)v.findViewById(R.id.tabindicator_icon)).setImageDrawable(res.getDrawable(R.drawable.ui_icon_equipment));
tabHost.addTab(tabHost.newTabSpec("inv")
.setIndicator(v)
,HeroinfoActivity_Inventory.class, null);
String t = world.model.uiSelections.selectedTabHeroInfo;
if (t != null && t.length() > 0) {
tabHost.setCurrentTabByTag(t);
}
updateIconForPlayer();
}
@Override
protected void onResume() {
super.onResume();
updateIconForPlayer();
}
private void updateIconForPlayer() {
ImageView iv = (ImageView) tabHost.getTabWidget().getChildTabViewAt(0).findViewById(R.id.tabindicator_icon);
world.tileManager.setImageViewTileForPlayer(getResources(), iv, world.model.player.iconID);
}
@Override
protected void onPause() {
super.onPause();
world.model.uiSelections.selectedTabHeroInfo = tabHost.getCurrentTabTag();
}
}

View File

@@ -1,876 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import android.Manifest;
import android.app.Activity;
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 androidx.annotation.RequiresApi;
import androidx.documentfile.provider.DocumentFile;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.TextView;
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;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
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 exportImportContainer = (ViewGroup) findViewById(R.id.loadsave_export_import_save_container);
addSavegameSlotButtons(slotList, params, Savegames.getUsedSavegameSlots(this));
checkAndRequestPermissions();
if (!isLoading) {
createNewSlot.setTag(SLOT_NUMBER_CREATE_NEW_SLOT);
createNewSlot.setOnClickListener(this);
newSlotContainer.setVisibility(View.VISIBLE);
exportImportContainer.setVisibility(View.GONE);
} else {
newSlotContainer.setVisibility(View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
exportSaves.setOnClickListener(this);
importSaves.setOnClickListener(this);
importWorldmap.setOnClickListener(this);
exportImportContainer.setVisibility(View.VISIBLE);
boolean hasSavegames = !Savegames.getUsedSavegameSlots(this).isEmpty();
exportSaves.setEnabled(hasSavegames);
} else {
exportImportContainer.setVisibility(View.GONE);
}
}
}
private static final int READ_EXTERNAL_STORAGE_REQUEST = 1;
private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 2;
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 cancelLoadSaveActivity(int slot) {
completeLoadSaveActivity(slot, false);
}
private void completeLoadSaveActivity(int slot) {
completeLoadSaveActivity(slot, true);
}
private void completeLoadSaveActivity(int slot, boolean success) {
Intent i = new Intent();
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) {
slot = getFirstFreeSlot();
} else if (slot == SLOT_NUMBER_EXPORT_SAVEGAMES
|| slot == SLOT_NUMBER_IMPORT_SAVEGAMES
|| slot == SLOT_NUMBER_IMPORT_WORLDMAP) {
i.putExtra("import_export", true);
if (slot == SLOT_NUMBER_IMPORT_WORLDMAP) {
i.putExtra("import_worldmap", true);
}
if (slot == SLOT_NUMBER_IMPORT_SAVEGAMES) {
i.putExtra("import_savegames", true);
}
if (slot == SLOT_NUMBER_EXPORT_SAVEGAMES) {
i.putExtra("export", true);
}
} else if (slot < SLOT_NUMBER_FIRST_SLOT) {
slot = SLOT_NUMBER_FIRST_SLOT;
}
i.putExtra("slot", slot);
if (success) {
setResult(Activity.RESULT_OK, i);
} else {
setResult(Activity.RESULT_CANCELED, i);
}
LoadSaveActivity.this.finish();
}
private int getFirstFreeSlot() {
int slot;
List<Integer> usedSlots = Savegames.getUsedSavegameSlots(this);
if (usedSlots.isEmpty()) {
slot = SLOT_NUMBER_FIRST_SLOT;
} else {
slot = Collections.max(usedSlots) + 1;
}
return slot;
}
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.P) {
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 CustomDialog 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
//region Export
@RequiresApi(api = Build.VERSION_CODES.P)
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 target = DocumentFile.fromTreeUri(context, uri);
if (target == null) {
return;
}
File[] files = storageDir.listFiles();
if (files == null) {
showErrorExportingSaveGamesUnknown();
return;
}
boolean hasExistingFiles = false;
for (File file : files) {
String fileName = file.getName();
DocumentFile existingFile = target.findFile(fileName);
if (existingFile != null) {
hasExistingFiles = true;
break;
}
}
if (hasExistingFiles) {
showConfirmOverwriteByExportQuestion(resolver, target, files);
} else {
exportSaveGamesFolderContentToFolder(target, files);
}
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void exportSaveGamesFolderContentToFolder(DocumentFile target, File[] files) {
DocumentFile[] sourceFiles = new DocumentFile[files.length];
File[] worldmapFiles = null;
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isFile()) {
sourceFiles[i] = DocumentFile.fromFile(file);
} else if (file.isDirectory() && Objects.equals(file.getName(),
Constants.FILENAME_WORLDMAP_DIRECTORY)) {
worldmapFiles = file.listFiles();
}
}
Context context = this;
File[] finalWorldmapFiles = worldmapFiles;
CopyFilesToExternalFolder(target, sourceFiles, context, finalWorldmapFiles);
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void CopyFilesToExternalFolder(DocumentFile target,
DocumentFile[] sourceFiles,
Context context,
File[] finalWorldmapFiles) {
AndroidStorage.copyDocumentFilesToDirAsync(sourceFiles,
context,
target,
getString(R.string.loadsave_exporting_savegames),
(success) -> {
if (success) {
CopyWorldmapFilesAsZip(target,
context,
finalWorldmapFiles);
} else {
completeLoadSaveActivity(
SLOT_NUMBER_EXPORT_SAVEGAMES,
false);
}
});
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void CopyWorldmapFilesAsZip(DocumentFile target,
Context context,
File[] finalWorldmapFiles) {
AndroidStorage.createZipDocumentFileFromFilesAsync(finalWorldmapFiles,
context,
target,
Constants.FILENAME_WORLDMAP_DIRECTORY,
getString(R.string.loadsave_exporting_worldmap),
(successWorldmap) -> completeLoadSaveActivity(
SLOT_NUMBER_EXPORT_SAVEGAMES,
successWorldmap));
}
//endregion
@RequiresApi(api = Build.VERSION_CODES.P)
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 = AndorsTrailApplication.getApplicationFromActivity(this)
.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);
}
@RequiresApi(api = Build.VERSION_CODES.P)
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);
}
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void importSaveGames(ContentResolver resolver,
DocumentFile appSavegameFolder,
List<DocumentFile> saveFiles) {
int size = saveFiles.size();
DocumentFile[] sources = new DocumentFile[size];
DocumentFile[] targets = new DocumentFile[size];
boolean saveAsNew = false;
for (int i = 0; i < size; i++) {
DocumentFile file = saveFiles.get(i);
if (file == null) {//null is value a marker that the next should be saved as new
saveAsNew = true;
continue;
}
int slot = getSlotFromSavegameFileName(file.getName());
if (slot == -1) {
//invalid file name
continue;
}
if (saveAsNew) {
slot = getFirstFreeSlot();
saveAsNew = false;
}
String targetName = Savegames.getSlotFileName(slot);
sources[i] = file;
targets[i] = getOrCreateDocumentFile(appSavegameFolder, targetName);
}
AndroidStorage.copyDocumentFilesFromToAsync(sources,
this,
targets,
getString(R.string.loadsave_importing_savegames),
(sucess) -> completeLoadSaveActivity(
SLOT_NUMBER_IMPORT_SAVEGAMES,
sucess));
}
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)) {
return -1;
}
String slotStr = fileName.substring(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX.length());
int slot;
try {
slot = Integer.parseInt(slotStr);
return slot;
} catch (NumberFormatException e) {
return -1;
}
}
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;
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void importWorldmap(Intent data) {
Uri uri = data.getData();
Context context = AndorsTrailApplication.getApplicationFromActivity(this).getApplicationContext();
DocumentFile chosenZip = DocumentFile.fromSingleUri(context, uri);
if (chosenZip == null || !chosenZip.isFile()) {
showErrorImportingWorldmapWrongDirectory();
return;
}
String chosenZipName = chosenZip.getName();
if (!chosenZipName.startsWith(Constants.FILENAME_WORLDMAP_DIRECTORY)) {
showErrorImportingWorldmapWrongDirectory();
return;
}
File ownWorldmapFolder = getOwnWorldmapFolder(context);
AndroidStorage.unzipDocumentFileToDirectoryAsync(chosenZip,
this,
ownWorldmapFolder,
false,
getString(R.string.loadsave_importing_worldmap),
(success) -> completeLoadSaveActivity(
SLOT_NUMBER_IMPORT_WORLDMAP,
success));
}
private File getOwnWorldmapFolder(Context context) {
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
File ownWorldmapFolder = null;
for (File f : storageDir.listFiles()) {
if (f.getName().equals(Constants.FILENAME_WORLDMAP_DIRECTORY)) {
ownWorldmapFolder = f;
break;
}
}
if (ownWorldmapFolder == null) {
ownWorldmapFolder = new File(storageDir, Constants.FILENAME_WORLDMAP_DIRECTORY);
ownWorldmapFolder.mkdir();
}
return ownWorldmapFolder;
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void clickExportSaveGames() {
showStartExportInfo(view -> startActivityForResult(AndroidStorage.getNewOpenDirectoryIntent(),
-SLOT_NUMBER_EXPORT_SAVEGAMES));
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void clickImportSaveGames() {
showStartImportSavesInfo(view -> startActivityForResult(AndroidStorage.getNewSelectMultipleSavegameFilesIntent(),
-SLOT_NUMBER_IMPORT_SAVEGAMES));
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void clickImportWorldmap() {
showStartImportWorldmapInfo(view -> startActivityForResult(AndroidStorage.getNewSelectZipIntent(),
-SLOT_NUMBER_IMPORT_WORLDMAP));
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void showConfirmOverwriteByExportQuestion(ContentResolver resolver,
DocumentFile targetFolder,
File[] files) {
final CustomDialog 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(targetFolder, files));
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
@RequiresApi(api = Build.VERSION_CODES.P)
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_file_exists_question);
StringBuilder sb = new StringBuilder();
sb.append('\n');
int amount = alreadyExistingFiles.size();
Context context = AndorsTrailApplication.getApplicationFromActivity(this).getApplicationContext();
ArrayList<CustomDialog> dialogs = new ArrayList<>(amount);
for (int i = 0; i < amount; i++) {
DocumentFile alreadyExistingFile = alreadyExistingFiles.get(i);
int slot = getSlotFromSavegameFileName(alreadyExistingFile.getName());
FileHeader existingFileHeader = Savegames.quickload(context, slot);
FileHeader importedFileHeader = null;
try (InputStream stream = resolver.openInputStream(alreadyExistingFile.getUri());
DataInputStream dataStream = new DataInputStream(stream)) {
importedFileHeader = new FileHeader(dataStream, true);
} catch (FileNotFoundException e) {
e.printStackTrace();
continue;
} catch (IOException e) {
e.printStackTrace();
continue;
}
StringBuilder messageSb = new StringBuilder();
String existingFileDescription = getString(R.string.loadsave_import_existing_description,
Integer.toString(slot),
existingFileHeader.describe());
String importedFileDescription = getString(R.string.loadsave_import_imported_description,
Integer.toString(slot),
importedFileHeader.describe());
messageSb.append(getString(R.string.loadsave_import_file_exists_question,
existingFileDescription,
importedFileDescription));
String m = messageSb.toString();
CustomDialog dialog = CustomDialogFactory.createDialog(this,
title,
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
m,
null,
true,
false,
true);
CustomDialogFactory.addButton(dialog, R.string.loadsave_import_option_keep_existing, v -> {
//do nothing
GoToNextConflictOrFinish(resolver, appSavegameFolder, newFiles, dialogs);
});
CustomDialogFactory.addButton(dialog, R.string.loadsave_import_option_keep_imported, v -> {
newFiles.add(alreadyExistingFile);
GoToNextConflictOrFinish(resolver, appSavegameFolder, newFiles, dialogs);
});
CustomDialogFactory.addButton(dialog, R.string.loadsave_import_option_add_as_new, v -> {
newFiles.add(null);//add a null element as marker to know later if the next file
// should be imported as new or overwrite the existing one
newFiles.add(alreadyExistingFile);
GoToNextConflictOrFinish(resolver, appSavegameFolder, newFiles, dialogs);
});
CustomDialogFactory.addCancelButton(dialog, android.R.string.cancel);
CustomDialogFactory.setCancelListener(dialog, v -> {
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_SAVEGAMES, false);
});
dialogs.add(dialog);
}
GoToNextConflictOrFinish(resolver, appSavegameFolder, newFiles, dialogs);
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void GoToNextConflictOrFinish(ContentResolver resolver,
DocumentFile appSavegameFolder,
List<DocumentFile> newFiles,
ArrayList<CustomDialog> dialogs) {
if (dialogs.stream().count() > 0) {
CustomDialog d = dialogs.remove(0);
CustomDialogFactory.show(d);
} else {
importSaveGames(resolver, appSavegameFolder, newFiles);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
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
//region Import/Export
@RequiresApi(api = Build.VERSION_CODES.P)
private void showStartExportInfo(OnClickListener onOk) {
final CustomDialog d = CustomDialogFactory.createDialog(this,
getString(R.string.loadsave_export),
getResources().getDrawable(android.R.drawable.ic_dialog_info),
getString(R.string.loadsave_export_info),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, onOk);
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void showStartImportSavesInfo(OnClickListener onOk) {
final CustomDialog d = CustomDialogFactory.createDialog(this,
getString(R.string.loadsave_import_save),
getResources().getDrawable(android.R.drawable.ic_dialog_info),
getString(R.string.loadsave_import_save_info),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, onOk);
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
@RequiresApi(api = Build.VERSION_CODES.P)
private void showStartImportWorldmapInfo(OnClickListener onOk) {
final CustomDialog d = CustomDialogFactory.createDialog(this,
getString(R.string.loadsave_import_worldmap),
getResources().getDrawable(android.R.drawable.ic_dialog_info),
getString(R.string.loadsave_import_worldmap_info),
null,
true);
CustomDialogFactory.addButton(d, android.R.string.yes, onOk);
CustomDialogFactory.addDismissButton(d, android.R.string.no);
CustomDialogFactory.show(d);
}
private void showErrorImportingWorldmapWrongDirectory() {
final CustomDialog d = CustomDialogFactory.createErrorDialog(this,
getString(R.string.loadsave_import_worldmap_unsuccessfull),
getString(R.string.loadsave_import_worldmap_wrong_file));
CustomDialogFactory.show(d);
}
private void showErrorExportingSaveGamesUnknown() {
final CustomDialog d = CustomDialogFactory.createErrorDialog(this,
getString(R.string.loadsave_export_unsuccessfull),
getString(R.string.loadsave_export_error_unknown));
CustomDialogFactory.show(d);
}
//endregion
private void showErrorLoadingEmptySlot() {
final CustomDialog 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 CustomDialog 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 CustomDialog 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
}

View File

@@ -1,180 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.WorldSetup;
import com.gpl.rpg.AndorsTrail.WorldSetup.OnResourcesLoadedListener;
import com.gpl.rpg.AndorsTrail.WorldSetup.OnSceneLoadedListener;
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
import com.gpl.rpg.AndorsTrail.view.CloudsAnimatorView;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
public final class LoadingActivity extends AndorsTrailBaseActivity implements OnResourcesLoadedListener, OnSceneLoadedListener {
private WorldSetup setup;
private CustomDialog progressDialog;
private CloudsAnimatorView clouds_back, clouds_mid, clouds_front;
boolean loaded = false;
private Object semaphore = new Object();
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getBaseTheme());
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setWindowParameters(this);
setContentView(R.layout.startscreen);
TextView tv = (TextView) findViewById(R.id.startscreen_version);
tv.setVisibility(View.GONE);
clouds_back = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_back);
if (clouds_back != null) clouds_back.setCloudsCountAndLayer(40, CloudsAnimatorView.Layer.below);
clouds_mid = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_mid);
if (clouds_mid != null) clouds_mid.setCloudsCountAndLayer(15, CloudsAnimatorView.Layer.center);
clouds_front = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_front);
if (clouds_front != null) clouds_front.setCloudsCountAndLayer(8, CloudsAnimatorView.Layer.above);
this.setup = app.getWorldSetup();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
((AnimationDrawable)((ImageView)findViewById(R.id.title_logo)).getDrawable()).start();
ImageView iv = (ImageView) findViewById(R.id.ts_foreground);
int ivWidth = iv.getWidth();
int drawableWidth = iv.getDrawable().getIntrinsicWidth();
float ratio = ((float)ivWidth) / ((float)drawableWidth);
if (clouds_back != null) {
clouds_back.setScalingRatio(ratio);
}
if (clouds_mid != null) {
clouds_mid.setScalingRatio(ratio);
}
if (clouds_front != null) {
clouds_front.setScalingRatio(ratio);
}
if (progressDialog == null) {
progressDialog = CustomDialogFactory.createDialog(this, getResources().getString(R.string.dialog_loading_message),
getResources().getDrawable(R.drawable.loading_anim), null, null, false, false);
synchronized (semaphore) {
if (!loaded) {
progressDialog.setOwnerActivity(this);
CustomDialogFactory.show(progressDialog);
}
}
}
}
}
@Override
public void onResume() {
super.onResume();
setup.setOnResourcesLoadedListener(this);
final ImageView iv = (ImageView) findViewById(R.id.ts_foreground);
iv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
float[] point = new float[]{0f,0.25f * iv.getDrawable().getIntrinsicHeight()};
iv.getImageMatrix().mapPoints(point);
int imgY = (int) (iv.getTop() + point[1]);
if (clouds_back != null) {
clouds_back.setYMax(imgY);
}
if (clouds_mid != null) {
clouds_mid.setYMax(imgY);
}
if (clouds_front != null) {
clouds_front.setYMax(imgY);
}
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
if (clouds_back != null)clouds_back.resumeAnimation();
if (clouds_mid != null)clouds_mid.resumeAnimation();
if (clouds_front != null)clouds_front.resumeAnimation();
}
@Override
public void onPause() {
super.onPause();
setup.setOnResourcesLoadedListener(null);
setup.removeOnSceneLoadedListener(this);
if (clouds_back != null)clouds_back.pauseAnimation();
if (clouds_mid != null)clouds_mid.pauseAnimation();
if (clouds_front != null)clouds_front.pauseAnimation();
}
@Override
public void onResourcesLoaded() {
loaded = false;
setup.startCharacterSetup(this);
}
@Override
public void onSceneLoaded() {
synchronized (semaphore) {
if (progressDialog != null) progressDialog.dismiss();
loaded =true;
}
startActivity(new Intent(this, MainActivity.class));
this.finish();
}
@Override
public void onSceneLoadFailed(Savegames.LoadSavegameResult loadResult) {
synchronized (semaphore) {
if (progressDialog != null) progressDialog.dismiss();
loaded =true;
}
if (loadResult == Savegames.LoadSavegameResult.savegameIsFromAFutureVersion) {
showLoadingFailedDialog(R.string.dialog_loading_failed_incorrectversion);
} else if (loadResult == Savegames.LoadSavegameResult.cheatingDetected) {
showLoadingFailedDialog(R.string.dialog_loading_failed_cheat);
} else {
showLoadingFailedDialog(R.string.dialog_loading_failed_message);
}
}
private void showLoadingFailedDialog(int messageResourceID) {
final CustomDialog d = CustomDialogFactory.createDialog(this, getResources().getString(R.string.dialog_loading_failed_title), null, getResources().getString(messageResourceID), null, true);
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
CustomDialogFactory.setDismissListener(d, new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
LoadingActivity.this.finish();
}
});
CustomDialogFactory.show(d);
}
}

View File

@@ -1,36 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.Window;
import android.view.WindowManager;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
public final class Preferences extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.getBaseTheme());
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
if (app.getPreferences().fullscreen) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
app.setLocale(this);
addPreferencesFromResource(R.xml.preferences);
}
@Override
protected void onResume() {
super.onResume();
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
app.setLocale(this);
}
}

View File

@@ -1,288 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.activity.fragment.StartScreenActivity_MainMenu;
import com.gpl.rpg.AndorsTrail.activity.fragment.StartScreenActivity_MainMenu.OnNewGameRequestedListener;
import com.gpl.rpg.AndorsTrail.activity.fragment.StartScreenActivity_NewGame;
import com.gpl.rpg.AndorsTrail.activity.fragment.StartScreenActivity_NewGame.GameCreationOverListener;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
import com.gpl.rpg.AndorsTrail.view.CloudsAnimatorView;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity implements OnNewGameRequestedListener, GameCreationOverListener, OnBackStackChangedListener {
private TextView tv;
private TextView development_version;
private CloudsAnimatorView clouds_back, clouds_mid, clouds_front;
private Fragment currentFragment;
//Means false by default, as a toggle is initiated in onCreate.
boolean ui_visible = true;
@Override
public void onCreate(Bundle savedInstanceState) {
initPreferences();
setTheme(ThemeHelper.getBaseTheme());
super.onCreate(savedInstanceState);
final AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
final Resources res = getResources();
TileManager tileManager = app.getWorld().tileManager;
tileManager.setDensity(res);
app.setWindowParameters(this);
setContentView(R.layout.startscreen);
if (findViewById(R.id.startscreen_fragment_container) != null) {
StartScreenActivity_MainMenu mainMenu = new StartScreenActivity_MainMenu();
getSupportFragmentManager().beginTransaction()
.replace(R.id.startscreen_fragment_container, mainMenu)
.commit();
currentFragment = mainMenu;
getSupportFragmentManager().addOnBackStackChangedListener(this);
}
tv = (TextView) findViewById(R.id.startscreen_version);
tv.setText('v' + AndorsTrailApplication.CURRENT_VERSION_DISPLAY);
development_version = (TextView) findViewById(R.id.startscreen_dev_version);
if (AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAMES) {
development_version.setText(R.string.startscreen_incompatible_savegames);
development_version.setVisibility(View.VISIBLE);
} else if (!AndorsTrailApplication.IS_RELEASE_VERSION) {
development_version.setText(R.string.startscreen_non_release_version);
development_version.setVisibility(View.VISIBLE);
}
clouds_back = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_back);
if (clouds_back != null) clouds_back.setCloudsCountAndLayer(40, CloudsAnimatorView.Layer.below);
clouds_mid = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_mid);
if (clouds_mid != null) clouds_mid.setCloudsCountAndLayer(15, CloudsAnimatorView.Layer.center);
clouds_front = (CloudsAnimatorView) findViewById(R.id.ts_clouds_animator_front);
if (clouds_front != null) clouds_front.setCloudsCountAndLayer(8, CloudsAnimatorView.Layer.above);
View background = findViewById(R.id.title_bg);
if (background != null) {
background.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleUiVisibility();
}
});
}
if (development_version.getVisibility() == View.VISIBLE) {
development_version.setText(development_version.getText()
// +
// "\nMax Heap: " + Runtime.getRuntime().maxMemory() / (1024 * 1024) + "MB"+
// "\nUsed Heap: " + Runtime.getRuntime().totalMemory() / (1024 * 1024) + "MB"+
// "\nTile size: " + (int) (32 * res.getDisplayMetrics().density)
);
}
toggleUiVisibility();
app.getWorldSetup().startResourceLoader(res);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
final CustomDialog d = CustomDialogFactory.createDialog(this,
getResources().getString(R.string.dialog_permission_information_title),
getResources().getDrawable(android.R.drawable.ic_dialog_info),
getResources().getString(R.string.dialog_permission_information),
null,
true);
final Activity activity = this;
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
CustomDialogFactory.setDismissListener(d, new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
StartScreenActivity_MainMenu.checkAndRequestPermissions(activity);
}
});
CustomDialogFactory.show(d);
}
}
private void toggleUiVisibility() {
ui_visible = !ui_visible;
int visibility = ui_visible ? View.VISIBLE : View.GONE;
if (tv != null) tv.setVisibility(visibility);
if (!AndorsTrailApplication.IS_RELEASE_VERSION) {
if (development_version != null) development_version.setVisibility(visibility);
}
if (currentFragment != null) {
if (ui_visible) {
if (!AndorsTrailApplication.IS_RELEASE_VERSION) {
development_version.setText(
development_version.getText()
// +
// "\nMax Heap: " + Runtime.getRuntime().maxMemory() / (1024 * 1024) + "MB"+
// "\nUsed Heap: " + Runtime.getRuntime().totalMemory() / (1024 * 1024) + "MB"+
// "\nTile size: " + (int) (32 * getResources().getDisplayMetrics().density)
);
}
getSupportFragmentManager().beginTransaction()
.show(currentFragment)
.commit();
} else {
getSupportFragmentManager().beginTransaction()
.hide(currentFragment)
.commit();
}
}
}
private void initPreferences() {
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
AndorsTrailPreferences preferences = app.getPreferences();
preferences.read(this);
ThemeHelper.changeTheme(preferences.selectedTheme);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
((AnimationDrawable)((ImageView)findViewById(R.id.title_logo)).getDrawable()).start();
ImageView iv = (ImageView) findViewById(R.id.ts_foreground);
int ivWidth = iv.getWidth();
int drawableWidth = iv.getDrawable().getIntrinsicWidth();
float ratio = ((float)ivWidth) / ((float)drawableWidth);
if (clouds_back != null) {
clouds_back.setScalingRatio(ratio);
}
if (clouds_mid != null) {
clouds_mid.setScalingRatio(ratio);
}
if (clouds_front != null) {
clouds_front.setScalingRatio(ratio);
}
}
}
@Override
protected void onResume() {
super.onResume();
final ImageView iv = (ImageView) findViewById(R.id.ts_foreground);
iv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
float[] point = new float[]{0f,0.25f * iv.getDrawable().getIntrinsicHeight()};
iv.getImageMatrix().mapPoints(point);
int imgY = (int) (iv.getTop() + point[1]);
int screenHeight = getResources().getDisplayMetrics().heightPixels;
if (clouds_back != null) {
clouds_back.setYMax(imgY);
}
if (clouds_mid != null) {
clouds_mid.setYMax(imgY);
}
if (clouds_front != null) {
clouds_front.setYMax(imgY);
}
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
if (clouds_back != null)clouds_back.resumeAnimation();
if (clouds_mid != null)clouds_mid.resumeAnimation();
if (clouds_front != null)clouds_front.resumeAnimation();
}
@Override
protected void onPause() {
super.onPause();
if (clouds_back != null)clouds_back.pauseAnimation();
if (clouds_mid != null)clouds_mid.pauseAnimation();
if (clouds_front != null)clouds_front.pauseAnimation();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
backPressed();
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
return super.onKeyDown(keyCode, event);
}
private void backPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
currentFragment = getSupportFragmentManager().findFragmentById(R.id.startscreen_fragment_container);
}
}
public void onNewGameRequested() {
if (findViewById(R.id.startscreen_fragment_container) != null) {
StartScreenActivity_NewGame newGameFragment = new StartScreenActivity_NewGame();
getSupportFragmentManager().beginTransaction()
.replace(R.id.startscreen_fragment_container, newGameFragment)
.addToBackStack(null)
.commit();
currentFragment = newGameFragment;
}
}
@Override
public void onGameCreationCancelled() {
backPressed();
}
@Override
public void onBackStackChanged() {
currentFragment = getSupportFragmentManager().findFragmentById(R.id.startscreen_fragment_container);
}
}

View File

@@ -1,416 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity.fragment;
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
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.LoadingActivity;
import com.gpl.rpg.AndorsTrail.activity.Preferences;
import com.gpl.rpg.AndorsTrail.controller.Constants;
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.L;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
public class StartScreenActivity_MainMenu extends Fragment {
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 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);
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);
}
});
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();
}
}
});
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));
}
});
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 CustomDialog 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);
} else {
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
}
}
});
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);
}
// 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;
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());
}
});
}
}
@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 CustomDialog 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);
CustomDialogFactory.show(d);
if (!AndroidStorage.migrateToInternalStorage(activity.getApplicationContext())) {
final CustomDialog 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() {
// new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AndorsTrailStyle_Dialog))
// .setTitle(R.string.startscreen_newgame)
// .setMessage(R.string.startscreen_newgame_confirm)
// .setIcon(android.R.drawable.ic_delete)
// .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface dialog, int which) {
// //continueGame(true);
//// hasExistingGame = false;
//// setButtonState(null, null, 0);
// createNewGame();
// }
// })
// .setNegativeButton(android.R.string.cancel, null)
// .create().show();
//
//
final CustomDialog 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);
}
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:
boolean unsuccessful = resultCode != Activity.RESULT_OK;
if(data == null) break;
final boolean wasImportOrExport = data.getBooleanExtra("import_export", false);
if (wasImportOrExport) {
String message = getImportExportMessage(!unsuccessful, data);
Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
break;
}
if (unsuccessful) break;
final int slot = data.getIntExtra("slot", 1);
continueGame(false, slot, null);
break;
case INTENTREQUEST_PREFERENCES:
updatePreferences(true);
break;
}
}
private String getImportExportMessage(boolean successful, Intent data) {
String message = "";
boolean isImportWorldmap = data.getBooleanExtra("import_worldmap", false);
boolean isImportSaves = data.getBooleanExtra("import_savegames", false);
boolean isExport = data.getBooleanExtra("export", false);
if(isImportWorldmap) {
message = getString(successful ? R.string.loadsave_import_worldmap_successfull : R.string.loadsave_import_worldmap_unsuccessfull);
} else if(isImportSaves) {
message = getString(successful ? R.string.loadsave_import_save_successfull : R.string.loadsave_import_save_unsuccessfull);
} else if(isExport) {
message = getString(successful ? R.string.loadsave_export_successfull : R.string.loadsave_export_unsuccessfull);
}
return message;
}
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

@@ -1,181 +0,0 @@
package com.gpl.rpg.AndorsTrail.activity.fragment;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.WorldSetup;
import com.gpl.rpg.AndorsTrail.activity.LoadingActivity;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.view.SpinnerEmulator;
public class StartScreenActivity_NewGame extends Fragment {
private TextView startscreen_enterheroname;
private int selectedIconID = TileManager.CHAR_HERO;
private int startLives = -1;
private boolean unlimitedSaves = true;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (container != null) {
container.removeAllViews();
}
View root = inflater.inflate(R.layout.startscreen_newgame, container, false);
startscreen_enterheroname = (TextView) root.findViewById(R.id.startscreen_enterheroname);
new SpinnerEmulator(root, R.id.startscreen_mode_selector_button, R.array.startscreen_mode_selector, R.string.startscreen_game_mode) {
@Override
public void setValue(int value) {
if (value == 0) {
startLives = -1;
unlimitedSaves = true;
} else {
unlimitedSaves = false;
if (value == 1) {
startLives = -1;
} else if (value == 2) {
startLives = 50;
} else if (value == 3) {
startLives = 10;
} else if (value == 4) {
startLives = 3;
} else {
startLives = 1;
}
}
}
@Override
public void selectionChanged(int value) {
}
@Override
public int getValue() {
return 0;
}
};
final RadioGroup group = (RadioGroup) root.findViewById(R.id.newgame_spritegroup);
group.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
ToggleButton tb = ((ToggleButton)group.getChildAt(i));
tb.setChecked(tb.getId() == checkedId);
}
switch (checkedId) {
case R.id.newgame_sprite0:
selectedIconID = TileManager.CHAR_HERO_0;
break;
case R.id.newgame_sprite1:
selectedIconID = TileManager.CHAR_HERO_1;
break;
case R.id.newgame_sprite2:
selectedIconID = TileManager.CHAR_HERO_2;
break;
}
}
});
OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
group.check(v.getId());
}
};
for (int i = 0; i < group.getChildCount(); i++) {
ToggleButton tb = ((ToggleButton)group.getChildAt(i));
tb.setOnClickListener(l);
}
Button b = (Button) root.findViewById(R.id.startscreen_newgame_start);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
createNewGame();
}
});
b = (Button) root.findViewById(R.id.startscreen_newgame_cancel);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
gameCreationOver();
}
});
return root;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
listener = (GameCreationOverListener) activity;
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
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;
setup.newHeroIcon = selectedIconID;
setup.newHeroStartLives = startLives;
setup.newHeroUnlimitedSaves = unlimitedSaves;
gameCreationOver();
startActivity(new Intent(getActivity(), LoadingActivity.class));
}
private void createNewGame() {
String name = startscreen_enterheroname.getText().toString().trim();
if (name == null || name.length() <= 0) {
Toast.makeText(getActivity(), R.string.startscreen_enterheroname, Toast.LENGTH_SHORT).show();
return;
}
continueGame(true, 0, name);
}
public interface GameCreationOverListener {
public void onGameCreationCancelled();
}
private GameCreationOverListener listener = null;
private void gameCreationOver() {
if (listener != null) {
listener.onGameCreationCancelled();
}
}
}

View File

@@ -1,342 +0,0 @@
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;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.L;
public final class InputController implements OnClickListener, OnLongClickListener{
private final ControllerContext controllers;
private final WorldContext world;
private final Coord lastTouchPosition_tileCoords = new Coord();
private int lastTouchPosition_dx = 0;
private int lastTouchPosition_dy = 0;
private long lastTouchEventTime = 0;
private boolean isDpadActive = false;
private int keyState_dx = 0;
private int keyState_dy = 0;
private boolean keyState_attack = false;
private boolean keyState_flee = false;
private boolean keyState_endturn = false;
final private int KEY_UNHANDLED = 0; // Default, for unhandled keycodes
final private int KEY_MOVE_UP = 1;
final private int KEY_MOVE_DOWN = 2;
final private int KEY_MOVE_LEFT = 3;
final private int KEY_MOVE_RIGHT = 4;
final private int KEY_MOVE_UP_LEFT = 5;
final private int KEY_MOVE_UP_RIGHT = 6;
final private int KEY_MOVE_DOWN_LEFT = 7;
final private int KEY_MOVE_DOWN_RIGHT = 8;
final private int KEY_ATTACK = 9;
final private int KEY_FLEE = 10;
final private int KEY_END_TURN = 11;
final private int KEY_HERO_INFO = 12;
final private int KEY_TOOLBOX = 13;
private SparseIntArray keyMap = new SparseIntArray(); // Android keycode to internal key event mapping. TODO: Configure via preferences
public InputController(ControllerContext controllers, WorldContext world) {
this.controllers = controllers;
this.world = world;
initializeKeyMap();
}
/* New keyboard handler. Both Key Down and Key Up events handled here to allow conditional behaviours.
On 4-way dpad controllers, cursor keys, and WASD, diagonals are generated by chording two keys.
Single-key diagonals are supported on numeric keypad and 8-way dpads (not seen/tested in the wild).
Because two-key combos initially generate a ordinal movement (one key comes in first), which can
be dangerous in tight spaces, modifiers are provided to "lock" the input until both keys are down.
TODO: Use delay timer to enable chorded diagonals on first move without locking kludge?
*/
// Map key codes to spectic internal actions
// TODO: Move mapping out of code to JSON/XML file, or maybe player prefs
private void initializeKeyMap() {
int key;
// Keys mapping to UP
key = KEY_MOVE_UP;
keyMap.put(KeyEvent.KEYCODE_DPAD_UP, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_8, key);
keyMap.put(KeyEvent.KEYCODE_8, key);
keyMap.put(KeyEvent.KEYCODE_W, key);
// Keys mapping to DOWN
key = KEY_MOVE_DOWN;
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_2, key);
keyMap.put(KeyEvent.KEYCODE_2, key);
keyMap.put(KeyEvent.KEYCODE_S, key);
// Keys mapping to LEFT
key = KEY_MOVE_LEFT;
keyMap.put(KeyEvent.KEYCODE_DPAD_LEFT, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_4, key);
keyMap.put(KeyEvent.KEYCODE_4, key);
keyMap.put(KeyEvent.KEYCODE_A, key);
// Keys mapping to RIGHT
key = KEY_MOVE_RIGHT;
keyMap.put(KeyEvent.KEYCODE_DPAD_RIGHT, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_6, key);
keyMap.put(KeyEvent.KEYCODE_6, key);
keyMap.put(KeyEvent.KEYCODE_D, key);
// Keys mapping to UP_LEFT
key = KEY_MOVE_UP_LEFT;
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;
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;
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;
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);
// Keys mapping to ATTACK
key = KEY_ATTACK;
keyMap.put(KeyEvent.KEYCODE_DPAD_CENTER, key);
keyMap.put(KeyEvent.KEYCODE_BUTTON_A, key);
keyMap.put(KeyEvent.KEYCODE_SPACE, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_5, key);
// Keys mapping to FLEE
key = KEY_FLEE;
keyMap.put(KeyEvent.KEYCODE_BUTTON_X, key);
keyMap.put(KeyEvent.KEYCODE_F, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, key);
keyMap.put(KeyEvent.KEYCODE_ENTER, key);
// Keys mapping to END_TURN
key = KEY_END_TURN;
keyMap.put(KeyEvent.KEYCODE_BUTTON_Y, key);
keyMap.put(KeyEvent.KEYCODE_E, key);
keyMap.put(KeyEvent.KEYCODE_FORWARD_DEL, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_DOT, key);
// Keys mapping to HERO_INFO
key = KEY_HERO_INFO;
//keyMap.put(KeyEvent.KEYCODE_BUTTON_SELECT, key);
keyMap.put(KeyEvent.KEYCODE_BUTTON_L1, key);
keyMap.put(KeyEvent.KEYCODE_NUM_LOCK, key);
keyMap.put(KeyEvent.KEYCODE_C, key);
// Keys mapping to TOOLBOX
key = KEY_TOOLBOX;
keyMap.put(KeyEvent.KEYCODE_BUTTON_R1, key);
keyMap.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE, key);
keyMap.put(KeyEvent.KEYCODE_B, key);
}
// Generate game actions based on mapped keys
public boolean onKeyboardAction(Context context, KeyEvent event, boolean acceptInput) {
//L.log("onKeyboardAction(): Processing action " + event.getAction() + " for keyCode " + event.getKeyCode());
if (event.getAction() != KeyEvent.ACTION_DOWN && event.getAction() != KeyEvent.ACTION_UP) return false; // don't handle other actions
boolean keydown = (event.getAction() == KeyEvent.ACTION_DOWN);
boolean inihbit = (keyState_attack || keyState_flee); // used to inhibit movement if an action key is held down
switch (keyMap.get(event.getKeyCode())) {
// Ordinal directional keys - only modify one direction register; registers are combined when
// keys used simultaneously to create synthetic diagonals
case KEY_MOVE_UP:
keyState_dy = keydown ? -1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_DOWN:
keyState_dy = keydown ? 1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_LEFT:
keyState_dx = keydown ? -1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_RIGHT:
keyState_dx = keydown ? 1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
// Diagonal directional keys. Modify both direction registers, can't be combined
// TODO: store individual key position to allow combinations. May not be worth the trouble.
case KEY_MOVE_UP_LEFT:
keyState_dx = keydown ? -1 : 0;
keyState_dy = keydown ? -1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_UP_RIGHT:
keyState_dx = keydown ? 1 : 0;
keyState_dy = keydown ? -1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_DOWN_LEFT:
keyState_dx = keydown ? -1 : 0;
keyState_dy = keydown ? 1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KEY_MOVE_DOWN_RIGHT:
keyState_dx = keydown ? 1 : 0;
keyState_dy = keydown ? 1 : 0;
if (acceptInput && !inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
// Special key handling below - some combat/movement stuff done here because it's too
// specific for logic in onRelativeMovement
// "Attack" shortcut - freeze movement to allow chorded direction when key is released.
// if in combat, executes an attack on key release
case KEY_ATTACK:
if (keydown && !keyState_attack) { // key pressed - pause any movement
if(!world.model.uiSelections.isInCombat) controllers.movementController.stopMovement();
} else if (!keydown && keyState_attack) { // key released - execute attack / move in direction
if (acceptInput) onRelativeMovement(keyState_dx, keyState_dy);
}
keyState_attack = keydown;
break;
// "Flee" shortcut. Intitiates flee when pressed. If a direction is held, moves in chosen direction when released
case KEY_FLEE:
if (world.model.uiSelections.isInCombat) {
if (keydown && !keyState_flee) { // button pressed - set flee; movement locked while pressed
if(acceptInput) controllers.combatController.startFlee();
} else if (!keydown && keyState_flee) { // button released - move flee direction, if held
// We need to do a special call because the movement key may already be down, and if the device
// doesn't generate repeat keystrokes, this handler won't get another event
if ((keyState_dx != 0 || keyState_dy != 0) && allowInputInterval()) {
if(acceptInput) controllers.combatController.executeMoveAttack(keyState_dx, keyState_dy);
}
}
}
keyState_flee = keydown;
break;
// "End Turn" shortcut. Flag prevents repeated end turn if key is held down.
case KEY_END_TURN:
if (acceptInput && keydown && !keyState_endturn) {
if (world.model.uiSelections.isInCombat) controllers.combatController.endPlayerTurn();
}
keyState_endturn = keydown;
break;
// "Hero Info" screen shortcut. New activity takes focus, so we don't need to worry about repeats.
case KEY_HERO_INFO:
if (acceptInput && keydown) context.startActivity(new Intent(context, HeroinfoActivity.class));
break;
case KEY_TOOLBOX:
// ??? ToolboxView toolboxview = context.getApplicationContext(). findViewById(R.id.main_toolboxview);
break;
case KEY_UNHANDLED: // Unhandled keycode
return false;
default: // unhandled keymap code entry (should not happen)
L.log("onKeyboardAction(): Unhandled keyMap code constant " + keyMap.get(event.getKeyCode()) + " for keyCode " + event.getKeyCode());
return false;
}
return true;
}
public void onRelativeMovement(int dx, int dy) {
//L.log("onRelativeMovement(): dx=" + dx + " dy=" + dy + " combat: " + world.model.uiSelections.isInCombat);
if (world.model.uiSelections.isInCombat) {
if (allowInputInterval()) controllers.combatController.executeMoveAttack(dx, dy);
} else if (dx == 0 && dy == 0) {
controllers.movementController.stopMovement();
} else {
controllers.movementController.startMovement(dx, dy, null);
}
}
public void onKeyboardCancel() {
controllers.movementController.stopMovement();
}
@Override
public void onClick(View arg0) {
if (!world.model.uiSelections.isInCombat) return;
onRelativeMovement(lastTouchPosition_dx, lastTouchPosition_dy);
}
@Override
public boolean onLongClick(View arg0) {
if (world.model.uiSelections.isInCombat) {
//TODO: Should be able to mark positions far away (mapwalk / ranged combat)
if (lastTouchPosition_dx == 0 && lastTouchPosition_dy == 0) return false;
if (Math.abs(lastTouchPosition_dx) > 1) return false;
if (Math.abs(lastTouchPosition_dy) > 1) return false;
controllers.combatController.setCombatSelection(lastTouchPosition_tileCoords);
return true;
}
return false;
}
private boolean allowInputInterval() {
final long now = System.currentTimeMillis();
if ((now - lastTouchEventTime) < Constants.MINIMUM_INPUT_INTERVAL) return false;
lastTouchEventTime = now;
return true;
}
public void setDpadActive(boolean isDpadActive) {
this.isDpadActive = isDpadActive;
}
public void onTouchCancel() {
controllers.movementController.stopMovement();
}
public boolean onTouchedTile(int tile_x, int tile_y) {
lastTouchPosition_tileCoords.set(tile_x, tile_y);
lastTouchPosition_dx = tile_x - world.model.player.position.x;
lastTouchPosition_dy = tile_y - world.model.player.position.y;
if (world.model.uiSelections.isInCombat || isDpadActive) return false;
controllers.movementController.startMovement(lastTouchPosition_dx, lastTouchPosition_dy, lastTouchPosition_tileCoords);
return true;
}
}

View File

@@ -1,26 +0,0 @@
package com.gpl.rpg.AndorsTrail.controller.listeners;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.ListOfListeners;
public final class PlayerMovementListeners extends ListOfListeners<PlayerMovementListener> implements PlayerMovementListener {
private final Function3<PlayerMovementListener, PredefinedMap, Coord, Coord> onPlayerMoved = new Function3<PlayerMovementListener, PredefinedMap, Coord, Coord>() {
@Override public void call(PlayerMovementListener listener, PredefinedMap map, Coord newPosition, Coord previousPosition) { listener.onPlayerMoved(map, newPosition, previousPosition); }
};
private final Function2<PlayerMovementListener, PredefinedMap, Coord> onPlayerEnteredNewMap = new Function2<PlayerMovementListener, PredefinedMap, Coord>() {
@Override public void call(PlayerMovementListener listener, PredefinedMap map, Coord p) { listener.onPlayerEnteredNewMap(map, p); }
};
@Override
public void onPlayerMoved(PredefinedMap map, Coord newPosition, Coord previousPosition) {
callAllListeners(this.onPlayerMoved, map, newPosition, previousPosition);
}
@Override
public void onPlayerEnteredNewMap(PredefinedMap map, Coord p) {
callAllListeners(this.onPlayerEnteredNewMap, map, p);
}
}

View File

@@ -1,14 +0,0 @@
package com.gpl.rpg.AndorsTrail.controller.listeners;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
public interface VisualEffectFrameListener {
void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset);
void onAnimationCompleted(VisualEffectAnimation animation);
void onSpriteMoveStarted(SpriteMoveAnimation animation);
void onNewSpriteMoveFrame(SpriteMoveAnimation animation);
void onSpriteMoveCompleted(SpriteMoveAnimation animation);
void onAsyncAreaUpdate(CoordRect area);
}

View File

@@ -1,63 +0,0 @@
package com.gpl.rpg.AndorsTrail.controller.listeners;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.ListOfListeners;
public final class VisualEffectFrameListeners extends ListOfListeners<VisualEffectFrameListener> implements VisualEffectFrameListener {
private final Function3<VisualEffectFrameListener, VisualEffectAnimation, Integer, Integer> onNewAnimationFrame = new Function3<VisualEffectFrameListener, VisualEffectAnimation, Integer, Integer>() {
@Override public void call(VisualEffectFrameListener listener, VisualEffectAnimation animation, Integer tileID, Integer textYOffset) { listener.onNewAnimationFrame(animation, tileID, textYOffset); }
};
private final Function1<VisualEffectFrameListener, VisualEffectAnimation> onAnimationCompleted = new Function1<VisualEffectFrameListener, VisualEffectAnimation>() {
@Override public void call(VisualEffectFrameListener listener, VisualEffectAnimation animation) { listener.onAnimationCompleted(animation); }
};
private final Function1<VisualEffectFrameListener, SpriteMoveAnimation> onSpriteMoveStarted = new Function1<VisualEffectFrameListener, SpriteMoveAnimation>() {
@Override public void call(VisualEffectFrameListener listener, SpriteMoveAnimation animation) { listener.onSpriteMoveStarted(animation); }
};
private final Function1<VisualEffectFrameListener, SpriteMoveAnimation> onNewSpriteMoveFrame = new Function1<VisualEffectFrameListener, SpriteMoveAnimation>() {
@Override public void call(VisualEffectFrameListener listener, SpriteMoveAnimation animation) { listener.onNewSpriteMoveFrame(animation); }
};
private final Function1<VisualEffectFrameListener, SpriteMoveAnimation> onSpriteMoveCompleted = new Function1<VisualEffectFrameListener, SpriteMoveAnimation>() {
@Override public void call(VisualEffectFrameListener listener, SpriteMoveAnimation animation) { listener.onSpriteMoveCompleted(animation); }
};
private final Function1<VisualEffectFrameListener, CoordRect> onAsyncAreaUpdate = new Function1<VisualEffectFrameListener, CoordRect>() {
@Override public void call(VisualEffectFrameListener listener, CoordRect area) { listener.onAsyncAreaUpdate(area); }
};
@Override
public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) {
callAllListeners(this.onNewAnimationFrame, animation, tileID, textYOffset);
}
@Override
public void onAnimationCompleted(VisualEffectAnimation animation) {
callAllListeners(this.onAnimationCompleted, animation);
}
@Override
public void onSpriteMoveStarted(SpriteMoveAnimation animation) {
callAllListeners(this.onSpriteMoveStarted, animation);
}
@Override
public void onNewSpriteMoveFrame(SpriteMoveAnimation animation) {
callAllListeners(this.onNewSpriteMoveFrame, animation);
}
@Override
public void onSpriteMoveCompleted(SpriteMoveAnimation animation) {
callAllListeners(this.onSpriteMoveCompleted, animation);
}
@Override
public void onAsyncAreaUpdate(CoordRect area) {
callAllListeners(this.onAsyncAreaUpdate, area);
}
}

View File

@@ -1,11 +0,0 @@
package com.gpl.rpg.AndorsTrail.model;
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
public final class MapBundle {
public PredefinedMap map;
public LayeredTileMap tileMap;
public TileCollection tiles;
}

View File

@@ -1,117 +0,0 @@
package com.gpl.rpg.AndorsTrail.model;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Calendar;
public final class WorldData {
private long worldTime = 0; // Measured in number of game rounds
private final HashMap<String, Long> timers = new HashMap<String, Long>();
public WorldData() {}
public void tickWorldTime() {
++worldTime;
}
public void tickWorldTime(int ticks) {
worldTime += ticks;
}
public long getWorldTime() {
return worldTime;
}
public void createTimer(String name) {
timers.put(name, worldTime);
}
public void removeTimer(String name) {
timers.remove(name);
}
public boolean hasTimerElapsed(String name, long duration) {
Long v = timers.get(name);
if (v == null) return false;
return v + duration <= worldTime;
}
public int getDate(String format) {
Calendar now = Calendar.getInstance();
int ret;
switch (format) {
case "YYYYMMDD":
ret = now.get(Calendar.YEAR)*10000 + (now.get(Calendar.MONTH) + 1)*100 + now.get(Calendar.DAY_OF_MONTH);
break;
case "YYYYMM":
ret = now.get(Calendar.YEAR)*100 + (now.get(Calendar.MONTH) + 1);
break;
case "YYYY":
ret = now.get(Calendar.YEAR);
break;
case "MMDD":
ret = (now.get(Calendar.MONTH) + 1)*100 + now.get(Calendar.DAY_OF_MONTH);
break;
case "MM":
ret = (now.get(Calendar.MONTH) + 1);
break;
case "DD":
ret = now.get(Calendar.DAY_OF_MONTH);
break;
default:
ret = 99999999; //never true
}
return ret;
}
public int getTime(String format) {
Calendar now = Calendar.getInstance();
int ret;
switch (format) {
case "HHMMSS":
ret = now.get(Calendar.HOUR_OF_DAY)*10000 + now.get(Calendar.MINUTE)*100 + now.get(Calendar.SECOND);
break;
case "HHMM":
ret = now.get(Calendar.HOUR_OF_DAY)*100 + now.get(Calendar.MINUTE);
break;
case "HH":
ret = now.get(Calendar.HOUR_OF_DAY);
break;
case "MMSS":
ret = now.get(Calendar.MINUTE)*100 + now.get(Calendar.SECOND);
break;
case "MM":
ret = now.get(Calendar.MINUTE);
break;
case "SS":
ret = now.get(Calendar.SECOND);
break;
default:
ret = 99999999; //never true
}
return ret;
}
// ====== PARCELABLE ===================================================================
public WorldData(DataInputStream src, int fileversion) throws IOException {
worldTime = src.readLong();
final int numTimers = src.readInt();
for(int i = 0; i < numTimers; ++i) {
final String timerName = src.readUTF();
final long value = src.readLong();
this.timers.put(timerName, value);
}
}
public void writeToParcel(DataOutputStream dest) throws IOException {
dest.writeLong(worldTime);
dest.writeInt(timers.size());
for(Map.Entry<String, Long> e : timers.entrySet()) {
dest.writeUTF(e.getKey());
dest.writeLong(e.getValue());
}
}
}

View File

@@ -1,58 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.actor;
import java.util.LinkedList;
import java.util.List;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
public class HeroCollection {
//Id in save is the index in the list +1
private static final List<HeroDesc> listOfHeroes = new LinkedList<HeroCollection.HeroDesc>();
public static boolean isInitialized = false;
public static class HeroDesc {
int tileIdInSpritesheet, tileIdInManager, smallSpriteResId, largeSpriteResId;
public HeroDesc(int tileIdInSpritesheet, int smallSpriteResId, int largeSpriteResId) {
this.smallSpriteResId = smallSpriteResId;
this.largeSpriteResId = largeSpriteResId;
this.tileIdInSpritesheet = tileIdInSpritesheet;
//tileIdInManager will be filled by prepareHeroesTileId, called by ResourceLoader
}
}
static {
listOfHeroes.add(new HeroDesc(0, R.drawable.char_hero, R.drawable.char_hero_large));
listOfHeroes.add(new HeroDesc(0, R.drawable.char_hero_maksiu_girl_01, R.drawable.char_hero_maksiu_girl_01_large));
listOfHeroes.add(new HeroDesc(0, R.drawable.char_hero_maksiu_boy_01, R.drawable.char_hero_maksiu_boy_01_large));
}
public static int getHeroTileIdForTileManage(int heroId) {
//Id in save is the index in the list +1
heroId--;
if (heroId >= listOfHeroes.size()) return -1;
return listOfHeroes.get(heroId).tileIdInManager;
}
public static int getHeroSmallSpriteId(int heroId) {
//Id in save is the index in the list +1
heroId--;
if (heroId >= listOfHeroes.size()) return -1;
return listOfHeroes.get(heroId).smallSpriteResId;
}
public static int getHeroLargeSprite(int heroId) {
//Id in save is the index in the list +1
heroId--;
if (heroId >= listOfHeroes.size()) return -1;
return listOfHeroes.get(heroId).largeSpriteResId;
}
public static void prepareHeroesTileId(DynamicTileLoader loader) {
for (HeroDesc hero : listOfHeroes) {
hero.tileIdInManager = loader.prepareTileID(hero.smallSpriteResId, hero.tileIdInSpritesheet);
}
}
}

View File

@@ -1,283 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.item;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
public class ItemContainer {
public final ArrayList<ItemEntry> items = new ArrayList<ItemEntry>();
public ItemContainer() {}
public int countItems() {
int result = 0;
for (ItemEntry i : items) {
result += i.quantity;
}
return result;
}
public static final class ItemEntry {
public final ItemType itemType;
public int quantity;
public ItemEntry(ItemType itemType, int initialQuantity) {
this.itemType = itemType;
this.quantity = initialQuantity;
}
// ====== PARCELABLE ===================================================================
public ItemEntry(DataInputStream src, WorldContext world, int fileversion) throws IOException {
this.itemType = world.itemTypes.getItemType(src.readUTF());
this.quantity = src.readInt();
}
public void writeToParcel(DataOutputStream dest) throws IOException {
dest.writeUTF(itemType.id);
dest.writeInt(quantity);
}
}
public void addItem(ItemType itemType, int quantity) {
if (quantity == 0) return;
ItemEntry e = findItem(itemType.id);
if (e != null) {
e.quantity += quantity;
} else {
items.add(new ItemEntry(itemType, quantity));
}
}
public void addItem(ItemType itemType) { addItem(itemType, 1); }
public void add(final ItemContainer items) {
for (ItemEntry e : items.items) {
addItem(e.itemType, e.quantity);
}
}
public boolean isEmpty() { return items.isEmpty(); }
public boolean removeItem(String itemTypeID) { return removeItem(itemTypeID, 1); }
public boolean removeItem(String itemTypeID, int quantity) {
int index = -1;
ItemEntry e = null;
for (int i = 0; i < items.size(); ++i) {
e = items.get(i);
if (e.itemType.id.equals(itemTypeID)) {
index = i;
break;
}
}
if (index < 0) return false;
if (e.quantity == quantity) {
items.remove(index);
} else if (e.quantity > quantity) {
e.quantity -= quantity;
} else {
return false;
}
return true;
}
public ItemEntry findItem(String itemTypeID) {
for (ItemEntry e : items) {
if (e.itemType.id.equals(itemTypeID)) return e;
}
return null;
}
public int findItemIndex(String itemTypeID) {
for (int i = 0; i < items.size(); ++i) {
if (items.get(i).itemType.id.equals(itemTypeID)) return i;
}
return -1;
}
public boolean hasItem(String itemTypeID) { return findItem(itemTypeID) != null; }
public boolean hasItem(String itemTypeID, int minimumQuantity) {
return getItemQuantity(itemTypeID) >= minimumQuantity;
}
public int getItemQuantity(String itemTypeID) {
ItemEntry e = findItem(itemTypeID);
if (e == null) return 0;
return e.quantity;
}
public void sortToTop(String itemTypeID) {
int i = findItemIndex(itemTypeID);
if (i <= 0) return;
items.add(0, items.remove(i));
}
public void sortToBottom(String itemTypeID) {
int i = findItemIndex(itemTypeID);
if (i < 0) return;
items.add(items.remove(i));
}
public ItemContainer usableItems() {
ItemContainer usableContainer = new ItemContainer();
for (ItemEntry item : items) {
if (item.itemType.isUsable()) {
usableContainer.addItem(item.itemType, item.quantity);
}
}
return usableContainer;
}
public void sortByName(Player p) {
final Player q = p;
Comparator<ItemEntry> comparatorName = new Comparator<ItemEntry>() {
@Override
public int compare(ItemEntry item1, ItemEntry item2) {
return item1.itemType.getName(q).compareTo(item2.itemType.getName(q));
}
};
Collections.sort(this.items, comparatorName);
}
public void sortByPrice(Player p) {
final Player q = p;
Comparator<ItemEntry> comparatorPrice = new Comparator<ItemEntry>() {
@Override
public int compare(ItemEntry item1, ItemEntry item2) {
// More expensive items go to top
if (item1.itemType.baseMarketCost < item2.itemType.baseMarketCost) {
return 1;
} else if (item1.itemType.baseMarketCost > item2.itemType.baseMarketCost) {
return -1;
} else { // compares the names if rarity is the same
return item1.itemType.getName(q).compareTo(item2.itemType.getName(q));
}
}
};
Collections.sort(this.items, comparatorPrice);
}
public void sortByQuantity(Player p) {
final Player q = p;
Comparator<ItemEntry> comparatorQuantity = new Comparator<ItemEntry>() {
@Override
public int compare(ItemEntry item1, ItemEntry item2) {
// Bigger quantity is put first
if (item1.quantity > item2.quantity) {
return -1;
} else if (item1.quantity < item2.quantity) {
return 1;
} else { // compares the names if quantity is the same
return item1.itemType.getName(q).compareTo(item2.itemType.getName(q));
}
}
};
Collections.sort(this.items, comparatorQuantity);
}
public void sortByRarity(Player p) {
final Player q = p;
Comparator<ItemEntry> comparatorRarity = new Comparator<ItemEntry>() {
@Override
public int compare(ItemEntry item1, ItemEntry item2) {
// More rare items go to top
if (item1.itemType.displayType.compareTo(item2.itemType.displayType) != 0 ) {
return (-1) * item1.itemType.displayType.compareTo(item2.itemType.displayType);
// ^ More rare goes on top
} else { // compares the names if rarity is the same
return item1.itemType.getName(q).compareTo(item2.itemType.getName(q));
}
}
};
Collections.sort(this.items, comparatorRarity);
}
public void sortByType(Player p) {
final Player q = p;
Comparator<ItemEntry> comparatorType = new Comparator<ItemEntry>() {
@Override
public int compare(ItemEntry item1, ItemEntry item2) {
if (determineType(item1) > determineType(item2)) {
return 1;
} else if (determineType(item1) < determineType(item2)) {
return -666;
} else { // compares the names if type is the same
return item1.itemType.getName(q).compareTo(item2.itemType.getName(q));
}
}
};
Collections.sort(this.items, comparatorType);
}
public int determineType(ItemEntry item) {
if (item.itemType.isEquippable()) {
switch (item.itemType.category.inventorySlot) {
case weapon:
if (item.itemType.isTwohandWeapon()) {
return 100;
} else {
return 110;
}
case shield: return 200;
case head: return 210;
case body: return 220;
case hand: return 230;
case feet: return 240;
case neck: return 250;
case leftring: return 260;
case rightring: return 260; // Note: not used - all rings are leftring by category
default: return 270;
}
} else if (item.itemType.isUsable()) {
if ("pot".equals(item.itemType.category.id) || "healing".equals(item.itemType.category.id)) {
return 300;
} else {
return 310;
}
} else if (item.itemType.isQuestItem()) {
return 400;
} else {
return 500;
}
}
public void sortByReverse() {
Collections.reverse(this.items);
}
// ====== PARCELABLE ===================================================================
public static ItemContainer newFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
ItemContainer result = new ItemContainer();
result.readFromParcel(src, world, fileversion);
return result;
}
protected void readFromParcel(DataInputStream src, WorldContext world, int fileversion) throws IOException {
items.clear();
final int size = src.readInt();
for(int i = 0; i < size; ++i) {
ItemEntry entry = new ItemEntry(src, world, fileversion);
if (entry.itemType != null) items.add(entry);
}
}
public void writeToParcel(DataOutputStream dest) throws IOException {
dest.writeInt(items.size());
for (ItemEntry e : items) {
e.writeToParcel(dest);
}
}
}

View File

@@ -1,26 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.item;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
public class ItemTraits_OnHitReceived extends ItemTraits_OnUse {
public final StatsModifierTraits changedStats_target;
public ItemTraits_OnHitReceived(
StatsModifierTraits changedStats
, StatsModifierTraits changedStats_target
, ActorConditionEffect[] addedConditions_source
, ActorConditionEffect[] addedConditions_target
) {
super(changedStats_target, addedConditions_source, addedConditions_target);
this.changedStats_target = changedStats_target;
}
public int calculateHitReceivedCost() {
int costStats = changedStats == null ? 0 : changedStats.calculateHitCost();
costStats += changedStats_target == null ? 0 : -changedStats_target.calculateHitCost();
return costStats;
}
}

View File

@@ -1,237 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.map;
import java.util.Collection;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Size;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
public final class LayeredTileMap {
private static final ColorFilter colorFilterBlack20 = createGrayScaleColorFilter(0.8f);
private static final ColorFilter colorFilterBlack40 = createGrayScaleColorFilter(0.6f);
private static final ColorFilter colorFilterBlack60 = createGrayScaleColorFilter(0.4f);
private static final ColorFilter colorFilterBlack80 = createGrayScaleColorFilter(0.2f);
private static final ColorFilter colorFilterInvert = createInvertColorFilter();
private static final ColorFilter colorFilterBW = createBWColorFilter();
private static final ColorFilter colorFilterRedTint = createRedTintColorFilter();
private static final ColorFilter colorFilterGreenTint = createGreenTintColorFilter();
private static final ColorFilter colorFilterBlueTint = createBlueTintColorFilter();
public enum ColorFilterId {
none,
black20,
black40,
black60,
black80,
invert,
bw,
redtint,
greentint,
bluetint
}
private final Size size;
public final MapSection currentLayout;
private String currentLayoutHash;
public final ReplaceableMapSection[] replacements;
public final ColorFilterId originalColorFilter;
public ColorFilterId colorFilter;
public final Collection<Integer> usedTileIDs;
public LayeredTileMap(
Size size
, MapSection layout
, ReplaceableMapSection[] replacements
, ColorFilterId colorFilter
, Collection<Integer> usedTileIDs
) {
this.size = size;
this.currentLayout = layout;
this.replacements = replacements;
this.originalColorFilter = colorFilter;
colorFilter = originalColorFilter;
this.usedTileIDs = usedTileIDs;
this.currentLayoutHash = currentLayout.calculateHash(colorFilter.name());
}
public final boolean isWalkable(final Coord p) {
if (isOutside(p.x, p.y)) return false;
return currentLayout.isWalkable[p.x][p.y];
}
public final boolean isWalkable(final int x, final int y) {
if (isOutside(x, y)) return false;
return currentLayout.isWalkable[x][y];
}
public final boolean isWalkable(final CoordRect p) {
for (int y = 0; y < p.size.height; ++y) {
for (int x = 0; x < p.size.width; ++x) {
if (!isWalkable(p.topLeft.x + x, p.topLeft.y + y)) return false;
}
}
return true;
}
public final boolean isOutside(final Coord p) { return isOutside(p.x, p.y); }
public final boolean isOutside(final int x, final int y) {
if (x < 0) return true;
if (y < 0) return true;
if (x >= size.width) return true;
if (y >= size.height) return true;
return false;
}
public final boolean isOutside(final CoordRect area) {
if (isOutside(area.topLeft)) return true;
if (area.topLeft.x + area.size.width > size.width) return true;
if (area.topLeft.y + area.size.height > size.height) return true;
return false;
}
public boolean setColorFilter(Paint mPaint, Paint alternateColorFilterPaint, boolean highQuality) {
if (!highQuality) {
highQuality = !setColor(alternateColorFilterPaint);
}
mPaint.setColorFilter(highQuality ? getColorFilter() : null);
return !highQuality;
}
public ColorFilter getColorFilter() {
if (colorFilter == null) return null;
switch (colorFilter) {
case black20:
return colorFilterBlack20;
case black40:
return colorFilterBlack40;
case black60:
return colorFilterBlack60;
case black80:
return colorFilterBlack80;
case invert:
return colorFilterInvert;
case bw:
return colorFilterBW;
case redtint:
return colorFilterRedTint;
case greentint:
return colorFilterGreenTint;
case bluetint:
return colorFilterBlueTint;
default:
return null;
}
}
public boolean setColor(Paint p) {
if (colorFilter == null) {
p.setARGB(0, 0, 0, 0);
return true;
}
switch (colorFilter) {
case black20:
p.setARGB(51, 0, 0, 0); return true;
case black40:
p.setARGB(102, 0, 0, 0); return true;
case black60:
p.setARGB(153, 0, 0, 0); return true;
case black80:
p.setARGB(204, 0, 0, 0); return true;
case redtint:
p.setARGB(50, 200, 0, 0); return true;
case greentint:
p.setARGB(50, 0, 200, 0); return true;
case bluetint:
p.setARGB(50, 0, 0, 200); return true;
case bw:
case invert:
return false;
default:
p.setARGB(0, 0, 0, 0); return true;
}
}
private static ColorMatrixColorFilter createGrayScaleColorFilter(float blackOpacity) {
final float f = blackOpacity;
return new ColorMatrixColorFilter(new float[] {
f, 0.00f, 0.00f, 0.0f, 0.0f,
0.00f, f, 0.00f, 0.0f, 0.0f,
0.00f, 0.00f, f, 0.0f, 0.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
private static ColorMatrixColorFilter createInvertColorFilter() {
return new ColorMatrixColorFilter(new float[] {
-1.00f, 0.00f, 0.00f, 0.0f, 255.0f,
0.00f, -1.00f, 0.00f, 0.0f, 255.0f,
0.00f, 0.00f, -1.00f, 0.0f, 255.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
private static ColorMatrixColorFilter createBWColorFilter() {
return new ColorMatrixColorFilter(new float[] {
0.33f, 0.59f, 0.11f, 0.0f, 0.0f,
0.33f, 0.59f, 0.11f, 0.0f, 0.0f,
0.33f, 0.59f, 0.11f, 0.0f, 0.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
private static ColorMatrixColorFilter createRedTintColorFilter() {
return new ColorMatrixColorFilter(new float[] {
1.20f, 0.20f, 0.20f, 0.0f, 25.0f,
0.00f, 0.80f, 0.00f, 0.0f, 0.0f,
0.00f, 0.00f, 0.80f, 0.0f, 0.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
private static ColorMatrixColorFilter createGreenTintColorFilter() {
return new ColorMatrixColorFilter(new float[] {
0.85f, 0.00f, 0.00f, 0.0f, 0.0f,
0.15f, 1.15f, 0.15f, 0.0f, 15.0f,
0.00f, 0.00f, 0.85f, 0.0f, 0.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
private static ColorMatrixColorFilter createBlueTintColorFilter() {
return new ColorMatrixColorFilter(new float[] {
0.70f, 0.00f, 0.00f, 0.0f, 0.0f,
0.00f, 0.70f, 0.00f, 0.0f, 0.0f,
0.30f, 0.30f, 1.30f, 0.0f, 40.0f,
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
public String getCurrentLayoutHash() {
return currentLayoutHash;
}
public void applyReplacement(ReplaceableMapSection replacement) {
replacement.apply(currentLayout);
currentLayoutHash = currentLayout.calculateHash(colorFilter == ColorFilterId.none ? null : colorFilter.name());
}
public void changeColorFilter(ColorFilterId id) {
if (colorFilter == id) return;
colorFilter = id;
currentLayoutHash = currentLayout.calculateHash(colorFilter == ColorFilterId.none ? null : colorFilter.name());
}
public void changeColorFilter(String idString) {
ColorFilterId id;
if (idString == null) id = originalColorFilter;
else id = ColorFilterId.valueOf(idString);
if (id != null) {
changeColorFilter(id);
}
}
}

View File

@@ -1,103 +0,0 @@
package com.gpl.rpg.AndorsTrail.model.script;
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
import com.gpl.rpg.AndorsTrail.util.ConstRange;
public final class Requirement {
public static enum RequirementType {
questProgress
,questLatestProgress // Highest quest stage reached must match.
,inventoryRemove // Player must have item(s) in inventory. Items will be removed when selecting reply.
,inventoryKeep // Player must have item(s) in inventory. Items will NOT be removed when selecting reply.
,wear // Player must be wearing item(s). Items will NOT be removed when selecting reply.
,skillLevel // Player needs to have a specific skill equal to or above a certain level
,killedMonster
,timerElapsed
,usedItem
,spentGold
,consumedBonemeals
,hasActorCondition
,factionScore
,random
,factionScoreEquals
,wearRemove
,date
,dateEquals
,time
,timeEquals
}
public final RequirementType requireType;
public final String requireID;
public final int value;
public final boolean negate;
public final ConstRange chance;
public Requirement(
RequirementType requireType
, String requireID
, int value
, boolean negate
, ConstRange chance
) {
this.requireType = requireType;
this.requireID = requireID;
this.value = value;
this.negate = negate;
this.chance = chance;
}
public Requirement(QuestProgress qp) {
this.requireType = RequirementType.questProgress;
this.requireID = qp.questID;
this.value = qp.progress;
this.negate = false;
this.chance = null;
}
public String toString() {
StringBuilder buf = new StringBuilder(requireType.toString());
buf.append("--");
buf.append(requireID);
buf.append("--");
if (negate) buf.append('!');
buf.append(value);
return buf.toString();
}
public boolean isValid() {
switch (this.requireType) {
case consumedBonemeals:
return value >= 0;
case hasActorCondition:
case factionScore:
case factionScoreEquals:
return requireID != null;
case inventoryKeep:
case inventoryRemove:
case wear:
case wearRemove:
case usedItem:
return requireID != null && value >= 0;
case killedMonster:
return requireID != null && value >= 0;
case questLatestProgress:
case questProgress:
return requireID != null && value >= 0;
case skillLevel:
return requireID != null && value >= 0;
case spentGold:
case date:
case dateEquals:
case time:
case timeEquals:
return value >= 0;
case random:
return chance != null;
case timerElapsed:
return requireID != null && value >= 0;
default:
return false;
}
}
}

View File

@@ -1,564 +0,0 @@
package com.gpl.rpg.AndorsTrail.resource.tiles;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.AsyncTask;
import android.widget.ImageView;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionType;
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapTranslator;
import com.gpl.rpg.AndorsTrail.util.L;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
public final class TileManager {
public static final int BEGIN_ID = 1;
public static final int CHAR_HERO_0 = BEGIN_ID;
public static final int CHAR_HERO_1 = CHAR_HERO_0+1;
public static final int CHAR_HERO_2 = CHAR_HERO_1+1;
//Default hero
public static final int CHAR_HERO = CHAR_HERO_0;
//Max hero icon ID in this version.
public static final int LAST_HERO = CHAR_HERO_2;
public static final int iconID_selection_red = CHAR_HERO_2+1;
public static final int iconID_selection_yellow = iconID_selection_red+1;
public static final int iconID_attackselect = iconID_selection_red;
public static final int iconID_moveselect = iconID_selection_yellow;
public static final int iconID_groundbag = iconID_moveselect+1;
public static final int iconID_boxopened = iconID_groundbag+1;
public static final int iconID_boxclosed = iconID_boxopened+1;
public static final int iconID_shop = iconID_groundbag;
public static final int iconID_unassigned_quickslot = iconID_groundbag;
public static final int iconID_selection_blue = iconID_boxclosed+1;
public static final int iconID_selection_purple = iconID_selection_blue+1;
public static final int iconID_selection_green = iconID_selection_purple+1;
public static final int iconID_splatter_red_1a = iconID_selection_green+1;
public static final int iconID_splatter_red_1b = iconID_splatter_red_1a+1;
public static final int iconID_splatter_red_2a = iconID_splatter_red_1b+1;
public static final int iconID_splatter_red_2b = iconID_splatter_red_2a+1;
public static final int iconID_splatter_brown_1a = iconID_splatter_red_2b+1;
public static final int iconID_splatter_brown_1b = iconID_splatter_brown_1a+1;
public static final int iconID_splatter_brown_2a = iconID_splatter_brown_1b+1;
public static final int iconID_splatter_brown_2b = iconID_splatter_brown_2a+1;
public static final int iconID_splatter_white_1a = iconID_splatter_brown_2b+1;
public static final int iconID_splatter_white_1b = iconID_splatter_white_1a+1;
public static final int iconID_immunity_overlay = iconID_splatter_white_1b+1;
public static final int tileID_placeholder_hero = iconID_immunity_overlay+1;
public static final int tileID_placeholder_hat = tileID_placeholder_hero+1;
public static final int tileID_placeholder_armor = tileID_placeholder_hat+1;
public static final int tileID_placeholder_necklace = tileID_placeholder_armor+1;
public static final int tileID_placeholder_weapon = tileID_placeholder_necklace+1;
public static final int tileID_placeholder_shield = tileID_placeholder_weapon+1;
public static final int tileID_placeholder_lring = tileID_placeholder_shield+1;
public static final int tileID_placeholder_rring = tileID_placeholder_lring+1;
public static final int tileID_placeholder_gloves = tileID_placeholder_rring+1;
public static final int tileID_placeholder_boots = tileID_placeholder_gloves+1;
public int tileSize;
public float density;
public float uiIconScale;
public int viewTileSize;
public float scale;
public final TileCache tileCache = new TileCache();
public TileCollection preloadedTiles;// = new TileCollection(116);
public TileCollection adjacentMapTiles;
private final HashSet<Integer> preloadedTileIDs = new HashSet<Integer>();
public TileCollection loadTilesFor(Collection<Integer> tileIDs, Resources r) {
return tileCache.loadTilesFor(tileIDs, r);
}
public TileCollection loadTilesFor(ItemContainer container, Resources r) {
return tileCache.loadTilesFor(getTileIDsFor(container), r);
}
public HashSet<Integer> getTileIDsFor(ItemContainer container) {
HashSet<Integer> iconIDs = new HashSet<Integer>();
for(ItemEntry i : container.items) {
iconIDs.add(i.itemType.iconID);
}
return iconIDs;
}
public TileCollection loadTilesFor(Inventory inventory, Resources r) {
HashSet<Integer> iconIDs = getTileIDsFor(inventory);
for (Inventory.WearSlot slot : Inventory.WearSlot.values()) {
ItemType t = inventory.getItemTypeInWearSlot(slot);
if (t != null) iconIDs.add(t.iconID);
}
return tileCache.loadTilesFor(iconIDs, r);
}
public TileCollection loadTilesFor(PredefinedMap map, LayeredTileMap tileMap, WorldContext world, Resources r) {
HashSet<Integer> iconIDs = getTileIDsFor(map, tileMap, world);
TileCollection result = tileCache.loadTilesFor(iconIDs, r);
for(int i : preloadedTileIDs) {
result.setBitmap(i, preloadedTiles.getBitmap(i));
}
//TODO patch placeholders on the fly here.
updatePlaceholdersTiles(result, world);
return result;
}
private void updatePlaceholdersTiles(TileCollection result, WorldContext world) {
result.setBitmap(tileID_placeholder_hero, preloadedTiles.getBitmap(world.model.player.iconID));
}
public HashSet<Integer> getTileIDsFor(PredefinedMap map, LayeredTileMap tileMap, WorldContext world) {
HashSet<Integer> iconIDs = new HashSet<Integer>();
for (MonsterSpawnArea a : map.spawnAreas) {
for (String monsterTypeID : a.monsterTypeIDs) {
iconIDs.add(world.monsterTypes.getMonsterType(monsterTypeID).iconID);
}
// Add icons for monsters that are already spawned, but that do not belong to the group of
// monsters that usually spawn here. This could happen if we change the contents of spawn-
// areas in a later release,
for (Monster m : a.monsters) {
iconIDs.add(m.iconID);
}
}
iconIDs.addAll(tileMap.usedTileIDs);
return iconIDs;
}
public void setDensity(Resources r) {
density = r.getDisplayMetrics().density;
uiIconScale = 100 * density;
// tileSize = (int) (32 * density);
if (density < 1) tileSize = (int) (32 * density);
else tileSize = 32;
}
public void updatePreferences(AndorsTrailPreferences prefs) {
float densityScaler = 1;
if (density > 1) densityScaler = density;
scale = prefs.scalingFactor * densityScaler;
viewTileSize = (int) (tileSize * prefs.scalingFactor * densityScaler);
}
public void setImageViewTile(Resources res, TextView textView, Monster monster, TileCollection tiles) { setImageViewTileForMonster(res, textView, monster.iconID, tiles); }
public void setImageViewTile(Resources res, TextView textView, Player player) { setImageViewTileForPlayer(res, textView, player.iconID); }
public void setImageViewTileForMonster(Resources res, TextView textView, int iconID, TileCollection tiles) { setImageViewTile(res, textView, tiles.getBitmap(iconID)); }
public void setImageViewTileForPlayer(Resources res, TextView textView, int iconID) { setImageViewTile(res, textView, preloadedTiles.getBitmap(iconID)); }
public void setImageViewTile(Resources res, TextView textView, ActorConditionType conditionType) { setImageViewTile(res, textView, preloadedTiles.getBitmap(conditionType.iconID)); }
public void setImageViewTile(Resources res, TextView textView, ActorConditionType conditionType, boolean immunityOverlay) { setImageViewTile(res, textView, preloadedTiles.getBitmap(conditionType.iconID), immunityOverlay); }
public void setImageViewTileForUIIcon(Resources res, TextView textView, int iconID) { setImageViewTile(res, textView, preloadedTiles.getBitmap(iconID)); }
private void setImageViewTile(Resources res, TextView textView, Bitmap b) {
if (density > 1) {
setImageViewTile(textView, new BitmapDrawable(res, Bitmap.createScaledBitmap(b, (int)(tileSize*density), (int)(tileSize*density), true)));
} else {
setImageViewTile(textView, new BitmapDrawable(res, b));
}
}
public void setImageViewTile(Resources res, TextView textView, Bitmap b, boolean immunityOverlay) {
if (!immunityOverlay) setImageViewTile(res, textView, b);
else {
Drawable[] layers = new Drawable[2];
if (density > 1) {
layers[0] = new BitmapDrawable(res, Bitmap.createScaledBitmap(b, (int)(tileSize*density), (int)(tileSize*density), true));
layers[1] = new BitmapDrawable(res, preloadedTiles.getBitmap(iconID_immunity_overlay));
} else {
layers[0] = new BitmapDrawable(res, b);
layers[1] = new BitmapDrawable(res, preloadedTiles.getBitmap(iconID_immunity_overlay));
}
LayerDrawable layered = new LayerDrawable(layers);
setImageViewTile(textView, layered);
}
}
private void setImageViewTile(TextView textView, Drawable d) {
/*if (density > 1) {
ScaleDrawable sd = new ScaleDrawable(d, 0, uiIconScale, uiIconScale);
sd.setLevel(8000);
d.setBounds(0, 0, (int)(tileSize * density), (int)(tileSize * density));
textView.setCompoundDrawables(sd, null, null, null);
}
else */textView.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
}
public void setImageViewTileForSingleItemType(Resources res, TextView textView, ItemType itemType) {
final Bitmap icon = tileCache.loadSingleTile(itemType.iconID, res);
setImageViewTile(res, textView, itemType, icon);
}
public void setImageViewTile(Resources res, TextView textView, ItemType itemType, TileCollection itemTileCollection) {
final Bitmap icon = itemTileCollection.getBitmap(itemType.iconID);
setImageViewTile(res, textView, itemType, icon);
}
private void setImageViewTile(Resources res, TextView textView, ItemType itemType, Bitmap icon) {
final int overlayIconID = itemType.getOverlayTileID();
if (overlayIconID != -1) {
if (density > 1) {
setImageViewTile(textView,
new LayerDrawable(new Drawable[] {
new BitmapDrawable(res, Bitmap.createScaledBitmap(preloadedTiles.getBitmap(overlayIconID), (int)(tileSize*density), (int)(tileSize*density), true))
,new BitmapDrawable(res, Bitmap.createScaledBitmap(icon, (int)(tileSize*density), (int)(tileSize*density), true))
})
);
} else {
setImageViewTile(textView,
new LayerDrawable(new Drawable[] {
new BitmapDrawable(res, preloadedTiles.getBitmap(overlayIconID))
,new BitmapDrawable(res, icon)
})
);
}
} else {
setImageViewTile(res, textView, icon);
}
}
public void setImageViewTile(Resources res, ImageView imageView, Monster monster, TileCollection tiles) { setImageViewTileForMonster(res, imageView, monster.iconID, tiles); }
public void setImageViewTile(Resources res, ImageView imageView, Player player) { setImageViewTileForPlayer(res, imageView, player.iconID); }
public void setImageViewTileForMonster(Resources res, ImageView imageView, int iconID, TileCollection tiles) { setImageViewTile(res, imageView, tiles.getBitmap(iconID)); }
public void setImageViewTileForPlayer(Resources res, ImageView imageView, int iconID) { setImageViewTile(res, imageView, preloadedTiles.getBitmap(iconID)); }
// public void setImageViewTile(Resources res, ImageView imageView, ActorConditionType conditionType) { setImageViewTile(res, imageView, preloadedTiles.getBitmap(conditionType.iconID)); }
public void setImageViewTile(Context ctx, ImageView imageView, ActorConditionType conditionType, boolean immunityOverlay) { setImageViewTile(ctx, imageView, preloadedTiles.getBitmap(conditionType.iconID), immunityOverlay); }
public void setImageViewTile(Context ctx, ImageView imageView, ActorConditionType conditionType, boolean immunityOverlay, String exponent, String index) { setImageViewTile(ctx, imageView, preloadedTiles.getBitmap(conditionType.iconID), immunityOverlay, exponent, index); }
public void setImageViewTileForUIIcon(Resources res, ImageView imageView, int iconID) { setImageViewTile(res, imageView, preloadedTiles.getBitmap(iconID)); }
public void setImageViewTile(Resources res, ImageView imageView, Bitmap b) {
if (density > 1) {
setImageViewTile(imageView, new BitmapDrawable(res, Bitmap.createScaledBitmap(b, (int)(tileSize*density), (int)(tileSize*density), true)));
} else {
setImageViewTile(imageView, new BitmapDrawable(res, b));
}
}
public void setImageViewTile(Context ctx, ImageView imageView, Bitmap b, boolean immunityOverlay) {
setImageViewTile(ctx, imageView, b, immunityOverlay, null, null);
}
public void setImageViewTile(Context ctx, ImageView imageView, Bitmap b, boolean immunityOverlay, String exponent, String index) {
if (!immunityOverlay && exponent == null && index == null) setImageViewTile(ctx.getResources(), imageView, b);
else {
Drawable[] layers = new Drawable[1+
(immunityOverlay ? 1 : 0)+
(exponent != null ? 1 : 0)+
(index != null ? 1 : 0)];
int tileWidth;
if (density > 1) {
tileWidth = (int)(tileSize*density);
layers[0] = new BitmapDrawable(ctx.getResources(), Bitmap.createScaledBitmap(b, tileWidth, tileWidth, true));
} else {
tileWidth = tileSize;
layers[0] = new BitmapDrawable(ctx.getResources(), b);
}
int nextIndex = 1;
if (immunityOverlay) {
layers[nextIndex] = new BitmapDrawable(ctx.getResources(), preloadedTiles.getBitmap(iconID_immunity_overlay));
nextIndex++;
}
if (exponent != null) {
layers[nextIndex] = new TextDrawable(ctx, tileWidth, tileWidth, exponent, TextDrawable.Align.TOP_RIGHT);
nextIndex++;
}
if (index != null) {
layers[nextIndex] = new TextDrawable(ctx, tileWidth, tileWidth, index, TextDrawable.Align.BOTTOM_RIGHT);
nextIndex++;
}
LayerDrawable layered = new LayerDrawable(layers);
setImageViewTile(imageView, layered);
}
}
public void setImageViewTile(ImageView imageView, Drawable d) {
imageView.setImageDrawable(d);
}
public void setImageViewTile(Resources res, ImageView imageView, ItemType itemType, TileCollection itemTileCollection) {
final Bitmap icon = itemTileCollection.getBitmap(itemType.iconID);
setImageViewTile(res, imageView, itemType, icon);
}
public void setImageViewTileWithOverlay(Resources res, ImageView imageView, int overlayIconID, Bitmap icon, boolean overlayAbove) {
if (overlayIconID != -1) {
Drawable overlayDrawable, iconDrawable;
if (density > 1) {
overlayDrawable = new BitmapDrawable(res, Bitmap.createScaledBitmap(preloadedTiles.getBitmap(overlayIconID), (int)(tileSize*density), (int)(tileSize*density), true));
iconDrawable = new BitmapDrawable(res, Bitmap.createScaledBitmap(icon, (int)(tileSize*density), (int)(tileSize*density), true));
} else {
overlayDrawable = new BitmapDrawable(res, preloadedTiles.getBitmap(overlayIconID));
iconDrawable = new BitmapDrawable(res, icon);
}
if (overlayAbove) {
LayerDrawable layered = new LayerDrawable(new Drawable[] {
iconDrawable
,overlayDrawable
});
setImageViewTile(imageView, layered);
} else {
LayerDrawable layered = new LayerDrawable(new Drawable[] {
overlayDrawable
,iconDrawable
});
setImageViewTile(imageView, layered);
}
} else {
setImageViewTile(res, imageView, icon);
}
}
private void setImageViewTile(Resources res, ImageView imageView, ItemType itemType, Bitmap icon) {
final int overlayIconID = itemType.getOverlayTileID();
setImageViewTileWithOverlay(res, imageView, overlayIconID, icon, false);
}
public Drawable getDrawableForItem(Resources res, int iconID, TileCollection itemTileCollection) {
final Bitmap icon = itemTileCollection.getBitmap(iconID);
if (density > 1) {
return new BitmapDrawable(res, Bitmap.createScaledBitmap(icon, (int)(tileSize*density), (int)(tileSize*density), true));
} else {
return new BitmapDrawable(res, icon);
}
}
public void loadPreloadedTiles(Resources r) {
int maxTileID = tileCache.getMaxTileID();
// if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
// if (maxTileID > preloadedTiles.maxTileID) {
// L.log("ERROR: TileManager.preloadedTiles needs to be initialized with at least " + maxTileID + " slots. Application will crash now.");
// throw new IndexOutOfBoundsException("ERROR: TileManager.preloadedTiles needs to be initialized with at least " + maxTileID + " slots. Application will crash now.");
// }
// }
preloadedTiles = new TileCollection(maxTileID);
for(int i = TileManager.BEGIN_ID; i <= maxTileID; ++i) {
preloadedTileIDs.add(i);
}
tileCache.loadTilesFor(preloadedTileIDs, r, preloadedTiles);
}
private final HashMap<String, HashSet<Integer>> tileIDsPerMap = new HashMap<String, HashSet<Integer>>();
private void addTileIDsFor(HashSet<Integer> dest, String mapName, final Resources res, final WorldContext world) {
HashSet<Integer> cachedTileIDs = tileIDsPerMap.get(mapName);
if (cachedTileIDs == null) {
PredefinedMap adjacentMap = world.maps.findPredefinedMap(mapName);
if (adjacentMap == null) return;
LayeredTileMap adjacentMapTiles = TMXMapTranslator.readLayeredTileMap(res, tileCache, adjacentMap);
cachedTileIDs = getTileIDsFor(adjacentMap, adjacentMapTiles, world);
tileIDsPerMap.put(mapName, cachedTileIDs);
}
if(AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES){
L.log("TileIDsFor " + mapName + "\n" + cachedTileIDs);
}
dest.addAll(cachedTileIDs);
}
public void cacheAdjacentMaps(final Resources res, final WorldContext world, final PredefinedMap nextMap) {
(new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... arg0) {
adjacentMapTiles = null;
HashSet<String> adjacentMapNames = new HashSet<String>();
for (MapObject o : nextMap.eventObjects) {
if (o.type != MapObject.MapObjectType.newmap) continue;
if (o.map == null) continue;
adjacentMapNames.add(o.map);
}
HashSet<Integer> tileIDs = new HashSet<Integer>();
for (String mapName : adjacentMapNames) {
if(AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES){
L.log("addTileIDsFor " + mapName);
}
addTileIDsFor(tileIDs, mapName, res, world);
}
long freeMemRequired = tileSize * tileSize * tileIDs.size() * 4 /*RGBA_8888*/ * 2 /*Require twice the needed size, to leave room for others*/;
Runtime r = Runtime.getRuntime();
if (r.maxMemory() - r.totalMemory() > freeMemRequired) {
adjacentMapTiles = tileCache.loadTilesFor(tileIDs, res);
}
return null;
}
}).execute();
}
private static class TextDrawable extends Drawable {
private String text;
private int size = 15;
private Align align = Align.CENTER;
private Paint mFillPaint;
private Paint mStrokePaint;
private Rect textBounds;
private int cHeight;
private int cWidth;
public enum Align {
TOP,
TOP_LEFT,
TOP_RIGHT,
CENTER,
LEFT,
RIGHT,
BOTTOM,
BOTTOM_LEFT,
BOTTOM_RIGHT
}
public TextDrawable(Context ctx, int cWidth, int cHeight, String text, Align align, int size) {
this.text= text;
this.align = align;
this.size = size;
this.cWidth = cWidth;
this.cHeight = cHeight;
init(ctx);
}
public TextDrawable(Context ctx, int cWidth, int cHeight, String text, Align align) {
this.text= text;
this.align = align;
this.cWidth = cWidth;
this.cHeight = cHeight;
init(ctx);
}
public TextDrawable(Context ctx, int cWidth, int cHeight, String text) {
this.text= text;
this.cWidth = cWidth;
this.cHeight = cHeight;
init(ctx);
}
public void init(Context ctx) {
mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFillPaint.setColor(ThemeHelper.getThemeColor(ctx, R.attr.ui_theme_dialogue_light_color));
// mFillPaint.setShadowLayer(5f * res.getDisplayMetrics().scaledDensity, 1, 1, res.getColor(android.R.color.black));
mFillPaint.setStyle(Paint.Style.FILL);
mFillPaint.setTextSize(size * ctx.getResources().getDisplayMetrics().scaledDensity);
textBounds = new Rect();
mFillPaint.getTextBounds(text, 0, text.length(), textBounds);
mStrokePaint=new Paint(mFillPaint);
// mStrokePaint.setStyle(Paint.Style.FILL);
// mStrokePaint.setStrokeWidth(1f * res.getDisplayMetrics().scaledDensity);
mStrokePaint.setColor(ThemeHelper.getThemeColor(ctx, R.attr.ui_theme_buttonbar_bg_color));
}
@Override
public void draw(Canvas canvas) {
float x,y;
switch (align) {
case BOTTOM:
case BOTTOM_LEFT:
case BOTTOM_RIGHT:
y = cHeight - textBounds.bottom;
break;
case CENTER:
case LEFT:
case RIGHT:
y = (cHeight - textBounds.height()) / 2;
break;
case TOP:
case TOP_LEFT:
case TOP_RIGHT:
default:
y = 0 - textBounds.top;
break;
}
switch (align) {
case BOTTOM:
case CENTER:
case TOP:
x = (cWidth - textBounds.width()) / 2;
break;
case BOTTOM_LEFT:
case LEFT:
case TOP_LEFT:
default:
x = 0 - textBounds.left;
break;
case BOTTOM_RIGHT:
case RIGHT:
case TOP_RIGHT:
x = cWidth - textBounds.right;
break;
}
canvas.drawRect(x, y - textBounds.height(), x + textBounds.width(), y, mStrokePaint);
canvas.drawText(text, x, y, mFillPaint);
// canvas.drawText(text, x, y, mStrokePaint);
}
@Override
public void setAlpha(int alpha) {
mFillPaint.setAlpha(alpha);
// mStrokePaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
mFillPaint.setColorFilter(cf);
// mStrokePaint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return mFillPaint.getAlpha();
}
@Override
public int getIntrinsicWidth() {
return cWidth;
}
@Override
public int getIntrinsicHeight() {
return cHeight;
}
@Override
public boolean getPadding(Rect padding) {
padding.bottom = 0;
padding.top = 0;
padding.left = 0;
padding.right = 0;
return false;
}
}
}

View File

@@ -1,60 +0,0 @@
package com.gpl.rpg.AndorsTrail.savegames;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.WorldMapController;
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment;
import com.gpl.rpg.AndorsTrail.util.L;
import android.content.res.Resources;
public class LegacySavegamesContentAdaptations {
public static void adaptToNewContentForVersion45(WorldContext world, ControllerContext controllers, Resources res) {
PredefinedMap fields5Map = world.maps.findPredefinedMap("fields5");
if (fields5Map != null) {
for (MonsterSpawnArea area : fields5Map.spawnAreas) {
if (area.monsters != null) {
for (Monster m : area.monsters) {
if (m.getMonsterTypeID().equals("feygard_bridgeguard")) {
area.resetForNewGame();
for (MonsterSpawnArea newarea : fields5Map.spawnAreas) {
if (newarea.areaID.equals("guynmart_robber1")) {
controllers.monsterSpawnController.spawnAllInArea(fields5Map,
(world.model.currentMaps.map == fields5Map ? world.model.currentMaps.tileMap : null),
newarea, true);
break;
}
}
break;
}
}
}
}
}
//Force update of existing worldmaps to ensure regenerating the html when needed, using the new UTF-8-enabled template.
List<String> segmentsCovered = new LinkedList<String>();
for (WorldMapSegment segment : world.maps.worldMapSegments.values()) {
if (segment == null || segment.name == null) continue;
if (segmentsCovered.contains(segment.name)) continue;
segmentsCovered.add(segment.name);
try {
WorldMapController.updateWorldMapSegment(controllers.getContext(), res, world, segment.name);
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Forcing generation of worldmap file for segment " + segment.name);
}
} catch (IOException e) {
L.log("Error creating worldmap file for segment " + segment.name + " : " + e.toString());
}
}
}
}

View File

@@ -1,394 +0,0 @@
package com.gpl.rpg.AndorsTrail.savegames;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.content.res.Resources;
import android.os.SystemClock;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
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.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;
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;
// 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();
FileOutputStream fos = getOutputFile(androidContext, slot);
fos.write(savegame);
fos.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();
}
}
return true;
} catch (IOException e) {
L.log("Error saving world: " + e.toString());
return false;
}
}
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();
}
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;
}
}
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();
}
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 (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
}
dataInputStream.close();
fileInputStream.close();
}
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 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 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;
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);
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();
}
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);
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();
}
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 new ArrayList<Integer>();
}
}
private static final class CheatDetection {
public final int fileversion;
public final long savedVersion;
// ====== PARCELABLE ===================================================================
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 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 ===================================================================
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 >= 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);
}
}
}

View File

@@ -1,472 +0,0 @@
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 androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;
import androidx.documentfile.provider.DocumentFile;
import android.os.Handler;
import android.os.Looper;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.util.BackgroundWorker.BackgroundWorkerCallback;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public final class AndroidStorage {
public static File getStorageDirectory(Context context, String name) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return context.getExternalFilesDir(name);
} 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);
File internalSaveGameDirectory = getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
if (externalSaveGameDirectory.exists()
&& externalSaveGameDirectory.isDirectory()
&& externalSaveGameDirectory.listFiles().length > 0
&& (!internalSaveGameDirectory.exists()
|| internalSaveGameDirectory.isDirectory()
&& internalSaveGameDirectory.listFiles().length < 2)) {
ret = true;
}
return ret;
}
public static boolean migrateToInternalStorage(Context context) {
try {
copy(new File(Environment.getExternalStorageDirectory(), Constants.CHEAT_DETECTION_FOLDER),
getStorageDirectory(context, Constants.CHEAT_DETECTION_FOLDER));
copy(new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY),
getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY));
} catch (IOException e) {
L.log("Error migrating data: " + e);
return false;
}
return true;
}
private static void copy(File sourceLocation, File targetLocation) throws IOException {
if (!sourceLocation.exists()) {
return;
}
if (sourceLocation.isDirectory()) {
copyDirectory(sourceLocation, targetLocation);
} else {
copyFile(sourceLocation, targetLocation);
}
}
private static void copyDirectory(File source, File target) throws IOException {
if (!target.exists()) {
target.mkdir();
}
for (String f : source.list()) {
copy(new File(source, f), new File(target, f));
}
}
public static void copyFile(File source, File target) throws IOException {
try (InputStream in = new FileInputStream(source); OutputStream out = new FileOutputStream(target)) {
copyStream(in, out);
}
}
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);
}
}
@RequiresApi(api = Build.VERSION_CODES.P)
public static void createZipDocumentFileFromFilesAsync(File[] files,
Context context,
DocumentFile targetDirectory,
String fileName,
String loadingMessage,
Consumer<Boolean> callback) {
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
progressDialog.setOnCancelListener(dialog -> worker.cancel());
ContentResolver resolver = context.getContentResolver();
Handler handler = Handler.createAsync(Looper.getMainLooper());
worker.setTask(workerCallback -> {
try {
workerCallback.onInitialize();
//region create zip file
File zip = File.createTempFile("temp_worldmap", ".zip");
try (OutputStream out = new FileOutputStream(zip)) {
ZipOutputStream zipOut = new ZipOutputStream(out);
for (int i = 0; i < files.length; i++) {
File file = files[i];
try (FileInputStream fis = new FileInputStream(file)) {
workerCallback.onProgress((float) i / files.length);
zipOut.putNextEntry(new ZipEntry(file.getName()));
copyStream(fis, zipOut);
zipOut.closeEntry();
}
}
zipOut.close();
}
//endregion
DocumentFile worldmapZip = DocumentFile.fromFile(zip);
DocumentFile worldmapTarget = targetDirectory.createFile("application/zip", fileName);
if (worldmapTarget != null && worldmapTarget.exists()) {
AndroidStorage.copyDocumentFile(worldmapZip, resolver, worldmapTarget);
workerCallback.onComplete(true);
} else {
throw new FileNotFoundException("Could not create File");
}
} catch (NullPointerException e) {
if (worker.isCancelled()) {
workerCallback.onFailure(new CancellationException("Cancelled"));
} else {
workerCallback.onFailure(e);
}
} catch (Exception e) {
workerCallback.onFailure(e);
}
});
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
worker.run();
}
public static void unzipToDirectory(File zipFile,
File targetDirectory,
boolean overwriteNotSkip) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
unzipStreamToDirectory(targetDirectory, overwriteNotSkip, zis);
}
}
@RequiresApi(api = Build.VERSION_CODES.P)
public static void unzipDocumentFileToDirectoryAsync(DocumentFile zipFile,
Context context,
File targetDirectory,
boolean overwriteNotSkip,
String loadingMessage,
Consumer<Boolean> callback) {
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
progressDialog.setOnCancelListener(dialog -> worker.cancel());
ContentResolver resolver = context.getContentResolver();
Handler handler = Handler.createAsync(Looper.getMainLooper());
worker.setTask(workerCallback -> {
try {
workerCallback.onInitialize();
workerCallback.onProgress(-1);//set dummy progress since we don't know the
// progress of the unzip
unzipDocumentFileToDirectory(zipFile, resolver, targetDirectory, overwriteNotSkip);
workerCallback.onComplete(true);
} catch (IOException e) {
workerCallback.onFailure(e);
}
});
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
worker.run();
}
public static void unzipDocumentFileToDirectory(DocumentFile zipFile,
ContentResolver resolver,
File targetDirectory,
boolean overwriteNotSkip) throws IOException {
try (ZipInputStream zis = new ZipInputStream(resolver.openInputStream(zipFile.getUri()))) {
unzipStreamToDirectory(targetDirectory, overwriteNotSkip, zis);
}
}
private static void unzipStreamToDirectory(File targetDirectory,
boolean overwriteNotSkip,
ZipInputStream zis) throws IOException {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
File file = new File(targetDirectory, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
file.getParentFile().mkdirs();
if (file.exists() && !overwriteNotSkip) {
continue;
}
try (FileOutputStream fos = new FileOutputStream(file)) {
copyStream(zis, fos);
}
}
}
}
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);
}
}
public static String getUrlForFile(Context context, File worldmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
String applicationId = context.getPackageName();
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() {
return new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
}
@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;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static Intent getNewSelectZipIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/zip");
return intent;
}
@RequiresApi(api = Build.VERSION_CODES.P)
public static void copyDocumentFilesFromToAsync(DocumentFile[] sources,
Context context,
DocumentFile[] targets,
String loadingMessage,
Consumer<Boolean> callback) {
if (sources.length != targets.length) {
throw new IllegalArgumentException("Both arrays, target & source have to have the same size");
}
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
progressDialog.setOnCancelListener(dialog -> worker.cancel());
ContentResolver resolver = context.getContentResolver();
Handler handler = Handler.createAsync(Looper.getMainLooper());
worker.setTask(workerCallback -> {
try {
workerCallback.onInitialize();
for (int i = 0; i < sources.length; i++) {
if (worker.isCancelled()) {
workerCallback.onFailure(new CancellationException("Cancelled"));
return;
}
DocumentFile source = sources[i];
DocumentFile target = targets[i];
if (source == null || target == null) {
continue;
}
copyDocumentFile(source, resolver, target);
float progress = i / (float) sources.length;
workerCallback.onProgress(progress);
}
workerCallback.onComplete(true);
} catch (NullPointerException e) {
if (worker.isCancelled()) {
workerCallback.onFailure(new CancellationException("Cancelled"));
return;
}
} catch (Exception e) {
workerCallback.onFailure(e);
}
});
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
worker.run();
}
@RequiresApi(api = Build.VERSION_CODES.P)
public static void copyDocumentFilesToDirAsync(DocumentFile[] files,
Context context,
DocumentFile targetDirectory,
String loadingMessage,
Consumer<Boolean> callback) {
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
progressDialog.setOnCancelListener(dialog -> worker.cancel());
ContentResolver resolver = context.getContentResolver();
Handler handler = Handler.createAsync(Looper.getMainLooper());
worker.setTask(workerCallback -> {
try {
workerCallback.onInitialize();
for (int i = 0; i < files.length; i++) {
if (worker.isCancelled()) {
workerCallback.onFailure(new CancellationException("Cancelled"));
return;
}
DocumentFile file = files[i];
if (file == null) {
continue;
}
copyDocumentFileToNewOrExistingFile(file, resolver, targetDirectory);
float progress = i / (float) files.length;
workerCallback.onProgress(progress);
}
workerCallback.onComplete(true);
} catch (NullPointerException e) {
if (worker.isCancelled()) {
workerCallback.onFailure(new CancellationException("Cancelled"));
}
} catch (Exception e) {
workerCallback.onFailure(e);
}
});
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
worker.run();
}
private static BackgroundWorkerCallback<Boolean> getDefaultBackgroundWorkerCallback(Handler handler,
CustomDialogFactory.CustomDialog progressDialog,
Consumer<Boolean> callback) {
return new BackgroundWorkerCallback<Boolean>() {
private int progress = -1;
@Override
public void onInitialize() {
handler.post(() -> {
CustomDialogFactory.show(progressDialog);
});
}
@Override
public void onProgress(float progress) {
handler.post(() -> {
int intProgress = (int) (progress * 100);
if (this.progress == intProgress) {
return;
}
this.progress = intProgress;
if (progress == -1) {
CustomDialogFactory.setDesc(progressDialog, null);
return;
}
CustomDialogFactory.setDesc(progressDialog, intProgress + "%");
});
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onFailure(Exception e) {
this.onComplete(false);
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onComplete(Boolean result) {
handler.post(() -> {
progressDialog.dismiss();
callback.accept(result);
});
}
};
}
private static CustomDialogFactory.CustomDialog getLoadingDialog(Context context) {
return getLoadingDialog(context, null);
}
private static CustomDialogFactory.CustomDialog getLoadingDialog(Context context, String message) {
if (message == null) {
message = context.getResources().getString(R.string.dialog_loading_message);
}
CustomDialogFactory.CustomDialog dialog = CustomDialogFactory.createDialog(context,
message,
context.getResources()
.getDrawable(R.drawable.loading_anim),
null,
null,
true,
false);
CustomDialogFactory.addCancelButton(dialog, android.R.string.no);
return dialog;
}
}

View File

@@ -1,46 +0,0 @@
package com.gpl.rpg.AndorsTrail.util;
import java.util.concurrent.Executors;
public final class BackgroundWorker<T> {
boolean cancelled = false;
worker<T> task;
BackgroundWorkerCallback<T> callback;
public void setTask(worker<T> task) {
this.task = task;
}
public void setCallback(BackgroundWorkerCallback<T> callback) {
this.callback = callback;
}
public void cancel() {
cancelled = true;
}
interface worker<T> {
void doWork(BackgroundWorkerCallback<T> callback);
}
interface BackgroundWorkerCallback<T> {
void onInitialize();
default void onProgress(float progress) {
}
void onFailure(Exception e);
void onComplete(T result);
}
public void run() {
Executors.newSingleThreadExecutor().execute(() -> {
task.doWork(callback);
});
}
public boolean isCancelled() {
return cancelled;
}
}

View File

@@ -1,16 +0,0 @@
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

@@ -1,87 +0,0 @@
package com.gpl.rpg.AndorsTrail.util;
import java.util.HashMap;
import java.util.Map;
import com.gpl.rpg.AndorsTrail.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
public class ThemeHelper {
private static final class ThemeSet {
int baseThemeRes, noBackgroundThemeRes, dialogThemeRes;
public ThemeSet(int baseThemeRes, int noBackgroundThemeRes, int dialogThemeRes) {
this.baseThemeRes = baseThemeRes;
this.noBackgroundThemeRes = noBackgroundThemeRes;
this.dialogThemeRes = dialogThemeRes;
}
}
public static enum Theme {
blue,
green,
charcoal
}
private static final Map<Theme, ThemeSet> THEME_SETS = new HashMap<ThemeHelper.Theme, ThemeHelper.ThemeSet>();
private static Theme SELECTED_THEME = Theme.blue;
private static boolean first = true;
static {
THEME_SETS.put(Theme.blue, new ThemeSet(R.style.AndorsTrailTheme_Blue, R.style.AndorsTrailTheme_Blue_NoBackground, R.style.AndorsTrailDialogTheme_Blue));
THEME_SETS.put(Theme.green, new ThemeSet(R.style.AndorsTrailTheme_Green, R.style.AndorsTrailTheme_Green_NoBackground, R.style.AndorsTrailDialogTheme_Green));
THEME_SETS.put(Theme.charcoal, new ThemeSet(R.style.AndorsTrailTheme_Charcoal, R.style.AndorsTrailTheme_Charcoal_NoBackground, R.style.AndorsTrailDialogTheme_Charcoal));
}
public static int getThemeColor(Context context, int attrResId) {
TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] {attrResId});
int c = ta.getColor(0, Color.BLACK);
ta.recycle();
return c;
}
public static int getThemeResource(Context context, int attrResId) {
TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] {attrResId});
int resId = ta.getResourceId(0, 0);
ta.recycle();
return resId;
}
public static Drawable getThemeDrawable(Context context, int attrResId) {
TypedArray ta = context.getTheme().obtainStyledAttributes(new int[] {attrResId});
Drawable d = ta.getDrawable(0);
ta.recycle();
return d;
}
public static int getBaseTheme() {
return THEME_SETS.get(SELECTED_THEME).baseThemeRes;
}
public static int getNoBackgroundTheme() {
return THEME_SETS.get(SELECTED_THEME).noBackgroundThemeRes;
}
public static int getDialogTheme() {
return THEME_SETS.get(SELECTED_THEME).dialogThemeRes;
}
//Returns true if theme has changed after startup.
public static boolean changeTheme(int id) {
Theme t = Theme.values()[id];
if (t == SELECTED_THEME) {
first = false;
return false;
}
SELECTED_THEME = t;
if (first) {
first = false;
return false;
}
return true;
}
}

View File

@@ -1,223 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import java.util.concurrent.ConcurrentHashMap;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.gpl.rpg.AndorsTrail.R;
public class CloudsAnimatorView extends FrameLayout {
private static final int DEFAULT_DURATION = 80000;
private static final float SPEED_VARIANCE = 0.08f;
private static final float BELOW_SPEED_FACTOR = 0.8f;
private static final float CENTER_SPEED_FACTOR = 1.0f;
private static final float ABOVE_SPEED_FACTOR = 1.2f;
public static enum Layer {
below,
center,
above
}
private static final int[] belowDrawablesId = new int[]{R.drawable.ts_clouds_s_01, R.drawable.ts_clouds_s_02, R.drawable.ts_clouds_s_03};
private static final int[] centerDrawablesId = new int[]{R.drawable.ts_clouds_m_01, R.drawable.ts_clouds_m_02};
private static final int[] aboveDrawablesId = new int[]{R.drawable.ts_clouds_l_01, R.drawable.ts_clouds_l_02, R.drawable.ts_clouds_l_03, R.drawable.ts_clouds_l_04};
private int[] drawableIds = centerDrawablesId;
private float speedFactor = CENTER_SPEED_FACTOR;
private int count = 15;
private ViewGroup layer;
private int duration = DEFAULT_DURATION;
private int yMax = 100;
private float scalingRatio = 1.0f;
private ConcurrentHashMap<ImageView, PausableTranslateAnimation> animations;
public CloudsAnimatorView(Context context) {
super(context);
init();
}
public CloudsAnimatorView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CloudsAnimatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setFocusable(false);
inflate(getContext(), R.layout.clouds_animator, this);
layer = (ViewGroup) findViewById(R.id.ts_clouds_layer);
}
public void setCloudsCountAndLayer(int count, Layer layer) {
this.count = count;
switch (layer) {
case above:
drawableIds = aboveDrawablesId;
speedFactor = ABOVE_SPEED_FACTOR;
break;
case below:
drawableIds = belowDrawablesId;
speedFactor = BELOW_SPEED_FACTOR;
break;
case center:
drawableIds = centerDrawablesId;
speedFactor = CENTER_SPEED_FACTOR;
break;
}
animations = new ConcurrentHashMap<ImageView, PausableTranslateAnimation>(count);
}
private void createCloud() {
final ImageView iv = new ImageView(getContext());
iv.setImageDrawable(getResources().getDrawable(drawableIds[(int)(drawableIds.length * Math.random())]));
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int) (iv.getDrawable().getIntrinsicWidth() * scalingRatio), (int) (iv.getDrawable().getIntrinsicHeight() * scalingRatio));//RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layer.addView(iv, lp);
final float y = (float) (Math.random() * yMax) - (int) (iv.getDrawable().getIntrinsicHeight() * scalingRatio);
float ratio = (float)Math.random();
final float x = (float) (((1-ratio) * (iv.getDrawable().getMinimumWidth() + layer.getWidth())) - iv.getDrawable().getMinimumWidth());
final long d = (long)((ratio * duration) / (speedFactor + (Math.random() * SPEED_VARIANCE)));
prepareAnimation(iv, layer, speedFactor, x, y, d);
}
private void resetCloud(final ImageView iv) {
final float y = (float) (Math.random() * yMax) - (int) (iv.getDrawable().getIntrinsicHeight() * scalingRatio);
final float x = -iv.getWidth();
final long d = (long)(duration / (speedFactor + (Math.random() * SPEED_VARIANCE)));
prepareAnimation(iv, layer, speedFactor, x, y, d);
}
private void prepareAnimation(final ImageView iv, final ViewGroup layer, final float speedFactor, final float x, final float y, final long d) {
PausableTranslateAnimation anim = new PausableTranslateAnimation(
TranslateAnimation.ABSOLUTE, x, TranslateAnimation.ABSOLUTE, layer.getWidth(),
TranslateAnimation.ABSOLUTE, y, TranslateAnimation.ABSOLUTE, y);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
iv.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
iv.setVisibility(View.GONE);
resetCloud(iv);
}
});
anim.setInterpolator(new LinearInterpolator());
anim.setDuration(d);
animations.put(iv, anim);
iv.startAnimation(anim);
if (paused) {
anim.pause();
}
}
public void startAnimation() {
int i = count;
while (i-- > 0) {
createCloud();
}
}
boolean started = false;
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
if (!started) {
startAnimation();
started = true;
}
}
}
private boolean paused = false;
public void resumeAnimation() {
paused = false;
if (started) {
for (PausableTranslateAnimation a : animations.values()) {
a.resume();
}
}
}
public void pauseAnimation() {
paused = true;
for (PausableTranslateAnimation a : animations.values()) {
a.pause();
}
}
public void setScalingRatio(float ratio) {
this.scalingRatio = ratio;
duration = (int) (DEFAULT_DURATION * getWidth() / (1024 * ratio));
}
public void setYMax(int yMax) {
this.yMax = yMax;
}
private static class PausableTranslateAnimation extends TranslateAnimation {
private long elapsedAtPause = 0;
private boolean paused = false;
private boolean resume = false;
public PausableTranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
int fromYType, float fromYValue, int toYType, float toYValue) {
super(fromXType, fromXValue, toXType, toXValue, fromYType, fromYValue, toYType, toYValue);
}
@Override
public boolean getTransformation(long currentTime, Transformation outTransformation) {
if (paused && elapsedAtPause == 0) {
elapsedAtPause = currentTime - getStartTime();
}
if (paused) {
setStartTime(currentTime - elapsedAtPause);
if (resume) {
paused = false;
resume = false;
}
}
return super.getTransformation(currentTime, outTransformation);
}
public void pause() {
elapsedAtPause = 0;
paused = true;
}
public void resume() {
if (paused) resume = true;
}
}
}

View File

@@ -1,247 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import android.content.Context;
import android.content.DialogInterface.OnDismissListener;
import android.content.DialogInterface.OnCancelListener;
import android.graphics.Rect;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.view.ContextThemeWrapper;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
public class CustomDialogFactory {
public static class CustomDialog extends android.app.Dialog {
public CustomDialog(Context context) {
super(context);
}
boolean verticalButtons = false;
}
public static CustomDialog createDialog(final Context context, String title, Drawable icon,
String desc, View content, boolean hasButtons, boolean canDismiss) {
return createDialog(context, title, icon, desc, content, hasButtons, canDismiss, false);
}
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 boolean verticalButtons) {
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.verticalButtons = verticalButtons;
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 = getButtonContainer(dialog);
ViewGroup unusedButtonsHolder = getUnusedButtonContainer(dialog);
unusedButtonsHolder.setVisibility(View.GONE);
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 CustomDialog addButton(final CustomDialog dialog, String text, final OnClickListener listener) {
return addButton(dialog, -1, text, listener);
}
public static CustomDialog addButton(final CustomDialog dialog, int textId, final OnClickListener listener) {
return addButton(dialog, textId, null, listener);
}
public static CustomDialog addButton(final CustomDialog dialog, int textId, String text, final OnClickListener listener) {
Button template = getButtonTemplate(dialog);
LayoutParams params = template.getLayoutParams();
ViewGroup buttonsHolder = getButtonContainer(dialog);
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));
if(textId != -1) {
b.setText(textId);
} else {
b.setText(text);
}
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(v);
dialog.dismiss();
}
});
buttonsHolder.addView(b, params);
return dialog;
}
public static CustomDialog addDismissButton(final CustomDialog dialog, int textId) {
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
public static CustomDialog addCancelButton(final CustomDialog dialog, int textId) {
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
@Override
public void onClick(View v) {
dialog.cancel();
}
});
}
public static CustomDialog setDismissListener(CustomDialog dialog, OnDismissListener listener) {
dialog.setOnDismissListener(listener);
return dialog;
}
public static CustomDialog setCancelListener(CustomDialog dialog, OnCancelListener listener) {
dialog.setOnCancelListener(listener);
return dialog;
}
public static void show(CustomDialog dialog) {
dialog.findViewById(R.id.dialog_template_button).setVisibility(View.GONE);
dialog.findViewById(R.id.dialog_template_button_vertical).setVisibility(View.GONE);
dialog.show();
}
private static ViewGroup getUnusedButtonContainer(CustomDialog dialog) {
if (dialog.verticalButtons)
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
else
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container_vertical);
}
private static ViewGroup getButtonContainer(CustomDialog dialog) {
if (dialog.verticalButtons)
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container_vertical);
else
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
}
private static Button getButtonTemplate(CustomDialog dialog) {
if (dialog.verticalButtons)
return (Button) dialog.findViewById(R.id.dialog_template_button_vertical);
else
return (Button) dialog.findViewById(R.id.dialog_template_button);
}
}

View File

@@ -1,101 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
public class CustomListPreference extends ListPreference {
//Extensive constructor support
public CustomListPreference(Context context) {
super(context);
}
public CustomListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
// Min API 21
// @TargetApi(Build.VERSION_CODES.LOLLIPOP)
// public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
// super(context, attrs, defStyleAttr);
// }
// @TargetApi(Build.VERSION_CODES.LOLLIPOP)
// public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
// super(context, attrs, defStyleAttr, defStyleRes);
// }
CustomDialog d = null;
int clickedEntryIndex = 0;
@Override
public Dialog getDialog() {
if (d == null) createDialog();
return d;
}
private void createDialog() {
final ListView choicesList = new ListView(getContext());
choicesList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
choicesList.setBackgroundResource(android.R.color.transparent);
ArrayAdapter<CharSequence> choicesAdapter = new ArrayAdapter<CharSequence>(getContext(), R.layout.custom_checkedlistitem_layout, getEntries());
choicesList.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, ListView.LayoutParams.WRAP_CONTENT));
choicesList.setAdapter(choicesAdapter);
choicesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (getValue() != getEntryValues()[position]) {
CustomListPreference.this.notifyChanged();
clickedEntryIndex = position;
CustomListPreference.this.onClick(d, DialogInterface.BUTTON_POSITIVE);
} else {
CustomListPreference.this.onClick(d, DialogInterface.BUTTON_NEGATIVE);
}
d.dismiss();
}
});
choicesList.setItemChecked(getValueIndex(), true);
d = CustomDialogFactory.createDialog(getContext(), getTitle().toString(), null, null, choicesList, false);
}
public int getValueIndex() {
int selectedPosition;
for (selectedPosition = getEntryValues().length - 1; selectedPosition >= 0; selectedPosition--) {
if (getValue().equals(getEntryValues()[selectedPosition].toString())) break;
}
return selectedPosition;
}
@Override
protected void onDialogClosed(boolean positiveResult) {
CharSequence[] entryValues = getEntryValues();
if (positiveResult && clickedEntryIndex >= 0 && entryValues != null) {
String value = entryValues[clickedEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
}
@Override
protected void showDialog(Bundle state) {
getDialog().setOnDismissListener(this);
getDialog().show();
}
@Override
public void onDismiss(DialogInterface dialog) {
d = null;
super.onDismiss(dialog);
}
}

View File

@@ -1,559 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import java.util.ArrayList;
import java.util.List;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class CustomMenuInflater {
public interface MenuItemSelectedListener {
public void onMenuItemSelected(MenuItem item, Object data);
}
public static Dialog showMenuInDialog(Activity activity, Menu menu, Drawable icon, String title, Object data, MenuItemSelectedListener listener ) {
Dialog d = getMenuDialog(activity, menu, icon, title, data, listener);
d.show();
return d;
}
public static Dialog getMenuDialog(Activity activity, Menu menu, Drawable icon, String title, Object data, MenuItemSelectedListener listener ) {
final CustomDialog dialog = CustomDialogFactory.createDialog(activity, title, icon, null, null, false);
View v = getMenuView(activity, menu, icon, title, data, dialog, listener);
v.setLayoutParams(getItemLayoutParams());
CustomDialogFactory.setContent(dialog, v);
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
return dialog;
}
public static View getMenuView(Activity activity, Menu menu, Drawable icon, String title, Object data, Dialog dialog, MenuItemSelectedListener listener ) {
ViewGroup scroll = (ViewGroup) activity.getLayoutInflater().inflate(R.layout.custom_menu_layout, null);
ViewGroup vg = (ViewGroup) scroll.findViewById(R.id.custom_menu_items_wrapper);
MenuItem item;
boolean first =true;
for (int i = 0; i < menu.size(); i++) {
item = menu.getItem(i);
if (item.isVisible()) {
if (first) {
first = false;
} else {
addMenuItemSeparator(activity, vg);
}
if (item.hasSubMenu()) {
addSubMenuItemView(activity, vg, icon, title, item, data, dialog, listener);
} else {
addMenuItemView(activity, vg, item, data, dialog, listener);
}
}
}
return scroll;
}
private static void addMenuItemView(Activity activity, ViewGroup vg, final MenuItem item, final Object data, final Dialog dialog, final MenuItemSelectedListener listener) {
TextView tv = (TextView) activity.getLayoutInflater().inflate(R.layout.custom_menu_item_layout, null);
tv.setText(item.getTitle());
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onMenuItemSelected(item, data);
dialog.dismiss();
}
});
tv.setLayoutParams(getItemLayoutParams());
vg.addView(tv);
}
private static void addSubMenuItemView(final Activity activity, ViewGroup vg, final Drawable icon, final String title, final MenuItem item, final Object data, final Dialog dialog, final MenuItemSelectedListener listener) {
TextView tv = (TextView) activity.getLayoutInflater().inflate(R.layout.custom_menu_submenu_layout, null);
tv.setText(item.getTitle());
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showMenuInDialog(activity, item.getSubMenu(), icon, title, data, listener);
dialog.dismiss();
}
});
tv.setLayoutParams(getItemLayoutParams());
vg.addView(tv);
}
private static void addMenuItemSeparator(final Activity activity, ViewGroup vg) {
View v = activity.getLayoutInflater().inflate(R.layout.custom_menu_item_separator_layout, null);
v.setLayoutParams(getItemLayoutParams());
vg.addView(v);
}
private static LayoutParams getItemLayoutParams() {
return new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
}
public static Menu newMenuInstance(Context context) {
return new DummyMenu(context);
}
private static class DummyMenu implements Menu {
Context context;
List<MenuItem> items = new ArrayList<MenuItem>();
public DummyMenu(Context context) {
this.context = context;
}
@Override
public MenuItem add(CharSequence title) {
MenuItem item = new DummyMenuItem(context, title, -1, null);
items.add(item);
return item;
}
@Override
public MenuItem add(int titleRes) {
return add(context.getString(titleRes));
}
@Override
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
MenuItem item = new DummyMenuItem(context, title, itemId, null);
items.add(item);
return item;
}
@Override
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
return add(groupId, itemId, order, context.getString(titleRes));
}
@Override
public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics,
Intent intent, int flags, MenuItem[] outSpecificItems) {
return 0;
}
@Override
public SubMenu addSubMenu(CharSequence title) {
DummySubMenu sm = new DummySubMenu(context, title);
MenuItem item = new DummyMenuItem(context, title, 0, sm);
items.add(item);
return sm;
}
@Override
public SubMenu addSubMenu(int titleRes) {
return addSubMenu(context.getString(titleRes));
}
@Override
public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
DummySubMenu sm = new DummySubMenu(context, title);
MenuItem item = new DummyMenuItem(context, title, itemId, sm);
items.add(item);
return sm;
}
@Override
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
return addSubMenu(groupId, itemId, order, context.getString(titleRes));
}
@Override
public void clear() {
items.clear();
}
@Override
public void close() {}
@Override
public MenuItem findItem(int id) {
MenuItem found = null;
for (MenuItem item : items) {
if (item.getItemId() == id) return item;
if (item.hasSubMenu()) {
found = item.getSubMenu().findItem(id);
if (found != null) return found;
}
}
return null;
}
@Override
public MenuItem getItem(int index) {
return items.get(index);
}
@Override
public boolean hasVisibleItems() {
for (MenuItem item : items) {
if (item.isVisible()) return true;
}
return false;
}
@Override
public boolean isShortcutKey(int keyCode, KeyEvent event) {
return false;
}
@Override
public boolean performIdentifierAction(int id, int flags) {
return false;
}
@Override
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
return false;
}
@Override
public void removeGroup(int groupId) {
}
@Override
public void removeItem(int id) {
MenuItem found = null;
for (MenuItem item : items) {
if (item.getItemId() == id) found=item;
if (item.hasSubMenu()) {
item.getSubMenu().removeItem(id);
}
}
}
@Override
public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
}
@Override
public void setGroupEnabled(int group, boolean enabled) {
}
@Override
public void setGroupVisible(int group, boolean visible) {
}
@Override
public void setQwertyMode(boolean isQwerty) {
}
@Override
public int size() {
return items.size();
}
}
private static class DummyMenuItem implements MenuItem {
Context context;
CharSequence title;
int id;
DummySubMenu subMenu;
boolean visible = true;
public DummyMenuItem(Context context, CharSequence title, int id, DummySubMenu subMenu) {
this.context = context;
this.title = title;
this.id = id;
this.subMenu = subMenu;
if (subMenu != null) subMenu.setItem(this);
}
@Override
public boolean collapseActionView() {
return false;
}
@Override
public boolean expandActionView() {
return false;
}
@Override
public ActionProvider getActionProvider() {
return null;
}
@Override
public View getActionView() {
return null;
}
@Override
public char getAlphabeticShortcut() {
return 0;
}
@Override
public int getGroupId() {
return 0;
}
@Override
public Drawable getIcon() {
return null;
}
@Override
public Intent getIntent() {
return null;
}
@Override
public int getItemId() {
return id;
}
@Override
public ContextMenuInfo getMenuInfo() {
return null;
}
@Override
public char getNumericShortcut() {
return 0;
}
@Override
public int getOrder() {
return 0;
}
@Override
public SubMenu getSubMenu() {
return subMenu;
}
@Override
public CharSequence getTitle() {
return title;
}
@Override
public CharSequence getTitleCondensed() {
return null;
}
@Override
public boolean hasSubMenu() {
return subMenu != null;
}
@Override
public boolean isActionViewExpanded() {
return false;
}
@Override
public boolean isCheckable() {
return false;
}
@Override
public boolean isChecked() {
return false;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isVisible() {
return visible;
}
@Override
public MenuItem setActionProvider(ActionProvider actionProvider) {
return this;
}
@Override
public MenuItem setActionView(View view) {
return this;
}
@Override
public MenuItem setActionView(int resId) {
return this;
}
@Override
public MenuItem setAlphabeticShortcut(char alphaChar) {
return this;
}
@Override
public MenuItem setCheckable(boolean checkable) {
return this;
}
@Override
public MenuItem setChecked(boolean checked) {
return this;
}
@Override
public MenuItem setEnabled(boolean enabled) {
return this;
}
@Override
public MenuItem setIcon(Drawable icon) {
return this;
}
@Override
public MenuItem setIcon(int iconRes) {
return this;
}
@Override
public MenuItem setIntent(Intent intent) {
return this;
}
@Override
public MenuItem setNumericShortcut(char numericChar) {
return this;
}
@Override
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
return this;
}
@Override
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
return this;
}
@Override
public MenuItem setShortcut(char numericChar, char alphaChar) {
return this;
}
@Override
public void setShowAsAction(int actionEnum) {
}
@Override
public MenuItem setShowAsActionFlags(int actionEnum) {
return this;
}
@Override
public MenuItem setTitle(CharSequence title) {
this.title = title;
return this;
}
@Override
public MenuItem setTitle(int title) {
setTitle(context.getString(title));
return this;
}
@Override
public MenuItem setTitleCondensed(CharSequence title) {
return this;
}
@Override
public MenuItem setVisible(boolean visible) {
this.visible = visible;
return this;
}
}
private static class DummySubMenu extends DummyMenu implements SubMenu {
CharSequence title;
MenuItem parent;
public DummySubMenu(Context context, CharSequence title) {
super(context);
this.title = title;
}
@Override
public void clearHeader() {
}
public void setItem(MenuItem item) {
this.parent = item;
}
@Override
public MenuItem getItem() {
return parent;
}
@Override
public SubMenu setHeaderIcon(int iconRes) {
return this;
}
@Override
public SubMenu setHeaderIcon(Drawable icon) {
return this;
}
@Override
public SubMenu setHeaderTitle(int titleRes) {
return this;
}
@Override
public SubMenu setHeaderTitle(CharSequence title) {
return this;
}
@Override
public SubMenu setHeaderView(View view) {
return this;
}
@Override
public SubMenu setIcon(int iconRes) {
return this;
}
@Override
public SubMenu setIcon(Drawable icon) {
return this;
}
}
}

View File

@@ -1,74 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import java.util.ArrayList;
import java.util.Arrays;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnUse;
public final class ItemEffectsView_OnDeath extends LinearLayout {
private final LinearLayout itemeffect_ondeath_ontarget_list;
private final ActorConditionEffectList itemeffect_ondeath_conditions_source;
private final TextView itemeffect_ondeath_target_title;
public ItemEffectsView_OnDeath(Context context, AttributeSet attr) {
super(context, attr);
setFocusable(false);
setOrientation(LinearLayout.VERTICAL);
inflate(context, R.layout.itemeffectview_ondeath, this);
itemeffect_ondeath_ontarget_list = (LinearLayout) findViewById(R.id.itemeffect_ondeath_ontarget_list);
itemeffect_ondeath_target_title = (TextView) findViewById(R.id.itemeffect_ondeath_target_title);
itemeffect_ondeath_conditions_source = (ActorConditionEffectList) findViewById(R.id.itemeffect_ondeath_conditions_source);
}
public void update(ItemTraits_OnUse effects) {
ArrayList<ActorConditionEffect> sourceEffects = new ArrayList<ActorConditionEffect>();
itemeffect_ondeath_ontarget_list.removeAllViews();
boolean sourceHasStatsModifiers = false;
if (effects != null) {
final Context context = getContext();
final Resources res = getResources();
if (effects.addedConditions_source != null) sourceEffects.addAll(Arrays.asList(effects.addedConditions_source));
if (effects.changedStats != null) {
describeStatsModifierTraits(effects.changedStats, context, res, itemeffect_ondeath_ontarget_list);
if (effects.changedStats.currentAPBoost != null || effects.changedStats.currentHPBoost != null) sourceHasStatsModifiers = true;
}
}
itemeffect_ondeath_conditions_source.update(sourceEffects);
if (sourceEffects.isEmpty() && !sourceHasStatsModifiers) {
itemeffect_ondeath_target_title.setVisibility(View.GONE);
} else {
itemeffect_ondeath_target_title.setVisibility(View.VISIBLE);
}
}
public static void describeStatsModifierTraits(StatsModifierTraits traits, Context context, Resources res, LinearLayout listView) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
if (traits.currentAPBoost != null) {
final int label = traits.currentAPBoost.max > 0 ? R.string.iteminfo_effect_increase_current_ap : R.string.iteminfo_effect_decrease_current_ap;
final TextView tv = new TextView(context);
tv.setText(res.getString(label, traits.currentAPBoost.toMinMaxAbsString()));
listView.addView(tv, layoutParams);
}
if (traits.currentHPBoost != null) {
final int label = traits.currentHPBoost.max > 0 ? R.string.iteminfo_effect_increase_current_hp : R.string.iteminfo_effect_decrease_current_hp;
final TextView tv = new TextView(context);
tv.setText(res.getString(label, traits.currentHPBoost.toMinMaxAbsString()));
listView.addView(tv, layoutParams);
}
}
}

View File

@@ -1,97 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect;
import com.gpl.rpg.AndorsTrail.model.ability.traits.StatsModifierTraits;
import com.gpl.rpg.AndorsTrail.model.item.ItemTraits_OnHitReceived;
public final class ItemEffectsView_OnHitReceived extends LinearLayout {
private final LinearLayout itemeffect_onhitreceived_onsource_list;
private final LinearLayout itemeffect_onhitreceived_ontarget_list;
private final ActorConditionEffectList itemeffect_onhitreceived_conditions_source;
private final ActorConditionEffectList itemeffect_onhitreceived_conditions_target;
private final TextView itemeffect_onhitreceived_source_title;
private final TextView itemeffect_onhitreceived_target_title;
public ItemEffectsView_OnHitReceived(Context context, AttributeSet attr) {
super(context, attr);
setFocusable(false);
setOrientation(LinearLayout.VERTICAL);
inflate(context, R.layout.itemeffectview_onhitreceived, this);
itemeffect_onhitreceived_onsource_list = (LinearLayout) findViewById(R.id.itemeffect_onhitreceived_onsource_list);
itemeffect_onhitreceived_ontarget_list = (LinearLayout) findViewById(R.id.itemeffect_onhitreceived_ontarget_list);
itemeffect_onhitreceived_source_title = (TextView) findViewById(R.id.itemeffect_onhitreceived_source_title);
itemeffect_onhitreceived_target_title = (TextView) findViewById(R.id.itemeffect_onhitreceived_target_title);
itemeffect_onhitreceived_conditions_source = (ActorConditionEffectList) findViewById(R.id.itemeffect_onhitreceived_conditions_source);
itemeffect_onhitreceived_conditions_target = (ActorConditionEffectList) findViewById(R.id.itemeffect_onhitreceived_conditions_target);
}
public void update(Collection<ItemTraits_OnHitReceived> effects) {
ArrayList<ActorConditionEffect> sourceEffects = new ArrayList<ActorConditionEffect>();
ArrayList<ActorConditionEffect> targetEffects = new ArrayList<ActorConditionEffect>();
itemeffect_onhitreceived_onsource_list.removeAllViews();
itemeffect_onhitreceived_ontarget_list.removeAllViews();
boolean sourceHasStatsModifiers = false;
boolean targetHasStatsModifiers = false;
if (effects != null) {
final Context context = getContext();
final Resources res = getResources();
for (ItemTraits_OnHitReceived t : effects) {
if (t.addedConditions_source != null) sourceEffects.addAll(Arrays.asList(t.addedConditions_source));
if (t.addedConditions_target != null) targetEffects.addAll(Arrays.asList(t.addedConditions_target));
if (t.changedStats != null) {
describeStatsModifierTraits(t.changedStats, context, res, itemeffect_onhitreceived_onsource_list);
if (t.changedStats.currentAPBoost != null || t.changedStats.currentHPBoost != null) sourceHasStatsModifiers = true;
}
if (t.changedStats_target != null) {
describeStatsModifierTraits(t.changedStats_target, context, res, itemeffect_onhitreceived_ontarget_list);
if (t.changedStats_target.currentAPBoost != null || t.changedStats_target.currentHPBoost != null) targetHasStatsModifiers = true;
}
}
}
itemeffect_onhitreceived_conditions_source.update(sourceEffects);
itemeffect_onhitreceived_conditions_target.update(targetEffects);
if (sourceEffects.isEmpty() && !sourceHasStatsModifiers) {
itemeffect_onhitreceived_source_title.setVisibility(View.GONE);
} else {
itemeffect_onhitreceived_source_title.setVisibility(View.VISIBLE);
}
if (targetEffects.isEmpty() && !targetHasStatsModifiers) {
itemeffect_onhitreceived_target_title.setVisibility(View.GONE);
} else {
itemeffect_onhitreceived_target_title.setVisibility(View.VISIBLE);
}
}
public static void describeStatsModifierTraits(StatsModifierTraits traits, Context context, Resources res, LinearLayout listView) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
if (traits.currentAPBoost != null) {
final int label = traits.currentAPBoost.max > 0 ? R.string.iteminfo_effect_increase_current_ap : R.string.iteminfo_effect_decrease_current_ap;
final TextView tv = new TextView(context);
tv.setText(res.getString(label, traits.currentAPBoost.toMinMaxAbsString()));
listView.addView(tv, layoutParams);
}
if (traits.currentHPBoost != null) {
final int label = traits.currentHPBoost.max > 0 ? R.string.iteminfo_effect_increase_current_hp : R.string.iteminfo_effect_decrease_current_hp;
final TextView tv = new TextView(context);
tv.setText(res.getString(label, traits.currentHPBoost.toMinMaxAbsString()));
listView.addView(tv, layoutParams);
}
}
}

View File

@@ -1,846 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import java.lang.ref.WeakReference;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.Constants;
import com.gpl.rpg.AndorsTrail.controller.InputController;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation;
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation;
import com.gpl.rpg.AndorsTrail.controller.listeners.CombatSelectionListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.GameRoundListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.MapLayoutListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterMovementListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterSpawnListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.PlayerMovementListener;
import com.gpl.rpg.AndorsTrail.controller.listeners.VisualEffectFrameListener;
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
import com.gpl.rpg.AndorsTrail.model.item.Loot;
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Size;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public final class MainView extends SurfaceView
implements SurfaceHolder.Callback,
PlayerMovementListener,
CombatSelectionListener,
MonsterSpawnListener,
MonsterMovementListener,
MapLayoutListener,
VisualEffectFrameListener,
GameRoundListener {
private final int tileSize;
private float scale;
private int scaledTileSize;
private Size screenSizeTileCount = null;
private final Coord screenOffset = new Coord(); // pixel offset where the image begins
private final Coord mapTopLeft = new Coord(); // Map coords of visible map
private CoordRect mapViewArea; // Area in mapcoordinates containing the visible map. topleft == this.topleft
private Rect redrawClip = new Rect(); //Area in screen coordinates containing the visible map.
private final ModelContainer model;
private final WorldContext world;
private final ControllerContext controllers;
private final InputController inputController;
private final AndorsTrailPreferences preferences;
private final SurfaceHolder holder;
private final Paint mPaint = new Paint();
private final Paint debugPaint = new Paint();
private final int[] debugColors = {Color.MAGENTA, Color.BLUE, Color.CYAN, Color.GREEN, Color.YELLOW, Color.RED, Color.WHITE};
private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1));
private boolean hasSurface = false;
//DEBUG
// private Coord touchedTile = null;
// private static Paint touchHighlight = new Paint();
// private static Paint redrawHighlight = new Paint();
//
// static {
// touchHighlight.setColor(Color.RED);
// touchHighlight.setStrokeWidth(0f);
// touchHighlight.setStyle(Style.STROKE);
// redrawHighlight.setColor(Color.CYAN);
// redrawHighlight.setStrokeWidth(0f);
// redrawHighlight.setStyle(Style.STROKE);
// }
private PredefinedMap currentMap;
private LayeredTileMap currentTileMap;
private TileCollection tiles;
private final Coord playerPosition = new Coord();
private Size surfaceSize;
private boolean redrawNextTick = false;
private boolean scrolling = false;
private Coord scrollVector;
private long scrollStartTime;
//TODO restore private final modifiers before release
public static long SCROLL_DURATION = Constants.MINIMUM_INPUT_INTERVAL;
private int movingSprites = 0;
private SpriteMoveAnimationHandler movingSpritesRedrawTick = new SpriteMoveAnimationHandler(this);
private Paint alternateColorFilterPaint = new Paint();
private boolean useAlternateColorFilterPaint = false;
public MainView(Context context, AttributeSet attr) {
super(context, attr);
this.holder = getHolder();
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
this.controllers = app.getControllerContext();
this.world = app.getWorld();
this.model = world.model;
this.tileSize = world.tileManager.tileSize;
this.inputController = controllers.inputController;
this.preferences = app.getPreferences();
alternateColorFilterPaint.setStyle(Style.FILL);
holder.addCallback(this);
setFocusable(true);
requestFocus();
setOnClickListener(this.inputController);
setOnLongClickListener(this.inputController);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
// onKeyboardAction needs context to start new activities.
// canAcceptInput() checks done in handler so it can preserve keystate even if it does not have focus.
return inputController.onKeyboardAction(getContext(), keyEvent, canAcceptInput()) || super.onKeyDown(keyCode, keyEvent);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
// Android provides artificial ACTION_UP events when focus changes; we process them to prevent "stuck key" effect after dialogs close
return inputController.onKeyboardAction(getContext(), keyEvent, canAcceptInput()) || super.onKeyUp(keyCode, keyEvent);
}
@Override
public void surfaceChanged(SurfaceHolder sh, int format, int w, int h) {
if (w <= 0 || h <= 0) return;
this.scale = world.tileManager.scale;
this.mPaint.setFilterBitmap(scale != 1);
this.scaledTileSize = world.tileManager.viewTileSize;
// this.surfaceSize = new Size(w, h);
this.surfaceSize = new Size((int) (getWidth() / scale), (int) (getHeight() / scale));
this.screenSizeTileCount = new Size(
(int) Math.floor(getWidth() / scaledTileSize)
,(int) Math.floor(getHeight() / scaledTileSize)
);
if (sh.getSurfaceFrame().right != surfaceSize.width || sh.getSurfaceFrame().bottom != surfaceSize.height) {
sh.setFixedSize(surfaceSize.width, surfaceSize.height);
}
if (model.currentMaps.map != null) {
onPlayerEnteredNewMap(model.currentMaps.map, model.player.position);
} else {
redrawAll(RedrawAllDebugReason.SurfaceChanged);
}
}
@Override
public void surfaceCreated(SurfaceHolder sh) {
hasSurface = true;
}
@Override
public void surfaceDestroyed(SurfaceHolder sh) {
hasSurface = false;
movingSpritesRedrawTick.stop();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!canAcceptInput()) return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
final int tile_x = (int) Math.floor(((int)event.getX() - screenOffset.x * scale) / scaledTileSize) + mapTopLeft.x;
final int tile_y = (int) Math.floor(((int)event.getY() - screenOffset.y * scale) / scaledTileSize) + mapTopLeft.y;
// touchedTile = new Coord(tile_x, tile_y);
if (inputController.onTouchedTile(tile_x, tile_y)) return true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE:
inputController.onTouchCancel();
break;
}
return super.onTouchEvent(event);
}
private boolean canAcceptInput() {
if (!model.uiSelections.isMainActivityVisible) return false;
if (!hasSurface) return false;
return true;
}
private static enum RedrawAllDebugReason {
SurfaceChanged, MapChanged, PlayerMoved, SpriteMoved, MapScrolling, FilterAnimation
}
private static enum RedrawAreaDebugReason {
MonsterMoved, MonsterKilled, EffectCompleted, AsyncRequest
}
private static enum RedrawTileDebugReason {
SelectionRemoved, SelectionAdded, Bag
}
private void redrawAll(RedrawAllDebugReason why) {
if (preferences.enableUiAnimations) {
if (scrolling && why != RedrawAllDebugReason.MapScrolling) return;
if (!scrolling && movingSprites > 0 && why != RedrawAllDebugReason.SpriteMoved) return;
}
redrawArea_(mapViewArea, null, 0, 0);
}
private void redrawTile(final Coord p, RedrawTileDebugReason why) {
if (scrolling) return;
p1x1.topLeft.set(p);
redrawArea_(p1x1, null, 0, 0);
}
private void redrawArea(final CoordRect area, RedrawAreaDebugReason why) {
if (scrolling) return;
redrawArea_(area, null, 0, 0);
}
private void redrawArea_(CoordRect area, final VisualEffectAnimation effect, int tileID, int textYOffset) {
if (!hasSurface) return;
if (!currentMap.intersects(area)) return;
if (!mapViewArea.intersects(area)) return;
if (shouldRedrawEverything()) {
area = mapViewArea;
}
calculateRedrawRect(area);
redrawRect.intersect(redrawClip);
Canvas c = null;
try {
c = holder.lockCanvas(redrawRect);
// lockCanvas sometimes changes redrawRect, when the double-buffer has not been
// sufficiently filled beforehand. In those cases, we need to redraw the whole scene.
if (area != mapViewArea) {
if (isRedrawRectWholeScreen(redrawRect)) {
area = mapViewArea;
}
}
if (area == mapViewArea) {
area = adaptAreaToScrolling(area);
}
synchronized (holder) { synchronized (tiles) {
int xScroll = 0;
int yScroll = 0;
if (scrolling && scrollVector != null) {
xScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
xScroll = Math.max(0, Math.min(tileSize, xScroll)) * scrollVector.x;
yScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
yScroll = Math.max(0, Math.min(tileSize, yScroll)) * scrollVector.y;
}
c.clipRect(redrawClip);
c.translate(screenOffset.x + xScroll, screenOffset.y + yScroll);
// c.scale(scale, scale);
doDrawRect(c, area);
if (effect != null) {
drawFromMapPosition(c, area, effect.position, tileID);
if (effect.displayText != null) {
drawEffectText(c, area, effect, textYOffset, effect.getTextPaint());
}
}
// c.drawRect(new Rect(
// (area.topLeft.x - mapViewArea.topLeft.x) * tileSize,
// (area.topLeft.y - mapViewArea.topLeft.y) * tileSize,
// (area.topLeft.x - mapViewArea.topLeft.x + area.size.width) * tileSize - 1,
// (area.topLeft.y - mapViewArea.topLeft.y + area.size.height) * tileSize - 1),
// redrawHighlight);
// if (touchedTile != null) c.drawRect(new Rect(
// (touchedTile.x - mapViewArea.topLeft.x) * tileSize,
// (touchedTile.y - mapViewArea.topLeft.y) * tileSize,
// (touchedTile.x - mapViewArea.topLeft.x + 1) * tileSize - 1,
// (touchedTile.y - mapViewArea.topLeft.y + 1) * tileSize - 1),
// touchHighlight);
} }
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
}
private boolean isRedrawRectWholeScreen(Rect redrawRect) {
// if (redrawRect.width() < mapViewArea.size.width * scaledTileSize) return false;
// if (redrawRect.height() < mapViewArea.size.height * scaledTileSize) return false;
if (redrawRect.width() < mapViewArea.size.width * tileSize) return false;
if (redrawRect.height() < mapViewArea.size.height * tileSize) return false;
return true;
}
private boolean shouldRedrawEverything() {
if (scrolling) return true;
if (model.uiSelections.isInCombat) return true; // Discard the "optimized drawing" setting while in combat.
if (preferences.optimizedDrawing) return false;
return true;
}
private final Rect redrawRect = new Rect();
private void redrawAreaWithEffect(final VisualEffectAnimation effect, int tileID, int textYOffset) {
CoordRect area = effect.area;
// if (shouldRedrawEverythingForVisualEffect()) area = mapViewArea;
redrawArea_(area, effect, tileID, textYOffset);
}
private void clearCanvas() {
if (!hasSurface) return;
Canvas c = null;
try {
c = holder.lockCanvas();
synchronized (holder) {
c.drawColor(Color.BLACK);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
}
private CoordRect adaptAreaToScrolling(final CoordRect area) {
if (!scrolling || scrollVector == null) return area;
int x, y, w, h;
if (scrollVector.x > 0) {
x = area.topLeft.x - scrollVector.x;
w = area.size.width + scrollVector.x;
} else {
x = area.topLeft.x;
w = area.size.width - scrollVector.x;
}
if (scrollVector.y > 0) {
y = area.topLeft.y - scrollVector.y;
h = area.size.height + scrollVector.y;
} else {
y = area.topLeft.y;
h = area.size.height - scrollVector.y;
}
CoordRect result = new CoordRect(new Coord(x, y), new Size(w, h));
return result;
}
private void calculateRedrawRect(final CoordRect area) {
worldCoordsToScreenCords(area, redrawRect);
}
private void worldCoordsToScreenCords(final CoordRect worldArea, Rect destScreenRect) {
// destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * scaledTileSize;
// destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * scaledTileSize;
// destScreenRect.right = destScreenRect.left + worldArea.size.width * scaledTileSize;
// destScreenRect.bottom = destScreenRect.top + worldArea.size.height * scaledTileSize;
destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * tileSize;
destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * tileSize;
destScreenRect.right = destScreenRect.left + worldArea.size.width * tileSize;
destScreenRect.bottom = destScreenRect.top + worldArea.size.height * tileSize;
}
// private void worldCoordsToBitmapCoords(final CoordRect worldArea, Rect dstBitmapArea) {
// dstBitmapArea.left = worldArea.topLeft.x * tileSize;
// dstBitmapArea.top = worldArea.topLeft.y * tileSize;
// dstBitmapArea.right = dstBitmapArea.left + worldArea.size.width * tileSize;
// dstBitmapArea.bottom = dstBitmapArea.top + worldArea.size.height * tileSize;
//
// }
private void doDrawRect(Canvas canvas, CoordRect area) {
doDrawRect_Ground(canvas, area);
doDrawRect_Objects(canvas, area);
doDrawRect_Above(canvas, area);
if (useAlternateColorFilterPaint) {
applyAlternateFilter(canvas, area);
}
}
private void doDrawRect_Ground(Canvas canvas, CoordRect area) {
if (AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAMES) {
drawUnderLayer(canvas, area);
}
tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerBase);
drawMapLayer(canvas, area, currentTileMap.currentLayout.layerGround);
tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
}
private void doDrawRect_Objects(Canvas canvas, CoordRect area) {
// if (!tryDrawMapBitmap(canvas, area, objectsBitmap)) {
// tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
// }
for (BloodSplatter splatter : currentMap.splatters) {
drawFromMapPosition(canvas, area, splatter.position, splatter.iconID);
}
for (Loot l : currentMap.groundBags) {
if (l.isVisible) {
drawFromMapPosition(canvas, area, l.position, TileManager.iconID_groundbag);
}
}
if (!model.player.hasVFXRunning) {
drawFromMapPosition(canvas, area, playerPosition, model.player.iconID);
} else if (area.contains(playerPosition)) {
int vfxElapsedTime = (int) (System.currentTimeMillis() - model.player.vfxStartTime);
if (vfxElapsedTime > model.player.vfxDuration) vfxElapsedTime = model.player.vfxDuration;
int x = ((model.player.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((model.player.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
int y = ((model.player.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((model.player.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
tiles.drawTile(canvas, model.player.iconID, x, y, mPaint);
}
for (MonsterSpawnArea a : currentMap.spawnAreas) {
for (Monster m : a.monsters) {
if (!m.hasVFXRunning) {
drawFromMapPosition(canvas, area, m.rectPosition, m.iconID);
} else if (area.intersects(m.rectPosition) || area.intersects(new CoordRect(m.lastPosition,m.rectPosition.size))) {
int vfxElapsedTime = (int) (System.currentTimeMillis() - m.vfxStartTime);
if (vfxElapsedTime > m.vfxDuration) vfxElapsedTime = m.vfxDuration;
int x = ((m.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((m.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
int y = ((m.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((m.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
tiles.drawTile(canvas, m.iconID, x, y, mPaint);
}
}
}
}
private void doDrawRect_Above(Canvas canvas, CoordRect area) {
tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerAbove);
tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerTop);
if (model.uiSelections.selectedPosition != null) {
if (model.uiSelections.selectedMonster != null) {
drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_attackselect);
} else {
drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_moveselect);
}
}
}
private void tryDrawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
if (layer != null) drawMapLayer(canvas, area, layer);
}
// In debug builds, draw a fake layer under the Ground to make incorrect transparency more obvious when testing
private void drawUnderLayer(Canvas canvas, final CoordRect area) {
float left = (area.topLeft.x - mapViewArea.topLeft.x) * tileSize;
float top = (area.topLeft.y - mapViewArea.topLeft.y) * tileSize;
float right = left + area.size.width * tileSize;
float bottom = top + area.size.height * tileSize;
int selectedColor = (int)(System.currentTimeMillis() / 500 % debugColors.length);
// int selectedColor = (int)(Math.random() * debugColors.length);
debugPaint.setColor(debugColors[selectedColor]);
canvas.drawRect(left, top, right, bottom, debugPaint);
}
private void drawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
int my = area.topLeft.y;
int py = (area.topLeft.y - mapViewArea.topLeft.y) * tileSize;
int px0 = (area.topLeft.x - mapViewArea.topLeft.x) * tileSize;
for (int y = 0; y < area.size.height; ++y, ++my, py += tileSize) {
int mx = area.topLeft.x;
if (my < 0) continue;
if (my >= currentMap.size.height) break;
int px = px0;
for (int x = 0; x < area.size.width; ++x, ++mx, px += tileSize) {
if (mx < 0) continue;
if (mx >= currentMap.size.width) break;
final int tile = layer.tiles[mx][my];
if (tile == 0) continue;
tiles.drawTile(canvas, tile, px, py, mPaint);
}
}
}
private void applyAlternateFilter(Canvas canvas, CoordRect area) {
canvas.drawRect(canvas.getClipBounds(), alternateColorFilterPaint);
}
private void drawFromMapPosition(Canvas canvas, final CoordRect area, final Coord p, final int tile) {
if (!area.contains(p)) return;
_drawFromMapPosition(canvas, area, p.x, p.y, tile);
}
private void drawFromMapPosition(Canvas canvas, final CoordRect area, final CoordRect p, final int tile) {
if (!area.intersects(p)) return;
_drawFromMapPosition(canvas, area, p.topLeft.x, p.topLeft.y, tile);
}
private void _drawFromMapPosition(Canvas canvas, final CoordRect area, int x, int y, final int tile) {
x -= mapViewArea.topLeft.x;
y -= mapViewArea.topLeft.y;
// if ( (x >= 0 && x < mapViewArea.size.width)
// && (y >= 0 && y < mapViewArea.size.height)) {
tiles.drawTile(canvas, tile, x * tileSize, y * tileSize, mPaint);
// }
}
private void drawEffectText(Canvas canvas, final CoordRect area, final VisualEffectAnimation e, int textYOffset, Paint textPaint) {
int x = (e.position.x - mapViewArea.topLeft.x) * tileSize + tileSize/2;
int y = (e.position.y - mapViewArea.topLeft.y) * tileSize + tileSize/2 + textYOffset;
canvas.drawText(e.displayText, x, y, textPaint);
}
@Override
public void onPlayerEnteredNewMap(PredefinedMap map, Coord p) {
movingSpritesRedrawTick.start();
synchronized (holder) {
currentMap = map;
currentTileMap = model.currentMaps.tileMap;
tiles = world.model.currentMaps.tiles;
movingSprites = 0;
Size visibleNumberOfTiles = new Size(
Math.min(screenSizeTileCount.width, currentMap.size.width)
,Math.min(screenSizeTileCount.height, currentMap.size.height)
);
mapViewArea = new CoordRect(mapTopLeft, visibleNumberOfTiles);
updateClip();
// screenOffset.set(
// (surfaceSize.width - scaledTileSize * visibleNumberOfTiles.width) / 2
// ,(surfaceSize.height - scaledTileSize * visibleNumberOfTiles.height) / 2
// );
screenOffset.set(
(surfaceSize.width - tileSize * visibleNumberOfTiles.width) / 2
,(surfaceSize.height - tileSize * visibleNumberOfTiles.height) / 2
);
useAlternateColorFilterPaint = currentTileMap.setColorFilter(this.mPaint, this.alternateColorFilterPaint, preferences.highQualityFilters);
}
// touchedTile = null;
clearCanvas();
recalculateMapTopLeft(model.player.position, false);
redrawAll(RedrawAllDebugReason.MapChanged);
}
private void recalculateMapTopLeft(Coord playerPosition, boolean allowScrolling) {
synchronized (holder) {
int oldX = mapTopLeft.x;
int oldY = mapTopLeft.y;
this.playerPosition.set(playerPosition);
mapTopLeft.set(0, 0);
if (currentMap.size.width > screenSizeTileCount.width) {
mapTopLeft.x = Math.max(0, playerPosition.x - mapViewArea.size.width/2);
mapTopLeft.x = Math.min(mapTopLeft.x, currentMap.size.width - mapViewArea.size.width);
}
if (currentMap.size.height > screenSizeTileCount.height) {
mapTopLeft.y = Math.max(0, playerPosition.y - mapViewArea.size.height/2);
mapTopLeft.y = Math.min(mapTopLeft.y, currentMap.size.height - mapViewArea.size.height);
}
updateClip();
if (allowScrolling) {
if (mapTopLeft.x != oldX || mapTopLeft.y != oldY) {
scrollVector = new Coord(mapTopLeft.x - oldX, mapTopLeft.y - oldY);
new ScrollAnimationHandler(this).start();
}
} else {
scrolling = false;
}
}
}
private void updateClip() {
worldCoordsToScreenCords(mapViewArea, redrawClip);
}
public static final class ScrollAnimationHandler extends Handler implements Runnable {
private static final int FRAME_DURATION = 40;
private final WeakReference<MainView> view;
public ScrollAnimationHandler(MainView view) {
this.view = new WeakReference<MainView>(view);
}
@Override
public void run() {
MainView v = view.get();
if (v == null) return;
if (System.currentTimeMillis() - v.scrollStartTime >= SCROLL_DURATION) {
onCompleted();
} else {
postDelayed(this, FRAME_DURATION);
}
update();
}
private void update() {
MainView v = view.get();
if (v == null) return;
v.redrawAll(RedrawAllDebugReason.MapScrolling);
}
private void onCompleted() {
MainView v = view.get();
if (v == null) return;
v.scrolling = false;
v.scrollVector = null;
}
public void start() {
MainView v = view.get();
if (v == null) return;
v.scrolling = true;
v.scrollStartTime = System.currentTimeMillis();
postDelayed(this, 0);
}
}
public static final class SpriteMoveAnimationHandler extends Handler implements Runnable {
private static final int FRAME_DURATION = 40;
private final WeakReference<MainView> view;
private boolean stop = true;
public SpriteMoveAnimationHandler(MainView view) {
this.view = new WeakReference<MainView>(view);
}
@Override
public void run() {
if (!stop) postDelayed(this, FRAME_DURATION);
update();
}
private void update() {
// L.log("stop="+stop+" - scroll="+scrolling+" - moving="+movingSprites);
if (stop) return;
MainView v = view.get();
if (v == null) return;
if (!v.scrolling) {
if (v.movingSprites > 0) {
//TODO : limit redraw area when shouldRedrawEverything() returns false.
//Implies keeping track of the animation bounding box in a thread-safe way... :'(
v.redrawAll(RedrawAllDebugReason.SpriteMoved);
}
}
synchronized (this) {
if (v.movingSprites <= 0) stop();
}
}
public void start() {
if (stop) {
stop = false;
MainView v = view.get();
if (v == null) return;
if (v.controllers.preferences.enableUiAnimations) postDelayed(this, 0);
}
}
public void stop() {
stop = true;
}
}
@Override
public void onPlayerMoved(PredefinedMap map, Coord newPosition, Coord previousPosition) {
if (map != currentMap) return;
recalculateMapTopLeft(newPosition, preferences.enableUiAnimations);
redrawAll(RedrawAllDebugReason.PlayerMoved);
}
public void subscribe() {
controllers.gameRoundController.gameRoundListeners.add(this);
controllers.effectController.visualEffectFrameListeners.add(this);
controllers.mapController.mapLayoutListeners.add(this);
controllers.movementController.playerMovementListeners.add(this);
controllers.combatController.combatSelectionListeners.add(this);
controllers.monsterSpawnController.monsterSpawnListeners.add(this);
controllers.monsterMovementController.monsterMovementListeners.add(this);
}
public void unsubscribe() {
controllers.monsterMovementController.monsterMovementListeners.remove(this);
controllers.monsterSpawnController.monsterSpawnListeners.remove(this);
controllers.combatController.combatSelectionListeners.remove(this);
controllers.movementController.playerMovementListeners.remove(this);
controllers.mapController.mapLayoutListeners.remove(this);
controllers.effectController.visualEffectFrameListeners.remove(this);
controllers.gameRoundController.gameRoundListeners.remove(this);
}
@Override
public void onMonsterSelected(Monster m, Coord selectedPosition, Coord previousSelection) {
if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
}
@Override
public void onMovementDestinationSelected(Coord selectedPosition, Coord previousSelection) {
if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
}
@Override
public void onCombatSelectionCleared(Coord previousSelection) {
redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
}
@Override
public void onMonsterSpawned(PredefinedMap map, Monster m) {
if (map != currentMap) return;
if (!mapViewArea.intersects(m.rectPosition)) return;
redrawNextTick = true;
}
@Override
public void onMonsterRemoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
if (map != currentMap) return;
redrawArea(previousPosition, RedrawAreaDebugReason.MonsterKilled);
}
@Override
public void onMonsterSteppedOnPlayer(Monster m) {
}
@Override
public void onMonsterMoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
if (map != currentMap) return;
if (!mapViewArea.intersects(m.rectPosition) && !mapViewArea.intersects(previousPosition)) return;
if (model.uiSelections.isInCombat) {
redrawArea(previousPosition, RedrawAreaDebugReason.MonsterMoved);
redrawArea(m.rectPosition, RedrawAreaDebugReason.MonsterMoved);
} else {
redrawNextTick = true;
}
}
@Override
public void onSplatterAdded(PredefinedMap map, Coord p) {
if (map != currentMap) return;
if (!mapViewArea.contains(p)) return;
redrawNextTick = true;
}
@Override
public void onSplatterChanged(PredefinedMap map, Coord p) {
if (map != currentMap) return;
if (!mapViewArea.contains(p)) return;
redrawNextTick = true;
}
@Override
public void onSplatterRemoved(PredefinedMap map, Coord p) {
if (map != currentMap) return;
if (!mapViewArea.contains(p)) return;
redrawNextTick = true;
}
@Override
public void onLootBagCreated(PredefinedMap map, Coord p) {
if (map != currentMap) return;
redrawTile(p, RedrawTileDebugReason.Bag);
}
@Override
public void onLootBagRemoved(PredefinedMap map, Coord p) {
if (map != currentMap) return;
redrawTile(p, RedrawTileDebugReason.Bag);
}
@Override
public void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap) {
if (map != currentMap) return;
useAlternateColorFilterPaint = currentTileMap.setColorFilter(this.mPaint, this.alternateColorFilterPaint, preferences.highQualityFilters);
redrawAll(RedrawAllDebugReason.MapChanged);
}
@Override
public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) {
redrawAreaWithEffect(animation, tileID, textYOffset);
}
@Override
public void onAnimationCompleted(VisualEffectAnimation animation) {
redrawArea(animation.area, RedrawAreaDebugReason.EffectCompleted);
}
@Override
public void onSpriteMoveStarted(SpriteMoveAnimation animation) {
if (animation.map != currentMap) return;
synchronized (movingSpritesRedrawTick) {
movingSprites++;
movingSpritesRedrawTick.start();
}
}
@Override
public void onNewSpriteMoveFrame(SpriteMoveAnimation animation) {
//redrawMoveArea_(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), animation);
}
@Override
public void onSpriteMoveCompleted(SpriteMoveAnimation animation) {
if (animation.map != currentMap) return;
movingSprites--;
redrawArea(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), RedrawAreaDebugReason.EffectCompleted);
}
@Override
public void onAsyncAreaUpdate(CoordRect area) {
redrawArea(area, RedrawAreaDebugReason.AsyncRequest);
}
@Override
public void onNewTick() {
if (!redrawNextTick) return;
redrawAll(RedrawAllDebugReason.PlayerMoved);
redrawNextTick = false;
}
@Override
public void onNewRound() { }
@Override
public void onNewFullRound() { }
}

View File

@@ -1,62 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import android.content.Context;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.model.actor.Player;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
public class QuickslotsItemContainerAdapter extends ItemContainerAdapter {
public static final ItemEntry EMPTY_ENTRY = new ItemEntry(null, 0);
public static Drawable EMPTY_DRAWABLE = null;
public QuickslotsItemContainerAdapter(Context context, TileManager tileManager, ItemContainer items, Player player, TileCollection tileCollection) {
super(context, tileManager, items, player, tileCollection);
insert(EMPTY_ENTRY, 0);
if (EMPTY_DRAWABLE == null) {
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
EMPTY_DRAWABLE = context.getResources().getDrawable(R.drawable.ui_icon_equipment).mutate();
EMPTY_DRAWABLE.setColorFilter(filter);
}
}
public QuickslotsItemContainerAdapter(Context context, TileManager tileManager, ItemContainer items, Player player) {
this(context, tileManager, items, player, tileManager.loadTilesFor(items, context.getResources()));
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (getItem(position) == EMPTY_ENTRY) {
View result = convertView;
if (result == null) {
result = View.inflate(getContext(), R.layout.inventoryitemview, null);
}
TextView tv = (TextView) result;
tv.setCompoundDrawablesWithIntrinsicBounds(EMPTY_DRAWABLE, null, null, null);
tv.setText(R.string.inventory_unassign);
return result;
}
return super.getView(position, convertView, parent);
}
@Override
public long getItemId(int position) {
if (getItem(position) == EMPTY_ENTRY) return EMPTY_ENTRY.hashCode();
return super.getItemId(position);
}
}

View File

@@ -1,60 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.TextView;
//Thanks to https://stackoverflow.com/questions/6205339/listview-item-selected-state-not-working
public class SelectableTextView extends TextView implements Checkable {
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
private boolean mChecked;
public SelectableTextView(Context context) {
super(context);
}
public SelectableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// @TargetApi(Build.VERSION_CODES.LOLLIPOP)
// public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
// super(context, attrs, defStyleAttr, defStyleRes);
// }
@Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
@Override
public boolean isChecked() {
return mChecked;
}
@Override
public void toggle() {
setSelected(!mChecked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}

View File

@@ -1,77 +0,0 @@
package com.gpl.rpg.AndorsTrail.view;
import android.app.Dialog;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
/**
* Simply instantiate this class, implement abstract methods in an anonymous type, and tada, your Button is a Spinner!
*/
public abstract class SpinnerEmulator {
private Button spinnerButton;
private CustomDialog spinnerDialog = null;
private ListView choicesList;
private Context context;
public SpinnerEmulator(Button b, int arrayResId, int promptResId) {
spinnerButton = b;
context=b.getContext();
initializeSpinnerEmulation(arrayResId, promptResId);
}
public SpinnerEmulator(View v, int buttonId, int arrayResId, int promptResId) {
spinnerButton = (Button) v.findViewById(buttonId);
context=v.getContext();
initializeSpinnerEmulation(arrayResId, promptResId);
}
public void initializeSpinnerEmulation(final int arrayResId, final int promptResId) {
choicesList = new ListView(context);//(Spinner) v.findViewById(R.id.inventorylist_category_filters);
choicesList.setBackgroundResource(android.R.color.transparent);
ArrayAdapter<CharSequence> skillCategoryFilterAdapter = ArrayAdapter.createFromResource(context, arrayResId, android.R.layout.simple_list_item_1);
choicesList.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, ListView.LayoutParams.WRAP_CONTENT));
choicesList.setAdapter(skillCategoryFilterAdapter);
choicesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (getValue() == position) {
spinnerDialog.dismiss();
return;
}
setValue(position);
spinnerButton.setText(context.getResources().getStringArray(arrayResId)[position]);
spinnerDialog.dismiss();
selectionChanged(position);
}
});
choicesList.setSelection(getValue());
spinnerButton.setText(context.getResources().getStringArray(arrayResId)[getValue()]);
spinnerButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (spinnerDialog == null) {
spinnerDialog = CustomDialogFactory.createDialog(context, context.getString(promptResId), null, null, choicesList, false);
}
CustomDialogFactory.show(spinnerDialog);
}
});
}
public abstract int getValue();
public abstract void setValue(int value);
public abstract void selectionChanged(int value);
}

View File

@@ -1,30 +0,0 @@
package com.gpl.rpg.AndorsTrail.controller;
import com.gpl.rpg.AndorsTrail.model.actor.Actor;
import org.junit.Test;
import static org.junit.Assert.*;
public class CombatControllerTest {
@Test
public void getAverageDamagePerHit() throws Exception {
Actor attacker = new Actor(null, false, false);
attacker.attackChance = 100;
attacker.damagePotential.set(5, 3);
Actor target = new Actor(null, false, false);
target.damageResistance = 3;
target.blockChance = 50;
float averageDamagePerHit = CombatController.getAverageDamagePerHit(attacker, target);
assertEquals(0.5, averageDamagePerHit, 0.01);
attacker.criticalSkill = 30;
attacker.criticalMultiplier = 2.5f;
averageDamagePerHit = CombatController.getAverageDamagePerHit(attacker, target);
assertEquals(1.038, averageDamagePerHit, 0.01);
}
}

View File

@@ -0,0 +1 @@
*.mo

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

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

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

0
AndorsTrail/assets/translation/createMo.sh Normal file → Executable file
View File

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

Binary file not shown.

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

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

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

Binary file not shown.

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

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

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