This file was deleted.

@@ -99,6 +99,11 @@ public void setZ(int z) {
this.z = z;
}

@Override
public int getPriority() {
return 1;
}

public long getId() {
return id;
}
@@ -34,7 +34,9 @@
import me.scarlet.undertailor.exception.LuaScriptException;
import me.scarlet.undertailor.lua.impl.WorldRoomImplementable;
import me.scarlet.undertailor.manager.ScriptManager;
import me.scarlet.undertailor.overworld.map.RoomMapLayer;
import me.scarlet.undertailor.util.InputRetriever.InputData;
import me.scarlet.undertailor.util.Layerable;
import me.scarlet.undertailor.wrappers.RoomDataWrapper;

import java.util.HashMap;
@@ -111,7 +113,7 @@ public void onCollide(Collider collider) {
try {
ScriptManager scriptMan = Undertailor.getScriptManager();
WorldRoomImplementable impl = scriptMan.getImplementable(WorldRoomImplementable.class);
WorldRoom room = impl.load(targetRoom[0], Undertailor.getRoomManager().getRoom(targetRoom[0]));
WorldRoom room = impl.load(targetRoom[0]);
Undertailor.getOverworldController().setCurrentRoom(room, true, id, entrypoint);
} catch(LuaScriptException e) {
Undertailor.instance.error("overworld", "entrypoint with id " + id + " failed to process room switch: could not load target room " + targetRoom[0]);
@@ -137,15 +139,19 @@ public Vector2 getVelocity() {

}

private static final TreeSet<WorldObject> RETURN_SET;
private static final TreeSet<Layerable> RETURN_SET;
private static final Set<Collider> COLLIDER_SET;
private static final Set<Collider> TARGET_SET;
private static long nextId;

static {
RETURN_SET = new TreeSet<WorldObject>((WorldObject obj1, WorldObject obj2) -> {
if(obj1.getZ() == obj2.getZ()) {
return Float.compare(obj2.getPosition().y, obj1.getPosition().y);
RETURN_SET = new TreeSet<Layerable>((Layerable obj1, Layerable obj2) -> {
if((obj1.getZ() == obj2.getZ())
&& obj1 instanceof WorldObject
&& obj2 instanceof WorldObject) {
WorldObject wobj1 = (WorldObject) obj1;
WorldObject wobj2 = (WorldObject) obj2;
return Float.compare(wobj2.getPosition().y, wobj1.getPosition().y);
} else {
return Integer.compare(obj1.getZ(), obj2.getZ());
}
@@ -157,30 +163,32 @@ public Vector2 getVelocity() {
}

private String roomName;
private RoomMap room;
private RoomDataWrapper roomWrapper;
private Map<String, Entrypoint> entrypoints;

private Set<WorldObject> removed;
private Map<Long, WorldObject> added;
private Map<Long, WorldObject> objects;

public WorldRoom(RoomDataWrapper roomWrapper) {
public WorldRoom() {
this.added = new HashMap<>();
this.removed = new HashSet<>();
this.entrypoints = new HashMap<>();
this.objects = new HashMap<>();
this.roomWrapper = roomWrapper;
this.room = roomWrapper.getReference(this);
this.roomName = roomWrapper.getRoomScript().getName().split("\\.")[0];
this.roomWrapper = null;
}

public String getRoomName() {
return roomName;
}

public RoomMap getMap() {
return room;
public RoomDataWrapper getMap() {
return roomWrapper;
}

public void setMap(RoomDataWrapper wrapper) {
this.dispose();
this.roomWrapper = wrapper;
}

public Entrypoint getEntrypoint(String name) {
@@ -237,14 +245,23 @@ public void process(CollisionHandler collisionHandler, float delta, InputData in
}

public void render() {
room.render();
for(WorldObject object : getObjectsInRenderOrder()) {
object.render();
// room.render();
Set<Layerable> renderOrder = getObjectsInRenderOrder();
for(Layerable object : renderOrder) {
if(object instanceof WorldObject) {
((WorldObject) object).render();
}

if(object instanceof RoomMapLayer) {
((RoomMapLayer) object).render();
}
}

if(Undertailor.getOverworldController().isRenderingHitboxes()) {
for(WorldObject object : getObjectsInRenderOrder()) {
object.renderBox();
for(Layerable object : renderOrder) {
if(object instanceof WorldObject) {
((WorldObject) object).renderBox();
}
}

for(Entrypoint entrypoint : entrypoints.values()) {
@@ -325,8 +342,15 @@ public void resume() {
}
}

private TreeSet<WorldObject> getObjectsInRenderOrder() {
private TreeSet<Layerable> getObjectsInRenderOrder() {
RETURN_SET.clear();

if(this.roomWrapper != null) {
for(RoomMapLayer layer : roomWrapper.getReference().getLayers()) {
RETURN_SET.add(layer);
}
}

for(WorldObject object : objects.values()) {
RETURN_SET.add(object);
}
@@ -336,7 +360,9 @@ private TreeSet<WorldObject> getObjectsInRenderOrder() {

@Override
public void dispose() {
roomWrapper.removeReference(this);
if(roomWrapper != null) {
roomWrapper.removeReference(this);
}
}

public void onPause() {}
@@ -22,9 +22,10 @@
* SOFTWARE.
*/

package me.scarlet.undertailor.manager;
package me.scarlet.undertailor.overworld.map;

import me.scarlet.undertailor.Undertailor;
import me.scarlet.undertailor.manager.Manager;
import me.scarlet.undertailor.util.LuaUtil;
import me.scarlet.undertailor.wrappers.RoomDataWrapper;
import ninja.leaping.configurate.json.JSONConfigurationLoader;
@@ -33,14 +34,16 @@
import java.util.HashMap;
import java.util.Map;

public class RoomManager extends Manager<RoomDataWrapper> {
public class RoomLoader extends Manager<RoomDataWrapper> {

public static final String MANAGER_TAG = "bellboy";
public static final String MANAGER_TAG = "roomman";

private Map<String, File> scriptFiles;
private Map<String, RoomDataWrapper> rooms;

public RoomManager() {
public RoomLoader() {
this.rooms = new HashMap<>();
this.scriptFiles = new HashMap<>();
}

public void loadObjects(File directory) {
@@ -66,36 +69,78 @@ public void loadObjects(File dir, String heading) {
}

for(File file : dir.listFiles(file -> {
return file.isDirectory() || file.getName().endsWith(".lua");
return file.isDirectory() || file.getName().endsWith(".roommap");
})) {
if(file.isDirectory()) {
loadObjects(file, heading + (heading.isEmpty() ? "" : ".") + file.getName() + ".");
continue;
}

String roomName = file.getName().substring(0, file.getName().length() - 4);
String roomName = file.getName().substring(0, file.getName().length() - 8);
String entryName = heading + (heading.isEmpty() ? "" : ".") + roomName;
File mapDataFile = new File(dir, roomName + ".roommap");
if(!mapDataFile.exists()) {
Undertailor.instance.warn(MANAGER_TAG, "ignoring room " + entryName + " (no map file)");
continue;
}

if(!mapDataFile.isFile()) {
if(!file.isFile()) {
Undertailor.instance.warn(MANAGER_TAG, "ignoring room " + entryName + " (bad map file)");
continue;
}

JSONConfigurationLoader loader = JSONConfigurationLoader.builder().setFile(mapDataFile).build();
JSONConfigurationLoader loader = JSONConfigurationLoader.builder().setFile(file).build();
try {
Undertailor.instance.debug(MANAGER_TAG, "loading room " + entryName);
rooms.put(entryName, new RoomDataWrapper(file, loader.load()));
rooms.put(entryName, new RoomDataWrapper(loader.load()));
} catch(Exception e) {
Undertailor.instance.error(MANAGER_TAG, "could not load room " + entryName + ": " + LuaUtil.formatJavaException(e), e);
}
}
}

public void loadScripts(File directory) {
loadScripts(directory, null);
Undertailor.instance.log(MANAGER_TAG, rooms.keySet().size() + " room script(s) currently loaded");
}

public void loadScripts(File dir, String heading) {
String dirPath = dir.getAbsolutePath();
if(!dir.exists()) {
Undertailor.instance.warn(MANAGER_TAG, "could not load room scripts directory " + dirPath + " (did not exist)");
return;
}

if(!dir.isDirectory()) {
Undertailor.instance.warn(MANAGER_TAG, "could not load room scripts directory " + dirPath + " (not a directory)");
return;
}

Undertailor.instance.log(MANAGER_TAG, "searching for room scripts in " + dirPath);
if(heading == null) {
heading = "";
}

for(File file : dir.listFiles(file -> {
return file.isDirectory() || file.getName().endsWith(".lua");
})) {
if(file.isDirectory()) {
loadObjects(file, heading + (heading.isEmpty() ? "" : ".") + file.getName() + ".");
continue;
}

String roomName = file.getName().substring(0, file.getName().length() - 4);
String entryName = heading + (heading.isEmpty() ? "" : ".") + roomName;

if(!file.isFile()) {
Undertailor.instance.warn(MANAGER_TAG, "ignoring room script" + entryName + " (bad file)");
continue;
}

try {
Undertailor.instance.debug(MANAGER_TAG, "loading room script " + entryName);
scriptFiles.put(entryName, file);
} catch(Exception e) {
Undertailor.instance.error(MANAGER_TAG, "could not load room script " + entryName + ": " + LuaUtil.formatJavaException(e), e);
}
}
}

public RoomDataWrapper getRoom(String name) {
if(rooms.containsKey(name)) {
return rooms.get(name);
@@ -104,4 +149,13 @@ public RoomDataWrapper getRoom(String name) {
Undertailor.instance.warn(MANAGER_TAG, "system requested non-existing room (" + name + ")");
return null;
}

public File getRoomScript(String name) {
if(rooms.containsKey(name)) {
return scriptFiles.get(name);
}

Undertailor.instance.warn(MANAGER_TAG, "system requested non-existing room script (" + name + ")");
return null;
}
}
@@ -0,0 +1,153 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Tellerva, Marc Lawrence
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package me.scarlet.undertailor.overworld.map;

import com.badlogic.gdx.utils.Disposable;
import me.scarlet.undertailor.Undertailor;
import me.scarlet.undertailor.util.ConfigurateUtil;
import me.scarlet.undertailor.wrappers.TilemapWrapper;
import ninja.leaping.configurate.ConfigurationNode;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class RoomMap implements Disposable {

public static class TileData implements Cloneable {

public static final String KEY_VISIBLE = "visible";
public static final String KEY_TRAVERSABLE = "traversable";

private Map<String, Float> values;

public TileData() {
this.values = new HashMap<>();
this.values.put(KEY_VISIBLE, 1.0F);
this.values.put(KEY_TRAVERSABLE, 1.0F);
}

public boolean getBoolean(String key) {
if(values.containsKey(key)) {
return values.get(key) > 0.0F;
}

return false;
}

public void setBoolean(String key, boolean flag) {
values.put(key, flag ? 1.0F : 0.0F);
}

public float getNumber(String key) {
if(values.containsKey(key)) {
return values.get(key);
}

return 0.0F;
}

public void setNumber(String key, float num) {
values.put(key, num);
}

public boolean isTraversable() {
return this.getBoolean(KEY_TRAVERSABLE);
}

public boolean isVisible() {
return this.getBoolean(KEY_VISIBLE);
}

@Override
public TileData clone() {
TileData data = new TileData();
data.values = new HashMap<>(values);
return data;
}
}

public static final int DEFAULT_FLOOR_Z = 0;
public static final int DEFAULT_OBJECT_Z = 1;
public static final int DEFAULT_CEILING_Z = 2;

public static RoomMap fromConfig(ConfigurationNode node) {
RoomMap map = new RoomMap();
map.sizeX = ConfigurateUtil.processInt(node.getNode("sizeX"), null);
map.sizeY = ConfigurateUtil.processInt(node.getNode("sizeY"), null);
String[] tilemapNames = ConfigurateUtil.processStringArray(node.getNode("tilemaps"), null);

map.tilemaps = new TilemapWrapper[tilemapNames.length];
for(int i = 0; i < map.tilemaps.length; i++) {
TilemapWrapper wrapper = Undertailor.getTilemapManager().getTilemap(tilemapNames[i]);
if(wrapper == null) {
Undertailor.instance.error(RoomLoader.MANAGER_TAG, "failed to load room: map data referenced non-existing tilemap (" + tilemapNames[i] + ")");
return null;
}

map.tilemaps[i] = wrapper;
}

Map<Object, ? extends ConfigurationNode> layerMapping = node.getNode("map").getChildrenMap();
for(Entry<Object, ? extends ConfigurationNode> entry : layerMapping.entrySet()) {
RoomMapLayer loaded = new RoomMapLayer(map, entry.getValue());
map.layers.put(loaded.getName(), loaded);
}

return map;
}

private int sizeX, sizeY;
private Map<String, RoomMapLayer> layers;
private TilemapWrapper[] tilemaps;

public RoomMap() {
this.layers = new HashMap<>(); // don't need to organize; worldroom already tries to organize for rendering
}

public Collection<RoomMapLayer> getLayers() {
return layers.values();
}

public int getSizeX() {
return sizeX;
}

public int getSizeY() {
return sizeY;
}

public Tilemap getTilemap(int index) {
return tilemaps[index].getReference();
}

@Override
public void dispose() {
for(TilemapWrapper wrapper : tilemaps) {
wrapper.removeReference(this);
}
}
}
@@ -0,0 +1,144 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Tellerva, Marc Lawrence
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package me.scarlet.undertailor.overworld.map;

import me.scarlet.undertailor.exception.BadConfigurationException;
import me.scarlet.undertailor.util.ConfigurateUtil;
import me.scarlet.undertailor.util.Layerable;
import ninja.leaping.configurate.ConfigurationNode;

public class RoomMapLayer implements Layerable, Cloneable {

private int z;
private String name;
private int priority;
private RoomMap parent;
private Tile[][] mapping;
private boolean visible;

private RoomMapLayer() {} // for clones;

// tilemapid:tileid
public RoomMapLayer(RoomMap parent, ConfigurationNode layerData) {
this.parent = parent;
this.priority = ConfigurateUtil.processBoolean(layerData.getNode("wallLayer"), false) ? 1 : 0;
this.name = layerData.getKey().toString();
this.mapping = new Tile[parent.getSizeY()][parent.getSizeX()];
this.visible = true;

this.z = ConfigurateUtil.processInt(layerData.getNode("z"), 0);

String[] mapping = ConfigurateUtil.processStringArray(layerData.getNode("mapping"), null);
for(int y = 0; y < parent.getSizeY(); y++) {
String[] tiles = mapping[y].split(",");
for(int x = 0; x < parent.getSizeX(); x++) {
this.mapping[y][x] = parseTileMapping(tiles[x]);
}
}
}

@Override
public int getZ() {
return z;
}

@Override
public void setZ(int z) {
this.z = z;
}

@Override
public int getPriority() {
return priority;
}

public boolean isVisible() {
return visible;
}

public void setVisible(boolean flag) {
this.visible = flag;
}

public String getName() {
return name;
}

public RoomMap getParent() {
return parent;
}

public Tile getTileAt(int x, int y) {
return mapping[y][x];
}

public RoomMapLayer clone() {
RoomMapLayer clone = new RoomMapLayer();
clone.z = this.z;
clone.name = this.name;
clone.parent = this.parent;
clone.priority = this.priority;
clone.visible = true;
clone.mapping = new Tile[parent.getSizeY()][parent.getSizeX()];

for(int y = 0; y < parent.getSizeY(); y++) {
for(int x = 0; x < parent.getSizeX(); x++) {
clone.mapping[y][x] = this.mapping[y][x].clone();
}
}

return clone;
}

public void render() {
if(visible) {
for(int x = 0; x < parent.getSizeX(); x++) {
for(int y = 0; y < parent.getSizeY(); y++) {
Tile tile = mapping[y][x];
if(tile != null) {
float xPos = x * 20F;
float yPos = y * 20F;
tile.getCurrentState().getSprite().draw(xPos, yPos, 1F, 1F, 0F, false, false, 20, 20, true);
}
}
}
}
}

Tile parseTileMapping(String mapping) {
try {
String[] mappingSplit = mapping.split(":");
Tilemap map = parent.getTilemap(Integer.parseInt(mappingSplit[0]));
System.out.println(mappingSplit[1]);
Tile returned = map.getTile(mappingSplit[1]).clone();

return returned;
} catch(NullPointerException e) {
BadConfigurationException thrown = new BadConfigurationException("bad map data: data requested non-existing tilemap or tile");
thrown.initCause(e);
throw thrown;
}
}
}
@@ -0,0 +1,112 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Tellerva, Marc Lawrence
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package me.scarlet.undertailor.overworld.map;

import me.scarlet.undertailor.gfx.Sprite;
import ninja.leaping.configurate.ConfigurationNode;

import java.util.HashMap;
import java.util.Map;

public class Tile implements Cloneable {

public static class TileState {

public static TileState fromConfig(ConfigurationNode config) {
return null; // TODO;
}

private Tile parent;
private Sprite sprite; // TODO tile animation
private String stateName;

public TileState(String stateName, Tile parent, Sprite sprite) {
this.sprite = sprite;
this.parent = parent;
this.stateName = stateName;
}

public Tile getParent() {
return parent;
}

public String getStateName() {
return stateName;
}

public Sprite getSprite() {
return sprite;
}
}

private String tileName;
private String currentState;
private Map<String, TileState> states;

private Tile() {
this.tileName = null;
this.currentState = null;
this.states = new HashMap<String, TileState>();
}

public Tile(String tileName) {
this.tileName = tileName;
this.currentState = null;
this.states = new HashMap<String, TileState>();
}

public String getTileName() {
return tileName;
}

public void addState(TileState state) {
this.addStates(state);
}

public void addStates(TileState... states) {
for(TileState state : states) {
this.states.put(state.getStateName(), state);
}
}

public TileState getCurrentState() {
return states.get(currentState);
}

public void setCurrentState(String stateId) {
if(states.containsKey(stateId)) {
this.currentState = stateId;
}
}

public Tile clone() {
Tile returned = new Tile();
returned.tileName = this.tileName;
returned.currentState = this.currentState;
returned.states = new HashMap<>(this.states);

return returned;
}
}
@@ -0,0 +1,135 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Tellerva, Marc Lawrence
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package me.scarlet.undertailor.overworld.map;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Disposable;
import me.scarlet.undertailor.Undertailor;
import me.scarlet.undertailor.exception.TextureTilingException;
import me.scarlet.undertailor.gfx.SpriteSheet;
import me.scarlet.undertailor.gfx.SpriteSheet.SpriteSheetMeta;
import me.scarlet.undertailor.manager.TilemapManager;
import me.scarlet.undertailor.overworld.map.Tile.TileState;
import me.scarlet.undertailor.util.ConfigurateUtil;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.json.JSONConfigurationLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.naming.ConfigurationException;

public class Tilemap implements Disposable {

public static final String TILEMAP_SHEET_PREFIX = "$ttlm-";
public static final String ILLEGAL_CHARACTERS = ",;:=";

public static float getPropertyValue(String str) {
try {
return Float.parseFloat(str);
} catch(NumberFormatException e) {
if(str.equalsIgnoreCase("true")) {
return 1.0F;
}

return 0.0F;
}
}

private String name;
private SpriteSheet sheet;
private Map<String, Tile> tiles;

public Tilemap(String name, File texture, File meta) throws TextureTilingException, FileNotFoundException, ConfigurationException, IOException {
this.name = name;
this.tiles = new HashMap<>();

if(!texture.exists() || !meta.exists()) {
throw new FileNotFoundException("texture/meta file not found (" + texture.getName() + "/" + meta.getName() + ")");
}

Texture tx = new Texture(Gdx.files.absolute(texture.getAbsolutePath()));
if(tx.getWidth() % 20 != 0 || tx.getHeight() % 20 != 0) {
throw new TextureTilingException("texture does not contain 20x20 tiled sprites");
}

SpriteSheetMeta smeta = new SpriteSheetMeta();
smeta.gridX = tx.getWidth() / 20;
smeta.gridY = tx.getHeight() / 20;
this.sheet = new SpriteSheet(TILEMAP_SHEET_PREFIX + name, tx, smeta);

JSONConfigurationLoader loader = JSONConfigurationLoader.builder().setFile(meta).build();
ConfigurationNode node = loader.load();

Map<Object, ? extends ConfigurationNode> map = node.getNode("tiles").getChildrenMap();
for(Entry<Object, ? extends ConfigurationNode> entry : map.entrySet()) {
ConfigurationNode tileConfig = entry.getValue();
String tileName = tileConfig.getKey().toString();
String defaultState = null;
Tile tile = new Tile(tileName);

for(int i = 0; i < ILLEGAL_CHARACTERS.length(); i++) {
char ch = ILLEGAL_CHARACTERS.charAt(i);
if(tileName.contains(ch + "")) {
throw new ConfigurationException("tile name \"" + tileName + "\" contained illegal character '" + ch + "'");
}
}

Map<Object, ? extends ConfigurationNode> states = tileConfig.getNode("states").getChildrenMap();
for(Entry<Object, ? extends ConfigurationNode> stateEntry : states.entrySet()) {
TileState state = new TileState(stateEntry.getKey().toString(), tile, this.sheet.getSprite(ConfigurateUtil.processInt(stateEntry.getValue().getNode("sprite"), null)));
tile.addState(state);

if(defaultState == null) {
defaultState = state.getStateName();
tile.setCurrentState(defaultState);
}

Undertailor.instance.debug(TilemapManager.MANAGER_TAG, "loading tilestate " + tileName + ":" + state.getStateName());
}

Undertailor.instance.debug(TilemapManager.MANAGER_TAG, "loaded tile " + this.name + ":" + tileName);
this.tiles.put(tileName, tile);
}
}

public String getName() {
return this.name;
}

public Tile getTile(String id) {
return tiles.get(id);
}

@Override
public void dispose() {
this.sheet.dispose();
}
}
@@ -32,5 +32,6 @@ public interface Layerable {

public int getZ();
public void setZ(int z);
public int getPriority(); // floors should be 0; everything else should be 1

}
@@ -0,0 +1,18 @@
package me.scarlet.undertailor.util;

import java.util.Comparator;
import java.util.Map;

public abstract class ValueComparator<T1, T2> implements Comparator<T1> {

private Map<T1, T2> map;
public ValueComparator(Map<T1, T2> map) {
this.map = map;
}

public Map<T1, T2> getMap() {
return map;
}

public abstract int compare(T1 o1, T1 o2);
}
@@ -24,25 +24,17 @@

package me.scarlet.undertailor.wrappers;

import me.scarlet.undertailor.overworld.RoomMap;
import me.scarlet.undertailor.overworld.map.RoomMap;
import ninja.leaping.configurate.ConfigurationNode;

import java.io.File;

public class RoomDataWrapper extends DisposableWrapper<RoomMap> {

public static final long MAX_LIFETIME = 60000; // 1min

private File roomScript;
private ConfigurationNode mapData;
public RoomDataWrapper(File roomScript, ConfigurationNode mapData) {
public RoomDataWrapper(ConfigurationNode mapData) {
super(null);
this.mapData = mapData;
this.roomScript = roomScript;
}

public File getRoomScript() {
return roomScript;
}

@Override
@@ -24,34 +24,28 @@

package me.scarlet.undertailor.wrappers;

import com.badlogic.gdx.graphics.Texture;
import me.scarlet.undertailor.exception.TextureTilingException;
import me.scarlet.undertailor.gfx.SpriteSheet;
import me.scarlet.undertailor.gfx.SpriteSheet.SpriteSheetMeta;
import me.scarlet.undertailor.overworld.map.Tilemap;

public class TilemapWrapper extends DisposableWrapper<SpriteSheet> {
import java.io.File;

private Texture texture;
public class TilemapWrapper extends DisposableWrapper<Tilemap> {

private File meta;
private File texture;
private String tilemapName;
public TilemapWrapper(String tilemapName, Texture texture) throws TextureTilingException {
public TilemapWrapper(String tilemapName, File texture, File meta) throws TextureTilingException {
super(null);
this.meta = meta;
this.texture = texture;
this.tilemapName = tilemapName;

if(texture.getWidth() % 20 != 0 || texture.getHeight() % 20 != 0) {
throw new TextureTilingException("tilemap texture does not contain 20x20 sprites");
}
}

@Override
public SpriteSheet newReference() {
SpriteSheetMeta meta = new SpriteSheetMeta();
meta.gridX = texture.getWidth() / 20;
meta.gridY = texture.getHeight() / 20;

public Tilemap newReference() {
try {
return new SpriteSheet(tilemapName, texture, meta);
} catch(TextureTilingException e) {
return new Tilemap(tilemapName, texture, meta);
} catch(Exception e) {
e.printStackTrace();
return null;
}