diff --git a/AndorsTrail/res/raw/conversationlist_debug.json b/AndorsTrail/res/raw/conversationlist_debug.json
index ead482671..50cc54102 100644
--- a/AndorsTrail/res/raw/conversationlist_debug.json
+++ b/AndorsTrail/res/raw/conversationlist_debug.json
@@ -193,18 +193,46 @@
{
"nextPhraseID":"npc3_1",
"text":"Beer!"
- },
- {
- "nextPhraseID":"npc3_2",
- "text":"Lights out!"
},
{
"nextPhraseID":"npc3_3",
- "text":"Lights on!"
+ "text":"No filter!"
+ },
+ {
+ "nextPhraseID":"npc3_5",
+ "text":"Black 20%!"
+ },
+ {
+ "nextPhraseID":"npc3_6",
+ "text":"Black 40%!"
+ },
+ {
+ "nextPhraseID":"npc3_7",
+ "text":"Black 60%!"
+ },
+ {
+ "nextPhraseID":"npc3_2",
+ "text":"Black 80%!"
},
{
"nextPhraseID":"npc3_4",
"text":"Red ligths!"
+ },
+ {
+ "nextPhraseID":"npc3_9",
+ "text":"Green ligths!"
+ },
+ {
+ "nextPhraseID":"npc3_10",
+ "text":"Blue ligths!"
+ },
+ {
+ "nextPhraseID":"npc3_11",
+ "text":"Black & White!"
+ },
+ {
+ "nextPhraseID":"npc3_8",
+ "text":"Invert!"
}
]
},
@@ -266,6 +294,83 @@
}
]
},
+ {
+ "id":"npc3_5",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"black20",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_6",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"black40",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_7",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"black60",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_8",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"invert",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_9",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"greentint",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_10",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"bluetint",
+ "mapName":"debugmap"
+ }
+ ]
+ },
+ {
+ "id":"npc3_11",
+ "message":"Ok.",
+ "rewards":[
+ {
+ "rewardType":"changeMapFilter",
+ "rewardID":"bw",
+ "mapName":"debugmap"
+ }
+ ]
+ },
{
"id":"chaotic_rewarder_0",
"message":"What do you want ?",
diff --git a/AndorsTrail/res/values/strings.xml b/AndorsTrail/res/values/strings.xml
index 7867fb831..8936ab5ee 100644
--- a/AndorsTrail/res/values/strings.xml
+++ b/AndorsTrail/res/values/strings.xml
@@ -475,6 +475,10 @@
Optimized drawing
Disable this if you see graphical artifacts. Enabling this option will make the game only redraw changed parts of the screen every frame.
+ High quality filters
+ Disable this if you experience performance issues on filtered maps (dark caves for example). Enabling this option will make the game use advanced color filters, instead of solid color overlays.
+
+
diff --git a/AndorsTrail/res/xml/preferences.xml b/AndorsTrail/res/xml/preferences.xml
index 5fdd0caf8..aaa992698 100644
--- a/AndorsTrail/res/xml/preferences.xml
+++ b/AndorsTrail/res/xml/preferences.xml
@@ -26,6 +26,11 @@
android:defaultValue="false"
android:summary="@string/preferences_optimized_drawing"
android:key="optimized_drawing" />
+
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java
index 2cf7f9ce0..b71d932de 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java
@@ -3,28 +3,27 @@ package com.gpl.rpg.AndorsTrail;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
+
+import com.gpl.rpg.AndorsTrail.context.ControllerContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.Constants;
+
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.os.Build;
import android.os.Environment;
import android.view.Window;
import android.view.WindowManager;
-import com.gpl.rpg.AndorsTrail.context.ControllerContext;
-import com.gpl.rpg.AndorsTrail.context.WorldContext;
-import com.gpl.rpg.AndorsTrail.controller.Constants;
-import com.gpl.rpg.AndorsTrail.util.L;
-
public final class AndorsTrailApplication extends Application {
- public static final boolean DEVELOPMENT_DEBUGRESOURCES = false;
+ public static final boolean DEVELOPMENT_DEBUGRESOURCES = true;
public static final boolean DEVELOPMENT_FORCE_STARTNEWGAME = false;
public static final boolean DEVELOPMENT_FORCE_CONTINUEGAME = false;
- public static final boolean DEVELOPMENT_DEBUGBUTTONS = false;
+ public static final boolean DEVELOPMENT_DEBUGBUTTONS = true;
public static final boolean DEVELOPMENT_FASTSPEED = false;
public static final boolean DEVELOPMENT_VALIDATEDATA = true;
public static final boolean DEVELOPMENT_DEBUGMESSAGES = true;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
index d90d5ec01..e9af916a5 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailPreferences.java
@@ -1,102 +1,105 @@
-package com.gpl.rpg.AndorsTrail;
-
-import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-public final class AndorsTrailPreferences {
- public static final int DISPLAYLOOT_DIALOG_ALWAYS = 0;
- public static final int DISPLAYLOOT_DIALOG_FOR_ITEMS = 3;
- public static final int DISPLAYLOOT_DIALOG_FOR_ITEMS_ELSE_TOAST = 4;
- public static final int DISPLAYLOOT_TOAST = 1;
- public static final int DISPLAYLOOT_TOAST_FOR_ITEMS = 5;
- public static final int DISPLAYLOOT_NONE = 2;
- public static final int MOVEMENTMETHOD_STRAIGHT = 0;
- public static final int MOVEMENTMETHOD_DIRECTIONAL = 1;
- public static final int MOVEMENTAGGRESSIVENESS_NORMAL = 0;
- public static final int MOVEMENTAGGRESSIVENESS_AGGRESSIVE = 1;
- public static final int MOVEMENTAGGRESSIVENESS_DEFENSIVE = 2;
- public static final int DPAD_POSITION_DISABLED = 0;
- public static final int DPAD_POSITION_LOWER_RIGHT = 1;
- public static final int DPAD_POSITION_LOWER_LEFT = 2;
- public static final int DPAD_POSITION_LOWER_CENTER = 3;
- public static final int DPAD_POSITION_CENTER_LEFT = 4;
- public static final int DPAD_POSITION_CENTER_RIGHT = 5;
- public static final int DPAD_POSITION_UPPER_LEFT = 6;
- public static final int DPAD_POSITION_UPPER_RIGHT = 7;
- public static final int DPAD_POSITION_UPPER_CENTER = 8;
- public static final int CONFIRM_OVERWRITE_SAVEGAME_ALWAYS = 0;
- public static final int CONFIRM_OVERWRITE_SAVEGAME_WHEN_PLAYERNAME_DIFFERS = 1;
- public static final int CONFIRM_OVERWRITE_SAVEGAME_NEVER = 2;
- public static final int QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM = 0;
- public static final int QUICKSLOTS_POSITION_VERTICAL_CENTER_LEFT = 1;
- public static final int QUICKSLOTS_POSITION_VERTICAL_CENTER_RIGHT = 2;
- public static final int QUICKSLOTS_POSITION_VERTICAL_BOTTOM_LEFT = 3;
- public static final int QUICKSLOTS_POSITION_HORIZONTAL_BOTTOM_LEFT = 4;
- public static final int QUICKSLOTS_POSITION_HORIZONTAL_BOTTOM_RIGHT = 5;
- public static final int QUICKSLOTS_POSITION_VERTICAL_BOTTOM_RIGHT = 6;
- public static final int ATTACKSPEED_DEFAULT_MILLISECONDS = 1000;
-
- public boolean confirmRest = true;
- public boolean confirmAttack = true;
- public int displayLoot = DISPLAYLOOT_DIALOG_ALWAYS;
- public boolean fullscreen = true;
- public int attackspeed_milliseconds = 1000;
- public int movementMethod = MOVEMENTMETHOD_STRAIGHT;
- public int movementAggressiveness = MOVEMENTAGGRESSIVENESS_NORMAL;
- public float scalingFactor = 1.0f;
- public int dpadPosition;
- public boolean dpadMinimizeable = true;
- public boolean optimizedDrawing = false;
- public boolean enableUiAnimations = true;
- public int displayOverwriteSavegame = CONFIRM_OVERWRITE_SAVEGAME_ALWAYS;
- public int quickslotsPosition = QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM;
- public boolean showQuickslotsWhenToolboxIsVisible = false;
- public boolean useLocalizedResources = true;
- public int selectedTheme = 0;
-
- public void read(final Context androidContext) {
- AndorsTrailPreferences dest = this;
- try {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(androidContext);
- dest.confirmRest = prefs.getBoolean("confirm_rest", true);
- dest.confirmAttack = prefs.getBoolean("confirm_attack", true);
- dest.displayLoot = Integer.parseInt(prefs.getString("display_lootdialog", Integer.toString(DISPLAYLOOT_DIALOG_ALWAYS)));
- dest.fullscreen = prefs.getBoolean("fullscreen", true);
- dest.attackspeed_milliseconds = Integer.parseInt(prefs.getString("attackspeed", "1000"));
- dest.movementMethod = Integer.parseInt(prefs.getString("movementmethod", Integer.toString(MOVEMENTMETHOD_STRAIGHT)));
- dest.scalingFactor = Float.parseFloat(prefs.getString("scaling_factor", "1.0f"));
- dest.dpadPosition = Integer.parseInt(prefs.getString("dpadposition", Integer.toString(DPAD_POSITION_DISABLED)));
- dest.dpadMinimizeable = prefs.getBoolean("dpadMinimizeable", true);
- dest.optimizedDrawing = prefs.getBoolean("optimized_drawing", false);
- dest.enableUiAnimations = prefs.getBoolean("enableUiAnimations", true);
- dest.displayOverwriteSavegame = Integer.parseInt(prefs.getString("display_overwrite_savegame", Integer.toString(CONFIRM_OVERWRITE_SAVEGAME_ALWAYS)));
- dest.quickslotsPosition = Integer.parseInt(prefs.getString("quickslots_placement", Integer.toString(QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM)));
- dest.showQuickslotsWhenToolboxIsVisible = prefs.getBoolean("showQuickslotsWhenToolboxIsVisible", false);
- dest.useLocalizedResources = prefs.getBoolean("useLocalizedResources", true);
- dest.selectedTheme = Integer.parseInt(prefs.getString("selectedTheme", Integer.toString(0)));
- // This might be implemented as a skill in the future.
- //dest.movementAggressiveness = Integer.parseInt(prefs.getString("movementaggressiveness", Integer.toString(MOVEMENTAGGRESSIVENESS_NORMAL)));
- } catch (Exception e) {
- dest.confirmRest = true;
- dest.confirmAttack = true;
- dest.displayLoot = DISPLAYLOOT_DIALOG_ALWAYS;
- dest.fullscreen = true;
- dest.attackspeed_milliseconds = 1000;
- dest.movementMethod = MOVEMENTMETHOD_STRAIGHT;
- dest.movementAggressiveness = MOVEMENTAGGRESSIVENESS_NORMAL;
- dest.scalingFactor = 1.0f;
- dest.dpadPosition = DPAD_POSITION_DISABLED;
- dest.dpadMinimizeable = true;
- dest.optimizedDrawing = false;
- dest.enableUiAnimations = true;
- dest.displayOverwriteSavegame = CONFIRM_OVERWRITE_SAVEGAME_ALWAYS;
- dest.quickslotsPosition = QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM;
- dest.showQuickslotsWhenToolboxIsVisible = false;
- dest.useLocalizedResources = true;
- dest.selectedTheme = 0;
- }
- }
-}
+package com.gpl.rpg.AndorsTrail;
+
+import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+public final class AndorsTrailPreferences {
+ public static final int DISPLAYLOOT_DIALOG_ALWAYS = 0;
+ public static final int DISPLAYLOOT_DIALOG_FOR_ITEMS = 3;
+ public static final int DISPLAYLOOT_DIALOG_FOR_ITEMS_ELSE_TOAST = 4;
+ public static final int DISPLAYLOOT_TOAST = 1;
+ public static final int DISPLAYLOOT_TOAST_FOR_ITEMS = 5;
+ public static final int DISPLAYLOOT_NONE = 2;
+ public static final int MOVEMENTMETHOD_STRAIGHT = 0;
+ public static final int MOVEMENTMETHOD_DIRECTIONAL = 1;
+ public static final int MOVEMENTAGGRESSIVENESS_NORMAL = 0;
+ public static final int MOVEMENTAGGRESSIVENESS_AGGRESSIVE = 1;
+ public static final int MOVEMENTAGGRESSIVENESS_DEFENSIVE = 2;
+ public static final int DPAD_POSITION_DISABLED = 0;
+ public static final int DPAD_POSITION_LOWER_RIGHT = 1;
+ public static final int DPAD_POSITION_LOWER_LEFT = 2;
+ public static final int DPAD_POSITION_LOWER_CENTER = 3;
+ public static final int DPAD_POSITION_CENTER_LEFT = 4;
+ public static final int DPAD_POSITION_CENTER_RIGHT = 5;
+ public static final int DPAD_POSITION_UPPER_LEFT = 6;
+ public static final int DPAD_POSITION_UPPER_RIGHT = 7;
+ public static final int DPAD_POSITION_UPPER_CENTER = 8;
+ public static final int CONFIRM_OVERWRITE_SAVEGAME_ALWAYS = 0;
+ public static final int CONFIRM_OVERWRITE_SAVEGAME_WHEN_PLAYERNAME_DIFFERS = 1;
+ public static final int CONFIRM_OVERWRITE_SAVEGAME_NEVER = 2;
+ public static final int QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM = 0;
+ public static final int QUICKSLOTS_POSITION_VERTICAL_CENTER_LEFT = 1;
+ public static final int QUICKSLOTS_POSITION_VERTICAL_CENTER_RIGHT = 2;
+ public static final int QUICKSLOTS_POSITION_VERTICAL_BOTTOM_LEFT = 3;
+ public static final int QUICKSLOTS_POSITION_HORIZONTAL_BOTTOM_LEFT = 4;
+ public static final int QUICKSLOTS_POSITION_HORIZONTAL_BOTTOM_RIGHT = 5;
+ public static final int QUICKSLOTS_POSITION_VERTICAL_BOTTOM_RIGHT = 6;
+ public static final int ATTACKSPEED_DEFAULT_MILLISECONDS = 1000;
+
+ public boolean confirmRest = true;
+ public boolean confirmAttack = true;
+ public int displayLoot = DISPLAYLOOT_DIALOG_ALWAYS;
+ public boolean fullscreen = true;
+ public int attackspeed_milliseconds = 1000;
+ public int movementMethod = MOVEMENTMETHOD_STRAIGHT;
+ public int movementAggressiveness = MOVEMENTAGGRESSIVENESS_NORMAL;
+ public float scalingFactor = 1.0f;
+ public int dpadPosition;
+ public boolean dpadMinimizeable = true;
+ public boolean optimizedDrawing = false;
+ public boolean highQualityFilters = true;
+ public boolean enableUiAnimations = true;
+ public int displayOverwriteSavegame = CONFIRM_OVERWRITE_SAVEGAME_ALWAYS;
+ public int quickslotsPosition = QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM;
+ public boolean showQuickslotsWhenToolboxIsVisible = false;
+ public boolean useLocalizedResources = true;
+ public int selectedTheme = 0;
+
+ public void read(final Context androidContext) {
+ AndorsTrailPreferences dest = this;
+ try {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(androidContext);
+ dest.confirmRest = prefs.getBoolean("confirm_rest", true);
+ dest.confirmAttack = prefs.getBoolean("confirm_attack", true);
+ dest.displayLoot = Integer.parseInt(prefs.getString("display_lootdialog", Integer.toString(DISPLAYLOOT_DIALOG_ALWAYS)));
+ dest.fullscreen = prefs.getBoolean("fullscreen", true);
+ dest.attackspeed_milliseconds = Integer.parseInt(prefs.getString("attackspeed", "1000"));
+ dest.movementMethod = Integer.parseInt(prefs.getString("movementmethod", Integer.toString(MOVEMENTMETHOD_STRAIGHT)));
+ dest.scalingFactor = Float.parseFloat(prefs.getString("scaling_factor", "1.0f"));
+ dest.dpadPosition = Integer.parseInt(prefs.getString("dpadposition", Integer.toString(DPAD_POSITION_DISABLED)));
+ dest.dpadMinimizeable = prefs.getBoolean("dpadMinimizeable", true);
+ dest.optimizedDrawing = prefs.getBoolean("optimized_drawing", false);
+ dest.highQualityFilters = prefs.getBoolean("high_quality_filters", true);
+ dest.enableUiAnimations = prefs.getBoolean("enableUiAnimations", true);
+ dest.displayOverwriteSavegame = Integer.parseInt(prefs.getString("display_overwrite_savegame", Integer.toString(CONFIRM_OVERWRITE_SAVEGAME_ALWAYS)));
+ dest.quickslotsPosition = Integer.parseInt(prefs.getString("quickslots_placement", Integer.toString(QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM)));
+ dest.showQuickslotsWhenToolboxIsVisible = prefs.getBoolean("showQuickslotsWhenToolboxIsVisible", false);
+ dest.useLocalizedResources = prefs.getBoolean("useLocalizedResources", true);
+ dest.selectedTheme = Integer.parseInt(prefs.getString("selectedTheme", Integer.toString(0)));
+ // This might be implemented as a skill in the future.
+ //dest.movementAggressiveness = Integer.parseInt(prefs.getString("movementaggressiveness", Integer.toString(MOVEMENTAGGRESSIVENESS_NORMAL)));
+ } catch (Exception e) {
+ dest.confirmRest = true;
+ dest.confirmAttack = true;
+ dest.displayLoot = DISPLAYLOOT_DIALOG_ALWAYS;
+ dest.fullscreen = true;
+ dest.attackspeed_milliseconds = 1000;
+ dest.movementMethod = MOVEMENTMETHOD_STRAIGHT;
+ dest.movementAggressiveness = MOVEMENTAGGRESSIVENESS_NORMAL;
+ dest.scalingFactor = 1.0f;
+ dest.dpadPosition = DPAD_POSITION_DISABLED;
+ dest.dpadMinimizeable = true;
+ dest.optimizedDrawing = false;
+ dest.highQualityFilters = true;
+ dest.enableUiAnimations = true;
+ dest.displayOverwriteSavegame = CONFIRM_OVERWRITE_SAVEGAME_ALWAYS;
+ dest.quickslotsPosition = QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM;
+ dest.showQuickslotsWhenToolboxIsVisible = false;
+ dest.useLocalizedResources = true;
+ dest.selectedTheme = 0;
+ }
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/WorldMapController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/WorldMapController.java
index 32626c5c7..3e1edb8e3 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/WorldMapController.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/WorldMapController.java
@@ -115,7 +115,7 @@ public final class WorldMapController {
this.cachedTiles = cachedTiles;
this.tileSize = world.tileManager.tileSize;
this.scale = (float) WORLDMAP_SCREENSHOT_TILESIZE / world.tileManager.tileSize;
- mapTiles.setColorFilter(mPaint);
+ mapTiles.setColorFilter(mPaint, null, true);
}
public Bitmap drawMap() {
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java
index c35be2452..11eba43c0 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java
@@ -2,14 +2,14 @@ package com.gpl.rpg.AndorsTrail.model.map;
import java.util.Collection;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Size;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+
public final class LayeredTileMap {
private static final ColorFilter colorFilterBlack20 = createGrayScaleColorFilter(0.8f);
private static final ColorFilter colorFilterBlack40 = createGrayScaleColorFilter(0.6f);
@@ -20,7 +20,6 @@ public final class LayeredTileMap {
private static final ColorFilter colorFilterRedTint = createRedTintColorFilter();
private static final ColorFilter colorFilterGreenTint = createGreenTintColorFilter();
private static final ColorFilter colorFilterBlueTint = createBlueTintColorFilter();
-
public enum ColorFilterId {
none,
@@ -89,8 +88,9 @@ public final class LayeredTileMap {
return false;
}
- public void setColorFilter(Paint mPaint) {
- mPaint.setColorFilter(getColorFilter());
+ public void setColorFilter(Paint mPaint, Paint alternateColorFilterPaint, boolean highQuality) {
+ if (highQuality) mPaint.setColorFilter(getColorFilter());
+ else setColor(alternateColorFilterPaint);
}
public ColorFilter getColorFilter() {
@@ -120,6 +120,34 @@ public final class LayeredTileMap {
}
}
+
+
+ public void setColor(Paint p) {
+ if (colorFilter == null) {
+ p.setARGB(0, 0, 0, 0);
+ return;
+ }
+ switch (colorFilter) {
+ case black20:
+ p.setARGB(51, 0, 0, 0); return;
+ case black40:
+ p.setARGB(102, 0, 0, 0); return;
+ case black60:
+ p.setARGB(153, 0, 0, 0); return;
+ case black80:
+ p.setARGB(204, 0, 0, 0); return;
+ case redtint:
+ p.setARGB(50, 200, 0, 0); return;
+ case greentint:
+ p.setARGB(50, 0, 200, 0); return;
+ case bluetint:
+ p.setARGB(50, 0, 0, 200); return;
+ default:
+ p.setARGB(0, 0, 0, 0); return;
+
+ }
+
+ }
private static ColorMatrixColorFilter createGrayScaleColorFilter(float blackOpacity) {
final float f = blackOpacity;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
index 08137b3d4..ede798575 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
@@ -1,863 +1,825 @@
-package com.gpl.rpg.AndorsTrail.view;
-
-import java.lang.ref.WeakReference;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
-import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
-import com.gpl.rpg.AndorsTrail.context.ControllerContext;
-import com.gpl.rpg.AndorsTrail.context.WorldContext;
-import com.gpl.rpg.AndorsTrail.controller.Constants;
-import com.gpl.rpg.AndorsTrail.controller.InputController;
-import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
-import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation;
-import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation;
-import com.gpl.rpg.AndorsTrail.controller.listeners.CombatSelectionListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.GameRoundListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.MapLayoutListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterMovementListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterSpawnListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.PlayerMovementListener;
-import com.gpl.rpg.AndorsTrail.controller.listeners.VisualEffectFrameListener;
-import com.gpl.rpg.AndorsTrail.model.ModelContainer;
-import com.gpl.rpg.AndorsTrail.model.actor.Monster;
-import com.gpl.rpg.AndorsTrail.model.item.Loot;
-import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
-import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
-import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
-import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
-import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
-import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
-import com.gpl.rpg.AndorsTrail.util.Coord;
-import com.gpl.rpg.AndorsTrail.util.CoordRect;
-import com.gpl.rpg.AndorsTrail.util.L;
-import com.gpl.rpg.AndorsTrail.util.Size;
-
-public final class MainView extends SurfaceView
- implements SurfaceHolder.Callback,
- PlayerMovementListener,
- CombatSelectionListener,
- MonsterSpawnListener,
- MonsterMovementListener,
- MapLayoutListener,
- VisualEffectFrameListener,
- GameRoundListener {
-
- private final int tileSize;
- private float scale;
- private int scaledTileSize;
-
- private Size screenSizeTileCount = null;
- private final Coord screenOffset = new Coord(); // pixel offset where the image begins
- private final Coord mapTopLeft = new Coord(); // Map coords of visible map
- private CoordRect mapViewArea; // Area in mapcoordinates containing the visible map. topleft == this.topleft
- private Rect redrawClip = new Rect(); //Area in screen coordinates containing the visible map.
-
- private final ModelContainer model;
- private final WorldContext world;
- private final ControllerContext controllers;
- private final InputController inputController;
- private final AndorsTrailPreferences preferences;
-
- private final SurfaceHolder holder;
- private final Paint mPaint = new Paint();
- private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1));
- private boolean hasSurface = false;
-
- //DEBUG
-// private Coord touchedTile = null;
-// private static Paint touchHighlight = new Paint();
-// private static Paint redrawHighlight = new Paint();
-//
-// static {
-// touchHighlight.setColor(Color.RED);
-// touchHighlight.setStrokeWidth(0f);
-// touchHighlight.setStyle(Style.STROKE);
-// redrawHighlight.setColor(Color.CYAN);
-// redrawHighlight.setStrokeWidth(0f);
-// redrawHighlight.setStyle(Style.STROKE);
-// }
-
- private PredefinedMap currentMap;
- private LayeredTileMap currentTileMap;
- private TileCollection tiles;
-
- private final Coord playerPosition = new Coord();
- private Size surfaceSize;
- private boolean redrawNextTick = false;
-
- private boolean scrolling = false;
- private Coord scrollVector;
- private long scrollStartTime;
- //TODO restore private final modifiers before release
- public static long SCROLL_DURATION = Constants.MINIMUM_INPUT_INTERVAL;
- private int movingSprites = 0;
- private SpriteMoveAnimationHandler movingSpritesRedrawTick = new SpriteMoveAnimationHandler(this);
-
-
- public MainView(Context context, AttributeSet attr) {
- super(context, attr);
- this.holder = getHolder();
-
- AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
- this.controllers = app.getControllerContext();
- this.world = app.getWorld();
- this.model = world.model;
- this.tileSize = world.tileManager.tileSize;
- this.inputController = controllers.inputController;
- this.preferences = app.getPreferences();
-
- holder.addCallback(this);
-
- setFocusable(true);
- requestFocus();
- setOnClickListener(this.inputController);
- setOnLongClickListener(this.inputController);
-
-
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent msg) {
- if (!canAcceptInput()) return true;
-
- if (inputController.onKeyboardAction(keyCode)) return true;
- else return super.onKeyDown(keyCode, msg);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent msg) {
- if (!canAcceptInput()) return true;
-
- inputController.onKeyboardCancel();
-
- return super.onKeyUp(keyCode, msg);
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder sh, int format, int w, int h) {
- if (w <= 0 || h <= 0) return;
-
-
- this.scale = world.tileManager.scale;
- this.mPaint.setFilterBitmap(scale != 1);
- this.scaledTileSize = world.tileManager.viewTileSize;
-// this.surfaceSize = new Size(w, h);
- this.surfaceSize = new Size((int) (getWidth() / scale), (int) (getHeight() / scale));
- this.screenSizeTileCount = new Size(
- (int) Math.floor(getWidth() / scaledTileSize)
- ,(int) Math.floor(getHeight() / scaledTileSize)
- );
-
- if (sh.getSurfaceFrame().right != surfaceSize.width || sh.getSurfaceFrame().bottom != surfaceSize.height) {
- sh.setFixedSize(surfaceSize.width, surfaceSize.height);
- }
-
- if (model.currentMap != null) {
- onPlayerEnteredNewMap(model.currentMap, model.player.position);
- } else {
- redrawAll(RedrawAllDebugReason.SurfaceChanged);
- }
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder sh) {
- hasSurface = true;
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder sh) {
- hasSurface = false;
- movingSpritesRedrawTick.stop();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!canAcceptInput()) return true;
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- final int tile_x = (int) Math.floor(((int)event.getX() - screenOffset.x * scale) / scaledTileSize) + mapTopLeft.x;
- final int tile_y = (int) Math.floor(((int)event.getY() - screenOffset.y * scale) / scaledTileSize) + mapTopLeft.y;
-// touchedTile = new Coord(tile_x, tile_y);
- if (inputController.onTouchedTile(tile_x, tile_y)) return true;
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_OUTSIDE:
- inputController.onTouchCancel();
- break;
- }
- return super.onTouchEvent(event);
- }
-
- private boolean canAcceptInput() {
- if (!model.uiSelections.isMainActivityVisible) return false;
- if (!hasSurface) return false;
- return true;
- }
-
- private static enum RedrawAllDebugReason {
- SurfaceChanged, MapChanged, PlayerMoved, SpriteMoved, MapScrolling, FilterAnimation
- }
- private static enum RedrawAreaDebugReason {
- MonsterMoved, MonsterKilled, EffectCompleted, AsyncRequest
- }
- private static enum RedrawTileDebugReason {
- SelectionRemoved, SelectionAdded, Bag
- }
-
- private void redrawAll(RedrawAllDebugReason why) {
- if (preferences.enableUiAnimations) {
- if (scrolling && why != RedrawAllDebugReason.MapScrolling) return;
- if (!scrolling && movingSprites > 0 && why != RedrawAllDebugReason.SpriteMoved) return;
- }
- redrawArea_(mapViewArea, null, 0, 0);
- }
- private void redrawTile(final Coord p, RedrawTileDebugReason why) {
- if (scrolling) return;
- p1x1.topLeft.set(p);
- redrawArea_(p1x1, null, 0, 0);
- }
- private void redrawArea(final CoordRect area, RedrawAreaDebugReason why) {
- if (scrolling) return;
- redrawArea_(area, null, 0, 0);
- }
- private void redrawArea_(CoordRect area, final VisualEffectAnimation effect, int tileID, int textYOffset) {
- if (!hasSurface) return;
-
-
- if (!currentMap.intersects(area)) return;
- if (!mapViewArea.intersects(area)) return;
-
- if (shouldRedrawEverything()) {
- area = mapViewArea;
- }
-
- calculateRedrawRect(area);
- redrawRect.intersect(redrawClip);
- Canvas c = null;
- try {
- c = holder.lockCanvas(redrawRect);
- // lockCanvas sometimes changes redrawRect, when the double-buffer has not been
- // sufficiently filled beforehand. In those cases, we need to redraw the whole scene.
- if (area != mapViewArea) {
- if (isRedrawRectWholeScreen(redrawRect)) {
- area = mapViewArea;
- }
- }
- if (area == mapViewArea) {
- area = adaptAreaToScrolling(area);
- }
-
- synchronized (holder) { synchronized (tiles) {
- int xScroll = 0;
- int yScroll = 0;
- if (scrolling && scrollVector != null) {
- xScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
- xScroll = Math.max(0, Math.min(tileSize, xScroll)) * scrollVector.x;
- yScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
- yScroll = Math.max(0, Math.min(tileSize, yScroll)) * scrollVector.y;
- }
- c.clipRect(redrawClip);
- c.translate(screenOffset.x + xScroll, screenOffset.y + yScroll);
-// c.scale(scale, scale);
- doDrawRect(c, area);
- if (effect != null) {
- drawFromMapPosition(c, area, effect.position, tileID);
- if (effect.displayText != null) {
- drawEffectText(c, area, effect, textYOffset, effect.getTextPaint());
- }
- }
-
-// c.drawRect(new Rect(
-// (area.topLeft.x - mapViewArea.topLeft.x) * tileSize,
-// (area.topLeft.y - mapViewArea.topLeft.y) * tileSize,
-// (area.topLeft.x - mapViewArea.topLeft.x + area.size.width) * tileSize - 1,
-// (area.topLeft.y - mapViewArea.topLeft.y + area.size.height) * tileSize - 1),
-// redrawHighlight);
-// if (touchedTile != null) c.drawRect(new Rect(
-// (touchedTile.x - mapViewArea.topLeft.x) * tileSize,
-// (touchedTile.y - mapViewArea.topLeft.y) * tileSize,
-// (touchedTile.x - mapViewArea.topLeft.x + 1) * tileSize - 1,
-// (touchedTile.y - mapViewArea.topLeft.y + 1) * tileSize - 1),
-// touchHighlight);
- } }
- } finally {
- if (c != null) holder.unlockCanvasAndPost(c);
- }
- }
-
- private void redrawMoveArea_(CoordRect area, final SpriteMoveAnimation effect) {
- if (!hasSurface) return;
- if (scrolling) return;
-
- if (currentMap.isOutside(area)) return;
- if (!mapViewArea.intersects(area)) return;
-
- if (shouldRedrawEverything()) {
- area = mapViewArea;
- }
-
- calculateRedrawRect(area);
- Canvas c = null;
- try {
- c = holder.lockCanvas(redrawRect);
- // lockCanvas sometimes changes redrawRect, when the double-buffer has not been
- // sufficiently filled beforehand. In those cases, we need to redraw the whole scene.
- if (area != mapViewArea) {
- if (isRedrawRectWholeScreen(redrawRect)) {
- area = mapViewArea;
- }
- }
- synchronized (holder) { synchronized (tiles) {
- c.clipRect(redrawClip);
- c.translate(screenOffset.x, screenOffset.y);
-// c.scale(scale, scale);
- doDrawRect(c, area);
-
-// c.drawRect(new Rect(
-// (area.topLeft.x - mapViewArea.topLeft.x) * tileSize,
-// (area.topLeft.y - mapViewArea.topLeft.y) * tileSize,
-// (area.topLeft.x - mapViewArea.topLeft.x + area.size.width) * tileSize - 1,
-// (area.topLeft.y - mapViewArea.topLeft.y + area.size.height) * tileSize - 1),
-// redrawHighlight);
-// if (touchedTile != null) c.drawRect(new Rect(
-// (touchedTile.x - mapViewArea.topLeft.x) * tileSize,
-// (touchedTile.y - mapViewArea.topLeft.y) * tileSize,
-// (touchedTile.x - mapViewArea.topLeft.x + 1) * tileSize - 1,
-// (touchedTile.y - mapViewArea.topLeft.y + 1) * tileSize - 1),
-// touchHighlight);
-
- } }
- } finally {
- if (c != null) holder.unlockCanvasAndPost(c);
- }
- }
-
- private boolean isRedrawRectWholeScreen(Rect redrawRect) {
-// if (redrawRect.width() < mapViewArea.size.width * scaledTileSize) return false;
-// if (redrawRect.height() < mapViewArea.size.height * scaledTileSize) return false;
- if (redrawRect.width() < mapViewArea.size.width * tileSize) return false;
- if (redrawRect.height() < mapViewArea.size.height * tileSize) return false;
- return true;
- }
-
- private boolean shouldRedrawEverything() {
- if (scrolling) return true;
- if (model.uiSelections.isInCombat) return true; // Discard the "optimized drawing" setting while in combat.
- if (preferences.optimizedDrawing) return false;
- return true;
- }
- private final Rect redrawRect = new Rect();
- private void redrawAreaWithEffect(final VisualEffectAnimation effect, int tileID, int textYOffset) {
- CoordRect area = effect.area;
-// if (shouldRedrawEverythingForVisualEffect()) area = mapViewArea;
- redrawArea_(area, effect, tileID, textYOffset);
- }
- private void clearCanvas() {
- if (!hasSurface) return;
- Canvas c = null;
- try {
- c = holder.lockCanvas();
- synchronized (holder) {
- c.drawColor(Color.BLACK);
- }
- } finally {
- if (c != null) holder.unlockCanvasAndPost(c);
- }
- }
-
- private CoordRect adaptAreaToScrolling(final CoordRect area) {
-
- if (!scrolling || scrollVector == null) return area;
-
- int x, y, w, h;
- if (scrollVector.x > 0) {
- x = area.topLeft.x - scrollVector.x;
- w = area.size.width + scrollVector.x;
- } else {
- x = area.topLeft.x;
- w = area.size.width - scrollVector.x;
- }
- if (scrollVector.y > 0) {
- y = area.topLeft.y - scrollVector.y;
- h = area.size.height + scrollVector.y;
- } else {
- y = area.topLeft.y;
- h = area.size.height - scrollVector.y;
- }
- CoordRect result = new CoordRect(new Coord(x, y), new Size(w, h));
- return result;
- }
-
- private void calculateRedrawRect(final CoordRect area) {
- worldCoordsToScreenCords(area, redrawRect);
- }
-
- private void worldCoordsToScreenCords(final CoordRect worldArea, Rect destScreenRect) {
-// destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * scaledTileSize;
-// destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * scaledTileSize;
-// destScreenRect.right = destScreenRect.left + worldArea.size.width * scaledTileSize;
-// destScreenRect.bottom = destScreenRect.top + worldArea.size.height * scaledTileSize;
-
- destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * tileSize;
- destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * tileSize;
- destScreenRect.right = destScreenRect.left + worldArea.size.width * tileSize;
- destScreenRect.bottom = destScreenRect.top + worldArea.size.height * tileSize;
- }
-
-// private void worldCoordsToBitmapCoords(final CoordRect worldArea, Rect dstBitmapArea) {
-// dstBitmapArea.left = worldArea.topLeft.x * tileSize;
-// dstBitmapArea.top = worldArea.topLeft.y * tileSize;
-// dstBitmapArea.right = dstBitmapArea.left + worldArea.size.width * tileSize;
-// dstBitmapArea.bottom = dstBitmapArea.top + worldArea.size.height * tileSize;
-//
-// }
-
- private void doDrawRect(Canvas canvas, CoordRect area) {
- doDrawRect_Ground(canvas, area);
- doDrawRect_Objects(canvas, area);
- doDrawRect_Above(canvas, area);
-
- }
-
- private void doDrawRect_Ground(Canvas canvas, CoordRect area) {
- drawMapLayer(canvas, area, currentTileMap.currentLayout.layerGround);
- tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
- }
-
- private void doDrawRect_Objects(Canvas canvas, CoordRect area) {
-// if (!tryDrawMapBitmap(canvas, area, objectsBitmap)) {
-// tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
-// }
-
- for (BloodSplatter splatter : currentMap.splatters) {
- drawFromMapPosition(canvas, area, splatter.position, splatter.iconID);
- }
-
- for (Loot l : currentMap.groundBags) {
- if (l.isVisible) {
- drawFromMapPosition(canvas, area, l.position, TileManager.iconID_groundbag);
- }
- }
-
- if (!model.player.hasVFXRunning) {
- drawFromMapPosition(canvas, area, playerPosition, model.player.iconID);
- } else if (area.contains(playerPosition)) {
- int vfxElapsedTime = (int) (System.currentTimeMillis() - model.player.vfxStartTime);
- if (vfxElapsedTime > model.player.vfxDuration) vfxElapsedTime = model.player.vfxDuration;
- int x = ((model.player.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((model.player.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
- int y = ((model.player.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((model.player.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
- tiles.drawTile(canvas, model.player.iconID, x, y, mPaint);
- }
- for (MonsterSpawnArea a : currentMap.spawnAreas) {
- for (Monster m : a.monsters) {
- if (!m.hasVFXRunning) {
- drawFromMapPosition(canvas, area, m.rectPosition, m.iconID);
- } else if (area.intersects(m.rectPosition) || area.intersects(new CoordRect(m.lastPosition,m.rectPosition.size))) {
- int vfxElapsedTime = (int) (System.currentTimeMillis() - m.vfxStartTime);
- if (vfxElapsedTime > m.vfxDuration) vfxElapsedTime = m.vfxDuration;
- int x = ((m.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((m.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
- int y = ((m.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((m.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
- tiles.drawTile(canvas, m.iconID, x, y, mPaint);
- }
- }
- }
- }
-
- private void doDrawRect_Above(Canvas canvas, CoordRect area) {
- tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerAbove);
- tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerTop);
-
- if (model.uiSelections.selectedPosition != null) {
- if (model.uiSelections.selectedMonster != null) {
- drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_attackselect);
- } else {
- drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_moveselect);
- }
- }
- }
-
- private void tryDrawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
- if (layer != null) drawMapLayer(canvas, area, layer);
- }
-
- private void drawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
- int my = area.topLeft.y;
- int py = (area.topLeft.y - mapViewArea.topLeft.y) * tileSize;
- int px0 = (area.topLeft.x - mapViewArea.topLeft.x) * tileSize;
- for (int y = 0; y < area.size.height; ++y, ++my, py += tileSize) {
- int mx = area.topLeft.x;
- if (my < 0) continue;
- if (my >= currentMap.size.height) break;
- int px = px0;
- for (int x = 0; x < area.size.width; ++x, ++mx, px += tileSize) {
- if (mx < 0) continue;
- if (mx >= currentMap.size.width) break;
- final int tile = layer.tiles[mx][my];
- if (tile == 0) continue;
- tiles.drawTile(canvas, tile, px, py, mPaint);
- }
- }
- }
-
- private void drawFromMapPosition(Canvas canvas, final CoordRect area, final Coord p, final int tile) {
- if (!area.contains(p)) return;
- _drawFromMapPosition(canvas, area, p.x, p.y, tile);
- }
- private void drawFromMapPosition(Canvas canvas, final CoordRect area, final CoordRect p, final int tile) {
- if (!area.intersects(p)) return;
- _drawFromMapPosition(canvas, area, p.topLeft.x, p.topLeft.y, tile);
- }
- private void _drawFromMapPosition(Canvas canvas, final CoordRect area, int x, int y, final int tile) {
- x -= mapViewArea.topLeft.x;
- y -= mapViewArea.topLeft.y;
-// if ( (x >= 0 && x < mapViewArea.size.width)
-// && (y >= 0 && y < mapViewArea.size.height)) {
- tiles.drawTile(canvas, tile, x * tileSize, y * tileSize, mPaint);
-// }
- }
-
- private void drawEffectText(Canvas canvas, final CoordRect area, final VisualEffectAnimation e, int textYOffset, Paint textPaint) {
- int x = (e.position.x - mapViewArea.topLeft.x) * tileSize + tileSize/2;
- int y = (e.position.y - mapViewArea.topLeft.y) * tileSize + tileSize/2 + textYOffset;
- canvas.drawText(e.displayText, x, y, textPaint);
- }
-
- @Override
- public void onPlayerEnteredNewMap(PredefinedMap map, Coord p) {
- movingSpritesRedrawTick.start();
- synchronized (holder) {
- currentMap = map;
- currentTileMap = model.currentTileMap;
- tiles = world.tileManager.currentMapTiles;
- movingSprites = 0;
- Size visibleNumberOfTiles = new Size(
- Math.min(screenSizeTileCount.width, currentMap.size.width)
- ,Math.min(screenSizeTileCount.height, currentMap.size.height)
- );
- mapViewArea = new CoordRect(mapTopLeft, visibleNumberOfTiles);
- updateClip();
-
-// screenOffset.set(
-// (surfaceSize.width - scaledTileSize * visibleNumberOfTiles.width) / 2
-// ,(surfaceSize.height - scaledTileSize * visibleNumberOfTiles.height) / 2
-// );
-
-
- screenOffset.set(
- (surfaceSize.width - tileSize * visibleNumberOfTiles.width) / 2
- ,(surfaceSize.height - tileSize * visibleNumberOfTiles.height) / 2
- );
-
- currentTileMap.setColorFilter(this.mPaint);
- }
-
-// touchedTile = null;
-
- clearCanvas();
-
- recalculateMapTopLeft(model.player.position, false);
- redrawAll(RedrawAllDebugReason.MapChanged);
- }
-
- private void recalculateMapTopLeft(Coord playerPosition, boolean allowScrolling) {
- synchronized (holder) {
- int oldX = mapTopLeft.x;
- int oldY = mapTopLeft.y;
- this.playerPosition.set(playerPosition);
- mapTopLeft.set(0, 0);
-
- if (currentMap.size.width > screenSizeTileCount.width) {
- mapTopLeft.x = Math.max(0, playerPosition.x - mapViewArea.size.width/2);
- mapTopLeft.x = Math.min(mapTopLeft.x, currentMap.size.width - mapViewArea.size.width);
- }
- if (currentMap.size.height > screenSizeTileCount.height) {
- mapTopLeft.y = Math.max(0, playerPosition.y - mapViewArea.size.height/2);
- mapTopLeft.y = Math.min(mapTopLeft.y, currentMap.size.height - mapViewArea.size.height);
- }
- updateClip();
- if (allowScrolling) {
- if (mapTopLeft.x != oldX || mapTopLeft.y != oldY) {
- scrollVector = new Coord(mapTopLeft.x - oldX, mapTopLeft.y - oldY);
- new ScrollAnimationHandler(this).start();
- }
- } else {
- scrolling = false;
- }
- }
- }
-
- private void updateClip() {
- worldCoordsToScreenCords(mapViewArea, redrawClip);
- }
-
-
- public static final class ScrollAnimationHandler extends Handler implements Runnable {
-
- private static final int FRAME_DURATION = 40;
-
- private final WeakReference view;
-
- public ScrollAnimationHandler(MainView view) {
- this.view = new WeakReference(view);
- }
-
- @Override
- public void run() {
- MainView v = view.get();
- if (v == null) return;
- if (System.currentTimeMillis() - v.scrollStartTime >= SCROLL_DURATION) {
- onCompleted();
- } else {
- postDelayed(this, FRAME_DURATION);
- }
- update();
- }
-
- private void update() {
- MainView v = view.get();
- if (v == null) return;
- v.redrawAll(RedrawAllDebugReason.MapScrolling);
- }
-
- private void onCompleted() {
- MainView v = view.get();
- if (v == null) return;
- v.scrolling = false;
- v.scrollVector = null;
- }
-
- public void start() {
- MainView v = view.get();
- if (v == null) return;
- v.scrolling = true;
- v.scrollStartTime = System.currentTimeMillis();
- postDelayed(this, 0);
- }
- }
-
-
- public static final class SpriteMoveAnimationHandler extends Handler implements Runnable {
-
- private static final int FRAME_DURATION = 40;
- private final WeakReference view;
- private boolean stop = true;
-
- public SpriteMoveAnimationHandler(MainView view) {
- this.view = new WeakReference(view);
- }
-
- @Override
- public void run() {
- if (!stop) postDelayed(this, FRAME_DURATION);
- update();
- }
-
- private void update() {
-// L.log("stop="+stop+" - scroll="+scrolling+" - moving="+movingSprites);
- if (stop) return;
- MainView v = view.get();
- if (v == null) return;
- if (!v.scrolling) {
- if (v.movingSprites > 0) {
- //TODO : limit redraw area when shouldRedrawEverything() returns false.
- //Implies keeping track of the animation bounding box in a thread-safe way... :'(
- v.redrawAll(RedrawAllDebugReason.SpriteMoved);
- }
- }
- synchronized (this) {
- if (v.movingSprites <= 0) stop();
- }
- }
-
- public void start() {
- if (stop) {
- stop = false;
- MainView v = view.get();
- if (v == null) return;
- if (v.controllers.preferences.enableUiAnimations) postDelayed(this, 0);
- }
- }
-
- public void stop() {
- stop = true;
- }
- }
-
-
-
- @Override
- public void onPlayerMoved(Coord newPosition, Coord previousPosition) {
- recalculateMapTopLeft(newPosition, preferences.enableUiAnimations);
- redrawAll(RedrawAllDebugReason.PlayerMoved);
- }
-
- public void subscribe() {
- controllers.gameRoundController.gameRoundListeners.add(this);
- controllers.effectController.visualEffectFrameListeners.add(this);
- controllers.mapController.mapLayoutListeners.add(this);
- controllers.movementController.playerMovementListeners.add(this);
- controllers.combatController.combatSelectionListeners.add(this);
- controllers.monsterSpawnController.monsterSpawnListeners.add(this);
- controllers.monsterMovementController.monsterMovementListeners.add(this);
- }
- public void unsubscribe() {
- controllers.monsterMovementController.monsterMovementListeners.remove(this);
- controllers.monsterSpawnController.monsterSpawnListeners.remove(this);
- controllers.combatController.combatSelectionListeners.remove(this);
- controllers.movementController.playerMovementListeners.remove(this);
- controllers.mapController.mapLayoutListeners.remove(this);
- controllers.effectController.visualEffectFrameListeners.remove(this);
- controllers.gameRoundController.gameRoundListeners.remove(this);
- }
-
- @Override
- public void onMonsterSelected(Monster m, Coord selectedPosition, Coord previousSelection) {
- if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
- redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
- }
-
- @Override
- public void onMovementDestinationSelected(Coord selectedPosition, Coord previousSelection) {
- if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
- redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
- }
-
- @Override
- public void onCombatSelectionCleared(Coord previousSelection) {
- redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
- }
-
- @Override
- public void onMonsterSpawned(PredefinedMap map, Monster m) {
- if (map != currentMap) return;
- if (!mapViewArea.intersects(m.rectPosition)) return;
- redrawNextTick = true;
- }
-
- @Override
- public void onMonsterRemoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
- if (map != currentMap) return;
- redrawArea(previousPosition, RedrawAreaDebugReason.MonsterKilled);
- }
-
- @Override
- public void onMonsterSteppedOnPlayer(Monster m) {
- }
-
- @Override
- public void onMonsterMoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
- if (map != currentMap) return;
- if (!mapViewArea.intersects(m.rectPosition) && !mapViewArea.intersects(previousPosition)) return;
- if (model.uiSelections.isInCombat) {
- redrawArea(previousPosition, RedrawAreaDebugReason.MonsterMoved);
- redrawArea(m.rectPosition, RedrawAreaDebugReason.MonsterMoved);
- } else {
- redrawNextTick = true;
- }
- }
-
- @Override
- public void onSplatterAdded(PredefinedMap map, Coord p) {
- if (map != currentMap) return;
- if (!mapViewArea.contains(p)) return;
- redrawNextTick = true;
- }
-
- @Override
- public void onSplatterChanged(PredefinedMap map, Coord p) {
- if (map != currentMap) return;
- if (!mapViewArea.contains(p)) return;
- redrawNextTick = true;
- }
-
- @Override
- public void onSplatterRemoved(PredefinedMap map, Coord p) {
- if (map != currentMap) return;
- if (!mapViewArea.contains(p)) return;
- redrawNextTick = true;
- }
-
- @Override
- public void onLootBagCreated(PredefinedMap map, Coord p) {
- if (map != currentMap) return;
- redrawTile(p, RedrawTileDebugReason.Bag);
- }
-
- @Override
- public void onLootBagRemoved(PredefinedMap map, Coord p) {
- if (map != currentMap) return;
- redrawTile(p, RedrawTileDebugReason.Bag);
- }
-
- @Override
- public void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap) {
- if (map != currentMap) return;
- currentTileMap.setColorFilter(this.mPaint);
- redrawAll(RedrawAllDebugReason.MapChanged);
- }
-
- @Override
- public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) {
- redrawAreaWithEffect(animation, tileID, textYOffset);
- }
-
- @Override
- public void onAnimationCompleted(VisualEffectAnimation animation) {
- redrawArea(animation.area, RedrawAreaDebugReason.EffectCompleted);
- }
-
- @Override
- public void onSpriteMoveStarted(SpriteMoveAnimation animation) {
- synchronized (movingSpritesRedrawTick) {
- movingSprites++;
- movingSpritesRedrawTick.start();
- }
- }
-
- @Override
- public void onNewSpriteMoveFrame(SpriteMoveAnimation animation) {
- //redrawMoveArea_(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), animation);
- }
-
- @Override
- public void onSpriteMoveCompleted(SpriteMoveAnimation animation) {
- movingSprites--;
- redrawArea(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), RedrawAreaDebugReason.EffectCompleted);
- }
-
- @Override
- public void onAsyncAreaUpdate(CoordRect area) {
- redrawArea(area, RedrawAreaDebugReason.AsyncRequest);
- }
-
- @Override
- public void onNewTick() {
- if (!redrawNextTick) return;
-
- redrawAll(RedrawAllDebugReason.PlayerMoved);
-
- redrawNextTick = false;
- }
-
- @Override
- public void onNewRound() { }
-
- @Override
- public void onNewFullRound() { }
-}
+package com.gpl.rpg.AndorsTrail.view;
+
+import java.lang.ref.WeakReference;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
+import com.gpl.rpg.AndorsTrail.context.ControllerContext;
+import com.gpl.rpg.AndorsTrail.context.WorldContext;
+import com.gpl.rpg.AndorsTrail.controller.Constants;
+import com.gpl.rpg.AndorsTrail.controller.InputController;
+import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
+import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.SpriteMoveAnimation;
+import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation;
+import com.gpl.rpg.AndorsTrail.controller.listeners.CombatSelectionListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.GameRoundListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.MapLayoutListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterMovementListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.MonsterSpawnListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.PlayerMovementListener;
+import com.gpl.rpg.AndorsTrail.controller.listeners.VisualEffectFrameListener;
+import com.gpl.rpg.AndorsTrail.model.ModelContainer;
+import com.gpl.rpg.AndorsTrail.model.actor.Monster;
+import com.gpl.rpg.AndorsTrail.model.item.Loot;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
+import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
+import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
+import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
+import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
+import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public final class MainView extends SurfaceView
+ implements SurfaceHolder.Callback,
+ PlayerMovementListener,
+ CombatSelectionListener,
+ MonsterSpawnListener,
+ MonsterMovementListener,
+ MapLayoutListener,
+ VisualEffectFrameListener,
+ GameRoundListener {
+
+ private final int tileSize;
+ private float scale;
+ private int scaledTileSize;
+
+ private Size screenSizeTileCount = null;
+ private final Coord screenOffset = new Coord(); // pixel offset where the image begins
+ private final Coord mapTopLeft = new Coord(); // Map coords of visible map
+ private CoordRect mapViewArea; // Area in mapcoordinates containing the visible map. topleft == this.topleft
+ private Rect redrawClip = new Rect(); //Area in screen coordinates containing the visible map.
+
+ private final ModelContainer model;
+ private final WorldContext world;
+ private final ControllerContext controllers;
+ private final InputController inputController;
+ private final AndorsTrailPreferences preferences;
+
+ private final SurfaceHolder holder;
+ private final Paint mPaint = new Paint();
+ private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1));
+ private boolean hasSurface = false;
+
+ //DEBUG
+// private Coord touchedTile = null;
+// private static Paint touchHighlight = new Paint();
+// private static Paint redrawHighlight = new Paint();
+//
+// static {
+// touchHighlight.setColor(Color.RED);
+// touchHighlight.setStrokeWidth(0f);
+// touchHighlight.setStyle(Style.STROKE);
+// redrawHighlight.setColor(Color.CYAN);
+// redrawHighlight.setStrokeWidth(0f);
+// redrawHighlight.setStyle(Style.STROKE);
+// }
+
+ private PredefinedMap currentMap;
+ private LayeredTileMap currentTileMap;
+ private TileCollection tiles;
+
+ private final Coord playerPosition = new Coord();
+ private Size surfaceSize;
+ private boolean redrawNextTick = false;
+
+ private boolean scrolling = false;
+ private Coord scrollVector;
+ private long scrollStartTime;
+ //TODO restore private final modifiers before release
+ public static long SCROLL_DURATION = Constants.MINIMUM_INPUT_INTERVAL;
+ private int movingSprites = 0;
+ private SpriteMoveAnimationHandler movingSpritesRedrawTick = new SpriteMoveAnimationHandler(this);
+ private Paint alternateColorFilterPaint = new Paint();
+
+ public MainView(Context context, AttributeSet attr) {
+ super(context, attr);
+ this.holder = getHolder();
+
+ AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context);
+ this.controllers = app.getControllerContext();
+ this.world = app.getWorld();
+ this.model = world.model;
+ this.tileSize = world.tileManager.tileSize;
+ this.inputController = controllers.inputController;
+ this.preferences = app.getPreferences();
+
+ alternateColorFilterPaint.setStyle(Style.FILL);
+
+ holder.addCallback(this);
+
+ setFocusable(true);
+ requestFocus();
+ setOnClickListener(this.inputController);
+ setOnLongClickListener(this.inputController);
+
+
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent msg) {
+ if (!canAcceptInput()) return true;
+
+ if (inputController.onKeyboardAction(keyCode)) return true;
+ else return super.onKeyDown(keyCode, msg);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent msg) {
+ if (!canAcceptInput()) return true;
+
+ inputController.onKeyboardCancel();
+
+ return super.onKeyUp(keyCode, msg);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder sh, int format, int w, int h) {
+ if (w <= 0 || h <= 0) return;
+
+
+ this.scale = world.tileManager.scale;
+ this.mPaint.setFilterBitmap(scale != 1);
+ this.scaledTileSize = world.tileManager.viewTileSize;
+// this.surfaceSize = new Size(w, h);
+ this.surfaceSize = new Size((int) (getWidth() / scale), (int) (getHeight() / scale));
+ this.screenSizeTileCount = new Size(
+ (int) Math.floor(getWidth() / scaledTileSize)
+ ,(int) Math.floor(getHeight() / scaledTileSize)
+ );
+
+ if (sh.getSurfaceFrame().right != surfaceSize.width || sh.getSurfaceFrame().bottom != surfaceSize.height) {
+ sh.setFixedSize(surfaceSize.width, surfaceSize.height);
+ }
+
+ if (model.currentMap != null) {
+ onPlayerEnteredNewMap(model.currentMap, model.player.position);
+ } else {
+ redrawAll(RedrawAllDebugReason.SurfaceChanged);
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder sh) {
+ hasSurface = true;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder sh) {
+ hasSurface = false;
+ movingSpritesRedrawTick.stop();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!canAcceptInput()) return true;
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ final int tile_x = (int) Math.floor(((int)event.getX() - screenOffset.x * scale) / scaledTileSize) + mapTopLeft.x;
+ final int tile_y = (int) Math.floor(((int)event.getY() - screenOffset.y * scale) / scaledTileSize) + mapTopLeft.y;
+// touchedTile = new Coord(tile_x, tile_y);
+ if (inputController.onTouchedTile(tile_x, tile_y)) return true;
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_OUTSIDE:
+ inputController.onTouchCancel();
+ break;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ private boolean canAcceptInput() {
+ if (!model.uiSelections.isMainActivityVisible) return false;
+ if (!hasSurface) return false;
+ return true;
+ }
+
+ private static enum RedrawAllDebugReason {
+ SurfaceChanged, MapChanged, PlayerMoved, SpriteMoved, MapScrolling, FilterAnimation
+ }
+ private static enum RedrawAreaDebugReason {
+ MonsterMoved, MonsterKilled, EffectCompleted, AsyncRequest
+ }
+ private static enum RedrawTileDebugReason {
+ SelectionRemoved, SelectionAdded, Bag
+ }
+
+ private void redrawAll(RedrawAllDebugReason why) {
+ if (preferences.enableUiAnimations) {
+ if (scrolling && why != RedrawAllDebugReason.MapScrolling) return;
+ if (!scrolling && movingSprites > 0 && why != RedrawAllDebugReason.SpriteMoved) return;
+ }
+ redrawArea_(mapViewArea, null, 0, 0);
+ }
+ private void redrawTile(final Coord p, RedrawTileDebugReason why) {
+ if (scrolling) return;
+ p1x1.topLeft.set(p);
+ redrawArea_(p1x1, null, 0, 0);
+ }
+ private void redrawArea(final CoordRect area, RedrawAreaDebugReason why) {
+ if (scrolling) return;
+ redrawArea_(area, null, 0, 0);
+ }
+ private void redrawArea_(CoordRect area, final VisualEffectAnimation effect, int tileID, int textYOffset) {
+ if (!hasSurface) return;
+
+
+ if (!currentMap.intersects(area)) return;
+ if (!mapViewArea.intersects(area)) return;
+
+ if (shouldRedrawEverything()) {
+ area = mapViewArea;
+ }
+
+ calculateRedrawRect(area);
+ redrawRect.intersect(redrawClip);
+ Canvas c = null;
+ try {
+ c = holder.lockCanvas(redrawRect);
+ // lockCanvas sometimes changes redrawRect, when the double-buffer has not been
+ // sufficiently filled beforehand. In those cases, we need to redraw the whole scene.
+ if (area != mapViewArea) {
+ if (isRedrawRectWholeScreen(redrawRect)) {
+ area = mapViewArea;
+ }
+ }
+ if (area == mapViewArea) {
+ area = adaptAreaToScrolling(area);
+ }
+
+ synchronized (holder) { synchronized (tiles) {
+ int xScroll = 0;
+ int yScroll = 0;
+ if (scrolling && scrollVector != null) {
+ xScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
+ xScroll = Math.max(0, Math.min(tileSize, xScroll)) * scrollVector.x;
+ yScroll = (int) (tileSize - (tileSize * (System.currentTimeMillis() - scrollStartTime) / SCROLL_DURATION));
+ yScroll = Math.max(0, Math.min(tileSize, yScroll)) * scrollVector.y;
+ }
+ c.clipRect(redrawClip);
+ c.translate(screenOffset.x + xScroll, screenOffset.y + yScroll);
+// c.scale(scale, scale);
+ doDrawRect(c, area);
+ if (effect != null) {
+ drawFromMapPosition(c, area, effect.position, tileID);
+ if (effect.displayText != null) {
+ drawEffectText(c, area, effect, textYOffset, effect.getTextPaint());
+ }
+ }
+
+// c.drawRect(new Rect(
+// (area.topLeft.x - mapViewArea.topLeft.x) * tileSize,
+// (area.topLeft.y - mapViewArea.topLeft.y) * tileSize,
+// (area.topLeft.x - mapViewArea.topLeft.x + area.size.width) * tileSize - 1,
+// (area.topLeft.y - mapViewArea.topLeft.y + area.size.height) * tileSize - 1),
+// redrawHighlight);
+// if (touchedTile != null) c.drawRect(new Rect(
+// (touchedTile.x - mapViewArea.topLeft.x) * tileSize,
+// (touchedTile.y - mapViewArea.topLeft.y) * tileSize,
+// (touchedTile.x - mapViewArea.topLeft.x + 1) * tileSize - 1,
+// (touchedTile.y - mapViewArea.topLeft.y + 1) * tileSize - 1),
+// touchHighlight);
+ } }
+ } finally {
+ if (c != null) holder.unlockCanvasAndPost(c);
+ }
+ }
+
+ private boolean isRedrawRectWholeScreen(Rect redrawRect) {
+// if (redrawRect.width() < mapViewArea.size.width * scaledTileSize) return false;
+// if (redrawRect.height() < mapViewArea.size.height * scaledTileSize) return false;
+ if (redrawRect.width() < mapViewArea.size.width * tileSize) return false;
+ if (redrawRect.height() < mapViewArea.size.height * tileSize) return false;
+ return true;
+ }
+
+ private boolean shouldRedrawEverything() {
+ if (scrolling) return true;
+ if (model.uiSelections.isInCombat) return true; // Discard the "optimized drawing" setting while in combat.
+ if (preferences.optimizedDrawing) return false;
+ return true;
+ }
+ private final Rect redrawRect = new Rect();
+ private void redrawAreaWithEffect(final VisualEffectAnimation effect, int tileID, int textYOffset) {
+ CoordRect area = effect.area;
+// if (shouldRedrawEverythingForVisualEffect()) area = mapViewArea;
+ redrawArea_(area, effect, tileID, textYOffset);
+ }
+ private void clearCanvas() {
+ if (!hasSurface) return;
+ Canvas c = null;
+ try {
+ c = holder.lockCanvas();
+ synchronized (holder) {
+ c.drawColor(Color.BLACK);
+ }
+ } finally {
+ if (c != null) holder.unlockCanvasAndPost(c);
+ }
+ }
+
+ private CoordRect adaptAreaToScrolling(final CoordRect area) {
+
+ if (!scrolling || scrollVector == null) return area;
+
+ int x, y, w, h;
+ if (scrollVector.x > 0) {
+ x = area.topLeft.x - scrollVector.x;
+ w = area.size.width + scrollVector.x;
+ } else {
+ x = area.topLeft.x;
+ w = area.size.width - scrollVector.x;
+ }
+ if (scrollVector.y > 0) {
+ y = area.topLeft.y - scrollVector.y;
+ h = area.size.height + scrollVector.y;
+ } else {
+ y = area.topLeft.y;
+ h = area.size.height - scrollVector.y;
+ }
+ CoordRect result = new CoordRect(new Coord(x, y), new Size(w, h));
+ return result;
+ }
+
+ private void calculateRedrawRect(final CoordRect area) {
+ worldCoordsToScreenCords(area, redrawRect);
+ }
+
+ private void worldCoordsToScreenCords(final CoordRect worldArea, Rect destScreenRect) {
+// destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * scaledTileSize;
+// destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * scaledTileSize;
+// destScreenRect.right = destScreenRect.left + worldArea.size.width * scaledTileSize;
+// destScreenRect.bottom = destScreenRect.top + worldArea.size.height * scaledTileSize;
+
+ destScreenRect.left = screenOffset.x + (worldArea.topLeft.x - mapViewArea.topLeft.x) * tileSize;
+ destScreenRect.top = screenOffset.y + (worldArea.topLeft.y - mapViewArea.topLeft.y) * tileSize;
+ destScreenRect.right = destScreenRect.left + worldArea.size.width * tileSize;
+ destScreenRect.bottom = destScreenRect.top + worldArea.size.height * tileSize;
+ }
+
+// private void worldCoordsToBitmapCoords(final CoordRect worldArea, Rect dstBitmapArea) {
+// dstBitmapArea.left = worldArea.topLeft.x * tileSize;
+// dstBitmapArea.top = worldArea.topLeft.y * tileSize;
+// dstBitmapArea.right = dstBitmapArea.left + worldArea.size.width * tileSize;
+// dstBitmapArea.bottom = dstBitmapArea.top + worldArea.size.height * tileSize;
+//
+// }
+
+ private void doDrawRect(Canvas canvas, CoordRect area) {
+ doDrawRect_Ground(canvas, area);
+ doDrawRect_Objects(canvas, area);
+ doDrawRect_Above(canvas, area);
+ if (!preferences.highQualityFilters) {
+ applyAlternateFilter(canvas, area);
+ }
+ }
+
+ private void doDrawRect_Ground(Canvas canvas, CoordRect area) {
+ drawMapLayer(canvas, area, currentTileMap.currentLayout.layerGround);
+ tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
+ }
+
+ private void doDrawRect_Objects(Canvas canvas, CoordRect area) {
+// if (!tryDrawMapBitmap(canvas, area, objectsBitmap)) {
+// tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
+// }
+
+ for (BloodSplatter splatter : currentMap.splatters) {
+ drawFromMapPosition(canvas, area, splatter.position, splatter.iconID);
+ }
+
+ for (Loot l : currentMap.groundBags) {
+ if (l.isVisible) {
+ drawFromMapPosition(canvas, area, l.position, TileManager.iconID_groundbag);
+ }
+ }
+
+ if (!model.player.hasVFXRunning) {
+ drawFromMapPosition(canvas, area, playerPosition, model.player.iconID);
+ } else if (area.contains(playerPosition)) {
+ int vfxElapsedTime = (int) (System.currentTimeMillis() - model.player.vfxStartTime);
+ if (vfxElapsedTime > model.player.vfxDuration) vfxElapsedTime = model.player.vfxDuration;
+ int x = ((model.player.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((model.player.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
+ int y = ((model.player.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((model.player.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (model.player.vfxDuration - vfxElapsedTime))) / model.player.vfxDuration;
+ tiles.drawTile(canvas, model.player.iconID, x, y, mPaint);
+ }
+ for (MonsterSpawnArea a : currentMap.spawnAreas) {
+ for (Monster m : a.monsters) {
+ if (!m.hasVFXRunning) {
+ drawFromMapPosition(canvas, area, m.rectPosition, m.iconID);
+ } else if (area.intersects(m.rectPosition) || area.intersects(new CoordRect(m.lastPosition,m.rectPosition.size))) {
+ int vfxElapsedTime = (int) (System.currentTimeMillis() - m.vfxStartTime);
+ if (vfxElapsedTime > m.vfxDuration) vfxElapsedTime = m.vfxDuration;
+ int x = ((m.position.x - mapViewArea.topLeft.x) * tileSize * vfxElapsedTime + ((m.lastPosition.x - mapViewArea.topLeft.x) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
+ int y = ((m.position.y - mapViewArea.topLeft.y) * tileSize * vfxElapsedTime + ((m.lastPosition.y - mapViewArea.topLeft.y) * tileSize * (m.vfxDuration - vfxElapsedTime))) / m.vfxDuration;
+ tiles.drawTile(canvas, m.iconID, x, y, mPaint);
+ }
+ }
+ }
+ }
+
+ private void doDrawRect_Above(Canvas canvas, CoordRect area) {
+ tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerAbove);
+ tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerTop);
+
+ if (model.uiSelections.selectedPosition != null) {
+ if (model.uiSelections.selectedMonster != null) {
+ drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_attackselect);
+ } else {
+ drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_moveselect);
+ }
+ }
+ }
+
+ private void tryDrawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
+ if (layer != null) drawMapLayer(canvas, area, layer);
+ }
+
+ private void drawMapLayer(Canvas canvas, final CoordRect area, final MapLayer layer) {
+ int my = area.topLeft.y;
+ int py = (area.topLeft.y - mapViewArea.topLeft.y) * tileSize;
+ int px0 = (area.topLeft.x - mapViewArea.topLeft.x) * tileSize;
+ for (int y = 0; y < area.size.height; ++y, ++my, py += tileSize) {
+ int mx = area.topLeft.x;
+ if (my < 0) continue;
+ if (my >= currentMap.size.height) break;
+ int px = px0;
+ for (int x = 0; x < area.size.width; ++x, ++mx, px += tileSize) {
+ if (mx < 0) continue;
+ if (mx >= currentMap.size.width) break;
+ final int tile = layer.tiles[mx][my];
+ if (tile == 0) continue;
+ tiles.drawTile(canvas, tile, px, py, mPaint);
+ }
+ }
+ }
+
+
+ private void applyAlternateFilter(Canvas canvas, CoordRect area) {
+ canvas.drawRect(canvas.getClipBounds(), alternateColorFilterPaint);
+
+ }
+
+ private void drawFromMapPosition(Canvas canvas, final CoordRect area, final Coord p, final int tile) {
+ if (!area.contains(p)) return;
+ _drawFromMapPosition(canvas, area, p.x, p.y, tile);
+ }
+ private void drawFromMapPosition(Canvas canvas, final CoordRect area, final CoordRect p, final int tile) {
+ if (!area.intersects(p)) return;
+ _drawFromMapPosition(canvas, area, p.topLeft.x, p.topLeft.y, tile);
+ }
+ private void _drawFromMapPosition(Canvas canvas, final CoordRect area, int x, int y, final int tile) {
+ x -= mapViewArea.topLeft.x;
+ y -= mapViewArea.topLeft.y;
+// if ( (x >= 0 && x < mapViewArea.size.width)
+// && (y >= 0 && y < mapViewArea.size.height)) {
+ tiles.drawTile(canvas, tile, x * tileSize, y * tileSize, mPaint);
+// }
+ }
+
+ private void drawEffectText(Canvas canvas, final CoordRect area, final VisualEffectAnimation e, int textYOffset, Paint textPaint) {
+ int x = (e.position.x - mapViewArea.topLeft.x) * tileSize + tileSize/2;
+ int y = (e.position.y - mapViewArea.topLeft.y) * tileSize + tileSize/2 + textYOffset;
+ canvas.drawText(e.displayText, x, y, textPaint);
+ }
+
+ @Override
+ public void onPlayerEnteredNewMap(PredefinedMap map, Coord p) {
+ movingSpritesRedrawTick.start();
+ synchronized (holder) {
+ currentMap = map;
+ currentTileMap = model.currentTileMap;
+ tiles = world.tileManager.currentMapTiles;
+ movingSprites = 0;
+ Size visibleNumberOfTiles = new Size(
+ Math.min(screenSizeTileCount.width, currentMap.size.width)
+ ,Math.min(screenSizeTileCount.height, currentMap.size.height)
+ );
+ mapViewArea = new CoordRect(mapTopLeft, visibleNumberOfTiles);
+ updateClip();
+
+// screenOffset.set(
+// (surfaceSize.width - scaledTileSize * visibleNumberOfTiles.width) / 2
+// ,(surfaceSize.height - scaledTileSize * visibleNumberOfTiles.height) / 2
+// );
+
+
+ screenOffset.set(
+ (surfaceSize.width - tileSize * visibleNumberOfTiles.width) / 2
+ ,(surfaceSize.height - tileSize * visibleNumberOfTiles.height) / 2
+ );
+
+ currentTileMap.setColorFilter(this.mPaint, this.alternateColorFilterPaint, preferences.highQualityFilters);
+ }
+
+// touchedTile = null;
+
+ clearCanvas();
+
+ recalculateMapTopLeft(model.player.position, false);
+ redrawAll(RedrawAllDebugReason.MapChanged);
+ }
+
+ private void recalculateMapTopLeft(Coord playerPosition, boolean allowScrolling) {
+ synchronized (holder) {
+ int oldX = mapTopLeft.x;
+ int oldY = mapTopLeft.y;
+ this.playerPosition.set(playerPosition);
+ mapTopLeft.set(0, 0);
+
+ if (currentMap.size.width > screenSizeTileCount.width) {
+ mapTopLeft.x = Math.max(0, playerPosition.x - mapViewArea.size.width/2);
+ mapTopLeft.x = Math.min(mapTopLeft.x, currentMap.size.width - mapViewArea.size.width);
+ }
+ if (currentMap.size.height > screenSizeTileCount.height) {
+ mapTopLeft.y = Math.max(0, playerPosition.y - mapViewArea.size.height/2);
+ mapTopLeft.y = Math.min(mapTopLeft.y, currentMap.size.height - mapViewArea.size.height);
+ }
+ updateClip();
+ if (allowScrolling) {
+ if (mapTopLeft.x != oldX || mapTopLeft.y != oldY) {
+ scrollVector = new Coord(mapTopLeft.x - oldX, mapTopLeft.y - oldY);
+ new ScrollAnimationHandler(this).start();
+ }
+ } else {
+ scrolling = false;
+ }
+ }
+ }
+
+ private void updateClip() {
+ worldCoordsToScreenCords(mapViewArea, redrawClip);
+ }
+
+
+ public static final class ScrollAnimationHandler extends Handler implements Runnable {
+
+ private static final int FRAME_DURATION = 40;
+
+ private final WeakReference view;
+
+ public ScrollAnimationHandler(MainView view) {
+ this.view = new WeakReference(view);
+ }
+
+ @Override
+ public void run() {
+ MainView v = view.get();
+ if (v == null) return;
+ if (System.currentTimeMillis() - v.scrollStartTime >= SCROLL_DURATION) {
+ onCompleted();
+ } else {
+ postDelayed(this, FRAME_DURATION);
+ }
+ update();
+ }
+
+ private void update() {
+ MainView v = view.get();
+ if (v == null) return;
+ v.redrawAll(RedrawAllDebugReason.MapScrolling);
+ }
+
+ private void onCompleted() {
+ MainView v = view.get();
+ if (v == null) return;
+ v.scrolling = false;
+ v.scrollVector = null;
+ }
+
+ public void start() {
+ MainView v = view.get();
+ if (v == null) return;
+ v.scrolling = true;
+ v.scrollStartTime = System.currentTimeMillis();
+ postDelayed(this, 0);
+ }
+ }
+
+
+ public static final class SpriteMoveAnimationHandler extends Handler implements Runnable {
+
+ private static final int FRAME_DURATION = 40;
+ private final WeakReference view;
+ private boolean stop = true;
+
+ public SpriteMoveAnimationHandler(MainView view) {
+ this.view = new WeakReference(view);
+ }
+
+ @Override
+ public void run() {
+ if (!stop) postDelayed(this, FRAME_DURATION);
+ update();
+ }
+
+ private void update() {
+// L.log("stop="+stop+" - scroll="+scrolling+" - moving="+movingSprites);
+ if (stop) return;
+ MainView v = view.get();
+ if (v == null) return;
+ if (!v.scrolling) {
+ if (v.movingSprites > 0) {
+ //TODO : limit redraw area when shouldRedrawEverything() returns false.
+ //Implies keeping track of the animation bounding box in a thread-safe way... :'(
+ v.redrawAll(RedrawAllDebugReason.SpriteMoved);
+ }
+ }
+ synchronized (this) {
+ if (v.movingSprites <= 0) stop();
+ }
+ }
+
+ public void start() {
+ if (stop) {
+ stop = false;
+ MainView v = view.get();
+ if (v == null) return;
+ if (v.controllers.preferences.enableUiAnimations) postDelayed(this, 0);
+ }
+ }
+
+ public void stop() {
+ stop = true;
+ }
+ }
+
+
+
+ @Override
+ public void onPlayerMoved(Coord newPosition, Coord previousPosition) {
+ recalculateMapTopLeft(newPosition, preferences.enableUiAnimations);
+ redrawAll(RedrawAllDebugReason.PlayerMoved);
+ }
+
+ public void subscribe() {
+ controllers.gameRoundController.gameRoundListeners.add(this);
+ controllers.effectController.visualEffectFrameListeners.add(this);
+ controllers.mapController.mapLayoutListeners.add(this);
+ controllers.movementController.playerMovementListeners.add(this);
+ controllers.combatController.combatSelectionListeners.add(this);
+ controllers.monsterSpawnController.monsterSpawnListeners.add(this);
+ controllers.monsterMovementController.monsterMovementListeners.add(this);
+ }
+ public void unsubscribe() {
+ controllers.monsterMovementController.monsterMovementListeners.remove(this);
+ controllers.monsterSpawnController.monsterSpawnListeners.remove(this);
+ controllers.combatController.combatSelectionListeners.remove(this);
+ controllers.movementController.playerMovementListeners.remove(this);
+ controllers.mapController.mapLayoutListeners.remove(this);
+ controllers.effectController.visualEffectFrameListeners.remove(this);
+ controllers.gameRoundController.gameRoundListeners.remove(this);
+ }
+
+ @Override
+ public void onMonsterSelected(Monster m, Coord selectedPosition, Coord previousSelection) {
+ if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
+ redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
+ }
+
+ @Override
+ public void onMovementDestinationSelected(Coord selectedPosition, Coord previousSelection) {
+ if (previousSelection != null) redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
+ redrawTile(selectedPosition, RedrawTileDebugReason.SelectionAdded);
+ }
+
+ @Override
+ public void onCombatSelectionCleared(Coord previousSelection) {
+ redrawTile(previousSelection, RedrawTileDebugReason.SelectionRemoved);
+ }
+
+ @Override
+ public void onMonsterSpawned(PredefinedMap map, Monster m) {
+ if (map != currentMap) return;
+ if (!mapViewArea.intersects(m.rectPosition)) return;
+ redrawNextTick = true;
+ }
+
+ @Override
+ public void onMonsterRemoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
+ if (map != currentMap) return;
+ redrawArea(previousPosition, RedrawAreaDebugReason.MonsterKilled);
+ }
+
+ @Override
+ public void onMonsterSteppedOnPlayer(Monster m) {
+ }
+
+ @Override
+ public void onMonsterMoved(PredefinedMap map, Monster m, CoordRect previousPosition) {
+ if (map != currentMap) return;
+ if (!mapViewArea.intersects(m.rectPosition) && !mapViewArea.intersects(previousPosition)) return;
+ if (model.uiSelections.isInCombat) {
+ redrawArea(previousPosition, RedrawAreaDebugReason.MonsterMoved);
+ redrawArea(m.rectPosition, RedrawAreaDebugReason.MonsterMoved);
+ } else {
+ redrawNextTick = true;
+ }
+ }
+
+ @Override
+ public void onSplatterAdded(PredefinedMap map, Coord p) {
+ if (map != currentMap) return;
+ if (!mapViewArea.contains(p)) return;
+ redrawNextTick = true;
+ }
+
+ @Override
+ public void onSplatterChanged(PredefinedMap map, Coord p) {
+ if (map != currentMap) return;
+ if (!mapViewArea.contains(p)) return;
+ redrawNextTick = true;
+ }
+
+ @Override
+ public void onSplatterRemoved(PredefinedMap map, Coord p) {
+ if (map != currentMap) return;
+ if (!mapViewArea.contains(p)) return;
+ redrawNextTick = true;
+ }
+
+ @Override
+ public void onLootBagCreated(PredefinedMap map, Coord p) {
+ if (map != currentMap) return;
+ redrawTile(p, RedrawTileDebugReason.Bag);
+ }
+
+ @Override
+ public void onLootBagRemoved(PredefinedMap map, Coord p) {
+ if (map != currentMap) return;
+ redrawTile(p, RedrawTileDebugReason.Bag);
+ }
+
+ @Override
+ public void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap) {
+ if (map != currentMap) return;
+ currentTileMap.setColorFilter(this.mPaint, this.alternateColorFilterPaint, preferences.highQualityFilters);
+ redrawAll(RedrawAllDebugReason.MapChanged);
+ }
+
+ @Override
+ public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) {
+ redrawAreaWithEffect(animation, tileID, textYOffset);
+ }
+
+ @Override
+ public void onAnimationCompleted(VisualEffectAnimation animation) {
+ redrawArea(animation.area, RedrawAreaDebugReason.EffectCompleted);
+ }
+
+ @Override
+ public void onSpriteMoveStarted(SpriteMoveAnimation animation) {
+ synchronized (movingSpritesRedrawTick) {
+ movingSprites++;
+ movingSpritesRedrawTick.start();
+ }
+ }
+
+ @Override
+ public void onNewSpriteMoveFrame(SpriteMoveAnimation animation) {
+ //redrawMoveArea_(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), animation);
+ }
+
+ @Override
+ public void onSpriteMoveCompleted(SpriteMoveAnimation animation) {
+ movingSprites--;
+ redrawArea(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), RedrawAreaDebugReason.EffectCompleted);
+ }
+
+ @Override
+ public void onAsyncAreaUpdate(CoordRect area) {
+ redrawArea(area, RedrawAreaDebugReason.AsyncRequest);
+ }
+
+ @Override
+ public void onNewTick() {
+ if (!redrawNextTick) return;
+
+ redrawAll(RedrawAllDebugReason.PlayerMoved);
+
+ redrawNextTick = false;
+ }
+
+ @Override
+ public void onNewRound() { }
+
+ @Override
+ public void onNewFullRound() { }
+}