displayedMapNames) {
+ private static CoordRect determineNamedAreaBoundary(NamedWorldMapArea area, WorldMapSegment segment, WorldContext world, Set
displayedMapNames) {
Coord topLeft = null;
Coord bottomRight = null;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListeners.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListeners.java
deleted file mode 100644
index 440908eac..000000000
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListeners.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.gpl.rpg.AndorsTrail.controller.listeners;
-
-import com.gpl.rpg.AndorsTrail.util.ListOfListeners;
-import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
-import com.gpl.rpg.AndorsTrail.util.Coord;
-
-public final class LootBagListeners extends ListOfListeners implements LootBagListener {
-
- private final Function2 onLootBagCreated = new Function2() {
- @Override public void call(LootBagListener listener, PredefinedMap map, Coord p) { listener.onLootBagCreated(map, p); }
- };
-
- private final Function2 onLootBagRemoved = new Function2() {
- @Override public void call(LootBagListener listener, PredefinedMap map, Coord p) { listener.onLootBagRemoved(map, p); }
- };
-
- @Override
- public void onLootBagCreated(PredefinedMap map, Coord p) {
- callAllListeners(this.onLootBagCreated, map, p);
- }
-
- @Override
- public void onLootBagRemoved(PredefinedMap map, Coord p) {
- callAllListeners(this.onLootBagRemoved, map, p);
- }
-}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListener.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListener.java
similarity index 61%
rename from AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListener.java
rename to AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListener.java
index 816c9129e..897e6eb9a 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/LootBagListener.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListener.java
@@ -1,9 +1,11 @@
package com.gpl.rpg.AndorsTrail.controller.listeners;
+import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.util.Coord;
-public interface LootBagListener {
+public interface MapLayoutListener {
void onLootBagCreated(PredefinedMap map, Coord p);
void onLootBagRemoved(PredefinedMap map, Coord p);
+ void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap);
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListeners.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListeners.java
new file mode 100644
index 000000000..946c36d05
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/listeners/MapLayoutListeners.java
@@ -0,0 +1,36 @@
+package com.gpl.rpg.AndorsTrail.controller.listeners;
+
+import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
+import com.gpl.rpg.AndorsTrail.util.ListOfListeners;
+import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+
+public final class MapLayoutListeners extends ListOfListeners implements MapLayoutListener {
+
+ private final Function2 onLootBagCreated = new Function2() {
+ @Override public void call(MapLayoutListener listener, PredefinedMap map, Coord p) { listener.onLootBagCreated(map, p); }
+ };
+
+ private final Function2 onLootBagRemoved = new Function2() {
+ @Override public void call(MapLayoutListener listener, PredefinedMap map, Coord p) { listener.onLootBagRemoved(map, p); }
+ };
+
+ private final Function2 onMapTilesChanged = new Function2() {
+ @Override public void call(MapLayoutListener listener, PredefinedMap map, LayeredTileMap tileMap) { listener.onMapTilesChanged(map, tileMap); }
+ };
+
+ @Override
+ public void onLootBagCreated(PredefinedMap map, Coord p) {
+ callAllListeners(this.onLootBagCreated, map, p);
+ }
+
+ @Override
+ public void onLootBagRemoved(PredefinedMap map, Coord p) {
+ callAllListeners(this.onLootBagRemoved, map, p);
+ }
+
+ @Override
+ public void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap) {
+ callAllListeners(this.onMapTilesChanged, map, tileMap);
+ }
+}
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 851826ca3..86ee8d55c 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java
@@ -11,46 +11,38 @@ import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class LayeredTileMap {
- public static final int LAYER_GROUND = 0;
- public static final int LAYER_OBJECTS = 1;
- public static final int LAYER_ABOVE = 2;
-
private static final ColorFilter colorFilterBlack20 = createGrayScaleColorFilter(0.2f);
private static final ColorFilter colorFilterBlack40 = createGrayScaleColorFilter(0.4f);
private static final ColorFilter colorFilterBlack60 = createGrayScaleColorFilter(0.6f);
private static final ColorFilter colorFilterBlack80 = createGrayScaleColorFilter(0.8f);
private final Size size;
- public final MapLayer[] layers;
- public final Collection usedTileIDs;
- private final boolean[][] isWalkable;
+ public final MapSection currentLayout;
+ private String currentLayoutHash;
+ public final ReplaceableMapSection[] replacements;
public final String colorFilter;
-
+ public final Collection usedTileIDs;
public LayeredTileMap(
Size size,
- MapLayer[] layers,
- boolean[][] isWalkable,
- Collection usedTileIDs,
- String colorFilter) {
- assert(size.width > 0);
- assert(size.height > 0);
- assert(layers.length == 3);
- assert(isWalkable.length == size.width);
- assert(isWalkable[0].length == size.height);
+ MapSection layout,
+ ReplaceableMapSection[] replacements,
+ String colorFilter,
+ Collection usedTileIDs) {
this.size = size;
- this.layers = layers;
- this.usedTileIDs = usedTileIDs;
- this.isWalkable = isWalkable;
+ this.currentLayout = layout;
+ this.replacements = replacements;
this.colorFilter = colorFilter;
+ this.usedTileIDs = usedTileIDs;
+ this.currentLayoutHash = currentLayout.calculateHash();
}
public final boolean isWalkable(final Coord p) {
if (isOutside(p.x, p.y)) return false;
- return isWalkable[p.x][p.y];
+ return currentLayout.isWalkable[p.x][p.y];
}
public final boolean isWalkable(final int x, final int y) {
if (isOutside(x, y)) return false;
- return isWalkable[x][y];
+ return currentLayout.isWalkable[x][y];
}
public final boolean isWalkable(final CoordRect p) {
for (int y = 0; y < p.size.height; ++y) {
@@ -98,4 +90,13 @@ public final class LayeredTileMap {
0.00f, 0.00f, 0.00f, 1.0f, 0.0f
});
}
+
+ public String getCurrentLayoutHash() {
+ return currentLayoutHash;
+ }
+
+ public void applyReplacement(ReplaceableMapSection replacement) {
+ replacement.apply(currentLayout);
+ currentLayoutHash = currentLayout.calculateHash();
+ }
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java
index d56649a8a..ded0dcba7 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java
@@ -17,6 +17,7 @@ import java.util.List;
public final class MapCollection {
private final HashMap predefinedMaps = new HashMap();
public final HashMap worldMapSegments = new HashMap();
+ public boolean worldMapRequiresUpdate = true;
public MapCollection() {}
@@ -43,6 +44,7 @@ public final class MapCollection {
for (PredefinedMap m : getAllMaps()) {
m.reset();
}
+ worldMapRequiresUpdate = true;
}
public String getWorldMapSegmentNameForMap(String mapName) {
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java
index 906ae4dc3..0d2dbfa98 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapLayer.java
@@ -4,27 +4,12 @@ import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.Size;
public final class MapLayer {
- private final Size size;
public final int[][] tiles;
public MapLayer(Size size) {
- this.size = size;
tiles = new int[size.width][size.height];
}
public void setTile(int type, int x, int y) {
tiles[x][y] = type;
}
- public void setTile(int type, Coord p) {
- setTile(type, p.x, p.y);
- }
- public final boolean isOutside(int x, int y) {
- if (x < 0) return true;
- if (y < 0) return true;
- if (x >= size.width) return true;
- if (y >= size.height) return true;
- return false;
- }
- public final boolean isOutside(Coord p) {
- return isOutside(p.x, p.y);
- }
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapSection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapSection.java
new file mode 100644
index 000000000..b1b07e1e1
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapSection.java
@@ -0,0 +1,54 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import com.gpl.rpg.AndorsTrail.util.ByteUtils;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+
+public final class MapSection {
+ public final MapLayer layerGround;
+ public final MapLayer layerObjects;
+ public final MapLayer layerAbove;
+ public final boolean[][] isWalkable;
+ private final byte[] layoutHash;
+
+ public MapSection(
+ MapLayer layerGround,
+ MapLayer layerObjects,
+ MapLayer layerAbove,
+ boolean[][] isWalkable,
+ byte[] layoutHash) {
+ this.layerGround = layerGround;
+ this.layerObjects = layerObjects;
+ this.layerAbove = layerAbove;
+ this.isWalkable = isWalkable;
+ this.layoutHash = layoutHash;
+ }
+
+ public void replaceLayerContentsWith(final MapSection replaceLayersWith, final CoordRect replacementArea) {
+ replaceTileLayerSection(layerGround, replaceLayersWith.layerGround, replacementArea);
+ replaceTileLayerSection(layerObjects, replaceLayersWith.layerObjects, replacementArea);
+ replaceTileLayerSection(layerAbove, replaceLayersWith.layerAbove, replacementArea);
+ if (replaceLayersWith.isWalkable != null) {
+ final int dy = replacementArea.topLeft.y;
+ final int height = replacementArea.size.height;
+ for (int sx = 0, dx = replacementArea.topLeft.x; sx < replacementArea.size.width; ++sx, ++dx) {
+ System.arraycopy(replaceLayersWith.isWalkable[sx], 0, isWalkable[dx], dy, height);
+ }
+ }
+ for(int i = 0; i < layoutHash.length; ++i) {
+ layoutHash[i] ^= replaceLayersWith.layoutHash[i];
+ }
+ }
+
+ private static void replaceTileLayerSection(MapLayer dest, MapLayer src, CoordRect area) {
+ if (src == null) return;
+ final int dy = area.topLeft.y;
+ final int height = area.size.height;
+ for (int sx = 0, dx = area.topLeft.x; sx < area.size.width; ++sx, ++dx) {
+ System.arraycopy(src.tiles[sx], 0, dest.tiles[dx], dy, height);
+ }
+ }
+
+ public String calculateHash() {
+ return ByteUtils.toHexString(layoutHash, 4);
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/PredefinedMap.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/PredefinedMap.java
index fb5568da8..d3e322d6f 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/PredefinedMap.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/PredefinedMap.java
@@ -29,7 +29,7 @@ public final class PredefinedMap {
public final ArrayList groundBags = new ArrayList();
public boolean visited = false;
public long lastVisitTime = VISIT_RESET;
- public int lastVisitVersion = 0;
+ public String lastSeenLayoutHash = "";
private final boolean isOutdoors;
public final ArrayList splatters = new ArrayList();
@@ -136,7 +136,7 @@ public final class PredefinedMap {
}
groundBags.clear();
visited = false;
- lastVisitVersion = 0;
+ lastSeenLayoutHash = "";
}
public boolean isRecentlyVisited() {
@@ -145,7 +145,6 @@ public final class PredefinedMap {
}
public void updateLastVisitTime() {
lastVisitTime = System.currentTimeMillis();
- lastVisitVersion = AndorsTrailApplication.CURRENT_VERSION;
}
public void resetTemporaryData() {
for(MonsterSpawnArea a : spawnAreas) {
@@ -213,10 +212,13 @@ public final class PredefinedMap {
lastVisitTime = src.readLong();
if (visited) {
- if (fileversion <= 30) lastVisitVersion = 30;
- else lastVisitVersion = src.readInt();
+ if (fileversion > 30 && fileversion < 36) {
+ /*int lastVisitVersion = */src.readInt();
+ }
+ 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);
@@ -235,6 +237,8 @@ public final class PredefinedMap {
}
dest.writeBoolean(visited);
dest.writeLong(lastVisitTime);
- if (visited) dest.writeInt(lastVisitVersion);
+ if (visited) {
+ dest.writeUTF(lastSeenLayoutHash);
+ }
}
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/ReplaceableMapSection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/ReplaceableMapSection.java
new file mode 100644
index 000000000..7ec9012d4
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/ReplaceableMapSection.java
@@ -0,0 +1,25 @@
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+
+public final class ReplaceableMapSection {
+ public boolean isApplied = false;
+ public final CoordRect replacementArea;
+ public final MapSection replaceLayersWith;
+ public final QuestProgress requireQuestStage;
+
+ public ReplaceableMapSection(
+ CoordRect replacementArea,
+ MapSection replaceLayersWith,
+ QuestProgress requireQuestStage) {
+ this.replacementArea = replacementArea;
+ this.replaceLayersWith = replaceLayersWith;
+ this.requireQuestStage = requireQuestStage;
+ }
+
+ public void apply(MapSection dest) {
+ dest.replaceLayerContentsWith(replaceLayersWith, replacementArea);
+ isApplied = true;
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapFileParser.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapFileParser.java
index 3c4f9b523..ae545414b 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapFileParser.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapFileParser.java
@@ -1,31 +1,31 @@
package com.gpl.rpg.AndorsTrail.model.map;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import com.gpl.rpg.AndorsTrail.util.Base64;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.XmlResourceParserUtils;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
-import org.xmlpull.v1.XmlPullParserException;
-
-import com.gpl.rpg.AndorsTrail.util.Base64;
-import com.gpl.rpg.AndorsTrail.util.L;
-import com.gpl.rpg.AndorsTrail.util.XmlResourceParserUtils;
-
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-
public final class TMXMapFileParser {
- public static TMXMap read(Resources r, int xmlResourceId, String name) {
- return read(r.getXml(xmlResourceId), xmlResourceId, name);
+ public static TMXObjectMap readObjectMap(Resources r, int xmlResourceId, String name) {
+ return readObjectMap(r.getXml(xmlResourceId), xmlResourceId, name);
}
- public static TMXLayerMap readLayeredTileMap(Resources r, int xmlResourceId, String name) {
+ public static TMXLayerMap readLayerMap(Resources r, int xmlResourceId, String name) {
return readLayerMap(r.getXml(xmlResourceId), name);
}
- private static TMXMap read(XmlResourceParser xrp, int xmlResourceId, String name) {
- final TMXMap map = new TMXMap();
+ private static TMXObjectMap readObjectMap(XmlResourceParser xrp, int xmlResourceId, String name) {
+ final TMXObjectMap map = new TMXObjectMap();
map.xmlResourceId = xmlResourceId;
try {
// Map format: http://sourceforge.net/apps/mediawiki/tiled/index.php?title=Examining_the_map_format
@@ -35,7 +35,6 @@ public final class TMXMapFileParser {
String s = xrp.getName();
if (s.equals("map")) {
map.name = name;
- map.orientation = xrp.getAttributeValue(null, "orientation");
map.width = xrp.getAttributeIntValue(null, "width", -1);
map.height = xrp.getAttributeIntValue(null, "height", -1);
map.tilewidth = xrp.getAttributeIntValue(null, "tilewidth", -1);
@@ -72,8 +71,11 @@ public final class TMXMapFileParser {
if (eventType == XmlResourceParser.START_TAG) {
String s = xrp.getName();
if (s.equals("map")) {
+ map.name = name;
map.width = xrp.getAttributeIntValue(null, "width", -1);
map.height = xrp.getAttributeIntValue(null, "height", -1);
+ map.tilewidth = xrp.getAttributeIntValue(null, "tilewidth", -1);
+ map.tileheight = xrp.getAttributeIntValue(null, "tileheight", -1);
XmlResourceParserUtils.readCurrentTagUntilEnd(xrp, new XmlResourceParserUtils.TagHandler() {
public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
if (tagName.equals("tileset")) {
@@ -82,6 +84,8 @@ public final class TMXMapFileParser {
layers.add(readTMXMapLayer(xrp));
} else if (tagName.equals("property")) {
map.properties.add(readTMXProperty(xrp));
+ } else if (tagName.equals("objectgroup")) {
+ map.objectGroups.add(readTMXObjectGroup(xrp));
}
}
});
@@ -196,11 +200,17 @@ public final class TMXMapFileParser {
for(int y = 0; y < layer.height; ++y) {
for(int x = 0; x < layer.width; ++x, i += 4) {
int gid = readIntLittleEndian(buffer, i);
- //if (gid != 0) L.log(getHexString(buffer, i) + " -> " + gid);
layer.gids[x][y] = gid;
- //L.log("(" + x + "," + y + ") : " + layer.gids[x][y]);
}
}
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ digest.update(buffer);
+ layer.layoutHash = digest.digest();
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("Failed to create layout hash for map layer " + layer.name);
+ }
}
private static TMXProperty readTMXProperty(XmlResourceParser xrp) {
@@ -241,19 +251,21 @@ public final class TMXMapFileParser {
(buffer[offset + 3] << 24) & 0xff000000;
}
- public static final class TMXMap extends TMXLayerMap {
+ public static final class TMXObjectMap extends TMXMap {
public int xmlResourceId;
- public String name;
- public String orientation;
- public int tilewidth;
- public int tileheight;
public final ArrayList objectGroups = new ArrayList();
}
- public static class TMXLayerMap {
- public int width;
- public int height;
+ public static final class TMXLayerMap extends TMXMap {
public TMXTileSet[] tileSets;
public TMXLayer[] layers;
+ public final ArrayList objectGroups = new ArrayList();
+ }
+ public static class TMXMap {
+ public String name;
+ public int width;
+ public int height;
+ public int tilewidth;
+ public int tileheight;
public final ArrayList properties = new ArrayList();
}
public static final class TMXTileSet {
@@ -269,6 +281,7 @@ public final class TMXMapFileParser {
public int width;
public int height;
public int[][] gids;
+ public byte[] layoutHash;
}
public static final class TMXObjectGroup {
public String name;
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java
index cfa5d236d..e962e6db4 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java
@@ -1,8 +1,8 @@
package com.gpl.rpg.AndorsTrail.model.map;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
@@ -12,12 +12,12 @@ import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXLayer;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXLayerMap;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXMap;
+import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXObjectMap;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXObject;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXObjectGroup;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXProperty;
import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXTileSet;
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
-import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCache;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.CoordRect;
@@ -28,25 +28,24 @@ import com.gpl.rpg.AndorsTrail.util.Size;
import android.content.res.Resources;
public final class TMXMapTranslator {
- private final ArrayList maps = new ArrayList();
+ private final ArrayList maps = new ArrayList();
public void read(Resources r, int xmlResourceId, String name) {
- maps.add(TMXMapFileParser.read(r, xmlResourceId, name));
+ maps.add(TMXMapFileParser.readObjectMap(r, xmlResourceId, name));
}
public static LayeredTileMap readLayeredTileMap(Resources res, TileCache tileCache, PredefinedMap map) {
- TMXLayerMap resultMap = TMXMapFileParser.readLayeredTileMap(res, map.xmlResourceId, map.name);
- return transformMap(resultMap, tileCache, map.name);
+ TMXLayerMap resultMap = TMXMapFileParser.readLayerMap(res, map.xmlResourceId, map.name);
+ return transformMap(resultMap, tileCache);
}
public ArrayList transformMaps(MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
return transformMaps(maps, monsterTypes, dropLists);
}
- public ArrayList transformMaps(Collection maps, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
+ public ArrayList transformMaps(Collection maps, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
ArrayList result = new ArrayList();
- Tile tile = new Tile();
- for (TMXMap m : maps) {
+ for (TMXObjectMap m : maps) {
assert(m.name != null);
assert(m.name.length() > 0);
assert(m.width > 0);
@@ -64,13 +63,7 @@ public final class TMXMapTranslator {
for (TMXObjectGroup group : m.objectGroups) {
for (TMXObject object : group.objects) {
- final Coord topLeft = new Coord(
- Math.round(((float)object.x) / m.tilewidth)
- ,Math.round(((float)object.y) / m.tileheight)
- );
- final int width = Math.round(((float)object.width) / m.tilewidth);
- final int height = Math.round(((float)object.height) / m.tileheight);
- final CoordRect position = new CoordRect(topLeft, new Size(width, height));
+ final CoordRect position = getTMXObjectPosition(object, m);
if (object.type == null) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA)
@@ -148,6 +141,8 @@ public final class TMXMapTranslator {
DropList dropList = dropLists.getDropList(object.name);
if (dropList == null) continue;
mapObjects.add(MapObject.createNewContainerArea(position, dropList));
+ } else if (object.type.equals("replace")) {
+ // Do nothing. Will be handled when reading map layers instead.
} else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
L.log("OPTIMIZE: Map " + m.name + ", has unrecognized object type \"" + object.type + "\" for name \"" + object.name + "\".");
}
@@ -163,66 +158,178 @@ public final class TMXMapTranslator {
return result;
}
-
- private static LayeredTileMap transformMap(TMXLayerMap map, TileCache tileCache, String mapName) {
+ private static CoordRect getTMXObjectPosition(TMXObject object, TMXMap m) {
+ final Coord topLeft = new Coord(
+ Math.round(((float)object.x) / m.tilewidth)
+ ,Math.round(((float)object.y) / m.tileheight)
+ );
+ final int width = Math.round(((float)object.width) / m.tilewidth);
+ final int height = Math.round(((float)object.height) / m.tileheight);
+ return new CoordRect(topLeft, new Size(width, height));
+ }
+
+ private static final String LAYERNAME_GROUND = "ground";
+ private static final String LAYERNAME_OBJECTS = "objects";
+ private static final String LAYERNAME_ABOVE = "above";
+ private static final String LAYERNAME_WALKABLE = "walkable";
+ private static final SetOfLayerNames defaultLayerNames = new SetOfLayerNames(LAYERNAME_GROUND, LAYERNAME_OBJECTS, LAYERNAME_ABOVE, LAYERNAME_WALKABLE);
+
+ private static LayeredTileMap transformMap(TMXLayerMap map, TileCache tileCache) {
final Size mapSize = new Size(map.width, map.height);
- final MapLayer[] layers = new MapLayer[] {
- new MapLayer(mapSize)
- ,new MapLayer(mapSize)
- ,new MapLayer(mapSize)
- };
- boolean[][] isWalkable = new boolean[map.width][map.height];
- for (int y = 0; y < map.height; ++y) {
- for (int x = 0; x < map.width; ++x) {
- isWalkable[x][y] = true;
- }
- }
- Tile tile = new Tile();
String colorFilter = null;
for (TMXProperty prop : map.properties) {
if (prop.name.equalsIgnoreCase("colorfilter")) colorFilter = prop.value;
}
HashSet usedTileIDs = new HashSet();
+ HashMap layersPerLayerName = new HashMap();
for (TMXLayer layer : map.layers) {
- int ixMapLayer = 0;
String layerName = layer.name;
assert(layerName != null);
assert(layerName.length() > 0);
layerName = layerName.toLowerCase();
- boolean isWalkableLayer = false;
- if (layerName.startsWith("object")) {
- ixMapLayer = LayeredTileMap.LAYER_OBJECTS;
- } else if (layerName.startsWith("ground")) {
- ixMapLayer = LayeredTileMap.LAYER_GROUND;
- } else if (layerName.startsWith("above")) {
- ixMapLayer = LayeredTileMap.LAYER_ABOVE;
- } else if (layerName.startsWith("walk")) {
- isWalkableLayer = true;
- } else {
- continue;
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ if (layersPerLayerName.containsKey(layerName)) {
+ L.log("WARNING: Map \"" + map.name + "\" contains multiple layers with name \"" + layerName + "\".");
+ }
}
-
- for (int y = 0; y < layer.height; ++y) {
- for (int x = 0; x < layer.width; ++x) {
- int gid = layer.gids[x][y];
- if (gid <= 0) continue;
-
- if (!getTile(map, gid, tile)) continue;
+ layersPerLayerName.put(layerName, layer);
+ }
- if (isWalkableLayer) {
- isWalkable[x][y] = false;
- } else {
- int tileID = tileCache.getTileID(tile.tilesetName, tile.localId);
- layers[ixMapLayer].tiles[x][y] = tileID;
- usedTileIDs.add(tileID);
+ MapSection defaultLayout = transformMapSection(map,
+ tileCache,
+ new CoordRect(new Coord(0,0), mapSize),
+ layersPerLayerName,
+ usedTileIDs,
+ defaultLayerNames);
+
+ ArrayList replaceableSections = new ArrayList();
+ for (TMXObjectGroup objectGroup : map.objectGroups) {
+ for(TMXObject obj : objectGroup.objects) {
+ if ("replace".equals(obj.type)) {
+ final CoordRect position = getTMXObjectPosition(obj, map);
+ SetOfLayerNames layerNames = new SetOfLayerNames();
+ for (TMXProperty prop : obj.properties) {
+ if (prop.name.equalsIgnoreCase(LAYERNAME_GROUND)) layerNames.groundLayerName = prop.value;
+ else if (prop.name.equalsIgnoreCase(LAYERNAME_OBJECTS)) layerNames.objectsLayerName = prop.value;
+ else if (prop.name.equalsIgnoreCase(LAYERNAME_ABOVE)) layerNames.aboveLayersName = prop.value;
+ else if (prop.name.equalsIgnoreCase(LAYERNAME_WALKABLE)) layerNames.walkableLayersName = prop.value;
+ else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + map.name + " contains replace area with unknown property \"" + prop.name + "\".");
+ }
}
+ MapSection replacementSection = transformMapSection(map, tileCache, position, layersPerLayerName, usedTileIDs, layerNames);
+ QuestProgress requireQuestStage = QuestProgress.parseQuestProgress(obj.name);
+ if (requireQuestStage == null) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + map.name + " contains replace area that cannot be parsed as a quest stage.");
+ }
+ continue;
+ }
+ replaceableSections.add(new ReplaceableMapSection(position, replacementSection, requireQuestStage));
}
}
}
- return new LayeredTileMap(mapSize, layers, isWalkable, usedTileIDs, colorFilter);
+
+ ReplaceableMapSection[] replaceableSections_ = null;
+ if (!replaceableSections.isEmpty()) {
+ replaceableSections_ = replaceableSections.toArray(new ReplaceableMapSection[replaceableSections.size()]);
+ }
+ return new LayeredTileMap(mapSize, defaultLayout, replaceableSections_, colorFilter, usedTileIDs);
}
-
+
+ private static MapSection transformMapSection(
+ TMXLayerMap srcMap,
+ TileCache tileCache,
+ CoordRect area,
+ HashMap layersPerLayerName,
+ HashSet 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);
+ boolean[][] isWalkable = transformWalkableMapLayer(findLayer(layersPerLayerName, layerNames.walkableLayersName, srcMap.name), area);
+ byte[] layoutHash = calculateLayoutHash(srcMap, layersPerLayerName, layerNames);
+ return new MapSection(layerGround, layerObjects, layerAbove, isWalkable, layoutHash);
+ }
+
+ private static TMXLayer findLayer(HashMap layersPerLayerName, String layerName, String mapName) {
+ if (layerName == null) return null;
+ if (layerName.length() == 0) return null;
+ TMXLayer result = layersPerLayerName.get(layerName);
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ if (result == null) {
+ L.log("WARNING: Cannot find maplayer \"" + layerName + "\" requested by map \"" + mapName + "\".");
+ }
+ }
+ return result;
+ }
+
+ private static MapLayer transformMapLayer(
+ HashMap layersPerLayerName,
+ String layerName,
+ TMXLayerMap srcMap,
+ TileCache tileCache,
+ CoordRect area,
+ HashSet usedTileIDs
+ ) {
+ TMXLayer srcLayer = findLayer(layersPerLayerName, layerName, srcMap.name);
+ if (srcLayer == null) return null;
+ final MapLayer result = new MapLayer(area.size);
+ Tile tile = new Tile();
+ for (int dy = 0, sy = area.topLeft.y; dy < area.size.height; ++dy, ++sy) {
+ for (int dx = 0, sx = area.topLeft.x; dx < area.size.width; ++dx, ++sx) {
+ int gid = srcLayer.gids[sx][sy];
+ if (gid <= 0) continue;
+
+ if (!getTile(srcMap, gid, tile)) continue;
+
+ int tileID = tileCache.getTileID(tile.tilesetName, tile.localId);
+ result.tiles[dx][dy] = tileID;
+ usedTileIDs.add(tileID);
+ }
+ }
+ return result;
+ }
+
+ private static boolean[][] transformWalkableMapLayer(TMXLayer srcLayer, CoordRect area) {
+ if (srcLayer == null) return null;
+ final boolean[][] isWalkable = new boolean[area.size.width][area.size.height];
+ for (int x = 0; x < area.size.width; ++x) {
+ Arrays.fill(isWalkable[x], true);
+ }
+ for (int dy = 0, sy = area.topLeft.y; dy < area.size.height; ++dy, ++sy) {
+ for (int dx = 0, sx = area.topLeft.x; dx < area.size.width; ++dx, ++sx) {
+ int gid = srcLayer.gids[sx][sy];
+ if (gid > 0) {
+ isWalkable[dx][dy] = false;
+ }
+ }
+ }
+ return isWalkable;
+ }
+
+ private static byte[] calculateLayoutHash(TMXLayerMap map, HashMap layersPerLayerName, SetOfLayerNames layerNames) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ digestLayer(layersPerLayerName, layerNames.groundLayerName, map, digest);
+ digestLayer(layersPerLayerName, layerNames.objectsLayerName, map, digest);
+ digestLayer(layersPerLayerName, layerNames.aboveLayersName, map, digest);
+ return digest.digest();
+ } catch (NoSuchAlgorithmException e) {
+ L.log("ERROR: Failed to create layout hash for map " + map.name + " : " + e.toString());
+ }
+ return new byte[0];
+ }
+
+ private static void digestLayer(HashMap layersPerLayerName, String layerName, TMXLayerMap map, MessageDigest digest) {
+ TMXLayer srcLayer = findLayer(layersPerLayerName, layerName, map.name);
+ if (srcLayer == null) return;
+ if (srcLayer.layoutHash == null) return;
+ digest.update(srcLayer.layoutHash);
+ }
+
private static boolean getTile(final TMXLayerMap map, final int gid, final Tile dest) {
for(int i = map.tileSets.length - 1; i >= 0; --i) {
TMXTileSet ts = map.tileSets[i];
@@ -232,7 +339,7 @@ public final class TMXMapTranslator {
return true;
}
}
- L.log("WARNING: Cannot find tile for gid " + gid); //(" + x + ", " + y + "), ")
+ L.log("WARNING: Cannot find tile for gid " + gid);
return false;
}
@@ -240,73 +347,23 @@ public final class TMXMapTranslator {
public String tilesetName;
public int localId;
}
-
- /*
- public static final class TMXMap extends TMXLayerMap {
- public int xmlResourceId;
- public String name;
- public String orientation;
- public int tilewidth;
- public int tileheight;
- public ArrayList objectGroups = new ArrayList();
- }
- public static class TMXLayerMap {
- public int width;
- public int height;
- public TMXTileSet[] tileSets;
- public TMXLayer[] layers;
- }
- public static final class TMXTileSet {
- public int firstgid;
- public String name;
- public int tilewidth;
- public int tileheight;
- public String imageSource;
- public String imageName;
- }
- public static final class TMXLayer {
- public String name;
- public int width;
- public int height;
- public int[][] gids;
- }
- public static final class TMXObjectGroup {
- public String name;
- public int width;
- public int height;
- public ArrayList objects = new ArrayList();
- }
- public static final class TMXObject {
- public String name;
- public String type;
- public int x;
- public int y;
- public int width;
- public int height;
- public ArrayList properties = new ArrayList();
- }
- public static final class TMXProperty {
- public String name;
- public String value;
- }
- */
- /*
-
-
- */
+ private static final class SetOfLayerNames {
+ public String groundLayerName;
+ public String objectsLayerName;
+ public String aboveLayersName;
+ public String walkableLayersName;
+ public SetOfLayerNames() {
+ this.groundLayerName = null;
+ this.objectsLayerName = null;
+ this.aboveLayersName = null;
+ this.walkableLayersName = null;
+ }
+ public SetOfLayerNames(String groundLayerName, String objectsLayerName, String aboveLayersName, String walkableLayersName) {
+ this.groundLayerName = groundLayerName;
+ this.objectsLayerName = objectsLayerName;
+ this.aboveLayersName = aboveLayersName;
+ this.walkableLayersName = walkableLayersName;
+ }
+ }
}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ByteUtils.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ByteUtils.java
new file mode 100644
index 000000000..b3db4f716
--- /dev/null
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/util/ByteUtils.java
@@ -0,0 +1,16 @@
+package com.gpl.rpg.AndorsTrail.util;
+
+public final class ByteUtils {
+ public static String toHexString(byte[] bytes) { return toHexString(bytes, bytes.length); }
+ public static String toHexString(byte[] bytes, int numBytes) {
+ if (bytes == null) return "";
+ if (bytes.length == 0) return "";
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < Math.min(numBytes, bytes.length); i++) {
+ String h = Integer.toHexString(0xFF & bytes[i]);
+ if (h.length() < 2) result.append('0');
+ result.append(h);
+ }
+ return result.toString();
+ }
+}
diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
index 61e7e517b..5059e1517 100644
--- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
+++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java
@@ -38,7 +38,7 @@ public final class MainView extends SurfaceView
CombatSelectionListener,
MonsterSpawnListener,
MonsterMovementListener,
- LootBagListener,
+ MapLayoutListener,
VisualEffectFrameListener,
GameRoundListener {
@@ -276,8 +276,8 @@ public final class MainView extends SurfaceView
private void doDrawRect(Canvas canvas, CoordRect area) {
- drawMapLayer(canvas, area, currentTileMap.layers[LayeredTileMap.LAYER_GROUND]);
- tryDrawMapLayer(canvas, area, LayeredTileMap.LAYER_OBJECTS);
+ drawMapLayer(canvas, area, currentTileMap.currentLayout.layerGround);
+ tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerObjects);
for (BloodSplatter splatter : currentMap.splatters) {
drawFromMapPosition(canvas, area, splatter.position, splatter.iconID);
@@ -296,7 +296,7 @@ public final class MainView extends SurfaceView
}
}
- tryDrawMapLayer(canvas, area, LayeredTileMap.LAYER_ABOVE);
+ tryDrawMapLayer(canvas, area, currentTileMap.currentLayout.layerAbove);
if (model.uiSelections.selectedPosition != null) {
if (model.uiSelections.selectedMonster != null) {
@@ -307,8 +307,8 @@ public final class MainView extends SurfaceView
}
}
- private void tryDrawMapLayer(Canvas canvas, final CoordRect area, final int layerIndex) {
- if (currentTileMap.layers.length > layerIndex) drawMapLayer(canvas, area, currentTileMap.layers[layerIndex]);
+ 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) {
@@ -401,7 +401,7 @@ public final class MainView extends SurfaceView
public void subscribe() {
controllers.gameRoundController.gameRoundListeners.add(this);
controllers.effectController.visualEffectFrameListeners.add(this);
- controllers.itemController.lootBagListeners.add(this);
+ controllers.mapController.mapLayoutListeners.add(this);
controllers.movementController.playerMovementListeners.add(this);
controllers.combatController.combatSelectionListeners.add(this);
controllers.monsterSpawnController.monsterSpawnListeners.add(this);
@@ -412,7 +412,7 @@ public final class MainView extends SurfaceView
controllers.monsterSpawnController.monsterSpawnListeners.remove(this);
controllers.combatController.combatSelectionListeners.remove(this);
controllers.movementController.playerMovementListeners.remove(this);
- controllers.itemController.lootBagListeners.remove(this);
+ controllers.mapController.mapLayoutListeners.remove(this);
controllers.effectController.visualEffectFrameListeners.remove(this);
controllers.gameRoundController.gameRoundListeners.remove(this);
}
@@ -494,6 +494,12 @@ public final class MainView extends SurfaceView
redrawTile(p, REDRAW_TILE_BAG);
}
+ @Override
+ public void onMapTilesChanged(PredefinedMap map, LayeredTileMap tileMap) {
+ if (map != currentMap) return;
+ redrawAll(REDRAW_ALL_MAP_CHANGED);
+ }
+
@Override
public void onNewAnimationFrame(VisualEffectAnimation animation, int tileID, int textYOffset) {
redrawAreaWithEffect(animation, tileID, textYOffset);