diff --git a/AndorsTrail/.classpath b/AndorsTrail/.classpath
new file mode 100644
index 000000000..609aa00eb
--- /dev/null
+++ b/AndorsTrail/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/AndorsTrail/.project b/AndorsTrail/.project
new file mode 100644
index 000000000..f02b17960
--- /dev/null
+++ b/AndorsTrail/.project
@@ -0,0 +1,33 @@
+
+
+ AndorsTrail
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/AndorsTrail/AndroidManifest.xml b/AndorsTrail/AndroidManifest.xml
new file mode 100644
index 000000000..1235b56f8
--- /dev/null
+++ b/AndorsTrail/AndroidManifest.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/bin/AndorsTrail.apk b/AndorsTrail/bin/AndorsTrail.apk
new file mode 100644
index 000000000..744add865
Binary files /dev/null and b/AndorsTrail/bin/AndorsTrail.apk differ
diff --git a/AndorsTrail/bin/classes.dex b/AndorsTrail/bin/classes.dex
new file mode 100644
index 000000000..45e6db775
Binary files /dev/null and b/AndorsTrail/bin/classes.dex differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.class
new file mode 100644
index 000000000..2e15e99e0
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$1.class
new file mode 100644
index 000000000..b9e45b848
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$2.class
new file mode 100644
index 000000000..617b10c34
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$3.class
new file mode 100644
index 000000000..d9432f232
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$4.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$4.class
new file mode 100644
index 000000000..e5a73dd51
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$4.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$5.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$5.class
new file mode 100644
index 000000000..74f80f029
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs$5.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs.class
new file mode 100644
index 000000000..ab094cb9e
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/Dialogs.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection$Effect.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection$Effect.class
new file mode 100644
index 000000000..df98ab062
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection$Effect.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection.class
new file mode 100644
index 000000000..74705e27e
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/EffectCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$attr.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$attr.class
new file mode 100644
index 000000000..ac9d294b0
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$attr.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$dimen.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$dimen.class
new file mode 100644
index 000000000..8aa185a87
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$dimen.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$drawable.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$drawable.class
new file mode 100644
index 000000000..e4375f179
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$drawable.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$id.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$id.class
new file mode 100644
index 000000000..51eadec80
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$id.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$layout.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$layout.class
new file mode 100644
index 000000000..372f6fc2a
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$layout.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$menu.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$menu.class
new file mode 100644
index 000000000..6670bbeeb
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$menu.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$string.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$string.class
new file mode 100644
index 000000000..7478f2dfe
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$string.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$style.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$style.class
new file mode 100644
index 000000000..b4f0e9644
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$style.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$xml.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$xml.class
new file mode 100644
index 000000000..ccd9e553f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R$xml.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R.class
new file mode 100644
index 000000000..a6ef21744
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/R.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$1.class
new file mode 100644
index 000000000..ba3bf428a
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$2.class
new file mode 100644
index 000000000..322ebc5e9
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$OnSceneLoadedListener.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$OnSceneLoadedListener.class
new file mode 100644
index 000000000..ab2dea018
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup$OnSceneLoadedListener.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup.class
new file mode 100644
index 000000000..02d8cc1d1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/WorldSetup.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$1.class
new file mode 100644
index 000000000..8de1fc482
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$2.class
new file mode 100644
index 000000000..447128514
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$3.class
new file mode 100644
index 000000000..9df4e6062
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity.class
new file mode 100644
index 000000000..510e0d4ec
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/AboutActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity$1.class
new file mode 100644
index 000000000..4adf32a25
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.class
new file mode 100644
index 000000000..44381e8a7
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$1.class
new file mode 100644
index 000000000..294df541c
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$2.class
new file mode 100644
index 000000000..33d056aee
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$3.class
new file mode 100644
index 000000000..f234e67d6
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.class
new file mode 100644
index 000000000..513b96029
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$1.class
new file mode 100644
index 000000000..1957136dd
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$2.class
new file mode 100644
index 000000000..3d0aa7353
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.class
new file mode 100644
index 000000000..6c12763b5
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$1.class
new file mode 100644
index 000000000..23f4ff12f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$2.class
new file mode 100644
index 000000000..013a08f77
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$3.class
new file mode 100644
index 000000000..10e6b526c
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$4.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$4.class
new file mode 100644
index 000000000..43f159831
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity$4.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.class
new file mode 100644
index 000000000..289d575a7
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$1.class
new file mode 100644
index 000000000..c6f52c8f2
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$2.class
new file mode 100644
index 000000000..a019f3478
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$3.class
new file mode 100644
index 000000000..1141e2842
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$DebugButton.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$DebugButton.class
new file mode 100644
index 000000000..9a883aa88
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity$DebugButton.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity.class
new file mode 100644
index 000000000..170c0dff1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MainActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$1.class
new file mode 100644
index 000000000..94133f873
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$2.class
new file mode 100644
index 000000000..ff0ae8c93
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$3.class
new file mode 100644
index 000000000..2c1923367
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.class
new file mode 100644
index 000000000..bd7b1af21
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity$1.class
new file mode 100644
index 000000000..a00229b20
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.class
new file mode 100644
index 000000000..6505304c1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ShopActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ShopActivity.class
new file mode 100644
index 000000000..bb05af63a
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/ShopActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$1.class
new file mode 100644
index 000000000..55a33aa57
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$2.class
new file mode 100644
index 000000000..6eb6acf5d
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$3.class
new file mode 100644
index 000000000..0499ab8fc
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$4.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$4.class
new file mode 100644
index 000000000..bed85ebc8
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$4.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$5.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$5.class
new file mode 100644
index 000000000..fb29723df
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity$5.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.class
new file mode 100644
index 000000000..56d94249f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/ViewContext.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/ViewContext.class
new file mode 100644
index 000000000..917a47b7e
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/ViewContext.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/WorldContext.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/WorldContext.class
new file mode 100644
index 000000000..0ab712e47
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/context/WorldContext.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController$1.class
new file mode 100644
index 000000000..50005f198
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController.class
new file mode 100644
index 000000000..e0d4151f0
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/CombatController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller$RefreshHandler.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller$RefreshHandler.class
new file mode 100644
index 000000000..7480f00e4
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller$RefreshHandler.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller.class
new file mode 100644
index 000000000..53bff5280
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/Controller.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ConversationController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ConversationController.class
new file mode 100644
index 000000000..abdaf80ef
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ConversationController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController$EffectAnimation.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController$EffectAnimation.class
new file mode 100644
index 000000000..e64977962
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController$EffectAnimation.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController.class
new file mode 100644
index 000000000..da56a9584
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/EffectController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ItemController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ItemController.class
new file mode 100644
index 000000000..09b546f10
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/ItemController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.class
new file mode 100644
index 000000000..b0576037d
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MovementController.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MovementController.class
new file mode 100644
index 000000000..23773711b
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/controller/MovementController.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.class
new file mode 100644
index 000000000..1ba42851f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase$Reply.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase$Reply.class
new file mode 100644
index 000000000..43e20a64b
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase$Reply.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase.class
new file mode 100644
index 000000000..5d0bd6cdc
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/conversation/Phrase.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/AttackResult.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/AttackResult.class
new file mode 100644
index 000000000..d99023a85
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/AttackResult.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/CombatTraits.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/CombatTraits.class
new file mode 100644
index 000000000..68643dfa6
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/CombatTraits.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/GameStatistics.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/GameStatistics.class
new file mode 100644
index 000000000..97debbc90
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/GameStatistics.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/InterfaceData.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/InterfaceData.class
new file mode 100644
index 000000000..f27ba89a1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/InterfaceData.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/ModelContainer.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/ModelContainer.class
new file mode 100644
index 000000000..741b33118
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/ModelContainer.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Actor.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Actor.class
new file mode 100644
index 000000000..989af2041
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Actor.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.class
new file mode 100644
index 000000000..1b9712056
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Monster.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Monster.class
new file mode 100644
index 000000000..b82c0c484
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Monster.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.class
new file mode 100644
index 000000000..972ee4bbd
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.class
new file mode 100644
index 000000000..6e5f608c9
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Player.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Player.class
new file mode 100644
index 000000000..8c795ecf2
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Player.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Skills.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Skills.class
new file mode 100644
index 000000000..ce3cbabb9
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/actor/Skills.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList$DropItem.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList$DropItem.class
new file mode 100644
index 000000000..b538622f5
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList$DropItem.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList.class
new file mode 100644
index 000000000..963a53505
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropList.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.class
new file mode 100644
index 000000000..18a2fabe2
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Inventory.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Inventory.class
new file mode 100644
index 000000000..576de5bc4
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Inventory.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer$ItemEntry.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer$ItemEntry.class
new file mode 100644
index 000000000..9b9672325
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer$ItemEntry.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.class
new file mode 100644
index 000000000..2bc0584d1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemType.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemType.class
new file mode 100644
index 000000000..7e7661b2a
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemType.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.class
new file mode 100644
index 000000000..88485a686
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Loot.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Loot.class
new file mode 100644
index 000000000..c4d3ee08b
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/item/Loot.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/KeyArea.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/KeyArea.class
new file mode 100644
index 000000000..0b3283da9
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/KeyArea.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.class
new file mode 100644
index 000000000..45a71708f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapCollection.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapCollection.class
new file mode 100644
index 000000000..4fb016c0c
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapCollection.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapLayer.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapLayer.class
new file mode 100644
index 000000000..5dab59d67
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapLayer.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapObject.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapObject.class
new file mode 100644
index 000000000..014a5b026
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MapObject.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.class
new file mode 100644
index 000000000..85f08e600
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$1.class
new file mode 100644
index 000000000..f4b1abc50
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$2.class
new file mode 100644
index 000000000..d544fcf34
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3$1.class
new file mode 100644
index 000000000..318b639a8
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3.class
new file mode 100644
index 000000000..4939b0e54
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1.class
new file mode 100644
index 000000000..0aa174960
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$Pair.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$Pair.class
new file mode 100644
index 000000000..713d59cda
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$Pair.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXLayer.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXLayer.class
new file mode 100644
index 000000000..e494dc297
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXLayer.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXMap.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXMap.class
new file mode 100644
index 000000000..915b40fce
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXMap.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObject.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObject.class
new file mode 100644
index 000000000..7934141de
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObject.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObjectGroup.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObjectGroup.class
new file mode 100644
index 000000000..d1a63d04f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXObjectGroup.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXProperty.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXProperty.class
new file mode 100644
index 000000000..d01f95abe
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXProperty.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXTileSet.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXTileSet.class
new file mode 100644
index 000000000..021cd12f1
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TMXTileSet.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TagHandler.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TagHandler.class
new file mode 100644
index 000000000..9c147bd27
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader$TagHandler.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.class
new file mode 100644
index 000000000..1c13ab856
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader$TilesetBitmap.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader$TilesetBitmap.class
new file mode 100644
index 000000000..1ded13c43
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader$TilesetBitmap.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.class
new file mode 100644
index 000000000..33ac852de
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.class
new file mode 100644
index 000000000..c42871fd5
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/TileStore.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/TileStore.class
new file mode 100644
index 000000000..b011a97bb
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/resource/TileStore.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Base64.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Base64.class
new file mode 100644
index 000000000..93cc03f27
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Base64.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/ConstRange.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/ConstRange.class
new file mode 100644
index 000000000..73cdba5ca
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/ConstRange.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Coord.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Coord.class
new file mode 100644
index 000000000..fc4299a3e
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Coord.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/CoordRect.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/CoordRect.class
new file mode 100644
index 000000000..c9d4d6d87
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/CoordRect.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/L.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/L.class
new file mode 100644
index 000000000..0cbcf2b59
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/L.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Range.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Range.class
new file mode 100644
index 000000000..7ff4d8015
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Range.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Size.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Size.class
new file mode 100644
index 000000000..5f17a851f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/util/Size.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$1.class
new file mode 100644
index 000000000..fa1458761
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$2.class
new file mode 100644
index 000000000..a09fc3cda
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$3.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$3.class
new file mode 100644
index 000000000..d7c95bd86
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$3.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$4.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$4.class
new file mode 100644
index 000000000..5b7bd3ef5
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView$4.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView.class
new file mode 100644
index 000000000..f03c65158
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/CombatView.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.class
new file mode 100644
index 000000000..4fc96449f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$1.class
new file mode 100644
index 000000000..2998fc57f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$2.class
new file mode 100644
index 000000000..e971a1e07
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView.class
new file mode 100644
index 000000000..02bde8324
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/MainView.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/RangeBar.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/RangeBar.class
new file mode 100644
index 000000000..dd8cf345f
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/RangeBar.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$1.class
new file mode 100644
index 000000000..12a815480
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$2.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$2.class
new file mode 100644
index 000000000..6ec847349
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$2.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$OnContainerItemClickedListener.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$OnContainerItemClickedListener.class
new file mode 100644
index 000000000..cadcdf0ed
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter$OnContainerItemClickedListener.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.class
new file mode 100644
index 000000000..3e1e74aad
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView$1.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView$1.class
new file mode 100644
index 000000000..cee9c9b48
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView$1.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView.class
new file mode 100644
index 000000000..98baa19f3
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/StatusView.class differ
diff --git a/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.class b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.class
new file mode 100644
index 000000000..82d3641ff
Binary files /dev/null and b/AndorsTrail/bin/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.class differ
diff --git a/AndorsTrail/bin/resources.ap_ b/AndorsTrail/bin/resources.ap_
new file mode 100644
index 000000000..13f8f6e26
Binary files /dev/null and b/AndorsTrail/bin/resources.ap_ differ
diff --git a/AndorsTrail/default.properties b/AndorsTrail/default.properties
new file mode 100644
index 000000000..0b9250e02
--- /dev/null
+++ b/AndorsTrail/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/AndorsTrail/gen/com/gpl/rpg/AndorsTrail/R.java b/AndorsTrail/gen/com/gpl/rpg/AndorsTrail/R.java
new file mode 100644
index 000000000..4a1d66276
--- /dev/null
+++ b/AndorsTrail/gen/com/gpl/rpg/AndorsTrail/R.java
@@ -0,0 +1,431 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package com.gpl.rpg.AndorsTrail;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class dimen {
+ public static final int boxshape_margin=0x7f060007;
+ public static final int boxshape_width=0x7f060008;
+ public static final int dialog_iconpadding_bottom=0x7f060006;
+ public static final int dialog_iconpadding_right=0x7f060005;
+ public static final int dialog_margin=0x7f060004;
+ public static final int healthbar_height=0x7f060003;
+ public static final int section_margin=0x7f060009;
+ public static final int smalltext=0x7f060000;
+ public static final int smalltext_buttonheight=0x7f060001;
+ public static final int titletext=0x7f060002;
+ }
+ public static final class drawable {
+ public static final int andors_trail_logo=0x7f020000;
+ public static final int char_hero=0x7f020001;
+ public static final int effect_blood3=0x7f020002;
+ public static final int equip_body=0x7f020003;
+ public static final int equip_feet=0x7f020004;
+ public static final int equip_hand=0x7f020005;
+ public static final int equip_head=0x7f020006;
+ public static final int equip_neck=0x7f020007;
+ public static final int equip_ring=0x7f020008;
+ public static final int equip_shield=0x7f020009;
+ public static final int equip_square=0x7f02000a;
+ public static final int equip_weapon=0x7f02000b;
+ public static final int icon=0x7f02000c;
+ public static final int icon_coin=0x7f02000d;
+ public static final int items_tiles=0x7f02000e;
+ public static final int map_tiles_1_1=0x7f02000f;
+ public static final int map_tiles_1_2=0x7f020010;
+ public static final int map_tiles_1_3=0x7f020011;
+ public static final int map_tiles_1_4=0x7f020012;
+ public static final int map_tiles_1_5=0x7f020013;
+ public static final int map_tiles_1_6=0x7f020014;
+ public static final int map_tiles_1_7=0x7f020015;
+ public static final int map_tiles_1_8=0x7f020016;
+ public static final int map_tiles_2_1=0x7f020017;
+ public static final int map_tiles_2_2=0x7f020018;
+ public static final int map_tiles_2_3=0x7f020019;
+ public static final int map_tiles_2_4=0x7f02001a;
+ public static final int map_tiles_2_5=0x7f02001b;
+ public static final int map_tiles_2_6=0x7f02001c;
+ public static final int map_tiles_2_7=0x7f02001d;
+ public static final int map_tiles_2_8=0x7f02001e;
+ public static final int monsters_armor1=0x7f02001f;
+ public static final int monsters_cyclops=0x7f020020;
+ public static final int monsters_demon1=0x7f020021;
+ public static final int monsters_demon2=0x7f020022;
+ public static final int monsters_dogs=0x7f020023;
+ public static final int monsters_dragon1=0x7f020024;
+ public static final int monsters_dragons=0x7f020025;
+ public static final int monsters_eye1=0x7f020026;
+ public static final int monsters_eye2=0x7f020027;
+ public static final int monsters_eye3=0x7f020028;
+ public static final int monsters_eye4=0x7f020029;
+ public static final int monsters_ghost1=0x7f02002a;
+ public static final int monsters_ghost2=0x7f02002b;
+ public static final int monsters_hydra1=0x7f02002c;
+ public static final int monsters_insects=0x7f02002d;
+ public static final int monsters_liches=0x7f02002e;
+ public static final int monsters_mage=0x7f02002f;
+ public static final int monsters_mage2=0x7f020030;
+ public static final int monsters_mage3=0x7f020031;
+ public static final int monsters_mage4=0x7f020032;
+ public static final int monsters_man1=0x7f020033;
+ public static final int monsters_men=0x7f020034;
+ public static final int monsters_misc=0x7f020035;
+ public static final int monsters_rats=0x7f020036;
+ public static final int monsters_rogue1=0x7f020037;
+ public static final int monsters_skeleton1=0x7f020038;
+ public static final int monsters_skeleton2=0x7f020039;
+ public static final int monsters_snakes=0x7f02003a;
+ public static final int monsters_warrior1=0x7f02003b;
+ public static final int monsters_wraiths=0x7f02003c;
+ public static final int monsters_zombie1=0x7f02003d;
+ public static final int monsters_zombie2=0x7f02003e;
+ public static final int ui_bar_background=0x7f02003f;
+ public static final int ui_blue_foreground=0x7f020040;
+ public static final int ui_boxshape=0x7f020041;
+ public static final int ui_debug_background=0x7f020042;
+ public static final int ui_gradientshape=0x7f020043;
+ public static final int ui_green_foreground=0x7f020044;
+ public static final int ui_progress_ap=0x7f020045;
+ public static final int ui_progress_exp=0x7f020046;
+ public static final int ui_progress_health=0x7f020047;
+ public static final int ui_purple_foreground=0x7f020048;
+ public static final int ui_red_foreground=0x7f020049;
+ public static final int ui_startbackground=0x7f02004a;
+ public static final int ui_statustext=0x7f02004b;
+ public static final int ui_yellow_foreground=0x7f02004c;
+ }
+ public static final class id {
+ public static final int about_button1=0x7f090001;
+ public static final int about_button2=0x7f090002;
+ public static final int about_button3=0x7f090003;
+ public static final int about_contents=0x7f090004;
+ public static final int about_title=0x7f090000;
+ public static final int combatview_actionbar=0x7f090005;
+ public static final int combatview_endcombat=0x7f090007;
+ public static final int combatview_endturn=0x7f090008;
+ public static final int combatview_monsterbar=0x7f09000b;
+ public static final int combatview_monsterhealth=0x7f09000d;
+ public static final int combatview_monsterinfo=0x7f09000c;
+ public static final int combatview_monsterismoving=0x7f09000a;
+ public static final int combatview_moveattack=0x7f090006;
+ public static final int combatview_status=0x7f090009;
+ public static final int conversation_image=0x7f09000e;
+ public static final int conversation_reply1=0x7f090011;
+ public static final int conversation_reply2=0x7f090012;
+ public static final int conversation_reply3=0x7f090013;
+ public static final int conversation_text=0x7f090010;
+ public static final int conversation_title=0x7f09000f;
+ public static final int heroinfo_ap=0x7f090025;
+ public static final int heroinfo_basetraits=0x7f09002a;
+ public static final int heroinfo_currenttraits=0x7f090029;
+ public static final int heroinfo_expbar=0x7f090028;
+ public static final int heroinfo_healthbar=0x7f090027;
+ public static final int heroinfo_image=0x7f090021;
+ public static final int heroinfo_level=0x7f090023;
+ public static final int heroinfo_levelup=0x7f09002b;
+ public static final int heroinfo_movecost=0x7f090026;
+ public static final int heroinfo_stats_attack=0x7f09002d;
+ public static final int heroinfo_stats_defense=0x7f09002e;
+ public static final int heroinfo_stats_gold=0x7f09002c;
+ public static final int heroinfo_tab1=0x7f090014;
+ public static final int heroinfo_tab2=0x7f090015;
+ public static final int heroinfo_title=0x7f090022;
+ public static final int heroinfo_totalexperience=0x7f090024;
+ public static final int heroinfo_worn_body=0x7f090018;
+ public static final int heroinfo_worn_center=0x7f090016;
+ public static final int heroinfo_worn_feet=0x7f09001b;
+ public static final int heroinfo_worn_hand=0x7f09001a;
+ public static final int heroinfo_worn_head=0x7f090017;
+ public static final int heroinfo_worn_neck=0x7f090019;
+ public static final int heroinfo_worn_ringleft=0x7f09001d;
+ public static final int heroinfo_worn_ringright=0x7f09001f;
+ public static final int heroinfo_worn_shield=0x7f09001e;
+ public static final int heroinfo_worn_weapon=0x7f09001c;
+ public static final int inv_image=0x7f09002f;
+ public static final int inv_menu_drop=0x7f090078;
+ public static final int inv_menu_equip=0x7f090075;
+ public static final int inv_menu_info=0x7f090074;
+ public static final int inv_menu_unequip=0x7f090076;
+ public static final int inv_menu_use=0x7f090077;
+ public static final int inv_text=0x7f090030;
+ public static final int inventorylist_root=0x7f090020;
+ public static final int iteminfo_action=0x7f090036;
+ public static final int iteminfo_category=0x7f090033;
+ public static final int iteminfo_close=0x7f090037;
+ public static final int iteminfo_description=0x7f090034;
+ public static final int iteminfo_image=0x7f090031;
+ public static final int iteminfo_title=0x7f090032;
+ public static final int iteminfo_traits=0x7f090035;
+ public static final int levelup_add_attackchance=0x7f09003c;
+ public static final int levelup_add_attackdamage=0x7f09003d;
+ public static final int levelup_add_blockchance=0x7f09003e;
+ public static final int levelup_add_health=0x7f09003b;
+ public static final int levelup_description=0x7f09003a;
+ public static final int levelup_image=0x7f090039;
+ public static final int levelup_titlelayout=0x7f090038;
+ public static final int main_combatview=0x7f090041;
+ public static final int main_container=0x7f09003f;
+ public static final int main_mainview=0x7f090042;
+ public static final int main_statusview=0x7f090040;
+ public static final int monsterencounter_attack=0x7f090047;
+ public static final int monsterencounter_cancel=0x7f090049;
+ public static final int monsterencounter_description=0x7f090046;
+ public static final int monsterencounter_image=0x7f090044;
+ public static final int monsterencounter_info=0x7f090048;
+ public static final int monsterencounter_title=0x7f090045;
+ public static final int monsterinfo_close=0x7f09004f;
+ public static final int monsterinfo_currenttraits=0x7f09004e;
+ public static final int monsterinfo_difficulty=0x7f09004c;
+ public static final int monsterinfo_healthbar=0x7f09004d;
+ public static final int monsterinfo_image=0x7f09004a;
+ public static final int monsterinfo_title=0x7f09004b;
+ public static final int rangebar_label=0x7f090050;
+ public static final int rangebar_progress=0x7f090051;
+ public static final int rangebar_text=0x7f090052;
+ public static final int shop_buy_gc=0x7f090054;
+ public static final int shop_buy_list=0x7f090055;
+ public static final int shop_sell_gc=0x7f090057;
+ public static final int shop_sell_list=0x7f090058;
+ public static final int shop_tab1=0x7f090053;
+ public static final int shop_tab2=0x7f090056;
+ public static final int shopitem_image=0x7f090059;
+ public static final int shopitem_infobutton=0x7f09005b;
+ public static final int shopitem_shopbutton=0x7f09005a;
+ public static final int shopitem_text=0x7f09005c;
+ public static final int startscreen_about=0x7f090061;
+ public static final int startscreen_continue=0x7f09005f;
+ public static final int startscreen_currenthero=0x7f09005d;
+ public static final int startscreen_enterheroname=0x7f09005e;
+ public static final int startscreen_newgame=0x7f090060;
+ public static final int startscreen_quit=0x7f090062;
+ public static final int status_image=0x7f090063;
+ public static final int statusview_exp=0x7f090065;
+ public static final int statusview_health=0x7f090064;
+ public static final int statusview_statustext=0x7f090043;
+ public static final int traitsinfo_attack_chance=0x7f090069;
+ public static final int traitsinfo_attack_cost=0x7f090067;
+ public static final int traitsinfo_attack_damage=0x7f09006b;
+ public static final int traitsinfo_attack_row1=0x7f090066;
+ public static final int traitsinfo_attack_row2=0x7f090068;
+ public static final int traitsinfo_attack_row3=0x7f09006a;
+ public static final int traitsinfo_critical_row1=0x7f09006c;
+ public static final int traitsinfo_critical_row2=0x7f09006e;
+ public static final int traitsinfo_criticalhit_chance=0x7f09006d;
+ public static final int traitsinfo_criticalhit_multiplier=0x7f09006f;
+ public static final int traitsinfo_defense_chance=0x7f090071;
+ public static final int traitsinfo_defense_damageresist=0x7f090073;
+ public static final int traitsinfo_defense_row1=0x7f090070;
+ public static final int traitsinfo_defense_row2=0x7f090072;
+ }
+ public static final class layout {
+ public static final int about=0x7f030000;
+ public static final int combatview=0x7f030001;
+ public static final int conversation=0x7f030002;
+ public static final int heroinfo=0x7f030003;
+ public static final int heroinfo_equipped=0x7f030004;
+ public static final int heroinfo_inventory=0x7f030005;
+ public static final int heroinfo_stats=0x7f030006;
+ public static final int heroinfo_statsicons=0x7f030007;
+ public static final int inventoryitemview=0x7f030008;
+ public static final int iteminfo=0x7f030009;
+ public static final int levelup=0x7f03000a;
+ public static final int main=0x7f03000b;
+ public static final int monsterencounter=0x7f03000c;
+ public static final int monsterinfo=0x7f03000d;
+ public static final int rangebar=0x7f03000e;
+ public static final int shop=0x7f03000f;
+ public static final int shopitemview=0x7f030010;
+ public static final int startscreen=0x7f030011;
+ public static final int statusview=0x7f030012;
+ public static final int traitsinfoview=0x7f030013;
+ }
+ public static final class menu {
+ public static final int inventoryitem=0x7f080000;
+ }
+ public static final class string {
+ public static final int about_button1=0x7f050098;
+ public static final int about_button2=0x7f050099;
+ public static final int about_button3=0x7f05009a;
+ public static final int about_contents1=0x7f05009b;
+ public static final int about_contents2=0x7f05009c;
+ public static final int about_contents3=0x7f05009d;
+ public static final int actorinfo_attack=0x7f05005a;
+ public static final int actorinfo_attacksperturn=0x7f050058;
+ public static final int actorinfo_basetraits=0x7f05005e;
+ public static final int actorinfo_class=0x7f050055;
+ public static final int actorinfo_criticalhit=0x7f05005b;
+ public static final int actorinfo_currenttraits=0x7f05005f;
+ public static final int actorinfo_defense=0x7f05005c;
+ public static final int actorinfo_difficulty=0x7f050056;
+ public static final int actorinfo_health=0x7f050057;
+ public static final int actorinfo_movecost=0x7f05005d;
+ public static final int actorinfo_movesperturn=0x7f050059;
+ public static final int app_name=0x7f050010;
+ public static final int combat_attack=0x7f05002e;
+ public static final int combat_cannotexitcombat=0x7f050037;
+ public static final int combat_endcombat=0x7f050033;
+ public static final int combat_endturn=0x7f050032;
+ public static final int combat_hero_dies=0x7f050040;
+ public static final int combat_monsteraction=0x7f050036;
+ public static final int combat_monsterhealth=0x7f050035;
+ public static final int combat_move=0x7f05002f;
+ public static final int combat_not_enough_ap=0x7f05003f;
+ public static final int combat_result_herohit=0x7f05003c;
+ public static final int combat_result_herohitcritical=0x7f05003d;
+ public static final int combat_result_herokillsmonster=0x7f05003e;
+ public static final int combat_result_heromiss=0x7f05003b;
+ public static final int combat_result_monsterhit=0x7f050039;
+ public static final int combat_result_monsterhitcritical=0x7f05003a;
+ public static final int combat_result_monstermiss=0x7f050038;
+ public static final int combat_spell=0x7f050031;
+ public static final int combat_status_ap=0x7f050034;
+ public static final int combat_use=0x7f050030;
+ public static final int conversation_rewardexp=0x7f050082;
+ public static final int conversation_rewardgold=0x7f050083;
+ public static final int conversation_title=0x7f050081;
+ public static final int conversationlist_crossglen=0x7f050002;
+ public static final int conversationlist_debug=0x7f050000;
+ public static final int conversationlist_mikhail=0x7f050001;
+ public static final int dialog_close=0x7f050015;
+ public static final int dialog_confirmexit_message=0x7f050017;
+ public static final int dialog_confirmexit_title=0x7f050016;
+ public static final int dialog_groundloot_message=0x7f05004c;
+ public static final int dialog_groundloot_title=0x7f05004b;
+ public static final int dialog_loading_message=0x7f050014;
+ public static final int dialog_loot_foundgold=0x7f05004a;
+ public static final int dialog_loot_pickall=0x7f050049;
+ public static final int dialog_monsterencounter_info=0x7f05001d;
+ public static final int dialog_monsterencounter_message=0x7f05001c;
+ public static final int dialog_monsterencounter_title=0x7f05001b;
+ public static final int dialog_monsterloot_gainedexp=0x7f05004f;
+ public static final int dialog_monsterloot_message=0x7f05004e;
+ public static final int dialog_monsterloot_title=0x7f05004d;
+ public static final int dialog_newversion_message=0x7f05009f;
+ public static final int dialog_newversion_title=0x7f05009e;
+ public static final int dialog_paused_message=0x7f050019;
+ public static final int dialog_paused_resume=0x7f05001a;
+ public static final int dialog_paused_title=0x7f050018;
+ public static final int dialog_rest_confirm_message=0x7f050096;
+ public static final int dialog_rest_message=0x7f050097;
+ public static final int dialog_rest_title=0x7f050095;
+ public static final int exit=0x7f050011;
+ public static final int exit_to_menu=0x7f050012;
+ public static final int heroinfo_actionpoints=0x7f05002d;
+ public static final int heroinfo_char=0x7f050022;
+ public static final int heroinfo_gold=0x7f05002c;
+ public static final int heroinfo_inv=0x7f050023;
+ public static final int heroinfo_inventory=0x7f05002b;
+ public static final int heroinfo_level=0x7f050028;
+ public static final int heroinfo_levelup=0x7f050027;
+ public static final int heroinfo_skill=0x7f050025;
+ public static final int heroinfo_spell=0x7f050026;
+ public static final int heroinfo_totalexperience=0x7f050029;
+ public static final int heroinfo_wear=0x7f050024;
+ public static final int heroinfo_wornequipment=0x7f05002a;
+ public static final int inventory_drop=0x7f050045;
+ public static final int inventory_equip=0x7f050042;
+ public static final int inventory_info=0x7f050041;
+ public static final int inventory_item_dropped=0x7f050047;
+ public static final int inventory_item_equipped=0x7f050048;
+ public static final int inventory_item_used=0x7f050046;
+ public static final int inventory_unequip=0x7f050043;
+ public static final int inventory_use=0x7f050044;
+ public static final int itemcategory_money=0x7f050070;
+ public static final int itemcategory_other=0x7f05007a;
+ public static final int itemcategory_potion=0x7f050079;
+ public static final int itemcategory_shield=0x7f050072;
+ public static final int itemcategory_weapon=0x7f050071;
+ public static final int itemcategory_wearable_body=0x7f050074;
+ public static final int itemcategory_wearable_feet=0x7f050076;
+ public static final int itemcategory_wearable_hand=0x7f050075;
+ public static final int itemcategory_wearable_head=0x7f050073;
+ public static final int itemcategory_wearable_neck=0x7f050077;
+ public static final int itemcategory_wearable_ring=0x7f050078;
+ public static final int iteminfo_action_equip=0x7f05006a;
+ public static final int iteminfo_action_equip_ap=0x7f05006d;
+ public static final int iteminfo_action_unequip=0x7f05006b;
+ public static final int iteminfo_action_unequip_ap=0x7f05006e;
+ public static final int iteminfo_action_use=0x7f050069;
+ public static final int iteminfo_action_use_ap=0x7f05006c;
+ public static final int iteminfo_category=0x7f050068;
+ public static final int iteminfo_effect_heal=0x7f05006f;
+ public static final int itemlist_animal=0x7f050009;
+ public static final int itemlist_armour=0x7f050007;
+ public static final int itemlist_debug=0x7f050004;
+ public static final int itemlist_food=0x7f050008;
+ public static final int itemlist_junk=0x7f05000a;
+ public static final int itemlist_money=0x7f050003;
+ public static final int itemlist_quest=0x7f05000b;
+ public static final int itemlist_rings=0x7f050006;
+ public static final int itemlist_weapons=0x7f050005;
+ public static final int key_required=0x7f050067;
+ public static final int levelup_add_attackchance=0x7f05008f;
+ public static final int levelup_add_attackchance_description=0x7f050090;
+ public static final int levelup_add_attackdamage=0x7f050091;
+ public static final int levelup_add_attackdamage_description=0x7f050092;
+ public static final int levelup_add_blockchance=0x7f050093;
+ public static final int levelup_add_blockchance_description=0x7f050094;
+ public static final int levelup_add_health=0x7f05008d;
+ public static final int levelup_add_health_description=0x7f05008e;
+ public static final int levelup_buttontext=0x7f05008c;
+ public static final int levelup_description=0x7f05008b;
+ public static final int levelup_title=0x7f05008a;
+ public static final int menu_pause=0x7f050013;
+ public static final int monster_difficulty_easy=0x7f050051;
+ public static final int monster_difficulty_hard=0x7f050053;
+ public static final int monster_difficulty_normal=0x7f050052;
+ public static final int monster_difficulty_veryeasy=0x7f050050;
+ public static final int monster_difficulty_veryhard=0x7f050054;
+ public static final int monsterlist_crossglen_animals=0x7f05000e;
+ public static final int monsterlist_crossglen_npcs=0x7f05000f;
+ public static final int monsterlist_debug=0x7f05000c;
+ public static final int monsterlist_misc=0x7f05000d;
+ public static final int shop_buy=0x7f050084;
+ public static final int shop_buyitem=0x7f050087;
+ public static final int shop_infoitem=0x7f050086;
+ public static final int shop_sell=0x7f050085;
+ public static final int shop_sellitem=0x7f050088;
+ public static final int shop_yourgold=0x7f050089;
+ public static final int startscreen_about=0x7f05007e;
+ public static final int startscreen_continue=0x7f05007b;
+ public static final int startscreen_currenthero=0x7f05007f;
+ public static final int startscreen_enterheroname=0x7f050080;
+ public static final int startscreen_newgame=0x7f05007c;
+ public static final int startscreen_newgame_confirm=0x7f05007d;
+ public static final int status_ap=0x7f050020;
+ public static final int status_exp=0x7f050021;
+ public static final int status_hp=0x7f05001e;
+ public static final int status_mp=0x7f05001f;
+ public static final int traitsinfo_attack_chance=0x7f050061;
+ public static final int traitsinfo_attack_cost=0x7f050060;
+ public static final int traitsinfo_attack_damage=0x7f050062;
+ public static final int traitsinfo_criticalhit_chance=0x7f050063;
+ public static final int traitsinfo_criticalhit_multiplier=0x7f050064;
+ public static final int traitsinfo_defense_chance=0x7f050065;
+ public static final int traitsinfo_defense_damageresist=0x7f050066;
+ }
+ public static final class style {
+ public static final int Theme_NoBackground=0x7f070000;
+ }
+ public static final class xml {
+ public static final int crossglen=0x7f040000;
+ public static final int crossglen_cave=0x7f040001;
+ public static final int crossglen_farmhouse=0x7f040002;
+ public static final int crossglen_farmhouse_basement=0x7f040003;
+ public static final int crossglen_hall=0x7f040004;
+ public static final int crossglen_smith=0x7f040005;
+ public static final int debugmap=0x7f040006;
+ public static final int dungeon=0x7f040007;
+ public static final int home=0x7f040008;
+ public static final int startmap=0x7f040009;
+ public static final int template=0x7f04000a;
+ public static final int wilderness=0x7f04000b;
+ }
+}
diff --git a/AndorsTrail/res/drawable-hdpi/icon.png b/AndorsTrail/res/drawable-hdpi/icon.png
new file mode 100644
index 000000000..604eb2ed6
Binary files /dev/null and b/AndorsTrail/res/drawable-hdpi/icon.png differ
diff --git a/AndorsTrail/res/drawable-ldpi/icon.png b/AndorsTrail/res/drawable-ldpi/icon.png
new file mode 100644
index 000000000..4fcdc2e00
Binary files /dev/null and b/AndorsTrail/res/drawable-ldpi/icon.png differ
diff --git a/AndorsTrail/res/drawable-mdpi/icon.png b/AndorsTrail/res/drawable-mdpi/icon.png
new file mode 100644
index 000000000..e6305c409
Binary files /dev/null and b/AndorsTrail/res/drawable-mdpi/icon.png differ
diff --git a/AndorsTrail/res/drawable/andors_trail_logo.png b/AndorsTrail/res/drawable/andors_trail_logo.png
new file mode 100644
index 000000000..3ef9cec41
Binary files /dev/null and b/AndorsTrail/res/drawable/andors_trail_logo.png differ
diff --git a/AndorsTrail/res/drawable/char_hero.png b/AndorsTrail/res/drawable/char_hero.png
new file mode 100644
index 000000000..54e22e510
Binary files /dev/null and b/AndorsTrail/res/drawable/char_hero.png differ
diff --git a/AndorsTrail/res/drawable/effect_blood3.png b/AndorsTrail/res/drawable/effect_blood3.png
new file mode 100644
index 000000000..ee7206b12
Binary files /dev/null and b/AndorsTrail/res/drawable/effect_blood3.png differ
diff --git a/AndorsTrail/res/drawable/equip_body.png b/AndorsTrail/res/drawable/equip_body.png
new file mode 100644
index 000000000..1bd1e52b5
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_body.png differ
diff --git a/AndorsTrail/res/drawable/equip_feet.png b/AndorsTrail/res/drawable/equip_feet.png
new file mode 100644
index 000000000..603c70612
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_feet.png differ
diff --git a/AndorsTrail/res/drawable/equip_hand.png b/AndorsTrail/res/drawable/equip_hand.png
new file mode 100644
index 000000000..a1a2061be
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_hand.png differ
diff --git a/AndorsTrail/res/drawable/equip_head.png b/AndorsTrail/res/drawable/equip_head.png
new file mode 100644
index 000000000..fb0b3fa32
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_head.png differ
diff --git a/AndorsTrail/res/drawable/equip_neck.png b/AndorsTrail/res/drawable/equip_neck.png
new file mode 100644
index 000000000..f8143e205
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_neck.png differ
diff --git a/AndorsTrail/res/drawable/equip_ring.png b/AndorsTrail/res/drawable/equip_ring.png
new file mode 100644
index 000000000..65c03d2a7
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_ring.png differ
diff --git a/AndorsTrail/res/drawable/equip_shield.png b/AndorsTrail/res/drawable/equip_shield.png
new file mode 100644
index 000000000..6cfdf12cb
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_shield.png differ
diff --git a/AndorsTrail/res/drawable/equip_square.png b/AndorsTrail/res/drawable/equip_square.png
new file mode 100644
index 000000000..f8b5c9bfc
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_square.png differ
diff --git a/AndorsTrail/res/drawable/equip_weapon.png b/AndorsTrail/res/drawable/equip_weapon.png
new file mode 100644
index 000000000..fa88fe380
Binary files /dev/null and b/AndorsTrail/res/drawable/equip_weapon.png differ
diff --git a/AndorsTrail/res/drawable/icon_coin.png b/AndorsTrail/res/drawable/icon_coin.png
new file mode 100644
index 000000000..779dcdf17
Binary files /dev/null and b/AndorsTrail/res/drawable/icon_coin.png differ
diff --git a/AndorsTrail/res/drawable/items_tiles.png b/AndorsTrail/res/drawable/items_tiles.png
new file mode 100644
index 000000000..45b3bedcb
Binary files /dev/null and b/AndorsTrail/res/drawable/items_tiles.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_1.png b/AndorsTrail/res/drawable/map_tiles_1_1.png
new file mode 100644
index 000000000..e30280c1d
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_1.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_2.png b/AndorsTrail/res/drawable/map_tiles_1_2.png
new file mode 100644
index 000000000..27c597486
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_2.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_3.png b/AndorsTrail/res/drawable/map_tiles_1_3.png
new file mode 100644
index 000000000..17be6976c
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_3.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_4.png b/AndorsTrail/res/drawable/map_tiles_1_4.png
new file mode 100644
index 000000000..f3aac68af
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_4.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_5.png b/AndorsTrail/res/drawable/map_tiles_1_5.png
new file mode 100644
index 000000000..b6bed60ee
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_5.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_6.png b/AndorsTrail/res/drawable/map_tiles_1_6.png
new file mode 100644
index 000000000..01b6af67f
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_6.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_7.png b/AndorsTrail/res/drawable/map_tiles_1_7.png
new file mode 100644
index 000000000..59dcdc559
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_7.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_1_8.png b/AndorsTrail/res/drawable/map_tiles_1_8.png
new file mode 100644
index 000000000..4344ef7a8
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_1_8.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_1.png b/AndorsTrail/res/drawable/map_tiles_2_1.png
new file mode 100644
index 000000000..2b574dae2
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_1.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_2.png b/AndorsTrail/res/drawable/map_tiles_2_2.png
new file mode 100644
index 000000000..d108fee4c
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_2.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_3.png b/AndorsTrail/res/drawable/map_tiles_2_3.png
new file mode 100644
index 000000000..a1762ebf4
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_3.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_4.png b/AndorsTrail/res/drawable/map_tiles_2_4.png
new file mode 100644
index 000000000..8cbf33604
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_4.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_5.png b/AndorsTrail/res/drawable/map_tiles_2_5.png
new file mode 100644
index 000000000..cea20ecf5
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_5.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_6.png b/AndorsTrail/res/drawable/map_tiles_2_6.png
new file mode 100644
index 000000000..b7362ee34
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_6.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_7.png b/AndorsTrail/res/drawable/map_tiles_2_7.png
new file mode 100644
index 000000000..e1cad9740
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_7.png differ
diff --git a/AndorsTrail/res/drawable/map_tiles_2_8.png b/AndorsTrail/res/drawable/map_tiles_2_8.png
new file mode 100644
index 000000000..cc2f9413c
Binary files /dev/null and b/AndorsTrail/res/drawable/map_tiles_2_8.png differ
diff --git a/AndorsTrail/res/drawable/monsters_armor1.png b/AndorsTrail/res/drawable/monsters_armor1.png
new file mode 100644
index 000000000..7ba8050e1
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_armor1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_cyclops.png b/AndorsTrail/res/drawable/monsters_cyclops.png
new file mode 100644
index 000000000..857f66a90
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_cyclops.png differ
diff --git a/AndorsTrail/res/drawable/monsters_demon1.png b/AndorsTrail/res/drawable/monsters_demon1.png
new file mode 100644
index 000000000..8b34d94b5
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_demon1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_demon2.png b/AndorsTrail/res/drawable/monsters_demon2.png
new file mode 100644
index 000000000..dea058100
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_demon2.png differ
diff --git a/AndorsTrail/res/drawable/monsters_dogs.png b/AndorsTrail/res/drawable/monsters_dogs.png
new file mode 100644
index 000000000..977e71320
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_dogs.png differ
diff --git a/AndorsTrail/res/drawable/monsters_dragon1.png b/AndorsTrail/res/drawable/monsters_dragon1.png
new file mode 100644
index 000000000..f33e6dfa6
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_dragon1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_dragons.png b/AndorsTrail/res/drawable/monsters_dragons.png
new file mode 100644
index 000000000..e4a6f3855
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_dragons.png differ
diff --git a/AndorsTrail/res/drawable/monsters_eye1.png b/AndorsTrail/res/drawable/monsters_eye1.png
new file mode 100644
index 000000000..e69cfeb85
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_eye1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_eye2.png b/AndorsTrail/res/drawable/monsters_eye2.png
new file mode 100644
index 000000000..c7379fb5c
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_eye2.png differ
diff --git a/AndorsTrail/res/drawable/monsters_eye3.png b/AndorsTrail/res/drawable/monsters_eye3.png
new file mode 100644
index 000000000..5fe95c689
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_eye3.png differ
diff --git a/AndorsTrail/res/drawable/monsters_eye4.png b/AndorsTrail/res/drawable/monsters_eye4.png
new file mode 100644
index 000000000..6b2da51d0
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_eye4.png differ
diff --git a/AndorsTrail/res/drawable/monsters_ghost1.png b/AndorsTrail/res/drawable/monsters_ghost1.png
new file mode 100644
index 000000000..10696ad67
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_ghost1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_ghost2.png b/AndorsTrail/res/drawable/monsters_ghost2.png
new file mode 100644
index 000000000..4a73dac53
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_ghost2.png differ
diff --git a/AndorsTrail/res/drawable/monsters_hydra1.png b/AndorsTrail/res/drawable/monsters_hydra1.png
new file mode 100644
index 000000000..52f867de1
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_hydra1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_insects.png b/AndorsTrail/res/drawable/monsters_insects.png
new file mode 100644
index 000000000..b6916f46f
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_insects.png differ
diff --git a/AndorsTrail/res/drawable/monsters_liches.png b/AndorsTrail/res/drawable/monsters_liches.png
new file mode 100644
index 000000000..b50198505
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_liches.png differ
diff --git a/AndorsTrail/res/drawable/monsters_mage.png b/AndorsTrail/res/drawable/monsters_mage.png
new file mode 100644
index 000000000..835a7d7cf
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_mage.png differ
diff --git a/AndorsTrail/res/drawable/monsters_mage2.png b/AndorsTrail/res/drawable/monsters_mage2.png
new file mode 100644
index 000000000..00166f7b3
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_mage2.png differ
diff --git a/AndorsTrail/res/drawable/monsters_mage3.png b/AndorsTrail/res/drawable/monsters_mage3.png
new file mode 100644
index 000000000..7c0ede970
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_mage3.png differ
diff --git a/AndorsTrail/res/drawable/monsters_mage4.png b/AndorsTrail/res/drawable/monsters_mage4.png
new file mode 100644
index 000000000..25d8d1a49
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_mage4.png differ
diff --git a/AndorsTrail/res/drawable/monsters_man1.png b/AndorsTrail/res/drawable/monsters_man1.png
new file mode 100644
index 000000000..f748d4156
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_man1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_men.png b/AndorsTrail/res/drawable/monsters_men.png
new file mode 100644
index 000000000..ac2b43b35
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_men.png differ
diff --git a/AndorsTrail/res/drawable/monsters_misc.png b/AndorsTrail/res/drawable/monsters_misc.png
new file mode 100644
index 000000000..e2e8ecf4a
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_misc.png differ
diff --git a/AndorsTrail/res/drawable/monsters_rats.png b/AndorsTrail/res/drawable/monsters_rats.png
new file mode 100644
index 000000000..47df0720e
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_rats.png differ
diff --git a/AndorsTrail/res/drawable/monsters_rogue1.png b/AndorsTrail/res/drawable/monsters_rogue1.png
new file mode 100644
index 000000000..a48699b49
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_rogue1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_skeleton1.png b/AndorsTrail/res/drawable/monsters_skeleton1.png
new file mode 100644
index 000000000..756d7b4fb
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_skeleton1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_skeleton2.png b/AndorsTrail/res/drawable/monsters_skeleton2.png
new file mode 100644
index 000000000..4d3b5db87
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_skeleton2.png differ
diff --git a/AndorsTrail/res/drawable/monsters_snakes.png b/AndorsTrail/res/drawable/monsters_snakes.png
new file mode 100644
index 000000000..23f5ebd5a
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_snakes.png differ
diff --git a/AndorsTrail/res/drawable/monsters_warrior1.png b/AndorsTrail/res/drawable/monsters_warrior1.png
new file mode 100644
index 000000000..9d0bd5d1a
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_warrior1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_wraiths.png b/AndorsTrail/res/drawable/monsters_wraiths.png
new file mode 100644
index 000000000..df023ab4c
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_wraiths.png differ
diff --git a/AndorsTrail/res/drawable/monsters_zombie1.png b/AndorsTrail/res/drawable/monsters_zombie1.png
new file mode 100644
index 000000000..67b6b52d3
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_zombie1.png differ
diff --git a/AndorsTrail/res/drawable/monsters_zombie2.png b/AndorsTrail/res/drawable/monsters_zombie2.png
new file mode 100644
index 000000000..f3e7f01f4
Binary files /dev/null and b/AndorsTrail/res/drawable/monsters_zombie2.png differ
diff --git a/AndorsTrail/res/drawable/ui_bar_background.9.png b/AndorsTrail/res/drawable/ui_bar_background.9.png
new file mode 100644
index 000000000..3a6ca9691
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_bar_background.9.png differ
diff --git a/AndorsTrail/res/drawable/ui_blue_foreground.9.png b/AndorsTrail/res/drawable/ui_blue_foreground.9.png
new file mode 100644
index 000000000..821b3060e
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_blue_foreground.9.png differ
diff --git a/AndorsTrail/res/drawable/ui_boxshape.xml b/AndorsTrail/res/drawable/ui_boxshape.xml
new file mode 100644
index 000000000..212293e9d
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_boxshape.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_debug_background.xml b/AndorsTrail/res/drawable/ui_debug_background.xml
new file mode 100644
index 000000000..ff1cfe25c
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_debug_background.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_gradientshape.xml b/AndorsTrail/res/drawable/ui_gradientshape.xml
new file mode 100644
index 000000000..024609a2e
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_gradientshape.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_green_foreground.9.png b/AndorsTrail/res/drawable/ui_green_foreground.9.png
new file mode 100644
index 000000000..475a92dd9
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_green_foreground.9.png differ
diff --git a/AndorsTrail/res/drawable/ui_progress_ap.xml b/AndorsTrail/res/drawable/ui_progress_ap.xml
new file mode 100644
index 000000000..435b0278f
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_progress_ap.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_progress_exp.xml b/AndorsTrail/res/drawable/ui_progress_exp.xml
new file mode 100644
index 000000000..a521618f0
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_progress_exp.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_progress_health.xml b/AndorsTrail/res/drawable/ui_progress_health.xml
new file mode 100644
index 000000000..e55b93ada
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_progress_health.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_purple_foreground.9.png b/AndorsTrail/res/drawable/ui_purple_foreground.9.png
new file mode 100644
index 000000000..350a2f015
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_purple_foreground.9.png differ
diff --git a/AndorsTrail/res/drawable/ui_red_foreground.9.png b/AndorsTrail/res/drawable/ui_red_foreground.9.png
new file mode 100644
index 000000000..382058930
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_red_foreground.9.png differ
diff --git a/AndorsTrail/res/drawable/ui_startbackground.xml b/AndorsTrail/res/drawable/ui_startbackground.xml
new file mode 100644
index 000000000..2d8e853fc
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_startbackground.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_statustext.xml b/AndorsTrail/res/drawable/ui_statustext.xml
new file mode 100644
index 000000000..ecfe7a638
--- /dev/null
+++ b/AndorsTrail/res/drawable/ui_statustext.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/drawable/ui_yellow_foreground.9.png b/AndorsTrail/res/drawable/ui_yellow_foreground.9.png
new file mode 100644
index 000000000..4cc7d6550
Binary files /dev/null and b/AndorsTrail/res/drawable/ui_yellow_foreground.9.png differ
diff --git a/AndorsTrail/res/layout/about.xml b/AndorsTrail/res/layout/about.xml
new file mode 100644
index 000000000..8f00cc927
--- /dev/null
+++ b/AndorsTrail/res/layout/about.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/combatview.xml b/AndorsTrail/res/layout/combatview.xml
new file mode 100644
index 000000000..a143ad27b
--- /dev/null
+++ b/AndorsTrail/res/layout/combatview.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/conversation.xml b/AndorsTrail/res/layout/conversation.xml
new file mode 100644
index 000000000..7c0d88265
--- /dev/null
+++ b/AndorsTrail/res/layout/conversation.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/heroinfo.xml b/AndorsTrail/res/layout/heroinfo.xml
new file mode 100644
index 000000000..dcfe5f1a1
--- /dev/null
+++ b/AndorsTrail/res/layout/heroinfo.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/heroinfo_equipped.xml b/AndorsTrail/res/layout/heroinfo_equipped.xml
new file mode 100644
index 000000000..e5e4c74f5
--- /dev/null
+++ b/AndorsTrail/res/layout/heroinfo_equipped.xml
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/heroinfo_inventory.xml b/AndorsTrail/res/layout/heroinfo_inventory.xml
new file mode 100644
index 000000000..277a76c7a
--- /dev/null
+++ b/AndorsTrail/res/layout/heroinfo_inventory.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/heroinfo_stats.xml b/AndorsTrail/res/layout/heroinfo_stats.xml
new file mode 100644
index 000000000..4f812b85e
--- /dev/null
+++ b/AndorsTrail/res/layout/heroinfo_stats.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/heroinfo_statsicons.xml b/AndorsTrail/res/layout/heroinfo_statsicons.xml
new file mode 100644
index 000000000..54f4aa53b
--- /dev/null
+++ b/AndorsTrail/res/layout/heroinfo_statsicons.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/inventoryitemview.xml b/AndorsTrail/res/layout/inventoryitemview.xml
new file mode 100644
index 000000000..932a1815c
--- /dev/null
+++ b/AndorsTrail/res/layout/inventoryitemview.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/iteminfo.xml b/AndorsTrail/res/layout/iteminfo.xml
new file mode 100644
index 000000000..d5dc67f61
--- /dev/null
+++ b/AndorsTrail/res/layout/iteminfo.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/levelup.xml b/AndorsTrail/res/layout/levelup.xml
new file mode 100644
index 000000000..107126774
--- /dev/null
+++ b/AndorsTrail/res/layout/levelup.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/main.xml b/AndorsTrail/res/layout/main.xml
new file mode 100644
index 000000000..696f016f7
--- /dev/null
+++ b/AndorsTrail/res/layout/main.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/monsterencounter.xml b/AndorsTrail/res/layout/monsterencounter.xml
new file mode 100644
index 000000000..041996cfa
--- /dev/null
+++ b/AndorsTrail/res/layout/monsterencounter.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/monsterinfo.xml b/AndorsTrail/res/layout/monsterinfo.xml
new file mode 100644
index 000000000..5106716e5
--- /dev/null
+++ b/AndorsTrail/res/layout/monsterinfo.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/rangebar.xml b/AndorsTrail/res/layout/rangebar.xml
new file mode 100644
index 000000000..a513e027c
--- /dev/null
+++ b/AndorsTrail/res/layout/rangebar.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/shop.xml b/AndorsTrail/res/layout/shop.xml
new file mode 100644
index 000000000..db7c3f1a2
--- /dev/null
+++ b/AndorsTrail/res/layout/shop.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/shopitemview.xml b/AndorsTrail/res/layout/shopitemview.xml
new file mode 100644
index 000000000..762375747
--- /dev/null
+++ b/AndorsTrail/res/layout/shopitemview.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/startscreen.xml b/AndorsTrail/res/layout/startscreen.xml
new file mode 100644
index 000000000..1e731fb80
--- /dev/null
+++ b/AndorsTrail/res/layout/startscreen.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/layout/statusview.xml b/AndorsTrail/res/layout/statusview.xml
new file mode 100644
index 000000000..1811a69f2
--- /dev/null
+++ b/AndorsTrail/res/layout/statusview.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/layout/traitsinfoview.xml b/AndorsTrail/res/layout/traitsinfoview.xml
new file mode 100644
index 000000000..9a764cd5f
--- /dev/null
+++ b/AndorsTrail/res/layout/traitsinfoview.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndorsTrail/res/menu/inventoryitem.xml b/AndorsTrail/res/menu/inventoryitem.xml
new file mode 100644
index 000000000..e7ec8a7a6
--- /dev/null
+++ b/AndorsTrail/res/menu/inventoryitem.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/AndorsTrail/res/values/conversationlist.xml b/AndorsTrail/res/values/conversationlist.xml
new file mode 100644
index 000000000..939eadfe8
--- /dev/null
+++ b/AndorsTrail/res/values/conversationlist.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+[ID|Text|EnableKey|RwdExp|RwdGold|Rep_text0|Rep_id0|Rep_reqKey0|Rep_itemTag0|Rep_itemQty0|Rep_text1|Rep_id1|Rep_reqKey1|Rep_itemTag1|Rep_itemQty1|Rep_text2|Rep_id2|Rep_reqKey2|Rep_itemTag2|Rep_itemQty2|];
+{debug||||||debug2|dialog2||||debug1|||||||||};
+{debug1|Welcome adventurer!|dialog2|||Trade|S||||Bye|X||||Debug|debug3||||};
+{debug2|Welcome back!||||Trade|S||||Bye|X||||Debug|debug3||||};
+{debug3|Debug 3\nTest||5|5|Iron sword*2|debug||sword1|2|Iron sword*1|debug||sword1|1|Iron longsword*1|debug||sword2|1|};
+
+{test1|Hello, test message||||Bye|X||||Shop|S||||Keytest|testmain||||};
+{testmain|Keytest main||||Back|test1||||Add key|test2||||I have it!|test3|testkey|||};
+{test2|Key added!|testkey|||Ok|testmain||||||||||||||};
+{test3|This is only reachable if you have testkey||||Back|testmain||||||||||||||};
+
+
+
+
+
+[ID|Text|EnableKey|RwdExp|RwdGold|Rep_text0|Rep_id0|Rep_reqKey0|Rep_itemTag0|Rep_itemQty0|Rep_text1|Rep_id1|Rep_reqKey1|Rep_itemTag1|Rep_itemQty1|Rep_text2|Rep_id2|Rep_reqKey2|Rep_itemTag2|Rep_itemQty2|];
+{mikhail_start_select||||||mikhail_visited|mikhail_visited||||mikhail_gamestart|||||||||};
+{mikhail_gamestart|Oh good, you are awake.||||Next|mikhail_visited||||||||||||||};
+{mikhail_visited|I can\'t seem to find your brother anywhere. He hasn\'t been back since he left yesterday.|mikhail_visited|||Next|mikhail3||||||||||||||};
+{mikhail3|Nevermind, he will probably be back soon.||||Next|mikhail_default||||||||||||||};
+{mikhail_default|Anything else I can help you with?||||Bread|mikhail_bread_select||||Rats|mikhail_rats_select||||Bye|X||||};
+
+{mikhail_bread_select||||||mikhail_bread_complete2|qmikhail_bread_complete||||mikhail_bread_continue|qmikhail_bread||||mikhail_bread_start||||};
+{mikhail_bread_start|Oh, I almost forgot. If you have time, please stop by Mara at the town hall and buy me some more bread.|qmikhail_bread|||I already have some bread|mikhail_bread_complete||bread|1|Sure|mikhail_default|||||||||};
+{mikhail_bread_continue|Did you get the bread from Mara at the town hall that i asked for?||||Yes, i got it|mikhail_bread_complete||bread|1|No, not yet|mikhail_default|||||||||};
+{mikhail_bread_complete|Thanks a lot, now i can get my breakfast. Here, take these coins for your help.|qmikhail_bread_complete||20|Back|mikhail_default||||Bye|X|||||||||};
+{mikhail_bread_complete2|Thanks for the bread earlier.||||You\'re welcome|mikhail_default||||Bye|X|||||||||};
+
+{mikhail_rats_select||||||mikhail_rats_complete2|qmikhail_rats_complete||||mikhail_rats_continue|qmikhail_rats||||mikhail_rats_start||||};
+{mikhail_rats_start|I saw some rats out back in our garden earlier. Could you please go check our garden if they are still there? Please kill any rats that you see.|qmikhail_rats|||I already killed them|mikhail_rats_complete||tail_trainingrat|2|Sure|mikhail_default|||||||||};
+{mikhail_rats_continue|Did you kill those rats in our garden?||||Yes|mikhail_rats_complete||tail_trainingrat|2|No, not yet|mikhail_default|||||||||};
+{mikhail_rats_complete|Thanks a lot for your help.|qmikhail_rats_complete|20||Back|mikhail_default||||Bye|X|||||||||};
+{mikhail_rats_complete2|Thanks for your help with the rats earlier.||||You\'re welcome|mikhail_default||||Bye|X|||||||||};
+
+
+
+
+[ID|Text|EnableKey|RwdExp|RwdGold|Rep_text0|Rep_id0|Rep_reqKey0|Rep_itemTag0|Rep_itemQty0|Rep_text1|Rep_id1|Rep_reqKey1|Rep_itemTag1|Rep_itemQty1|Rep_text2|Rep_id2|Rep_reqKey2|Rep_itemTag2|Rep_itemQty2|];
+{leta1|Hey, this is my house, get out of here!||||But I was just...|leta2||||Bye|X|||||||||};
+{leta2|Beat it kid, get out of my house!||||Bye|X||||||||||||||};
+{audir1|Welcome to my shop!\n\nPlease browse my selection of fine wares.||||Shop|S||||Bye|X|||||||||};
+{arambold1|Oh my, will I ever get any sleep with those drunkards singing like that?\n\nSomeone should do something about them.||||Can I rest here?|arambold2||||Trade|S||||Bye|X||||};
+{arambold2|Sure kid, you may rest here.\n\nPick any bed you want.||||Thanks, bye|X||||||||||||||};
+{tharal1|Embrace the one true god||||Trade|S||||Bye|X|||||||||};
+{drunk1|Drink drink drink, drink some more.\nDrink drink drink \'til you\'re on the floor.\n\nHey kid, wanna join us in our drinking game?||||No thanks|X||||||||||||||};
+{mara1|Never mind those drunken fellas, they\'re always causing trouble.\n\nWant something to eat?||||Trade|S||||Bye|X|||||||||};
+{gruil1|Psst, hey.\n\nWanna trade?||||Trade|S||||Bye|X|||||||||};
+{leonid1|Begone, peasant.||||Bye|X||||||||||||||};
+{farm1|Please do not disturb me, i have work to do.||||Bye|X||||||||||||||};
+{farm2|What?! Can\'t you see i\'m busy? Go bother someone else.||||Bye|X||||||||||||||};
+
+
diff --git a/AndorsTrail/res/values/dimen.xml b/AndorsTrail/res/values/dimen.xml
new file mode 100644
index 000000000..1383974b4
--- /dev/null
+++ b/AndorsTrail/res/values/dimen.xml
@@ -0,0 +1,19 @@
+
+
+ 10sp
+ 35sp
+ 20sp
+
+ 12sp
+
+ 10sp
+
+ 10sp
+ 10sp
+
+ 5dp
+ 100dp
+
+ 10dp
+
+
diff --git a/AndorsTrail/res/values/itemlist.xml b/AndorsTrail/res/values/itemlist.xml
new file mode 100644
index 000000000..3b067b921
--- /dev/null
+++ b/AndorsTrail/res/values/itemlist.xml
@@ -0,0 +1,132 @@
+
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{gold|items_tiles:220|Gold coins|30|1|||||||||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{|items_tiles:90|Black heart dagger|0|6||2|100|30|3|5-10|||};
+{|items_tiles:270|Black heart ring|7|3|||50|||10|||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{club1|items_tiles:126|Wooden club|0|7||5|10|||0-1|||};
+{club3|items_tiles:128|Iron club|0|253||5|5|||2-7|||};
+{ironsword0|items_tiles:70|Iron sword|0|12||5|10|||0-1|||};
+{hammer0|items_tiles:129|Iron hammer|0|12||5|10|||0-1|||};
+{dagger0|items_tiles:84|Iron dagger|0|12||5|10|||0-1|||};
+{dagger1|items_tiles:84|Sharp iron dagger|0|53||3|20|||1-2|||};
+{dagger2|items_tiles:84|Superior iron dagger|0|70||3|20|||2-3|||};
+{shortsword1|items_tiles:85|Iron shortsword|0|78||4|15|||1-2|||};
+{ironsword1|items_tiles:70|Iron sword|0|78||5|10|||1-3|||};
+{ironsword2|items_tiles:71|Iron longsword|0|121||5|10|||1-4|||};
+{broadsword1|items_tiles:75|Iron broadsword|0|251||7|2|||1-10|||};
+{broadsword2|items_tiles:76|Steel broadsword|0|582||6|15|||3-10|||};
+{steelsword1|items_tiles:77|Steel sword|0|874||4|25|||3-8|||};
+{axe1|items_tiles:140|Woodcutter axe|0|24||5|5|||1-3|||};
+{axe2|items_tiles:140|Iron axe|0|312||6|5|||2-5|||};
+
+
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{ring_dmg1|items_tiles:266|Ring of damage +1|7|215||||||1|||};
+{ring_dmg2|items_tiles:267|Ring of damage +2|7|398||||||2|||};
+{ring_dmg5|items_tiles:268|Ring of damage +5|7|2014||||||5|||};
+{ring_dmg6|items_tiles:269|Ring of damage +6|7|3186||||||6|||};
+{ring_block1|items_tiles:266|Ring of block|7|1239|||||||10||};
+{ring_block2|items_tiles:266|Ring of block|7|3866|||||||15||};
+{ring_atkch1|items_tiles:266|Ring of surehit|7|215|||15||||||};
+
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{shirt1|items_tiles:182|Cloth shirt|3|16|||||||2||};
+{shirt2|items_tiles:182|Fine shirt|3|72|||||||5||};
+{armor1|items_tiles:183|Leather armour|3|464|||||||8||};
+{armor2|items_tiles:183|Superior leather armour|3|624|||||||9||};
+{armor3|items_tiles:184|Hard leather armour|3|2407|||||||13||};
+{armor4|items_tiles:184|Superior hard leather armour|3|3866|||||||15||};
+{hat1|items_tiles:189|Green hat|2|13|||||||1||};
+{hat2|items_tiles:189|Fine green hat|2|25|||||||2||};
+{hat3|items_tiles:192|Leather cap|2|72|||||||5||};
+{hat4|items_tiles:192|Fine leather cap|2|146|||||||6||};
+{gloves1|items_tiles:203|Leather gloves|4|23|||||||3||};
+{gloves2|items_tiles:203|Fine leather gloves|4|38|||||||4||};
+{gloves3|items_tiles:204|Snakeskin gloves|4|72|||||||5||};
+{gloves4|items_tiles:204|Fine snakeskin gloves|4|146|||||||6||};
+{shield1|items_tiles:168|Wooden buckler|1|72|||-5||||5||};
+{shield3|items_tiles:169|Reinforced wooden buckler|1|226|||-5||||7||};
+{shield4|items_tiles:170|Wooden shield|1|464|||-5||||8||};
+{shield5|items_tiles:170|Superior wooden shield|1|624|||-4||||9||};
+{boots1|items_tiles:196|Leather boots|5|23|||||||3||};
+{boots2|items_tiles:196|Superior leather boots|5|38|||||||4||};
+{boots3|items_tiles:197|Snakeskin boots|5|146|||||||6||};
+{boots5|items_tiles:198|Reinforced boots|5|226|||||||7||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{health_minor|items_tiles:35|Minor potion of health|20|10|5||||||||};
+{health|items_tiles:49|Regular potion of health|20|40|10||||||||};
+{health_major|items_tiles:28|Major potion of health|20|210|40||||||||};
+{apple_green|items_tiles:2|Green apple|21|9|4||||||||};
+{apple_red|items_tiles:3|Red apple|21|15|6||||||||};
+{meat|items_tiles:25|Meat|21|45|12||||||||};
+{meat_cooked|items_tiles:27|Cooked meat|21|105|21||||||||};
+{|items_tiles:8|Strawberry|21|1|1||||||||};
+{|items_tiles:15|Carrot|21|9|4||||||||};
+{|items_tiles:21|Bread|21|10|5||||||||};
+{|items_tiles:19|Mushroom|21|1|1||||||||};
+{|items_tiles:9|Pear|21|9|4||||||||};
+{|items_tiles:20|Eggs|21|8|3||||||||};
+{|items_tiles:14|Radish|21|5|2||||||||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{hair|items_tiles:258|Animal hair|31|1|||||||||};
+{|items_tiles:262|Insect wing|31|2|||||||||};
+{|items_tiles:254|Bone|31|1|||||||||};
+{|items_tiles:255|Eye|31|1|||||||||};
+{|items_tiles:256|Bat wing|31|1|||||||||};
+{|items_tiles:257|Claws|31|1|||||||||};
+{shell|items_tiles:264|Insect shell|31|1|||||||||};
+{|items_tiles:226|Feather|31|3|||||||||};
+{|items_tiles:225|Red feather|31|7|||||||||};
+{gland|items_tiles:340|Poison gland|31|15|||||||||};
+{rat_tail|items_tiles:103|Rat tail|31|1|||||||||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{clay|items_tiles:289|Lump of clay|31|1|||||||||};
+{rock|items_tiles:238|Small rock|31|1|||||||||};
+{vial_empty1|items_tiles:56|Small empty vial|31|1|||||||||};
+{vial_empty2|items_tiles:57|Empty vial|31|1|||||||||};
+{vial_empty3|items_tiles:59|Empty flask|31|2|||||||||};
+{vial_empty4|items_tiles:58|Empty potion|31|3|||||||||};
+{gem1|items_tiles:210|Glass gem|31|2|||||||||};
+{gem2|items_tiles:211|Ruby gem|31|6|||||||||};
+{gem3|items_tiles:212|Polished gem|31|8|||||||||};
+{gem4|items_tiles:213|Sharpened gem|31|13|||||||||};
+{gem5|items_tiles:215|Polished sparkling gem|31|15|||||||||};
+{gem6|items_tiles:214|Shimmering gem|31|26|||||||||};
+{gem7|items_tiles:216|Heartstone|31|40|||||||||};
+{gem8|items_tiles:330|Brilliant gem|31|68|||||||||};
+
+
+
+[Tag|Icon|Name|Category|Cost|HP|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|];
+{tail_caverat|items_tiles:103|Cave rat tail|31|0|||||||||};
+{tail_trainingrat|items_tiles:103|Small rat tail|31|0|||||||||};
+{rest|items_tiles:33|Potion of restoration|20|0|99||||||||};
+{ring_mikhail|items_tiles:266|Mikhail\'s ring|7|15|||10||||||};
+
+
diff --git a/AndorsTrail/res/values/monsterlist.xml b/AndorsTrail/res/values/monsterlist.xml
new file mode 100644
index 000000000..5c08e8838
--- /dev/null
+++ b/AndorsTrail/res/values/monsterlist.xml
@@ -0,0 +1,117 @@
+
+
+
+
+[Icon|Name|Tags|Size|Exp|HP_max|AP_max|AP_move|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|Drop|Phrase|];
+{monsters_man1:0|Traveller|Human|1x1|11|10|10|10|10|50|||1-2|||shop1|debug|};
+
+
+
+[Icon|Name|Tags|Size|Exp|HP_max|AP_max|AP_move|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|Drop|Phrase|];
+{monsters_armor1:0|Armoured guardian|Human|1x1|20|10|10|10|10|50|||1-2|90|1|list1||};
+{monsters_men:0|Madman|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:1|Siren|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:3|Knight|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:4|Monk|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:5|Hermit|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:6|Nun|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:7|Amazon|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_men:8|Thief|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_rogue1:0|Rogue|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_warrior1:0|Warrior|Human|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:4|Dwarf miner|Dwarf|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:5|Troll|Dwarf|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:6|Dwarf warrior|Dwarf|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:7|Dwarf knight|Dwarf|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dogs:0|Puppy dog|Animal|1x1|3|1|10|10|10|50|||0-1|||list1||};
+{monsters_dogs:1|Young dog|Animal|1x1|4|5|10|10|10|50|||0-1|||list1||};
+{monsters_dogs:2|Dog|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dogs:3|Fox|Animal|1x1|15|20|10|10|10|50|||1-5|||list1||};
+{monsters_dogs:4|Wolf|Animal|1x1|24|40|10|10|10|50|||1-7|||list1||};
+{monsters_dogs:5|Werewolf|Animal|1x1|32|60|10|10|10|100|10|2|3-15|||list1||};
+{monsters_dogs:6|Boar|Animal|1x1|25|30|10|10|10|60|||2-7|||list1||};
+{monsters_rats:0|Tiny rat|Animal|1x1|1|1|10|10|10|50|||1|||list1||};
+{monsters_rats:1|Rat|Animal|1x1|4|3|10|10|10|50|||0-3|||list1||};
+{monsters_rats:2|Rabid rat|Animal|1x1|10|10|10|10|10|50|||1-6|||list1||};
+{monsters_rats:3|Strong rat|Animal|1x1|15|20|10|10|5|50|||1-10|||list1||};
+{monsters_snakes:0|Young snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_snakes:1|Snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_snakes:2|Poison snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_snakes:3|Venomous snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_snakes:4|Large snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_snakes:5|Paralyzing snake|Animal|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_insects:0|Black ant|Insect|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_insects:1|Small wasp|Insect|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_insects:2|Yellow ant|Insect|1x1|11|10|10|10|10|100|||4|||list1||};
+{monsters_insects:3|Red ant|Insect|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_insects:4|Beetle|Insect|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_insects:5|Wasp|Insect|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:0|Dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:1|Ice dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:2|Young dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:3|Hardened dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:4|Hatchling dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragons:5|Acid dragon|Dragon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_dragon1:0|Ancient dragon|Dragon|4x3|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_ghost1:0|Ethereal wraith|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_ghost2:0|Ghost|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_wraiths:0|Wraith|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_wraiths:1|Wraith master|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_wraiths:2|Ancient wraith|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_zombie2:0|Rotting zombie|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_zombie1:0|Zombie|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_liches:0|Lich apprentice|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_liches:1|Lich|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_liches:2|Lich master|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_liches:3|Ancient lich|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_skeleton1:0|Skeleton warrior|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_skeleton2:0|Skeleton champion|Undead|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_demon1:0|Winged demon|Demon|2x2|11|10|10|10|10|50|||10-20|||list1||};
+{monsters_demon2:0|Demon|Demon|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_eye1:0|Eye servant|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_eye2:0|Gazer|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_eye3:0|Eye master|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_eye4:0|Beholder|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_hydra1:0|Hydra|Beast|2x2|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:0|Gecko|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:1|Young gargoyle|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:2|Gargoyle|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:8|Lusca|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:9|Lusca master|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_rats:4|Basilisk|Beast|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_cyclops:0|Cyclops|Beast|2x3|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_mage:0|Mage|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_mage2:0|Mage apprentice|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_mage3:0|Mage master|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_mage4:0|Sorcerer|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:10|Abomination|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+{monsters_misc:11|Starved abomination|Magic|1x1|11|10|10|10|10|50|||1-2|||list1||};
+
+
+
+[Icon|Name|Tags|Size|Exp|HP_max|AP_max|AP_move|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|Drop|Phrase|];
+{monsters_rats:0|Tiny rat|trainingrat||4|2|||10|50|||1|||trainingrat||};
+{monsters_rats:1|Cave rat|crossglen_caverat||11|5|||10|90|||2|||rat||};
+{monsters_rats:1|Tough cave rat|crossglen_caverat2||14|5|||5|90|||3|||rat||};
+{monsters_rats:3|Strong cave rat|crossglen_caveboss||25|20|||5|100|||1-4|10||caveratboss||};
+{monsters_insects:0|Black ant|crossglen_ant||5|3|||10|70|||1-2|||insect||};
+{monsters_insects:1|Small wasp|crossglen_wasp||5|4|||10|70|||1-2|||wasp||};
+{monsters_insects:4|Beetle|crossglen_beetle||8|4|||10|70|||3|||insect||};
+
+
+
+
+[Icon|Name|Tags|Size|Exp|HP_max|AP_max|AP_move|AtkCost|AtkPct|CritPct|CritMult|DMG|BlkPct|DMG_res|Drop|Phrase|];
+{monsters_mage2:0|Mikhail|Quest|1x1|0|1|1|1|1|0|||0||||mikhail_start_select|};
+{monsters_men:2|Leta|farm|1x1|0|1|1|1|1|0|||0||||leta1|};
+{monsters_men:0|Audir|smith|1x1|0|1|1|1|1|0|||0|||shop_smith|audir1|};
+{monsters_men:3|Arambold|bard|1x1|0|1|1|1|1|0|||0|||shop_clothes|arambold1|};
+{monsters_men:4|Tharal|Priest|1x1|0|1|1|1|1|0|||0|||shop_priest|tharal1|};
+{monsters_warrior1:0|Drunk||1x1|0|1|1|1|1|0|||0||||drunk1|};
+{monsters_men:7|Mara|Tavern|1x1|0|1|1|1|1|0|||0|||shop_food|mara1|};
+{monsters_rogue1:0|Gruil||1x1|0|1|1|1|1|0|||0|||shop_thief|gruil1|};
+{monsters_men:3|Leonid||1x1|0|1|1|1|1|0|||0||||leonid1|};
+{monsters_man1:0|Farmer|crossglen_farmer1|1x1|0|1|1|1|1|0|||0||||farm1|};
+{monsters_man1:0|Farmer|crossglen_farmer2|1x1|0|1|1|1|1|0|||0||||farm2|};
+
+
diff --git a/AndorsTrail/res/values/strings.xml b/AndorsTrail/res/values/strings.xml
new file mode 100644
index 000000000..a58a3e148
--- /dev/null
+++ b/AndorsTrail/res/values/strings.xml
@@ -0,0 +1,205 @@
+
+
+
+ Andor\'s Trail
+
+ Exit
+ Exit to menu
+ Pause
+
+ Loading resources...
+
+ Close
+
+ Exit
+ Are you sure you want to exit?
+
+ Paused
+ Game is paused
+ Resume
+
+ Encounter
+ Do you want to attack?\nDifficulty: %s
+ Info
+
+ HP:
+ MP:
+ AP:
+ Level:
+
+ Overview
+ Inventory
+ Equipped
+ Skills
+ Spells
+ Level up
+ Level
+ Total experience
+ Worn equipment
+ Inventory
+ Gold: %d
+ Action points (AP):
+
+ Attack (%d AP)
+ Move (%d AP)
+ Use item
+ Spell
+ End turn
+ End combat
+ AP: %d
+ HP:
+ %s is attacking.
+ You cannot exit combat since there are adjacent monsters.
+ %s misses!
+ %s hits you for %d hp!
+ %s gets a critical hit for %d hp!
+ Your attack misses.
+ You hit %s for %d hp!
+ You get a critical hit on %s for %d hp!
+ %s dies!
+ Not enough AP left this round.
+ You fall unconscious but fortunately wake up alive. You lost %d experience.
+
+ Info
+ Equip
+ Unequip
+ Use
+ Drop
+ You used %s.
+ %s was dropped.
+ You equipped %s.
+
+ Pick up all
+ You found %d gold.
+ Items
+ You found some items.
+ Victory
+ You survived the encounter.
+ You gained %d experience.
+
+ Very easy
+ Easy
+ Normal
+ Hard
+ Very hard
+
+ Class:
+ Difficulty:
+ Health:
+ Attacks/turn:
+ Movement/turn:
+ Attack:
+ Critical hit:
+ Defense:
+ Move cost (AP):
+ Unequipped combat statistics (base)
+ Equipped combat statistics (current)
+
+ Attack cost (AP):
+ Attack chance:
+ Attack damage:
+ Critical hit chance:
+ Critical multiplier:
+ Block chance:
+ Damage resistance:
+
+ A specific key is required to pass.
+
+ Category:
+ Use
+ Equip
+ Unequip
+ Use (%d AP)
+ Equip (%d AP)
+ Unequip (%d AP)
+ Restores %s HP
+
+ Money
+ Weapon
+ Shield
+ Wearable (head)
+ Wearable (body)
+ Wearable (hands)
+ Wearable (feet)
+ Wearable (neck)
+ Wearable (ring)
+ Potion
+ Other
+
+ Continue current game
+ New game
+ This will destroy the current game and your current character, are you sure you want to start a new game?
+ About/help
+ %s, level %d
+ Enter hero name
+
+ %s says
+ [You gained %d experience]
+ [You gained %d gold]
+
+ Buy
+ Sell
+ Info
+ Buy (%d gold)
+ Sell (%d gold)
+ Your gold: %d
+
+ Level up
+ Welcome to level %d!
+ Level up
+ Increase health
+ Adds %d to your maximum health.
+ Increase attack chance
+ Adds %d\% to your base attack chance.
+ Increase attack damage
+ Adds %d\% to your base attack damage.
+ Increase block chance
+ Adds %d\% to your base block chance.
+
+ Rest
+ Do you want to rest here?
+ You have rested and regained your full health.
+
+ Help
+ Authors
+ License
+
+ Welcome to Andor\'s Trail, a roguelike RPG on Android.<br />
+ <br />
+ <a href="http://code.google.com/p/andors-trail/">Project homepage on code.google.com</a><br />
+ <br />
+ I should really add some info here about how to play the game :)<br />
+
+
+ Programming by Oskar Wiksten<br />
+ <a href="http://telles0808.deviantart.com/art/RPG-Maker-VX-RTP-Tileset-159218223">Map tilesets graphics by telles0808</a><br />
+ <a href="http://ails.deviantart.com/art/420-Pixel-Art-Icons-for-RPG-129892453">Item tilesets graphics by Ails</a><br />
+ <a href="http://redknight91.deviantart.com/art/Arena-Game-Sprites-154661559">Hero graphics by RedKnight91</a><br />
+ <a href="http://nacred.deviantart.com/art/Sprite-Sheet-171751308">Additional monster graphics by nacred</a><br />
+ <a href="http://rltiles.sourceforge.net">Monster tileset graphics by rltiles.sourceforge.net</a><br />
+ Part of (or All) the graphic tiles used in this program is the public domain roguelike tileset "RLTiles".
+ Some of the tiles have been modified by Oskar Wiksten.
+ You can find the original tileset at <a href="http://rltiles.sf.net">http://rltiles.sf.net</a><br />
+
+
+ Copyright (C) 2010 Oskar Wiksten<br />
+ <br />
+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.<br />
+ <br />
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.<br />
+ <br />
+ You should have received a copy of the GNU General Public License along with this program; if not, see <a href="http://www.gnu.org/licenses">http://www.gnu.org/licenses</a><br />
+ <br />
+ For source code and feature requests, please visit the project page at <a href="http://code.google.com/p/andors-trail/">http://code.google.com/p/andors-trail/</a><br />
+
+
+ Welcome
+
+ Thank you for downloading Andor\'s Trail!\n\n
+ Please note that this version is the INITIAL RELEASE of Andor\'s Trail, which means that the maps are not yet complete.\n
+ You are however of course free to explore Crossglen village as much as you like.\n
+ This inital release is intended as a bug-hunt before we start adding content.\n
+ Please visit the homepage to get more info or to contribute to the project (see "about").\n
+
+
+
diff --git a/AndorsTrail/res/values/theme.xml b/AndorsTrail/res/values/theme.xml
new file mode 100644
index 000000000..edf123488
--- /dev/null
+++ b/AndorsTrail/res/values/theme.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/AndorsTrail/res/xml/crossglen.tmx b/AndorsTrail/res/xml/crossglen.tmx
new file mode 100644
index 000000000..732c79632
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen.tmx
@@ -0,0 +1,129 @@
+
+
diff --git a/AndorsTrail/res/xml/crossglen_cave.tmx b/AndorsTrail/res/xml/crossglen_cave.tmx
new file mode 100644
index 000000000..33065959a
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen_cave.tmx
@@ -0,0 +1,107 @@
+
+
diff --git a/AndorsTrail/res/xml/crossglen_farmhouse.tmx b/AndorsTrail/res/xml/crossglen_farmhouse.tmx
new file mode 100644
index 000000000..be751a404
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen_farmhouse.tmx
@@ -0,0 +1,89 @@
+
+
diff --git a/AndorsTrail/res/xml/crossglen_farmhouse_basement.tmx b/AndorsTrail/res/xml/crossglen_farmhouse_basement.tmx
new file mode 100644
index 000000000..4544ad8fc
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen_farmhouse_basement.tmx
@@ -0,0 +1,87 @@
+
+
diff --git a/AndorsTrail/res/xml/crossglen_hall.tmx b/AndorsTrail/res/xml/crossglen_hall.tmx
new file mode 100644
index 000000000..ec3068d0d
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen_hall.tmx
@@ -0,0 +1,97 @@
+
+
diff --git a/AndorsTrail/res/xml/crossglen_smith.tmx b/AndorsTrail/res/xml/crossglen_smith.tmx
new file mode 100644
index 000000000..b7d845305
--- /dev/null
+++ b/AndorsTrail/res/xml/crossglen_smith.tmx
@@ -0,0 +1,89 @@
+
+
diff --git a/AndorsTrail/res/xml/debugmap.tmx b/AndorsTrail/res/xml/debugmap.tmx
new file mode 100644
index 000000000..b097301e4
--- /dev/null
+++ b/AndorsTrail/res/xml/debugmap.tmx
@@ -0,0 +1,58 @@
+
+
diff --git a/AndorsTrail/res/xml/dungeon.tmx b/AndorsTrail/res/xml/dungeon.tmx
new file mode 100644
index 000000000..6e57bda7e
--- /dev/null
+++ b/AndorsTrail/res/xml/dungeon.tmx
@@ -0,0 +1,122 @@
+
+
diff --git a/AndorsTrail/res/xml/home.tmx b/AndorsTrail/res/xml/home.tmx
new file mode 100644
index 000000000..349037f06
--- /dev/null
+++ b/AndorsTrail/res/xml/home.tmx
@@ -0,0 +1,91 @@
+
+
diff --git a/AndorsTrail/res/xml/startmap.tmx b/AndorsTrail/res/xml/startmap.tmx
new file mode 100644
index 000000000..4a66bc3c2
--- /dev/null
+++ b/AndorsTrail/res/xml/startmap.tmx
@@ -0,0 +1,105 @@
+
+
diff --git a/AndorsTrail/res/xml/template.tmx b/AndorsTrail/res/xml/template.tmx
new file mode 100644
index 000000000..7c20ebfe7
--- /dev/null
+++ b/AndorsTrail/res/xml/template.tmx
@@ -0,0 +1,74 @@
+
+
diff --git a/AndorsTrail/res/xml/wilderness.tmx b/AndorsTrail/res/xml/wilderness.tmx
new file mode 100644
index 000000000..c75cbbf99
--- /dev/null
+++ b/AndorsTrail/res/xml/wilderness.tmx
@@ -0,0 +1,131 @@
+
+
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java
new file mode 100644
index 000000000..fcb0d69d1
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java
@@ -0,0 +1,30 @@
+package com.gpl.rpg.AndorsTrail;
+
+import java.lang.ref.WeakReference;
+
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+
+public final class AndorsTrailApplication extends Application {
+
+ public static final boolean DEVELOPMENT_VERSION = false;
+ public static final boolean DEVELOPMENT_VALIDATEDATA = true;
+
+ public final WorldContext world = new WorldContext();
+ public WorldSetup setup = new WorldSetup(world, this);
+ public WeakReference currentView;
+
+ public static AndorsTrailApplication getApplicationFromActivity(Activity activity) {
+ return ((AndorsTrailApplication) activity.getApplication());
+ }
+ public static AndorsTrailApplication getApplicationFromActivityContext(Context context) {
+ return getApplicationFromActivity(getActivityFromActivityContext(context));
+ }
+ public static Activity getActivityFromActivityContext(Context context) {
+ return (Activity) context;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java
new file mode 100644
index 000000000..3df78e4b1
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java
@@ -0,0 +1,229 @@
+package com.gpl.rpg.AndorsTrail;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.DialogInterface.OnDismissListener;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.AdapterView.OnItemClickListener;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.activity.ConversationActivity;
+import com.gpl.rpg.AndorsTrail.activity.MainActivity;
+import com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity;
+import com.gpl.rpg.AndorsTrail.activity.ItemInfoActivity;
+import com.gpl.rpg.AndorsTrail.activity.LevelUpActivity;
+import com.gpl.rpg.AndorsTrail.activity.MonsterEncounterActivity;
+import com.gpl.rpg.AndorsTrail.activity.MonsterInfoActivity;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.controller.Controller;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter;
+
+public final class Dialogs {
+
+ private static void showDialogAndPause(Dialog d, final ViewContext context) {
+ showDialogAndPause(d, context, new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface arg0) {
+ context.controller.resume();
+ }
+ });
+ }
+ private static void showDialogAndPause(Dialog d, ViewContext context, OnDismissListener onDismiss) {
+ context.controller.pause();
+ d.setOnDismissListener(onDismiss);
+ //setBlurrywindow(d);
+ d.show();
+ }
+
+ /*
+ private static void setBlurrywindow(Dialog d) {
+ d.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+ }
+ */
+
+ public static void showMapSign(final Context androidContext, final ViewContext context, String title, String text) {
+ Dialog d = new AlertDialog.Builder(androidContext)
+ .setTitle(title)
+ .setMessage(text)
+ .setIcon(new BitmapDrawable(context.tileStore.bitmaps[TileStore.iconID_mapsign]))
+ .setNeutralButton(android.R.string.ok, null)
+ .create();
+ showDialogAndPause(d, context);
+ }
+
+ /*
+ public static void showConfirmExit(final Activity activity, final ViewContext context) {
+ Dialog d = new AlertDialog.Builder(activity)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.dialog_confirmexit_title)
+ .setMessage(R.string.dialog_confirmexit_message)
+ .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ activity.finish();
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .create();
+
+ showDialogAndPause(d, context);
+ }
+ */
+
+ public static void showPaused(final Context androidContext, final ViewContext context) {
+ Dialog d = new AlertDialog.Builder(androidContext)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(R.string.dialog_paused_title)
+ .setMessage(R.string.dialog_paused_message)
+ .setNeutralButton(R.string.dialog_paused_resume, null)
+ .create();
+
+ showDialogAndPause(d, context);
+ }
+
+ public static void showConversation(final MainActivity currentActivity, final String phraseID, final Monster npc) {
+ Intent intent = new Intent(currentActivity, ConversationActivity.class);
+ Uri.Builder b = Uri.parse("content://com.gpl.rpg.AndorsTrail/conversation/" + phraseID).buildUpon();
+ b.appendQueryParameter("monsterTypeID", Integer.toString(npc.monsterType.id));
+ intent.setData(b.build());
+ currentActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_CONVERSATION);
+ }
+
+ public static void showMonsterEncounter(final MainActivity currentActivity, final Monster m) {
+ Intent intent = new Intent(currentActivity, MonsterEncounterActivity.class);
+ intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/monsterencounter/" + m.monsterType.id));
+ currentActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_MONSTERENCOUNTER);
+ }
+
+ public static void showMonsterInfo(final Activity currentActivity, int monsterTypeID) {
+ Intent intent = new Intent(currentActivity, MonsterInfoActivity.class);
+ intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/monsterinfo/" + monsterTypeID));
+ currentActivity.startActivity(intent);
+ }
+
+ public static void showMonsterLoot(final Context androidContext, final ViewContext context, final Loot loot) {
+ showLoot(androidContext, context, loot, R.string.dialog_monsterloot_title, R.string.dialog_monsterloot_message);
+ }
+
+ public static void showGroundLoot(final Context androidContext, final ViewContext context, final Loot loot) {
+ showLoot(androidContext, context, loot, R.string.dialog_groundloot_title, R.string.dialog_groundloot_message);
+ }
+
+ private static void showLoot(final Context androidContext, final ViewContext context, final Loot loot, final int title, final int message) {
+ if (loot.isEmpty()) return;
+
+ String msg = androidContext.getString(message);
+ if (loot.exp > 0) {
+ msg += androidContext.getString(R.string.dialog_monsterloot_gainedexp, loot.exp);
+ }
+ if (loot.gold > 0) {
+ msg += androidContext.getString(R.string.dialog_loot_foundgold, loot.gold);
+ }
+
+ final ListView itemList = new ListView(androidContext);
+ itemList.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+ itemList.setPadding(20, 0, 20, 20);
+ itemList.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ final int itemTypeID = (int) id;
+ loot.items.removeItem(itemTypeID, 1);
+ ItemType type = context.itemTypes.getItemType(itemTypeID);
+ context.model.player.inventory.addItem(type);
+ ((ItemContainerAdapter) itemList.getAdapter()).notifyDataSetChanged();
+ }
+ });
+ itemList.setAdapter(new ItemContainerAdapter(androidContext, context.tileStore, loot.items));
+
+ Dialog d = new AlertDialog.Builder(androidContext)
+ .setTitle(title)
+ .setMessage(msg)
+ .setIcon(new BitmapDrawable(context.tileStore.bitmaps[TileStore.iconID_groundbag]))
+ .setPositiveButton(R.string.dialog_loot_pickall, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ context.model.player.inventory.add(loot.items);
+ loot.clear();
+ }
+ })
+ .setNegativeButton(R.string.dialog_close, null)
+ .setView(itemList)
+ .create();
+
+ showDialogAndPause(d, context, new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface arg0) {
+ if (loot.isEmpty()) {
+ context.model.currentMap.removeGroundLoot(loot);
+ context.mainActivity.redrawTile(loot.position);
+ }
+ context.mainActivity.statusview.update();
+ context.controller.resume();
+ }
+ });
+ }
+
+ public static void showItemInfo(final Activity currentActivity, int itemTypeID, int actionType, String buttonText, boolean buttonEnabled, int inventorySlot) {
+ Intent intent = new Intent(currentActivity, ItemInfoActivity.class);
+ intent.putExtra("buttonText", buttonText);
+ intent.putExtra("buttonEnabled", buttonEnabled);
+ intent.putExtra("itemTypeID", itemTypeID);
+ intent.putExtra("actionType", actionType);
+ intent.putExtra("inventorySlot", inventorySlot);
+ intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/iteminfo/" + itemTypeID));
+ currentActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_ITEMINFO);
+ }
+ public static void showLevelUp(final HeroinfoActivity currentActivity) {
+ Intent intent = new Intent(currentActivity, LevelUpActivity.class);
+ intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/levelup"));
+ currentActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_LEVELUP);
+ }
+ public static void showRest(final Activity currentActivity, final ViewContext viewContext) {
+ Dialog d = new AlertDialog.Builder(currentActivity)
+ .setTitle(R.string.dialog_rest_title)
+ .setMessage(R.string.dialog_rest_confirm_message)
+ .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Controller.playerRested(viewContext, false);
+ viewContext.mainActivity.statusview.update();
+ Dialogs.showRested(currentActivity, viewContext);
+ }
+ })
+ .setNegativeButton(android.R.string.no, null)
+ .create();
+
+ showDialogAndPause(d, viewContext);
+ }
+ public static void showRested(final Activity currentActivity, final ViewContext viewContext) {
+ Dialog d = new AlertDialog.Builder(currentActivity)
+ .setTitle(R.string.dialog_rest_title)
+ .setMessage(R.string.dialog_rest_message)
+ .setNeutralButton(android.R.string.ok, null)
+ .create();
+
+ showDialogAndPause(d, viewContext);
+ }
+
+ public static void showNewVersion(final Activity currentActivity) {
+ new AlertDialog.Builder(currentActivity)
+ .setTitle(R.string.dialog_newversion_title)
+ .setMessage(R.string.dialog_newversion_message)
+ .setNeutralButton(android.R.string.ok, null)
+ .show();
+ }
+
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/EffectCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/EffectCollection.java
new file mode 100644
index 000000000..9d73dd53d
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/EffectCollection.java
@@ -0,0 +1,52 @@
+package com.gpl.rpg.AndorsTrail;
+
+import android.graphics.Color;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+
+public final class EffectCollection {
+ public static final int EFFECT_BLOOD = 0;
+ public static final int EFFECT_RESTORE_HP = 0;
+ public static final int EFFECT_RESTORE_AP = 0;
+
+ public static final int NUM_EFFECTS = EFFECT_RESTORE_AP + 1;
+
+ public final Effect[] effects = new Effect[NUM_EFFECTS];
+
+ public void initialize(DynamicTileLoader loader) {
+ effects[EFFECT_BLOOD] = createEffect(loader, R.drawable.effect_blood3, new ConstRange(16, 0), 400, Color.RED);
+ }
+
+ private static Effect createEffect(DynamicTileLoader loader, int drawableID, ConstRange frameRange, int duration, int textColor) {
+ int[] frameIconIDs = new int[frameRange.max - frameRange.current];
+ for(int i = 0; i < frameIconIDs.length; ++i) {
+ frameIconIDs[i] = loader.getTileID(drawableID, frameRange.current + i);
+ }
+ return new Effect(frameIconIDs, duration, textColor);
+ }
+
+ public final static class Effect {
+ public final int[] frameIconIDs;
+ public final int duration; // milliseconds
+ public final int textColor;
+ //public final int fps = ModelContainer.attackAnimationFPS;
+ //public final int millisecondPerFrame = 1000 / fps;
+ //public final int totalFrames = duration / millisecondPerFrame;
+ public final int fps;
+ public final int millisecondPerFrame;
+ public final int totalFrames;
+ public final int lastFrame;
+
+ public Effect(int[] frameIconIDs, int duration, int textColor) {
+ this.frameIconIDs = frameIconIDs;
+ this.duration = duration;
+ this.textColor = textColor;
+ totalFrames = frameIconIDs.length;
+ lastFrame = totalFrames - 1;
+ millisecondPerFrame = duration / totalFrames;
+ fps = 1000 / millisecondPerFrame;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java
new file mode 100644
index 000000000..52e17bfcf
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java
@@ -0,0 +1,143 @@
+package com.gpl.rpg.AndorsTrail;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.Controller;
+import com.gpl.rpg.AndorsTrail.controller.MovementController;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.resource.ResourceLoader;
+import com.gpl.rpg.AndorsTrail.util.L;
+
+public final class WorldSetup {
+
+ private final WorldContext world;
+ private final WeakReference androidContext;
+ private boolean isResourcesInitialized = false;
+ private boolean isInitializingResources = false;
+ private WeakReference listener;
+
+ public boolean createNewCharacter = false;
+ public boolean isSceneReady = false;
+ public String newHeroName;
+
+ public WorldSetup(WorldContext world, Context androidContext) {
+ this.world = world;
+ this.androidContext = new WeakReference(androidContext);
+ }
+
+ public void startResourceLoader(final Resources r) {
+ if (isResourcesInitialized) return;
+
+ synchronized (this) {
+ if (isInitializingResources) return;
+ isInitializingResources = true;
+ }
+
+ (new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ ResourceLoader.loadResources(world, r);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ synchronized (WorldSetup.this) {
+ isResourcesInitialized = true;
+ isInitializingResources = false;
+ if (listener == null) return; // sceneloader will be fired by next caller.
+ }
+ startSceneLoader();
+ }
+ }).execute();
+ }
+
+ public void startCharacterSetup(final OnSceneLoadedListener listener) {
+ synchronized (WorldSetup.this) {
+ this.listener = new WeakReference(listener);
+ if (!isResourcesInitialized) return; // sceneloader will be fired by the resourceloader.
+ }
+ startSceneLoader();
+ }
+
+ private void startSceneLoader() {
+ isSceneReady = false;
+ (new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ if (createNewCharacter) {
+ createNewWorld();
+ } else {
+ continueWorld();
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ isSceneReady = true;
+ assert(listener != null);
+ OnSceneLoadedListener o = listener.get();
+ listener = null;
+ if (o == null) return;
+ o.onSceneLoaded();
+ }
+ }).execute();
+ }
+
+ private void continueWorld() {
+ loadWorld(world, androidContext.get());
+ }
+
+ private void createNewWorld() {
+ if (world.model != null) world.reset();
+ world.model = new ModelContainer();
+ world.model.player.initializeNewPlayer(world.itemTypes, world.dropLists, newHeroName);
+ Controller.playerRested(world, true);
+ MovementController.respawnPlayer(world);
+ }
+
+
+ public interface OnSceneLoadedListener {
+ void onSceneLoaded();
+ }
+
+ private static final String FILENAME_SAVEGAME = "savegame";
+ public static void saveWorld(WorldContext world, Context androidContext) {
+ try {
+ FileOutputStream fos = androidContext.openFileOutput(FILENAME_SAVEGAME, Context.MODE_PRIVATE);
+ DataOutputStream dest = new DataOutputStream(fos);
+ final int flags = 0;
+ world.maps.writeToParcel(dest, flags);
+ world.model.writeToParcel(dest, flags);
+ dest.close();
+ fos.close();
+ } catch (IOException e) {
+ L.log("Error saving world: " + e.toString());
+ }
+ }
+ private static void loadWorld(WorldContext world, Context androidContext) {
+ try {
+ FileInputStream fos = androidContext.openFileInput(FILENAME_SAVEGAME);
+ DataInputStream src = new DataInputStream(fos);
+ world.maps.readFromParcel(src, world);
+ world.model = new ModelContainer(src, world);
+ src.close();
+ fos.close();
+ } catch (IOException e) {
+ L.log("Error loading world: " + e.toString());
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java
new file mode 100644
index 000000000..85339919a
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java
@@ -0,0 +1,58 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.R;
+
+public class AboutActivity extends Activity {
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ setContentView(R.layout.about);
+ final Resources res = getResources();
+
+ final TextView tv = (TextView) findViewById(R.id.about_contents);
+ tv.setText(Html.fromHtml(res.getString(R.string.about_contents1)));
+
+ Button b = (Button) findViewById(R.id.about_button1);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tv.setText(Html.fromHtml(res.getString(R.string.about_contents1)));
+ }
+ });
+
+
+ b = (Button) findViewById(R.id.about_button2);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tv.setText(Html.fromHtml(res.getString(R.string.about_contents2)));
+ }
+ });
+
+ b = (Button) findViewById(R.id.about_button3);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tv.setText(Html.fromHtml(res.getString(R.string.about_contents3)));
+ }
+ });
+
+ tv.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java
new file mode 100644
index 000000000..94029eede
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java
@@ -0,0 +1,132 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+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.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.ConversationController;
+import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
+import com.gpl.rpg.AndorsTrail.conversation.Phrase;
+import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+
+public final class ConversationActivity extends Activity {
+ private WorldContext world;
+ private Player player;
+
+ private TextView text;
+ private Button reply1;
+ private Button reply2;
+ private Button reply3;
+ private MonsterType monsterType;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+ this.player = world.model.player;
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ Uri uri = getIntent().getData();
+ final int monsterTypeID = Integer.parseInt(uri.getQueryParameter("monsterTypeID"));
+
+ monsterType = world.monsterTypes.getMonsterType(monsterTypeID);
+
+ setContentView(R.layout.conversation);
+
+ ImageView iw = (ImageView) findViewById(R.id.conversation_image);
+ iw.setImageBitmap(world.tileStore.bitmaps[monsterType.iconID]);
+ TextView tv = (TextView) findViewById(R.id.conversation_title);
+ tv.setText(getResources().getString(R.string.conversation_title, monsterType.name));
+
+ text = (TextView) findViewById(R.id.conversation_text);
+ reply1 = (Button) findViewById(R.id.conversation_reply1);
+ reply2 = (Button) findViewById(R.id.conversation_reply2);
+ reply3 = (Button) findViewById(R.id.conversation_reply3);
+
+ setPhrase(uri.getLastPathSegment().toString());
+ }
+
+ public void setPhrase(String phraseID) {
+ if (phraseID.equalsIgnoreCase(ConversationCollection.PHRASE_CLOSE)) {
+ ConversationActivity.this.finish();
+ return;
+ } else if (phraseID.equalsIgnoreCase(ConversationCollection.PHRASE_SHOP)) {
+ assert(monsterType.dropList != null);
+ Intent intent = new Intent(this, ShopActivity.class);
+ intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/shop/" + monsterType.id));
+ startActivityForResult(intent, MainActivity.INTENTREQUEST_SHOP);
+ return;
+ }
+
+ final Phrase phrase = world.conversations.getPhrase(phraseID);
+ ConversationController.applyPhraseEffect(player, phrase);
+
+ if (phrase.message == null || phrase.message.length() <= 0) {
+ for (Reply r : phrase.replies) {
+ if (!ConversationController.canSelectReply(player, r)) continue;
+ setPhrase(r.nextPhrase);
+ return;
+ }
+ }
+
+ String message = phrase.message;
+ if (phrase.rewardExperience > 0) {
+ message += "\n" + getResources().getString(R.string.conversation_rewardexp, phrase.rewardExperience);
+ }
+ if (phrase.rewardGold > 0) {
+ message += "\n" + getResources().getString(R.string.conversation_rewardgold, phrase.rewardGold);
+ }
+
+ text.setText(message);
+ handleReply(phrase, 0, reply1);
+ handleReply(phrase, 1, reply2);
+ handleReply(phrase, 2, reply3);
+ }
+
+ private void handleReply(Phrase p, int replyIndex, Button b) {
+ if (p.replies.length <= replyIndex) {
+ b.setVisibility(View.GONE);
+ return;
+ }
+
+ final Reply r = p.replies[replyIndex];
+ if (!ConversationController.canSelectReply(player, r)) {
+ b.setVisibility(View.GONE);
+ return;
+ }
+
+ b.setVisibility(View.VISIBLE);
+ b.setText(r.text);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ ConversationController.applyReplyEffect(player, r);
+ ConversationActivity.this.setPhrase(r.nextPhrase);
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case MainActivity.INTENTREQUEST_SHOP:
+ ConversationActivity.this.finish();
+ break;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java
new file mode 100644
index 000000000..6f86ee404
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java
@@ -0,0 +1,325 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+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.ItemType;
+import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter;
+import com.gpl.rpg.AndorsTrail.view.RangeBar;
+import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
+
+import android.app.TabActivity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TabHost;
+import android.widget.TextView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class HeroinfoActivity extends TabActivity {
+ private WorldContext world;
+ private ViewContext view;
+
+ private Player player;
+ private ItemContainer container;
+
+ private ListView inventoryList;
+ private Button levelUpButton;
+ private TextView heroinfo_ap;
+ private TextView heroinfo_movecost;
+ private TraitsInfoView heroinfo_basetraits;
+ private TraitsInfoView heroinfo_currenttraits;
+ private TextView heroinfo_level;
+ private TextView heroinfo_totalexperience;
+ private TextView heroinfo_stats_gold;
+ private TextView heroinfo_stats_attack;
+ private TextView heroinfo_stats_defense;
+ private RangeBar rangebar_hp;
+ private RangeBar rangebar_exp;
+
+ private final ImageView[] wornItemImage = new ImageView[Inventory.NUM_WORN_SLOTS];
+ private final int[] defaultWornItemImageResourceIDs = new int[Inventory.NUM_WORN_SLOTS];
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+ this.view = app.currentView.get();
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ this.player = world.model.player;
+
+ setContentView(R.layout.heroinfo);
+
+ Resources res = getResources();
+ TabHost h = getTabHost();
+ h.addTab(h.newTabSpec("char")
+ .setIndicator(res.getString(R.string.heroinfo_char), res.getDrawable(R.drawable.char_hero)) //TODO: Should change icon
+ .setContent(R.id.heroinfo_tab1));
+ h.addTab(h.newTabSpec("inv")
+ .setIndicator(res.getString(R.string.heroinfo_inv), res.getDrawable(R.drawable.char_hero)) //TODO: Should change icon
+ .setContent(R.id.heroinfo_tab2));
+ String t = world.model.uiSelections.selectedTabHeroInfo;
+ if (t != null && t.length() > 0) {
+ h.setCurrentTabByTag(t);
+ }
+ h.setup();
+
+ inventoryList = (ListView) h.findViewById(R.id.inventorylist_root);
+ registerForContextMenu(inventoryList);
+ inventoryList.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ showInventoryItemInfo((int) id);
+ }
+ });
+ container = player.inventory;
+
+ ImageView iv = (ImageView) findViewById(R.id.heroinfo_image);
+ iv.setImageBitmap(world.tileStore.bitmaps[player.traits.iconID]);
+
+ ((TextView) findViewById(R.id.heroinfo_title)).setText(player.traits.name);
+ heroinfo_ap = (TextView) findViewById(R.id.heroinfo_ap);
+ heroinfo_movecost = (TextView) findViewById(R.id.heroinfo_movecost);
+ heroinfo_basetraits = (TraitsInfoView) findViewById(R.id.heroinfo_basetraits);
+ heroinfo_currenttraits = (TraitsInfoView) findViewById(R.id.heroinfo_currenttraits);
+ heroinfo_stats_gold = (TextView) findViewById(R.id.heroinfo_stats_gold);
+ heroinfo_stats_attack = (TextView) findViewById(R.id.heroinfo_stats_attack);
+ heroinfo_stats_defense = (TextView) findViewById(R.id.heroinfo_stats_defense);
+ heroinfo_level = (TextView) findViewById(R.id.heroinfo_level);
+ heroinfo_totalexperience = (TextView) findViewById(R.id.heroinfo_totalexperience);
+
+ rangebar_hp = (RangeBar) findViewById(R.id.heroinfo_healthbar);
+ rangebar_hp.init(R.drawable.ui_progress_health, R.string.status_hp);
+ rangebar_exp = (RangeBar) findViewById(R.id.heroinfo_expbar);
+ rangebar_exp.init(R.drawable.ui_progress_exp, R.string.status_exp);
+
+ levelUpButton = (Button) findViewById(R.id.heroinfo_levelup);
+ levelUpButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ Dialogs.showLevelUp(HeroinfoActivity.this);
+ }
+ });
+
+ setWearSlot(ItemType.CATEGORY_WEAPON, R.id.heroinfo_worn_weapon, R.drawable.equip_weapon);
+ setWearSlot(ItemType.CATEGORY_SHIELD, R.id.heroinfo_worn_shield, R.drawable.equip_shield);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_HEAD, R.id.heroinfo_worn_head, R.drawable.equip_head);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_BODY, R.id.heroinfo_worn_body, R.drawable.equip_body);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_FEET, R.id.heroinfo_worn_feet, R.drawable.equip_feet);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_NECK, R.id.heroinfo_worn_neck, R.drawable.equip_neck);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_HAND, R.id.heroinfo_worn_hand, R.drawable.equip_hand);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_RING, R.id.heroinfo_worn_ringleft, R.drawable.equip_ring);
+ setWearSlot(ItemType.CATEGORY_WEARABLE_RING+1, R.id.heroinfo_worn_ringright, R.drawable.equip_ring);
+
+ inventoryList.setAdapter(new ItemContainerAdapter(this, world.tileStore, container));
+
+ update();
+ }
+
+ private void setWearSlot(final int inventorySlot, int viewId, int resourceId) {
+ ImageView view = (ImageView) findViewById(viewId);
+ wornItemImage[inventorySlot] = view;
+ defaultWornItemImageResourceIDs[inventorySlot] = resourceId;
+ view.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (player.inventory.isEmptySlot(inventorySlot)) return;
+ showEquippedItemInfo(player.inventory.wear[inventorySlot], inventorySlot);
+ }
+ });
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ world.model.uiSelections.selectedTabHeroInfo = getTabHost().getCurrentTabTag();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case MainActivity.INTENTREQUEST_ITEMINFO:
+ if (resultCode != RESULT_OK) return;
+
+ ItemType itemType = world.itemTypes.getItemType(data.getExtras().getInt("itemTypeID"));
+ int actionType = data.getExtras().getInt("actionType");
+ if (actionType == ItemInfoActivity.ITEMACTION_UNEQUIP) {
+ view.itemController.unequipSlot(itemType, data.getExtras().getInt("inventorySlot"));
+ } else if (actionType == ItemInfoActivity.ITEMACTION_EQUIP) {
+ view.itemController.equipItem(itemType);
+ } else if (actionType == ItemInfoActivity.ITEMACTION_USE) {
+ view.itemController.useItem(itemType);
+ }
+ break;
+ case MainActivity.INTENTREQUEST_LEVELUP:
+ break;
+ }
+ update();
+ }
+
+ private void update() {
+ updateItemList();
+ updateTraits();
+ updateWorn();
+ updateLevelup();
+ }
+
+ private void updateLevelup() {
+ levelUpButton.setEnabled(player.canLevelup());
+ }
+
+ private void updateTraits() {
+ heroinfo_level.setText(Integer.toString(player.level));
+ heroinfo_totalexperience.setText(Integer.toString(player.totalExperience));
+ heroinfo_basetraits.update(player.traits.baseCombatTraits);
+ heroinfo_currenttraits.update(player.traits);
+ heroinfo_ap.setText(player.ap.toString());
+ heroinfo_movecost.setText(Integer.toString(player.traits.moveCost));
+ heroinfo_stats_gold.setText(getResources().getString(R.string.heroinfo_gold, player.inventory.gold));
+ heroinfo_stats_attack.setText(ItemType.describeAttackEffect(player.traits));
+ heroinfo_stats_defense.setText(ItemType.describeBlockEffect(player.traits));
+ rangebar_hp.update(player.health);
+ rangebar_exp.update(player.levelExperience);
+ }
+
+ private void updateWorn() {
+ for(int slot = 0; slot < Inventory.NUM_WORN_SLOTS; ++slot) {
+ updateWornImage(wornItemImage[slot], defaultWornItemImageResourceIDs[slot], player.inventory.wear[slot]);
+ }
+ }
+
+ private void updateWornImage(ImageView view, int resourceIDEmptyImage, ItemType type) {
+ if (type != null) {
+ view.setImageBitmap(world.tileStore.bitmaps[type.iconID]);
+ } else {
+ view.setImageResource(resourceIDEmptyImage);
+ }
+ }
+
+ private void updateItemList() {
+ ((ItemContainerAdapter) inventoryList.getAdapter()).notifyDataSetChanged();
+ //inventoryList.setAdapter(new ItemContainerAdapter(this, world.tileStore, container));
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ ItemType type = getSelectedItemType((AdapterContextMenuInfo) menuInfo);
+ MenuInflater inflater = getMenuInflater();
+ switch (v.getId()) {
+ case R.id.inventorylist_root:
+ inflater.inflate(R.menu.inventoryitem, menu);
+ if (type.isUsable()) menu.findItem(R.id.inv_menu_use).setVisible(true);
+ if (type.isEquippable()) menu.findItem(R.id.inv_menu_equip).setVisible(true);
+ break;
+ }
+ }
+
+ private int getSelectedID(AdapterContextMenuInfo info) {
+ return (int) info.id;
+ }
+ private ItemType getSelectedItemType(AdapterContextMenuInfo info) {
+ return world.itemTypes.getItemType(getSelectedID(info));
+ }
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ switch (item.getItemId()) {
+ case R.id.inv_menu_info:
+ showInventoryItemInfo(getSelectedItemType(info));
+ //context.controller.itemInfo(this, getSelectedItemType(info));
+ break;
+ case R.id.inv_menu_drop:
+ view.itemController.dropItem(getSelectedItemType(info));
+ break;
+ case R.id.inv_menu_equip:
+ view.itemController.equipItem(getSelectedItemType(info));
+ break;
+ /*case R.id.inv_menu_unequip:
+ context.controller.unequipItem(this, getSelectedItemType(info));
+ break;*/
+ case R.id.inv_menu_use:
+ view.itemController.useItem(getSelectedItemType(info));
+ break;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ update();
+ return true;
+ }
+
+ private void showEquippedItemInfo(ItemType itemType, int inventorySlot) {
+ String text;
+ boolean enabled = true;
+
+ if (world.model.uiSelections.isInCombat) {
+ int ap = world.model.player.reequipCost;
+ text = getResources().getString(R.string.iteminfo_action_unequip_ap, ap);
+ if (ap > 0) {
+ if (world.model.player.ap.current < ap) {
+ enabled = false;
+ }
+ }
+ } else {
+ text = getResources().getString(R.string.iteminfo_action_unequip);
+ }
+ Dialogs.showItemInfo(HeroinfoActivity.this, itemType.id, ItemInfoActivity.ITEMACTION_UNEQUIP, text, enabled, inventorySlot);
+ }
+ private void showInventoryItemInfo(int itemTypeID) {
+ showInventoryItemInfo(world.itemTypes.getItemType(itemTypeID));
+ }
+ private void showInventoryItemInfo(ItemType itemType) {
+ String text = "";
+ int ap = 0;
+ boolean enabled = true;
+ int action = ItemInfoActivity.ITEMACTION_NONE;
+ final boolean isInCombat = world.model.uiSelections.isInCombat;
+ if (itemType.isEquippable()) {
+ if (isInCombat) {
+ ap = world.model.player.reequipCost;
+ text = getResources().getString(R.string.iteminfo_action_equip_ap, ap);
+ } else {
+ text = getResources().getString(R.string.iteminfo_action_equip);
+ }
+ action = ItemInfoActivity.ITEMACTION_EQUIP;
+ } else if (itemType.isUsable()) {
+ if (isInCombat) {
+ ap = world.model.player.useItemCost;
+ text = getResources().getString(R.string.iteminfo_action_use_ap, ap);
+ } else {
+ text = getResources().getString(R.string.iteminfo_action_use);
+ }
+ action = ItemInfoActivity.ITEMACTION_USE;
+ }
+ if (isInCombat && ap > 0) {
+ if (world.model.player.ap.current < ap) {
+ enabled = false;
+ }
+ }
+
+ Dialogs.showItemInfo(HeroinfoActivity.this, itemType.id, action, text, enabled, -1);
+ }
+
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java
new file mode 100644
index 000000000..ce660c581
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java
@@ -0,0 +1,123 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+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.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
+
+public final class ItemInfoActivity extends Activity {
+
+ public static int ITEMACTION_NONE = 1;
+ public static int ITEMACTION_USE = 2;
+ public static int ITEMACTION_EQUIP = 3;
+ public static int ITEMACTION_UNEQUIP = 4;
+ public static int ITEMACTION_BUY = 5;
+ public static int ITEMACTION_SELL = 6;
+
+ private WorldContext world;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ final Intent intent = getIntent();
+ Bundle params = intent.getExtras();
+ int itemTypeID = params.getInt("itemTypeID");
+ final ItemType itemType = world.itemTypes.getItemType(itemTypeID);
+
+ final String buttonText = params.getString("buttonText");
+ boolean buttonEnabled = params.getBoolean("buttonEnabled");
+
+
+ setContentView(R.layout.iteminfo);
+
+ ImageView img = (ImageView) findViewById(R.id.iteminfo_image);
+ img.setImageBitmap(world.tileStore.bitmaps[itemType.iconID]);
+ TextView tv = (TextView) findViewById(R.id.iteminfo_title);
+ tv.setText(itemType.name);
+ tv = (TextView) findViewById(R.id.iteminfo_category);
+ tv.setText(getCategoryNameRes(itemType.category));
+
+ ((TraitsInfoView) findViewById(R.id.iteminfo_traits)).update(itemType.effect_combat);
+
+ tv = (TextView) findViewById(R.id.iteminfo_description);
+ if (itemType.effect_health != null && itemType.effect_health.max != 0) {
+ tv.setText(getResources().getString(R.string.iteminfo_effect_heal, itemType.effect_health.toMinMaxString()));
+ tv.setVisibility(View.VISIBLE);
+ } else {
+ tv.setVisibility(View.GONE);
+ }
+
+ Button b = (Button) findViewById(R.id.iteminfo_close);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ setResult(RESULT_CANCELED);
+ ItemInfoActivity.this.finish();
+ }
+ });
+
+ b = (Button) findViewById(R.id.iteminfo_action);
+ if (buttonText != null && buttonText.length() > 0) {
+ b.setVisibility(View.VISIBLE);
+ b.setEnabled(buttonEnabled);
+ b.setText(buttonText);
+ } else {
+ b.setVisibility(View.GONE);
+ }
+
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ Intent result = new Intent();
+ result.putExtras(intent);
+ setResult(RESULT_OK, result);
+ ItemInfoActivity.this.finish();
+ }
+ });
+ }
+
+ private static int getCategoryNameRes(int itemCategory) {
+ switch (itemCategory) {
+ case ItemType.CATEGORY_MONEY:
+ return R.string.itemcategory_money;
+ case ItemType.CATEGORY_WEAPON:
+ return R.string.itemcategory_weapon;
+ case ItemType.CATEGORY_SHIELD:
+ return R.string.itemcategory_shield;
+ case ItemType.CATEGORY_WEARABLE_HEAD:
+ return R.string.itemcategory_wearable_head;
+ case ItemType.CATEGORY_WEARABLE_HAND:
+ return R.string.itemcategory_wearable_hand;
+ case ItemType.CATEGORY_WEARABLE_FEET:
+ return R.string.itemcategory_wearable_feet;
+ case ItemType.CATEGORY_WEARABLE_BODY:
+ return R.string.itemcategory_wearable_body;
+ case ItemType.CATEGORY_WEARABLE_NECK:
+ return R.string.itemcategory_wearable_neck;
+ case ItemType.CATEGORY_WEARABLE_RING:
+ return R.string.itemcategory_wearable_ring;
+ case ItemType.CATEGORY_POTION:
+ return R.string.itemcategory_potion;
+ default:
+ return R.string.itemcategory_other;
+ }
+ }
+
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java
new file mode 100644
index 000000000..2b93c1654
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java
@@ -0,0 +1,180 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+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.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.Controller;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+
+public final class LevelUpActivity extends Activity {
+ private WorldContext world;
+ private Player player;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+ this.player = world.model.player;
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ setContentView(R.layout.levelup);
+ final Resources res = getResources();
+
+ ImageView img = (ImageView) findViewById(R.id.levelup_image);
+ img.setImageBitmap(world.tileStore.bitmaps[player.traits.iconID]);
+ TextView tv = (TextView) findViewById(R.id.levelup_description);
+ tv.setText(res.getString(R.string.levelup_description, player.level+1));
+
+ /*
+ ArrayList items = new ArrayList();
+ items.add(
+ new LevelUpSelection(
+ SELECT_HEALTH
+ , res.getString(R.string.levelup_add_health)
+ , res.getString(R.string.levelup_add_health_description, LEVELUP_EFFECT_HEALTH)
+ )
+ );
+ items.add(
+ new LevelUpSelection(
+ SELECT_ATK_CH
+ , res.getString(R.string.levelup_add_attackchance)
+ , res.getString(R.string.levelup_add_attackchance_description, LEVELUP_EFFECT_ATK_CH)
+ )
+ );
+ items.add(
+ new LevelUpSelection(
+ SELECT_ATK_DMG
+ , res.getString(R.string.levelup_add_attackdamage)
+ , res.getString(R.string.levelup_add_attackdamage_description, LEVELUP_EFFECT_ATK_DMG)
+ )
+ );
+ items.add(
+ new LevelUpSelection(
+ SELECT_DEF_CH
+ , res.getString(R.string.levelup_add_blockchance)
+ , res.getString(R.string.levelup_add_blockchance_description, LEVELUP_EFFECT_DEF_CH)
+ )
+ );
+
+ ListView lv = (ListView) findViewById(R.id.levelup_list);
+ lv.setAdapter(new LevelUpSelectionAdapter(this, items));
+ */
+
+ ((Button) findViewById(R.id.levelup_add_health)).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ levelup(SELECT_HEALTH);
+ }
+ });
+ ((Button) findViewById(R.id.levelup_add_attackchance)).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ levelup(SELECT_ATK_CH);
+ }
+ });
+ ((Button) findViewById(R.id.levelup_add_attackdamage)).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ levelup(SELECT_ATK_DMG);
+ }
+ });
+ ((Button) findViewById(R.id.levelup_add_blockchance)).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ levelup(SELECT_DEF_CH);
+ }
+ });
+ }
+
+ private static final int SELECT_HEALTH = 0;
+ private static final int SELECT_ATK_CH = 1;
+ private static final int SELECT_ATK_DMG = 2;
+ private static final int SELECT_DEF_CH = 3;
+
+ public void levelup(int selectionID) {
+ addLevelupEffect(player, selectionID);
+ LevelUpActivity.this.finish();
+ }
+
+ private static void addLevelupEffect(Player player, int selectionID) {
+ switch (selectionID) {
+ case SELECT_HEALTH:
+ player.health.max += Controller.LEVELUP_EFFECT_HEALTH;
+ player.health.current += Controller.LEVELUP_EFFECT_HEALTH;
+ break;
+ case SELECT_ATK_CH:
+ player.traits.baseCombatTraits.attackChance += Controller.LEVELUP_EFFECT_ATK_CH;
+ break;
+ case SELECT_ATK_DMG:
+ player.traits.baseCombatTraits.damagePotential.max += Controller.LEVELUP_EFFECT_ATK_DMG;
+ player.traits.baseCombatTraits.damagePotential.current += Controller.LEVELUP_EFFECT_ATK_DMG;
+ break;
+ case SELECT_DEF_CH:
+ player.traits.baseCombatTraits.blockChance += Controller.LEVELUP_EFFECT_DEF_CH;
+ break;
+ }
+ player.level++;
+ player.recalculateLevelExperience();
+ player.recalculateCombatTraits();
+ }
+
+ /*
+ private static final class LevelUpSelection {
+ public final int id;
+ public final String title;
+ public final String description;
+ public LevelUpSelection(int id, String title, String description) {
+ this.id = id;
+ this.title = title;
+ this.description = description;
+ }
+ }
+
+ private final class LevelUpSelectionAdapter extends ArrayAdapter {
+ public LevelUpSelectionAdapter(Context context, List items) {
+ super(context, 0, items);
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ final LevelUpSelection item = getItem(position);
+
+ View result = convertView;
+ if (result == null) {
+ result = View.inflate(getContext(), R.layout.levelupitemview, null);
+ }
+
+ TextView tv = (TextView) result.findViewById(R.id.levelupitem_title);
+ tv.setText(item.title);
+ //tv = (TextView) result.findViewById(R.id.levelupitem_description);
+ //tv.setText(item.description);
+
+ ((Button) result.findViewById(R.id.levelupitem_button)).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ levelup(item.id);
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).id;
+ }
+ }
+*/
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java
new file mode 100644
index 000000000..c10d29ffa
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java
@@ -0,0 +1,306 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import java.lang.ref.WeakReference;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.WorldSetup;
+import com.gpl.rpg.AndorsTrail.WorldSetup.OnSceneLoadedListener;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.view.CombatView;
+import com.gpl.rpg.AndorsTrail.view.MainView;
+import com.gpl.rpg.AndorsTrail.view.StatusView;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MainActivity extends Activity implements OnSceneLoadedListener {
+
+ private static final int DIALOG_LOADING = 1;
+
+ public static final int INTENTREQUEST_HEROINFO = 1;
+ public static final int INTENTREQUEST_MONSTERENCOUNTER = 2;
+ public static final int INTENTREQUEST_ITEMINFO = 3;
+ public static final int INTENTREQUEST_CONVERSATION = 4;
+ public static final int INTENTREQUEST_SHOP = 5;
+ public static final int INTENTREQUEST_LEVELUP = 6;
+
+ private ViewContext view;
+ private WorldContext world;
+
+ public MainView mainview;
+ public StatusView statusview;
+ public CombatView combatview;
+
+ private static final int NUM_MESSAGES = 3;
+ private final String[] messages = new String[NUM_MESSAGES];
+ private TextView statusText;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ L.log("onCreate");
+
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+
+ //Debug.startMethodTracing(ICICLE_KEY);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ showDialog(DIALOG_LOADING);
+ app.setup.startCharacterSetup(this);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case INTENTREQUEST_HEROINFO:
+ statusview.update();
+ combatview.updatePlayerAP(world.model.player.ap);
+ break;
+ case INTENTREQUEST_MONSTERENCOUNTER:
+ if (resultCode == Activity.RESULT_OK) {
+ view.combatController.enterCombat();
+ } else {
+ view.combatController.exitCombat();
+ }
+ break;
+ case INTENTREQUEST_CONVERSATION:
+ statusview.update();
+ break;
+ }
+ }
+
+ @Override
+ public void onSceneLoaded() {
+ L.log("onSceneLoaded");
+
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.view = new ViewContext(app, this);
+ app.currentView = new WeakReference(this.view);
+
+ setContentView(R.layout.main);
+ mainview = (MainView) findViewById(R.id.main_mainview);
+ statusview = (StatusView) findViewById(R.id.main_statusview);
+ combatview = (CombatView) findViewById(R.id.main_combatview);
+
+ statusText = (TextView) findViewById(R.id.statusview_statustext);
+ statusText.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ clearMessages();
+ }
+ });
+ clearMessages();
+
+ if (world.model.uiSelections.isInCombat) {
+ view.combatController.enterCombat();
+ view.combatController.setCombatSelection(world.model.uiSelections.selectedMonster, world.model.uiSelections.selectedPosition);
+ }
+
+ view.controller.resume();
+
+ removeDialog(DIALOG_LOADING);
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ addDebugButtons(new DebugButton[] {
+ new DebugButton("Add monster", new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ MonsterType type = world.monsterTypes.getMonsterType("Winged demon");
+ world.model.currentMap.TEST_spawnInArea(world.model.currentMap.spawnAreas[0], type);
+ }
+ })
+ ,new DebugButton("dmg=99", new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ world.model.player.traits.damagePotential.set(99, 99);
+ Toast.makeText(MainActivity.this, "DEBUG: damagePotential=99", Toast.LENGTH_SHORT);
+ }
+ })
+ ,new DebugButton("dmg=1", new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ world.model.player.traits.damagePotential.set(1, 1);
+ Toast.makeText(MainActivity.this, "DEBUG: damagePotential=1", Toast.LENGTH_SHORT);
+ }
+ })
+ ,new DebugButton("exp+=100", new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ world.model.player.addExperience(100);
+ statusview.update();
+ }
+ })
+ ,new DebugButton("gc+=10", new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ world.model.player.inventory.gold += 10;
+ statusview.update();
+ }
+ })
+ });
+ }
+ }
+
+ private class DebugButton {
+ public final String text;
+ public final OnClickListener listener;
+ public DebugButton(String text, OnClickListener listener) {
+ this.text = text;
+ this.listener = listener;
+ }
+ }
+
+ private void addDebugButton(DebugButton button, int id, RelativeLayout layout) {
+ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 30);
+ 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 b = new Button(this);
+ b.setText(button.text);
+ b.setTextSize(getResources().getDimension(R.dimen.smalltext));
+ b.setId(id);
+ b.setOnClickListener(button.listener);
+ layout.addView(b, lp);
+ }
+
+ private void addDebugButtons(DebugButton[] buttons) {
+ if (buttons == null || buttons.length <= 0) return;
+ RelativeLayout layout = (RelativeLayout) findViewById(R.id.main_container);
+
+ int id = 1;
+ for (DebugButton b : buttons) {
+ addDebugButton(b, id, layout);
+ ++id;
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ L.log("onPause");
+ view.controller.pause();
+
+ SharedPreferences p = getSharedPreferences(ModelContainer.PREFERENCE_MODEL_QUICKSAVE, MODE_PRIVATE);
+ SharedPreferences.Editor e = p.edit();
+ world.model.quicksave(e);
+ e.commit();
+
+ WorldSetup.saveWorld(world, getApplicationContext());
+ /*
+ Bundle b = new Bundle();
+ b.putParcelable(ModelContainer.PREFERENCE_MODEL_SAVE, world.model);
+ onSaveInstanceState(b);
+ p = getSharedPreferences(ModelContainer.PREFERENCE_MODEL_SAVE, MODE_PRIVATE);
+ e = p.edit();
+ world.model.save(e);
+ e.commit();
+ */
+
+ //Debug.stopMethodTracing();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ L.log("onResume");
+ if (!AndorsTrailApplication.getApplicationFromActivity(this).setup.isSceneReady) return;
+
+ view.controller.resume();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(final int id) {
+ switch(id) {
+ case DIALOG_LOADING:
+ ProgressDialog dialog = new ProgressDialog(this);
+ dialog.setMessage(getResources().getText(R.string.dialog_loading_message));
+ dialog.setIndeterminate(true);
+ dialog.setCancelable(false);
+ return dialog;
+ }
+ return super.onCreateDialog(id);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(R.string.exit_to_menu)
+ .setIcon(android.R.drawable.ic_menu_close_clear_cancel)
+ .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem arg0) {
+ //Dialogs.showConfirmExit(MainActivity.this, view);
+ MainActivity.this.finish();
+ return true;
+ }
+ });
+ menu.add(R.string.menu_pause)
+ .setIcon(android.R.drawable.ic_media_pause)
+ .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem arg0) {
+ Dialogs.showPaused(MainActivity.this, view);
+ return true;
+ }
+ }).setEnabled(false);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ menu.getItem(1).setEnabled(world.model.uiSelections.isTicking);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ public void redrawAll() {
+ this.mainview.redrawAll();
+ }
+ public void redrawTile(final Coord pos) {
+ this.mainview.redrawTile(pos);
+ }
+ public void message(String msg) {
+ StringBuilder sb = new StringBuilder();
+ for(int i = 0; i < NUM_MESSAGES-1; ++i) {
+ messages[i] = messages[i + 1];
+ if (messages[i].length() > 0) {
+ sb.append(messages[i]);
+ sb.append('\n');
+ }
+ }
+ messages[NUM_MESSAGES-1] = msg;
+ sb.append(msg);
+ statusText.setText(sb.toString());
+ statusText.setVisibility(View.VISIBLE);
+ }
+ public void clearMessages() {
+ for(int i = 0; i < NUM_MESSAGES; ++i) {
+ messages[i] = "";
+ }
+ statusText.setVisibility(View.GONE);
+ }
+
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java
new file mode 100644
index 000000000..5bdcdd60e
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java
@@ -0,0 +1,72 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+
+public final class MonsterEncounterActivity extends Activity {
+ private WorldContext world;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ Uri uri = getIntent().getData();
+ String monsterTypeID = uri.getLastPathSegment().toString();
+ final MonsterType monsterType = world.monsterTypes.getMonsterType(Integer.parseInt(monsterTypeID));
+
+ setContentView(R.layout.monsterencounter);
+
+ CharSequence difficulty = getText(MonsterInfoActivity.getMonsterDifficultyResource(world, monsterType));
+
+ TextView tv = (TextView) findViewById(R.id.monsterencounter_title);
+ tv.setText(monsterType.name);
+
+ tv = (TextView) findViewById(R.id.monsterencounter_description);
+ tv.setText(getString(R.string.dialog_monsterencounter_message, difficulty));
+
+ ImageView iw = (ImageView) findViewById(R.id.monsterencounter_image);
+ iw.setImageBitmap(world.tileStore.bitmaps[monsterType.iconID]);
+
+ Button b = (Button) findViewById(R.id.monsterencounter_attack);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ setResult(RESULT_OK);
+ MonsterEncounterActivity.this.finish();
+ }
+ });
+ b = (Button) findViewById(R.id.monsterencounter_cancel);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ setResult(RESULT_CANCELED);
+ MonsterEncounterActivity.this.finish();
+ }
+ });
+ b = (Button) findViewById(R.id.monsterencounter_info);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ Dialogs.showMonsterInfo(MonsterEncounterActivity.this, monsterType.id);
+ }
+ });
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java
new file mode 100644
index 000000000..346b98c52
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java
@@ -0,0 +1,74 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+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.CombatController;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.util.Range;
+import com.gpl.rpg.AndorsTrail.view.RangeBar;
+import com.gpl.rpg.AndorsTrail.view.TraitsInfoView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public final class MonsterInfoActivity extends Activity {
+ private WorldContext world;
+ private MonsterType monsterType;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ String monsterTypeID = getIntent().getData().getLastPathSegment().toString();
+ this.monsterType = world.monsterTypes.getMonsterType(Integer.parseInt(monsterTypeID));
+
+ setContentView(R.layout.monsterinfo);
+
+ ImageView img = (ImageView) findViewById(R.id.monsterinfo_image);
+ img.setImageBitmap(world.tileStore.bitmaps[monsterType.iconID]);
+ TextView tv = (TextView) findViewById(R.id.monsterinfo_title);
+ tv.setText(monsterType.name);
+ tv = (TextView) findViewById(R.id.monsterinfo_difficulty);
+ tv.setText(getMonsterDifficultyResource(world, monsterType));
+
+ /*
+ tv = (TextView) findViewById(R.id.monsterinfo_apt);
+ tv.setText(Integer.toString(monsterType.getAttacksPerTurn()));
+ tv = (TextView) findViewById(R.id.monsterinfo_mpt);
+ tv.setText(Integer.toString(monsterType.getMovesPerTurn()));
+ */
+
+ Button b = (Button) findViewById(R.id.monsterinfo_close);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ MonsterInfoActivity.this.finish();
+ }
+ });
+
+ ((TraitsInfoView) findViewById(R.id.monsterinfo_currenttraits)).update(monsterType);
+ RangeBar hp = (RangeBar) findViewById(R.id.monsterinfo_healthbar);
+ hp.init(R.drawable.ui_progress_health, R.string.status_hp);
+ hp.update(new Range(monsterType.maxHP, monsterType.maxHP)); //TODO: Should show actual monster HP.
+ }
+
+ public static int getMonsterDifficultyResource(WorldContext world, MonsterType monsterType) {
+ final int difficulty = CombatController.getMonsterDifficulty(world, monsterType);
+ if (difficulty >= 80) return R.string.monster_difficulty_veryeasy;
+ else if (difficulty >= 60) return R.string.monster_difficulty_easy;
+ else if (difficulty >= 40) return R.string.monster_difficulty_normal;
+ else if (difficulty >= 20) return R.string.monster_difficulty_hard;
+ else return R.string.monster_difficulty_veryhard;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java
new file mode 100644
index 000000000..854dbe163
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java
@@ -0,0 +1,196 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import android.app.TabActivity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Window;
+import android.widget.ListView;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+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.ItemController;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.view.ShopItemContainerAdapter;
+import com.gpl.rpg.AndorsTrail.view.ShopItemContainerAdapter.OnContainerItemClickedListener;
+
+public class ShopActivity extends TabActivity implements OnContainerItemClickedListener {
+
+ private WorldContext world;
+ private Player player;
+
+ private ListView shoplist_buy;
+ private ListView shoplist_sell;
+ private ItemContainer container_buy;
+ private ItemContainer container_sell;
+ private TextView shop_buy_gc;
+ private TextView shop_sell_gc;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ this.world = app.world;
+ this.player = world.model.player;
+
+ Uri uri = getIntent().getData();
+ String monsterTypeID = uri.getLastPathSegment().toString();
+ final MonsterType npcType = world.monsterTypes.getMonsterType(Integer.parseInt(monsterTypeID));
+
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ final Player player = world.model.player;
+
+ setContentView(R.layout.shop);
+
+ final Resources res = getResources();
+
+ TabHost h = getTabHost();
+ h.addTab(h.newTabSpec("buy")
+ .setIndicator(res.getString(R.string.shop_buy))
+ .setContent(R.id.shop_tab1));
+ h.addTab(h.newTabSpec("sell")
+ .setIndicator(res.getString(R.string.shop_sell))
+ .setContent(R.id.shop_tab2));
+ h.setup();
+ shop_buy_gc = (TextView) h.findViewById(R.id.shop_buy_gc);
+ shop_sell_gc = (TextView) h.findViewById(R.id.shop_sell_gc);
+
+ shoplist_buy = (ListView) h.findViewById(R.id.shop_buy_list);
+ /*
+ shoplist_buy.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ int itemTypeID = (int) id;
+ ItemType itemType = world.itemTypes.getItemType(itemTypeID);
+ int price = ItemController.getBuyingPrice(player, itemType);
+ String text = res.getString(R.string.shop_buyitem, price);
+ Dialogs.showItemInfo(ShopActivity.this, itemTypeID, ItemInfoActivity.ITEMACTION_BUY, text, ItemController.canAfford(player, price), -1);
+ }
+ });
+ */
+ shoplist_sell = (ListView) h.findViewById(R.id.shop_sell_list);
+ /*
+ shoplist_sell.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ int itemTypeID = (int) id;
+ ItemType itemType = world.itemTypes.getItemType(itemTypeID);
+ int price = ItemController.getBuyingPrice(player, itemType);
+ String text = res.getString(R.string.shop_sellitem, price);
+ Dialogs.showItemInfo(ShopActivity.this, itemTypeID, ItemInfoActivity.ITEMACTION_SELL, text, true, -1);
+ }
+ });
+ */
+
+ Loot merchantLoot = new Loot();
+ npcType.dropList.createRandomLoot(merchantLoot);
+ container_buy = merchantLoot.items;
+ container_sell = player.inventory;
+
+ shoplist_buy.setAdapter(new ShopItemContainerAdapter(
+ this
+ , world.tileStore
+ , player
+ , container_buy
+ , this
+ , false));
+ shoplist_sell.setAdapter(new ShopItemContainerAdapter(
+ this
+ , world.tileStore
+ , player
+ , container_sell
+ , this
+ , true));
+
+ update();
+ }
+
+ @Override
+ public void onItemActionClicked(int position, ItemType itemType, boolean isSelling) {
+ if (isSelling) {
+ sell(itemType);
+ } else {
+ buy(itemType);
+ }
+ }
+
+ @Override
+ public void onItemInfoClicked(int position, ItemType itemType, boolean isSelling) {
+ int price;
+ int resid;
+ boolean enableButton = true;
+ int action;
+ if (isSelling) {
+ resid = R.string.shop_sellitem;
+ action = ItemInfoActivity.ITEMACTION_SELL;
+ price = ItemController.getSellingPrice(player, itemType);
+ enableButton = ItemController.maySellItem(player, itemType);
+ } else {
+ resid = R.string.shop_buyitem;
+ action = ItemInfoActivity.ITEMACTION_BUY;
+ price = ItemController.getBuyingPrice(player, itemType);
+ enableButton = ItemController.canAfford(player, price);
+ }
+ String text = getResources().getString(resid, price);
+ Dialogs.showItemInfo(ShopActivity.this, itemType.id, action, text, enableButton, -1);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case MainActivity.INTENTREQUEST_ITEMINFO:
+ if (resultCode != RESULT_OK) return;
+
+ ItemType itemType = world.itemTypes.getItemType(data.getExtras().getInt("itemTypeID"));
+ int actionType = data.getExtras().getInt("actionType");
+ if (actionType == ItemInfoActivity.ITEMACTION_BUY) {
+ buy(itemType);
+ } else if (actionType == ItemInfoActivity.ITEMACTION_SELL) {
+ sell(itemType);
+ }
+ break;
+ }
+ }
+
+ private void sell(ItemType itemType) {
+ ItemController.sell(player, itemType, container_buy);
+ update();
+ }
+
+ private void buy(ItemType itemType) {
+ ItemController.buy(player, itemType, container_buy);
+ update();
+ }
+
+ private void update() {
+ updateBuyItemList();
+ updateSellItemList();
+ updateGc();
+ }
+
+ private void updateGc() {
+ String gc = getResources().getString(R.string.shop_yourgold, player.inventory.gold);
+ shop_buy_gc.setText(gc);
+ shop_sell_gc.setText(gc);
+ }
+
+ private void updateBuyItemList() {
+ ((ShopItemContainerAdapter) shoplist_buy.getAdapter()).notifyDataSetChanged();
+ }
+ private void updateSellItemList() {
+ ((ShopItemContainerAdapter) shoplist_sell.getAdapter()).notifyDataSetChanged();
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java
new file mode 100644
index 000000000..3b662b7d5
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java
@@ -0,0 +1,177 @@
+package com.gpl.rpg.AndorsTrail.activity;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.WorldSetup;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class StartScreenActivity extends Activity {
+ private boolean hasExistingGame = false;
+ private Button startscreen_continue;
+ private Button startscreen_newgame;
+ private TextView startscreen_currenthero;
+ private EditText startscreen_enterheroname;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.startscreen);
+
+ startscreen_currenthero = (TextView) findViewById(R.id.startscreen_currenthero);
+ startscreen_enterheroname = (EditText) findViewById(R.id.startscreen_enterheroname);
+ startscreen_enterheroname.setImeOptions(EditorInfo.IME_ACTION_DONE);
+
+ startscreen_continue = (Button) findViewById(R.id.startscreen_continue);
+ startscreen_continue.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ continueGame(false, null);
+ }
+ });
+
+ startscreen_newgame = (Button) findViewById(R.id.startscreen_newgame);
+ startscreen_newgame.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ if (hasExistingGame) {
+ comfirmNewGame();
+ } else {
+ createNewGame();
+ }
+ }
+ });
+
+ Button b = (Button) findViewById(R.id.startscreen_about);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ startActivity(new Intent(StartScreenActivity.this, AboutActivity.class));
+ }
+ });
+
+ b = (Button) findViewById(R.id.startscreen_quit);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ //comfirmQuit();
+ StartScreenActivity.this.finish();
+ }
+ });
+
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
+ app.setup.startResourceLoader(getResources());
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ continueGame(true, "Debug player");
+ }
+ }
+
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ ModelContainer model = new ModelContainer();
+ hasExistingGame = model.quickload(getSharedPreferences(ModelContainer.PREFERENCE_MODEL_QUICKSAVE, MODE_PRIVATE));
+
+ setButtonState(model.player);
+
+ if (isNewVersion()) {
+ Dialogs.showNewVersion(this);
+ }
+ }
+
+ private boolean isNewVersion() {
+ final String v = "lastversion";
+ SharedPreferences s = getSharedPreferences(ModelContainer.PREFERENCE_MODEL_LASTRUNVERSION, MODE_PRIVATE);
+ int lastversion = s.getInt(v, 0);
+ if (lastversion >= ModelContainer.CURRENT_VERSION) return false;
+ Editor e = s.edit();
+ e.putInt(v, ModelContainer.CURRENT_VERSION);
+ e.commit();
+ return true;
+ }
+
+
+ private void setButtonState(final Player player) {
+ startscreen_continue.setEnabled(hasExistingGame);
+ startscreen_newgame.setEnabled(true);
+ if (hasExistingGame) {
+ startscreen_currenthero.setText(getResources().getString(R.string.startscreen_currenthero, player.traits.name, player.level));
+ startscreen_enterheroname.setVisibility(View.GONE);
+ } else {
+ startscreen_currenthero.setText(R.string.startscreen_enterheroname);
+ startscreen_enterheroname.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void continueGame(boolean createNewCharacter, String name) {
+ final WorldSetup setup = AndorsTrailApplication.getApplicationFromActivity(this).setup;
+ setup.createNewCharacter = createNewCharacter;
+ setup.newHeroName = name;
+ startActivity(new Intent(this, MainActivity.class));
+ }
+
+ private void createNewGame() {
+ String name = startscreen_enterheroname.getText().toString().trim();
+ if (name == null || name.length() <= 0) {
+ Toast.makeText(this, R.string.startscreen_enterheroname, Toast.LENGTH_SHORT);
+ return;
+ }
+ continueGame(true, name);
+ }
+
+ private void comfirmNewGame() {
+ new AlertDialog.Builder(this)
+ .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);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create().show();
+ }
+
+ /*
+ private void comfirmQuit() {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.dialog_confirmexit_title)
+ .setMessage(R.string.dialog_confirmexit_message)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ StartScreenActivity.this.finish();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create().show();
+ }
+ */
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/ViewContext.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/ViewContext.java
new file mode 100644
index 000000000..f2fc619e9
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/ViewContext.java
@@ -0,0 +1,35 @@
+package com.gpl.rpg.AndorsTrail.context;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.activity.MainActivity;
+import com.gpl.rpg.AndorsTrail.controller.CombatController;
+import com.gpl.rpg.AndorsTrail.controller.Controller;
+import com.gpl.rpg.AndorsTrail.controller.EffectController;
+import com.gpl.rpg.AndorsTrail.controller.ItemController;
+import com.gpl.rpg.AndorsTrail.controller.MonsterMovementController;
+import com.gpl.rpg.AndorsTrail.controller.MovementController;
+
+public class ViewContext extends WorldContext {
+ //Views
+ public final MainActivity mainActivity;
+
+ //Controllers
+ public final Controller controller;
+ public final CombatController combatController;
+ public final EffectController effectController;
+ public final ItemController itemController;
+ public final MonsterMovementController monsterMovementController;
+ public final MovementController movementController;
+
+ public ViewContext(AndorsTrailApplication application, MainActivity mainActivity) {
+ super(application.world);
+ this.mainActivity = mainActivity;
+
+ this.controller = new Controller(this);
+ this.combatController = new CombatController(this);
+ this.effectController = new EffectController(this);
+ this.itemController = new ItemController(this);
+ this.monsterMovementController = new MonsterMovementController(this);
+ this.movementController = new MovementController(this);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java
new file mode 100644
index 000000000..1c1464ea6
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java
@@ -0,0 +1,50 @@
+package com.gpl.rpg.AndorsTrail.context;
+
+import com.gpl.rpg.AndorsTrail.EffectCollection;
+import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
+import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
+import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
+import com.gpl.rpg.AndorsTrail.model.map.MapCollection;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+
+public class WorldContext {
+ //Objectcollections
+ public final ConversationCollection conversations;
+ public final ItemTypeCollection itemTypes;
+ public final MonsterTypeCollection monsterTypes;
+ public final EffectCollection effectTypes;
+ public final DropListCollection dropLists;
+
+ //Objectcollections
+ public final TileStore tileStore;
+
+ //Model
+ public final MapCollection maps;
+ public ModelContainer model;
+
+ public WorldContext() {
+ this.conversations = new ConversationCollection();
+ this.itemTypes = new ItemTypeCollection();
+ this.monsterTypes = new MonsterTypeCollection();
+ this.effectTypes = new EffectCollection();
+ this.dropLists = new DropListCollection();
+ this.tileStore = new TileStore();
+ this.maps = new MapCollection();
+ //this.model = new ModelContainer();
+ }
+ public WorldContext(WorldContext copy) {
+ this.conversations = copy.conversations;
+ this.itemTypes = copy.itemTypes;
+ this.monsterTypes = copy.monsterTypes;
+ this.effectTypes = copy.effectTypes;
+ this.dropLists = copy.dropLists;
+ this.tileStore = copy.tileStore;
+ this.maps = copy.maps;
+ this.model = copy.model;
+ }
+ public void reset() {
+ maps.reset();
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java
new file mode 100644
index 000000000..30085b058
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/CombatController.java
@@ -0,0 +1,344 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import java.util.ArrayList;
+
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.EffectCollection;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.AttackResult;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Actor;
+import com.gpl.rpg.AndorsTrail.model.actor.ActorTraits;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredWorldMap;
+import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class CombatController {
+ private final ViewContext context;
+ private final WorldContext world;
+ private final ModelContainer model;
+
+ private Monster currentActiveMonster = null;
+ private final ArrayList killedMonsters = new ArrayList();
+
+ public CombatController(ViewContext context) {
+ this.context = context;
+ this.world = context;
+ this.model = world.model;
+ }
+
+ public void enterCombat() {
+ context.mainActivity.combatview.setVisibility(View.VISIBLE);
+ context.mainActivity.combatview.bringToFront();
+ model.uiSelections.isInCombat = true;
+ killedMonsters.clear();
+ context.mainActivity.clearMessages();
+ newPlayerTurn();
+ }
+ public void exitCombat() {
+ setCombatSelection(null, null);
+ context.mainActivity.combatview.setVisibility(View.GONE);
+ model.uiSelections.isInCombat = false;
+ context.mainActivity.clearMessages();
+ currentActiveMonster = null;
+ if (!killedMonsters.isEmpty()) {
+ lootMonsters(killedMonsters);
+ killedMonsters.clear();
+ }
+ context.controller.queueAnotherTick();
+ }
+
+ private void lootMonsters(ArrayList killedMonsters) {
+ Loot loot = model.currentMap.getBagOrCreateAt(killedMonsters.get(0).position);
+ for(Monster m : killedMonsters) {
+ m.createLoot(loot);
+ model.statistics.addMonsterKill(m.monsterType);
+ }
+ if (loot.isEmpty()) return;
+ Dialogs.showMonsterLoot(context.mainActivity, context, loot);
+ ItemController.consumeLoot(loot, model.player);
+ context.mainActivity.statusview.update();
+ }
+
+ public boolean isMonsterTurn() {
+ return currentActiveMonster != null;
+ }
+
+ public void setCombatSelection(Monster selectedMonster, Coord selectedPosition) {
+ if (selectedMonster != null) {
+ if (!selectedMonster.monsterType.isAgressive()) return;
+ }
+ Coord previousSelection = model.uiSelections.selectedPosition;
+ if (model.uiSelections.selectedPosition != null) {
+ model.uiSelections.selectedPosition = null;
+ context.mainActivity.redrawTile(previousSelection);
+ }
+ model.uiSelections.selectedMonster = selectedMonster;
+ model.uiSelections.selectedPosition = selectedPosition;
+ context.mainActivity.combatview.updateCombatSelection(selectedMonster, selectedPosition);
+ if (selectedPosition != null) {
+ model.uiSelections.isInCombat = true;
+ context.mainActivity.redrawTile(selectedPosition);
+ }
+ }
+ public void setCombatSelection(Coord p) {
+ LayeredWorldMap map = model.currentMap;
+ Monster m = map.getMonsterAt(p);
+ if (m != null) {
+ setCombatSelection(m, p);
+ } else if (map.isWalkable(p)) {
+ setCombatSelection(null, p);
+ }
+ }
+
+ private void message(String s) {
+ context.mainActivity.message(s);
+ }
+ private boolean useAPs(int cost) {
+ if (model.player.useAPs(cost)) {
+ context.mainActivity.combatview.updatePlayerAP(model.player.ap);
+ return true;
+ } else {
+ message(context.mainActivity.getResources().getString(R.string.combat_not_enough_ap));
+ return false;
+ }
+ }
+
+ public boolean canExitCombat() { return getAdjacentMonster() == null; }
+ private Monster getAdjacentMonster() {
+ for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ if (!m.monsterType.isAgressive()) continue;
+ if (m.rectPosition.isAdjacentTo(model.player.position)) {
+ return m;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void executeMoveAttack() {
+ if (world.model.uiSelections.selectedMonster != null) {
+ executeAttack();
+ } else if (world.model.uiSelections.selectedPosition != null) {
+ executeMove();
+ } else if (canExitCombat()) {
+ exitCombat();
+ }
+ }
+
+ private void executeAttack() {
+ if (!useAPs(model.player.traits.attackCost)) return;
+ Monster target = model.uiSelections.selectedMonster;
+
+ AttackResult attack = playerAttacks(model, target);
+ Resources r = context.mainActivity.getResources();
+ if (attack.isHit) {
+ String msg;
+
+ final String monsterName = target.traits.name;
+ if (attack.isCriticalHit) {
+ msg = r.getString(R.string.combat_result_herohitcritical, monsterName, attack.damage);
+ } else {
+ msg = r.getString(R.string.combat_result_herohit, monsterName, attack.damage);
+ }
+ if (attack.targetDied) {
+ msg += " " + r.getString(R.string.combat_result_herokillsmonster, monsterName, attack.damage);
+ }
+ message(msg);
+ context.effectController.startEffect(
+ context.mainActivity.mainview
+ , model.uiSelections.selectedPosition
+ , EffectCollection.EFFECT_BLOOD
+ , attack.damage);
+
+ if (!attack.targetDied) {
+ context.mainActivity.combatview.updateMonsterHealth(target.health);
+ } else {
+ killedMonsters.add(target);
+ Monster nextMonster = getAdjacentMonster();
+ if (nextMonster == null) {
+ exitCombat();
+ } else {
+ setCombatSelection(nextMonster, nextMonster.position);
+ }
+ }
+ } else {
+ message(r.getString(R.string.combat_result_heromiss));
+ }
+
+ if (!attack.isHit || !attack.targetDied) {
+ maybeAutoEndTurn();
+ }
+ }
+
+ private void maybeAutoEndTurn() {
+ if (model.player.ap.current < model.player.useItemCost
+ && model.player.ap.current < model.player.traits.attackCost
+ && model.player.ap.current < model.player.traits.moveCost) {
+ endPlayerTurn();
+ }
+ }
+
+ private void executeMove() {
+ if (model.uiSelections.selectedMonster != null) return;
+ if (model.uiSelections.selectedPosition == null) return;
+ if (!useAPs(model.player.traits.moveCost)) return;
+
+ model.player.nextPosition.set(model.uiSelections.selectedPosition);
+ context.movementController.moveToNextIfPossible(false);
+
+ maybeAutoEndTurn();
+ }
+
+ private final Handler monsterTurnHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ CombatController.this.handleNextMonsterAction();
+ }
+ };
+ public void endPlayerTurn() {
+ model.player.ap.current = 0;
+
+ for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ m.setMaxAP();
+ }
+ }
+
+ handleNextMonsterAction();
+ }
+
+ private Monster determineNextMonster(Monster previousMonster) {
+ if (previousMonster != null) {
+ if (previousMonster.useAPs(previousMonster.traits.attackCost)) return previousMonster;
+ }
+
+ for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ if (!m.monsterType.isAgressive()) continue;
+
+ if (m.rectPosition.isAdjacentTo(model.player.position)) {
+ if (m.useAPs(m.traits.attackCost)) return m;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void handleNextMonsterAction() {
+ currentActiveMonster = determineNextMonster(currentActiveMonster);
+ if (currentActiveMonster == null) {
+ endMonsterTurn();
+ return;
+ }
+ context.mainActivity.combatview.updateTurnInfo(currentActiveMonster);
+ Resources r = context.mainActivity.getResources();
+ AttackResult attack = monsterAttacks(model, currentActiveMonster);
+ String monsterName = currentActiveMonster.traits.name;
+ if (attack.isHit) {
+ context.effectController.startEffect(
+ context.mainActivity.mainview
+ , model.player.position
+ , EffectCollection.EFFECT_BLOOD
+ , attack.damage);
+ if (attack.isCriticalHit) {
+ message(r.getString(R.string.combat_result_monsterhitcritical, monsterName, attack.damage));
+ } else {
+ message(r.getString(R.string.combat_result_monsterhit, monsterName, attack.damage));
+ }
+ if (attack.targetDied) {
+ exitCombat();
+ context.controller.handlePlayerDeath();
+ return;
+ }
+ } else {
+ message(r.getString(R.string.combat_result_monstermiss, monsterName));
+ }
+ context.mainActivity.statusview.update();
+ monsterTurnHandler.sendEmptyMessageDelayed(0, ModelContainer.monsterAttackDelay);
+ }
+
+ private void endMonsterTurn() {
+ newPlayerTurn();
+ }
+
+ private void newPlayerTurn() {
+ currentActiveMonster = null;
+ model.player.ap.setMax();
+ context.mainActivity.combatview.updateTurnInfo(null);
+ context.mainActivity.combatview.updatePlayerAP(model.player.ap);
+ }
+
+ private static float getAverageDamagePerHit(ActorTraits attacker, ActorTraits target) {
+ float result = (float) (attacker.attackChance - target.blockChance) * attacker.damagePotential.average() / 100;
+ result += (float) attacker.criticalChance * result * attacker.criticalMultiplier / 100;
+ result -= target.damageResistance;
+ return result;
+ }
+ private static float getAverageDamagePerTurn(ActorTraits attacker, ActorTraits target) {
+ return getAverageDamagePerHit(attacker, target) * attacker.getAttacksPerTurn();
+ }
+ private static int getTurnsToKillTarget(ActorTraits attacker, ActorTraits target) {
+ float averageDamagePerTurn = getAverageDamagePerTurn(attacker, target);
+ if (averageDamagePerTurn == 0) return 100;
+ return (int) Math.ceil(target.maxHP / averageDamagePerTurn);
+ }
+ public static int getMonsterDifficulty(WorldContext world, MonsterType monsterType) {
+ // returns [0..100) . 100 == easy.
+ int turnsToKillMonster = getTurnsToKillTarget(world.model.player.traits, monsterType);
+ int turnsToKillPlayer = getTurnsToKillTarget(monsterType, world.model.player.traits);
+ int result = 50 + (turnsToKillPlayer - turnsToKillMonster) * 2;
+ if (result < 0) result = 0;
+ else if (result > 100) result = 100;
+ return result;
+ }
+
+ public AttackResult playerAttacks(ModelContainer model, Monster currentMonster) {
+ AttackResult result = attack(model.player, currentMonster);
+
+ if (result.targetDied) {
+ model.currentMap.remove(currentMonster);
+ }
+
+ return result;
+ }
+
+ public AttackResult monsterAttacks(ModelContainer model, Monster currentMonster) {
+ return attack(currentMonster, model.player);
+ }
+
+
+ private static AttackResult attack(final Actor attacker, final Actor target) {
+ int hitChance = attacker.traits.attackChance - target.traits.blockChance;
+ if (!ModelContainer.roll100(hitChance)) return AttackResult.MISS;
+
+ int damage = ModelContainer.rollValue(attacker.traits.damagePotential);
+ boolean isCriticalHit = false;
+ if (attacker.traits.hasCriticalEffect()) {
+ isCriticalHit = ModelContainer.roll100(attacker.traits.criticalChance);
+ if (isCriticalHit) {
+ damage *= attacker.traits.criticalMultiplier;
+ }
+ }
+ damage -= target.traits.damageResistance;
+ target.health.subtract(damage, false);
+
+ return new AttackResult(true, isCriticalHit, damage, target.health.current <= 0);
+ }
+
+ public void monsterSteppedOnPlayer(Monster m) {
+ enterCombat();
+ endPlayerTurn();
+ setCombatSelection(m, m.position);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/Controller.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/Controller.java
new file mode 100644
index 000000000..59ad714a5
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/Controller.java
@@ -0,0 +1,144 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.activity.MainActivity;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.map.KeyArea;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredWorldMap;
+import com.gpl.rpg.AndorsTrail.model.map.MapObject;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class Controller {
+ private static final int PERCENT_EXP_LOST_WHEN_DIED = 30;
+ public static final int LEVELUP_EFFECT_HEALTH = 5;
+ public static final int LEVELUP_EFFECT_ATK_CH = 5;
+ public static final int LEVELUP_EFFECT_ATK_DMG = 1;
+ public static final int LEVELUP_EFFECT_DEF_CH = 3;
+
+ private final ViewContext view;
+ private final WorldContext world;
+ private final ModelContainer model;
+
+ private boolean hasQueuedTick = false;
+ //private final int id;
+
+ public Controller(ViewContext context) {
+ this.view = context;
+ this.world = context;
+ this.model = world.model;
+ //this.id = ModelContainer.rnd.nextInt();
+ }
+
+ private final RefreshHandler mTickHandler = new RefreshHandler();
+ private class RefreshHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message msg) {
+ hasQueuedTick = false;
+ Controller.this.tick();
+ }
+
+ public void sleep(long delayMillis) {
+ this.removeMessages(0);
+ sendMessageDelayed(obtainMessage(0), delayMillis);
+ }
+ };
+
+ public void queueAnotherTick() {
+ if (hasQueuedTick) return;
+ hasQueuedTick = true;
+ mTickHandler.sleep(ModelContainer.tickDelay);
+ }
+
+ private void tick() {
+ //L.log(id + " : Controller::tick()");
+ if (!model.uiSelections.isTicking) return;
+ if (model.uiSelections.isInCombat) return;
+
+ boolean hasChanged = false;
+ if (view.monsterMovementController.moveMonsters()) hasChanged = true;
+ if (model.currentMap.maybeSpawn(world)) hasChanged = true;
+
+ if (hasChanged) view.mainActivity.redrawAll(); //TODO: should only redraw spawned tiles
+
+ queueAnotherTick();
+ }
+
+ public void resume() {
+ //L.log(id + " : Controller::resume()");
+ model.uiSelections.isTicking = true;
+ queueAnotherTick();
+ }
+ public void pause() {
+ //L.log(id + " : Controller::pause()");
+ model.uiSelections.isTicking = false;
+ }
+
+ public void handleMapEvent(MapObject o) {
+ switch (o.type) {
+ case MapObject.MAPEVENT_SIGN:
+ if (o.text == null) return;
+ Dialogs.showMapSign(view.mainActivity, view, o.title, o.text);
+ break;
+ case MapObject.MAPEVENT_NEWMAP:
+ if (o.map == null || o.place == null) return;
+ view.movementController.placePlayerAt(o.map, o.place);
+ break;
+ case MapObject.MAPEVENT_REST:
+ Dialogs.showRest(view.mainActivity, view);
+ break;
+ }
+ }
+
+ public void steppedOnMonster(Monster m, Coord p) {
+ if (m.monsterType.isAgressive()) {
+ view.combatController.setCombatSelection(m, p);
+ Dialogs.showMonsterEncounter(view.mainActivity, m);
+ } else {
+ Dialogs.showConversation(view.mainActivity, m.monsterType.phraseID, m);
+ }
+ }
+
+ public void handlePlayerDeath() {
+ final Player player = model.player;
+ int lostExp = player.levelExperience.current / (100 / PERCENT_EXP_LOST_WHEN_DIED);
+ player.addExperience(-lostExp);
+ model.statistics.addPlayerDeath(lostExp);
+ playerRested(world, false);
+ MovementController.respawnPlayer(world);
+ final MainActivity act = view.mainActivity;
+ act.mainview.notifyMapChanged();
+ act.message(act.getResources().getString(R.string.combat_hero_dies, lostExp));
+ act.statusview.update();
+ }
+
+ public static void playerRested(final WorldContext world, boolean respawnUniqueMonsters) {
+ final Player player = world.model.player;
+ player.setMaxAP();
+ player.setMaxHP();
+ for (LayeredWorldMap m : world.maps.predefinedMaps) {
+ m.spawnAll(world, respawnUniqueMonsters);
+ }
+ }
+
+ public boolean handleKeyArea(KeyArea area) {
+ if (view.model.player.hasKey(area.requiredKey)) return true;
+ final Context androidContext = view.mainActivity;
+
+ String message = area.message;
+ if (message == null || message.length() == 0) {
+ message = androidContext.getResources().getString(R.string.key_required);
+ }
+ view.mainActivity.message(message);
+ return false;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java
new file mode 100644
index 000000000..54e97ce39
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java
@@ -0,0 +1,41 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import com.gpl.rpg.AndorsTrail.conversation.Phrase;
+import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+
+public class ConversationController {
+
+ public static void applyPhraseEffect(final Player player, final Phrase phrase) {
+ if (phrase.enablesKey != null) player.addKey(phrase.enablesKey);
+ if (phrase.rewardExperience > 0) player.addExperience(phrase.rewardExperience);
+ if (phrase.rewardGold > 0) player.inventory.gold += phrase.rewardGold;
+ }
+
+ public static void applyReplyEffect(final Player player, final Reply reply) {
+ if (reply.requiresItemTypeID > 0 && reply.requiresItemQuantity > 0) {
+ player.inventory.removeItem(reply.requiresItemTypeID, reply.requiresItemQuantity);
+ }
+ }
+
+ public static boolean canSelectReply(final Player player, final Reply reply) {
+ if (!hasRequiredKey(player, reply.requiresKey)) return false;
+ if (!hasRequiredItems(player, reply.requiresItemTypeID, reply.requiresItemQuantity)) return false;
+ return true;
+ }
+
+ private static boolean hasRequiredKey(final Player player, final String key) {
+ if (key == null) return true;
+ if (key.startsWith("!")) {
+ return !player.hasKey(key.substring(1));
+ } else {
+ return player.hasKey(key);
+ }
+ }
+
+ private static boolean hasRequiredItems(final Player player, int requiresItemTypeID, int requiresItemQuantity) {
+ if (requiresItemTypeID <= 0) return true;
+ if (requiresItemQuantity <= 0) return true;
+ return player.inventory.hasItem(requiresItemTypeID, requiresItemQuantity);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/EffectController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/EffectController.java
new file mode 100644
index 000000000..bd9c98d7e
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/EffectController.java
@@ -0,0 +1,100 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+
+import com.gpl.rpg.AndorsTrail.EffectCollection;
+import com.gpl.rpg.AndorsTrail.EffectCollection.Effect;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.Size;
+import com.gpl.rpg.AndorsTrail.view.MainView;
+
+public final class EffectController {
+ private EffectAnimation currentEffect;
+
+ private final EffectCollection effectTypes;
+ public EffectController(WorldContext world) {
+ this.effectTypes = world.effectTypes;
+ }
+
+ public void startEffect(MainView mainview, Coord position, int effectID, int displayValue) {
+ EffectAnimation e = currentEffect;
+ if (e != null) {
+ e.killjoin();
+ }
+ currentEffect = new EffectAnimation(effectTypes.effects[effectID], position, mainview, displayValue);
+ currentEffect.start();
+ }
+
+ public final class EffectAnimation extends Thread {
+
+ @Override
+ public void run() {
+ while (isAlive) {
+ update();
+ try {
+ sleep(8);
+ } catch (InterruptedException e) {
+ isAlive = false;
+ }
+ }
+ view.redrawFromDoubleBuffer();
+ EffectController.this.currentEffect = null;
+ }
+
+ public void killjoin() {
+ isAlive = false;
+ try {
+ join();
+ } catch (InterruptedException e) {}
+ }
+ private void update() {
+ int elapsed = (int)(System.currentTimeMillis() - startTime);
+ if (elapsed > effect.duration) {
+ isAlive = false;
+ return;
+ }
+
+ int currentFrame = (int) Math.floor((float)elapsed / effect.millisecondPerFrame);
+ setCurrentTile(currentFrame);
+ }
+
+ private final Effect effect;
+ private final long startTime;
+ private final MainView view;
+
+ public final Coord position;
+ private final CoordRect area;
+ public final String displayText;
+ public final Paint textPaint = new Paint();
+ public int currentTileID = 0;
+ public int textYOffset = 0;
+ private boolean isAlive = false;
+
+ public EffectAnimation(Effect effect, Coord position, MainView view, int displayValue) {
+ this.position = position;
+ this.area = new CoordRect(new Coord(position.x, position.y - 1), new Size(1, 2));
+ this.effect = effect;
+ this.displayText = (displayValue == 0) ? null : String.valueOf(displayValue);
+ this.textPaint.setColor(effect.textColor);
+ this.textPaint.setShadowLayer(1, 1, 1, Color.DKGRAY);
+ this.isAlive = true;
+ this.startTime = System.currentTimeMillis();
+ this.view = view;
+ setCurrentTile(0);
+ }
+
+ private void setCurrentTile(int currentFrame) {
+ if (currentFrame > effect.lastFrame) currentFrame = effect.lastFrame;
+ int newTileID = effect.frameIconIDs[currentFrame];
+ final boolean changed = newTileID != this.currentTileID;
+ this.currentTileID = newTileID;
+ this.textYOffset = -2 * (currentFrame);
+ if (changed) {
+ view.redrawTileWithEffect(area, this);
+ }
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ItemController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ItemController.java
new file mode 100644
index 000000000..d455a4cc7
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ItemController.java
@@ -0,0 +1,151 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.EffectCollection;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Actor;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+
+public final class ItemController {
+ private static final int MARKET_PRICEFACTOR_PERCENT = 15;
+
+ private final ViewContext view;
+ private final WorldContext world;
+ private final ModelContainer model;
+
+ public ItemController(ViewContext context) {
+ this.view = context;
+ this.world = context;
+ this.model = world.model;
+ }
+
+ public void dropItem(ItemType type) {
+ model.player.inventory.removeItem(type.id, 1);
+ model.currentMap.itemDropped(type, 1, model.player.position);
+ //message(androidContext, androidContext.getResources().getString(R.string.inventory_item_dropped, t.name));
+ }
+
+ public void equipItem(ItemType type) {
+ if (!type.isEquippable()) return;
+ final Player player = model.player;
+ if (model.uiSelections.isInCombat) {
+ if (!player.useAPs(player.reequipCost)) return;
+ }
+
+ int slot = type.category;
+ if (slot == ItemType.CATEGORY_WEARABLE_RING) {
+ if (!player.inventory.isEmptySlot(slot)) {
+ ++slot;
+ }
+ }
+
+ if (!player.inventory.removeItem(type.id, 1)) return;
+
+ if (!player.inventory.isEmptySlot(slot)) {
+ player.inventory.addItem(player.inventory.wear[slot]);
+ }
+ player.inventory.wear[slot] = type;
+ player.recalculateCombatTraits();
+
+ //message(androidContext, androidContext.getResources().getString(R.string.inventory_item_equipped, t.name));
+ }
+
+ public void unequipSlot(ItemType type, int slot) {
+ if (!type.isEquippable()) return;
+ final Player player = model.player;
+ if (player.inventory.isEmptySlot(slot)) return;
+
+ if (model.uiSelections.isInCombat) {
+ if (!player.useAPs(player.reequipCost)) return;
+ }
+
+ player.inventory.addItem(player.inventory.wear[slot]);
+ player.inventory.wear[slot] = null;
+ player.recalculateCombatTraits();
+
+ //message(androidContext, androidContext.getResources().getString(R.string.inventory_item_unequipped, t.name));
+ }
+
+ public void useItem(ItemType type) {
+ if (!type.isUsable()) return;
+ final Player player = model.player;
+ if (model.uiSelections.isInCombat) {
+ if (!player.useAPs(player.useItemCost)) return;
+ }
+
+ player.inventory.removeItem(type.id, 1);
+ applyUseEffect(player, type);
+
+ //TODO: provide feedback that the item has been used.
+ //context.mainActivity.message(androidContext.getResources().getString(R.string.inventory_item_used, type.name));
+ }
+
+ public void handleLootBag(Loot loot) {
+ Dialogs.showGroundLoot(view.mainActivity, view, loot);
+ consumeLoot(loot, model.player);
+ }
+
+ private void applyUseEffect(Actor actor, ItemType t) {
+ if (t.effect_ap != null) {
+ int value = ModelContainer.rollValue(t.effect_ap);
+ actor.ap.add(value, false);
+ view.effectController.startEffect(
+ view.mainActivity.mainview
+ , model.player.position
+ , EffectCollection.EFFECT_RESTORE_AP
+ , value);
+ }
+ if (t.effect_health != null) {
+ int value = ModelContainer.rollValue(t.effect_health);
+ actor.health.add(value, false);
+ view.effectController.startEffect(
+ view.mainActivity.mainview
+ , model.player.position
+ , EffectCollection.EFFECT_RESTORE_HP
+ , value);
+ }
+ }
+
+ public static void consumeLoot(Loot loot, Player player) {
+ player.addExperience(loot.exp);
+ loot.exp = 0;
+ player.inventory.gold += loot.gold;
+ loot.gold = 0;
+ }
+
+ public static int getBuyingPrice(Player player, ItemType itemType) {
+ return itemType.baseMarketCost * (100 + MARKET_PRICEFACTOR_PERCENT) / 100;
+ }
+ public static int getSellingPrice(Player player, ItemType itemType) {
+ return itemType.baseMarketCost * (100 - MARKET_PRICEFACTOR_PERCENT) / 100;
+ }
+
+ public static boolean canAfford(Player player, ItemType itemType) {
+ return player.inventory.gold >= getBuyingPrice(player, itemType);
+ }
+ public static boolean canAfford(Player player, int price) {
+ return player.inventory.gold >= price;
+ }
+ public static boolean maySellItem(Player player, ItemType itemType) {
+ if (itemType.isQuestItem()) return false;
+ return true;
+ }
+ public static void sell(Player player, ItemType itemType, ItemContainer merchant) {
+ int price = getSellingPrice(player, itemType);
+ player.inventory.gold += price;
+ player.inventory.removeItem(itemType.id);
+ merchant.addItem(itemType);
+ }
+ public static void buy(Player player, ItemType itemType, ItemContainer merchant) {
+ int price = getBuyingPrice(player, itemType);
+ if (!canAfford(player, price)) return;
+ player.inventory.gold -= price;
+ player.inventory.addItem(itemType);
+ merchant.removeItem(itemType.id);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.java
new file mode 100644
index 000000000..2050cd233
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MonsterMovementController.java
@@ -0,0 +1,94 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+
+public final class MonsterMovementController {
+ private final ViewContext view;
+ private final WorldContext world;
+ private final ModelContainer model;
+
+ public MonsterMovementController(ViewContext context) {
+ this.view = context;
+ this.world = context;
+ this.model = world.model;
+ }
+
+ public boolean moveMonsters() {
+ boolean hasMoved = false;
+ long currentTime = System.currentTimeMillis();
+
+ for (MonsterSpawnArea a : model.currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ if (m.nextActionTime <= currentTime) {
+ if (moveMonster(m, a, currentTime)) hasMoved = true;
+ }
+ }
+ }
+
+ return hasMoved;
+ }
+
+ private boolean moveMonster(final Monster m, final MonsterSpawnArea area, long currentTime) {
+ m.nextActionTime += m.millisecondsPerMove;
+ if (m.movementDestination == null) {
+ // Monster has waited and should start to move again.
+ m.movementDestination = new Coord(m.position);
+ if (ModelContainer.rnd.nextBoolean()) {
+ m.movementDestination.x = area.area.topLeft.x + ModelContainer.rnd.nextInt(area.area.size.width);
+ } else {
+ m.movementDestination.y = area.area.topLeft.y + ModelContainer.rnd.nextInt(area.area.size.height);
+ }
+ } else if (m.position.equals(m.movementDestination)) {
+ // Monster has been moving and arrived at the destination.
+ cancelCurrentMonsterMovement(m);
+ } else {
+ // Monster is moving.
+ CoordRect p = new CoordRect(
+ new Coord(
+ m.position.x + sgn(m.movementDestination.x - m.position.x)
+ ,m.position.y + sgn(m.movementDestination.y - m.position.y)
+ )
+ ,m.monsterType.tileSize
+ );
+
+ if (!monsterCanMoveTo(p)) {
+ cancelCurrentMonsterMovement(m);
+ return false;
+ }
+ if (p.contains(model.player.position)) {
+ if (!m.monsterType.isAgressive()) {
+ cancelCurrentMonsterMovement(m);
+ return false;
+ }
+ view.combatController.monsterSteppedOnPlayer(m);
+ } else {
+ m.position.set(p.topLeft);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void cancelCurrentMonsterMovement(final Monster m) {
+ m.movementDestination = null;
+ m.nextActionTime += m.millisecondsPerMove * ModelContainer.rollValue(ModelContainer.monsterWaitTurns);
+ }
+
+ private boolean monsterCanMoveTo(final CoordRect p) {
+ if (!model.currentMap.isWalkable(p)) return false;
+ if (model.currentMap.getMonsterAt(p) != null) return false;
+ return true;
+ }
+
+ private static int sgn(int i) {
+ if (i <= -1) return -1;
+ else if (i >= 1) return 1;
+ return 0;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java
new file mode 100644
index 000000000..0611da9b9
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java
@@ -0,0 +1,110 @@
+package com.gpl.rpg.AndorsTrail.controller;
+
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.model.map.KeyArea;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredWorldMap;
+import com.gpl.rpg.AndorsTrail.model.map.MapObject;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.L;
+
+public final class MovementController {
+ private final ViewContext view;
+ private final WorldContext world;
+ private final ModelContainer model;
+
+ public MovementController(ViewContext context) {
+ this.view = context;
+ this.world = context;
+ this.model = world.model;
+ }
+
+ public void placePlayerAt(String mapName, String placeName) {
+ placePlayerAt(world, mapName, placeName);
+ view.mainActivity.mainview.notifyMapChanged();
+ }
+ public static void placePlayerAt(final WorldContext world, String mapName, String placeName) {
+ if (mapName == null || placeName == null) return;
+ LayeredWorldMap newMap = world.maps.findPredefinedMap(mapName);
+ if (newMap == null) {
+ L.log("Cannot find map " + mapName);
+ return;
+ }
+ MapObject place = newMap.findEventObject(MapObject.MAPEVENT_NEWMAP, placeName);
+ if (place == null) {
+ L.log("Cannot find place " + placeName + " in map " + mapName);
+ return;
+ }
+ final ModelContainer model = world.model;
+ model.currentMap = newMap;
+ model.player.position.set(place.position.topLeft);
+ model.player.lastPosition.set(model.player.position);
+ }
+
+ public boolean mayMovePlayer() {
+ return !model.uiSelections.isInCombat;
+ }
+
+ public void movePlayer(int dx, int dy) {
+ if (dx == 0 && dy == 0) return;
+ if (!mayMovePlayer()) return;
+ //if (isInCombat) return;
+
+ final Player player = model.player;
+ player.nextPosition.set(
+ player.position.x + dx
+ ,player.position.y + dy
+ );
+ final Coord newPosition = player.nextPosition;
+ if (!model.currentMap.isWalkable(newPosition)) {
+ return;
+ }
+
+ Monster m = model.currentMap.getMonsterAt(newPosition);
+ if (m != null) {
+ view.controller.steppedOnMonster(m, newPosition);
+ return;
+ }
+
+ moveToNextIfPossible(true);
+ }
+
+ public void moveToNextIfPossible(boolean handleEvents) {
+ final Player player = model.player;
+ final LayeredWorldMap currentMap = model.currentMap;
+ final Coord newPosition = player.nextPosition;
+
+ for (KeyArea a : currentMap.keyAreas) {
+ if (a.position.contains(newPosition)) {
+ if (!view.controller.handleKeyArea(a)) return;
+ }
+ }
+
+ player.lastPosition.set(player.position);
+ player.position.set(newPosition);
+ view.combatController.setCombatSelection(null, null);
+ view.mainActivity.mainview.notifyPlayerMoved();
+ view.mainActivity.redrawAll();
+
+ if (handleEvents) {
+ for (MapObject o : currentMap.eventObjects) {
+ if (o.position.contains(newPosition)) {
+ view.controller.handleMapEvent(o);
+ }
+ }
+
+ Loot loot = currentMap.getBagAt(newPosition);
+ if (loot != null) {
+ view.itemController.handleLootBag(loot);
+ }
+ }
+ }
+
+ public static void respawnPlayer(final WorldContext world) {
+ placePlayerAt(world, world.model.player.spawnMap, world.model.player.spawnPlace);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java
new file mode 100644
index 000000000..53f072749
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java
@@ -0,0 +1,63 @@
+package com.gpl.rpg.AndorsTrail.conversation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+
+import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
+import com.gpl.rpg.AndorsTrail.resource.ResourceLoader;
+
+public class ConversationCollection {
+ public static final String PHRASE_CLOSE = "X";
+ public static final String PHRASE_SHOP = "S";
+
+ private final HashMap phrases = new HashMap();
+
+ public Phrase getPhrase(String id) {
+ return phrases.get(id);
+ }
+
+ public void initialize(ItemTypeCollection itemTypes, String phraselist) {
+ Matcher rowMatcher = ResourceLoader.rowPattern.matcher(phraselist);
+ while(rowMatcher.find()) {
+ String[] parts = rowMatcher.group(1).split(ResourceLoader.columnSeparator, -1);
+ if (parts.length < 21) continue;
+
+ ArrayList replies = new ArrayList();
+ final int startReplyOffset = 5;
+ final int replyLength = 5;
+ for (int i = 0; i < 3; ++i) {
+ int v = startReplyOffset + i * replyLength;
+ if (parts[v + 1].length() > 0) replies.add(parseReply(parts, v, itemTypes));
+ }
+ Reply[] _replies = new Reply[replies.size()];
+ _replies = replies.toArray(_replies);
+
+ phrases.put(parts[0], new Phrase(
+ parts[1]
+ , _replies
+ , parts[2]
+ , ResourceLoader.parseInt(parts[3], -1)
+ , ResourceLoader.parseInt(parts[4], -1)
+ ));
+ }
+ }
+
+ private static Reply parseReply(String[] parts, int startIndex, ItemTypeCollection itemTypes) {
+ String requiresItemTypeTag = parts[startIndex+3];
+ int requiresItemTypeID = 0;
+ if (requiresItemTypeTag.length() > 0) {
+ ItemType type = itemTypes.getItemTypeByTag(requiresItemTypeTag);
+ if (type != null) requiresItemTypeID = type.id;
+ }
+ return new Reply(
+ parts[startIndex]
+ ,parts[startIndex+1]
+ ,parts[startIndex+2]
+ ,requiresItemTypeID
+ ,ResourceLoader.parseInt(parts[startIndex+4], 0)
+ );
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java
new file mode 100644
index 000000000..f363eaf67
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java
@@ -0,0 +1,38 @@
+package com.gpl.rpg.AndorsTrail.conversation;
+
+public final class Phrase {
+ public static final Reply[] NO_REPLIES = new Reply[0];
+
+ public final String message;
+ public final Reply[] replies;
+ public final String enablesKey;
+ public final int rewardExperience;
+ public final int rewardGold;
+
+ public Phrase(String message, Reply[] replies, String enablesKey, int rewardExperience, int rewardGold) {
+ this.message = message;
+ if (replies == null) replies = NO_REPLIES;
+ this.replies = replies;
+ if (enablesKey != null && enablesKey.length() <= 0) enablesKey = null;
+ this.enablesKey = enablesKey;
+ this.rewardExperience = rewardExperience;
+ this.rewardGold = rewardGold;
+ }
+
+ public static final class Reply {
+ public final String text;
+ public final String nextPhrase;
+ public final String requiresKey;
+ public final int requiresItemTypeID;
+ public final int requiresItemQuantity;
+
+ public Reply(String text, String nextPhrase, String requiresKey, int requiresItemTypeID, int requiresItemQuantity) {
+ this.text = text;
+ this.nextPhrase = nextPhrase;
+ if (requiresKey != null && requiresKey.length() <= 0) requiresKey = null;
+ this.requiresKey = requiresKey;
+ this.requiresItemTypeID = requiresItemTypeID;
+ this.requiresItemQuantity = requiresItemQuantity;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/AttackResult.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/AttackResult.java
new file mode 100644
index 000000000..32a399762
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/AttackResult.java
@@ -0,0 +1,15 @@
+package com.gpl.rpg.AndorsTrail.model;
+
+public final class AttackResult {
+ public final boolean isHit;
+ public final boolean isCriticalHit;
+ public final int damage;
+ public final boolean targetDied;
+ public AttackResult(boolean isHit, boolean isCriticalHit, int damage, boolean targetDied) {
+ this.isHit = isHit;
+ this.isCriticalHit = isCriticalHit;
+ this.damage = damage;
+ this.targetDied = targetDied;
+ }
+ public static final AttackResult MISS = new AttackResult(false, false, 0, false);
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/CombatTraits.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/CombatTraits.java
new file mode 100644
index 000000000..d1e79da56
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/CombatTraits.java
@@ -0,0 +1,64 @@
+package com.gpl.rpg.AndorsTrail.model;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+public class CombatTraits {
+ public int attackCost;
+
+ public int attackChance;
+ public int criticalChance;
+ public int criticalMultiplier;
+ public final Range damagePotential;
+
+ public int blockChance;
+ public int damageResistance;
+
+ public CombatTraits() {
+ this.damagePotential = new Range();
+ }
+ public CombatTraits(CombatTraits copy) {
+ this();
+ set(copy);
+ }
+ public void set(CombatTraits copy) {
+ this.attackCost = copy.attackCost;
+ this.attackChance = copy.attackChance;
+ this.criticalChance = copy.criticalChance;
+ this.criticalMultiplier = copy.criticalMultiplier;
+ this.damagePotential.set(copy.damagePotential);
+ this.blockChance = copy.blockChance;
+ this.damageResistance = copy.damageResistance;
+ }
+
+ public boolean hasAttackChanceEffect() { return attackChance != 0; }
+ public boolean hasAttackDamageEffect() { return damagePotential.max > 0; }
+ public boolean hasBlockEffect() { return blockChance != 0; }
+ public boolean hasCriticalEffect() { return criticalChance > 0 && criticalMultiplier > 1; }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public CombatTraits(DataInputStream src) throws IOException {
+ this.attackCost = src.readInt();
+ this.attackChance = src.readInt();
+ this.criticalChance = src.readInt();
+ this.criticalMultiplier = src.readInt();
+ this.damagePotential = new Range(src);
+ this.blockChance = src.readInt();
+ this.damageResistance = src.readInt();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(attackCost);
+ dest.writeInt(attackChance);
+ dest.writeInt(criticalChance);
+ dest.writeInt(criticalMultiplier);
+ damagePotential.writeToParcel(dest, flags);
+ dest.writeInt(blockChance);
+ dest.writeInt(damageResistance);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/GameStatistics.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/GameStatistics.java
new file mode 100644
index 000000000..02206a8a3
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/GameStatistics.java
@@ -0,0 +1,49 @@
+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.Set;
+import java.util.Map.Entry;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+
+public final class GameStatistics {
+ public int deaths = 0;
+ public final HashMap killedMonsters = new HashMap();
+
+ public GameStatistics() { }
+ public void addMonsterKill(MonsterType type) {
+ final String n = type.name;
+ if (!killedMonsters.containsKey(n)) killedMonsters.put(n, 0);
+ killedMonsters.put(n, killedMonsters.get(n) + 1);
+ }
+ public void addPlayerDeath(int lostExp) {
+ ++deaths;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public GameStatistics(DataInputStream src, WorldContext world) throws IOException {
+ this.deaths = src.readInt();
+ final int size = src.readInt();
+ for(int i = 0; i < size; ++i) {
+ final String name = src.readUTF();
+ final int value = src.readInt();
+ this.killedMonsters.put(name, value);
+ }
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(deaths);
+ Set > set = killedMonsters.entrySet();
+ dest.writeInt(set.size());
+ for (Entry e : set) {
+ dest.writeUTF(e.getKey());
+ dest.writeInt(e.getValue());
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/InterfaceData.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/InterfaceData.java
new file mode 100644
index 000000000..74fefb7ac
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/InterfaceData.java
@@ -0,0 +1,45 @@
+package com.gpl.rpg.AndorsTrail.model;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class InterfaceData {
+ public boolean isTicking = false;
+ public boolean isInCombat = false;
+ public Monster selectedMonster;
+ public Coord selectedPosition;
+ public String selectedTabHeroInfo = "";
+
+ public InterfaceData() { }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public InterfaceData(DataInputStream src, WorldContext world) throws IOException {
+ this.isTicking = src.readBoolean();
+ this.isInCombat = src.readBoolean();
+ final boolean hasSelectedPosition = src.readBoolean();
+ if (hasSelectedPosition) {
+ this.selectedPosition = new Coord(src);
+ this.selectedMonster = world.model.currentMap.getMonsterAt(selectedPosition);
+ }
+ this.selectedTabHeroInfo = src.readUTF();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeBoolean(isTicking);
+ dest.writeBoolean(isInCombat);
+ if (selectedPosition != null) {
+ dest.writeBoolean(true);
+ selectedPosition.writeToParcel(dest, flags);
+ } else {
+ dest.writeBoolean(false);
+ }
+ dest.writeUTF(selectedTabHeroInfo);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ModelContainer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ModelContainer.java
new file mode 100644
index 000000000..33bb4b554
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/ModelContainer.java
@@ -0,0 +1,84 @@
+package com.gpl.rpg.AndorsTrail.model;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredWorldMap;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+public final class ModelContainer {
+
+ public static final int millisecondsPerTurn = 1200;
+ public static final int attackAnimationDuration = 1000;
+ public static final int attackAnimationFPS = 10;
+ public static final int monsterAttackDelay = 1000;
+ public static final int tickDelay = 500;
+ public static final ConstRange monsterWaitTurns = new ConstRange(30,4);
+ public static final Random rnd = new Random();
+ //public static final String PREFERENCE_MODEL_SAVE = "savegame";
+ public static final String PREFERENCE_MODEL_QUICKSAVE = "quicksave";
+ public static final String PREFERENCE_MODEL_LASTRUNVERSION = "lastversion";
+ public static final int CURRENT_VERSION = 4;
+
+ public final Player player;
+ public final InterfaceData uiSelections;
+ public final GameStatistics statistics;
+ public LayeredWorldMap currentMap;
+
+ public ModelContainer() {
+ player = new Player();
+ uiSelections = new InterfaceData();
+ statistics = new GameStatistics();
+ }
+
+ public static boolean roll100(final int chance) { return rnd.nextInt(100) < chance; }
+ public static int rollValue(final ConstRange r) {
+ if (r.isMax()) return r.max;
+ else return rnd.nextInt(r.max - r.current) + r.current;
+ }
+ public static int rollValue(final Range r) {
+ if (r.isMax()) return r.max;
+ else return rnd.nextInt(r.max - r.current + 1) + r.current;
+ }
+ public static boolean rollResult(final ConstRange r) { return rnd.nextInt(r.max) < r.current; }
+ public static boolean rollResult(final Range r) { return rnd.nextInt(r.max) < r.current; }
+
+
+ public void quicksave(Editor e) {
+ e.putString("playername", player.traits.name);
+ e.putInt("level", player.level);
+ }
+
+ public boolean quickload(SharedPreferences p) {
+ String name = p.getString("playername", null);
+ if (name == null) return false;
+ player.traits.name = name;
+ player.level = p.getInt("level", -1);
+ return true;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public ModelContainer(DataInputStream src, WorldContext world) throws IOException {
+ this.player = new Player(src, world);
+ this.currentMap = world.maps.findPredefinedMap(src.readUTF());
+ this.uiSelections = new InterfaceData(src, world);
+ this.statistics = new GameStatistics(src, world);
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ player.writeToParcel(dest, flags);
+ dest.writeUTF(currentMap.name);
+ uiSelections.writeToParcel(dest, flags);
+ statistics.writeToParcel(dest, flags);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java
new file mode 100644
index 000000000..4ea2edf35
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Actor.java
@@ -0,0 +1,59 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+public class Actor {
+ public final ActorTraits traits;
+ public final Range ap;
+ public final Range health;
+ public final Coord position;
+ public final CoordRect rectPosition;
+
+ public Actor(ActorTraits traits) {
+ this.traits = traits;
+ this.ap = new Range();
+ this.health = new Range();
+ this.position = new Coord();
+ this.rectPosition = new CoordRect(position, traits.tileSize);
+ setMaxAP();
+ setMaxHP();
+ }
+
+ public void setMaxAP() {
+ ap.set(traits.maxAP, traits.maxAP);
+ }
+ public void setMaxHP() {
+ health.set(traits.maxHP, traits.maxHP);
+ }
+
+ public boolean useAPs(int cost) {
+ if (ap.current < cost) return false;
+ ap.subtract(cost, false);
+ return true;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Actor(DataInputStream src, WorldContext world) throws IOException {
+ this.traits = new ActorTraits(src, world);
+ this.ap = new Range(src);
+ this.health = new Range(src);
+ this.position = new Coord(src);
+ this.rectPosition = new CoordRect(position, traits.tileSize);
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ traits.writeToParcel(dest, flags);
+ ap.writeToParcel(dest, flags);
+ health.writeToParcel(dest, flags);
+ position.writeToParcel(dest, flags);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.java
new file mode 100644
index 000000000..021d08646
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/ActorTraits.java
@@ -0,0 +1,64 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public class ActorTraits extends CombatTraits {
+ public final int iconID;
+ public final Size tileSize;
+
+ public int maxAP;
+ public int maxHP;
+
+ public String name;
+ public int moveCost;
+
+ public final CombatTraits baseCombatTraits;
+
+ public ActorTraits(
+ int iconID
+ , Size tileSize
+ , CombatTraits baseCombatTraits
+ ) {
+ super(baseCombatTraits);
+ this.iconID = iconID;
+ this.tileSize = tileSize;
+ this.baseCombatTraits = baseCombatTraits;
+ }
+ public int getAttacksPerTurn() {
+ return (int) Math.floor(maxAP / attackCost);
+ }
+ public int getMovesPerTurn() {
+ return (int) Math.floor(maxAP / moveCost);
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public ActorTraits(DataInputStream src, WorldContext world) throws IOException {
+ super(src);
+ this.iconID = src.readInt();
+ this.tileSize = new Size(src);
+ this.maxAP = src.readInt();
+ this.maxHP = src.readInt();
+ this.name = src.readUTF();
+ this.moveCost = src.readInt();
+ this.baseCombatTraits = new CombatTraits(src);
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(iconID);
+ tileSize.writeToParcel(dest, flags);
+ dest.writeInt(maxAP);
+ dest.writeInt(maxHP);
+ dest.writeUTF(name);
+ dest.writeInt(moveCost);
+ baseCombatTraits.writeToParcel(dest, flags);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Monster.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Monster.java
new file mode 100644
index 000000000..fcbac2413
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Monster.java
@@ -0,0 +1,50 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class Monster extends Actor {
+ public final MonsterType monsterType;
+
+ public final int millisecondsPerMove;
+ public Coord movementDestination = null;
+ public long nextActionTime = 0;
+
+ public Monster(MonsterType monsterType, Coord position) {
+ super(monsterType);
+ this.monsterType = monsterType;
+ this.position.set(position);
+ this.millisecondsPerMove = ModelContainer.millisecondsPerTurn / monsterType.getMovesPerTurn();
+ }
+
+ public void createLoot(Loot container) {
+ container.exp += monsterType.exp;
+ if (monsterType.dropList == null) return;
+ monsterType.dropList.createRandomLoot(container);
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public static Monster readFromParcel(DataInputStream src, WorldContext world) throws IOException {
+ MonsterType monsterType = world.monsterTypes.getMonsterType(src.readInt());
+ Coord position = new Coord(src);
+ Monster m = new Monster(monsterType, position);
+ m.ap.current = src.readInt();
+ m.health.current = src.readInt();
+ return m;
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(monsterType.id);
+ position.writeToParcel(dest, flags);
+ dest.writeInt(ap.current);
+ dest.writeInt(health.current);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.java
new file mode 100644
index 000000000..5b813d757
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterType.java
@@ -0,0 +1,38 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+import com.gpl.rpg.AndorsTrail.model.item.DropList;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public final class MonsterType extends ActorTraits {
+ public final int id;
+ private final String searchPattern;
+ public final int exp;
+ public final DropList dropList;
+ public final String phraseID;
+
+ public MonsterType(int id, String name, String tags, int iconID, Size tileSize, int maxHP, int maxAP, int moveCost, CombatTraits baseCombatTraits, int exp, DropList dropList, String phraseID) {
+ super(iconID, tileSize, baseCombatTraits);
+ this.id = id;
+ this.searchPattern = ',' + tags.toLowerCase() + ',';
+ this.exp = exp;
+ this.name = name;
+ this.maxHP = maxHP;
+ this.maxAP = maxAP;
+ this.moveCost = moveCost;
+ this.dropList = dropList;
+ if (phraseID != null && phraseID.length() == 0) phraseID = null;
+ this.phraseID = phraseID;
+ }
+ public boolean matchesAny(String[] tagsAndNames) {
+ for (String s : tagsAndNames) {
+ if (name.equalsIgnoreCase(s)) return true;
+ if (searchPattern.contains(',' + s + ',')) return true;
+ }
+ return false;
+ }
+
+ public boolean isAgressive() {
+ return phraseID == null;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java
new file mode 100644
index 000000000..d6db15f7b
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java
@@ -0,0 +1,68 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.regex.Matcher;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
+import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
+import com.gpl.rpg.AndorsTrail.resource.ResourceLoader;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public final class MonsterTypeCollection {
+ private final ArrayList monsterTypes = new ArrayList();
+
+ public MonsterType getMonsterType(int id) {
+ return monsterTypes.get(id);
+ }
+ public MonsterType getMonsterType(String name) {
+ for (MonsterType t : monsterTypes) {
+ if (t.name.equalsIgnoreCase(name)) return t;
+ }
+ return null;
+ }
+
+ public Collection extends MonsterType> getMonsterTypesFromTags(String tagsAndNames) {
+ String[] parts = tagsAndNames.toLowerCase().split(",");
+ ArrayList result = new ArrayList();
+ for (MonsterType t : monsterTypes) {
+ if (t.matchesAny(parts)) result.add(t);
+ }
+ //L.log("\"" + tagsAndNames + "\" -> found " + result.size() + " monsters.");
+ return result;
+ }
+
+ private static final Size size1x1 = new Size(1, 1);
+ public void initialize(DropListCollection droplists, DynamicTileLoader tileLoader, String monsterlist) {
+ int nextId = monsterTypes.size();
+ Matcher rowMatcher = ResourceLoader.rowPattern.matcher(monsterlist);
+ while(rowMatcher.find()) {
+ String[] parts = rowMatcher.group(1).split(ResourceLoader.columnSeparator, -1);
+ if (parts.length < 17) continue;
+
+ final String monsterTypeName = parts[1];
+
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA && getMonsterTypesFromTags(monsterTypeName).size() > 0) {
+ L.log("OPTIMIZE: Monster " + monsterTypeName + " may be duplicated.");
+ }
+
+ monsterTypes.add(new MonsterType(
+ nextId
+ , monsterTypeName
+ , parts[2]
+ , ResourceLoader.parseImage(tileLoader, parts[0])
+ , ResourceLoader.parseSize(parts[3], size1x1)
+ , ResourceLoader.parseInt(parts[5], 1) // HP
+ , ResourceLoader.parseInt(parts[6], 10) // AP
+ , ResourceLoader.parseInt(parts[7], 10) // MoveCost
+ , ResourceLoader.parseCombatTraits(parts, 8)
+ , ResourceLoader.parseInt(parts[4], 0) // Exp
+ , droplists.getDropList(parts[15])
+ , parts[16]
+ ));
+ ++nextId;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java
new file mode 100644
index 000000000..95b3a76b3
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java
@@ -0,0 +1,166 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
+import com.gpl.rpg.AndorsTrail.model.item.Inventory;
+import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.Range;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public final class Player extends Actor {
+ public final Coord lastPosition;
+ public final Coord nextPosition;
+ public int level;
+ public int totalExperience;
+ public final Range levelExperience; // ranges from 0 to the delta-amount of exp required for next level
+ public final Inventory inventory;
+ private final HashSet keys = new HashSet();
+ public int useItemCost;
+ public int reequipCost;
+ public final int[] skillLevels = new int[Skills.NUM_SKILLS];
+ public String spawnMap;
+ public String spawnPlace;
+
+ public Player() {
+ super(new ActorTraits(TileStore.CHAR_HERO, new Size(1, 1), new CombatTraits()));
+ this.lastPosition = new Coord();
+ this.nextPosition = new Coord();
+ this.levelExperience = new Range();
+ this.inventory = new Inventory();
+ }
+
+ public void initializeNewPlayer(ItemTypeCollection types, DropListCollection dropLists, String name) {
+ CombatTraits combat = new CombatTraits();
+ combat.attackCost = 3;
+ combat.attackChance = 60;
+ combat.criticalChance = 0;
+ combat.criticalMultiplier = 1;
+ combat.damagePotential.set(1, 1);
+ combat.blockChance = 0;
+ combat.damageResistance = 0;
+
+ traits.baseCombatTraits.set(combat);
+
+ traits.maxAP = 10;
+ traits.maxHP = 20;
+
+ traits.name = name;
+ traits.moveCost = 6;
+ useItemCost = 2;
+ reequipCost = 5;
+
+ level = 1;
+ totalExperience = 1;
+ recalculateLevelExperience();
+
+ Loot startItems = new Loot();
+ dropLists.getDropList(DropListCollection.DROPLIST_STARTITEMS).createRandomLoot(startItems);
+ inventory.add(startItems);
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ spawnMap = "debugmap";
+ spawnPlace = "start";
+ } else {
+ spawnMap = "home";
+ spawnPlace = "rest";
+ }
+
+ recalculateCombatTraits();
+ }
+
+ public boolean hasKey(String key) { return keys.contains(key); }
+ public void addKey(String key) { if (!keys.contains(key)) keys.add(key); }
+
+ public void recalculateCombatTraits() {
+ traits.set(traits.baseCombatTraits);
+ inventory.apply(traits);
+ }
+
+ public void recalculateLevelExperience() {
+ int experienceRequiredToReachThisLevel = getRequiredExperience(level);
+ levelExperience.set(getRequiredExperienceForNextLevel(level), totalExperience - experienceRequiredToReachThisLevel);
+ }
+ public void addExperience(int v) {
+ totalExperience += v;
+ levelExperience.add(v, true);
+ }
+
+
+
+ private static int getRequiredExperience(int currentLevel) {
+ int v = 0;
+ for(int i = 1; i < currentLevel; ++i) {
+ v += getRequiredExperienceForNextLevel(i);
+ }
+ return v;
+ }
+ private static final int EXP_base = 55;
+ private static final int EXP_D = 400;
+ private static final int EXP_powbase = 2;
+ private static int getRequiredExperienceForNextLevel(int currentLevel) {
+ return (int) (EXP_base * Math.pow(currentLevel, EXP_powbase + currentLevel/EXP_D));
+ }
+
+ public boolean canLevelup() {
+ return levelExperience.isMax();
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Player(DataInputStream src, WorldContext world) throws IOException {
+ super(src, world);
+ this.lastPosition = new Coord(src);
+ this.nextPosition = new Coord(src);
+ this.level = src.readInt();
+ this.totalExperience = src.readInt();
+ this.levelExperience = new Range();
+ this.recalculateLevelExperience();
+ this.inventory = new Inventory(src, world);
+ this.keys.clear();
+ final int size1 = src.readInt();
+ for(int i = 0; i < size1; ++i) {
+ this.keys.add(src.readUTF());
+ }
+ this.useItemCost = src.readInt();
+ this.reequipCost = src.readInt();
+ final int size2 = src.readInt();
+ for(int i = 0; i < size2; ++i) {
+ this.skillLevels[i] = src.readInt();
+ }
+ this.spawnMap = src.readUTF();
+ this.spawnPlace = src.readUTF();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ super.writeToParcel(dest, flags);
+ lastPosition.writeToParcel(dest, flags);
+ nextPosition.writeToParcel(dest, flags);
+ dest.writeInt(level);
+ dest.writeInt(totalExperience);
+ inventory.writeToParcel(dest, flags);
+ dest.writeInt(keys.size());
+ for (String k : keys) {
+ dest.writeUTF(k);
+ }
+ dest.writeInt(useItemCost);
+ dest.writeInt(reequipCost);
+ dest.writeInt(Skills.NUM_SKILLS);
+ for(int i = 0; i < Skills.NUM_SKILLS; ++i) {
+ dest.writeInt(this.skillLevels[i]);
+ }
+ dest.writeUTF(spawnMap);
+ dest.writeUTF(spawnPlace);
+ }
+}
+
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Skills.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Skills.java
new file mode 100644
index 000000000..fc918f8cb
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Skills.java
@@ -0,0 +1,20 @@
+package com.gpl.rpg.AndorsTrail.model.actor;
+
+public class Skills {
+ public static final int SKILL_WEAPON_CHANCE = 0;
+ public static final int SKILL_WEAPON_DMG = 1;
+ public static final int SKILL_BARTER = 2;
+ public static final int SKILL_DODGE = 3;
+ public static final int SKILL_BARKSKIN = 4;
+ public static final int SKILL_MORE_CRITICALS = 5;
+ public static final int SKILL_BETTER_CRITICALS = 6;
+ public static final int SKILL_SPEED = 7;
+ public static final int SKILL_COINFINDER = 8;
+ public static final int SKILL_MORE_EXP = 9;
+ public static final int SKILL_CLEAVE = 10;
+ public static final int SKILL_EATER = 11; // +1hp per kill
+ public static final int SKILL_BERSERKER = 12; // <=20%hp
+ public static final int SKILL_FORTITUDE = 13; // +2hp /level
+
+ public static final int NUM_SKILLS = 14;
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropList.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropList.java
new file mode 100644
index 000000000..118b08086
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropList.java
@@ -0,0 +1,40 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.util.Collection;
+
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+
+public final class DropList {
+ private final DropItem[] items;
+ public DropList(DropItem[] items) {
+ this.items = items;
+ }
+ public DropList(Collection items) {
+ this.items = items.toArray(new DropItem[items.size()]);
+ }
+ public void createRandomLoot(Loot loot) {
+ for (DropItem item : items) {
+ if (ModelContainer.rollResult(item.chance)) {
+ int quantity = ModelContainer.rollValue(item.quantity);
+ if (quantity > 0) {
+ if (item.itemType.id == ItemTypeCollection.ITEMTYPE_GOLD) {
+ loot.gold += quantity;
+ } else {
+ loot.items.addItem(item.itemType, quantity);
+ }
+ }
+ }
+ }
+ }
+ public static class DropItem {
+ public final ItemType itemType;
+ public final ConstRange chance;
+ public final ConstRange quantity;
+ public DropItem(ItemType itemType, ConstRange chance, ConstRange quantity) {
+ this.itemType = itemType;
+ this.chance = chance;
+ this.quantity = quantity;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.java
new file mode 100644
index 000000000..ddf63bb69
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/DropListCollection.java
@@ -0,0 +1,159 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.model.item.DropList.DropItem;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+import com.gpl.rpg.AndorsTrail.util.L;
+
+public final class DropListCollection {
+ public static final String DROPLIST_STARTITEMS = "startitems";
+
+ private final HashMap droplists = new HashMap();
+
+ public DropList getDropList(String name) {
+ if (name == null || name.length() <= 0) return null;
+
+ if (!droplists.containsKey(name)) {
+ L.log("WARNING: Cannot find droplist \"" + name + "\".");
+ }
+ return droplists.get(name);
+ }
+
+ public void initialize(ItemTypeCollection itemTypes) {
+ ArrayList items = new ArrayList();
+ final ConstRange one = new ConstRange(1, 1);
+ final ConstRange ten = new ConstRange(10, 10);
+ final ConstRange five = new ConstRange(5, 5);
+ final ConstRange always = one;
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), new ConstRange(100, 100), new ConstRange(10, 0)));
+ items.add(new DropItem(itemTypes.getItemType(1), new ConstRange(100, 10), new ConstRange(1, 1)));
+ items.add(new DropItem(itemTypes.getItemType(2), new ConstRange(100, 50), new ConstRange(1, 1)));
+ droplists.put("list1", new DropList(items));
+
+ items.clear();
+ for(int i = 1; i <= 20; ++i) {
+ items.add(new DropItem(itemTypes.getItemType(i), always, one));
+ }
+ droplists.put("shop1", new DropList(items));
+ }
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), always, new ConstRange(12, 12)));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("club1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shirt1"), always, one));
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_mikhail"), always, one));
+ }
+ droplists.put(DROPLIST_STARTITEMS, new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemTypeByTag("health_minor"), always, ten));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("health"), always, ten));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("health_major"), always, ten));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_dmg1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_dmg2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_block1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_atkch1"), always, one));
+ droplists.put("shop_priest", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemTypeByTag("apple_green"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("meat"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("meat_cooked"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("Carrot"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("Bread"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("Mushroom"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("Eggs"), always, five));
+ droplists.put("shop_food", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shirt1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shirt2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("hat1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("hat2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gloves1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gloves2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gloves3"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gloves4"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("boots1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("boots2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("boots3"), always, one));
+ droplists.put("shop_clothes", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemTypeByTag("club1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("club3"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ironsword0"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("hammer0"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("dagger0"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("dagger1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("dagger2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shortsword1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ironsword1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ironsword2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("broadsword1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("broadsword2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("steelsword1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("axe1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("axe2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("armor1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("armor2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("armor3"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shield1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shield3"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shield4"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shield5"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("boots1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("boots5"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("hat3"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("hat4"), always, one));
+ droplists.put("shop_smith", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shirt1"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shirt2"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gem1"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gem2"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("gem3"), always, five));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_dmg5"), always, one));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("ring_dmg6"), always, one));
+ droplists.put("shop_thief", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), always, new ConstRange(2, 0)));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("tail_trainingrat"), always, one));
+ droplists.put("trainingrat", new DropList(items));
+
+ final ConstRange seldom = new ConstRange(100, 30);
+ //final ConstRange sometimes = new ConstRange(100, 50);
+ final ConstRange often = new ConstRange(100, 70);
+ final ConstRange animalpart = seldom;
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), always, new ConstRange(2, 0)));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("rat_tail"), animalpart, one));
+ droplists.put("rat", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), always, ten));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("tail_caverat"), always, one));
+ droplists.put("caveratboss", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), often, new ConstRange(4, 1)));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("Insect wing"), animalpart, one));
+ droplists.put("wasp", new DropList(items));
+
+ items.clear();
+ items.add(new DropItem(itemTypes.getItemType(ItemTypeCollection.ITEMTYPE_GOLD), often, new ConstRange(4, 1)));
+ items.add(new DropItem(itemTypes.getItemTypeByTag("shell"), animalpart, one));
+ droplists.put("insect", new DropList(items));
+
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java
new file mode 100644
index 000000000..5947ffc45
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java
@@ -0,0 +1,90 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+
+public final class Inventory extends ItemContainer {
+
+ public int gold = 0;
+ public static final int NUM_WORN_SLOTS = ItemType.MAX_CATEGORY_WEAR+1+1; // +1 for 0 based index. +1 for left+right rings.
+ public final ItemType[] wear = new ItemType[NUM_WORN_SLOTS];
+
+ public Inventory() { }
+
+ public void add(final Loot loot) {
+ this.gold += loot.gold;
+ this.add(loot.items);
+ }
+
+ public boolean isEmptySlot(int slot) {
+ return wear[slot] == null;
+ }
+
+ public void apply(CombatTraits traits) {
+ ItemType weapon = wear[ItemType.CATEGORY_WEAPON];
+ if (weapon != null) {
+ CombatTraits weaponTraits = weapon.effect_combat;
+ if (weaponTraits != null) {
+ traits.attackCost = weaponTraits.attackCost;
+ traits.criticalMultiplier = weaponTraits.criticalMultiplier;
+ }
+ }
+
+ for (int i = 0; i < NUM_WORN_SLOTS; ++i) {
+ ItemType type = wear[i];
+ if (type != null) {
+ CombatTraits itemTraits = type.effect_combat;
+ if (itemTraits != null) {
+ if (i != ItemType.CATEGORY_WEAPON) {
+ // For weapons, these attributes should be SET, not added.
+ traits.attackCost += itemTraits.attackCost;
+ traits.criticalMultiplier += itemTraits.criticalMultiplier;
+ }
+ traits.attackChance += itemTraits.attackChance;
+ traits.criticalChance += itemTraits.criticalChance;
+ traits.damagePotential.add(itemTraits.damagePotential.current, true);
+ traits.damagePotential.max += itemTraits.damagePotential.max;
+ traits.blockChance += itemTraits.blockChance;
+ traits.damageResistance += itemTraits.damageResistance;
+ }
+ }
+ }
+
+ if (traits.attackCost <= 0) traits.attackCost = 1;
+ if (traits.attackChance < 0) traits.attackChance = 0;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Inventory(DataInputStream src, WorldContext world) throws IOException {
+ super(src, world);
+ gold = src.readInt();
+ final int size = src.readInt();
+ for(int i = 0; i < size; ++i) {
+ if (src.readBoolean()) {
+ wear[i] = world.itemTypes.getItemTypeByTag(src.readUTF());
+ } else {
+ wear[i] = null;
+ }
+ }
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(gold);
+ dest.writeInt(NUM_WORN_SLOTS);
+ for(int i = 0; i < NUM_WORN_SLOTS; ++i) {
+ if (wear[i] != null) {
+ dest.writeBoolean(true);
+ dest.writeUTF(wear[i].searchTag);
+ } else {
+ dest.writeBoolean(false);
+ }
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java
new file mode 100644
index 000000000..2906f63fe
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java
@@ -0,0 +1,102 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+
+public class ItemContainer {
+ public final ArrayList items = new ArrayList();
+
+ public ItemContainer() {}
+
+ 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) throws IOException {
+ this.itemType = world.itemTypes.getItemTypeByTag(src.readUTF());
+ this.quantity = src.readInt();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeUTF(itemType.searchTag);
+ dest.writeInt(quantity);
+ }
+ }
+
+ public void addItem(ItemType itemType, int quantity) {
+ 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(int itemTypeID) { return removeItem(itemTypeID, 1); }
+ public boolean removeItem(int 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 == itemTypeID) {
+ index = i;
+ break;
+ }
+ }
+ if (index < 0) return false;
+ if (e.quantity <= quantity) {
+ items.remove(index);
+ } else {
+ e.quantity -= quantity;
+ }
+ return true;
+ }
+
+ public ItemEntry findItem(int itemTypeID) {
+ for (ItemEntry e : items) {
+ if (e.itemType.id == itemTypeID) return e;
+ }
+ return null;
+ }
+ public boolean hasItem(int itemTypeID) { return findItem(itemTypeID) != null; }
+ public boolean hasItem(int itemTypeID, int minimumQuantity) {
+ ItemEntry e = findItem(itemTypeID);
+ if (e == null) return false;
+ return e.quantity >= minimumQuantity;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public ItemContainer(DataInputStream src, WorldContext world) throws IOException {
+ final int size = src.readInt();
+ for(int i = 0; i < size; ++i) {
+ items.add(new ItemEntry(src, world));
+ }
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(items.size());
+ for (ItemEntry e : items) {
+ e.writeToParcel(dest, flags);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java
new file mode 100644
index 000000000..912665d47
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java
@@ -0,0 +1,122 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+
+public final class ItemType {
+ public static final int CATEGORY_WEAPON = 0;
+ public static final int CATEGORY_SHIELD = 1;
+ public static final int CATEGORY_WEARABLE_HEAD = 2;
+ public static final int CATEGORY_WEARABLE_BODY = 3;
+ public static final int CATEGORY_WEARABLE_HAND = 4;
+ public static final int CATEGORY_WEARABLE_FEET = 5;
+ //public static final int CATEGORY_WEARABLE_CAPE = 6;
+ //public static final int CATEGORY_WEARABLE_LEGS = 7;
+ public static final int CATEGORY_WEARABLE_NECK = 6;
+ public static final int CATEGORY_WEARABLE_RING = 7;
+ public static final int MAX_CATEGORY_WEAR = CATEGORY_WEARABLE_RING;
+ public static final int CATEGORY_POTION = 20;
+ public static final int CATEGORY_FOOD = 21;
+ public static final int MAX_CATEGORY_USE = CATEGORY_FOOD;
+ public static final int CATEGORY_MONEY = 30;
+ public static final int CATEGORY_OTHER = 31;
+
+ public static final int ACTIONTYPE_NONE = 0;
+ public static final int ACTIONTYPE_USE = 1;
+ public static final int ACTIONTYPE_EQUIP = 2;
+
+ public final int id;
+ public final int iconID;
+ public final String name;
+ public final int category;
+ public final int actionType;
+ public final int baseMarketCost;
+ public final String searchTag;
+
+ public final ConstRange effect_ap;
+ public final ConstRange effect_health;
+ public final CombatTraits effect_combat;
+
+ public ItemType(int id, int iconID, String name, String searchTag, int category, int baseMarketCost, ConstRange effect_ap, ConstRange effect_health, CombatTraits effect_combat) {
+ this.id = id;
+ this.iconID = iconID;
+ this.name = name;
+ this.searchTag = searchTag;
+ this.category = category;
+ this.actionType = getActionType(category);
+ this.baseMarketCost = baseMarketCost;
+ this.effect_ap = effect_ap;
+ this.effect_health = effect_health;
+ this.effect_combat = effect_combat;
+ }
+
+ private static int getActionType(int category) {
+ if (category <= MAX_CATEGORY_WEAR) return ACTIONTYPE_EQUIP;
+ else if (category <= MAX_CATEGORY_USE) return ACTIONTYPE_USE;
+ else return ACTIONTYPE_NONE;
+ }
+ public boolean isEquippable() { return actionType == ACTIONTYPE_EQUIP; }
+ public boolean isUsable() { return actionType == ACTIONTYPE_USE; }
+ public boolean isQuestItem() { return baseMarketCost == 0; }
+
+ public String describe(int quantity) {
+ StringBuilder sb = new StringBuilder(name);
+ if (quantity > 1) {
+ sb.append(" (");
+ sb.append(quantity);
+ sb.append(')');
+ }
+ if (effect_combat != null) {
+ if (effect_combat.hasAttackChanceEffect() || effect_combat.hasAttackDamageEffect()) {
+ sb.append(" [");
+ describeAttackEffect(effect_combat, sb);
+ sb.append(']');
+ }
+ if (effect_combat.hasBlockEffect()) {
+ sb.append(" [");
+ describeBlockEffect(effect_combat, sb);
+ sb.append(']');
+ }
+ }
+ return sb.toString();
+ }
+
+ public static void describeAttackEffect(CombatTraits attackEffect, StringBuilder sb) {
+ boolean addSpace = false;
+ if (attackEffect.hasAttackChanceEffect()) {
+ sb.append(attackEffect.attackChance);
+ sb.append('%');
+ addSpace = true;
+ }
+ if (attackEffect.hasAttackDamageEffect()) {
+ if (addSpace) sb.append(' ');
+ sb.append(attackEffect.damagePotential.toMinMaxString());
+ addSpace = true;
+ }
+ if (attackEffect.hasCriticalEffect()) {
+ sb.append(" +");
+ sb.append(attackEffect.criticalChance);
+ sb.append("%x");
+ sb.append(attackEffect.criticalMultiplier);
+ }
+ }
+ public static String describeAttackEffect(CombatTraits attackEffect) {
+ StringBuilder sb = new StringBuilder();
+ describeAttackEffect(attackEffect, sb);
+ return sb.toString();
+ }
+
+ public static void describeBlockEffect(CombatTraits defenseEffect, StringBuilder sb) {
+ sb.append(defenseEffect.blockChance);
+ sb.append('%');
+ if (defenseEffect.damageResistance != 0) {
+ sb.append('/');
+ sb.append(defenseEffect.damageResistance);
+ }
+ }
+ public static String describeBlockEffect(CombatTraits defenseEffect) {
+ StringBuilder sb = new StringBuilder();
+ describeBlockEffect(defenseEffect, sb);
+ return sb.toString();
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.java
new file mode 100644
index 000000000..02b4c1965
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemTypeCollection.java
@@ -0,0 +1,61 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
+import com.gpl.rpg.AndorsTrail.resource.ResourceLoader;
+import com.gpl.rpg.AndorsTrail.util.L;
+
+public final class ItemTypeCollection {
+ public static final int ITEMTYPE_GOLD = 0;
+
+ private final ArrayList itemTypes = new ArrayList();
+ public final ArrayList TEST_itemTypes = itemTypes;
+
+ public ItemType getItemType(int id) {
+ return itemTypes.get(id);
+ }
+ public ItemType getItemTypeByTag(String searchTag) {
+ for(ItemType t : itemTypes) {
+ if (t.searchTag.equalsIgnoreCase(searchTag)) return t;
+ }
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("WARNING: Cannot find ItemType for searchtag \"" + searchTag + "\".");
+ }
+ return null;
+ }
+
+ public void initialize(DynamicTileLoader tileLoader, String itemlist) {
+ int nextId = itemTypes.size();
+ Matcher rowMatcher = ResourceLoader.rowPattern.matcher(itemlist);
+ while(rowMatcher.find()) {
+ String[] parts = rowMatcher.group(1).split(ResourceLoader.columnSeparator, -1);
+ if (parts.length < 13) continue;
+
+ final String itemTypeName = parts[2];
+ String searchTag = parts[0];
+ if (searchTag == null || searchTag.length() <= 0) searchTag = itemTypeName;
+
+ itemTypes.add(new ItemType(
+ nextId
+ , ResourceLoader.parseImage(tileLoader, parts[1])
+ , itemTypeName
+ , searchTag
+ , Integer.parseInt(parts[3])
+ , Integer.parseInt(parts[4])
+ , null
+ , ResourceLoader.parseRange(parts[5])
+ , ResourceLoader.parseCombatTraits(parts, 6)
+ ));
+
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA && getItemTypeByTag(searchTag).id != nextId) {
+ L.log("OPTIMIZE: Item " + searchTag + " may be duplicated.");
+ }
+
+ ++nextId;
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Loot.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Loot.java
new file mode 100644
index 000000000..9cf2032a8
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Loot.java
@@ -0,0 +1,53 @@
+package com.gpl.rpg.AndorsTrail.model.item;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class Loot {
+ public int exp = 0;
+ public int gold = 0;
+ public final ItemContainer items;
+ public final Coord position;
+
+ public Loot() {
+ this.items = new ItemContainer();
+ this.position = new Coord();
+ }
+
+ public void add(Loot l) {
+ this.exp += l.exp;
+ this.gold += l.gold;
+ this.items.add(items);
+ }
+
+ public boolean isEmpty() {
+ return exp == 0 && gold == 0 && items.isEmpty();
+ }
+
+ public void clear() {
+ exp = 0;
+ gold = 0;
+ items.items.clear();
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Loot(DataInputStream src, WorldContext world) throws IOException {
+ this.exp = src.readInt();
+ this.gold = src.readInt();
+ this.items = new ItemContainer(src, world);
+ this.position = new Coord(src);
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(exp);
+ dest.writeInt(gold);
+ items.writeToParcel(dest, flags);
+ position.writeToParcel(dest, flags);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/KeyArea.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/KeyArea.java
new file mode 100644
index 000000000..b2e2a2168
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/KeyArea.java
@@ -0,0 +1,15 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+
+public final class KeyArea {
+ public final CoordRect position;
+ public final String requiredKey;
+ public final String message;
+
+ public KeyArea(final CoordRect position, final String requiredKey, final String message) {
+ this.position = new CoordRect(position);
+ this.requiredKey = requiredKey;
+ this.message = message;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.java
new file mode 100644
index 000000000..28484adf6
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredWorldMap.java
@@ -0,0 +1,203 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public final class LayeredWorldMap {
+ public static int LAYER_GROUND = 0;
+ public static int LAYER_OBJECTS = 1;
+ public static int LAYER_ABOVE = 2;
+
+ public final String name;
+ public final Size size;
+ public final MapLayer[] layers;
+ public final MapObject[] eventObjects;
+ public final KeyArea[] keyAreas;
+ public final MonsterSpawnArea[] spawnAreas;
+ public final ArrayList groundBags = new ArrayList();
+ //public final boolean hasFOW;
+ //public final boolean[][] isVisible;
+ public final boolean[][] isWalkable;
+
+ public LayeredWorldMap(String name, Size size, MapLayer[] layers, boolean[][] isWalkable, MapObject[] eventObjects, KeyArea[] keyAreas, MonsterSpawnArea[] spawnAreas, boolean hasFOW) {
+ this.name = name;
+ this.size = size;
+ this.eventObjects = eventObjects;
+ this.keyAreas = keyAreas;
+ this.spawnAreas = spawnAreas;
+ assert(size.width > 0);
+ assert(size.height > 0);
+ assert(layers.length == 3);
+ assert(isWalkable.length == size.width);
+ assert(isWalkable[0].length == size.height);
+ this.isWalkable = isWalkable;
+ this.layers = layers;
+ }
+
+ public final boolean isWalkable(final Coord p) {
+ if (isOutside(p.x, p.y)) return false;
+ return isWalkable[p.x][p.y];
+ }
+ public final boolean isWalkable(final int x, final int y) {
+ if (isOutside(x, y)) return false;
+ return 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 MapObject findEventObject(int objectType, String name) {
+ for (MapObject o : eventObjects) {
+ if (o.type == objectType && o.title.equals(name)) return o;
+ }
+ return null;
+ }
+
+ public Monster getMonsterAt(final CoordRect p) {
+ for (MonsterSpawnArea a : spawnAreas) {
+ Monster m = a.getMonsterAt(p);
+ if (m != null) return m;
+ }
+ return null;
+ }
+ public Monster getMonsterAt(final Coord p) { return getMonsterAt(p.x, p.y); }
+ public Monster getMonsterAt(final int x, final int y) {
+ for (MonsterSpawnArea a : spawnAreas) {
+ Monster m = a.getMonsterAt(x, y);
+ if (m != null) return m;
+ }
+ return null;
+ }
+
+ private boolean spawnInArea(MonsterSpawnArea a, WorldContext context) {
+ return spawnInArea(a, a.getRandomMonsterType(context));
+ }
+ public boolean TEST_spawnInArea(MonsterSpawnArea a, MonsterType type) { return spawnInArea(a, type); }
+ private boolean spawnInArea(MonsterSpawnArea a, MonsterType type) {
+ Coord p = getRandomFreePosition(a.area, type.tileSize);
+ if (p == null) return false;
+ a.spawn(p, type);
+ return true;
+ }
+
+ private Coord getRandomFreePosition(CoordRect area, Size requiredSize) {
+ CoordRect p = new CoordRect(requiredSize);
+ for(int i = 0; i < 100; ++i) {
+ p.topLeft.set(
+ area.topLeft.x + ModelContainer.rnd.nextInt(area.size.width)
+ ,area.topLeft.y + ModelContainer.rnd.nextInt(area.size.height));
+ if (!isWalkable(p)) continue;
+ if (getMonsterAt(p) != null) continue;
+ return p.topLeft;
+ }
+ return null; // Couldn't find a free spot.
+ }
+
+ public void spawnAll(WorldContext context, boolean respawnUniqueMonsters) {
+ for (MonsterSpawnArea a : spawnAreas) {
+ while (a.isSpawnable(respawnUniqueMonsters)) {
+ spawnInArea(a, context);
+ }
+ }
+ }
+ public boolean maybeSpawn(WorldContext context) {
+ boolean hasSpawned = false;
+ for (MonsterSpawnArea a : spawnAreas) {
+ if (!a.isSpawnable(false)) continue;
+ if (!a.rollShouldSpawn()) continue;
+ if (spawnInArea(a, context)) hasSpawned = true;
+ }
+ return hasSpawned;
+ }
+
+ public void remove(Monster m) {
+ for (MonsterSpawnArea a : spawnAreas) {
+ a.remove(m);
+ }
+ }
+ public Loot getBagAt(final Coord p) {
+ for (Loot l : groundBags) {
+ if (l.position.equals(p)) return l;
+ }
+ return null;
+ }
+ public Loot getBagOrCreateAt(final Coord position) {
+ Loot b = getBagAt(position);
+ if (b != null) return b;
+ b = new Loot();
+ b.position.set(position);
+ groundBags.add(b);
+ return b;
+ }
+ public void itemDropped(ItemType itemType, int quantity, Coord position) {
+ Loot l = getBagOrCreateAt(position);
+ l.items.addItem(itemType, quantity);
+ }
+ public void removeGroundLoot(Loot loot) {
+ groundBags.remove(loot);
+ }
+ public void reset() {
+ groundBags.clear();
+ for(MonsterSpawnArea a : spawnAreas) {
+ a.reset();
+ }
+ }
+
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public void readFromParcel(DataInputStream src, WorldContext world) throws IOException {
+ final int size1 = src.readInt();
+ for(int i = 0; i < size1; ++i) {
+ this.spawnAreas[i].readFromParcel(src, world);
+ }
+
+ /*
+ groundBags.clear();
+ final int size2 = src.readInt();
+ for(int i = 0; i < size2; ++i) {
+ groundBags.add(new Loot(src, world));
+ }
+ */
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(spawnAreas.length);
+ for(MonsterSpawnArea a : spawnAreas) {
+ a.writeToParcel(dest, flags);
+ }
+
+ /*
+ dest.writeInt(groundBags.size());
+ for(Loot l : groundBags) {
+ l.writeToParcel(dest, flags);
+ }
+ */
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java
new file mode 100644
index 000000000..c3dc70ce1
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java
@@ -0,0 +1,45 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+
+public final class MapCollection {
+ public final ArrayList predefinedMaps = new ArrayList();
+
+ public MapCollection() {}
+
+ public LayeredWorldMap findPredefinedMap(String name) {
+ for (LayeredWorldMap m : predefinedMaps) {
+ if (m.name.equals(name)) return m;
+ }
+ return null;
+ }
+
+ public void reset() {
+ for (LayeredWorldMap m : predefinedMaps) {
+ m.reset();
+ }
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public void readFromParcel(DataInputStream src, WorldContext world) throws IOException {
+ final int size = src.readInt();
+ for(int i = 0; i < size; ++i) {
+ predefinedMaps.get(i).readFromParcel(src, world);
+ }
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ final int size = predefinedMaps.size();
+ dest.writeInt(size);
+ for(int i = 0; i < size; ++i) {
+ predefinedMaps.get(i).writeToParcel(dest, flags);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java
new file mode 100644
index 000000000..a071c2a57
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java
@@ -0,0 +1,30 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+public final class MapLayer {
+ public final Size size;
+ public final int[][] tiles;
+
+ public MapLayer(Size size) {
+ this.size = size;
+ tiles = new int[size.width][size.height];
+ }
+ public void setTile(int type, int x, int y) {
+ tiles[x][y] = type;
+ }
+ public void setTile(int type, Coord p) {
+ setTile(type, p.x, p.y);
+ }
+ public final boolean isOutside(int x, 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(Coord p) {
+ return isOutside(p.x, p.y);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapObject.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapObject.java
new file mode 100644
index 000000000..49ac16aed
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapObject.java
@@ -0,0 +1,35 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+
+public final class MapObject {
+ public static final int MAPEVENT_SIGN = 1;
+ public static final int MAPEVENT_NEWMAP = 2;
+ public static final int MAPEVENT_REST = 3;
+
+ public final CoordRect position;
+ public final int type;
+ public final String text;
+ public final String title;
+ public final String map;
+ public final String place;
+
+ private MapObject(final CoordRect position, final int type, final String title, final String text, final String map, final String place) {
+ this.position = new CoordRect(position);
+ this.type = type;
+ this.title = title;
+ this.text = text;
+ this.map = map;
+ this.place = place;
+ }
+
+ public static MapObject createMapSignEvent(final CoordRect position, final String title, final String text) {
+ return new MapObject(position, MAPEVENT_SIGN, title, text, null, null);
+ }
+ public static MapObject createNewMapEvent(final CoordRect position, final String thisMapTitle, final String destinationMap, final String destinationPlace) {
+ return new MapObject(position, MAPEVENT_NEWMAP, thisMapTitle, null, destinationMap, destinationPlace);
+ }
+ public static MapObject createNewRest(final CoordRect position) {
+ return new MapObject(position, MAPEVENT_REST, null, null, null, null);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.java
new file mode 100644
index 000000000..588b195f7
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MonsterSpawnArea.java
@@ -0,0 +1,97 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+public final class MonsterSpawnArea {
+ public final CoordRect area;
+ public final Range quantity;
+ private final Range spawnChance;
+ public final int[] monsterTypeIDs;
+ public final ArrayList monsters = new ArrayList();
+ public final boolean isUnique; // unique == non-respawnable
+
+ public MonsterSpawnArea(CoordRect area, Range quantity, Range spawnChance, int[] monsterTypeIDs, boolean isUnique) {
+ this.area = area;
+ this.quantity = quantity;
+ this.spawnChance = spawnChance;
+ this.monsterTypeIDs = monsterTypeIDs;
+ this.isUnique = isUnique;
+ }
+
+ public Monster getMonsterAt(final Coord p) { return getMonsterAt(p.x, p.y); }
+ public Monster getMonsterAt(final int x, final int y) {
+ for (Monster m : monsters) {
+ if (m.rectPosition.contains(x, y)) return m;
+ }
+ return null;
+ }
+ public Monster getMonsterAt(final CoordRect p) {
+ for (Monster m : monsters) {
+ if (m.rectPosition.intersects(p)) return m;
+ }
+ return null;
+ }
+
+ public void spawn(Coord p, WorldContext context) {
+ final int monsterTypeID = monsterTypeIDs[ModelContainer.rnd.nextInt(monsterTypeIDs.length)];
+ spawn(p, monsterTypeID, context);
+ }
+ public MonsterType getRandomMonsterType(WorldContext context) {
+ final int monsterTypeID = monsterTypeIDs[ModelContainer.rnd.nextInt(monsterTypeIDs.length)];
+ return context.monsterTypes.getMonsterType(monsterTypeID);
+ }
+ public void spawn(Coord p, int monsterTypeID, WorldContext context) {
+ spawn(p, context.monsterTypes.getMonsterType(monsterTypeID));
+ }
+ public void spawn(Coord p, MonsterType type) {
+ monsters.add(new Monster(type, p));
+ quantity.current++;
+ }
+
+ public void remove(Monster m) {
+ if (monsters.remove(m)) quantity.current--;
+ }
+
+ public boolean isSpawnable(boolean includeUniqueMonsters) {
+ if (isUnique && !includeUniqueMonsters) return false;
+ return quantity.current < quantity.max;
+ }
+
+ public boolean rollShouldSpawn() {
+ return ModelContainer.rollResult(spawnChance);
+ }
+
+ public void reset() {
+ monsters.clear();
+ quantity.current = 0;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public void readFromParcel(DataInputStream src, WorldContext world) throws IOException {
+ monsters.clear();
+ quantity.current = src.readInt();
+ for(int i = 0; i < quantity.current; ++i) {
+ monsters.add(Monster.readFromParcel(src, world));
+ }
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(monsters.size());
+ for (Monster m : monsters) {
+ m.writeToParcel(dest, flags);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.java
new file mode 100644
index 000000000..8c799b2fb
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapReader.java
@@ -0,0 +1,429 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.zip.GZIPInputStream;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
+import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
+import com.gpl.rpg.AndorsTrail.util.Base64;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Range;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.res.XmlResourceParser;
+
+public final class TMXMapReader {
+ private ArrayList maps = new ArrayList();
+
+ public TMXMap read(XmlResourceParser xrp, String name) {
+ final TMXMap currentMap = new TMXMap();
+ try {
+ // Map format: http://sourceforge.net/apps/mediawiki/tiled/index.php?title=Examining_the_map_format
+ int eventType;
+ while ((eventType = xrp.next()) != XmlResourceParser.END_DOCUMENT) {
+ if (eventType == XmlResourceParser.START_TAG) {
+ String s = xrp.getName();
+ if (s.equals("map")) {
+ currentMap.name = name;
+ currentMap.orientation = xrp.getAttributeValue(null, "orientation");
+ currentMap.width = xrp.getAttributeIntValue(null, "width", -1);
+ currentMap.height = xrp.getAttributeIntValue(null, "height", -1);
+ currentMap.tilewidth = xrp.getAttributeIntValue(null, "tilewidth", -1);
+ currentMap.tileheight = xrp.getAttributeIntValue(null, "tileheight", -1);
+ readCurrentTagUntilEnd(xrp, new TagHandler() {
+ public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
+ if (tagName.equals("tileset")) {
+ final TMXTileSet ts = new TMXTileSet();
+ currentMap.tileSets.add(ts);
+ ts.firstgid = xrp.getAttributeIntValue(null, "firstgid", 1);
+ ts.name = xrp.getAttributeValue(null, "name");
+ ts.tilewidth = xrp.getAttributeIntValue(null, "tilewidth", -1);
+ ts.tileheight = xrp.getAttributeIntValue(null, "tileheight", -1);
+ readCurrentTagUntilEnd(xrp, new TagHandler() {
+ public void handleTag(XmlResourceParser xrp, String tagName) {
+ if (tagName.equals("image")) {
+ ts.imageSource = xrp.getAttributeValue(null, "source");
+ ts.imageName = ts.imageSource;
+
+ int v = ts.imageName.lastIndexOf('/');
+ if (v >= 0) ts.imageName = ts.imageName.substring(v+1);
+ }
+ }
+ });
+ } else if (tagName.equals("layer")) {
+ final TMXLayer layer = new TMXLayer();
+ currentMap.layers.add(layer);
+ layer.name = xrp.getAttributeValue(null, "name");
+ layer.width = xrp.getAttributeIntValue(null, "width", 1);
+ layer.height = xrp.getAttributeIntValue(null, "height", 1);
+ layer.gids = new int[layer.width][layer.height];
+ readCurrentTagUntilEnd(xrp, new TagHandler() {
+ public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
+ if (tagName.equals("data")) {
+ xrp.next();
+ String data = xrp.getText().trim();
+ final int len = layer.width * layer.height * 4;
+
+ //L.log("Layer " + layer.name + " with data " + data);
+ ByteArrayInputStream bi = new ByteArrayInputStream(Base64.decode(data));
+ GZIPInputStream zi = new GZIPInputStream(bi, len);
+ byte[] buffer = new byte[len];
+ zi.read(buffer, 0, len);
+ zi.close();
+ bi.close();
+ int i = 0;
+ for(int y = 0; y < layer.height; ++y) {
+ for(int x = 0; x < layer.width; ++x, i += 4) {
+ int gid = readIntLittleEndian(buffer, i);
+ //if (gid != 0) L.log(getHexString(buffer, i) + " -> " + gid);
+ layer.gids[x][y] = gid;
+ //L.log("(" + x + "," + y + ") : " + layer.gids[x][y]);
+ }
+ }
+ }
+ }
+ });
+ } else if (tagName.equals("objectgroup")) {
+ final TMXObjectGroup group = new TMXObjectGroup();
+ currentMap.objectGroups.add(group);
+ group.name = xrp.getAttributeValue(null, "name");
+ group.width = xrp.getAttributeIntValue(null, "width", 1);
+ group.height = xrp.getAttributeIntValue(null, "height", 1);
+ readCurrentTagUntilEnd(xrp, new TagHandler() {
+ public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
+ if (tagName.equals("object")) {
+ final TMXObject object = new TMXObject();
+ group.objects.add(object);
+ object.name = xrp.getAttributeValue(null, "name");
+ object.type = xrp.getAttributeValue(null, "type");
+ object.x = xrp.getAttributeIntValue(null, "x", -1);
+ object.y = xrp.getAttributeIntValue(null, "y", -1);
+ object.width = xrp.getAttributeIntValue(null, "width", -1);
+ object.height = xrp.getAttributeIntValue(null, "height", -1);
+ readCurrentTagUntilEnd(xrp, new TagHandler() {
+ public void handleTag(XmlResourceParser xrp, String tagName) {
+ if (tagName.equals("property")) {
+ final TMXProperty property = new TMXProperty();
+ object.properties.add(property);
+ property.name = xrp.getAttributeValue(null, "name");
+ property.value = xrp.getAttributeValue(null, "value");
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+ }
+ xrp.close();
+ } catch (XmlPullParserException e) {
+ L.log(e.toString());
+ } catch (IOException e) {
+ L.log(e.toString());
+ }
+ maps.add(currentMap);
+ return currentMap;
+ }
+
+ private interface TagHandler {
+ void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException;
+ }
+ private static void readCurrentTagUntilEnd(XmlResourceParser xrp, TagHandler handler) throws XmlPullParserException, IOException {
+ String outerTagName = xrp.getName();
+ String tagName;
+ int eventType;
+ while ((eventType = xrp.next()) != XmlResourceParser.END_DOCUMENT) {
+ if (eventType == XmlResourceParser.START_TAG) {
+ tagName = xrp.getName();
+ handler.handleTag(xrp, tagName);
+ } else if (eventType == XmlResourceParser.END_TAG) {
+ tagName = xrp.getName();
+ if (tagName.equals(outerTagName)) return;
+ }
+ }
+ }
+ /*
+ private static String getHexString(byte v) {
+ String result = Integer.toHexString(v & 0xff);
+ if (result.length() < 2) result = '0' + result;
+ return result;
+ }
+ private static String getHexString(byte[] buffer, int offset) {
+ return getHexString(buffer[offset])
+ + getHexString(buffer[offset+1])
+ + getHexString(buffer[offset+2])
+ + getHexString(buffer[offset+3]);
+ }
+ */
+ private static int readIntLittleEndian(byte[] buffer, int offset) {
+ return (buffer[offset + 0] << 0 ) & 0x000000ff |
+ (buffer[offset + 1] << 8 ) & 0x0000ff00 |
+ (buffer[offset + 2] << 16) & 0x00ff0000 |
+ (buffer[offset + 3] << 24) & 0xff000000;
+ }
+
+ public ArrayList transformMaps(DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes) {
+ return transformMaps(maps, tileLoader, monsterTypes);
+ }
+ public ArrayList transformMaps(Collection maps, DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes) {
+ ArrayList result = new ArrayList();
+
+ for (TMXMap m : maps) {
+ assert(m.name != null);
+ assert(m.name.length() > 0);
+ assert(m.width > 0);
+ assert(m.height > 0);
+
+ boolean[][] isWalkable = new boolean[m.width][m.height];
+ for (int y = 0; y < m.height; ++y) {
+ for (int x = 0; x < m.width; ++x) {
+ isWalkable[x][y] = true;
+ }
+ }
+ final Size mapSize = new Size(m.width, m.height);
+ MapLayer[] layers = new MapLayer[] {
+ new MapLayer(mapSize)
+ ,new MapLayer(mapSize)
+ ,new MapLayer(mapSize)
+ };
+ for (TMXLayer layer : m.layers) {
+ int ixMapLayer = -2;
+ String layerName = layer.name;
+ assert(layerName != null);
+ assert(layerName.length() > 0);
+ layerName = layerName.toLowerCase();
+ if (layerName.startsWith("object")) {
+ ixMapLayer = LayeredWorldMap.LAYER_OBJECTS;
+ } else if (layerName.startsWith("ground")) {
+ ixMapLayer = LayeredWorldMap.LAYER_GROUND;
+ } else if (layerName.startsWith("above")) {
+ ixMapLayer = LayeredWorldMap.LAYER_ABOVE;
+ } else if (layerName.startsWith("walk")) {
+ ixMapLayer = -1;
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: cannot handle layer " + layerName + " from map " + m.name);
+ continue;
+ }
+
+ for (int y = 0; y < layer.height; ++y) {
+ for (int x = 0; x < layer.width; ++x) {
+ int gid = layer.gids[x][y];
+ if (gid <= 0) continue;
+
+ if (ixMapLayer == -1) {
+ isWalkable[x][y] = false;
+ } else {
+ Pair p = getTile(m, gid);
+ if (p == null) continue;
+
+ String tilesetName = (String) p.first;
+ int localId = (Integer) p.second;
+ layers[ixMapLayer].tiles[x][y] = tileLoader.getTileID(tilesetName, localId);
+ }
+ }
+ }
+ }
+
+ ArrayList mapObjects = new ArrayList();
+ ArrayList spawnAreas = new ArrayList();
+ ArrayList keyAreas = new ArrayList();
+
+ for (TMXObjectGroup group : m.objectGroups) {
+ for (TMXObject object : group.objects) {
+ final Coord topLeft = new Coord(
+ Math.round(((float)object.x) / m.tilewidth)
+ ,Math.round(((float)object.y) / m.tileheight)
+ );
+ final int width = Math.round(((float)object.width) / m.tilewidth);
+ final int height = Math.round(((float)object.height) / m.tileheight);
+ final CoordRect position = new CoordRect(topLeft, new Size(width, height));
+
+ if (object.type.equalsIgnoreCase("sign")) {
+ String title = object.name;
+ String text = null;
+ for (TMXProperty p : object.properties) {
+ if(p.name.equalsIgnoreCase("text")) text = p.value;
+ else if(p.name.equalsIgnoreCase("title")) title = p.value;
+ else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", sign " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ mapObjects.add(MapObject.createMapSignEvent(position, title, text));
+ } else if (object.type.equalsIgnoreCase("mapchange")) {
+ String map = null;
+ String place = null;
+ for (TMXProperty p : object.properties) {
+ if(p.name.equalsIgnoreCase("map")) map = p.value;
+ else if(p.name.equalsIgnoreCase("place")) place = p.value;
+ else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", mapchange " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ mapObjects.add(MapObject.createNewMapEvent(position, object.name, map, place));
+ } else if (object.type.equalsIgnoreCase("spawn")) {
+ ArrayList types = new ArrayList();
+ types.addAll(monsterTypes.getMonsterTypesFromTags(object.name));
+ int maxQuantity = 1;
+ int spawnChance = 10;
+ boolean isUnique = false;
+ for (TMXProperty p : object.properties) {
+ if (p.name.equalsIgnoreCase("type")) {
+ types.addAll(monsterTypes.getMonsterTypesFromTags(p.value));
+ } else if (p.name.equalsIgnoreCase("quantity")) {
+ maxQuantity = Integer.parseInt(p.value);
+ } else if (p.name.equalsIgnoreCase("spawnchance")) {
+ spawnChance = Integer.parseInt(p.value);
+ } else if (p.name.equalsIgnoreCase("respawn")) {
+ isUnique = !Boolean.parseBoolean(p.value);
+ } else if (p.name.equalsIgnoreCase("unique")) {
+ isUnique = Boolean.parseBoolean(p.value);
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", spawn " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ }
+
+ if (types.isEmpty()) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + " contains spawn \"" + object.name + "\" that does not correspond to any monsters. The spawn will be removed.");
+ }
+ continue;
+ }
+
+ int[] monsterTypeIDs = new int[types.size()];
+ for (int i = 0; i < monsterTypeIDs.length; ++i) {
+ monsterTypeIDs[i] = types.get(i).id;
+ }
+ MonsterSpawnArea area = new MonsterSpawnArea(
+ position
+ ,new Range(maxQuantity, 0)
+ ,new Range(1000, spawnChance)
+ ,monsterTypeIDs
+ ,isUnique
+ );
+ spawnAreas.add(area);
+ } else if (object.type.equalsIgnoreCase("key")) {
+ String requiredKey = object.name;
+ String message = "";
+ for (TMXProperty p : object.properties) {
+ if (p.name.equalsIgnoreCase("message")) {
+ message = p.value;
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", key " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ }
+
+ keyAreas.add(new KeyArea(position, requiredKey, message));
+ } else if (object.type.equals("rest")) {
+ mapObjects.add(MapObject.createNewRest(position));
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", has unrecognized object type \"" + object.type + "\" for name \"" + object.name + "\".");
+ }
+ }
+ }
+ MapObject[] _eventObjects = new MapObject[mapObjects.size()];
+ _eventObjects = mapObjects.toArray(_eventObjects);
+ MonsterSpawnArea[] _spawnAreas = new MonsterSpawnArea[spawnAreas.size()];
+ _spawnAreas = spawnAreas.toArray(_spawnAreas);
+ KeyArea[] _keyAreas = new KeyArea[keyAreas.size()];
+ _keyAreas = keyAreas.toArray(_keyAreas);
+
+ result.add(new LayeredWorldMap(m.name, mapSize, layers, isWalkable, _eventObjects, _keyAreas, _spawnAreas, false));
+ }
+
+ return result;
+ }
+
+ private static Pair getTile(final TMXMap map, final int gid) {
+ for(int i = map.tileSets.size() - 1; i >= 0; --i) {
+ TMXTileSet ts = map.tileSets.get(i);
+ if (ts.firstgid <= gid) {
+ return new Pair(ts.imageName, (gid - ts.firstgid));
+ }
+ }
+ L.log("WARNING: Cannot find tile for gid " + gid); //(" + x + ", " + y + "), ")
+ return null;
+ }
+
+ private static class Pair {
+ public final T1 first;
+ public final T2 second;
+ public Pair(T1 first, T2 second) {
+ this.first = first;
+ this.second = second;
+ }
+ }
+
+ public class TMXMap {
+ public String name;
+ public String orientation;
+ public int width;
+ public int height;
+ public int tilewidth;
+ public int tileheight;
+ public List tileSets = new ArrayList();
+ public List layers = new ArrayList();
+ public List objectGroups = new ArrayList();
+ }
+ public class TMXTileSet {
+ public int firstgid;
+ public String name;
+ public int tilewidth;
+ public int tileheight;
+ public String imageSource;
+ public String imageName;
+ }
+ public class TMXLayer {
+ public String name;
+ public int width;
+ public int height;
+ public int[][] gids;
+ }
+ public class TMXObjectGroup {
+ public String name;
+ public int width;
+ public int height;
+ public List objects = new ArrayList();
+ }
+ public class TMXObject {
+ public String name;
+ public String type;
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+ public List properties = new ArrayList();
+ }
+ public class TMXProperty {
+ public String name;
+ public String value;
+ }
+ /*
+
+
+
+ */
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java
new file mode 100644
index 000000000..24cbcf56c
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java
@@ -0,0 +1,169 @@
+package com.gpl.rpg.AndorsTrail.resource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.graphics.BitmapFactory.Options;
+
+public final class DynamicTileLoader {
+ private final TileStore store;
+ private final Resources r;
+
+ private final ArrayList preparedTilesets = new ArrayList();
+ private int allocatedTiles = 0;
+ private int currentTileStoreIndex;
+
+ public DynamicTileLoader(TileStore store, Resources r) {
+ this.store = store;
+ this.r = r;
+ initialize();
+ }
+
+ private void initialize() {
+ allocatedTiles = 0;
+ preparedTilesets.clear();
+ currentTileStoreIndex = store.bitmaps.length;
+ }
+
+ public void prepareTileset(int resourceId, String tilesetName, Size numTiles, Size destinationTileSize) {
+ preparedTilesets.add(new TilesetBitmap(resourceId, tilesetName, numTiles, destinationTileSize));
+ }
+ private TilesetBitmap getTilesetBitmap(int tilesetImageResourceID) {
+ for (TilesetBitmap b : preparedTilesets) {
+ if (b.resourceId == tilesetImageResourceID) {
+ return b;
+ }
+ }
+ return null;
+ }
+
+ public int getTileID(int tilesetImageResourceID, int localId) {
+ TilesetBitmap b = getTilesetBitmap(tilesetImageResourceID);
+ if (b == null) {
+ L.log("WARNING: Cannot load tileset " + tilesetImageResourceID);
+ return currentTileStoreIndex-1;
+ }
+ return getTileID(b, localId);
+ }
+
+ public int getTileID(String tilesetName, int localId) {
+ for (TilesetBitmap b : preparedTilesets) {
+ if (b.tilesetName.equals(tilesetName)) {
+ return getTileID(b, localId);
+ }
+ }
+ L.log("WARNING: Cannot load tileset " + tilesetName);
+ return currentTileStoreIndex-1;
+ }
+
+ private int getTileID(TilesetBitmap tileset, int localId) {
+ int tileStoreIndex = 0;
+ if (tileset.tilesToLoad.containsKey(localId)) {
+ tileStoreIndex = tileset.tilesToLoad.get(localId);
+ } else {
+ tileStoreIndex = currentTileStoreIndex;
+ ++currentTileStoreIndex;
+ ++allocatedTiles;
+ tileset.tilesToLoad.put(localId, tileStoreIndex);
+ }
+ return tileStoreIndex;
+ }
+
+ public void flush() {
+ store.allocateTiles(allocatedTiles);
+
+ for (TilesetBitmap b : preparedTilesets) {
+ if (b.tilesToLoad.isEmpty()) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Tileset " + b.tilesetName + " does not contain any loaded tiles. The file could be removed from the project.");
+ }
+ continue;
+ }
+
+ boolean recycle = true;
+ Bitmap tilesetImage = createTilesetImage(b);
+ for (int localId : b.tilesToLoad.keySet()) {
+ int tileStoreIndex = b.tilesToLoad.get(localId);
+ store.bitmaps[tileStoreIndex] = createTileFromTileset(tilesetImage, b, localId);
+ if (store.bitmaps[tileStoreIndex] == tilesetImage) recycle = false;
+ }
+ if (recycle) tilesetImage.recycle();
+ }
+
+ initialize();
+ }
+
+ private Bitmap createTilesetImage(TilesetBitmap b) {
+ Options o = new Options();
+ o.inScaled = false;
+ Bitmap sourceImage = BitmapFactory.decodeResource(r, b.resourceId, o);
+ b.calculateFromSourceImageSize(sourceImage.getWidth(), sourceImage.getHeight());
+ return sourceImage;
+ }
+
+ private Bitmap createTileFromTileset(Bitmap tilesetImage, TilesetBitmap tileset, int localId) {
+ final int x = localId % tileset.numTiles.width;
+ final int y = (localId - x) / tileset.numTiles.width;
+ final int left = x * tileset.sourceTileSize.width;
+ final int top = y * tileset.sourceTileSize.height;
+ if (tileset.scale != null) {
+ return Bitmap.createBitmap(tilesetImage, left, top, tileset.sourceTileSize.width, tileset.sourceTileSize.height, tileset.scale, true);
+ } else {
+ return Bitmap.createBitmap(tilesetImage, left, top, tileset.sourceTileSize.width, tileset.sourceTileSize.height);
+ }
+ }
+
+ public static int measureBitmapWidth(Resources r, int resourceId) {
+ Bitmap b = BitmapFactory.decodeResource(r, resourceId);
+ int width = b.getWidth();
+ b.recycle();
+ return width;
+ }
+
+ private static class TilesetBitmap {
+ public final int resourceId;
+ public final String tilesetName;
+ public final Size destinationTileSize;
+ public final Size numTiles;
+ public Size sourceTileSize;
+ public Matrix scale;
+
+ public HashMap tilesToLoad = new HashMap();
+
+ public TilesetBitmap(int resourceId, String tilesetName, Size numTiles, Size destinationTileSize) {
+ this.resourceId = resourceId;
+ this.tilesetName = tilesetName;
+ this.destinationTileSize = destinationTileSize;
+ this.numTiles = numTiles;
+ }
+
+ public void calculateFromSourceImageSize(final int sourceWidth, final int sourceHeight) {
+ sourceTileSize = new Size(
+ sourceWidth / numTiles.width
+ ,sourceHeight / numTiles.height
+ );
+
+ if (destinationTileSize.width == sourceTileSize.width && destinationTileSize.height == sourceTileSize.height) {
+ scale = null;
+ } else {
+ scale = new Matrix();
+ scale.postScale(
+ ((float) destinationTileSize.width) / sourceTileSize.width
+ ,((float) destinationTileSize.height) / sourceTileSize.height
+ );
+
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Tileset " + tilesetName + " will be resized from " + sourceTileSize.toString() + " to " + destinationTileSize.toString());
+ }
+ }
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java
new file mode 100644
index 000000000..1c074aac7
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java
@@ -0,0 +1,242 @@
+package com.gpl.rpg.AndorsTrail.resource;
+
+import java.util.regex.Pattern;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
+import com.gpl.rpg.AndorsTrail.model.map.TMXMapReader;
+import com.gpl.rpg.AndorsTrail.util.ConstRange;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.res.Resources;
+
+public final class ResourceLoader {
+
+ public static void loadResources(WorldContext world, Resources r) {
+
+ final TileStore tiles = world.tileStore;
+ tiles.displayTileSize = DynamicTileLoader.measureBitmapWidth(r, R.drawable.equip_body);
+ final int mTileSize = 32; //tiles.displayTileSize;
+ L.log("displayTileSize=" + mTileSize);
+
+ final Size dst_sz2x2 = new Size(mTileSize*2, mTileSize*2);
+ final Size dst_sz2x3 = new Size(mTileSize*2, mTileSize*3);
+ final Size dst_sz4x3 = new Size(mTileSize*4, mTileSize*3);
+ final Size dst_sz1x1 = new Size(mTileSize, mTileSize);
+ final Size defaultTileSize = dst_sz1x1;
+ final Size src_sz1x1 = new Size(1, 1);
+ final Size src_sz6x1 = new Size(6, 1);
+ final Size src_sz7x1 = new Size(7, 1);
+ final Size src_mapTileSize = new Size(16, 8);
+ final Size src_mapTileSize7 = new Size(16, 7);
+
+ DynamicTileLoader loader = new DynamicTileLoader(tiles, r);
+
+ // ========================================================================
+ // Load various ui icons
+ loader.prepareTileset(R.drawable.char_hero, "char_hero", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_2, "map_tiles_1_2", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_7, "map_tiles_2_7", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_6, "map_tiles_1_6", src_mapTileSize, defaultTileSize);
+ /*tiles.iconID_CHAR_HERO = */loader.getTileID(R.drawable.char_hero, 0);
+ /*tiles.iconID_attackselect = */loader.getTileID(R.drawable.map_tiles_1_2, 6+16*5);
+ /*tiles.iconID_moveselect = */loader.getTileID(R.drawable.map_tiles_1_2, 7+16*5);
+ /*tiles.iconID_groundbag = */loader.getTileID(R.drawable.map_tiles_2_7, 13+16*0);
+ /*tiles.iconID_mapsign = */loader.getTileID(R.drawable.map_tiles_1_6, 1+16*3);
+ loader.flush();
+
+ // ========================================================================
+ // Load item icons
+ loader.prepareTileset(R.drawable.items_tiles, "items_tiles", new Size(14, 30), defaultTileSize);
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_money));
+ assert(world.itemTypes.getItemTypeByTag("gold") != null);
+ assert(world.itemTypes.getItemTypeByTag("gold").id == ItemTypeCollection.ITEMTYPE_GOLD);
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_weapons));
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_armour));
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_debug));
+ } else {
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_rings));
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_junk));
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_food));
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_animal));
+ world.itemTypes.initialize(loader, r.getString(R.string.itemlist_quest));
+ }
+ loader.flush();
+
+ world.dropLists.initialize(world.itemTypes);
+
+ // ========================================================================
+ // Conversation
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ world.conversations.initialize(world.itemTypes, r.getString(R.string.conversationlist_debug));
+ } else {
+ world.conversations.initialize(world.itemTypes, r.getString(R.string.conversationlist_mikhail));
+ world.conversations.initialize(world.itemTypes, r.getString(R.string.conversationlist_crossglen));
+ }
+
+ // ========================================================================
+ // Load monster icons
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.monsters_armor1, "monsters_armor1", src_sz1x1, defaultTileSize);
+ }
+ loader.prepareTileset(R.drawable.monsters_demon1, "monsters_demon1", src_sz1x1, dst_sz2x2);
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.monsters_demon2, "monsters_demon2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_dogs, "monsters_dogs", src_sz7x1, defaultTileSize);
+ }
+ loader.prepareTileset(R.drawable.monsters_dragons, "monsters_dragons", src_sz7x1, defaultTileSize);
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.monsters_eye1, "monsters_eye1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_eye2, "monsters_eye2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_eye3, "monsters_eye3", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_eye4, "monsters_eye4", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_ghost1, "monsters_ghost1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_ghost2, "monsters_ghost2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_hydra1, "monsters_hydra1", src_sz1x1, dst_sz2x2);
+ }
+ loader.prepareTileset(R.drawable.monsters_insects, "monsters_insects", src_sz6x1, defaultTileSize);
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.monsters_liches, "monsters_liches", new Size(4, 1), defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_mage2, "monsters_mage2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_mage3, "monsters_mage3", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_mage4, "monsters_mage4", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_mage, "monsters_mage", src_sz1x1, defaultTileSize);
+ }
+ loader.prepareTileset(R.drawable.monsters_man1, "monsters_man1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_men, "monsters_men", new Size(9, 1), defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_misc, "monsters_misc", new Size(12, 1), defaultTileSize);
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.monsters_rats, "monsters_rats", new Size(5, 1), defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_rogue1, "monsters_rogue1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_skeleton1, "monsters_skeleton1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_skeleton2, "monsters_skeleton2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_snakes, "monsters_snakes", src_sz6x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_cyclops, "monsters_cyclops", src_sz1x1, dst_sz2x3);
+ loader.prepareTileset(R.drawable.monsters_warrior1, "monsters_warrior1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_wraiths, "monsters_wraiths", new Size(3, 1), defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_zombie1, "monsters_zombie1", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_zombie2, "monsters_zombie2", src_sz1x1, defaultTileSize);
+ loader.prepareTileset(R.drawable.monsters_dragon1, "monsters_dragon1", src_sz1x1, dst_sz4x3);
+ }
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ world.monsterTypes.initialize(world.dropLists, loader, r.getString(R.string.monsterlist_debug));
+ world.monsterTypes.initialize(world.dropLists, loader, r.getString(R.string.monsterlist_misc));
+ }
+ world.monsterTypes.initialize(world.dropLists, loader, r.getString(R.string.monsterlist_crossglen_animals));
+ world.monsterTypes.initialize(world.dropLists, loader, r.getString(R.string.monsterlist_crossglen_npcs));
+ loader.flush();
+
+ // ========================================================================
+ // Load map icons
+ loader.prepareTileset(R.drawable.map_tiles_1_1, "map_tiles_1_1.png", src_mapTileSize, defaultTileSize);
+ if (!AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ loader.prepareTileset(R.drawable.map_tiles_1_2, "map_tiles_1_2.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_3, "map_tiles_1_3.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_4, "map_tiles_1_4.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_5, "map_tiles_1_5.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_6, "map_tiles_1_6.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_7, "map_tiles_1_7.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_1_8, "map_tiles_1_8.png", src_mapTileSize7, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_1, "map_tiles_2_1.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_2, "map_tiles_2_2.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_3, "map_tiles_2_3.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_4, "map_tiles_2_4.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_5, "map_tiles_2_5.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_6, "map_tiles_2_6.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_7, "map_tiles_2_7.png", src_mapTileSize, defaultTileSize);
+ loader.prepareTileset(R.drawable.map_tiles_2_8, "map_tiles_2_8.png", src_mapTileSize7, defaultTileSize);
+ }
+ TMXMapReader mapReader = new TMXMapReader();
+
+ if (AndorsTrailApplication.DEVELOPMENT_VERSION) {
+ mapReader.read(r.getXml(R.xml.debugmap), "debugmap");
+ } else {
+ mapReader.read(r.getXml(R.xml.home), "home");
+ mapReader.read(r.getXml(R.xml.crossglen), "crossglen");
+ mapReader.read(r.getXml(R.xml.crossglen_farmhouse), "crossglen_farmhouse");
+ mapReader.read(r.getXml(R.xml.crossglen_farmhouse_basement), "crossglen_farmhouse_basement");
+ mapReader.read(r.getXml(R.xml.crossglen_hall), "crossglen_hall");
+ mapReader.read(r.getXml(R.xml.crossglen_smith), "crossglen_smith");
+ mapReader.read(r.getXml(R.xml.crossglen_cave), "crossglen_cave");
+ }
+
+ world.maps.predefinedMaps.addAll(mapReader.transformMaps(loader, world.monsterTypes));
+ mapReader = null;
+
+ loader.flush();
+
+
+ // ========================================================================
+ // Load effects
+ loader.prepareTileset(R.drawable.effect_blood3, "effect_blood3", new Size(8, 2), dst_sz1x1);
+ world.effectTypes.initialize(loader);
+ loader.flush();
+
+ loader = null;
+ // ========================================================================
+ }
+
+ public static final Pattern rowPattern = Pattern.compile("\\{(.+?)\\};", Pattern.MULTILINE | Pattern.DOTALL);
+ public static final String columnSeparator = "\\|";
+ public static int parseImage(DynamicTileLoader tileLoader, String s) {
+ String[] parts = s.split(":");
+ return tileLoader.getTileID(parts[0], Integer.parseInt(parts[1]));
+ }
+ public static ConstRange parseRange(String s) {
+ if (s == null || s.length() <= 0) return null;
+ String[] parts = s.split("-");
+ if (parts.length < 2) {
+ int val = Integer.parseInt(s);
+ return new ConstRange(val, val);
+ } else {
+ return new ConstRange(Integer.parseInt(parts[1]), Integer.parseInt(parts[0]));
+ }
+ }
+ public static Size parseSize(String s, final Size defaultSize) {
+ if (s == null || s.length() <= 0) return defaultSize;
+ String[] parts = s.split("x");
+ if (parts.length < 2) return defaultSize;
+ return new Size(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
+ }
+ public static CombatTraits parseCombatTraits(String[] parts, int startIndex) {
+ String AtkCost = parts[startIndex];
+ String AtkPct = parts[startIndex + 1];
+ String CritPct = parts[startIndex + 2];
+ String CritMult = parts[startIndex + 3];
+ String DMG = parts[startIndex + 4];
+ String BlkPct = parts[startIndex + 5];
+ String DMG_res = parts[startIndex + 6];
+ if ( AtkCost.length() <= 0
+ && AtkPct.length() <= 0
+ && CritPct.length() <= 0
+ && CritMult.length() <= 0
+ && DMG.length() <= 0
+ && BlkPct.length() <= 0
+ && DMG_res.length() <= 0
+ ) {
+ return null;
+ } else {
+ CombatTraits result = new CombatTraits();
+ result.attackCost = parseInt(AtkCost, 0);
+ result.attackChance = parseInt(AtkPct, 0);
+ result.criticalChance = parseInt(CritPct, 0);
+ result.criticalMultiplier = parseInt(CritMult, 0);
+ ConstRange r = parseRange(DMG);
+ if (r != null) result.damagePotential.set(r);
+ result.blockChance = parseInt(BlkPct, 0);
+ result.damageResistance = parseInt(DMG_res, 0);
+ return result;
+ }
+ }
+ public static int parseInt(String s, int defaultValue) {
+ if (s == null || s.length() <= 0) return defaultValue;
+ return Integer.parseInt(s);
+ }
+
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java
new file mode 100644
index 000000000..265a25228
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java
@@ -0,0 +1,25 @@
+package com.gpl.rpg.AndorsTrail.resource;
+
+import android.graphics.Bitmap;
+
+public final class TileStore {
+ public static final int CHAR_HERO = 1;
+ public static final int iconID_attackselect = 2;
+ public static final int iconID_moveselect = 3;
+ public static final int iconID_groundbag = 4;
+ public static final int iconID_shop = iconID_groundbag;
+ public static final int iconID_mapsign = 5;
+
+ public int displayTileSize = 32;
+
+ //TODO: should be final.
+ public Bitmap[] bitmaps = new Bitmap[1];
+
+ public void allocateTiles(int tilecount) {
+ if (tilecount <= 0) return;
+
+ Bitmap[] oldArray = bitmaps;
+ bitmaps = new Bitmap[bitmaps.length + tilecount];
+ System.arraycopy(oldArray, 0, bitmaps, 0, oldArray.length);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Base64.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Base64.java
new file mode 100644
index 000000000..a72d2b34f
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Base64.java
@@ -0,0 +1,189 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+public final class Base64 {
+ private static final byte[] encodingTable = { (byte) 'A', (byte) 'B',
+ (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
+ (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
+ (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q',
+ (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V',
+ (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a',
+ (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k',
+ (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p',
+ (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4',
+ (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
+ (byte) '+', (byte) '/' };
+
+ /**
+ * encode the input data producong a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(byte[] data) {
+ byte[] bytes;
+
+ int modulus = data.length % 3;
+ if (modulus == 0) {
+ bytes = new byte[4 * data.length / 3];
+ } else {
+ bytes = new byte[4 * ((data.length / 3) + 1)];
+ }
+
+ int dataLength = (data.length - modulus);
+ int a1, a2, a3;
+ for (int i = 0, j = 0; i < dataLength; i += 3, j += 4) {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+ bytes[j] = encodingTable[(a1 >>> 2) & 0x3f];
+ bytes[j + 1] = encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f];
+ bytes[j + 2] = encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f];
+ bytes[j + 3] = encodingTable[a3 & 0x3f];
+ }
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+ switch (modulus) {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[data.length - 1] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+ bytes[bytes.length - 4] = encodingTable[b1];
+ bytes[bytes.length - 3] = encodingTable[b2];
+ bytes[bytes.length - 2] = (byte) '=';
+ bytes[bytes.length - 1] = (byte) '=';
+ break;
+ case 2:
+ d1 = data[data.length - 2] & 0xff;
+ d2 = data[data.length - 1] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+ bytes[bytes.length - 4] = encodingTable[b1];
+ bytes[bytes.length - 3] = encodingTable[b2];
+ bytes[bytes.length - 2] = encodingTable[b3];
+ bytes[bytes.length - 1] = (byte) '=';
+ break;
+ }
+ return bytes;
+ }
+
+ /*
+ * set up the decoding table.
+ */
+ private static final byte[] decodingTable;
+ static {
+ decodingTable = new byte[128];
+ for (int i = 'A'; i <= 'Z'; i++) {
+ decodingTable[i] = (byte) (i - 'A');
+ }
+ for (int i = 'a'; i <= 'z'; i++) {
+ decodingTable[i] = (byte) (i - 'a' + 26);
+ }
+ for (int i = '0'; i <= '9'; i++) {
+ decodingTable[i] = (byte) (i - '0' + 52);
+ }
+ decodingTable['+'] = 62;
+ decodingTable['/'] = 63;
+ }
+
+ /**
+ * decode the base 64 encoded input data.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(byte[] data) {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+ if (data[data.length - 2] == '=') {
+ bytes = new byte[(((data.length / 4) - 1) * 3) + 1];
+ } else if (data[data.length - 1] == '=') {
+ bytes = new byte[(((data.length / 4) - 1) * 3) + 2];
+ } else {
+ bytes = new byte[((data.length / 4) * 3)];
+ }
+ for (int i = 0, j = 0; i < data.length - 4; i += 4, j += 3) {
+ b1 = decodingTable[data[i]];
+ b2 = decodingTable[data[i + 1]];
+ b3 = decodingTable[data[i + 2]];
+ b4 = decodingTable[data[i + 3]];
+ bytes[j] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte) ((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte) ((b3 << 6) | b4);
+ }
+ if (data[data.length - 2] == '=') {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+ bytes[bytes.length - 1] = (byte) ((b1 << 2) | (b2 >> 4));
+ } else if (data[data.length - 1] == '=') {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+ b3 = decodingTable[data[data.length - 2]];
+ bytes[bytes.length - 2] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte) ((b2 << 4) | (b3 >> 2));
+ } else {
+ b1 = decodingTable[data[data.length - 4]];
+ b2 = decodingTable[data[data.length - 3]];
+ b3 = decodingTable[data[data.length - 2]];
+ b4 = decodingTable[data[data.length - 1]];
+ bytes[bytes.length - 3] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte) ((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte) ((b3 << 6) | b4);
+ }
+ return bytes;
+ }
+
+ /**
+ * decode the base 64 encoded String data.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(String data) {
+ byte[] bytes;
+ byte b1, b2, b3, b4;
+ if (data.charAt(data.length() - 2) == '=') {
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 1];
+ } else if (data.charAt(data.length() - 1) == '=') {
+ bytes = new byte[(((data.length() / 4) - 1) * 3) + 2];
+ } else {
+ bytes = new byte[((data.length() / 4) * 3)];
+ }
+ for (int i = 0, j = 0; i < data.length() - 4; i += 4, j += 3) {
+ b1 = decodingTable[data.charAt(i)];
+ b2 = decodingTable[data.charAt(i + 1)];
+ b3 = decodingTable[data.charAt(i + 2)];
+ b4 = decodingTable[data.charAt(i + 3)];
+ bytes[j] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[j + 1] = (byte) ((b2 << 4) | (b3 >> 2));
+ bytes[j + 2] = (byte) ((b3 << 6) | b4);
+ }
+ if (data.charAt(data.length() - 2) == '=') {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+ bytes[bytes.length - 1] = (byte) ((b1 << 2) | (b2 >> 4));
+ } else if (data.charAt(data.length() - 1) == '=') {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+ b3 = decodingTable[data.charAt(data.length() - 2)];
+ bytes[bytes.length - 2] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 1] = (byte) ((b2 << 4) | (b3 >> 2));
+ } else {
+ b1 = decodingTable[data.charAt(data.length() - 4)];
+ b2 = decodingTable[data.charAt(data.length() - 3)];
+ b3 = decodingTable[data.charAt(data.length() - 2)];
+ b4 = decodingTable[data.charAt(data.length() - 1)];
+
+ bytes[bytes.length - 3] = (byte) ((b1 << 2) | (b2 >> 4));
+ bytes[bytes.length - 2] = (byte) ((b2 << 4) | (b3 >> 2));
+ bytes[bytes.length - 1] = (byte) ((b3 << 6) | b4);
+ }
+
+ return bytes;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ConstRange.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ConstRange.java
new file mode 100644
index 000000000..5909cc9ac
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ConstRange.java
@@ -0,0 +1,29 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+public final class ConstRange {
+ public final int max;
+ public final int current;
+
+ public ConstRange(Range r) {
+ this.max = r.max;
+ this.current = r.current;
+ }
+ public ConstRange(ConstRange r) {
+ this.max = r.max;
+ this.current = r.current;
+ }
+ public ConstRange(int max, int current) {
+ this.max = max;
+ this.current = current;
+ }
+
+ public String toString() { return current + "/" + max; }
+ public String toMinMaxString() {
+ if (isMax()) return Integer.toString(max);
+ else return current + "-" + max;
+ }
+ public boolean isMax() { return max == current; }
+ public int average() {
+ return current + (max - current);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Coord.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Coord.java
new file mode 100644
index 000000000..d6b3449c3
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Coord.java
@@ -0,0 +1,47 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public final class Coord {
+ public int x;
+ public int y;
+ public Coord() {}
+ public Coord(int x, int y) { this.x = x; this.y = y; }
+ public Coord(Coord p) { this.x = p.x; this.y = p.y; }
+
+ public String toString() { return "(" + x + "," + y + ")"; }
+ public void set(int x, int y) { this.x = x; this.y = y; }
+ public void set(Coord r) {
+ this.x = r.x;
+ this.y = r.y;
+ }
+
+ public boolean equals(final Coord p) { return p.x == this.x && p.y == this.y; }
+ public boolean equals(final int x, final int y) { return x == this.x && y == this.y; }
+ public boolean contains(final Coord p) { return p.x == this.x && p.y == this.y; }
+ public boolean contains(final int x, final int y) { return x == this.x && y == this.y; }
+ public boolean isAdjacentTo(Coord p) {
+ final int dx = x - p.x;
+ final int dy = y - p.y;
+ if (dx == 0 && dy == 0) return false;
+ else if (Math.abs(dx) > 1) return false;
+ else if (Math.abs(dy) > 1) return false;
+ return true;
+ }
+
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Coord(DataInputStream src) throws IOException {
+ this.x = src.readInt();
+ this.y = src.readInt();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(x);
+ dest.writeInt(y);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/CoordRect.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/CoordRect.java
new file mode 100644
index 000000000..81a1f8ee1
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/CoordRect.java
@@ -0,0 +1,69 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+public final class CoordRect {
+ public final Coord topLeft;
+ public final Size size;
+ public CoordRect(Size size) {
+ topLeft = new Coord();
+ this.size = size;
+ }
+ public CoordRect(Coord topLeft, Size size) {
+ this.topLeft = topLeft;
+ this.size = size;
+ }
+ public CoordRect(CoordRect copy) {
+ this.topLeft = copy.topLeft;
+ this.size = copy.size;
+ }
+ public boolean contains(Coord p) {
+ if (p.x < topLeft.x) return false;
+ else if (p.y < topLeft.y) return false;
+ else if (p.x - topLeft.x >= size.width) return false;
+ else if (p.y - topLeft.y >= size.height) return false;
+ else return true;
+ }
+ public boolean contains(final int x, final int y) {
+ if (x < topLeft.x) return false;
+ else if (y < topLeft.y) return false;
+ else if (x - topLeft.x >= size.width) return false;
+ else if (y - topLeft.y >= size.height) return false;
+ else return true;
+ }
+
+ /*
+ public static boolean contains(final int x, final int y, final Size size, final Coord p) {
+ if (p.x < x) return false;
+ else if (p.y < y) return false;
+ else if (p.x - x >= size.width) return false;
+ else if (p.y - y >= size.height) return false;
+ else return true;
+ }
+ */
+ public boolean intersects(final CoordRect a) {
+ if (a.topLeft.x >= topLeft.x + size.width) return false;
+ if (a.topLeft.y >= topLeft.y + size.height) return false;
+ if (topLeft.x >= a.topLeft.x + a.size.width) return false;
+ if (topLeft.y >= a.topLeft.y + a.size.height) return false;
+ return true;
+ }
+
+ public boolean isAdjacentTo(Coord p) {
+ final int dx = p.x - topLeft.x;
+ final int dy = p.y - topLeft.y;
+ if (dx < -1) return false;
+ else if (dy < -1) return false;
+ else if (dx > size.width) return false;
+ else if (dy > size.height) return false;
+ return true;
+ }
+ public Coord getCenter() {
+ Coord center = new Coord(topLeft);
+ center.x += size.width / 2;
+ center.y += size.height / 2;
+ return center;
+ }
+
+ public String toString() {
+ return "{" + topLeft.toString() + ", " + size.toString() + "}";
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/L.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/L.java
new file mode 100644
index 000000000..264233cc3
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/L.java
@@ -0,0 +1,11 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+import android.util.Log;
+
+public class L {
+ private static final String TAG = "AndorsTrail";
+
+ public static void log(String s) {
+ Log.d(TAG, s);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Range.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Range.java
new file mode 100644
index 000000000..d40d41606
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Range.java
@@ -0,0 +1,63 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public final class Range {
+ public int max;
+ public int current;
+
+ public Range() { }
+ public Range(Range r) { set(r); }
+ public Range(ConstRange r) { set(r); }
+ public Range(int max, int current) {
+ this.max = max;
+ this.current = current;
+ }
+
+ public void set(Range r) {
+ this.max = r.max;
+ this.current = r.current;
+ }
+ public void set(ConstRange r) {
+ this.max = r.max;
+ this.current = r.current;
+ }
+ public void set(int max, int current) {
+ this.max = max;
+ this.current = current;
+ }
+ public void add(int value, boolean mayOverflow) {
+ this.current += value;
+ if (!mayOverflow && current > max) current = max;
+ }
+ public void subtract(int value, boolean mayUnderflow) {
+ this.current -= value;
+ if (!mayUnderflow && current < 0) current = 0;
+ }
+
+ public String toString() { return current + "/" + max; }
+ public String toMinMaxString() {
+ if (isMax()) return Integer.toString(max);
+ else return current + "-" + max;
+ }
+ public boolean isMax() { return current >= max; }
+ public void setMax() { current = max; }
+ public int average() {
+ return current + (max - current);
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Range(DataInputStream src) throws IOException {
+ this.max = src.readInt();
+ this.current = src.readInt();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(max);
+ dest.writeInt(current);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Size.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Size.java
new file mode 100644
index 000000000..f5c3f595c
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/Size.java
@@ -0,0 +1,38 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public final class Size {
+ public final int width;
+ public final int height;
+ public Size(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ public String toString() {
+ return width + "x" + height;
+ }
+
+ public boolean equals(final Size s) {
+ return width == s.width && height == s.height;
+ }
+ public boolean equals(final int w, final int h) {
+ return width == w && height == h;
+ }
+
+
+ // ====== PARCELABLE ===================================================================
+
+ public Size(DataInputStream src) throws IOException {
+ this.width = src.readInt();
+ this.height = src.readInt();
+ }
+
+ public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
+ dest.writeInt(width);
+ dest.writeInt(height);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java
new file mode 100644
index 000000000..c68247d39
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java
@@ -0,0 +1,124 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.Dialogs;
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.activity.MainActivity;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.CombatController;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+public final class CombatView extends FrameLayout {
+ private final TextView statusTextView;
+ private final Button attackMoveButton;
+ private final ImageButton monsterInfo;
+ private final RangeBar monsterHealth;
+ private final View monsterBar;
+ private final View actionBar;
+ private final TextView monsterActionText;
+
+ private final WorldContext world;
+ private final ViewContext view;
+
+ private MonsterType currentMonsterType;
+ public CombatView(final Context context, AttributeSet attr) {
+ super(context, attr);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
+ this.world = app.world;
+ this.view = app.currentView.get();
+
+ setFocusable(false);
+ inflate(context, R.layout.combatview, this);
+ this.setBackgroundResource(R.drawable.ui_gradientshape);
+
+ final CombatController c = view.combatController;
+ attackMoveButton = (Button) findViewById(R.id.combatview_moveattack);
+ attackMoveButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ c.executeMoveAttack();
+ }
+ });
+
+ Button endTurnButton = (Button) findViewById(R.id.combatview_endturn);
+ endTurnButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ c.endPlayerTurn();
+ }
+ });
+ Button endCombatButton = (Button) findViewById(R.id.combatview_endcombat);
+ endCombatButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ if (c.canExitCombat()) {
+ c.exitCombat();
+ } else {
+ ((MainActivity) context).message(getResources().getString(R.string.combat_cannotexitcombat));
+ }
+ }
+ });
+
+ statusTextView = (TextView) findViewById(R.id.combatview_status);
+
+ monsterInfo = (ImageButton) findViewById(R.id.combatview_monsterinfo);
+ monsterInfo.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ Dialogs.showMonsterInfo(view.mainActivity, currentMonsterType.id);
+ }
+ });
+
+ monsterHealth = (RangeBar) findViewById(R.id.combatview_monsterhealth);
+ monsterHealth.init(R.drawable.ui_progress_health, R.string.combat_monsterhealth);
+ monsterBar = findViewById(R.id.combatview_monsterbar);
+ actionBar = findViewById(R.id.combatview_actionbar);
+ monsterActionText = (TextView) findViewById(R.id.combatview_monsterismoving);
+ }
+
+ public void updateTurnInfo(Monster currentActiveMonster) {
+ if (currentActiveMonster != null) {
+ actionBar.setVisibility(View.INVISIBLE);
+ monsterActionText.setVisibility(View.VISIBLE);
+ monsterActionText.setText(getResources().getString(R.string.combat_monsteraction, currentActiveMonster.traits.name));
+ } else {
+ actionBar.setVisibility(View.VISIBLE);
+ monsterActionText.setVisibility(View.GONE);
+ }
+ }
+
+ public void updateMonsterHealth(Range range) {
+ monsterHealth.update(range);
+ }
+ public void updatePlayerAP(Range range) {
+ statusTextView.setText(getResources().getString(R.string.combat_status_ap, range.current));
+ }
+ public void updateCombatSelection(Monster selectedMonster, Coord selectedMovePosition) {
+ attackMoveButton.setEnabled(true);
+ monsterBar.setVisibility(View.INVISIBLE);
+ currentMonsterType = null;
+ if (selectedMonster != null) {
+ attackMoveButton.setText(getResources().getString(R.string.combat_attack, world.model.player.traits.attackCost));
+ monsterBar.setVisibility(View.VISIBLE);
+ monsterInfo.setImageBitmap(world.tileStore.bitmaps[selectedMonster.traits.iconID]);
+ updateMonsterHealth(selectedMonster.health);
+ currentMonsterType = selectedMonster.monsterType;
+ } else if (selectedMovePosition != null) {
+ attackMoveButton.setText(getResources().getString(R.string.combat_move, world.model.player.traits.moveCost));
+ } else {
+ attackMoveButton.setEnabled(false);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java
new file mode 100644
index 000000000..633f22274
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java
@@ -0,0 +1,42 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+
+public final class ItemContainerAdapter extends ArrayAdapter {
+ private final TileStore tileStore;
+
+ public ItemContainerAdapter(Context context, TileStore tileStore, ItemContainer items) {
+ super(context, 0, items.items);
+ this.tileStore = tileStore;
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ //return new InventoryItemView(getContext(), getItem(position));
+ final ItemEntry item = getItem(position);
+
+ View result = convertView;
+ if (result == null) {
+ result = View.inflate(getContext(), R.layout.inventoryitemview, null);
+ }
+
+ ((ImageView) result.findViewById(R.id.inv_image)).setImageBitmap(tileStore.bitmaps[item.itemType.iconID]);
+ ((TextView) result.findViewById(R.id.inv_text)).setText(item.itemType.describe(item.quantity));
+ return result;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).itemType.id;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
new file mode 100644
index 000000000..191df1dbf
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
@@ -0,0 +1,457 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.context.ViewContext;
+import com.gpl.rpg.AndorsTrail.controller.EffectController.EffectAnimation;
+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.LayeredWorldMap;
+import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
+import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+public final class MainView extends SurfaceView implements SurfaceHolder.Callback {
+
+ private int displayTileSize = 32;
+
+ 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 final ModelContainer model;
+ private final TileStore tiles;
+ private final ViewContext view;
+
+ private final SurfaceHolder holder;
+ private final Paint mPaint = new Paint();
+ private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1));
+ private Bitmap doubleBuffer;
+ private Canvas doubleBufferCanvas;
+ private boolean hasSurface = false;
+
+ private final Coord lastTouchPosition = new Coord();
+
+ public MainView(Context context, AttributeSet attr) {
+ super(context, attr);
+ this.holder = getHolder();
+
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
+ this.view = app.currentView.get();
+ this.model = app.world.model;
+ this.tiles = app.world.tileStore;
+
+ holder.addCallback(this);
+
+ setFocusable(true);
+ requestFocus();
+ setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ MainView.this.onClick();
+ }
+ });
+ setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ return MainView.this.onLongClick();
+ }
+ });
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent msg) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ movePlayer(0, -1);
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ movePlayer(0, 1);
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ movePlayer(-1, 0);
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ movePlayer(1, 0);
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ this.onClick();
+ } else {
+ return super.onKeyDown(keyCode, msg);
+ }
+ //TODO: add more keys
+ return true;
+ }
+
+ private void movePlayer(int dx, int dy) {
+ view.movementController.movePlayer(dx, dy);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ if (w <= 0 || h <= 0) return;
+
+ L.log("surfaceChanged " + w + ", " + h);
+
+ displayTileSize = tiles.displayTileSize;
+
+ screenSizeTileCount = new Size(
+ (int) Math.floor(w / displayTileSize)
+ ,(int) Math.floor(h / displayTileSize)
+ );
+
+ screenOffset.set(
+ (w - (displayTileSize * screenSizeTileCount.width)) / 2
+ ,(h - (displayTileSize * screenSizeTileCount.height)) / 2
+ );
+
+ if (doubleBuffer != null) {
+ doubleBuffer.recycle();
+ }
+ doubleBuffer = Bitmap.createBitmap(displayTileSize * screenSizeTileCount.width, displayTileSize * screenSizeTileCount.height, Bitmap.Config.RGB_565);
+ doubleBufferCanvas = new Canvas(doubleBuffer);
+ //doubleBufferCanvas.clipRect(0, 0, displayTileSize * screenSizeTileCount.width, displayTileSize * screenSizeTileCount.height);
+
+ if (model.currentMap != null) {
+ notifyMapChanged();
+ }
+
+ redrawAll();
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ hasSurface = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ hasSurface = false;
+ L.log("surfaceDestroyed");
+ if (doubleBuffer != null) {
+ doubleBufferCanvas = null;
+ doubleBuffer.recycle();
+ doubleBuffer = null;
+ }
+ }
+
+ private void onClick() {
+ if (model.uiSelections.isInCombat) {
+ view.combatController.executeMoveAttack();
+ }
+ }
+
+ private boolean onLongClick() {
+ final Coord tilePosition = getScreenToTilePosition(lastTouchPosition);
+ final int dx = tilePosition.x - model.player.position.x;
+ final int dy = tilePosition.y - model.player.position.y;
+ if (model.uiSelections.isInCombat) {
+ //TODO: Should be able to mark positions far away (mapwalk / ranged combat)
+ if (dx == 0 && dy == 0) return false;
+ if (Math.abs(dx) > 1) return false;
+ if (Math.abs(dy) > 1) return false;
+
+ view.combatController.setCombatSelection(tilePosition);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ lastTouchPosition.set((int)event.getX(), (int)event.getY());
+ if (!model.uiSelections.isInCombat) {
+ final Coord tilePosition = getScreenToTilePosition(lastTouchPosition);
+ final int dx = tilePosition.x - model.player.position.x;
+ final int dy = tilePosition.y - model.player.position.y;
+ view.movementController.movePlayer(sgn(dx), sgn(dy));
+ return true;
+ }
+ }
+ return super.onTouchEvent(event);
+ }
+
+ private static int sgn(final int v) {
+ if (v == 0) return 0;
+ else if (v > 0) return 1;
+ else return -1;
+ }
+
+ private Coord getScreenToTilePosition(Coord c) {
+ return new Coord(
+ (int) Math.floor((c.x - screenOffset.x) / displayTileSize) + mapTopLeft.x
+ ,(int) Math.floor((c.y - screenOffset.y) / displayTileSize) + mapTopLeft.y
+ );
+ }
+
+ public void redrawAll() {
+ updateDoubleBuffer(mapViewArea);
+ redrawFromDoubleBuffer();
+ }
+
+ public void redrawTile(final Coord p) {
+ p1x1.topLeft.set(p);
+ updateDoubleBuffer(p1x1);
+ redrawFromDoubleBuffer();
+ }
+ private void updateDoubleBuffer(final CoordRect area) {
+ if (!hasSurface) return;
+ doDrawRect(doubleBufferCanvas, area);
+ }
+ public void redrawFromDoubleBuffer() {
+ if (!hasSurface) return;
+
+ //L.log("Redraw ");
+ //long start = System.currentTimeMillis();
+
+ Canvas c = null;
+ try {
+ c = holder.lockCanvas(null);
+ synchronized (holder) {
+ c.drawBitmap(doubleBuffer, screenOffset.x, screenOffset.y, mPaint);
+ }
+ } finally {
+ // do this in a finally so that if an exception is thrown
+ // during the above, we don't leave the Surface in an
+ // inconsistent state
+ if (c != null) {
+ holder.unlockCanvasAndPost(c);
+ }
+ }
+ //long stop = System.currentTimeMillis();
+ //L.log("draw: " + (stop-start) + "ms");
+ }
+
+ public void redrawTileWithEffect(final CoordRect area, final EffectAnimation effect) {
+ if (!hasSurface) return;
+
+ Canvas c = null;
+ try {
+ c = holder.lockCanvas(null);
+ synchronized (holder) {
+ c.translate(screenOffset.x, screenOffset.y);
+ c.drawBitmap(doubleBuffer, 0, 0, mPaint);
+ drawFromMapPosition(c, area, effect.position.x, effect.position.y, effect.currentTileID);
+ if (effect.displayText != null) {
+ drawEffectText(c, area, effect);
+ }
+ }
+ } finally {
+ // do this in a finally so that if an exception is thrown
+ // during the above, we don't leave the Surface in an
+ // inconsistent state
+ if (c != null) {
+ holder.unlockCanvasAndPost(c);
+ }
+ }
+ }
+
+
+ /*
+ private void doDraw(Canvas canvas) {
+ final LayeredWorldMap currentMap = model.currentMap;
+
+ drawMapLayer(canvas, currentMap.layers[LayeredWorldMap.LAYER_GROUND]);
+ tryDrawMapLayer(canvas, currentMap, LayeredWorldMap.LAYER_OBJECTS);
+
+ for (Loot l : currentMap.groundBags) {
+ drawFromMapPosition(canvas, l.position, TileStore.iconID_groundbag);
+ }
+
+ drawFromMapPosition(canvas, model.player.position, model.player.traits.iconID);
+ for (MonsterSpawnArea a : currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ drawFromMapPosition(canvas, m.position, m.traits.iconID);
+ }
+ }
+
+ tryDrawMapLayer(canvas, currentMap, LayeredWorldMap.LAYER_ABOVE);
+
+ if (model.uiSelections.selectedMonster != null) {
+ drawFromMapPosition(canvas, model.uiSelections.selectedPosition, TileStore.iconID_attackselect);
+ } else if (model.uiSelections.selectedPosition != null) {
+ drawFromMapPosition(canvas, model.uiSelections.selectedPosition, TileStore.iconID_moveselect);
+ }
+
+ for (EffectAnimation e : view.effectController.currentEffects) {
+ if (e == null) continue;
+ drawFromMapPosition(canvas, e.position.x, e.position.y, e.currentTileID);
+ if (e.displayText != null) {
+ drawEffectText(canvas, e);
+ }
+ }
+ }
+
+ private void doDrawTile(final Canvas canvas, final Coord pos) {
+ int sx = pos.x - mapTopLeft.x;
+ int sy = pos.y - mapTopLeft.y;
+ if (sx < 0 || sx > mapViewSize.width) return;
+ if (sy < 0 || sy > mapViewSize.height) return;
+ sx *= mTileSize;
+ sy *= mTileSize;
+
+ final int mx = pos.x;
+ final int my = pos.y;
+
+ final LayeredWorldMap currentMap = model.currentMap;
+ int tile = currentMap.layers[LayeredWorldMap.LAYER_GROUND].tiles[mx][my];
+ if (tile != 0) canvas.drawBitmap(tiles.bitmaps[tile], sx, sy, mPaint);
+
+ tile = currentMap.layers[LayeredWorldMap.LAYER_OBJECTS].tiles[mx][my];
+ if (tile != 0) canvas.drawBitmap(tiles.bitmaps[tile], sx, sy, mPaint);
+
+ for (Loot l : currentMap.groundBags) {
+ if (l.position.equals(pos)) {
+ canvas.drawBitmap(tiles.bitmaps[TileStore.iconID_groundbag], sx, sy, mPaint);
+ }
+ }
+
+ if (model.player.position.equals(pos)) {
+ canvas.drawBitmap(tiles.bitmaps[model.player.traits.iconID], sx, sy, mPaint);
+ }
+
+ for (MonsterSpawnArea a : currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ if (m.position.equals(pos)) {
+ canvas.drawBitmap(tiles.bitmaps[m.traits.iconID], sx, sy, mPaint);
+ }
+ }
+ }
+
+ if (currentMap.layers.length > LayeredWorldMap.LAYER_ABOVE) {
+ tile = currentMap.layers[LayeredWorldMap.LAYER_ABOVE].tiles[mx][my];
+ if (tile != 0) canvas.drawBitmap(tiles.bitmaps[tile], sx, sy, mPaint);
+ }
+
+ if (model.uiSelections.selectedPosition != null && model.uiSelections.selectedPosition.equals(pos)) {
+ if (model.uiSelections.selectedMonster != null) {
+ canvas.drawBitmap(tiles.bitmaps[TileStore.iconID_attackselect], sx, sy, mPaint);
+ } else if (model.uiSelections.selectedPosition != null) {
+ canvas.drawBitmap(tiles.bitmaps[TileStore.iconID_moveselect], sx, sy, mPaint);
+ }
+ }
+
+ for (EffectAnimation e : view.effectController.currentEffects) {
+ if (e == null) continue;
+ if (e.position.equals(pos)) {
+ canvas.drawBitmap(tiles.bitmaps[e.currentTileID], sx, sy, mPaint);
+ if (e.displayText != null) {
+ drawEffectText(canvas, e);
+ }
+ }
+ }
+ }
+ */
+
+ private void doDrawRect(Canvas canvas, CoordRect area) {
+ final LayeredWorldMap currentMap = model.currentMap;
+
+ drawMapLayer(canvas, area, currentMap.layers[LayeredWorldMap.LAYER_GROUND]);
+ tryDrawMapLayer(canvas, area, currentMap, LayeredWorldMap.LAYER_OBJECTS);
+
+ for (Loot l : currentMap.groundBags) {
+ drawFromMapPosition(canvas, area, l.position, TileStore.iconID_groundbag);
+ }
+
+ drawFromMapPosition(canvas, area, model.player.position, model.player.traits.iconID);
+ for (MonsterSpawnArea a : currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ drawFromMapPosition(canvas, area, m.position, m.traits.iconID);
+ }
+ }
+
+ tryDrawMapLayer(canvas, area, currentMap, LayeredWorldMap.LAYER_ABOVE);
+
+ if (model.uiSelections.selectedPosition != null) {
+ if (model.uiSelections.selectedMonster != null) {
+ drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileStore.iconID_attackselect);
+ } else {
+ drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileStore.iconID_moveselect);
+ }
+ }
+ }
+
+ private void tryDrawMapLayer(Canvas canvas, final CoordRect area, final LayeredWorldMap currentMap, final int layerIndex) {
+ if (currentMap.layers.length > layerIndex) drawMapLayer(canvas, area, currentMap.layers[layerIndex]);
+ }
+
+ private void drawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
+ int my = area.topLeft.y;
+ int py = (area.topLeft.y - mapViewArea.topLeft.y) * displayTileSize;
+ int px0 = (area.topLeft.x - mapViewArea.topLeft.x) * displayTileSize;
+ for (int y = 0; y < area.size.height; ++y, ++my, py += displayTileSize) {
+ int mx = area.topLeft.x;
+ int px = px0;
+ for (int x = 0; x < area.size.width; ++x, ++mx, px += displayTileSize) {
+ final int tile = layer.tiles[mx][my];
+ if (tile != 0) {
+ canvas.drawBitmap(tiles.bitmaps[tile], px, py, mPaint);
+ }
+ }
+ }
+ }
+
+ private void drawFromMapPosition(Canvas canvas, final CoordRect area, final Coord p, final int tile) {
+ drawFromMapPosition(canvas, area, p.x, p.y, tile);
+ }
+
+ private void drawFromMapPosition(Canvas canvas, final CoordRect area, int x, int y, final int tile) {
+ if (!area.contains(x, y)) return;
+
+ x -= mapViewArea.topLeft.x;
+ y -= mapViewArea.topLeft.y;
+ if ( (x >= 0 && x < mapViewArea.size.width)
+ && (y >= 0 && y < mapViewArea.size.height)) {
+ canvas.drawBitmap(tiles.bitmaps[tile],
+ x * displayTileSize,
+ y * displayTileSize,
+ mPaint);
+ }
+ }
+
+ private void drawEffectText(Canvas canvas, final CoordRect area, final EffectAnimation e) {
+ int x = (e.position.x - mapViewArea.topLeft.x) * displayTileSize + displayTileSize/2;
+ int y = (e.position.y - mapViewArea.topLeft.y) * displayTileSize + displayTileSize/2 + e.textYOffset;
+ canvas.drawText(e.displayText, x, y, e.textPaint);
+ }
+
+ public void notifyMapChanged() {
+ Size mapViewSize = new Size(
+ Math.min(screenSizeTileCount.width, model.currentMap.size.width)
+ ,Math.min(screenSizeTileCount.height, model.currentMap.size.height)
+ );
+ mapViewArea = new CoordRect(mapTopLeft, mapViewSize);
+ notifyPlayerMoved();
+ doubleBufferCanvas.drawColor(Color.BLACK);
+ redrawAll();
+ }
+ public void notifyPlayerMoved() {
+ mapTopLeft.set(0, 0);
+
+ final LayeredWorldMap currentMap = model.currentMap;
+ final Coord playerpos = model.player.position;
+
+ if (currentMap.size.width > screenSizeTileCount.width) {
+ mapTopLeft.x = Math.max(0, playerpos.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, playerpos.y - mapViewArea.size.height/2);
+ mapTopLeft.y = Math.min(mapTopLeft.y, currentMap.size.height - mapViewArea.size.height);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/RangeBar.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/RangeBar.java
new file mode 100644
index 000000000..46b54fc99
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/RangeBar.java
@@ -0,0 +1,41 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.util.Range;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public final class RangeBar extends RelativeLayout {
+ private final ProgressBar progressBar;
+ private final TextView progressBarText;
+ private final TextView labelText;
+
+ public RangeBar(Context context, AttributeSet attr) {
+ super(context, attr);
+ setFocusable(false);
+ inflate(context, R.layout.rangebar, this);
+
+ progressBarText = (TextView) findViewById(R.id.rangebar_text);
+ progressBar = (ProgressBar) findViewById(R.id.rangebar_progress);
+ labelText = (TextView) findViewById(R.id.rangebar_label);
+ }
+
+ public void init(int drawableID, int labelTextID) {
+ // Wow, you actually need to call this twice (!), or the progressbar won't show the progress image, just the background.
+ // TODO: investigate strangeness of setProgressDrawable
+ progressBar.setProgressDrawable(getResources().getDrawable(drawableID));
+ progressBar.setProgressDrawable(getResources().getDrawable(drawableID));
+ labelText.setText(labelTextID);
+ }
+
+ public void update(final Range range) {
+ progressBar.setMax(range.max);
+ progressBar.setProgress(Math.min(range.current, range.max));
+ progressBarText.setText(range.toString());
+ invalidate();
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java
new file mode 100644
index 000000000..95ccf3082
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java
@@ -0,0 +1,84 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.controller.ItemController;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
+import com.gpl.rpg.AndorsTrail.model.item.ItemType;
+import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+
+public final class ShopItemContainerAdapter extends ArrayAdapter {
+ private final TileStore tileStore;
+ private final OnContainerItemClickedListener clickListener;
+ private final boolean isSelling;
+ private final Resources r;
+ private final Player player;
+
+ public ShopItemContainerAdapter(Context context, TileStore tileStore, Player player, ItemContainer items, OnContainerItemClickedListener clickListener, boolean isSelling) {
+ super(context, 0, items.items);
+ this.tileStore = tileStore;
+ this.player = player;
+ this.clickListener = clickListener;
+ this.isSelling = isSelling;
+ this.r = context.getResources();
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ //return new InventoryItemView(getContext(), getItem(position));
+ final ItemEntry item = getItem(position);
+ final ItemType itemType = item.itemType;
+
+ View result = convertView;
+ if (result == null) {
+ result = View.inflate(getContext(), R.layout.shopitemview, null);
+ }
+
+ ((ImageView) result.findViewById(R.id.shopitem_image)).setImageBitmap(tileStore.bitmaps[itemType.iconID]);
+ ((TextView) result.findViewById(R.id.shopitem_text)).setText(itemType.describe(item.quantity));
+ Button b = (Button) result.findViewById(R.id.shopitem_shopbutton);
+ if (isSelling) {
+ b.setText(r.getString(R.string.shop_sellitem, ItemController.getSellingPrice(player, itemType)));
+ b.setEnabled(ItemController.maySellItem(player, itemType));
+ } else {
+ int price = ItemController.getBuyingPrice(player, itemType);
+ b.setText(r.getString(R.string.shop_buyitem, price));
+ b.setEnabled(ItemController.canAfford(player, price));
+ }
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ clickListener.onItemActionClicked(position, itemType, isSelling);
+ }
+ });
+ b = (Button) result.findViewById(R.id.shopitem_infobutton);
+ b.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ clickListener.onItemInfoClicked(position, itemType, isSelling);
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).itemType.id;
+ }
+
+ public static interface OnContainerItemClickedListener {
+ void onItemActionClicked(int position, ItemType itemType, boolean isSelling);
+ void onItemInfoClicked(int position, ItemType itemType, boolean isSelling);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java
new file mode 100644
index 000000000..75ba23cbc
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java
@@ -0,0 +1,84 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.activity.MainActivity;
+import com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.model.actor.Player;
+import com.gpl.rpg.AndorsTrail.resource.TileStore;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.ImageButton;
+
+public final class StatusView extends RelativeLayout {
+
+ private final WorldContext world;
+ private final Player player;
+
+ private final RangeBar healthBar;
+ private final RangeBar expBar;
+ private final ImageButton heroImage;
+ private boolean showingLevelup;
+ private final Drawable levelupDrawable;
+
+ public StatusView(final Context context, AttributeSet attr) {
+ super(context, attr);
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
+ this.world = app.world;
+ this.player = app.world.model.player;
+
+ setFocusable(false);
+ inflate(context, R.layout.statusview, this);
+ this.setBackgroundResource(R.drawable.ui_gradientshape);
+
+ heroImage = (ImageButton) findViewById(R.id.status_image);
+ showingLevelup = true;
+
+ heroImage.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ Intent intent = new Intent(context, HeroinfoActivity.class);
+ AndorsTrailApplication.getActivityFromActivityContext(context).startActivityForResult(intent, MainActivity.INTENTREQUEST_HEROINFO);
+ }
+ });
+ healthBar = (RangeBar) findViewById(R.id.statusview_health);
+ healthBar.init(R.drawable.ui_progress_health, R.string.status_hp);
+
+ expBar = (RangeBar) findViewById(R.id.statusview_exp);
+ expBar.init(R.drawable.ui_progress_exp, R.string.status_exp);
+
+ levelupDrawable = new LayerDrawable(new Drawable[] {
+ new BitmapDrawable(world.tileStore.bitmaps[player.traits.iconID])
+ ,new BitmapDrawable(world.tileStore.bitmaps[TileStore.iconID_moveselect])
+ });
+
+ update();
+ updateIcon(player.canLevelup());
+ }
+
+ public void update() {
+ healthBar.update(player.health);
+ expBar.update(player.levelExperience);
+ boolean canLevelUp = player.canLevelup();
+ if (showingLevelup != canLevelUp) {
+ updateIcon(canLevelUp);
+ }
+ }
+
+ private void updateIcon(boolean canLevelUp) {
+ showingLevelup = canLevelUp;
+ if (canLevelUp) {
+ heroImage.setImageDrawable(levelupDrawable);
+ } else {
+ heroImage.setImageBitmap(world.tileStore.bitmaps[player.traits.iconID]);
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.java
new file mode 100644
index 000000000..74b7a0d0c
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/TraitsInfoView.java
@@ -0,0 +1,91 @@
+package com.gpl.rpg.AndorsTrail.view;
+
+import com.gpl.rpg.AndorsTrail.R;
+import com.gpl.rpg.AndorsTrail.model.CombatTraits;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+public final class TraitsInfoView extends TableLayout {
+ private final TableRow traitsinfo_attack_row1;
+ private final TableRow traitsinfo_attack_row2;
+ private final TableRow traitsinfo_attack_row3;
+ private final TableRow traitsinfo_critical_row1;
+ private final TableRow traitsinfo_critical_row2;
+ private final TableRow traitsinfo_defense_row1;
+ private final TableRow traitsinfo_defense_row2;
+ private final TextView traitsinfo_attack_cost;
+ private final TextView traitsinfo_attack_chance;
+ private final TextView traitsinfo_attack_damage;
+ private final TextView traitsinfo_criticalhit_chance;
+ private final TextView traitsinfo_criticalhit_multiplier;
+ private final TextView traitsinfo_defense_chance;
+ private final TextView traitsinfo_defense_damageresist;
+
+ public TraitsInfoView(Context context, AttributeSet attr) {
+ super(context, attr);
+ setFocusable(false);
+ inflate(context, R.layout.traitsinfoview, this);
+
+ traitsinfo_attack_row1 = (TableRow) findViewById(R.id.traitsinfo_attack_row1);
+ traitsinfo_attack_row2 = (TableRow) findViewById(R.id.traitsinfo_attack_row2);
+ traitsinfo_attack_row3 = (TableRow) findViewById(R.id.traitsinfo_attack_row3);
+ traitsinfo_critical_row1 = (TableRow) findViewById(R.id.traitsinfo_critical_row1);
+ traitsinfo_critical_row2 = (TableRow) findViewById(R.id.traitsinfo_critical_row2);
+ traitsinfo_defense_row1 = (TableRow) findViewById(R.id.traitsinfo_defense_row1);
+ traitsinfo_defense_row2 = (TableRow) findViewById(R.id.traitsinfo_defense_row2);
+ traitsinfo_attack_cost = (TextView) findViewById(R.id.traitsinfo_attack_cost);
+ traitsinfo_attack_chance = (TextView) findViewById(R.id.traitsinfo_attack_chance);
+ traitsinfo_attack_damage = (TextView) findViewById(R.id.traitsinfo_attack_damage);
+ traitsinfo_criticalhit_chance = (TextView) findViewById(R.id.traitsinfo_criticalhit_chance);
+ traitsinfo_criticalhit_multiplier = (TextView) findViewById(R.id.traitsinfo_criticalhit_multiplier);
+ traitsinfo_defense_chance = (TextView) findViewById(R.id.traitsinfo_defense_chance);
+ traitsinfo_defense_damageresist = (TextView) findViewById(R.id.traitsinfo_defense_damageresist);
+ }
+
+ public void update(CombatTraits traits) {
+ if (traits != null && traits.attackCost != 0) {
+ traitsinfo_attack_row1.setVisibility(View.VISIBLE);
+ traitsinfo_attack_cost.setText(Integer.toString(traits.attackCost));
+ } else {
+ traitsinfo_attack_row1.setVisibility(View.GONE);
+ }
+ if (traits != null && traits.hasAttackChanceEffect()) {
+ traitsinfo_attack_row2.setVisibility(View.VISIBLE);
+ traitsinfo_attack_chance.setText(Integer.toString(traits.attackChance) + "%");
+ } else {
+ traitsinfo_attack_row2.setVisibility(View.GONE);
+ }
+ if (traits != null && traits.hasAttackDamageEffect()) {
+ traitsinfo_attack_row3.setVisibility(View.VISIBLE);
+ traitsinfo_attack_damage.setText(traits.damagePotential.toMinMaxString());
+ } else {
+ traitsinfo_attack_row3.setVisibility(View.GONE);
+ }
+ if (traits != null && traits.hasCriticalEffect()) {
+ traitsinfo_critical_row1.setVisibility(View.VISIBLE);
+ traitsinfo_critical_row2.setVisibility(View.VISIBLE);
+ traitsinfo_criticalhit_chance.setText(Integer.toString(traits.criticalChance) + "%");
+ traitsinfo_criticalhit_multiplier.setText(Integer.toString(traits.criticalMultiplier));
+ } else {
+ traitsinfo_critical_row1.setVisibility(View.GONE);
+ traitsinfo_critical_row2.setVisibility(View.GONE);
+ }
+ if (traits != null && traits.hasBlockEffect()) {
+ traitsinfo_defense_row1.setVisibility(View.VISIBLE);
+ traitsinfo_defense_chance.setText(Integer.toString(traits.blockChance) + "%");
+ } else {
+ traitsinfo_defense_row1.setVisibility(View.GONE);
+ }
+ if (traits != null && traits.damageResistance != 0) {
+ traitsinfo_defense_row2.setVisibility(View.VISIBLE);
+ traitsinfo_defense_damageresist.setText(Integer.toString(traits.damageResistance));
+ } else {
+ traitsinfo_defense_row2.setVisibility(View.GONE);
+ }
+ }
+}