package net.fourbytes.shadow;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.MapProperties;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.LongMap;
import net.fourbytes.shadow.blocks.BlockType;
import net.fourbytes.shadow.entities.Cursor;
import net.fourbytes.shadow.entities.Player;
import net.fourbytes.shadow.map.IsSaveable;
import net.fourbytes.shadow.map.MapObject;
import net.fourbytes.shadow.map.ShadowMap;
import net.fourbytes.shadow.systems.DefaultSystemManager;
import net.fourbytes.shadow.systems.ISystemManager;
import java.lang.reflect.Field;
import java.util.Iterator;
public class Level {
public LongMap<GameObject> goIDMap = new LongMap<GameObject>();
public ShadowMap map;
public ISystemManager systems = createSystems();
public IntMap<Layer> layers = new IntMap<Layer>(16);
public Layer mainLayer = new Layer(this);
@IsSaveable
public Color globalLight = new Color(1f, 1f, 1f, 1f);
public Player player;
public Cursor c;
public Array<Cursor> cursors = new Array<Cursor>(false, 8, Cursor.class);
@IsSaveable
public float gravity = 0.02f;
@IsSaveable
public float xgravity = 0.0f;
public static float inviewf = 10f;
//Abstract constructor, can be used for non-gameplay levels (menus).
public Level() {
}
@IsSaveable
public String nextlvl;
public boolean ready = false;
public boolean paused = false;
public boolean ftick = true;
public long tickid = 0;
public boolean dirtify = false;
public Level(String name) {
this(name, null);
}
public Level(String name, LoadingLevel loading) {
if (loading != null) {
loading.bgpaused = true;
loading.bglevel = this;
}
dirtify = false;
fillLayer(0);
c = new Cursor(new Vector2(0f, 0f), layers.get(0));
if (Gdx.files.internal("data/levels/"+name+".smf").exists()) {
map = ShadowMap.loadFile(Gdx.files.internal("data/levels/"+name+".smf"));
map.fillLevel(this, loading);
} else if (Gdx.files.internal("data/levels/"+name+".tmx").exists()) {
map = new ShadowMap();
try {
TmxMapLoader tml = new TmxMapLoader();
//TODO Custom TmxMapLoader that loads TiledMaps without loading tileset images
initTilED(tml.load("data/levels/"+name+".tmx"), loading);
ready = true;
} catch (Throwable t) {
t.printStackTrace();
}
} else {
map = new ShadowMap();
System.err.println("Map not found: "+name);
}
System.gc();
dirtify = true;
ready = true;
}
public ISystemManager createSystems() {
ISystemManager systems = new DefaultSystemManager(this);
systems.init();
return systems;
}
public Layer fillLayer(int key) {
Layer layer = layers.get(key);
if (layer == null) {
layer = new Layer(this);
layers.put(key, layer);
}
return layer;
}
public void initTilED(TiledMap map) {
initTilED(map);
}
public void initTilED(TiledMap map, LoadingLevel loading) {
if (loading != null) {
loading.progress = 0;
loading.progressMax = 0;
}
map.dispose();
//tiledw = map.width;
//tiledh = map.height;
int gridWidth = map.getProperties().get("tilewidth", Integer.class);
int gridHeight = map.getProperties().get("tileheight", Integer.class);
nextlvl = (String) map.getProperties().get("nextlvl");
int pln = 0;
for (int li = 0; li < map.getLayers().getCount(); li++) {
MapLayer l = map.getLayers().get(li);
int ln = li;
if (l.getProperties().containsKey("layer")) {
ln = pln + Integer.parseInt(l.getProperties().get("layer", String.class));
}
Layer ll = fillLayer(ln);
if (l instanceof TiledMapTileLayer) {
TiledMapTileLayer tl = (TiledMapTileLayer) l;
for (int x = 0; x < tl.getWidth(); x++) {
for (int y = 0; y < tl.getHeight(); y++) {
Cell cell = tl.getCell(x, y);
if (cell != null && cell.getTile() != null) {
GameObject go = getGameObject(ln, x, tl.getHeight() - y, cell);
if (go instanceof Player) {
pln = ln;
}
ll.add(go);
}
}
}
}
MapObjects objs = l.getObjects();
if (objs != null) {
for (int i = 0; i < objs.getCount(); i++) {
com.badlogic.gdx.maps.MapObject mo = objs.get(i);
GameObject go = getGameObject(ln,
(int) (mo.getProperties().get("x", Float.class) / gridWidth),
map.getProperties().get("height", Integer.class) - (int) (mo.getProperties().get("y", Float.class) / gridHeight), mo);
ll.add(go);
}
}
}
}
protected GameObject getGameObject(int ln, int x, int y, Cell cell) {
int tid = cell.getTile().getId();
String type = cell.getTile().getProperties().get("type", String.class);
String subtype = cell.getTile().getProperties().get("subtype", String.class);
GameObject obj = ShadowMap.convert(x, y, layers.get(ln), tid, type, subtype);
if (obj instanceof Player) {
player = (Player) obj;
}
return obj;
}
protected GameObject getGameObject(int ln, int x, int y, com.badlogic.gdx.maps.MapObject mo) {
String subtype = mo.getProperties().get("type", String.class);
GameObject obj = ShadowMap.convert(x, y, layers.get(ln), -1, null, subtype);
if (obj instanceof Player) {
player = (Player) obj;
}
Class<? extends GameObject> clazz = obj.getClass();
Iterator<String> keys = mo.getProperties().getKeys();
String key;
while (keys.hasNext()) {
key = keys.next();
try {
Field field = clazz.getField(key);
field.setAccessible(true);
Object value = mo.getProperties().get(key);
Class type = field.getType();
if (type.equals(byte.class)) {
field.setByte(obj, Byte.parseByte((String) value));
} else if (type.equals(short.class)) {
field.setShort(obj, Short.parseShort((String) value));
} else if (type.equals(int.class)) {
field.setInt(obj, Integer.parseInt((String) value));
} else if (type.equals(long.class)) {
field.setLong(obj, Long.parseLong((String) value));
} else if (type.equals(float.class)) {
field.setFloat(obj, Float.parseFloat((String) value));
} else if (type.equals(double.class)) {
field.setDouble(obj, Double.parseDouble((String) value));
} else if (type.equals(boolean.class)) {
field.setBoolean(obj, Boolean.parseBoolean((String) value));
} else if (type.equals(char.class)) {
field.setChar(obj, ((String) value).charAt(0));
} else {
field.set(obj, value);
}
} catch (Exception e) {
}
}
return obj;
}
public void tick(float delta) {
Rectangle vp = Shadow.cam.camrec;
tickid++;
mainLayer.inView.clear();
for (Layer ll : layers.values()) {
if (ll == null) continue;
ll.inView.clear();
}
float ox, oy, ow, oh;
boolean shallTick;
for (int i = 0; i < mainLayer.blocks.size; i++) {
Block block = mainLayer.blocks.items[i];
if (block == null) continue;
ox = block.pos.x-inviewf;
oy = block.pos.y-inviewf;
ow = block.rec.width+inviewf*2f;
oh = block.rec.height+inviewf*2f;
if (vp.x < ox + ow && vp.x + vp.width > ox && vp.y < oy + oh && vp.y + vp.height > oy) {
Array<GameObject> inView;
inView = mainLayer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size / 2);
}
inView.items[inView.size++] = block;
inView = block.layer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size/2);
}
inView.items[inView.size++] = block;
shallTick = block.tickInView;
} else {
shallTick = false;
}
if ((ftick || block.tickAlways || shallTick) && !paused) {
block.tick(delta);
}
block.frame(delta);
}
for (int i = 0; i < mainLayer.entities.size; i++) {
Entity entity = mainLayer.entities.items[i];
if (entity == null) continue;
ox = entity.pos.x-inviewf;
oy = entity.pos.y-inviewf;
ow = entity.rec.width+inviewf*2f;
oh = entity.rec.height+inviewf*2f;
if (vp.x < ox + ow && vp.x + vp.width > ox && vp.y < oy + oh && vp.y + vp.height > oy) {
Array<GameObject> inView;
inView = mainLayer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size / 2);
}
inView.items[inView.size++] = entity;
inView = entity.layer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size/2);
}
inView.items[inView.size++] = entity;
}
if (!paused) {
entity.tick(delta);
}
entity.frame(delta);
}
for (int i = 0; i < mainLayer.particles.size; i++) {
Particle particle = mainLayer.particles.items[i];
if (particle == null) continue;
ox = particle.pos.x-inviewf;
oy = particle.pos.y-inviewf;
ow = particle.rec.width+inviewf*2f;
oh = particle.rec.height+inviewf*2f;
if (vp.x < ox + ow && vp.x + vp.width > ox && vp.y < oy + oh && vp.y + vp.height > oy) {
Array<GameObject> inView;
inView = mainLayer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size / 2);
}
inView.items[inView.size++] = particle;
inView = particle.layer.inView;
if (inView.size == inView.items.length) {
inView.items = inView.ensureCapacity(inView.size/2);
}
inView.items[inView.size++] = particle;
}
particle.tick(delta);
}
if (ready) {
systems.tick(delta);
if (!paused) {
if (Shadow.level == this && c != null) {
for (int i = 0; i < cursors.size; i++) {
Cursor c = cursors.items[i];
c.tick(delta);
}
c.tick(delta);
if (pointblock != null) {
pointblock.tick(delta);
}
}
}
}
ftick = false;
}
public boolean canRenderImpl = true;
public BitmapFont font = Fonts.light_normal;
protected static Image bgwhite;
protected static Image fgwhite;
protected Block pointblock;
public void renderImpl() {
if (!canRenderImpl) return;
Rectangle vp = Shadow.cam.camrec;
/*
img.setScale((1f/16f));
img.setPosition(vp.x + Shadow.vieww/2 -(1.25f*(2.5f-i)) - 0.125f, vp.y + 1.5f);
img.draw(Shadow.spriteBatch, 0.9f);
*/
if (player != null) {
float alpha = 0.9f;
float bgw = 5.1f;
float fgw = player.health*5f;
float bgh = 0.5f;
float fgh = 0.4f;
float xx1 = vp.x;
float xx2 = xx1 + 0.05f;
float yy1 = vp.y + bgh;
float yy2 = yy1 - 0.05f;
Image white;
if (bgwhite == null) {
bgwhite = Images.getImage("white");
}
white = bgwhite;
white.setColor(0f, 0f, 0f, alpha);
white.setPosition(xx1, yy1);
white.setSize(1f, -1f);
white.setScale(bgw, bgh);
white.draw(Shadow.spriteBatch, 1f);
if (fgwhite == null) {
fgwhite = Images.getImage("white");
}
white = fgwhite;
white.setColor(1f-1f*(player.health/player.MAXHEALTH), 1f*(player.health/player.MAXHEALTH), 0.2f, alpha);
white.setPosition(xx2, yy2);
white.setSize(1f, -1f);
white.setScale(fgw, fgh);
white.draw(Shadow.spriteBatch, 1f);
if (pointblock == null) {
fillLayer(0);
pointblock = BlockType.getInstance("BlockPoint", 0, 0, layers.get(0));
}
float xx3 = vp.x;
float xx4 = vp.x + 1.2f;
float yy3 = vp.y + bgh - 0.1f;
float yy4 = vp.y + bgh + 0.1f;
pointblock.pos.set(xx3, yy3);
pointblock.preRender();
pointblock.render();
font.setScale(Shadow.vieww/Shadow.dispw, -Shadow.viewh/Shadow.disph);
font.draw(Shadow.spriteBatch, "x"+player.points, xx4, yy4);
}
}
}