package stray.world;
import java.io.IOException;
import stray.LevelData.LevelType;
import stray.Main;
import stray.Settings;
import stray.blocks.Block;
import stray.blocks.Block.BlockFaces;
import stray.blocks.BlockCameraMagnet;
import stray.blocks.BlockPlayerSpawner;
import stray.blocks.Blocks;
import stray.entity.Entity;
import stray.entity.EntityPlayer;
import stray.objective.Objective;
import stray.objective.Objectives;
import stray.pathfinding.Mover;
import stray.pathfinding.TileBasedMap;
import stray.util.AssetMap;
import stray.util.DamageSource;
import stray.util.GlobalVariables;
import stray.util.KeyBinds;
import stray.util.MathHelper;
import stray.util.Particle;
import stray.util.ParticlePool;
import stray.util.Sizeable;
import stray.util.Utils;
import stray.util.render.SmoothCamera;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
import com.badlogic.gdx.utils.XmlWriter;
public class World implements TileBasedMap {
public Main main;
public SpriteBatch batch;
public int sizex = 32;
public int sizey = 32;
public static final int tilesizex = 64;
public static final int tilesizey = 64;
public static final float tilepartx = (1f / tilesizex);
public static final float tileparty = (1f / tilesizey);
public float gravity = 20f;
public float drag = 20f;
public String background = "levelbgcircuit";
public Block[][] blocks;
public int[][] meta;
public Pool<BlockUpdate> buPool = Pools.get(BlockUpdate.class);
public Array<BlockUpdate> scheduledUpdates = new Array<BlockUpdate>();
public Array<Entity> entities;
private int playerIndex = 0;
public Array<Particle> particles;
public LevelType levelType = LevelType.NORMAL;
public SmoothCamera camera;
private float cameramovex = 0, cameramovey = 0;
/**
* number of ticks since creation
*/
public long tickTime = -1;
public int canRespawnIn = 0;
/**
* millisecond time since show() was called
*/
public long msTime = 0;
public WorldRenderer renderer;
public Color vignettecolour = new Color(0, 0, 0, 0);
public GlobalVariables global = new GlobalVariables();
public String levelfile = null;
public float checkpointx, checkpointy;
public Array<DamageSource> deaths = new Array<DamageSource>(32);
public Array<Objective> objectives = new Array<Objective>();
public World(Main main) {
this(main, 32, 24, LevelType.NORMAL);
}
public World(Main main, int x, int y, LevelType type) {
this.main = main;
batch = main.batch;
sizex = x;
sizey = y;
camera = new SmoothCamera(this);
prepare();
renderer = new WorldRenderer(this);
levelType = type;
}
public void prepare() {
msTime = System.currentTimeMillis();
global.clear();
blocks = new Block[sizex][sizey];
meta = new int[sizex][sizey];
for (int j = 0; j < sizex; j++) {
for (int k = 0; k < sizey; k++) {
blocks[j][k] = Blocks.instance().getBlock(Blocks.defaultBlock);
if (j == 0 || j + 1 == sizex) blocks[j][k] = Blocks.instance().getBlock("wall");
if (k == 0 || k + 1 == sizey) blocks[j][k] = Blocks.instance().getBlock("wall");
meta[j][k] = 0;
}
}
deaths.clear();
entities = new Array<Entity>(32);
particles = new Array<Particle>();
addPlayer();
// camera.forceCenterOn(getPlayer().x, getPlayer().y);
setCheckpoint();
objectives.clear();
// addObjective("complete_level");
}
public void addPlayer() {
if (getPlayer() == null) {
EntityPlayer player = new EntityPlayer(this, 13, sizey - 9);
player.prepare();
entities.add(player);
}
}
public float getPan(float x) {
return Utils.getSoundPan(x, camera.camerax);
}
public World getWorld() {
return this;
}
public void generateCircle(int cx, int cy, String id, int rad) {
for (int x = cx - rad; x < cx + rad + 1; x++) {
for (int y = cy - rad; y < cy + rad + 1; y++) {
if (getBlock(x, y) != Blocks.instance().getBlock(id)) {
if (Math.round(MathHelper.calcDistance(x, y, cx, cy)) <= rad) {
setBlock(Blocks.instance().getBlock(id), x, y);
}
}
}
}
}
public void setVignette(float r, float g, float b, float alpha) {
vignettecolour.set(r, g, b, alpha);
}
public void setVignette(float alpha) {
vignettecolour.set(vignettecolour.r, vignettecolour.g, vignettecolour.b, alpha);
}
public void setVignette(Color c, float alpha) {
vignettecolour.set(c);
setVignette(alpha);
}
public void inputUpdate() {
if (main.getConv() != null) return;
if (getPlayer() == null) return;
if (getPlayer().health > 0 && getPlayer().stunTime <= 0) {
if (Gdx.input.isKeyPressed(KeyBinds.MOVEMENT_JUMP)) {
getPlayer().jump();
}
if (Gdx.input.isKeyPressed(KeyBinds.MOVEMENT_DOWN)) {
} else if (Gdx.input.isKeyJustPressed(KeyBinds.MOVEMENT_UP)) {
}
if (Gdx.input.isKeyPressed(KeyBinds.MOVEMENT_LEFT)) {
getPlayer().moveLeft();
} else if (Gdx.input.isKeyPressed(KeyBinds.MOVEMENT_RIGHT)) {
getPlayer().moveRight();
} else {
}
}
if (Gdx.input.isKeyPressed(Keys.I)) {
cameramovey = -World.tilesizey * 1.5f;
} else if (Gdx.input.isKeyPressed(Keys.K)) {
cameramovey = World.tilesizey * 1.5f;
} else {
cameramovey = 0;
}
if (Gdx.input.isKeyPressed(Keys.J)) {
cameramovex = -World.tilesizex * 1.5f;
} else if (Gdx.input.isKeyPressed(Keys.L)) {
cameramovex = World.tilesizex * 1.5f;
} else cameramovex = 0;
if (Settings.debug) {
if (Gdx.input.isKeyPressed(Keys.ALT_LEFT) || Gdx.input.isKeyPressed(Keys.ALT_RIGHT)) {
if (Gdx.input.isKeyJustPressed(Keys.T)) {
getPlayer().damage(0.999f, DamageSource.generic);
} else if (Gdx.input.isKeyJustPressed(Keys.Y)) {
explosion(getPlayer().x + 0.5f, getPlayer().y + 0.5f);
}
}
}
}
public void renderUpdate() {
inputUpdate();
for (Entity e : entities) {
e.renderUpdate();
}
if (objectives.size > 0) for (int i = objectives.size - 1; i >= 0; i--) {
if (System.currentTimeMillis() - objectives.get(i).completedTime >= Objective.showTimeWhenCompleted
&& objectives.get(i).completedTime != -1) {
objectives.removeIndex(i);
}
}
}
public EntityPlayer getPlayer() {
if (entities.size < 1) return null;
if (playerIndex < entities.size || entities.get(playerIndex) instanceof EntityPlayer) {
return (EntityPlayer) entities.get(playerIndex);
}
for (int i = 0; i < entities.size; i++) {
if (entities.get(i) instanceof EntityPlayer) {
playerIndex = i;
return (EntityPlayer) entities.get(i);
}
}
return null;
}
private void centerCamera() {
EntityPlayer p = getPlayer();
if (p == null) {
return;
}
if (p.health <= 0) return;
camera.centerX(((p.x + (p.sizex / 2f)) * tilesizex + cameramovex));
if (p.getBlockCollidingDown() != null || !isPlayerVisible()) {
camera.centerY(((p.y + (p.sizey / 2f)) * tilesizey + cameramovey) - (tilesizey * 1.5f));
}
int halfScreenWidth = ((Settings.DEFAULT_WIDTH / 2) / tilesizex);
int halfScreenHeight = ((Settings.DEFAULT_HEIGHT / 2) / tilesizey);
for (int x = (int) (p.x - halfScreenWidth) + 2; x < (int) (p.x + halfScreenWidth) - 2; x++) {
for (int y = (int) (p.y - halfScreenHeight) + 1; y < (int) (p.y + halfScreenHeight) + 1; y++) {
if (getBlock(x, y) instanceof BlockCameraMagnet) {
camera.centerOn((x + 0.5f) * tilesizex, (y - 0.5f) * tilesizex);
camera.clamp();
}
}
}
camera.clamp();
main.camera.update();
}
protected boolean isPlayerVisible() {
EntityPlayer e = getPlayer();
return (((e.y + e.sizey) * World.tilesizey) <= camera.cameray + Settings.DEFAULT_HEIGHT)
&& ((e.y * World.tilesizey) >= camera.cameray);
}
protected boolean isEntityOnScreen(Entity e) {
if (e.x * World.tilesizex > camera.camerax + Settings.DEFAULT_WIDTH) return false;
if ((e.x + e.sizex) * World.tilesizex < camera.camerax) return false;
if ((((e.y) * World.tilesizey) > camera.cameray + Settings.DEFAULT_HEIGHT)) return false;
if ((((e.y + e.sizey) * World.tilesizey) < camera.cameray)) return false;
return true;
}
public void renderOnly() {
main.buffer.begin();
batch.begin();
renderer.renderBackground();
batch.flush();
renderer.renderBlocks();
// particles
if (particles.size > 0) {
for (Particle p : particles) {
p.render(this, main);
}
}
batch.end();
main.buffer.end();
batch.begin();
renderer.renderBuffer();
batch.end();
}
public void render() {
if (vignettecolour.a > 0) {
vignettecolour.a -= Gdx.graphics.getDeltaTime();
if (vignettecolour.a < 0) vignettecolour.a = 0;
}
renderOnly();
batch.begin();
renderer.renderUi();
batch.end();
Particle item;
for (int i = particles.size; --i >= 0;) {
item = particles.get(i);
if (item.lifetime <= 0) {
particles.removeIndex(i);
ParticlePool.instance().getPool().free(item);
}
}
}
private Color setAlphaColor(float a, Color c) {
c.a = a;
return c;
}
public void setCheckpoint() {
setCheckpoint(getPlayer().x, getPlayer().y);
}
public void setCheckpoint(float x, float y) {
checkpointx = x;
checkpointy = y;
}
public void attemptCheckpoint() {
}
public void tickUpdate() {
++tickTime;
renderer.tickUpdate();
for (int y = sizey - 1; y >= 0; y--) {
for (int x = 0; x < sizex; x++) {
executeBlockUpdates();
if (getBlock(x, y).getTickRate() < 1) continue;
if (getBlock(x, y).getTickRate() > 1) if (tickTime % getBlock(x, y).getTickRate() != 0) continue;
getBlock(x, y).tickUpdate(this, x, y);
}
}
executeBlockUpdates();
if (canRespawnIn > 0) {
canRespawnIn--;
if (canRespawnIn == 0) {
getPlayer().x = checkpointx;
getPlayer().y = checkpointy;
getPlayer().health = getPlayer().maxhealth;
getPlayer().invincibility = Main.TICKS;
getPlayer().gravityCoefficient = 1;
deaths.add(getPlayer().getLastDamageSource());
} else {
getPlayer().gravityCoefficient = 0;
getPlayer().velox = 0;
getPlayer().veloy = 0;
}
}
for (int i = 0; i < entities.size; i++) {
entities.get(i).tickUpdate();
}
for (int i = entities.size - 1; i > -1; i--) {
if (entities.get(i).isDead()) {
if (!entities.get(i).onDeath()) entities.removeIndex(i);
}
}
centerCamera();
camera.update();
}
public void executeBlockUpdates() {
BlockUpdate b;
for (int i = scheduledUpdates.size; --i >= 0;) {
b = scheduledUpdates.get(i);
setBlock(b.block, b.x, b.y);
setMeta(b.meta, b.x, b.y);
scheduledUpdates.removeIndex(i);
buPool.free(b);
}
}
private int getEntitiesType(Class<? extends Entity> cls) {
int num = 0;
for (Entity e : entities) {
if (cls.isInstance(e)) {
num++;
}
}
return num;
}
public boolean canSpawn(Sizeable s, int x, int y) {
if (x >= 0 && y >= 0 && x < sizex && y < sizey) {
int width = ((int) s.getWidth()) + 1;
int height = ((int) s.getHeight()) + 1;
for (int checkx = x; checkx < x + width; checkx++) {
for (int checky = y; checky < y + height; checky++) {
if (getBlock(checkx, checky).isSolid(this, checkx, checky) != BlockFaces.NONE) {
return false;
}
}
}
return true;
}
return false;
}
public void explosion(float x, float y) {
camera.shake(0.15f, 2.5f, false);
int smokeToSpawn = 30;
float smokeVelocity = 6f;
for (int i = 0; i < smokeToSpawn; i++) {
particles.add(ParticlePool
.obtain()
.setPosition(x, y)
.setLifetime(0.5f)
.setTexture("poof")
.setRotation(5f, MathUtils.randomBoolean())
.setVelocity(smokeVelocity * MathUtils.cosDeg((360f / smokeToSpawn) * i),
smokeVelocity * MathUtils.sinDeg((360f / smokeToSpawn) * i)));
}
for (int i = 0; i < MathUtils.random(45, 60); i++) {
particles.add(ParticlePool
.obtain()
.setPosition(x, y)
.setLifetime(0.5f)
.setTexture("poof")
.setRotation(5f, MathUtils.randomBoolean())
.setVelocity(
smokeVelocity * 3f * MathUtils.randomSign()
* MathUtils.random(0.25f, 1.25f),
smokeVelocity * 3f * MathUtils.randomSign()
* MathUtils.random(0.25f, 1.25f)));
}
particles.add(ParticlePool.obtain().setPosition(x, y).setLifetime(0.2f)
.setTexture("particleshockwave").setRotation(1f, MathUtils.randomBoolean())
.setStartScale(0.25f).setEndScale(1.5f));
particles.add(ParticlePool
.obtain()
.setPosition(x, y)
.setLifetime(0.25f)
.setTexture("particleflash" + MathUtils.random(3))
.setStartScale(0.9f)
.setEndScale(1.1f)
.setTint(1f, (204f + MathUtils.random(-16, 16)) / 255f,
(34f + MathUtils.random(-16, 16)) / 255f, 0.75f));
particles.add(ParticlePool
.obtain()
.setPosition(x, y)
.setLifetime(0.2f)
.setTexture("particleflame" + MathUtils.random(3))
.setStartScale(1.75f)
.setEndScale(2.0f)
.setTint(1f, (204f + MathUtils.random(-16, 16)) / 255f,
(34f + MathUtils.random(-16, 16)) / 255f, 0.5f)
.setRotation(0.1f, MathUtils.randomBoolean()));
}
public void addObjective(String objective) {
for (Objective o : objectives) {
if (o.id.equals(objective)) return;
}
objectives.add(new Objective(objective));
if(renderer != null) renderer.newObjective = 2.5f;
}
public void addObjective(Objective obj){
addObjective(obj.id);
}
public void completeObjective(String obj, boolean fail) {
for (Objective o : objectives) {
if (o.id == obj && !o.isCompleted()) {
o.complete(fail);
return;
}
}
}
/**
* completes the objective without a failure
* @param obj
*/
public void completeObjective(String obj){
completeObjective(obj, false);
}
public void show() {
msTime = System.currentTimeMillis();
}
public void hide() {
main.manager.get(AssetMap.get("voidambient"), Sound.class).stop();
}
public void dispose() {
}
/**
* get room position based on mouse coords
*
* @param x
* @return
*/
public int getRoomX(float x) {
return (int) ((x + camera.camerax) / tilesizex);
}
/**
* @see getRoomX
* @param y
* @return
*/
public int getRoomY(float y) {
return (int) ((y + camera.cameray) / tilesizey);
}
public Block getBlock(int x, int y) {
if (x < 0 || y < 0 || x >= sizex || y >= sizey) return Blocks.defaultBlock();
if (blocks[x][y] == null) return Blocks.defaultBlock();
return blocks[x][y];
}
public int getMeta(int x, int y) {
if (x < 0 || y < 0 || x >= sizex || y >= sizey) return 0;
return meta[x][y];
}
public void setBlock(Block r, int x, int y) {
if (x < 0 || y < 0 || x >= sizex || y >= sizey) return;
blocks[x][y] = r;
}
public void setMeta(int m, int x, int y) {
if (x < 0 || y < 0 || x >= sizex || y >= sizey) return;
meta[x][y] = m;
}
public boolean doesBlockExist(Array<Block> blocks) {
for (int x = 0; x < sizex; x++) {
for (int y = 0; y < sizey; y++) {
if (blocks.contains(getBlock(x, y), true)) return true;
}
}
return false;
}
@Override
public int getWidthInTiles() {
return sizex;
}
@Override
public int getHeightInTiles() {
return sizey;
}
@Override
public void pathFinderVisited(int x, int y) {
}
@Override
public boolean blocked(Mover mover, int tx, int ty) {
return getBlock(tx, ty).isSolid(this, tx, ty) != BlockFaces.NONE;
}
@Override
public float getCost(Mover mover, int sx, int sy, int tx, int ty) {
return 1;
}
public void save(FileHandle file) {
if (!file.exists()) try {
file.file().createNewFile();
} catch (IOException e1) {
e1.printStackTrace();
}
XmlWriter w = new XmlWriter(file.writer(false));
try {
XmlWriter writer = w.element("level");
XmlWriter essentials = writer.element("essentials");
essentials.attribute("sizex", "" + sizex);
essentials.attribute("sizey", "" + sizey);
essentials.attribute("bg", background);
essentials.pop();
XmlWriter tiles = writer.element("tiles");
for (int x = 0; x < sizex; x++) {
for (int y = 0; y < sizey; y++) {
XmlWriter tile = tiles.element("tile");
tile.attribute("x", "" + x);
tile.attribute("y", "" + y);
tile.attribute("block", Blocks.instance().getKey(getBlock(x, y)));
tile.attribute("meta", getMeta(x, y));
tile.pop();
}
}
tiles.pop();
writer.pop();
w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void load(FileHandle file) {
if (!file.exists()) {
Main.logger.warn("level + \"" + file.path() + "\" does not exist!");
return;
}
levelfile = file.nameWithoutExtension();
prepare();
entities.clear();
ParticlePool.instance().getPool().freeAll(particles);
XmlReader parser = new XmlReader();
Element root = null;
try {
root = parser.parse(file);
} catch (IOException e2) {
e2.printStackTrace();
}
Element essentials = root.getChildByName("essentials");
sizex = Integer.parseInt(essentials.getAttribute("sizex"));
sizey = Integer.parseInt(essentials.getAttribute("sizey"));
tickTime = -1;
background = essentials.getAttribute("bg", "levelbgcircuit");
prepare();
Array<Element> elements = root.getChildByName("tiles").getChildrenByName("tile");
for (Element tile : elements) {
setBlock(Blocks.instance().getBlock(tile.getAttribute("block")),
Integer.parseInt(tile.getAttribute("x")),
Integer.parseInt(tile.getAttribute("y")));
int meta = tile.getIntAttribute("meta", 0);
setMeta(meta, Integer.parseInt(tile.getAttribute("x")),
Integer.parseInt(tile.getAttribute("y")));
}
entities.clear();
if (getPlayer() == null) {
this.addPlayer();
getPlayer().x = -8;
getPlayer().y = -8;
}
for (int x = 0; x < sizex; x++) {
for (int y = 0; y < sizey; y++) {
if (getBlock(x, y) instanceof BlockPlayerSpawner) {
camera.forceCenterOn((x + 0.5f) * tilesizex, (y + 0.5f) * tilesizey
- (tilesizey * 3));
}
}
}
System.gc();
}
@Override
@Deprecated
public boolean canMoveDirectly(Mover mover, int sx, int sy, int tx, int ty) {
if (blocked(mover, tx, ty)) return false;
return true;
}
public Array<Entity> getEntities() {
return entities;
}
}