mirror of
https://github.com/OMGeeky/andors-trail.git
synced 2026-01-20 10:31:28 +01:00
Fixed "restart for locale" bugs.
Fixed missing parsing of the colorfilter map properties.
This commit is contained in:
@@ -3,12 +3,13 @@ package com.gpl.rpg.AndorsTrail;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
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;
|
||||
@@ -16,6 +17,7 @@ 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 {
|
||||
|
||||
@@ -32,9 +34,9 @@ public final class AndorsTrailApplication extends Application {
|
||||
public static final boolean IS_RELEASE_VERSION = !CURRENT_VERSION_DISPLAY.matches(".*[a-d].*");
|
||||
|
||||
private final AndorsTrailPreferences preferences = new AndorsTrailPreferences();
|
||||
private final WorldContext world = new WorldContext();
|
||||
private final ControllerContext controllers = new ControllerContext(this, world);
|
||||
private final WorldSetup setup = new WorldSetup(world, controllers, this);
|
||||
private WorldContext world = new WorldContext();
|
||||
private ControllerContext controllers = new ControllerContext(this, world);
|
||||
private WorldSetup setup = new WorldSetup(world, controllers, this);
|
||||
public WorldContext getWorld() { return world; }
|
||||
public WorldSetup getWorldSetup() { return setup; }
|
||||
public AndorsTrailPreferences getPreferences() { return preferences; }
|
||||
@@ -62,15 +64,23 @@ public final class AndorsTrailApplication extends Application {
|
||||
setLocale(activity);
|
||||
}
|
||||
|
||||
//Get default locale at startup, as somehow it seems that changing the app's
|
||||
//configured locale impacts the value returned by Locale.getDefault() nowadays.
|
||||
private final Locale defaultLocale = Locale.getDefault();
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public boolean setLocale(Activity context) {
|
||||
Resources res = context.getResources();
|
||||
Configuration conf = res.getConfiguration();
|
||||
final Locale targetLocale = preferences.useLocalizedResources ? Locale.getDefault() : Locale.US;
|
||||
if (targetLocale.equals(conf.locale)) return false;
|
||||
final Locale targetLocale = preferences.useLocalizedResources ? defaultLocale : Locale.US;
|
||||
if (targetLocale.equals(conf.locale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
conf.locale = targetLocale;
|
||||
res.updateConfiguration(conf, res.getDisplayMetrics());
|
||||
this.getResources().updateConfiguration(conf, res.getDisplayMetrics());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -127,4 +137,9 @@ public final class AndorsTrailApplication extends Application {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void discardWorld() {
|
||||
world = new WorldContext();
|
||||
controllers = new ControllerContext(this, world);
|
||||
setup = new WorldSetup(world, controllers, getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.activity.fragment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -28,6 +30,7 @@ import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames.FileHeader;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
|
||||
@@ -259,18 +262,25 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
// Changing the locale after having loaded the game requires resources to
|
||||
// be re-loaded. Therefore, we just exit here.
|
||||
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
|
||||
getActivity().finish();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
|
||||
// Changing the theme requires a restart to re-create all activities.
|
||||
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
|
||||
getActivity().finish();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
app.getWorld().tileManager.updatePreferences(preferences);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void doFinish() {
|
||||
//For Lollipop and above
|
||||
((AndorsTrailApplication)getActivity().getApplication()).discardWorld();
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
|
||||
public interface OnNewGameRequestedListener {
|
||||
|
||||
@@ -1,397 +1,391 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
|
||||
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.model.map.MapObject.MapObjectType;
|
||||
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 PredefinedMap {
|
||||
private static final long VISIT_RESET = 0;
|
||||
|
||||
public final int xmlResourceId;
|
||||
public final String name;
|
||||
public final Size size;
|
||||
public final MapObject[] eventObjects;
|
||||
public final MonsterSpawnArea[] spawnAreas;
|
||||
public final List<String> initiallyActiveMapObjectGroups;
|
||||
public final List<String> activeMapObjectGroups;
|
||||
public final ArrayList<Loot> groundBags = new ArrayList<Loot>();
|
||||
public boolean visited = false;
|
||||
public long lastVisitTime = VISIT_RESET;
|
||||
public String lastSeenLayoutHash = "";
|
||||
public final boolean isOutdoors;
|
||||
public String currentColorFilter = null;
|
||||
|
||||
public final ArrayList<BloodSplatter> splatters = new ArrayList<BloodSplatter>();
|
||||
|
||||
public PredefinedMap(
|
||||
int xmlResourceId
|
||||
, String name
|
||||
, Size size
|
||||
, MapObject[] eventObjects
|
||||
, MonsterSpawnArea[] spawnAreas
|
||||
, List<String> initiallyActiveMapObjectGroups
|
||||
, boolean isOutdoors
|
||||
) {
|
||||
this.xmlResourceId = xmlResourceId;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.eventObjects = eventObjects;
|
||||
this.spawnAreas = spawnAreas;
|
||||
this.initiallyActiveMapObjectGroups = initiallyActiveMapObjectGroups;
|
||||
this.activeMapObjectGroups = new LinkedList<String>();
|
||||
this.activeMapObjectGroups.addAll(this.initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
assert(size.width > 0);
|
||||
assert(size.height > 0);
|
||||
this.isOutdoors = isOutdoors;
|
||||
}
|
||||
|
||||
public final boolean isOutside(final Coord p) { return isOutside(p.x, p.y); }
|
||||
public final boolean isOutside(final int x, final int y) {
|
||||
if (x < 0) return true;
|
||||
if (y < 0) return true;
|
||||
if (x >= size.width) return true;
|
||||
if (y >= size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public final boolean isOutside(final CoordRect area) {
|
||||
if (isOutside(area.topLeft)) return true;
|
||||
if (area.topLeft.x + area.size.width > size.width) return true;
|
||||
if (area.topLeft.y + area.size.height > size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public boolean intersects(CoordRect area) {
|
||||
return new CoordRect(new Coord(0,0), size).intersects(area);
|
||||
}
|
||||
|
||||
public MapObject findEventObject(MapObject.MapObjectType objectType, String name) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.type != objectType) continue;
|
||||
if (!name.equals(o.id)) continue;
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<MapObject> getActiveEventObjectsAt(final Coord p) {
|
||||
List<MapObject> result = null;
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
//if (!activeMapObjectGroups.contains(o.group)) continue;
|
||||
if (result == null) result = new ArrayList<MapObject>();
|
||||
result.add(o);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public boolean hasContainerAt(final Coord p) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p) {
|
||||
return getMonsterAt(p, null);
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p, Monster exceptMe) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(p);
|
||||
if (m != null && (exceptMe == null || exceptMe != m)) 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;
|
||||
}
|
||||
|
||||
public Monster findSpawnedMonster(final String monsterTypeID) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.findSpawnedMonster(monsterTypeID);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
boolean isContainer = hasContainerAt(position);
|
||||
b = new Loot(!isContainer);
|
||||
b.position.set(position);
|
||||
if (isOutside(position)) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("WARNING: trying to place bag outside map. Map is " + size.toString() + ", bag tried to place at " + position.toString());
|
||||
}
|
||||
return b;
|
||||
}
|
||||
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 resetForNewGame() {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
a.resetForNewGame();
|
||||
}
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
resetTemporaryData();
|
||||
groundBags.clear();
|
||||
visited = false;
|
||||
currentColorFilter = null;
|
||||
lastSeenLayoutHash = "";
|
||||
}
|
||||
|
||||
public boolean isRecentlyVisited() {
|
||||
if (lastVisitTime == VISIT_RESET) return false;
|
||||
return (System.currentTimeMillis() - lastVisitTime) < Constants.MAP_UNVISITED_RESPAWN_DURATION_MS;
|
||||
}
|
||||
public void updateLastVisitTime() {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
}
|
||||
public void resetTemporaryData() {
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
if (a.isUnique) a.resetShops();
|
||||
else a.removeAllMonsters();
|
||||
}
|
||||
splatters.clear();
|
||||
lastVisitTime = VISIT_RESET;
|
||||
}
|
||||
public boolean hasResetTemporaryData() {
|
||||
return lastVisitTime == VISIT_RESET;
|
||||
}
|
||||
|
||||
public void createAllContainerLoot() {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void createContainerLoot(MapObject container) {
|
||||
Loot bag = getBagOrCreateAt(container.position.topLeft);
|
||||
container.dropList.createRandomLoot(bag, null);
|
||||
}
|
||||
|
||||
|
||||
private void activateMapObjects() {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Applying active status to all map objects in map "+name);
|
||||
}
|
||||
for (MapObject o : eventObjects) {
|
||||
o.isActive = activeMapObjectGroups.contains(o.group);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateMapObjectGroup(String group) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Applying active status to object group "+group+" in map "+name);
|
||||
}
|
||||
if (!activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.add(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = true;
|
||||
if (o.type == MapObjectType.container) createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateMapObjectGroup(String group) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Removing active status to object group "+group+" in map"+name);
|
||||
}
|
||||
if (activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.remove(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public void readFromParcel(DataInputStream src, WorldContext world, ControllerContext controllers, int fileversion) throws IOException {
|
||||
boolean shouldLoadMapData = true;
|
||||
if (fileversion >= 37) shouldLoadMapData = src.readBoolean();
|
||||
|
||||
int loadedSpawnAreas = 0;
|
||||
if (shouldLoadMapData) {
|
||||
loadedSpawnAreas = src.readInt();
|
||||
for(int i = 0; i < loadedSpawnAreas; ++i) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (i >= this.spawnAreas.length) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + i + ". This will totally fail.");
|
||||
}
|
||||
}
|
||||
if(fileversion >= 43) {
|
||||
//Spawn areas now have unique IDs. Need to check as maps can change.
|
||||
String id = src.readUTF();
|
||||
int j = i;
|
||||
boolean found = false;
|
||||
do {
|
||||
if (this.spawnAreas[j].areaID.equals(id)) {
|
||||
this.spawnAreas[j].readFromParcel(src, world, fileversion);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
j = (j+1)%spawnAreas.length;
|
||||
} while (j != i);
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (!found) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + id + " but this area cannot be found. This will totally fail.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.spawnAreas[i].readFromParcel(src, world, fileversion);
|
||||
}
|
||||
}
|
||||
|
||||
activeMapObjectGroups.clear();
|
||||
if(fileversion >= 43) {
|
||||
int activeListLength = src.readInt();
|
||||
for (int i = 0; i < activeListLength; i++) {
|
||||
String activeGroupID = src.readUTF();
|
||||
activeMapObjectGroups.add(activeGroupID);
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
}
|
||||
activateMapObjects();
|
||||
|
||||
groundBags.clear();
|
||||
if (fileversion <= 5) return;
|
||||
|
||||
final int size2 = src.readInt();
|
||||
for(int i = 0; i < size2; ++i) {
|
||||
groundBags.add(new Loot(src, world, fileversion));
|
||||
}
|
||||
|
||||
if (fileversion <= 11) return;
|
||||
|
||||
if (fileversion < 37) visited = src.readBoolean();
|
||||
|
||||
if (fileversion <= 15) {
|
||||
if (visited) {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
createAllContainerLoot();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileversion >= 43) {
|
||||
if (src.readBoolean()) {
|
||||
currentColorFilter = src.readUTF();
|
||||
} else {
|
||||
currentColorFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastVisitTime = src.readLong();
|
||||
|
||||
if (visited) {
|
||||
if (fileversion > 30 && fileversion < 36) {
|
||||
/*int lastVisitVersion = */src.readInt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
}
|
||||
if (fileversion >= 37) {
|
||||
if (fileversion < 41) visited = true;
|
||||
else visited = src.readBoolean();
|
||||
}
|
||||
|
||||
if (fileversion < 36) lastSeenLayoutHash = "";
|
||||
else lastSeenLayoutHash = src.readUTF();
|
||||
|
||||
for(int i = loadedSpawnAreas; i < spawnAreas.length; ++i) {
|
||||
MonsterSpawnArea area = this.spawnAreas[i];
|
||||
if (area.isUnique && visited) controllers.monsterSpawnController.spawnAllInArea(this, null, area, true);
|
||||
else area.resetForNewGame();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSaveMapData(WorldContext world) {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (this == world.model.currentMap) return true;
|
||||
if (!groundBags.isEmpty()) return true;
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
if (this.visited && a.isUnique) return true;
|
||||
if (a.isSpawning != a.isSpawningForNewGame) return true;
|
||||
}
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
if (shouldSaveMapData(world)) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeInt(spawnAreas.length);
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
dest.writeUTF(a.areaID);
|
||||
a.writeToParcel(dest);
|
||||
}
|
||||
dest.writeInt(activeMapObjectGroups.size());
|
||||
for(String s : activeMapObjectGroups) {
|
||||
dest.writeUTF(s);
|
||||
}
|
||||
dest.writeInt(groundBags.size());
|
||||
for(Loot l : groundBags) {
|
||||
l.writeToParcel(dest);
|
||||
}
|
||||
dest.writeBoolean(currentColorFilter != null);
|
||||
if (currentColorFilter != null) dest.writeUTF(currentColorFilter);
|
||||
dest.writeLong(lastVisitTime);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
dest.writeBoolean(visited);
|
||||
dest.writeUTF(lastSeenLayoutHash);
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
|
||||
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.model.map.MapObject.MapObjectType;
|
||||
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 PredefinedMap {
|
||||
private static final long VISIT_RESET = 0;
|
||||
|
||||
public final int xmlResourceId;
|
||||
public final String name;
|
||||
public final Size size;
|
||||
public final MapObject[] eventObjects;
|
||||
public final MonsterSpawnArea[] spawnAreas;
|
||||
public final List<String> initiallyActiveMapObjectGroups;
|
||||
public final List<String> activeMapObjectGroups;
|
||||
public final ArrayList<Loot> groundBags = new ArrayList<Loot>();
|
||||
public final String initialColorFilter;
|
||||
public boolean visited = false;
|
||||
public long lastVisitTime = VISIT_RESET;
|
||||
public String lastSeenLayoutHash = "";
|
||||
public final boolean isOutdoors;
|
||||
public String currentColorFilter = null;
|
||||
|
||||
public final ArrayList<BloodSplatter> splatters = new ArrayList<BloodSplatter>();
|
||||
|
||||
public PredefinedMap(
|
||||
int xmlResourceId
|
||||
, String name
|
||||
, Size size
|
||||
, MapObject[] eventObjects
|
||||
, MonsterSpawnArea[] spawnAreas
|
||||
, List<String> initiallyActiveMapObjectGroups
|
||||
, boolean isOutdoors
|
||||
, String colorFilter
|
||||
) {
|
||||
this.xmlResourceId = xmlResourceId;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.eventObjects = eventObjects;
|
||||
this.spawnAreas = spawnAreas;
|
||||
this.initiallyActiveMapObjectGroups = initiallyActiveMapObjectGroups;
|
||||
this.activeMapObjectGroups = new LinkedList<String>();
|
||||
this.activeMapObjectGroups.addAll(this.initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
assert(size.width > 0);
|
||||
assert(size.height > 0);
|
||||
this.isOutdoors = isOutdoors;
|
||||
this.initialColorFilter = colorFilter;
|
||||
}
|
||||
|
||||
public final boolean isOutside(final Coord p) { return isOutside(p.x, p.y); }
|
||||
public final boolean isOutside(final int x, final int y) {
|
||||
if (x < 0) return true;
|
||||
if (y < 0) return true;
|
||||
if (x >= size.width) return true;
|
||||
if (y >= size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public final boolean isOutside(final CoordRect area) {
|
||||
if (isOutside(area.topLeft)) return true;
|
||||
if (area.topLeft.x + area.size.width > size.width) return true;
|
||||
if (area.topLeft.y + area.size.height > size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public boolean intersects(CoordRect area) {
|
||||
return new CoordRect(new Coord(0,0), size).intersects(area);
|
||||
}
|
||||
|
||||
public MapObject findEventObject(MapObject.MapObjectType objectType, String name) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.type != objectType) continue;
|
||||
if (!name.equals(o.id)) continue;
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<MapObject> getActiveEventObjectsAt(final Coord p) {
|
||||
List<MapObject> result = null;
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
//if (!activeMapObjectGroups.contains(o.group)) continue;
|
||||
if (result == null) result = new ArrayList<MapObject>();
|
||||
result.add(o);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public boolean hasContainerAt(final Coord p) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p) {
|
||||
return getMonsterAt(p, null);
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p, Monster exceptMe) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(p);
|
||||
if (m != null && (exceptMe == null || exceptMe != m)) 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;
|
||||
}
|
||||
|
||||
public Monster findSpawnedMonster(final String monsterTypeID) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.findSpawnedMonster(monsterTypeID);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
boolean isContainer = hasContainerAt(position);
|
||||
b = new Loot(!isContainer);
|
||||
b.position.set(position);
|
||||
if (isOutside(position)) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("WARNING: trying to place bag outside map. Map is " + size.toString() + ", bag tried to place at " + position.toString());
|
||||
}
|
||||
return b;
|
||||
}
|
||||
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 resetForNewGame() {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
a.resetForNewGame();
|
||||
}
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
resetTemporaryData();
|
||||
groundBags.clear();
|
||||
visited = false;
|
||||
currentColorFilter = initialColorFilter;
|
||||
lastSeenLayoutHash = "";
|
||||
}
|
||||
|
||||
public boolean isRecentlyVisited() {
|
||||
if (lastVisitTime == VISIT_RESET) return false;
|
||||
return (System.currentTimeMillis() - lastVisitTime) < Constants.MAP_UNVISITED_RESPAWN_DURATION_MS;
|
||||
}
|
||||
public void updateLastVisitTime() {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
}
|
||||
public void resetTemporaryData() {
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
if (a.isUnique) a.resetShops();
|
||||
else a.removeAllMonsters();
|
||||
}
|
||||
splatters.clear();
|
||||
lastVisitTime = VISIT_RESET;
|
||||
}
|
||||
public boolean hasResetTemporaryData() {
|
||||
return lastVisitTime == VISIT_RESET;
|
||||
}
|
||||
|
||||
public void createAllContainerLoot() {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void createContainerLoot(MapObject container) {
|
||||
Loot bag = getBagOrCreateAt(container.position.topLeft);
|
||||
container.dropList.createRandomLoot(bag, null);
|
||||
}
|
||||
|
||||
|
||||
private void activateMapObjects() {
|
||||
for (MapObject o : eventObjects) {
|
||||
o.isActive = activeMapObjectGroups.contains(o.group);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateMapObjectGroup(String group) {
|
||||
if (!activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.add(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = true;
|
||||
if (o.type == MapObjectType.container) createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateMapObjectGroup(String group) {
|
||||
if (activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.remove(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public void readFromParcel(DataInputStream src, WorldContext world, ControllerContext controllers, int fileversion) throws IOException {
|
||||
boolean shouldLoadMapData = true;
|
||||
if (fileversion >= 37) shouldLoadMapData = src.readBoolean();
|
||||
|
||||
int loadedSpawnAreas = 0;
|
||||
if (shouldLoadMapData) {
|
||||
loadedSpawnAreas = src.readInt();
|
||||
for(int i = 0; i < loadedSpawnAreas; ++i) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (i >= this.spawnAreas.length) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + i + ". This will totally fail.");
|
||||
}
|
||||
}
|
||||
if(fileversion >= 43) {
|
||||
//Spawn areas now have unique IDs. Need to check as maps can change.
|
||||
String id = src.readUTF();
|
||||
int j = i;
|
||||
boolean found = false;
|
||||
do {
|
||||
if (this.spawnAreas[j].areaID.equals(id)) {
|
||||
this.spawnAreas[j].readFromParcel(src, world, fileversion);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
j = (j+1)%spawnAreas.length;
|
||||
} while (j != i);
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (!found) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + id + " but this area cannot be found. This will totally fail.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.spawnAreas[i].readFromParcel(src, world, fileversion);
|
||||
}
|
||||
}
|
||||
|
||||
activeMapObjectGroups.clear();
|
||||
if(fileversion >= 43) {
|
||||
int activeListLength = src.readInt();
|
||||
for (int i = 0; i < activeListLength; i++) {
|
||||
String activeGroupID = src.readUTF();
|
||||
activeMapObjectGroups.add(activeGroupID);
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
}
|
||||
activateMapObjects();
|
||||
|
||||
groundBags.clear();
|
||||
if (fileversion <= 5) return;
|
||||
|
||||
final int size2 = src.readInt();
|
||||
for(int i = 0; i < size2; ++i) {
|
||||
groundBags.add(new Loot(src, world, fileversion));
|
||||
}
|
||||
|
||||
if (fileversion <= 11) return;
|
||||
|
||||
if (fileversion < 37) visited = src.readBoolean();
|
||||
|
||||
if (fileversion <= 15) {
|
||||
if (visited) {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
createAllContainerLoot();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileversion >= 43) {
|
||||
if (src.readBoolean()) {
|
||||
currentColorFilter = src.readUTF();
|
||||
} else {
|
||||
currentColorFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastVisitTime = src.readLong();
|
||||
|
||||
if (visited) {
|
||||
if (fileversion > 30 && fileversion < 36) {
|
||||
/*int lastVisitVersion = */src.readInt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
}
|
||||
if (fileversion >= 37) {
|
||||
if (fileversion < 41) visited = true;
|
||||
else visited = src.readBoolean();
|
||||
}
|
||||
|
||||
if (fileversion < 36) lastSeenLayoutHash = "";
|
||||
else lastSeenLayoutHash = src.readUTF();
|
||||
|
||||
for(int i = loadedSpawnAreas; i < spawnAreas.length; ++i) {
|
||||
MonsterSpawnArea area = this.spawnAreas[i];
|
||||
if (area.isUnique && visited) controllers.monsterSpawnController.spawnAllInArea(this, null, area, true);
|
||||
else area.resetForNewGame();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSaveMapData(WorldContext world) {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (this == world.model.currentMap) return true;
|
||||
if (!groundBags.isEmpty()) return true;
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
if (this.visited && a.isUnique) return true;
|
||||
if (a.isSpawning != a.isSpawningForNewGame) return true;
|
||||
}
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
if (shouldSaveMapData(world)) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeInt(spawnAreas.length);
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
dest.writeUTF(a.areaID);
|
||||
a.writeToParcel(dest);
|
||||
}
|
||||
dest.writeInt(activeMapObjectGroups.size());
|
||||
for(String s : activeMapObjectGroups) {
|
||||
dest.writeUTF(s);
|
||||
}
|
||||
dest.writeInt(groundBags.size());
|
||||
for(Loot l : groundBags) {
|
||||
l.writeToParcel(dest);
|
||||
}
|
||||
dest.writeBoolean(currentColorFilter != null);
|
||||
if (currentColorFilter != null) dest.writeUTF(currentColorFilter);
|
||||
dest.writeLong(lastVisitTime);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
dest.writeBoolean(visited);
|
||||
dest.writeUTF(lastSeenLayoutHash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,10 @@ public final class TMXMapTranslator {
|
||||
assert(m.height > 0);
|
||||
|
||||
boolean isOutdoors = false;
|
||||
String colorFilter = null;
|
||||
for (TMXProperty p : m.properties) {
|
||||
if(p.name.equalsIgnoreCase("outdoors")) isOutdoors = (Integer.parseInt(p.value) != 0);
|
||||
else if(p.name.equalsIgnoreCase("colorfilter")) colorFilter = p.value;
|
||||
else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + " has unrecognized property \"" + p.name + "\".");
|
||||
}
|
||||
|
||||
@@ -212,7 +214,7 @@ public final class TMXMapTranslator {
|
||||
MonsterSpawnArea[] _spawnAreas = new MonsterSpawnArea[spawnAreas.size()];
|
||||
_spawnAreas = spawnAreas.toArray(_spawnAreas);
|
||||
|
||||
result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, _eventObjects, _spawnAreas, activeGroups, isOutdoors));
|
||||
result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, _eventObjects, _spawnAreas, activeGroups, isOutdoors, colorFilter));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -347,6 +349,7 @@ public final class TMXMapTranslator {
|
||||
HashSet<Integer> usedTileIDs,
|
||||
SetOfLayerNames layerNames
|
||||
) {
|
||||
|
||||
final MapLayer layerGround = transformMapLayer(layersPerLayerName, layerNames.groundLayerName, srcMap, tileCache, area, usedTileIDs);
|
||||
final MapLayer layerObjects = transformMapLayer(layersPerLayerName, layerNames.objectsLayerName, srcMap, tileCache, area, usedTileIDs);
|
||||
final MapLayer layerAbove = transformMapLayer(layersPerLayerName, layerNames.aboveLayersName, srcMap, tileCache, area, usedTileIDs);
|
||||
|
||||
@@ -1,123 +1,125 @@
|
||||
package com.gpl.rpg.AndorsTrail.resource.tiles;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.util.LruCache;
|
||||
|
||||
public final class TileCache {
|
||||
|
||||
private final ReferenceQueue<Bitmap> gcQueue = new ReferenceQueue<Bitmap>();
|
||||
private ResourceFileTile[] resourceTiles = new ResourceFileTile[1];
|
||||
private final HashMap<String, SparseIntArray> tileIDsPerTilesetAndLocalID = new HashMap<String, SparseIntArray>();
|
||||
private final LruCache<Integer, Bitmap> cache = new LruCache<Integer, Bitmap>(1000);
|
||||
|
||||
public int getMaxTileID() { return resourceTiles.length-1; }
|
||||
public void allocateMaxTileID(int maxTileID) {
|
||||
if (maxTileID <= 0) return;
|
||||
|
||||
ResourceFileTile[] oldArray = resourceTiles;
|
||||
resourceTiles = new ResourceFileTile[maxTileID+1];
|
||||
System.arraycopy(oldArray, 0, resourceTiles, 0, oldArray.length);
|
||||
}
|
||||
public void setTile(int tileID, ResourceFileTileset tileset, int localID) {
|
||||
if (resourceTiles[tileID] == null) resourceTiles[tileID] = new ResourceFileTile(tileset, localID);
|
||||
SparseIntArray tileIDsPerLocalID = tileIDsPerTilesetAndLocalID.get(tileset.tilesetName);
|
||||
if (tileIDsPerLocalID == null) {
|
||||
tileIDsPerLocalID = new SparseIntArray();
|
||||
tileIDsPerTilesetAndLocalID.put(tileset.tilesetName, tileIDsPerLocalID);
|
||||
}
|
||||
tileIDsPerLocalID.put(localID, tileID);
|
||||
}
|
||||
public int getTileID(String tileSetName, int localID) {
|
||||
return tileIDsPerTilesetAndLocalID.get(tileSetName).get(localID);
|
||||
}
|
||||
|
||||
private static final class ResourceFileTile {
|
||||
public final ResourceFileTileset tileset;
|
||||
public final int localID;
|
||||
//public WeakReference<Bitmap> bitmap;
|
||||
public ResourceFileTile(ResourceFileTileset tileset, int localID) {
|
||||
this.tileset = tileset;
|
||||
this.localID = localID;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanQueue() {
|
||||
System.gc();
|
||||
Reference<? extends Bitmap> ref;
|
||||
while ((ref = gcQueue.poll()) != null) {
|
||||
Bitmap b = ref.get();
|
||||
if (b != null) b.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r) { return loadTilesFor(iconIDs, r, null); }
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r, TileCollection result) {
|
||||
int maxTileID = 0;
|
||||
HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>> tilesToLoadPerSourceFile = new HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>>();
|
||||
for(int tileID : iconIDs) {
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
SparseArray<ResourceFileTile> tiles = tilesToLoadPerSourceFile.get(tile.tileset);
|
||||
if (tiles == null) {
|
||||
tiles = new SparseArray<TileCache.ResourceFileTile>();
|
||||
tilesToLoadPerSourceFile.put(tile.tileset, tiles);
|
||||
}
|
||||
tiles.put(tileID, tile);
|
||||
maxTileID = Math.max(maxTileID, tileID);
|
||||
}
|
||||
|
||||
boolean hasLoadedTiles = false;
|
||||
if (result == null) result = new TileCollection(maxTileID);
|
||||
for(Entry<ResourceFileTileset, SparseArray<ResourceFileTile>> e : tilesToLoadPerSourceFile.entrySet()) {
|
||||
TileCutter cutter = null;
|
||||
|
||||
SparseArray<ResourceFileTile> tilesToLoad = e.getValue();
|
||||
for (int i = 0; i < tilesToLoad.size(); ++i) {
|
||||
int tileID = tilesToLoad.keyAt(i);
|
||||
ResourceFileTile tile = tilesToLoad.valueAt(i);
|
||||
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
|
||||
if (bitmap == null) {
|
||||
if (cutter == null) {
|
||||
if (!hasLoadedTiles) cleanQueue();
|
||||
cutter = new TileCutter(e.getKey(), r);
|
||||
hasLoadedTiles = true;
|
||||
}
|
||||
|
||||
bitmap = cutter.createTile(tile.localID);
|
||||
cache.put(tileID, bitmap);
|
||||
new WeakReference<Bitmap>(bitmap, gcQueue);
|
||||
}
|
||||
result.setBitmap(tileID, bitmap);
|
||||
}
|
||||
|
||||
if (cutter != null) cutter.recycle();
|
||||
}
|
||||
if (hasLoadedTiles) cleanQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Bitmap loadSingleTile(int tileID, Resources r) {
|
||||
cleanQueue();
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
if (bitmap != null) return bitmap;
|
||||
|
||||
TileCutter cutter = new TileCutter(tile.tileset, r);
|
||||
Bitmap result = cutter.createTile(tile.localID);
|
||||
cutter.recycle();
|
||||
cache.put(tileID, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.resource.tiles;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.LruCache;
|
||||
|
||||
public final class TileCache {
|
||||
|
||||
private final ReferenceQueue<Bitmap> gcQueue = new ReferenceQueue<Bitmap>();
|
||||
private ResourceFileTile[] resourceTiles = new ResourceFileTile[1];
|
||||
private final HashMap<String, SparseIntArray> tileIDsPerTilesetAndLocalID = new HashMap<String, SparseIntArray>();
|
||||
private final LruCache<Integer, Bitmap> cache = new LruCache<Integer, Bitmap>(1000);
|
||||
|
||||
public int getMaxTileID() { return resourceTiles.length-1; }
|
||||
public void allocateMaxTileID(int maxTileID) {
|
||||
if (maxTileID <= 0) return;
|
||||
|
||||
ResourceFileTile[] oldArray = resourceTiles;
|
||||
resourceTiles = new ResourceFileTile[maxTileID+1];
|
||||
System.arraycopy(oldArray, 0, resourceTiles, 0, oldArray.length);
|
||||
}
|
||||
public void setTile(int tileID, ResourceFileTileset tileset, int localID) {
|
||||
if (resourceTiles[tileID] == null) resourceTiles[tileID] = new ResourceFileTile(tileset, localID);
|
||||
SparseIntArray tileIDsPerLocalID = tileIDsPerTilesetAndLocalID.get(tileset.tilesetName);
|
||||
if (tileIDsPerLocalID == null) {
|
||||
tileIDsPerLocalID = new SparseIntArray();
|
||||
tileIDsPerTilesetAndLocalID.put(tileset.tilesetName, tileIDsPerLocalID);
|
||||
}
|
||||
tileIDsPerLocalID.put(localID, tileID);
|
||||
}
|
||||
public int getTileID(String tileSetName, int localID) {
|
||||
return tileIDsPerTilesetAndLocalID.get(tileSetName).get(localID);
|
||||
}
|
||||
|
||||
private static final class ResourceFileTile {
|
||||
public final ResourceFileTileset tileset;
|
||||
public final int localID;
|
||||
//public WeakReference<Bitmap> bitmap;
|
||||
public ResourceFileTile(ResourceFileTileset tileset, int localID) {
|
||||
this.tileset = tileset;
|
||||
this.localID = localID;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanQueue() {
|
||||
System.gc();
|
||||
Reference<? extends Bitmap> ref;
|
||||
while ((ref = gcQueue.poll()) != null) {
|
||||
Bitmap b = ref.get();
|
||||
if (b != null) b.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r) { return loadTilesFor(iconIDs, r, null); }
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r, TileCollection result) {
|
||||
int maxTileID = 0;
|
||||
HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>> tilesToLoadPerSourceFile = new HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>>();
|
||||
for(int tileID : iconIDs) {
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
SparseArray<ResourceFileTile> tiles = tilesToLoadPerSourceFile.get(tile.tileset);
|
||||
if (tiles == null) {
|
||||
tiles = new SparseArray<TileCache.ResourceFileTile>();
|
||||
tilesToLoadPerSourceFile.put(tile.tileset, tiles);
|
||||
}
|
||||
tiles.put(tileID, tile);
|
||||
maxTileID = Math.max(maxTileID, tileID);
|
||||
}
|
||||
|
||||
boolean hasLoadedTiles = false;
|
||||
if (result == null) result = new TileCollection(maxTileID);
|
||||
for(Entry<ResourceFileTileset, SparseArray<ResourceFileTile>> e : tilesToLoadPerSourceFile.entrySet()) {
|
||||
TileCutter cutter = null;
|
||||
|
||||
SparseArray<ResourceFileTile> tilesToLoad = e.getValue();
|
||||
for (int i = 0; i < tilesToLoad.size(); ++i) {
|
||||
int tileID = tilesToLoad.keyAt(i);
|
||||
ResourceFileTile tile = tilesToLoad.valueAt(i);
|
||||
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
|
||||
if (bitmap == null) {
|
||||
if (cutter == null) {
|
||||
if (!hasLoadedTiles) cleanQueue();
|
||||
cutter = new TileCutter(e.getKey(), r);
|
||||
hasLoadedTiles = true;
|
||||
}
|
||||
|
||||
bitmap = cutter.createTile(tile.localID);
|
||||
cache.put(tileID, bitmap);
|
||||
new WeakReference<Bitmap>(bitmap, gcQueue);
|
||||
}
|
||||
result.setBitmap(tileID, bitmap);
|
||||
}
|
||||
|
||||
if (cutter != null) cutter.recycle();
|
||||
}
|
||||
if (hasLoadedTiles) cleanQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Bitmap loadSingleTile(int tileID, Resources r) {
|
||||
cleanQueue();
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
if (bitmap != null) return bitmap;
|
||||
|
||||
TileCutter cutter = new TileCutter(tile.tileset, r);
|
||||
Bitmap result = cutter.createTile(tile.localID);
|
||||
cutter.recycle();
|
||||
cache.put(tileID, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
|
||||
public final class L {
|
||||
private static final String TAG = "AndorsTrail";
|
||||
|
||||
public static void log(String s) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
Log.d(TAG, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
|
||||
public final class L {
|
||||
private static final String TAG = "AndorsTrail";
|
||||
|
||||
public static void log(String s) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
Log.w(TAG, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user