android:name=".AndorsTrailApplication"
android:label="@string/app_name"
android:icon="@drawable/icon"
+ android:description="@string/app_description"
>
<activity
android:name=".activity.MainActivity"
{Here\'s 2000 gold, take it.|buceth_gold_yes||gold|2000|}
}|};
{buceth_gold_no|Hrmpf. Thanks for the gold, but I am not interested in talking to you. Now, please leave.||||};
-{buceth_gold_yes|You seem to realize the true value of the Shadow. Yes, this will do fine, thank you.|loneford:41||{{N|buceth_bribed_1||||}}|};
+{buceth_gold_yes|You seem to realize the true value of the Shadow. Yes, this will do fine, thank you.|loneford:41||{{N|buceth_story_1||||}}|};
{buceth_5|Let\'s assume you live in a village that, for the most part, keeps to itself. Your village is self-sustainable and the crops have been good for some years.|||{{N|buceth_6||||}}|};
{buceth_6|With the few exceptions of a some fights here and there between villagers because of misunderstandings, on the whole, your village is a friendly peaceful village.|||{{N|buceth_7||||}}|};
{buceth_7|You work in the same profession as your parents, which in turn worked in the same professions as their parents.|||{{N|buceth_8||||}}|};
<string name="droplists_crossglen_outside">
[id|items[itemID|quantity_Min|quantity_Max|chance|]|];
-{cavemonster|{{gold|4|12|70|}{gem2|1|1|25|}{hammer0|1|1|5|}{health_minor2|1|1|25|}}|};
+{cavemonster|{{gold|4|12|70|}{gem2|1|1|25|}{hammer0|1|1|5|}{health_minor|1|1|25|}}|};
{snake|{{gold|3|6|70|}{meat|1|1|30|}{gland|1|1|5|}}|};
{haunt|{{vial_empty1|1|1|25|}{gem1|1|1|25|}}|};
{cavecritter|{{gold|4|8|70|}{gem1|1|1|25|}{claws|1|1|30|}}|};
-{lich1|{{gold|5|15|70|}{gem2|1|1|25|}{health_minor2|1|1|25|}}|};
+{lich1|{{gold|5|15|70|}{gem2|1|1|25|}{health_minor|1|1|25|}}|};
{irogotu|{{neck_irogotu|1|1|100|}{ring_gandir|1|1|100|}{health|1|1|100|}}|};
{canineboss|{{gold|7|10|70|}{hair|1|1|30|}{gem1|1|1|25|}{meat|1|1|30|}{boots1|1|1|25|}}|};
{snakemaster|{{gold|9|9|70|}{dagger_venom|1|1|100|}{gem3|1|1|100|}{health|1|1|100|}}|};
[id|items[itemID|quantity_Min|quantity_Max|chance|]|];
{catacombrat|{{gold|1|5|70|}{gem1|1|1|25|}{vial_empty1|1|1|25|}}|};
{skeleton|{{gold|16|23|70|}{gem2|1|1|25|}{health|1|1|25|}{bone|1|1|30|}}|};
-{luthor|{{gold|1|5|70|}{gem1|1|1|100|}{key_luthor|1|1|100|}{health_major2|1|1|100|}}|};
+{luthor|{{gold|1|5|70|}{gem1|1|1|100|}{key_luthor|1|1|100|}{health_major|1|1|100|}}|};
{shop_thoronir|{{bonemeal_potion|10|10|100|}}|};
{larcal|{{gold|4|12|70|}{club1|1|1|100|}{calomyran_secrets|1|1|100|}{milk|1|1|100|}}|};
{catacombguard|{{gold|4|12|70|}{gem2|1|1|25|}{health|1|1|25|}{vial_empty2|1|1|25|}{gloves1|1|1|5|}}|};
{kazaul_1|{
{gold|3|19|70|}
{gem4|1|1|10|}
- {health_minor2|1|1|10|}
+ {health_minor|1|1|10|}
{rock|1|1|5|}
}|};
{kazaul_2|{
{restless_dead_1|{
{gold|20|29|70|}
{gem3|1|1|10|}
- {health_minor2|1|1|10|}
+ {health_minor|1|1|10|}
{bone|1|1|10|}
}|};
{restless_dead_2|{
{gold|1|30|70|}
{bone|1|1|10|}
{vial_empty1|1|1|25|}
- {health_minor2|1|1|10|}
+ {health_minor|1|1|10|}
}|};
{wyrm_2|{
{gold|1|40|70|}
{bone|1|1|10|}
{vial_empty1|1|1|25|}
- {health_minor2|1|2|10|}
+ {health_minor|1|2|10|}
}|};
{wyrm_3|{
{gold|1|60|70|}
{bone|1|2|10|}
{vial_empty1|1|1|25|}
{pot_poison_weak|1|3|5|}
- {health_minor2|1|2|10|}
+ {health_minor|1|2|10|}
{elytharan_redeemer|1|1|1/10000|}
}|};
{aulaeth|{
{ring_villain|1|1|100|}
}|};
{shop_tharal|{
- {health_minor|10|10|100|}
+ {health_minor2|10|10|100|}
{health|10|10|100|}
{health_major2|10|10|100|}
{necklace_shield_0|1|1|100|}
<resources>
<string name="app_name">Andor\'s Trail</string>
+ <string name="app_description">Quest-driven fantasy RPG</string>
<string name="exit">Exit</string>
<string name="exit_to_menu">Exit to menu</string>
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
-import com.gpl.rpg.AndorsTrail.model.map.TMXMapReader;
+import com.gpl.rpg.AndorsTrail.model.map.TMXMapTranslator;
import com.gpl.rpg.AndorsTrail.util.Coord;
import com.gpl.rpg.AndorsTrail.util.L;
import com.gpl.rpg.AndorsTrail.util.TimedMessageTask;
}
public static void loadCurrentTileMap(Resources res, WorldContext world) {
- world.model.currentTileMap = TMXMapReader.readLayeredTileMap(res, world.tileStore, world.model.currentMap);
+ world.model.currentTileMap = TMXMapTranslator.readLayeredTileMap(res, world.tileStore, world.model.currentMap);
}
private int movementDx;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import org.xmlpull.v1.XmlPullParserException;
-import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
-import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
-import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
-import com.gpl.rpg.AndorsTrail.model.item.DropList;
-import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
-import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
-import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
-import com.gpl.rpg.AndorsTrail.resource.TileStore;
import com.gpl.rpg.AndorsTrail.util.Base64;
-import com.gpl.rpg.AndorsTrail.util.Coord;
-import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.L;
-import com.gpl.rpg.AndorsTrail.util.Range;
-import com.gpl.rpg.AndorsTrail.util.Size;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-public final class TMXMapReader {
- private ArrayList<TMXMap> maps = new ArrayList<TMXMap>();
+public final class TMXMapFileParser {
+ public static TMXMap read(Resources r, int xmlResourceId, String name) {
+ return read(r.getXml(xmlResourceId), xmlResourceId, name);
+ }
- public void read(Resources r, int xmlResourceId, String name) {
- read(r.getXml(xmlResourceId), xmlResourceId, name);
+ public static TMXLayerMap readLayeredTileMap(Resources r, int xmlResourceId, String name) {
+ return readLayerMap(r.getXml(xmlResourceId), name);
}
- private TMXMap read(XmlResourceParser xrp, int xmlResourceId, String name) {
+
+ private static TMXMap read(XmlResourceParser xrp, int xmlResourceId, String name) {
final TMXMap map = new TMXMap();
map.xmlResourceId = xmlResourceId;
try {
// Map format: http://sourceforge.net/apps/mediawiki/tiled/index.php?title=Examining_the_map_format
int eventType;
+ final ArrayList<TMXLayer> layers = new ArrayList<TMXLayer>();
+ final ArrayList<TMXTileSet> tileSets = new ArrayList<TMXTileSet>();
while ((eventType = xrp.next()) != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) {
String s = xrp.getName();
readCurrentTagUntilEnd(xrp, new TagHandler() {
public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
if (tagName.equals("tileset")) {
- map.tileSets.add(readTMXTileSet(xrp));
+ tileSets.add(readTMXTileSet(xrp));
} else if (tagName.equals("objectgroup")) {
map.objectGroups.add(readTMXObjectGroup(xrp));
} else if (tagName.equals("layer")) {
- map.layers.add(readTMXMapLayer(xrp));
+ layers.add(readTMXMapLayer(xrp));
}
}
});
}
}
xrp.close();
+ map.layers = layers.toArray(new TMXLayer[layers.size()]);
+ map.tileSets = tileSets.toArray(new TMXTileSet[tileSets.size()]);
} catch (XmlPullParserException e) {
L.log("Error reading map \"" + name + "\": XmlPullParserException : " + e.toString());
} catch (IOException e) {
L.log("Error reading map \"" + name + "\": IOException : " + e.toString());
}
- maps.add(map);
return map;
}
- private static void readLayerMap(XmlResourceParser xrp, final String name, final TMXLayerMap map) {
+ private static TMXLayerMap readLayerMap(XmlResourceParser xrp, final String name) {
+ TMXLayerMap map = new TMXLayerMap();
try {
int eventType;
+ final ArrayList<TMXLayer> layers = new ArrayList<TMXLayer>();
+ final ArrayList<TMXTileSet> tileSets = new ArrayList<TMXTileSet>();
while ((eventType = xrp.next()) != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) {
String s = xrp.getName();
readCurrentTagUntilEnd(xrp, new TagHandler() {
public void handleTag(XmlResourceParser xrp, String tagName) throws XmlPullParserException, IOException {
if (tagName.equals("tileset")) {
- map.tileSets.add(readTMXTileSet(xrp));
+ tileSets.add(readTMXTileSet(xrp));
} else if (tagName.equals("layer")) {
- map.layers.add(readTMXMapLayer(xrp));
+ layers.add(readTMXMapLayer(xrp));
}
}
});
}
}
xrp.close();
+ map.layers = layers.toArray(new TMXLayer[layers.size()]);
+ map.tileSets = tileSets.toArray(new TMXTileSet[tileSets.size()]);
} catch (XmlPullParserException e) {
L.log("Error reading layered map \"" + name + "\": XmlPullParserException : " + e.toString());
} catch (IOException e) {
L.log("Error reading layered map \"" + name + "\": IOException : " + e.toString());
}
+ return map;
}
(buffer[offset + 3] << 24) & 0xff000000;
}
- public ArrayList<PredefinedMap> transformMaps(DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
- return transformMaps(maps, tileLoader, monsterTypes, dropLists);
- }
- public ArrayList<PredefinedMap> transformMaps(Collection<TMXMap> maps, DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
- ArrayList<PredefinedMap> result = new ArrayList<PredefinedMap>();
-
- for (TMXMap m : maps) {
- assert(m.name != null);
- assert(m.name.length() > 0);
- assert(m.width > 0);
- assert(m.height > 0);
-
- boolean[][] isWalkable = new boolean[m.width][m.height];
- for (int y = 0; y < m.height; ++y) {
- for (int x = 0; x < m.width; ++x) {
- isWalkable[x][y] = true;
- }
- }
- final Size mapSize = new Size(m.width, m.height);
- for (TMXLayer layer : m.layers) {
- String layerName = layer.name;
- assert(layerName != null);
- assert(layerName.length() > 0);
- layerName = layerName.toLowerCase();
-
- 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 (layerName.startsWith("walk")) {
- isWalkable[x][y] = false;
- } else {
- Pair<String, Integer> p = getTile(m, gid);
- if (p == null) continue;
-
- String tilesetName = (String) p.first;
- int localId = (Integer) p.second;
- tileLoader.prepareTileID(tilesetName, localId);
- }
- }
- }
- }
-
- ArrayList<MapObject> mapObjects = new ArrayList<MapObject>();
- ArrayList<MonsterSpawnArea> spawnAreas = new ArrayList<MonsterSpawnArea>();
-
- for (TMXObjectGroup group : m.objectGroups) {
- for (TMXObject object : group.objects) {
- final Coord topLeft = new Coord(
- Math.round(((float)object.x) / m.tilewidth)
- ,Math.round(((float)object.y) / m.tileheight)
- );
- final int width = Math.round(((float)object.width) / m.tilewidth);
- final int height = Math.round(((float)object.height) / m.tileheight);
- final CoordRect position = new CoordRect(topLeft, new Size(width, height));
-
- if (object.type == null) {
- if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA)
- L.log("WARNING: Map " + m.name + ", object \"" + object.name + "\" has null type.");
- } else if (object.type.equalsIgnoreCase("sign")) {
- String phraseID = object.name;
- for (TMXProperty p : object.properties) {
- if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", sign " + object.name + " has unrecognized property \"" + p.name + "\".");
- }
- mapObjects.add(MapObject.createMapSignEvent(position, phraseID));
- } else if (object.type.equalsIgnoreCase("mapchange")) {
- String map = null;
- String place = null;
- for (TMXProperty p : object.properties) {
- if(p.name.equalsIgnoreCase("map")) map = p.value;
- else if(p.name.equalsIgnoreCase("place")) place = p.value;
- else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", mapchange " + object.name + " has unrecognized property \"" + p.name + "\".");
- }
- mapObjects.add(MapObject.createNewMapEvent(position, object.name, map, place));
- } else if (object.type.equalsIgnoreCase("spawn")) {
- ArrayList<MonsterType> types = monsterTypes.getMonsterTypesFromSpawnGroup(object.name);
- int maxQuantity = 1;
- int spawnChance = 10;
- boolean isUnique = false;
- for (TMXProperty p : object.properties) {
- if (p.name.equalsIgnoreCase("quantity")) {
- maxQuantity = Integer.parseInt(p.value);
- } else if (p.name.equalsIgnoreCase("spawnchance")) {
- spawnChance = Integer.parseInt(p.value);
- } else if (p.name.equalsIgnoreCase("respawn")) {
- isUnique = !Boolean.parseBoolean(p.value);
- } else if (p.name.equalsIgnoreCase("unique")) {
- isUnique = Boolean.parseBoolean(p.value);
- } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
- L.log("OPTIMIZE: Map " + m.name + ", spawn " + object.name + " has unrecognized property \"" + p.name + "\".");
- }
- }
-
- if (types.isEmpty()) {
- if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
- L.log("OPTIMIZE: Map " + m.name + " contains spawn \"" + object.name + "\" that does not correspond to any monsters. The spawn will be removed.");
- }
- continue;
- }
-
- String[] monsterTypeIDs = new String[types.size()];
- for (int i = 0; i < monsterTypeIDs.length; ++i) {
- monsterTypeIDs[i] = types.get(i).id;
- if (isUnique) types.get(i).isRespawnable = false;
- }
- MonsterSpawnArea area = new MonsterSpawnArea(
- position
- ,new Range(maxQuantity, 0)
- ,new Range(1000, spawnChance)
- ,monsterTypeIDs
- ,isUnique
- );
- spawnAreas.add(area);
- } else if (object.type.equalsIgnoreCase("key")) {
- QuestProgress requireQuestStage = QuestProgress.parseQuestProgress(object.name);
- if (requireQuestStage == null) {
- if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
- L.log("OPTIMIZE: Map " + m.name + " contains key area that cannot be parsed as a quest stage.");
- }
- continue;
- }
- String phraseID = "";
- for (TMXProperty p : object.properties) {
- if (p.name.equalsIgnoreCase("phrase")) {
- phraseID = p.value;
- } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
- L.log("OPTIMIZE: Map " + m.name + ", key " + object.name + " has unrecognized property \"" + p.name + "\".");
- }
- }
-
- mapObjects.add(MapObject.createNewKeyArea(position, phraseID, requireQuestStage));
- } else if (object.type.equals("rest")) {
- mapObjects.add(MapObject.createNewRest(position, object.name));
- } else if (object.type.equals("container")) {
- DropList dropList = dropLists.getDropList(object.name);
- if (dropList == null) continue;
- mapObjects.add(MapObject.createNewContainerArea(position, dropList));
- } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
- L.log("OPTIMIZE: Map " + m.name + ", has unrecognized object type \"" + object.type + "\" for name \"" + object.name + "\".");
- }
- }
- }
- MapObject[] _eventObjects = new MapObject[mapObjects.size()];
- _eventObjects = mapObjects.toArray(_eventObjects);
- MonsterSpawnArea[] _spawnAreas = new MonsterSpawnArea[spawnAreas.size()];
- _spawnAreas = spawnAreas.toArray(_spawnAreas);
-
- result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, isWalkable, _eventObjects, _spawnAreas, false));
- }
-
- return result;
- }
-
-
- private static LayeredTileMap transformMap(TMXLayerMap map, TileStore tileStore) {
- final Size mapSize = new Size(map.width, map.height);
- final MapLayer[] layers = new MapLayer[] {
- new MapLayer(mapSize)
- ,new MapLayer(mapSize)
- ,new MapLayer(mapSize)
- };
- for (TMXLayer layer : map.layers) {
- int ixMapLayer = -2;
- String layerName = layer.name;
- assert(layerName != null);
- assert(layerName.length() > 0);
- layerName = layerName.toLowerCase();
- 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 {
- continue;
- }
-
- for (int y = 0; y < layer.height; ++y) {
- for (int x = 0; x < layer.width; ++x) {
- int gid = layer.gids[x][y];
- if (gid <= 0) continue;
-
- Pair<String, Integer> p = getTile(map, gid);
- if (p == null) continue;
-
- String tilesetName = (String) p.first;
- int localId = (Integer) p.second;
- layers[ixMapLayer].tiles[x][y] = tileStore.getTileID(tilesetName, localId);
- }
- }
- }
- return new LayeredTileMap(mapSize, layers);
- }
-
- public static LayeredTileMap readLayeredTileMap(Resources res, TileStore tileStore, PredefinedMap map) {
- TMXLayerMap result = new TMXLayerMap();
- readLayerMap(res.getXml(map.xmlResourceId), map.name, result);
- return transformMap(result, tileStore);
- }
-
- private static Pair<String, Integer> getTile(final TMXLayerMap map, final int gid) {
- for(int i = map.tileSets.size() - 1; i >= 0; --i) {
- TMXTileSet ts = map.tileSets.get(i);
- if (ts.firstgid <= gid) {
- return new Pair<String, Integer>(ts.imageName, (gid - ts.firstgid));
- }
- }
- L.log("WARNING: Cannot find tile for gid " + gid); //(" + x + ", " + y + "), ")
- return null;
- }
-
- private static final class Pair<T1, T2> {
- public final T1 first;
- public final T2 second;
- public Pair(T1 first, T2 second) {
- this.first = first;
- this.second = second;
- }
- }
-
public static final class TMXMap extends TMXLayerMap {
public int xmlResourceId;
public String name;
public static class TMXLayerMap {
public int width;
public int height;
- public ArrayList<TMXTileSet> tileSets = new ArrayList<TMXTileSet>();
- public ArrayList<TMXLayer> layers = new ArrayList<TMXLayer>();
+ public TMXTileSet[] tileSets;
+ public TMXLayer[] layers;
}
public static final class TMXTileSet {
public int firstgid;
--- /dev/null
+package com.gpl.rpg.AndorsTrail.model.map;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
+import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
+import com.gpl.rpg.AndorsTrail.model.item.DropList;
+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.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.TileStore;
+import com.gpl.rpg.AndorsTrail.util.Coord;
+import com.gpl.rpg.AndorsTrail.util.CoordRect;
+import com.gpl.rpg.AndorsTrail.util.L;
+import com.gpl.rpg.AndorsTrail.util.Range;
+import com.gpl.rpg.AndorsTrail.util.Size;
+
+import android.content.res.Resources;
+
+public final class TMXMapTranslator {
+ private ArrayList<TMXMap> maps = new ArrayList<TMXMap>();
+
+ public void read(Resources r, int xmlResourceId, String name) {
+ maps.add(TMXMapFileParser.read(r, xmlResourceId, name));
+ }
+
+ public static LayeredTileMap readLayeredTileMap(Resources res, TileStore tileStore, PredefinedMap map) {
+ TMXLayerMap resultMap = TMXMapFileParser.readLayeredTileMap(res, map.xmlResourceId, map.name);
+ return transformMap(resultMap, tileStore);
+ }
+
+ public ArrayList<PredefinedMap> transformMaps(DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
+ return transformMaps(maps, tileLoader, monsterTypes, dropLists);
+ }
+ public ArrayList<PredefinedMap> transformMaps(Collection<TMXMap> maps, DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes, DropListCollection dropLists) {
+ ArrayList<PredefinedMap> result = new ArrayList<PredefinedMap>();
+
+ Tile tile = new Tile();
+ for (TMXMap m : maps) {
+ assert(m.name != null);
+ assert(m.name.length() > 0);
+ assert(m.width > 0);
+ assert(m.height > 0);
+
+ boolean[][] isWalkable = new boolean[m.width][m.height];
+ for (int y = 0; y < m.height; ++y) {
+ for (int x = 0; x < m.width; ++x) {
+ isWalkable[x][y] = true;
+ }
+ }
+ final Size mapSize = new Size(m.width, m.height);
+ for (TMXLayer layer : m.layers) {
+ String layerName = layer.name;
+ assert(layerName != null);
+ assert(layerName.length() > 0);
+ layerName = layerName.toLowerCase();
+
+ boolean isWalkableLayer = layerName.startsWith("walk");
+
+ 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 (isWalkableLayer) {
+ isWalkable[x][y] = false;
+ } else {
+ if (!getTile(m, gid, tile)) continue;
+ tileLoader.prepareTileID(tile.tilesetName, tile.localId);
+ }
+ }
+ }
+ }
+
+ ArrayList<MapObject> mapObjects = new ArrayList<MapObject>();
+ ArrayList<MonsterSpawnArea> spawnAreas = new ArrayList<MonsterSpawnArea>();
+
+ for (TMXObjectGroup group : m.objectGroups) {
+ for (TMXObject object : group.objects) {
+ final Coord topLeft = new Coord(
+ Math.round(((float)object.x) / m.tilewidth)
+ ,Math.round(((float)object.y) / m.tileheight)
+ );
+ final int width = Math.round(((float)object.width) / m.tilewidth);
+ final int height = Math.round(((float)object.height) / m.tileheight);
+ final CoordRect position = new CoordRect(topLeft, new Size(width, height));
+
+ if (object.type == null) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA)
+ L.log("WARNING: Map " + m.name + ", object \"" + object.name + "\" has null type.");
+ } else if (object.type.equalsIgnoreCase("sign")) {
+ String phraseID = object.name;
+ for (TMXProperty p : object.properties) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", sign " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ mapObjects.add(MapObject.createMapSignEvent(position, phraseID));
+ } else if (object.type.equalsIgnoreCase("mapchange")) {
+ String map = null;
+ String place = null;
+ for (TMXProperty p : object.properties) {
+ if(p.name.equalsIgnoreCase("map")) map = p.value;
+ else if(p.name.equalsIgnoreCase("place")) place = p.value;
+ else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", mapchange " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ mapObjects.add(MapObject.createNewMapEvent(position, object.name, map, place));
+ } else if (object.type.equalsIgnoreCase("spawn")) {
+ ArrayList<MonsterType> types = monsterTypes.getMonsterTypesFromSpawnGroup(object.name);
+ int maxQuantity = 1;
+ int spawnChance = 10;
+ boolean isUnique = false;
+ for (TMXProperty p : object.properties) {
+ if (p.name.equalsIgnoreCase("quantity")) {
+ maxQuantity = Integer.parseInt(p.value);
+ } else if (p.name.equalsIgnoreCase("spawnchance")) {
+ spawnChance = Integer.parseInt(p.value);
+ } else if (p.name.equalsIgnoreCase("respawn")) {
+ isUnique = !Boolean.parseBoolean(p.value);
+ } else if (p.name.equalsIgnoreCase("unique")) {
+ isUnique = Boolean.parseBoolean(p.value);
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", spawn " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ }
+
+ if (types.isEmpty()) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + " contains spawn \"" + object.name + "\" that does not correspond to any monsters. The spawn will be removed.");
+ }
+ continue;
+ }
+
+ String[] monsterTypeIDs = new String[types.size()];
+ for (int i = 0; i < monsterTypeIDs.length; ++i) {
+ monsterTypeIDs[i] = types.get(i).id;
+ if (isUnique) types.get(i).isRespawnable = false;
+ }
+ MonsterSpawnArea area = new MonsterSpawnArea(
+ position
+ ,new Range(maxQuantity, 0)
+ ,new Range(1000, spawnChance)
+ ,monsterTypeIDs
+ ,isUnique
+ );
+ spawnAreas.add(area);
+ } else if (object.type.equalsIgnoreCase("key")) {
+ QuestProgress requireQuestStage = QuestProgress.parseQuestProgress(object.name);
+ if (requireQuestStage == null) {
+ if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + " contains key area that cannot be parsed as a quest stage.");
+ }
+ continue;
+ }
+ String phraseID = "";
+ for (TMXProperty p : object.properties) {
+ if (p.name.equalsIgnoreCase("phrase")) {
+ phraseID = p.value;
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", key " + object.name + " has unrecognized property \"" + p.name + "\".");
+ }
+ }
+
+ mapObjects.add(MapObject.createNewKeyArea(position, phraseID, requireQuestStage));
+ } else if (object.type.equals("rest")) {
+ mapObjects.add(MapObject.createNewRest(position, object.name));
+ } else if (object.type.equals("container")) {
+ DropList dropList = dropLists.getDropList(object.name);
+ if (dropList == null) continue;
+ mapObjects.add(MapObject.createNewContainerArea(position, dropList));
+ } else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
+ L.log("OPTIMIZE: Map " + m.name + ", has unrecognized object type \"" + object.type + "\" for name \"" + object.name + "\".");
+ }
+ }
+ }
+ MapObject[] _eventObjects = new MapObject[mapObjects.size()];
+ _eventObjects = mapObjects.toArray(_eventObjects);
+ MonsterSpawnArea[] _spawnAreas = new MonsterSpawnArea[spawnAreas.size()];
+ _spawnAreas = spawnAreas.toArray(_spawnAreas);
+
+ result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, isWalkable, _eventObjects, _spawnAreas, false));
+ }
+
+ return result;
+ }
+
+
+ private static LayeredTileMap transformMap(TMXLayerMap map, TileStore tileStore) {
+ final Size mapSize = new Size(map.width, map.height);
+ final MapLayer[] layers = new MapLayer[] {
+ new MapLayer(mapSize)
+ ,new MapLayer(mapSize)
+ ,new MapLayer(mapSize)
+ };
+ Tile tile = new Tile();
+ for (TMXLayer layer : map.layers) {
+ int ixMapLayer = -2;
+ String layerName = layer.name;
+ assert(layerName != null);
+ assert(layerName.length() > 0);
+ layerName = layerName.toLowerCase();
+ 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 {
+ continue;
+ }
+
+ for (int y = 0; y < layer.height; ++y) {
+ for (int x = 0; x < layer.width; ++x) {
+ int gid = layer.gids[x][y];
+ if (gid <= 0) continue;
+
+ if (!getTile(map, gid, tile)) continue;
+
+ layers[ixMapLayer].tiles[x][y] = tileStore.getTileID(tile.tilesetName, tile.localId);
+ }
+ }
+ }
+ return new LayeredTileMap(mapSize, layers);
+ }
+
+ 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];
+ if (ts.firstgid <= gid) {
+ dest.tilesetName = ts.imageName;
+ dest.localId = (gid - ts.firstgid);
+ return true;
+ }
+ }
+ L.log("WARNING: Cannot find tile for gid " + gid); //(" + x + ", " + y + "), ")
+ return false;
+ }
+
+ private static final class Tile {
+ 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<TMXObjectGroup> objectGroups = new ArrayList<TMXObjectGroup>();
+ }
+ 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<TMXObject> objects = new ArrayList<TMXObject>();
+ }
+ 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<TMXProperty> properties = new ArrayList<TMXProperty>();
+ }
+ public static final class TMXProperty {
+ public String name;
+ public String value;
+ }
+ */
+ /*
+
+ <map version="1.0" orientation="orthogonal" width="10" height="10" tilewidth="32" tileheight="32">
+ <tileset firstgid="1" name="tiles" tilewidth="32" tileheight="32">
+ <image source="tilesets/tiles.png"/>
+ </tileset>
+ <layer name="Tile Layer 1" width="10" height="10">
+ <data encoding="base64" compression="gzip">
+ H4sIAAAAAAAAA/NgYGDwIBK7AbEnHkyOOmwYXR02MwZSHQyTah4xGADnAt2SkAEAAA==
+ </data>
+ </layer>
+ <layer name="Tile Layer 2" width="10" height="10">
+ <data encoding="base64" compression="gzip">
+ H4sIAAAAAAAAA2NgoA1gYUHlP2HGro6NBbt4MysqXw2oLhEqlgSlU4H0YjR12EAbUE0KFnXPgG5iRLJ/GQ6zHuNwOy7gxE6aemQAAJRT7VKQAQAA
+ </data>
+ </layer>
+ </map>
+
+ */
+}
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
-import com.gpl.rpg.AndorsTrail.model.map.TMXMapReader;
+import com.gpl.rpg.AndorsTrail.model.map.TMXMapTranslator;
import com.gpl.rpg.AndorsTrail.resource.parsers.ActorConditionsTypeParser;
import com.gpl.rpg.AndorsTrail.resource.parsers.ConversationListParser;
import com.gpl.rpg.AndorsTrail.resource.parsers.DropListParser;
// ========================================================================
// Load maps
- TMXMapReader mapReader = new TMXMapReader();
+ TMXMapTranslator mapReader = new TMXMapTranslator();
final TypedArray mapsToLoad = r.obtainTypedArray(mapsResourceId);
for (int i = 0; i < mapsToLoad.length(); ++i) {
final int mapResourceId = mapsToLoad.getResourceId(i, -1);