Initial upload

This commit is contained in:
Anuken
2017-04-29 21:25:59 -04:00
commit 74e0680841
200 changed files with 5268 additions and 0 deletions

View File

@@ -0,0 +1,381 @@
package io.anuke.moment;
import static io.anuke.moment.world.TileType.tilesize;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import io.anuke.gif.GifRecorder;
import io.anuke.moment.ai.Pathfind;
import io.anuke.moment.entities.Enemy;
import io.anuke.moment.entities.TileEntity;
import io.anuke.moment.resource.ItemStack;
import io.anuke.moment.world.Tile;
import io.anuke.moment.world.TileType;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.graphics.Atlas;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.modules.RendererModule;
import io.anuke.ucore.scene.style.Styles;
import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timers;
public class Control extends RendererModule<Moment>{
GifRecorder recorder = new GifRecorder(batch);
int rangex = 10, rangey = 10;
float breaktime = 0;
float breakdur = 50;
public Control() {
atlas = new Atlas("moment.atlas");
cameraScale = 4f;
setPixelation();
buffers.add("shadow", (int) (Gdx.graphics.getWidth() / cameraScale), (int) (Gdx.graphics.getHeight() / cameraScale));
}
@Override
public void init(){
DrawContext.font = Styles.styles.font();
Entities.initPhysics(0, 0, main.pixsize, main.pixsize);
Effect.addDraw("place", 16, e -> {
Draw.thickness(3f - e.ifract() * 2f);
Draw.square(e.x, e.y, TileType.tilesize / 2 + e.ifract() * 3f);
Draw.clear();
});
Effect.addDraw("spark", 10, e -> {
Draw.thickness(1f);
Draw.color(Hue.mix(Color.WHITE, Color.GRAY, e.ifract()));
Draw.spikes(e.x, e.y, e.ifract() * 5f, 2, 8);
Draw.clear();
});
Effect.addDraw("smelt", 10, e -> {
Draw.thickness(1f);
Draw.color(Hue.mix(Color.YELLOW, Color.RED, e.ifract()));
Draw.spikes(e.x, e.y, e.ifract() * 5f, 2, 8);
Draw.clear();
});
Effect.addDraw("break", 12, e -> {
Draw.thickness(2f);
Draw.color(Color.WHITE, Color.GRAY, e.ifract());
Draw.spikes(e.x, e.y, e.ifract() * 5f, 2, 5);
Draw.clear();
});
Effect.addDraw("hit", 10, e -> {
Draw.thickness(1f);
Draw.color(Hue.mix(Color.WHITE, Color.ORANGE, e.ifract()));
Draw.spikes(e.x, e.y, e.ifract() * 3f, 2, 8);
Draw.clear();
});
Effect.addDraw("explosion", 15, e -> {
Draw.thickness(2f);
Draw.color(Hue.mix(Color.ORANGE, Color.GRAY, e.ifract()));
Draw.spikes(e.x, e.y, 2f + e.ifract() * 3f, 4, 6);
Draw.circle(e.x, e.y, 3f + e.ifract() * 3f);
Draw.clear();
});
Effect.addDraw("ind", 100, e -> {
Draw.thickness(3f);
Draw.color("royal");
Draw.circle(e.x, e.y, 3);
Draw.clear();
});
Pathfind.updatePath();
}
public void tryMove(SolidEntity e, float x, float y){
e.getBoundingBox(Rectangle.tmp);
Rectangle.tmp.setSize(Rectangle.tmp.width * 0.5f);
if(!overlaps(Rectangle.tmp, e.x + x, e.y)){
e.x += x;
}
if(!overlaps(Rectangle.tmp, e.x, e.y + y)){
e.y += y;
}
}
boolean overlaps(Rectangle rect, float x, float y){
int r = 1;
rect.setCenter(x, y);
int tilex = Mathf.scl2(x, tilesize);
int tiley = Mathf.scl2(y, tilesize);
for(int dx = -r; dx <= r; dx++){
for(int dy = -r; dy <= r; dy++){
Tile tile = main.tile(tilex + dx, tiley + dy);
if(tile != null && tile.block().solid && Rectangle.tmp2.setSize(tilesize).setCenter(tile.worldx(), tile.worldy()).overlaps(rect)){
return true;
}
}
}
return false;
}
Rectangle getRect(int x, int y){
return Rectangle.tmp2.setSize(tilesize).setCenter(x * tilesize, y * tilesize);
}
void input(){
if(UInput.keyUp("rotate"))
main.rotation++;
main.rotation %= 4;
if(main.recipe != null && !main.hasItems(main.recipe.requirements)){
main.recipe = null;
Cursors.restoreCursor();
}
if(UInput.keyUp(Keys.G))
new Enemy(0).set(main.player.x, main.player.y).add();
if(UInput.buttonUp(Buttons.LEFT) && main.recipe != null && validPlace(tilex(), tiley(), main.recipe.result) && !get(UI.class).hasMouse()){
Tile tile = main.tile(tilex(), tiley());
if(tile == null)
return; //just in ase
tile.setBlock(main.recipe.result);
tile.rotation = main.rotation;
Pathfind.updatePath();
Effects.effect("place", roundx(), roundy());
Effects.shake(2f, 2f);
for(ItemStack stack : main.recipe.requirements){
main.removeItem(stack);
}
if(!main.hasItems(main.recipe.requirements)){
main.recipe = null;
Cursors.restoreCursor();
}
}
if(main.recipe != null && UInput.buttonUp(Buttons.RIGHT)){
main.recipe = null;
Cursors.restoreCursor();
}
//block breaking
if(UInput.buttonDown(Buttons.RIGHT) && cursorNear() && main.tile(tilex(), tiley()).artifical()
&& main.tile(tilex(), tiley()).block() != TileType.core){
Tile tile = main.tile(tilex(), tiley());
breaktime += delta();
if(breaktime >= breakdur){
Effects.effect("break", tile.entity);
Effects.shake(3f, 1f);
tile.setBlock(TileType.air);
Pathfind.updatePath();
breaktime = 0f;
}
}else{
breaktime = 0f;
}
}
float roundx(){
return Mathf.round2(UGraphics.mouseWorldPos().x, TileType.tilesize);
}
float roundy(){
return Mathf.round2(UGraphics.mouseWorldPos().y, TileType.tilesize);
}
int tilex(){
return Mathf.scl2(UGraphics.mouseWorldPos().x, TileType.tilesize);
}
int tiley(){
return Mathf.scl2(UGraphics.mouseWorldPos().y, TileType.tilesize);
}
boolean validPlace(int x, int y, TileType tile){
if(!cursorNear())
return false;
for(SolidEntity e : Entities.getNearby(x * tilesize, y * tilesize, tilesize * 2f)){
Rectangle.tmp.setSize(e.hitsize);
Rectangle.tmp.setCenter(e.x, e.y);
if(getRect(x, y).overlaps(Rectangle.tmp)){
return false;
}
}
return main.tiles[x][y].block() == TileType.air;
}
boolean cursorNear(){
return Vector2.dst(main.player.x, main.player.y, tilex() * tilesize, tiley() * tilesize) <= main.placerange;
}
@Override
public void update(){
if(Gdx.input.isKeyJustPressed(Keys.ESCAPE))
Gdx.app.exit();
Entities.update();
input();
camera.position.set(main.player.x, main.player.y, 0f);
clampCamera(-tilesize / 2f, -tilesize / 2f, main.pixsize - tilesize / 2f, main.pixsize - tilesize / 2f);
drawDefault();
recorder.update();
}
@Override
public void draw(){
Draw.clear();
for(int l = 0; l < 4; l++){
if(l == 1){
batch.end();
buffers.end("pixel");
buffers.begin("shadow");
batch.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
for(int x = -rangex; x <= rangex; x++){
for(int y = -rangey; y <= rangey; y++){
int worldx = Mathf.scl(camera.position.x, tilesize) + x;
int worldy = Mathf.scl(camera.position.y, tilesize) + y;
if(Mathf.inBounds(worldx, worldy, main.tiles)){
Tile tile = main.tiles[worldx][worldy];
if(l == 1){
if(tile.block() != TileType.air)
Draw.rect("shadow", worldx * tilesize, worldy * tilesize);
}else if(l == 0 || l == 2){
(l == 0 ? tile.floor() : tile.block()).draw(tile);
}else{
tile.block().drawOver(tile);
}
}
}
}
if(l == 1){
batch.end();
buffers.end("shadow");
batch.setColor(0, 0, 0, 0.15f);
buffers.begin("pixel");
drawFull("shadow");
batch.setColor(Color.WHITE);
batch.setProjectionMatrix(camera.combined);
batch.begin();
}
}
Entities.draw();
if(main.recipe != null && !get(UI.class).hasMouse()){
float x = Mathf.round2(UGraphics.mouseWorldPos().x, tilesize);
float y = Mathf.round2(UGraphics.mouseWorldPos().y, tilesize);
boolean valid = validPlace(tilex(), tiley(), main.recipe.result);
Draw.color(valid ? Color.PURPLE : Color.SCARLET);
Draw.thickness(2f);
Draw.square(x, y, TileType.tilesize / 2 + MathUtils.sin(Timers.time() / 6f) + 1);
if(main.recipe.result.rotate){
Draw.color("orange");
vector.set(7, 0).rotate(main.rotation * 90);
Draw.line(x, y, x + vector.x, y + vector.y);
}
if(valid)
Cursors.setHand();
else
Cursors.restoreCursor();
}
//block breaking
if(UInput.buttonDown(Buttons.RIGHT) && cursorNear()){
Tile tile = main.tile(tilex(), tiley());
if(tile.artifical() && tile.block() != TileType.core){
Draw.color(Color.YELLOW, Color.SCARLET, breaktime / breakdur);
Draw.square(tile.worldx(), tile.worldy(), 4);
Draw.clear();
}
}
if(main.recipe == null && !get(UI.class).hasMouse()){
Tile tile = main.tiles[tilex()][tiley()];
if(tile.block() != TileType.air){
if(tile.block().name().contains("turret")){
Draw.color("green");
Draw.dashcircle(tile.worldx(), tile.worldy(), tile.block().range);
Draw.clear();
}
if(tile.entity != null)
drawHealth(tile.entity);
}
}
for(Entity entity : Entities.all()){
if(entity instanceof DestructibleEntity && !(entity instanceof TileEntity)){
DestructibleEntity dest = ((DestructibleEntity) entity);
drawHealth(dest);
}
}
//Draw.text(Gdx.graphics.getFramesPerSecond() + " FPS", main.player.x, main.player.y);
}
void drawHealth(DestructibleEntity dest){
float len = 3;
float offset = 7;
Draw.thickness(3f);
Draw.color(Color.GRAY);
Draw.line(dest.x - len + 1, dest.y - offset, dest.x + len + 1, dest.y - offset);
Draw.thickness(1f);
Draw.color(Color.BLACK);
Draw.line(dest.x - len + 1, dest.y - offset, dest.x + len, dest.y - offset);
Draw.color(Color.RED);
Draw.line(dest.x - len + 1, dest.y - offset, dest.x - len + len * 2 * ((float) dest.health / dest.maxhealth), dest.y - offset);
Draw.clear();
}
@Override
public void resize(int width, int height){
super.resize(width, height);
buffers.remove("shadow");
buffers.add("shadow", (int) (Gdx.graphics.getWidth() / cameraScale), (int) (Gdx.graphics.getHeight() / cameraScale));
rangex = (int) (width / tilesize / cameraScale);
rangey = (int) (height / tilesize / cameraScale);
}
}

View File

@@ -0,0 +1,169 @@
package io.anuke.moment;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.aabb.Collider;
import io.anuke.moment.entities.Enemy;
import io.anuke.moment.entities.Player;
import io.anuke.moment.resource.Item;
import io.anuke.moment.resource.ItemStack;
import io.anuke.moment.resource.Recipe;
import io.anuke.moment.world.Generator;
import io.anuke.moment.world.Tile;
import io.anuke.moment.world.TileType;
import io.anuke.ucore.core.KeyBinds;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.UInput;
import io.anuke.ucore.modules.ModuleController;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timers;
public class Moment extends ModuleController<Moment>{
public static Moment i;
public Player player;
public int size = 128;
public int pixsize = size*TileType.tilesize;
public Tile[][] tiles = new Tile[size][size];
public ObjectMap<Item, Integer> items = new ObjectMap<>();
public Recipe recipe;
public int rotation;
public float placerange = 60;
public int wave = 1;
public float wavespace = 2000/100;
public float wavetime = wavespace;
public Tile core;
public Array<Tile> spawnpoints = new Array<Tile>();
@Override
public void init(){
i = this;
addModule(new Control());
addModule(new UI());
}
@Override
public void setup(){
KeyBinds.defaults(
"up", Keys.W,
"left", Keys.A,
"down", Keys.S,
"right", Keys.D,
"rotate", Keys.R
);
Settings.loadAll("io.anuke.moment");
for(int x = 0; x < size; x ++){
for(int y = 0; y < size; y ++){
tiles[x][y] = new Tile(x, y, TileType.grass);
}
}
generate();
items.put(Item.stone, 200);
items.put(Item.iron, 200);
Collider.defaultDrag = 0.2f;
player = new Player().add();
player.x = core.worldx();
player.y = core.worldy()+10;
}
@Override
public void update(){
super.update();
if(Enemy.amount == 0)
wavetime -= delta();
if(wavetime < 0 || UInput.keyUp(Keys.F)){
runWave();
}
}
public void coreDestroyed(){
//TODO "you lose" message or something
}
void generate(){
Generator.generate(tiles, "map");
core.setBlock(TileType.core);
int x = core.x, y = core.y;
set(x, y-1, TileType.conveyor, 1);
set(x, y-2, TileType.router, 0);
set(x, y-3, TileType.conveyor, 1);
set(x, y-4, TileType.stonedrill, 0);
//just in case
tiles[x][y-4].setFloor(TileType.stone);
set(x+1, y-2, TileType.conveyor, 0);
set(x+2, y-2, TileType.conveyor, 1);
set(x+2, y-1, TileType.conveyor, 1);
set(x+2, y, TileType.turret, 0);
set(x-1, y-2, TileType.conveyor, 2);
set(x-2, y-2, TileType.conveyor, 1);
set(x-2, y-1, TileType.conveyor, 1);
set(x-2, y, TileType.turret, 0);
}
void set(int x, int y, TileType type, int rot){
tiles[x][y].setBlock(type);
tiles[x][y].rotation = rot;
}
public void runWave(){
int amount = 3*wave;
for(int i = 0; i < amount; i ++){
int point = i%spawnpoints.size;
Tile tile = spawnpoints.get(point);
Timers.run((int)(i/spawnpoints.size)*40f, ()->{
new Enemy(point).set(tile.worldx(), tile.worldy()).add();
});
}
wave ++;
wavetime = wavespace;
}
public Tile tile(int x, int y){
if(!Mathf.inBounds(x, y, tiles)) return null;
return tiles[x][y];
}
public Tile spawn(){
return tiles[size/2][size-1];
}
public void addItem(Item item, int amount){
items.put(item, items.get(item, 0)+amount);
get(UI.class).updateItems();
}
public boolean hasItems(ItemStack[] items){
for(ItemStack stack : items)
if(!hasItem(stack))
return false;
return true;
}
public boolean hasItem(ItemStack req){
return items.get(req.item, 0) >= req.amount;
}
public void removeItem(ItemStack req){
items.put(req.item, items.get(req.item, 0)-req.amount);
get(UI.class).updateItems();
}
}

View File

@@ -0,0 +1,194 @@
package io.anuke.moment;
import static io.anuke.moment.world.TileType.tilesize;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Align;
import io.anuke.moment.entities.Enemy;
import io.anuke.moment.resource.Item;
import io.anuke.moment.resource.ItemStack;
import io.anuke.moment.resource.Recipe;
import io.anuke.moment.world.Tile;
import io.anuke.moment.world.TileType;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.UGraphics;
import io.anuke.ucore.modules.SceneModule;
import io.anuke.ucore.scene.builders.*;
import io.anuke.ucore.scene.style.Styles;
import io.anuke.ucore.scene.ui.*;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Mathf;
public class UI extends SceneModule<Moment>{
Table itemtable;
public UI(){
Styles.styles.font().setUseIntegerPositions(false);
TooltipManager.getInstance().animations = false;
}
@Override
public void update(){
scene.getBatch().setProjectionMatrix(get(Control.class).camera.combined);
scene.getBatch().begin();
Tile tile = main.tiles[tilex()][tiley()];
if(tile.block() != TileType.air){
String error = tile.block().error(tile);
if(error != null){
Draw.tcolor(Color.SCARLET);
Draw.tscl(1/8f);
Draw.text(error, tile.worldx(), tile.worldy()+tilesize);
}else if(tile.block().name().contains("turret")){
Draw.tscl(1/8f);
Draw.tcolor(Color.GREEN);
Draw.text("Ammo: " + tile.entity.shots, tile.worldx(), tile.worldy()-tilesize);
}
Draw.tscl(0.5f);
Draw.clear();
}
scene.getBatch().end();
super.update();
}
@Override
public void init(){
build.begin(scene);
new table(){{
abottom();
aright();
new table(){{
get().background("button");
for(Recipe r : Recipe.values()){
Image image = new Image(Draw.region(r.result.name()));
new button(r.result.name(), ()->{
main.recipe = r;
}){{
get().clearChildren();
get().pad(10f);
get().add(image).size(42).padRight(4f);
Table table = new Table();
table.add(get().getLabel()).left();
get().add(table);
get().left();
ItemStack[] req = r.requirements;
for(ItemStack stack : req){
table.row();
table.add("[YELLOW]"+stack.amount +"x " +stack.item.name()).left();
}
get().getLabel().setAlignment(Align.left);
String description = r.result.description();
if(r.result.ammo != null){
description += "\n[SALMON]Ammo: " + r.result.ammo.name();
}
Table tiptable = new Table();
tiptable.background("button");
tiptable.add("[PURPLE]"+r.result.name(), 0.5f).left().padBottom(2f);
tiptable.row();
tiptable.add("[ORANGE]"+description).left();
tiptable.pad(8f);
Tooltip tip = new Tooltip(tiptable);
tip.setInstant(true);
get().addListener(tip);
Recipe current = r;
get().update(()->{
get().setDisabled(!main.hasItems(current.requirements));
//get().setTouchable(!main.hasItems(current.requirements) ? Touchable.disabled : Touchable.enabled);
});
}}.width(220f);
row();
}
get().pad(20f);
}}.right().bottom();
}}.end();
new table(){{
atop();
aleft();
itemtable = new table().top().left().get();
itemtable.background("button");
}}.end();
//wave table...
new table(){{
atop();
aright();
new table(){{
get().background("button");
new label("Wave 1"){{
get().setFontScale(1f);
get().update(()->{
get().setText("[YELLOW]Wave " + Moment.i.wave);
});
}}.left();
row();
new label("Time"){{
get().update(()->{
get().setText(Enemy.amount > 0 ?
Enemy.amount+" Enemies remaining" : "New wave in " + (int)(main.wavetime/60f));
});
}}.minWidth(150);
get().pad(8);
}};
}}.end();
updateItems();
build.end();
}
public void updateItems(){
itemtable.clear();
for(Item stack : main.items.keys()){
Image image = new Image(Draw.region("icon-" + stack.name()));
Label label = new Label(""+ main.items.get(stack));
label.setFontScale(1f);
itemtable.add(image).size(32);
itemtable.add(label);
itemtable.row();
}
}
float roundx(){
return Mathf.round2(UGraphics.mouseWorldPos().x, TileType.tilesize);
}
float roundy(){
return Mathf.round2(UGraphics.mouseWorldPos().y, TileType.tilesize);
}
int tilex(){
return Mathf.scl2(UGraphics.mouseWorldPos().x, TileType.tilesize);
}
int tiley(){
return Mathf.scl2(UGraphics.mouseWorldPos().y, TileType.tilesize);
}
}

View File

@@ -0,0 +1,22 @@
package io.anuke.moment.ai;
import com.badlogic.gdx.ai.pfa.Heuristic;
import io.anuke.moment.world.Tile;
import io.anuke.moment.world.TileType;
public class MHueristic implements Heuristic<Tile>{
//so this means that the cost of going through solids is 10x going through non solids
float multiplier = 10f;
@Override
public float estimate(Tile node, Tile other){
float cost = Math.abs(node.worldx() - other.worldx()) + Math.abs(node.worldy() - other.worldy());
//TODO balance multiplier
if(node.artifical() && node.block().solid) cost += TileType.tilesize*multiplier;
if(other.artifical() && other.block().solid) cost += TileType.tilesize*multiplier;
return cost;
}
}

View File

@@ -0,0 +1,38 @@
package io.anuke.moment.ai;
import com.badlogic.gdx.ai.pfa.Connection;
import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph;
import com.badlogic.gdx.utils.Array;
import io.anuke.moment.Moment;
import io.anuke.moment.world.Tile;
/**Tilegraph that ignores player-made tiles.*/
public class PassTileGraph implements IndexedGraph<Tile>{
private Array<Connection<Tile>> tempConnections = new Array<Connection<Tile>>();
@Override
public Array<Connection<Tile>> getConnections(Tile fromNode){
tempConnections.clear();
if(fromNode.block().solid && !fromNode.block().update)
return tempConnections;
for(Tile tile : fromNode.getNearby()){
if(tile != null && (!tile.block().solid || tile.block().update))
tempConnections.add(new TileConnection(fromNode, tile));
}
return tempConnections;
}
@Override
public int getIndex(Tile node){
return node.x+node.y*Moment.i.size;
}
@Override
public int getNodeCount(){
return Moment.i.size*Moment.i.size;
}
}

View File

@@ -0,0 +1,96 @@
package io.anuke.moment.ai;
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import io.anuke.moment.Moment;
import io.anuke.moment.entities.Enemy;
import io.anuke.moment.world.Tile;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
public class Pathfind{
static MHueristic heuristic = new MHueristic();
static TileGraph graph = new TileGraph();
static PassTileGraph passgraph = new PassTileGraph();
static IndexedAStarPathFinder<Tile> pathfinder = new IndexedAStarPathFinder<Tile>(graph);
static IndexedAStarPathFinder<Tile> passpathfinder = new IndexedAStarPathFinder<Tile>(passgraph);
static Array<DefaultGraphPath<Tile>> paths = new Array<>();
static Vector2 vector = new Vector2();
static public Vector2 find(Enemy enemy){
if(enemy.node == -1){
findNode(enemy);
}
//-1 is only possible here if both pathfindings failed, which should NOT happen
//check graph code
DefaultGraphPath<Tile> path = paths.get(enemy.spawn);
Tile target = path.get(enemy.node);
float dst = Vector2.dst(enemy.x, enemy.y, target.worldx(), target.worldy());
if(dst < 2){
if(enemy.node <= path.getCount()-2)
enemy.node ++;
target = path.get(enemy.node);
}
return vector.set(target.worldx(), target.worldy());
}
static public void updatePath(){
if(paths.size == 0){
for(int i = 0; i < Moment.i.spawnpoints.size; i ++){
DefaultGraphPath<Tile> path = new DefaultGraphPath<>();
paths.add(path);
}
}
int i = 0;
for(DefaultGraphPath<Tile> path : paths){
path.clear();
passpathfinder.searchNodePath(
Moment.i.spawnpoints.get(i),
Moment.i.core, heuristic, path);
//for(Tile tile : path){
// Effects.effect("ind", tile.worldx(), tile.worldy());
///}
i++;
}
for(Entity e : Entities.all()){
if(e instanceof Enemy){
findNode((Enemy)e);
}
}
}
static void findNode(Enemy enemy){
DefaultGraphPath<Tile> path = paths.get(enemy.spawn);
Tile closest = null;
float ldst = 0f;
int cindex = -1;
for(int i = 0; i < path.getCount(); i ++){
Tile tile = path.get(i);
float dst = Vector2.dst(tile.worldx(), tile.worldy(), enemy.x, enemy.y);
if(closest == null || dst < ldst){
ldst = dst;
closest = tile;
cindex = i;
}
}
enemy.node = cindex;
}
}

View File

@@ -0,0 +1,30 @@
package io.anuke.moment.ai;
import com.badlogic.gdx.ai.pfa.Connection;
import io.anuke.moment.world.Tile;
public class TileConnection implements Connection{
Tile a, b;
public TileConnection(Tile a, Tile b){
this.a = a;
this.b = b;
}
@Override
public float getCost(){
return Math.abs(a.worldx() - b.worldx()) + Math.abs(a.worldy() - b.worldy());
}
@Override
public Object getFromNode(){
return a;
}
@Override
public Object getToNode(){
return b;
}
}

View File

@@ -0,0 +1,36 @@
package io.anuke.moment.ai;
import com.badlogic.gdx.ai.pfa.Connection;
import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph;
import com.badlogic.gdx.utils.Array;
import io.anuke.moment.Moment;
import io.anuke.moment.world.Tile;
public class TileGraph implements IndexedGraph<Tile>{
private Array<Connection<Tile>> tempConnections = new Array<Connection<Tile>>();
@Override
public Array<Connection<Tile>> getConnections(Tile fromNode){
tempConnections.clear();
if(fromNode.block().solid && fromNode != Moment.i.core)
return tempConnections;
for(Tile tile : fromNode.getNearby()){
if(tile != null && (!tile.block().solid || tile == Moment.i.core))
tempConnections.add(new TileConnection(fromNode, tile));
}
return tempConnections;
}
@Override
public int getIndex(Tile node){
return node.x+node.y*Moment.i.size;
}
@Override
public int getNodeCount(){
return Moment.i.size*Moment.i.size;
}
}

View File

@@ -0,0 +1,32 @@
package io.anuke.moment.entities;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
public class Bullet extends BulletEntity{
BulletType type;
public Bullet(BulletType type, Entity owner, float x, float y, float angle){
super(owner, type.speed, angle);
set(x, y);
this.lifetime = type.lifetime;
this.type = type;
}
public void draw(){
type.draw(this);
}
@Override
public void collision(SolidEntity other){
super.collision(other);
type.collide(this);
}
@Override
public int getDamage(){
return type.damage;
}
}

View File

@@ -0,0 +1,51 @@
package io.anuke.moment.entities;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.entities.Effects;
public enum BulletType{
stone(1.5f, 2){
public void draw(Bullet b){
Draw.color("gray");
Draw.square(b.x, b.y, 1f);
Draw.clear();
}
},
iron(1.7f, 2){
public void draw(Bullet b){
Draw.color("gray");
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
small(1.5f, 1){
public void draw(Bullet b){
Draw.color("orange");
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
shot(2.4f, 2){
{lifetime=40;}
public void draw(Bullet b){
Draw.color(Color.GOLD);
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
};;
public float speed;
public int damage;
public float lifetime = 60;
private BulletType(float speed, int damage){
this.speed = speed;
this.damage = damage;
}
public void collide(Bullet b){
Effects.effect("hit", b);
}
public void draw(Bullet b){}
}

View File

@@ -0,0 +1,89 @@
package io.anuke.moment.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.moment.Control;
import io.anuke.moment.Moment;
import io.anuke.moment.ai.Pathfind;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.util.Timers;
public class Enemy extends DestructibleEntity{
public static int amount = 0;
public Vector2 direction = new Vector2();
public float xvelocity, yvelocity;
public float speed = 0.3f;
public int node = -1;
public Entity target;
public int spawn;
public float reload = 40;
public Enemy(int spawn){
this.spawn = spawn;
hitsize = 5;
maxhealth = 30;
heal();
amount ++;
}
void move(){
Vector2 vec = Pathfind.find(this);
vec.sub(x, y).setLength(speed);
Moment.module(Control.class).tryMove(this, vec.x*delta, vec.y*delta);
target = Entities.getClosest(x, y, 60, e->{
return (e instanceof TileEntity || e instanceof Player);
});
if(target != null){
if(Timers.get(this, reload))
new Bullet(BulletType.small, this, x, y, direction.angle()).add();
}
}
@Override
public boolean collides(SolidEntity other){
return (other instanceof Bullet) && !(((Bullet)other).owner instanceof Enemy);
}
@Override
public void onDeath(){
Effects.effect("explosion", this);
Effects.shake(3f, 4f);
remove();
}
@Override
public void removed(){
amount --;
}
@Override
public void update(){
float lastx = x, lasty = y;
move();
xvelocity = x - lastx;
yvelocity = y-lasty;
if(target == null){
direction.add(xvelocity, yvelocity);
direction.limit(speed*8);
}else{
float angle = angleTo(target);
direction.lerp(vector.set(0, 1).setAngle(angle), 0.25f);
}
}
@Override
public void draw(){
Draw.rect("mech1", x, y, direction.angle()-90);
}
}

View File

@@ -0,0 +1,74 @@
package io.anuke.moment.entities;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.math.Vector2;
import io.anuke.moment.Control;
import io.anuke.moment.Moment;
import io.anuke.moment.UI;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.UInput;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.util.Angles;
public class Player extends DestructibleEntity{
Vector2 direction = new Vector2();
float speed = 2f;
float rotation;
float reload;
Weapon weapon = Weapon.blaster;
public Player(){
hitsize = 5;
maxhealth = 100;
heal();
}
@Override
public void removed(){
}
@Override
public void draw(){
Draw.rect("player", x, y, direction.angle()-90);
}
@Override
public void update(){
vector.set(0, 0);
if(UInput.keyDown("up"))
vector.y += speed;
if(UInput.keyDown("down"))
vector.y -= speed;
if(UInput.keyDown("left"))
vector.x -= speed;
if(UInput.keyDown("right"))
vector.x += speed;
reload -= delta;
boolean shooting = UInput.buttonDown(Buttons.LEFT) && Moment.i.recipe == null && !Moment.module(UI.class).hasMouse();
if(shooting && reload <= 0){
weapon.shoot(this);
reload = weapon.reload;
}
vector.limit(speed);
//x += vector.x*delta;
//y += vector.y*delta;
Moment.module(Control.class).tryMove(this, vector.x*delta, vector.y*delta);
if(!shooting){
direction.add(vector.scl(delta));
direction.limit(speed*6);
}else{
float angle = Angles.mouseAngle(x, y);
direction.lerp(vector.set(0, 1).setAngle(angle), 0.26f);
}
}
}

View File

@@ -0,0 +1,96 @@
package io.anuke.moment.entities;
import com.badlogic.gdx.utils.DelayedRemovalArray;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.moment.Moment;
import io.anuke.moment.ai.Pathfind;
import io.anuke.moment.resource.Item;
import io.anuke.moment.world.Tile;
import io.anuke.moment.world.TileType;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.entities.Effects;
import io.anuke.ucore.entities.SolidEntity;
public class TileEntity extends DestructibleEntity{
public final Tile tile;
public DelayedRemovalArray<ItemPos> convey = new DelayedRemovalArray<>();
public ObjectMap<Item, Integer> items = new ObjectMap<>();
public int shots;
public TileEntity link;
public float rotation;
public TileEntity(Tile tile){
this.tile = tile;
x = tile.worldx();
y = tile.worldy();
hitsize = TileType.tilesize;
maxhealth = tile.block().health;
heal();
}
@Override
public boolean collides(SolidEntity other){
return (other instanceof Bullet) && ((Bullet)other).owner instanceof Enemy;
}
@Override
public void onDeath(){
if(tile.block() == TileType.core){
Moment.i.coreDestroyed();
}
tile.setBlock(TileType.air);
Pathfind.updatePath();
Effects.shake(4f, 4f);
Effects.effect("explosion", this);
}
@Override
public void update(){
tile.block().update(tile);
}
public int totalItems(){
int sum = 0;
for(Item item : Item.values()){
sum += items.get(item, 0);
}
return sum;
}
public boolean hasItem(Item item){
return items.get(item, 0) > 0;
}
public void addItem(Item item, int amount){
items.put(item, items.get(item, 0) + amount);
}
public void removeItem(Item item, int amount){
items.put(item, items.get(item, 0) - amount);
}
public void addConvey(Item item){
addConvey(item, 0);
}
public void addConvey(Item item, float pos){
ItemPos posa = new ItemPos(item);
posa.pos = pos;
convey.add(posa);
}
public void removeConvey(ItemPos pos){
convey.removeValue(pos, true);
}
static public class ItemPos{
public Item item;
public float pos;
public ItemPos(Item item){
this.item = item;
}
}
}

View File

@@ -0,0 +1,28 @@
package io.anuke.moment.entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.util.Angles;
public enum Weapon{
blaster(15, BulletType.shot){
{
unlocked = true;
}
};
public float reload;
public BulletType type;
public boolean unlocked;
private Weapon(float reload, BulletType type){
this.reload = reload;
this.type = type;
}
public void shoot(Player p){
bullet(p, p.x, p.y);
}
void bullet(Entity owner, float x, float y){
new Bullet(type, owner, x, y, Angles.mouseAngle(owner.x, owner.y)).add();
}
}

View File

@@ -0,0 +1,5 @@
package io.anuke.moment.resource;
public enum Item{
stone, iron, coal, steel;
}

View File

@@ -0,0 +1,12 @@
package io.anuke.moment.resource;
public class ItemStack{
public Item item;
public int amount;
public float pos;
public ItemStack(Item item, int amount){
this.item = item;
this.amount = amount;
}
}

View File

@@ -0,0 +1,30 @@
package io.anuke.moment.resource;
import io.anuke.moment.world.TileType;
public enum Recipe{
stonewall(TileType.stonewall, stack(Item.stone, 4)),
ironwall(TileType.ironwall, stack(Item.iron, 4)),
drill(TileType.stonedrill, stack(Item.stone, 5)),
irondrill(TileType.irondrill, stack(Item.stone, 30)),
coaldrill(TileType.coaldrill, stack(Item.stone, 30), stack(Item.iron, 30)),
conveyor(TileType.conveyor, stack(Item.stone, 1)),
router(TileType.router, stack(Item.stone, 3)),
smelter(TileType.smelter, stack(Item.stone, 40), stack(Item.iron, 40)),
healturret(TileType.healturret, stack(Item.iron, 20)),
turret(TileType.turret, stack(Item.stone, 4)),
dturret(TileType.doubleturret, stack(Item.stone, 6)),
machineturret(TileType.machineturret, stack(Item.iron, 8), stack(Item.stone, 6));
public TileType result;
public ItemStack[] requirements;
private Recipe(TileType result, ItemStack... requirements){
this.result = result;
this.requirements = requirements;
}
private static ItemStack stack(Item item, int amount){
return new ItemStack(item, amount);
}
}

View File

@@ -0,0 +1,52 @@
package io.anuke.moment.world;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.math.MathUtils;
import io.anuke.moment.Moment;
import io.anuke.ucore.noise.Noise;
public class Generator{
static final int black = Color.rgba8888(Color.BLACK);
static final int white = Color.rgba8888(Color.WHITE);
static final int red = Color.rgba8888(Color.RED);
static final int blue = Color.rgba8888(Color.BLUE);
public static void generate(Tile[][] tiles, String mapname){
Pixmap pix = new Pixmap(Gdx.files.internal("maps/"+mapname+".png"));
Noise.setSeed(MathUtils.random(0, 99999));
for(int x = 0; x < tiles.length; x ++){
for(int y = 0; y < tiles.length; y ++){
TileType floor = TileType.stone;
TileType block = TileType.air;
int color = pix.getPixel(x, pix.getHeight()-1-y);
if(Noise.nnoise(x, y, 8, 1) > 0.22){
floor = TileType.iron;
}
if(Noise.nnoise(x, y, 6, 1) > 0.245){
floor = TileType.coal;
}
if(color == white){
block = TileType.dirtblock;
}else if(color == blue){
Moment.i.core = tiles[x][y];
}else if(color == red){
Moment.i.spawnpoints.add(tiles[x][y]);
}
tiles[x][y].setBlock(block);
tiles[x][y].setFloor(floor);
}
}
pix.dispose();
}
}

View File

@@ -0,0 +1,74 @@
package io.anuke.moment.world;
import io.anuke.moment.Moment;
import io.anuke.moment.entities.TileEntity;
public class Tile{
private static Tile[] tiles = new Tile[4];
private TileType floor = TileType.air;
private TileType block = TileType.air;
public TileEntity entity;
public int x, y, rotation;
public Tile(int x, int y){
this.x = x;
this.y = y;
}
public Tile(int x, int y, TileType floor){
this(x, y);
this.floor = floor;
}
public int id(){
return x + y * Moment.i.size;
}
public float worldx(){
return x * TileType.tilesize;
}
public float worldy(){
return y * TileType.tilesize;
}
public TileType floor(){
return floor;
}
public TileType block(){
return block;
}
public void setBlock(TileType type){
this.block = type;
changed();
}
public void setFloor(TileType type){
this.floor = type;
}
public boolean artifical(){
return block.update;
}
public Tile[] getNearby(){
tiles[0] = Moment.i.tile(x+1, y);
tiles[1] = Moment.i.tile(x, y+1);
tiles[2] = Moment.i.tile(x-1, y);
tiles[3] = Moment.i.tile(x, y-1);
return tiles;
}
public void changed(){
//TODO where do the items go?
if(entity != null)
entity.remove();
if(block.update)
entity = new TileEntity(this).add();
}
}

View File

@@ -0,0 +1,571 @@
package io.anuke.moment.world;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import io.anuke.moment.Moment;
import io.anuke.moment.entities.*;
import io.anuke.moment.entities.TileEntity.ItemPos;
import io.anuke.moment.resource.Item;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timers;
public enum TileType{
air{
//nothing gets drawn
public void draw(Tile tile){
}
},
grass, stone, dirt, iron, coal, dirtblock(true), stoneblock(true), stonewall(true, true){
{
health = 50;
}
},
ironwall(true, true){
{
health = 80;
}
},
stonedrill(true, true){
public void update(Tile tile){
if(tile.floor() == TileType.stone && Timers.get(tile, 60 * 6)){
offloadNear(tile, Item.stone);
Effects.effect("spark", tile.x * tilesize, tile.y * tilesize);
}
if(Timers.get(tile.hashCode() + "dump", 30)){
tryDump(tile);
}
}
public String description(){
return "Mines 1 stone every 6 seconds.";
}
public String error(Tile tile){
if(tile.floor() != TileType.stone)
return "Not on stone block!";
return null;
}
},
irondrill(true, true){
public void update(Tile tile){
if(tile.floor() == TileType.iron && Timers.get(tile, 60 * 6)){
offloadNear(tile, Item.iron);
Effects.effect("spark", tile.x * tilesize, tile.y * tilesize);
}
if(Timers.get(tile.hashCode() + "dump", 30)){
tryDump(tile);
}
}
public String description(){
return "Mines 1 iron every 6 seconds.";
}
public String error(Tile tile){
if(tile.floor() != TileType.iron)
return "Not on iron ore block!";
return null;
}
},
coaldrill(true, true){
public void update(Tile tile){
if(tile.floor() == TileType.coal && Timers.get(tile, 60 * 6)){
offloadNear(tile, Item.coal);
Effects.effect("spark", tile.x * tilesize, tile.y * tilesize);
}
if(Timers.get(tile.hashCode() + "dump", 30)){
tryDump(tile);
}
}
public String description(){
return "Mines 1 coal every 6 seconds.";
}
public String error(Tile tile){
if(tile.floor() != TileType.coal)
return "Not on coal block!";
return null;
}
},
conveyor(false, true, true){
float speed = 0.02f;
public void draw(Tile tile){
Draw.rect(name() + (Timers.time() % ((20 / 100f) / speed) < (10 / 100f) / speed ? "" : "move"), tile.worldx(), tile.worldy(), tile.rotation * 90);
vector.set(tilesize, 0).rotate(tile.rotation * 90);
vector2.set(-tilesize / 2, 0).rotate(tile.rotation * 90);
for(ItemPos pos : tile.entity.convey){
Draw.rect("icon-" + pos.item.name(), tile.x * tilesize + vector.x * pos.pos + vector2.x, tile.y * tilesize + vector.y * pos.pos + vector2.y, 4, 4);
}
}
public void update(Tile tile){
tile.entity.convey.begin();
for(ItemPos pos : tile.entity.convey){
pos.pos += speed * Gdx.graphics.getDeltaTime() * 60f;
if(pos.pos >= 1f && offloadDir(tile, pos.item)){
tile.entity.removeConvey(pos);
continue;
}
pos.pos = Mathf.clamp(pos.pos);
}
tile.entity.convey.end();
}
@Override
public boolean accepts(Item item){
return true;
}
public String description(){
return "Moves Items";
}
@Override
void handleItem(Tile tile, Item item, float f){
tile.entity.addConvey(item, f);
}
},
steelconveyor(false, true, true){
float speed = 0.03f;
public void draw(Tile tile){
Draw.rect(name() + (Timers.time() % ((20 / 100f) / speed) < (10 / 100f) / speed ? "" : "move"), tile.worldx(), tile.worldy(), tile.rotation * 90);
vector.set(tilesize, 0).rotate(tile.rotation * 90);
vector2.set(-tilesize / 2, 0).rotate(tile.rotation * 90);
for(ItemPos pos : tile.entity.convey){
Draw.rect("icon-" + pos.item.name(), tile.x * tilesize + vector.x * pos.pos + vector2.x, tile.y * tilesize + vector.y * pos.pos + vector2.y, 4, 4);
}
}
public void update(Tile tile){
tile.entity.convey.begin();
for(ItemPos pos : tile.entity.convey){
pos.pos += speed * Gdx.graphics.getDeltaTime() * 60f;
if(pos.pos >= 1f && offloadDir(tile, pos.item)){
tile.entity.removeConvey(pos);
continue;
}
pos.pos = Mathf.clamp(pos.pos);
}
tile.entity.convey.end();
}
@Override
public boolean accepts(Item item){
return true;
}
public String description(){
return "Moves Items (faster than a normal conveyor!)";
}
@Override
void handleItem(Tile tile, Item item, float f){
tile.entity.addConvey(item, f);
}
},
router(true, true, false){
public void update(Tile tile){
if(Timers.get(tile, 20) && tile.entity.totalItems() > 0){
tryDump(tile, tile.rotation++);
tile.rotation %= 4;
}
}
@Override
public boolean accepts(Item item){
return true;
}
public String description(){
return "Splits conveyor belt input";
}
},
smelter(true, true, false){
{health=70;}
public void update(Tile tile){
if(tile.entity.hasItem(Item.coal) && tile.entity.hasItem(Item.iron)){
tile.entity.removeItem(Item.coal, 1);
tile.entity.removeItem(Item.iron, 1);
offloadNear(tile, Item.steel);
Effects.effect("smelt", tile.entity);
}
if(Timers.get(tile, 20) && tile.entity.hasItem(Item.steel)){
tryDump(tile);
}
}
@Override
public boolean accepts(Item item){
return item == Item.iron || item == Item.coal;
}
public String description(){
return "Smelts iron and coal into steel";
}
},
core(true, true, false){
{
health = 300;
}
@Override
void handleItem(Tile tile, Item item, float f){
Moment.i.addItem(item, 1);
}
@Override
public boolean accepts(Item item){
return true;
}
},
turret(true, true, false){
{
range = 40;
reload = 10f;
bullet = BulletType.stone;
ammo = Item.stone;
}
public void update(Tile tile){
updateTurret(tile);
}
public void draw(Tile tile){
Draw.rect("block", tile.worldx(), tile.worldy());
}
public void drawOver(Tile tile){
Draw.rect(name(), tile.worldx(), tile.worldy(), tile.entity.rotation - 90);
}
public String description(){
return "Shoots things.";
}
},
doubleturret(true, true, false){
{
range = 40;
reload = 10f;
bullet = BulletType.stone;
ammo = Item.stone;
health = 50;
}
public void update(Tile tile){
updateTurret(tile);
}
public void draw(Tile tile){
Draw.rect("block", tile.worldx(), tile.worldy());
}
public void drawOver(Tile tile){
Draw.rect(name(), tile.worldx(), tile.worldy(), tile.entity.rotation - 90);
}
public String description(){
return "Shoots things.";
}
},
machineturret(true, true, false){
{
range = 65;
reload = 5f;
bullet = BulletType.iron;
ammo = Item.iron;
health = 65;
}
public void update(Tile tile){
updateTurret(tile);
}
public void draw(Tile tile){
Draw.rect("block", tile.worldx(), tile.worldy());
}
public void drawOver(Tile tile){
Draw.rect(name(), tile.worldx(), tile.worldy(), tile.entity.rotation - 90);
}
public String description(){
return "Shoots things.";
}
},
healturret(true, true, false){
{
range = 30;
reload = 30f;
health = 50;
}
public void update(Tile tile){
/*
* if(tile.entity.hasItem(ammo)){ tile.entity.shots += 20;
* tile.entity.removeItem(ammo, 1); }
*/
//if(tile.entity.shots > 0){
tile.entity.link = findTileTarget(tile, range);
if(tile.entity.link != null){
tile.entity.rotation = tile.entity.angleTo(tile.entity.link);
if(Timers.get(tile, reload)){
tile.entity.link.health++;
}
}
//}
}
public void draw(Tile tile){
Draw.rect("block", tile.worldx(), tile.worldy());
}
public void drawOver(Tile tile){
if(tile.entity.link != null){
float x = tile.worldx(), y = tile.worldy();
float x2 = tile.entity.link.x, y2 = tile.entity.link.y;
Draw.color(Hue.rgb(138, 244, 138, (MathUtils.sin(Timers.time() / 2f) + 1f) / 15f));
Draw.alpha(0.3f);
Draw.thickness(4f);
Draw.line(x, y, x2, y2);
Draw.thickness(2f);
Draw.circle(x2, y2, 2f);
Draw.alpha(1f);
Draw.thickness(2f);
Draw.line(x, y, x2, y2);
Draw.thickness(1f);
Draw.circle(x2, y2, 1f);
Draw.clear();
}
Draw.rect(name(), tile.worldx(), tile.worldy(), tile.entity.rotation - 90);
}
public String description(){
return "Heals nearby tiles.";
}
};
static Vector2 vector = new Vector2();
static Vector2 vector2 = new Vector2();
public boolean solid, update, rotate;
public static final int tilesize = 8;
public int health = 40;
//turrets
public float range = 50f;
public float reload = 10f;
public BulletType bullet;
public Item ammo;
private TileType() {
solid = false;
}
private TileType(boolean solid) {
this.solid = solid;
}
private TileType(boolean solid, boolean update) {
this.solid = solid;
this.update = update;
}
private TileType(boolean solid, boolean update, boolean rotate) {
this.solid = solid;
this.update = update;
this.rotate = rotate;
}
public void init(TileEntity entity){
}
void updateTurret(Tile tile){
if(tile.entity.hasItem(ammo)){
tile.entity.shots += 20;
tile.entity.removeItem(ammo, 1);
}
if(tile.entity.shots > 0){
Enemy enemy = findTarget(tile, range);
if(enemy != null){
tile.entity.rotation = MathUtils.lerpAngleDeg(tile.entity.rotation, Angles.predictAngle(tile.worldx(), tile.worldy(), enemy.x, enemy.y, enemy.xvelocity, enemy.yvelocity, bullet.speed - 0.1f), 0.2f);
if(Timers.get(tile, reload)){
new Bullet(bullet, tile.entity, tile.worldx(), tile.worldy(), tile.entity.rotation).add();
tile.entity.shots--;
}
}
}
}
Enemy findTarget(Tile tile, float range){
Entity closest = null;
float dst = 0;
Array<SolidEntity> array = Entities.getNearby(tile.worldx(), tile.worldy(), 100);
for(Entity e : array){
if(e instanceof Enemy){
float ndst = Vector2.dst(tile.worldx(), tile.worldy(), e.x, e.y);
if(ndst < range && (closest == null || ndst < dst)){
dst = ndst;
closest = e;
}
}
}
return (Enemy) closest;
}
TileEntity findTileTarget(Tile tile, float range){
Entity closest = null;
float dst = 0;
Array<SolidEntity> array = Entities.getNearby(tile.worldx(), tile.worldy(), 100);
for(Entity e : array){
if(e instanceof TileEntity && ((TileEntity) e).health < ((TileEntity) e).tile.block().health){
float ndst = Vector2.dst(tile.worldx(), tile.worldy(), e.x, e.y);
if(ndst < range && (closest == null || ndst < dst)){
dst = ndst;
closest = e;
}
}
}
return (TileEntity) closest;
}
void handleItem(Tile tile, Item item, float f){
tile.entity.addItem(item, 1);
}
/**
* Tries to put this item into a nearby container, if there are no available
* containers, it gets added to the block's inventory.
*/
void offloadNear(Tile tile, Item item){
int i = 0;
for(Tile other : tile.getNearby()){
if(other != null && other.block().accepts(item)
//don't output to things facing this thing
&& !(other.block().rotate && (other.rotation + 2) % 4 == i)){
other.block().handleItem(other, item, 0);
return;
}
i++;
}
handleItem(tile, item, 0);
}
/** Try dumping any item near the tile. */
boolean tryDump(Tile tile){
return tryDump(tile, -1);
}
/**
* Try dumping any item near the tile. -1 = any direction
*/
boolean tryDump(Tile tile, int direction){
int i = 0;
for(Tile other : tile.getNearby()){
if(i == direction || direction == -1)
for(Item item : Item.values()){
if(tile.entity.hasItem(item) && other != null && other.block().accepts(item) &&
//don't output to things facing this thing
!(other.block().rotate && (other.rotation + 2) % 4 == i)){
other.block().handleItem(other, item, 0);
tile.entity.removeItem(item, 1);
return true;
}
}
i++;
}
return false;
}
/**
* Try offloading an item to a nearby container. Returns true if success.
*/
boolean offloadDir(Tile tile, Item item){
Tile other = tile.getNearby()[tile.rotation];
if(other != null && other.block().accepts(item)){
int ch = Math.abs(other.rotation - tile.rotation);
other.block().handleItem(other, item, ch == 1 ? 0.5f : ch == 2 ? 1f : 0f);
//other.entity.addCovey(item, ch == 1 ? 0.5f : ch ==2 ? 1f : 0f);
return true;
}
return false;
}
public boolean accepts(Item item){
return item == ammo;
}
public String description(){
return "[no description]";
}
public void draw(Tile tile){
if(tile.floor() == this){
MathUtils.random.setSeed(tile.id());
Draw.rect(name() + MathUtils.random(1, 3), tile.worldx(), tile.worldy(), rotate ? tile.rotation * 90 : 0);
}else{
Draw.rect(name(), tile.worldx(), tile.worldy(), rotate ? tile.rotation * 90 : 0);
}
}
public String error(Tile tile){
if(ammo != null && !tile.entity.hasItem(ammo) && tile.entity.shots <= 0)
return "No ammo!";
return null;
}
public void drawOver(Tile tile){
/*
* String error = error(tile); if(error != null){ Draw.color("scarlet");
* Draw.square(tile.worldx(), tile.worldy(), 6); Draw.clear(); }
*/
}
public void update(Tile tile){
}
}