Slight performance improvement to TMX file reader.

Added Android application description.
Conversation correction to Buceth.
Tweaked droplists that contains potions.

git-svn-id: https://andors-trail.googlecode.com/svn/trunk@176 08aca716-68be-ccc6-4d58-36f5abd142ac
This commit is contained in:
oskar.wiksten
2011-10-10 20:48:48 +00:00
parent af48a1cdf0
commit 6af1b95e89
8 changed files with 361 additions and 262 deletions

View File

@@ -24,6 +24,7 @@
android:name=".AndorsTrailApplication"
android:label="@string/app_name"
android:icon="@drawable/icon"
android:description="@string/app_description"
>
<activity
android:name=".activity.MainActivity"

View File

@@ -2901,7 +2901,7 @@
{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||||}}|};

View File

@@ -21,11 +21,11 @@
<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|}}|};
@@ -35,7 +35,7 @@
[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|}}|};
@@ -143,7 +143,7 @@
{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|{
@@ -156,7 +156,7 @@
{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|{
@@ -191,13 +191,13 @@
{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|}
@@ -211,7 +211,7 @@
{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|{
@@ -423,7 +423,7 @@
{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|}

View File

@@ -2,6 +2,7 @@
<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>

View File

@@ -12,7 +12,7 @@ import com.gpl.rpg.AndorsTrail.model.item.Loot;
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;
@@ -242,7 +242,7 @@ public final class MovementController implements TimedMessageTask.Callback {
}
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;

View File

@@ -3,42 +3,34 @@ package com.gpl.rpg.AndorsTrail.model.map;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.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 void read(Resources r, int xmlResourceId, String name) {
read(r.getXml(xmlResourceId), xmlResourceId, name);
public final class TMXMapFileParser {
public static TMXMap read(Resources r, int xmlResourceId, String name) {
return read(r.getXml(xmlResourceId), xmlResourceId, name);
}
private TMXMap read(XmlResourceParser xrp, int xmlResourceId, String name) {
public static TMXLayerMap readLayeredTileMap(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();
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();
@@ -52,11 +44,11 @@ public final class TMXMapReader {
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));
}
}
});
@@ -64,19 +56,23 @@ public final class TMXMapReader {
}
}
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();
@@ -86,9 +82,9 @@ public final class TMXMapReader {
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));
}
}
});
@@ -96,11 +92,14 @@ public final class TMXMapReader {
}
}
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;
}
@@ -258,227 +257,6 @@ public final class TMXMapReader {
(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;
@@ -490,8 +268,8 @@ public final class TMXMapReader {
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;

View File

@@ -0,0 +1,319 @@
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>
*/
}

View File

@@ -3,7 +3,7 @@ package com.gpl.rpg.AndorsTrail.resource;
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;
@@ -135,7 +135,7 @@ public final class ResourceLoader {
// ========================================================================
// 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);