mirror of
https://github.com/OMGeeky/andors-trail.git
synced 2026-01-03 18:25:02 +01:00
Merge branch 'permadeath' into nut_arulir_mountain
This commit is contained in:
@@ -80,6 +80,38 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPersonName" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginRight="2dp"
|
||||
android:background="?attr/ui_theme_stdframe_bitmap"
|
||||
android:clickable="true"
|
||||
android:gravity="bottom|start"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/startscreen_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:text="@string/startscreen_game_mode" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
style="@style/AndorsTrail_Style_StdFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:orientation="horizontal" >
|
||||
<Button
|
||||
android:id="@+id/startscreen_mode_selector_button"
|
||||
style="@style/AndorsTrail_Style_SpinnerEmulator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
<item>@string/questlog_includecompleted_onlycompleted</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Order is hardcoded within StartScreenActivity_NewGame-->
|
||||
<string-array name="startscreen_mode_selector">
|
||||
<item>Unlimited saves and lives</item>
|
||||
<item>Unlimited lives</item>
|
||||
<item>50 lives</item>
|
||||
<item>10 lives</item>
|
||||
<item>3 lives</item>
|
||||
<item>1 life (hardcore mode)</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Order is hardcoded within HeroInfoActivity_inventory-->
|
||||
<string-array name="inventorylist_category_filters">
|
||||
<item>@string/inventory_category_all</item>
|
||||
|
||||
@@ -19,11 +19,16 @@
|
||||
<string name="dialog_loading_failed_title">Load Failed</string>
|
||||
<string name="dialog_loading_failed_message">Andor\'s Trail was unable to load the savegame file.\n\n:(\n\nThe file may be damaged or incomplete.</string>
|
||||
<string name="dialog_loading_failed_incorrectversion">Andor\'s Trail was unable to load the savegame file. This savegame file is created with a newer version than what is currently running.</string>
|
||||
<string name="dialog_loading_failed_cheat">Andor\'s Trail was unable to load the savegame file. This savegame file has already been continued.</string>
|
||||
|
||||
<string name="dialog_recenter">Recenter</string>
|
||||
<string name="dialog_close">Close</string>
|
||||
<string name="dialog_more">More</string>
|
||||
|
||||
<string name="dialog_game_over_title">Game over</string>
|
||||
<string name="dialog_game_over_text">You take your last breath and die.</string>
|
||||
<string name="rip_startscreen">(RIP)</string>
|
||||
|
||||
<string name="dialog_monsterencounter_title">Encounter</string>
|
||||
<string name="dialog_monsterencounter_message">Do you want to attack?\nDifficulty: %1$s</string>
|
||||
<string name="dialog_monsterencounter_info">Info</string>
|
||||
@@ -50,6 +55,13 @@
|
||||
<string name="heroinfo_experiencepoints">Experience points (XP):</string>
|
||||
<string name="heroinfo_actionpoints">Action points (AP):</string>
|
||||
<string name="heroinfo_quests">Quests</string>
|
||||
<string name="heroinfo_unlimited_lives_and_saves">unlimited lives and saves</string>
|
||||
<string name="heroinfo_unlimited_lives">unlimited lives</string>
|
||||
<string name="heroinfo_hardcore_mode">1 life (hardcore mode)</string>
|
||||
<string name="heroinfo_lives_left">%1$d/%2$d lives left</string>
|
||||
<string name="heroinfo_unlimited_saves">, unlimited saves</string>
|
||||
|
||||
|
||||
|
||||
<string name="combat_attack">Attack (%1$d AP)</string>
|
||||
<string name="combat_move">Move (%1$d AP)</string>
|
||||
@@ -143,6 +155,13 @@
|
||||
<string name="startscreen_selectherosprite">Choose your hero</string>
|
||||
<string name="startscreen_enterheroname">Enter hero name</string>
|
||||
<string name="startscreen_load">Load</string>
|
||||
<string name="startscreen_game_mode">Mode</string>
|
||||
<string name="startscreen_load_game">Load game</string>
|
||||
<string name="startscreen_load_game_confirm">The current game is unsaved and you will loose your character.</string>
|
||||
<string name="startscreen_error_loading_game">Error loading game</string>
|
||||
<string name="startscreen_error_loading_empty_slot">Can\'t load from an empty slot.</string>
|
||||
<string name="startscreen_attention_slot_gets_delete_on_load">Attention</string>
|
||||
<string name="startscreen_attention_message_slot_gets_delete_on_load">Loading this game deletes its save slot. You will have to save again before switching to another game.</string>
|
||||
|
||||
<!-- <string name="conversation_title">%1$s says</string> -->
|
||||
<string name="conversation_rewardexp"> [You gained %1$d experience]</string>
|
||||
@@ -448,10 +467,10 @@
|
||||
<string name="skill_prerequisite_other_skill">To level up this skill, you need at least level %1$d of the %2$s skill.</string>
|
||||
<string name="skill_prerequisite_level">To level up this skill, you need at least experience level %1$d.</string>
|
||||
<string name="skill_prerequisite_stat">To level up this skill, you need at least %1$d %2$s (base stats).</string>
|
||||
<string name="skill_number_of_increases_one">You may select one skill to improve.</string>
|
||||
<string name="skill_number_of_increases_several">You may select %1$d skills to improve.</string>
|
||||
<string name="levelup_adds_new_skillpoint">This level also gives you a new skill point to spend!</string>
|
||||
|
||||
<string name="skill_number_of_increases_one">You may select one skill to improve.</string>
|
||||
<string name="skill_number_of_increases_several">You may select %1$d skills to improve.</string>
|
||||
<string name="levelup_adds_new_skillpoint">This level also gives you a new skill point to spend!</string>
|
||||
|
||||
<string name="loadsave_save_to_new_slot">Create new savegame slot</string>
|
||||
<string name="loadsave_save_overwrite_confirmation_title">Overwrite savegame?</string>
|
||||
<string name="loadsave_save_overwrite_confirmation">This savegame contains a different player name (%1$s) than your current player name (%2$s). Are you sure you want to overwrite this savegame?</string>
|
||||
@@ -470,7 +489,9 @@
|
||||
|
||||
<string name="traitsinfo_base_max_hp">Max HP:</string>
|
||||
<string name="traitsinfo_base_max_ap">Max AP:</string>
|
||||
<string name="menu_save_saving_not_allowed_in_combat">Cannot save the game while in combat.</string>
|
||||
<string name="menu_save_saving_not_allowed_in_combat">Cannot save the game while in combat.</string>
|
||||
<string name="menu_save_switch_character_title">Switch character</string>
|
||||
<string name="menu_save_switch_character">Saving allows you to switch to another character and later continue the current game. Do you want to save and exit the current game?</string>
|
||||
|
||||
<string name="preferences_optimized_drawing_title">Optimized drawing</string>
|
||||
<string name="preferences_optimized_drawing">Disable this if you see graphical artifacts. Enabling this option will make the game only redraw changed parts of the screen every frame.</string>
|
||||
@@ -548,6 +569,8 @@
|
||||
|
||||
<string name="loadsave_save_overwrite_confirmation_all">Are you sure you want to overwrite this savegame?</string>
|
||||
<string name="loadsave_save_overwrite_confirmation_slot">(slot %1$d)</string>
|
||||
<string name="loadsave_empty_slot">%1$d.<empty></string>
|
||||
|
||||
<string name="preferences_display_overwrite_savegame_entries_always_confirm">Always show confirmation dialog box</string>
|
||||
<string name="preferences_display_overwrite_savegame_entries_confirm_overwrite">Only show when overwriting a different playername</string>
|
||||
<string name="preferences_display_overwrite_savegame_entries_never_confirm">Never display confirmation dialog box</string>
|
||||
@@ -604,7 +627,7 @@
|
||||
<string name="skill_longdescription_weapon_prof_1hsword">For each skill level, increases attack chance of rapiers, longswords and broadswords by %1$d %% of the item\'s base attack chance, increases block chance by %2$d %% of the item\'s base block chance, and increases critical skill by %3$d %% of the item\'s base critical skill.</string>
|
||||
<string name="skill_longdescription_weapon_prof_2hsword">For each skill level, increases attack chance of two-handed swords by %1$d %% of the item\'s base attack chance, increases block chance by %2$d %% of the item\'s base block chance, and increases critical skill by %3$d %% of the item\'s base critical skill.</string>
|
||||
<string name="skill_longdescription_weapon_prof_axe">For each skill level, increases attack chance of axes and greataxes by %1$d %% of the item\'s base attack chance, increases block chance by %2$d %% of the item\'s base block chance, and increases critical skill by %3$d %% of the item\'s base critical skill.</string>
|
||||
<string name="skill_longdescription_weapon_prof_blunt">For each skill level, increases attack chance of bludgeoning weapons by %1$d %% of the item\'s base attack chance, increases block chance by %2$d %% of the item\'s base block chance, and increases critical skill by %3$d %% of the item\'s base critical skill. This includes clubs, quarterstaves, maces, scepters, war hammers and giant hammers.</string>
|
||||
<string name="skill_longdescription_weapon_prof_blunt">For each skill level, increases attack chance of bludgeoning weapons by %1$d %% of the item\'s base attack chance, increases block chance by %2$d %% of the item\'s base block chance, and increases critical skill by %3$d %% of the item\'s base critical skill. This includes clubs, quarterstaves, maces, scepters, war hammers and giant hammers.</string>
|
||||
<string name="skill_longdescription_weapon_prof_unarmed">When fighting without a weapon and shield, gain %1$d attack chance, %2$d damage potential and %3$d block chance per skill level.</string>
|
||||
<string name="skill_longdescription_armor_prof_shield">Increase damage resistance by %1$d per skill level while having a shield equipped.</string>
|
||||
<string name="skill_longdescription_armor_prof_unarmored">While fighting without having any piece of armor equipped, gain %1$d block chance per skill level. Items made of cloth are not considered as being armor.</string>
|
||||
|
||||
@@ -25,10 +25,10 @@ public final class AndorsTrailApplication extends Application {
|
||||
public static final boolean DEVELOPMENT_FORCE_CONTINUEGAME = false;
|
||||
public static final boolean DEVELOPMENT_DEBUGBUTTONS = true;
|
||||
public static final boolean DEVELOPMENT_FASTSPEED = false;
|
||||
public static final boolean DEVELOPMENT_VALIDATEDATA = false;
|
||||
public static final boolean DEVELOPMENT_DEBUGMESSAGES = false;
|
||||
public static final boolean DEVELOPMENT_VALIDATEDATA = true;
|
||||
public static final boolean DEVELOPMENT_DEBUGMESSAGES = true;
|
||||
public static final boolean DEVELOPMENT_INCOMPATIBLE_SAVEGAMES = DEVELOPMENT_DEBUGRESOURCES || DEVELOPMENT_DEBUGBUTTONS || DEVELOPMENT_FASTSPEED;
|
||||
public static final int CURRENT_VERSION = DEVELOPMENT_INCOMPATIBLE_SAVEGAMES ? 999 : 47;
|
||||
public static final int CURRENT_VERSION = DEVELOPMENT_INCOMPATIBLE_SAVEGAMES ? 999 : 48;
|
||||
public static final String CURRENT_VERSION_DISPLAY = "0.7.7";
|
||||
public static final boolean IS_RELEASE_VERSION = !CURRENT_VERSION_DISPLAY.matches(".*[a-d].*");
|
||||
|
||||
|
||||
@@ -244,6 +244,25 @@ public final class Dialogs {
|
||||
});
|
||||
}
|
||||
|
||||
public static void showHeroDied(final MainActivity mainActivity, final ControllerContext controllers) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
mainActivity.getResources().getString(R.string.dialog_game_over_title),
|
||||
mainActivity.getResources().getDrawable(R.drawable.ui_icon_combat),
|
||||
mainActivity.getResources().getString(R.string.dialog_game_over_text),
|
||||
null,
|
||||
true);
|
||||
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
|
||||
showDialogAndPause(d, controllers, new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface arg0) {
|
||||
mainActivity.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static Intent getIntentForItemInfo(final Context ctx, String itemTypeID, ItemInfoActivity.ItemInfoAction actionType, String buttonText, boolean buttonEnabled, Inventory.WearSlot inventorySlot) {
|
||||
Intent intent = new Intent(ctx, ItemInfoActivity.class);
|
||||
intent.putExtra("buttonText", buttonText);
|
||||
@@ -324,11 +343,33 @@ public final class Dialogs {
|
||||
Toast.makeText(mainActivity, R.string.menu_save_saving_not_allowed_in_combat, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
controllerContext.gameRoundController.pause();
|
||||
Intent intent = new Intent(mainActivity, LoadSaveActivity.class);
|
||||
intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/save"));
|
||||
mainActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_SAVEGAME);
|
||||
return true;
|
||||
|
||||
if (!world.model.statistics.hasUnlimitedSaves()) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
mainActivity.getResources().getString(R.string.menu_save_switch_character_title),
|
||||
null,
|
||||
mainActivity.getResources().getString(R.string.menu_save_switch_character),
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
controllerContext.gameRoundController.pause();
|
||||
Intent intent = new Intent(mainActivity, LoadSaveActivity.class);
|
||||
intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/save"));
|
||||
mainActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_SAVEGAME);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
|
||||
CustomDialogFactory.show(d);
|
||||
return false;
|
||||
} else {
|
||||
controllerContext.gameRoundController.pause();
|
||||
Intent intent = new Intent(mainActivity, LoadSaveActivity.class);
|
||||
intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/save"));
|
||||
mainActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_SAVEGAME);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void showLoad(final Activity currentActivity) {
|
||||
|
||||
@@ -28,6 +28,8 @@ public final class WorldSetup {
|
||||
public boolean isSceneReady = false;
|
||||
public String newHeroName;
|
||||
public int newHeroIcon;
|
||||
public int newHeroStartLives;
|
||||
public boolean newHeroUnlimitedSaves;
|
||||
private Savegames.LoadSavegameResult loadResult;
|
||||
|
||||
public WorldSetup(WorldContext world, ControllerContext controllers, Context androidContext) {
|
||||
@@ -149,7 +151,7 @@ public final class WorldSetup {
|
||||
|
||||
private void createNewWorld() {
|
||||
Context ctx = androidContext.get();
|
||||
world.model = new ModelContainer();
|
||||
world.model = new ModelContainer(newHeroStartLives, newHeroUnlimitedSaves);
|
||||
world.model.player.initializeNewPlayer(world.dropLists, newHeroName, newHeroIcon);
|
||||
|
||||
controllers.actorStatsController.recalculatePlayerStats(world.model.player);
|
||||
|
||||
@@ -108,10 +108,23 @@ public final class LoadSaveActivity extends Activity implements OnClickListener
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -139,6 +152,7 @@ public final class LoadSaveActivity extends Activity implements OnClickListener
|
||||
private String getConfirmOverwriteQuestion(int slot) {
|
||||
if (isLoading) return null;
|
||||
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) return null; // if we're creating a new slot
|
||||
if (!Savegames.getSlotFile(slot).exists()) return null;
|
||||
|
||||
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_ALWAYS) {
|
||||
return getString(R.string.loadsave_save_overwrite_confirmation_all);
|
||||
@@ -160,42 +174,73 @@ public final class LoadSaveActivity extends Activity implements OnClickListener
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final int slot = (Integer) view.getTag();
|
||||
final String message = getConfirmOverwriteQuestion(slot);
|
||||
|
||||
if (message != null) {
|
||||
final String title =
|
||||
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
|
||||
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
|
||||
// new AlertDialog.Builder(this)
|
||||
// .setIcon(android.R.drawable.ic_dialog_alert)
|
||||
// .setTitle(title)
|
||||
// .setMessage(message)
|
||||
// .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
// @Override
|
||||
// public void onClick(DialogInterface dialog, int which) {
|
||||
// loadsave(slot);
|
||||
// }
|
||||
// })
|
||||
// .setNegativeButton(android.R.string.no, null)
|
||||
// .show();
|
||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||
title,
|
||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
message,
|
||||
null,
|
||||
true);
|
||||
|
||||
CustomDialogFactory.addButton(d, android.R.string.yes, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
loadsave(slot);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
||||
|
||||
CustomDialogFactory.show(d);
|
||||
if (isLoading) {
|
||||
if(!Savegames.getSlotFile(slot).exists()) {
|
||||
showErrorLoadingEmptySlot();
|
||||
} else {
|
||||
final FileHeader header = Savegames.quickload(this, slot);
|
||||
if (header != null && !header.hasUnlimitedSaves) {
|
||||
showSlotGetsDeletedOnLoadWarning(slot);
|
||||
} else {
|
||||
loadsave(slot);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loadsave(slot);
|
||||
final String message = getConfirmOverwriteQuestion(slot);
|
||||
if (message != null) {
|
||||
showConfirmoverwriteQuestion(slot, message);
|
||||
} else {
|
||||
loadsave(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showErrorLoadingEmptySlot() {
|
||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||
getString(R.string.startscreen_error_loading_game),
|
||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
getString(R.string.startscreen_error_loading_empty_slot),
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
CustomDialogFactory.show(d);
|
||||
}
|
||||
|
||||
private void showSlotGetsDeletedOnLoadWarning(int slot) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||
getString(R.string.startscreen_attention_slot_gets_delete_on_load),
|
||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
getString(R.string.startscreen_attention_message_slot_gets_delete_on_load),
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
loadsave(slot);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.show(d);
|
||||
}
|
||||
|
||||
private void showConfirmoverwriteQuestion(int slot, String message) {
|
||||
final String title =
|
||||
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
|
||||
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
|
||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||
title,
|
||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
message,
|
||||
null,
|
||||
true);
|
||||
|
||||
CustomDialogFactory.addButton(d, android.R.string.yes, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
loadsave(slot);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
||||
CustomDialogFactory.show(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class LoadingActivity extends Activity implements OnResourcesLoaded
|
||||
private Dialog progressDialog;
|
||||
private CloudsAnimatorView clouds_back, clouds_mid, clouds_front;
|
||||
boolean loaded = false;
|
||||
|
||||
|
||||
private Object semaphore = new Object();
|
||||
|
||||
@Override
|
||||
@@ -158,6 +158,8 @@ public final class LoadingActivity extends Activity implements OnResourcesLoaded
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,9 @@ public final class MainActivity
|
||||
final int slot = data.getIntExtra("slot", 1);
|
||||
if (save(slot)) {
|
||||
Toast.makeText(this, getResources().getString(R.string.menu_save_gamesaved, slot), Toast.LENGTH_SHORT).show();
|
||||
if (!world.model.statistics.hasUnlimitedSaves()) {
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, R.string.menu_save_failed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
@@ -188,9 +191,11 @@ public final class MainActivity
|
||||
super.onResume();
|
||||
if (!AndorsTrailApplication.getApplicationFromActivity(this).getWorldSetup().isSceneReady) return;
|
||||
|
||||
controllers.gameRoundController.resume();
|
||||
|
||||
updateStatus();
|
||||
if (world.model.statistics.isDead()) this.finish();
|
||||
else {
|
||||
controllers.gameRoundController.resume();
|
||||
updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void unsubscribeFromModel() {
|
||||
@@ -452,7 +457,11 @@ public final class MainActivity
|
||||
|
||||
@Override
|
||||
public void onPlayerDied(int lostExp) {
|
||||
message(getString(R.string.combat_hero_dies, lostExp));
|
||||
if (!world.model.statistics.isDead()) {
|
||||
message(getString(R.string.combat_hero_dies, lostExp));
|
||||
} else {
|
||||
Dialogs.showHeroDied(this, controllers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.Dialogs;
|
||||
import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.model.GameStatistics;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.HeroCollection;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Player;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.Inventory;
|
||||
@@ -35,6 +36,7 @@ public final class HeroinfoActivity_Stats extends Fragment {
|
||||
|
||||
private WorldContext world;
|
||||
private Player player;
|
||||
private GameStatistics statistics;
|
||||
|
||||
private View view;
|
||||
private Button levelUpButton;
|
||||
@@ -53,6 +55,7 @@ public final class HeroinfoActivity_Stats extends Fragment {
|
||||
private TableLayout heroinfo_basestats_table;
|
||||
private ViewGroup heroinfo_container;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -60,6 +63,7 @@ public final class HeroinfoActivity_Stats extends Fragment {
|
||||
if (!app.isInitialized()) return;
|
||||
this.world = app.getWorld();
|
||||
this.player = world.model.player;
|
||||
this.statistics = world.model.statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,7 +76,23 @@ public final class HeroinfoActivity_Stats extends Fragment {
|
||||
|
||||
TextView tv = (TextView) v.findViewById(R.id.heroinfo_title);
|
||||
if (tv != null) {
|
||||
tv.setText(player.getName());
|
||||
String description = player.getName() + "\n";
|
||||
final Resources res = getResources();
|
||||
if (statistics.hasUnlimitedLives() && statistics.hasUnlimitedSaves()) {
|
||||
description += res.getString(R.string.heroinfo_unlimited_lives_and_saves);
|
||||
} else if (statistics.hasUnlimitedLives()) {
|
||||
description += res.getString(R.string.heroinfo_unlimited_lives);
|
||||
} else {
|
||||
if (statistics.getStartLives() == 1 && !statistics.hasUnlimitedSaves()) {
|
||||
description += res.getString(R.string.heroinfo_hardcore_mode);
|
||||
} else {
|
||||
description += res.getString(R.string.heroinfo_lives_left, statistics.getLivesLeft(), statistics.getStartLives());
|
||||
if (statistics.hasUnlimitedSaves()) {
|
||||
description += res.getString(R.string.heroinfo_unlimited_saves);
|
||||
}
|
||||
}
|
||||
}
|
||||
tv.setText(description);
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(HeroCollection.getHeroLargeSprite(player.iconID), 0, 0, 0);
|
||||
}
|
||||
heroinfo_container = (ViewGroup) v.findViewById(R.id.heroinfo_container);
|
||||
|
||||
@@ -106,7 +106,27 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
startscreen_load.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
||||
if (hasExistingGame && app != null && app.getWorld() != null && app.getWorld().model != null
|
||||
&& app.getWorld().model.statistics != null && !app.getWorld().model.statistics.hasUnlimitedSaves()) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
|
||||
getString(R.string.startscreen_load_game),
|
||||
getResources().getDrawable(android.R.drawable.ic_delete),
|
||||
getString(R.string.startscreen_load_game_confirm),
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
|
||||
CustomDialogFactory.show(d);
|
||||
|
||||
} else {
|
||||
Dialogs.showLoad(StartScreenActivity_MainMenu.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -131,12 +151,14 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
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);
|
||||
@@ -146,7 +168,7 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
}
|
||||
}
|
||||
hasExistingGame = (playerName != null);
|
||||
setButtonState(playerName, displayInfo, iconID);
|
||||
setButtonState(playerName, displayInfo, iconID, isDead);
|
||||
|
||||
if (isNewVersion()) {
|
||||
Dialogs.showNewVersion(getActivity());
|
||||
@@ -168,13 +190,13 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
listener = null;
|
||||
}
|
||||
|
||||
private void setButtonState(final String playerName, final String displayInfo, int iconID) {
|
||||
startscreen_continue.setEnabled(hasExistingGame);
|
||||
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(playerName + ", " + displayInfo);
|
||||
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);
|
||||
|
||||
@@ -20,12 +20,15 @@ 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) {
|
||||
@@ -39,7 +42,40 @@ public class StartScreenActivity_NewGame extends Fragment {
|
||||
|
||||
|
||||
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() {
|
||||
|
||||
@@ -114,6 +150,8 @@ public class StartScreenActivity_NewGame extends Fragment {
|
||||
setup.loadFromSlot = loadFromSlot;
|
||||
setup.newHeroName = name;
|
||||
setup.newHeroIcon = selectedIconID;
|
||||
setup.newHeroStartLives = startLives;
|
||||
setup.newHeroUnlimitedSaves = unlimitedSaves;
|
||||
gameCreationOver();
|
||||
startActivity(new Intent(getActivity(), LoadingActivity.class));
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public final class Constants {
|
||||
public static final String FILENAME_WORLDMAP_HTMLFILE_SUFFIX = ".html";
|
||||
public static final String FILENAME_SAVEGAME_FILENAME_PREFIX = "savegame";
|
||||
public static final String PLACEHOLDER_PLAYERNAME = "$playername";
|
||||
public static final String CHEAT_DETECTION_FOLDER = "dEAGyGE3YojqXjI3x4x7";
|
||||
|
||||
public static final Random rnd = new Random();
|
||||
public static int rollValue(final ConstRange r) { return rollValue(r.max, r.current); }
|
||||
|
||||
@@ -129,8 +129,11 @@ public final class MapController {
|
||||
if (lostExp < 0) lostExp = 0;
|
||||
controllers.actorStatsController.addExperience(-lostExp);
|
||||
world.model.statistics.addPlayerDeath(lostExp);
|
||||
controllers.movementController.respawnPlayerAsync();
|
||||
lotsOfTimePassed();
|
||||
|
||||
if (!world.model.statistics.isDead()) {
|
||||
controllers.movementController.respawnPlayerAsync();
|
||||
lotsOfTimePassed();
|
||||
}
|
||||
worldEventListeners.onPlayerDied(lostExp);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,14 @@ public final class GameStatistics {
|
||||
private final HashMap<String, Integer> killedMonsters = new HashMap<String, Integer>();
|
||||
private final HashMap<String, Integer> usedItems = new HashMap<String, Integer>();
|
||||
private int spentGold = 0;
|
||||
private boolean unlimitedSaves = true;
|
||||
private int startLives = -1; // -1 --> unlimited
|
||||
|
||||
public GameStatistics(boolean unlimitedSaves, int startLives) {
|
||||
this.unlimitedSaves = unlimitedSaves;
|
||||
this.startLives = startLives;
|
||||
}
|
||||
|
||||
public GameStatistics() { }
|
||||
public void addMonsterKill(String monsterTypeID) {
|
||||
if (!killedMonsters.containsKey(monsterTypeID)) killedMonsters.put(monsterTypeID, 1);
|
||||
else killedMonsters.put(monsterTypeID, killedMonsters.get(monsterTypeID) + 1);
|
||||
@@ -51,6 +57,16 @@ public final class GameStatistics {
|
||||
return spentGold;
|
||||
}
|
||||
|
||||
public boolean hasUnlimitedSaves() { return unlimitedSaves; }
|
||||
|
||||
public boolean hasUnlimitedLives() { return startLives == -1; }
|
||||
|
||||
public int getStartLives() { return startLives; }
|
||||
|
||||
public int getLivesLeft() { return hasUnlimitedLives() ? -1 : startLives - deaths; }
|
||||
|
||||
public boolean isDead() { return !hasUnlimitedLives() && getLivesLeft() < 1; }
|
||||
|
||||
public int getNumberOfKillsForMonsterType(String monsterTypeID) {
|
||||
Integer v = killedMonsters.get(monsterTypeID);
|
||||
if (v == null) return 0;
|
||||
@@ -167,6 +183,11 @@ public final class GameStatistics {
|
||||
this.usedItems.put(name, value);
|
||||
}
|
||||
this.spentGold = src.readInt();
|
||||
|
||||
if (fileversion < 48) return;
|
||||
|
||||
this.startLives = src.readInt();
|
||||
this.unlimitedSaves = src.readBoolean();
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest) throws IOException {
|
||||
@@ -184,5 +205,7 @@ public final class GameStatistics {
|
||||
dest.writeInt(e.getValue());
|
||||
}
|
||||
dest.writeInt(spentGold);
|
||||
dest.writeInt(startLives);
|
||||
dest.writeBoolean(unlimitedSaves);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ public final class ModelContainer {
|
||||
public PredefinedMap currentMap;
|
||||
public LayeredTileMap currentTileMap;
|
||||
|
||||
public ModelContainer() {
|
||||
public ModelContainer(int startLives, boolean unlimitedSaves) {
|
||||
player = new Player();
|
||||
uiSelections = new InterfaceData();
|
||||
statistics = new GameStatistics();
|
||||
statistics = new GameStatistics(unlimitedSaves, startLives);
|
||||
worldData = new WorldData();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
@@ -44,6 +45,8 @@ public final class Player extends Actor {
|
||||
private String spawnMap;
|
||||
private String spawnPlace;
|
||||
private final HashMap<String, Integer> alignments = new HashMap<String, Integer>();
|
||||
public String id = UUID.randomUUID().toString();
|
||||
public long savedVersion = 1; // the version get's increased for cheat detection everytime a player with limited saves is saved
|
||||
|
||||
// Unequipped stats
|
||||
public static final class PlayerBaseTraits {
|
||||
@@ -365,6 +368,11 @@ public final class Player extends Actor {
|
||||
this.alignments.put(faction, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (fileversion >= 48) {
|
||||
this.id = src.readUTF();
|
||||
this.savedVersion = src.readLong();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest) throws IOException {
|
||||
@@ -421,6 +429,8 @@ public final class Player extends Actor {
|
||||
dest.writeUTF(e.getKey());
|
||||
dest.writeInt(e.getValue());
|
||||
}
|
||||
dest.writeUTF(id);
|
||||
dest.writeLong(savedVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
@@ -21,6 +22,7 @@ import java.util.regex.Pattern;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Environment;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
@@ -32,15 +34,25 @@ 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, String displayInfo) {
|
||||
try {
|
||||
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();
|
||||
@@ -51,18 +63,51 @@ public final class Savegames {
|
||||
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(savegame, id);
|
||||
lastBackup = SystemClock.uptimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
L.log("Error saving world: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeBackup(byte[] savegame, String playerId) throws IOException {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
File cheatDetectionFolder = new File(root, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
File backupFile = new File(cheatDetectionFolder, playerId + "X");
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
|
||||
fileOutputStream.write(savegame);
|
||||
fileOutputStream.close();
|
||||
}
|
||||
|
||||
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()) {
|
||||
getSlotFile(slot).delete();
|
||||
writeCheatCheck(androidContext, DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED, fh.playerId);
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
@@ -76,6 +121,47 @@ public final class Savegames {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
|
||||
long savedVersionToCheck = 0;
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
File cheatDetectionFolder = new File(root, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
|
||||
if (cheatDetectionFile.exists()) {
|
||||
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||
savedVersionToCheck = cheatDetection.savedVersion;
|
||||
dataInputStream.close();
|
||||
fileInputStream.close();
|
||||
}
|
||||
|
||||
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (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);
|
||||
@@ -96,7 +182,8 @@ public final class Savegames {
|
||||
return new FileInputStream(getSlotFile(slot));
|
||||
}
|
||||
}
|
||||
private static File getSlotFile(int slot) {
|
||||
|
||||
public static File getSlotFile(int slot) {
|
||||
File root = getSavegameDirectory();
|
||||
return new File(root, Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot);
|
||||
}
|
||||
@@ -108,7 +195,12 @@ public final class Savegames {
|
||||
|
||||
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);
|
||||
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();
|
||||
@@ -156,6 +248,24 @@ public final class Savegames {
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
File cheatDetectionFolder = new File(root, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
|
||||
dataOutputStream.close();
|
||||
fileOutputStream.close();
|
||||
|
||||
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() {
|
||||
try {
|
||||
@@ -178,13 +288,36 @@ public final class Savegames {
|
||||
}
|
||||
}
|
||||
|
||||
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 playerName + ", " + displayInfo;
|
||||
}
|
||||
@@ -203,9 +336,10 @@ public final class Savegames {
|
||||
this.playerName = null;
|
||||
this.displayInfo = null;
|
||||
}
|
||||
if (fileversion >= 43 && !skipIcon) {
|
||||
|
||||
if (fileversion >= 43) {
|
||||
int id = src.readInt();
|
||||
if (id > TileManager.LAST_HERO) {
|
||||
if (skipIcon || id > TileManager.LAST_HERO) {
|
||||
this.iconID = TileManager.CHAR_HERO_0;
|
||||
this.skipIcon = true;
|
||||
} else {
|
||||
@@ -214,13 +348,29 @@ public final class Savegames {
|
||||
} else {
|
||||
this.iconID = TileManager.CHAR_HERO_0;
|
||||
}
|
||||
|
||||
if (fileversion >= 48) {
|
||||
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) throws IOException {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user