Renaming before uploading new code

This commit is contained in:
Anuken
2017-05-03 00:08:24 -04:00
parent f5e30f53e0
commit 883610d928
26 changed files with 155 additions and 168 deletions
+433
View File
@@ -0,0 +1,433 @@
package io.anuke.mindustry;
import static io.anuke.mindustry.world.TileType.tilesize;
import com.badlogic.gdx.Application.ApplicationType;
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.mindustry.ai.Pathfind;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.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));
Sounds.load("shoot.wav", "place.wav", "explosion.wav", "enemyshoot.wav", "corexplode.wav", "break.wav", "spawn.wav", "flame.wav");
Musics.load("1.mp3", "2.mp3", "3.mp3");
}
@Override
public void init(){
Musics.shuffleAll();
DrawContext.font = Styles.styles.font();
Entities.initPhysics(0, 0, main.pixsize, main.pixsize);
Effect.create("place", 16, e -> {
Draw.thickness(3f - e.ifract() * 2f);
Draw.square(e.x, e.y, TileType.tilesize / 2 + e.ifract() * 3f);
Draw.clear();
});
Effect.create("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.create("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.create("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.create("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.create("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.create("coreexplosion", 13, e -> {
Draw.thickness(3f-e.ifract()*2f);
Draw.color(Hue.mix(Color.ORANGE, Color.WHITE, e.ifract()));
Draw.spikes(e.x, e.y, 5f + e.ifract() * 40f, 6, 6);
Draw.circle(e.x, e.y, 4f + e.ifract() * 40f);
Draw.clear();
});
Effect.create("spawn", 23, e -> {
Draw.thickness(2f);
Draw.color(Hue.mix(Color.DARK_GRAY, Color.SCARLET, e.ifract()));
Draw.circle(e.x, e.y, 7f - e.ifract() * 6f);
Draw.clear();
});
Effect.create("ind", 100, e -> {
Draw.thickness(3f);
Draw.color("royal");
Draw.circle(e.x, e.y, 3);
Draw.clear();
});
Effect.create("respawn", main.respawntime, e -> {
Draw.tcolor(Color.SCARLET);
Draw.tscl(0.25f);
Draw.text("Respawning in " + (int)((e.lifetime-e.time)/60), e.x, e.y);
Draw.tscl(0.5f);
Draw.clear();
});
Pathfind.updatePath();
}
public void tryMove(SolidEntity e, float x, float y){
e.getBoundingBox(Rectangle.tmp);
Rectangle.tmp.setSize(4);
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(Inputs.keyUp("rotate"))
main.rotation++;
main.rotation %= 4;
if(main.recipe != null && !main.hasItems(main.recipe.requirements)){
main.recipe = null;
Cursors.restoreCursor();
}
if(Inputs.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);
Sounds.play("place");
for(ItemStack stack : main.recipe.requirements){
main.removeItem(stack);
}
if(!main.hasItems(main.recipe.requirements)){
main.recipe = null;
Cursors.restoreCursor();
}
}
if(main.recipe != null && Inputs.buttonUp(Buttons.RIGHT)){
main.recipe = null;
Cursors.restoreCursor();
}
//block breaking
if(Inputs.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;
Sounds.play("break");
}
}else{
breaktime = 0f;
}
}
float roundx(){
return Mathf.round2(Graphics.mouseWorld().x, TileType.tilesize);
}
float roundy(){
return Mathf.round2(Graphics.mouseWorld().y, TileType.tilesize);
}
int tilex(){
return Mathf.scl2(Graphics.mouseWorld().x, TileType.tilesize);
}
int tiley(){
return Mathf.scl2(Graphics.mouseWorld().y, TileType.tilesize);
}
boolean validPlace(int x, int y, TileType type){
if(!cursorNear())
return false;
for(Tile spawn : main.spawnpoints){
if(Vector2.dst(x * tilesize, y * tilesize, spawn.worldx(), spawn.worldy()) < main.spawnspace){
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.tile(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.getType() == ApplicationType.Desktop)
Gdx.app.exit();
if(!main.playing){
clearScreen();
return;
}
if(!main.paused)
Entities.update();
input();
if(main.core.block() == TileType.core)
camera.position.set(main.player.x, main.player.y, 0f);
else
camera.position.set(main.core.worldx(), main.core.worldy(), 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(Graphics.mouseWorld().x, tilesize);
float y = Mathf.round2(Graphics.mouseWorld().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);
}
Draw.thickness(1f);
Draw.color("scarlet");
for(Tile spawn : main.spawnpoints){
Draw.dashcircle(spawn.worldx(), spawn.worldy(), main.spawnspace);
}
if(valid)
Cursors.setHand();
else
Cursors.restoreCursor();
Draw.clear();
}
//block breaking
if(Inputs.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.x, tile.entity.y, tile.entity.health, tile.entity.maxhealth);
}
}
for(Entity entity : Entities.all()){
if(entity instanceof DestructibleEntity && !(entity instanceof TileEntity)){
DestructibleEntity dest = ((DestructibleEntity) entity);
drawHealth(dest.x, dest.y, dest.health, dest.maxhealth);
}
}
//Draw.text(Gdx.graphics.getFramesPerSecond() + " FPS", main.player.x, main.player.y);
}
void drawHealth(float x, float y, float health, float maxhealth){
float len = 3;
float offset = 7;
Draw.thickness(3f);
Draw.color(Color.GRAY);
Draw.line(x - len + 1, y - offset, x + len + 1, y - offset);
Draw.thickness(1f);
Draw.color(Color.BLACK);
Draw.line(x - len + 1, y - offset, x + len, y - offset);
Draw.color(Color.RED);
Draw.line(x - len + 1, y - offset, x - len + (int)(len * 2 * ((float) health / maxhealth)), 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/2)+2;
rangey = (int) (height / tilesize / cameraScale/2)+2;
}
}
+252
View File
@@ -0,0 +1,252 @@
package io.anuke.mindustry;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.world.Generator;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.TileType;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.Entities;
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 float respawntime = 60*5;
public int wave = 1;
public float wavespace = 35*60;
public float wavetime;
public float spawnspace = 65;
public Tile core;
public Array<Tile> spawnpoints = new Array<Tile>();
public boolean playing = false;
public boolean paused = false;
public boolean showedTutorial = false;
@Override
public void init(){
i = this;
addModule(new Control());
addModule(new UI());
}
@Override
public void preInit(){
KeyBinds.defaults(
"up", Keys.W,
"left", Keys.A,
"down", Keys.S,
"right", Keys.D,
"rotate", Keys.R,
"menu", Keys.ESCAPE
);
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);
}
}
player = new Player();
}
@Override
public void postInit(){
restart();
}
@Override
public void update(){
if(!paused)
super.update();
if(!playing || paused) return;
//if(UInput.keyUp(Keys.Q))
// System.out.println("Enemies: " + Enemy.amount + " Wavetime: " + wavetime + " Wave: " + wave + " Wavespace: " + wavespace);
//System.out.println(Enemy.amount);
if(Enemy.amount <= 0)
wavetime -= delta();
if(wavetime <= 0/* || UInput.keyUp(Keys.Q)*/){
runWave();
}
}
public void play(){
wavetime = waveSpacing();
if(showedTutorial){
playing = true;
paused = false;
}else{
playing = true;
paused = true;
get(UI.class).tutorial.show(get(UI.class).scene);
showedTutorial = true;
}
}
public void restart(){
wave = 1;
wavetime = waveSpacing();
Entities.clear();
Enemy.amount = 0;
player.add();
player.heal();
items.clear();
generate();
player.x = core.worldx();
player.y = core.worldy()-8;
items.put(Item.stone, 20);
//items.put(Item.stone, 2000);
//items.put(Item.iron, 2000);
//items.put(Item.steel, 2000);
if(get(UI.class).about != null)
get(UI.class).updateItems();
}
public void coreDestroyed(){
Effects.shake(5, 6);
Sounds.play("corexplode");
for(int i = 0; i < 16; i ++){
Timers.run(i*2, ()->{
Effects.effect("explosion", core.worldx()+Mathf.range(40), core.worldy()+Mathf.range(40));
});
}
Effects.effect("coreexplosion", core.worldx(), core.worldy());
Timers.run(60, ()->{
getModule(UI.class).showRestart();
});
}
void generate(){
spawnpoints.clear();
Pathfind.reset();
Generator.generate(tiles, "map");
Pathfind.updatePath();
core.setBlock(TileType.core);
int x = core.x, y = core.y;
set(x, y-1, TileType.conveyor, 1);
set(x, y-2, TileType.conveyor, 1);
set(x, y-3, TileType.conveyor, 1);
set(x, y-4, TileType.stonedrill, 0);
//just in case
tiles[x][y-4].setFloor(TileType.stone);
tiles[x+2][y-2].setFloor(TileType.stone);
set(x+2, y-2, TileType.stonedrill, 0);
set(x+2, y-1, TileType.conveyor, 1);
set(x+2, y, TileType.turret, 0);
tiles[x-2][y-2].setFloor(TileType.stone);
set(x-2, y-2, TileType.stonedrill, 0);
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 = wave;
Sounds.play("spawn");
for(int i = 0; i < amount; i ++){
int pos = i;
for(int w = 0; w < spawnpoints.size; w ++){
int point = w;
Tile tile = spawnpoints.get(w);
Timers.run(i*30f, ()->{
Enemy enemy = null;
if(wave%5 == 0 /*&& point == 1 */&& pos == 0){
enemy = new BossEnemy(point);
}else if(wave > 3 && pos < amount/2){
enemy = new FastEnemy(point);
}else if(wave > 8 && pos % 3 == 0 && wave%2==1){
enemy = new FlameEnemy(point);
}else{
enemy = new Enemy(point);
}
enemy.set(tile.worldx(), tile.worldy());
Effects.effect("spawn", enemy);
enemy.add();
});
}
}
wave ++;
wavetime = waveSpacing();
}
public float waveSpacing(){
int scale = Settings.getInt("difficulty");
float out = (scale == 0 ? 2f : scale == 1f ? 1f : 0.5f);
return wavespace*out;
}
public Tile tile(int x, int y){
if(!Mathf.inBounds(x, y, tiles)) return null;
return tiles[x][y];
}
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();
}
}
+488
View File
@@ -0,0 +1,488 @@
package io.anuke.mindustry;
import static io.anuke.mindustry.world.TileType.tilesize;
import java.util.function.BooleanSupplier;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.entities.Enemy;
import io.anuke.mindustry.resource.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.TileType;
import io.anuke.ucore.core.*;
import io.anuke.ucore.modules.SceneModule;
import io.anuke.ucore.scene.Scene;
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.Stack;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timers;
public class UI extends SceneModule<Moment>{
Table itemtable;
SettingsDialog prefs;
KeybindDialog keys;
Dialog about, menu, restart, tutorial;
Texture conveyor = new Texture("sprites/conveyor.png"), conveyort = new Texture("sprites/conveyort.png");
BooleanSupplier play = () -> {
return main.playing;
};
BooleanSupplier nplay = () -> {
return !main.playing;
};
public UI() {
Styles.styles.font().setUseIntegerPositions(false);
TooltipManager.getInstance().animations = false;
Dialog.closePadR = -1;
Dialog.closePadT = 4;
conveyor.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
conveyort.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
}
void drawBackground(){
Batch batch = scene.getBatch();
Draw.color();
int w = gwidth();
int h = gheight();
batch.draw(conveyor, 0, 0, (int)Timers.time(), 0, w, h);
int tw = w/64+1;//, th = h/64+1;
for(int x = 0; x < tw; x ++){
batch.draw(conveyort, x*64, 0, 0, (int)Timers.time(), 32, h);
}
Draw.tscl(1.5f);
Draw.text("[DARK_GRAY]-( Mindustry )-", w/2, h-16);
Draw.text("[#f1de60]-( Mindustry )-", w/2, h-10);
Draw.tscl(0.5f);
}
@Override
public void update(){
if(main.playing){
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().ammo != null){
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();
if(Inputs.keyUp("menu")){
if(menu.getScene() != null){
menu.hide();
main.paused = false;
}else{
main.paused = true;
menu.show(scene);
}
}
}else{
scene.getBatch().getProjectionMatrix().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
scene.getBatch().begin();
drawBackground();
scene.getBatch().end();
}
super.update();
}
@Override
public void init(){
prefs = new SettingsDialog();
prefs.sliderPref("screenshake", "Screen Shake", 4, 0, 12, i -> {
return (i / 4f) + "x";
});
prefs.sliderPref("difficulty", "Difficulty", 1, 0, 2, i -> {
return i == 0 ? "Easy" : i == 1 ? "Normal" : "Hard";
});
prefs.checkPref("fps", "Show FPS", false);
keys = new KeybindDialog();
about = new Dialog("About");
about.getContentTable().add("Made by [ROYAL]Anuken[] for the" + "\nGDL Metal Monstrosity jam.\n"
+ "\nSources used:"
+ "\n- [YELLOW]bfxr.com[] for sound effects"
+ "\n- [RED]freemusicarchive.org[] for music"
+ "\n- Music made by [GREEN]RoccoW[]"
);
about.addCloseButton();
tutorial = new Dialog("Tutorial", "dialog"){
@Override
public void hide(){
super.hide();
main.playing = true;
main.paused = false;
}
};
tutorial.addCloseButton();
tutorial.getButtonTable().addButton("OK", ()->{
tutorial.hide();
});
tutorial.content().add(
"[GREEN]Default Controls:[WHITE]\n[YELLOW][[WASD][] to move, [YELLOW][[R][] to rotate blocks."
+ "\nHold [YELLOW][[R-MOUSE][] to destroy blocks, click [YELLOW][[L-MOUSE][] to place them."
+ "\n[YELLOW][[L-MOUSE][] to shoot."
+ "\n\n[GOLD]Every 20 seconds, a new wave will appear."
+ "\nBuild turrets to defend the core."
+ "\nIf the core is destroyed, you lose the game."
+ "\n[LIME]To collect building resources, \nmove them into the core with conveyors."
+ "\n[LIME]Place [ORANGE]drills[] on the right material,\nthey will automatically mine material\nand dump it to nearby conveyors or turrets."
+ "\n\n[SCARLET]To produce steel, feed coal and iron into a smelter."
);
tutorial.content().pad(8);
restart = new Dialog("The core was destroyed.", "dialog"){
public Dialog show(Scene scene){
super.show(scene);
restart.content().clearChildren();
restart.content().add("You lasted until wave [GREEN]" + main.wave + "[].").pad(6);
restart.pack();
return this;
}
};
restart.getButtonTable().addButton("Back to menu", ()->{
restart.hide();
main.playing = false;
main.restart();
});
menu = new Dialog("Paused", "dialog");
menu.content().addButton("Back", ()->{
menu.hide();
main.paused = false;
}).width(200);
menu.content().row();
menu.content().addButton("Back to menu", ()->{
new Dialog("Confirm", "dialog"){
{
text("Are you sure you want to quit?");
button("Ok", true);
button("Cancel", false);
}
protected void result(Object object){
if(object == Boolean.TRUE){
menu.hide();
main.paused = false;
main.playing = false;
}
}
}.show(scene);
}).width(200);
build.begin(scene);
new table(){{
abottom();
aright();
new table(){{
get().background("button");
int rows = 3;
int maxcol = 0;
float size = 46;
Stack stack = new Stack();
ButtonGroup<ImageButton> group = new ButtonGroup<>();
Array<Recipe> recipes = new Array<Recipe>();
for(Section sec : Section.values()){
recipes.clear();
Recipe.getBy(sec, recipes);
maxcol = Math.max((int)((float)recipes.size/rows+1), maxcol);
}
for(Section sec : Section.values()){
recipes.clear();
Recipe.getBy(sec, recipes);
ImageButton button = new ImageButton("icon-"+sec.name(), "toggle");
add(button).size(size).height(size+8);
button.getImageCell().size(40).padBottom(4);
group.add(button);
Table table = new Table();
int i = 0;
for(Recipe r : recipes){
ImageButton image = new ImageButton(Draw.region(r.result.name()), "select");
image.clicked(()->{
if(main.hasItems(r.requirements))
main.recipe = r;
});
table.add(image).size(size+8).pad(4);
image.getImageCell().size(size);
image.update(()->{
boolean has = main.hasItems(r.requirements);
image.setDisabled(!has);
image.setChecked(main.recipe == r && has);
//image.setTouchable(has ? Touchable.enabled : Touchable.disabled);
image.getImage().setColor(has ? Color.WHITE : Color.GRAY);
});
if(i % rows == rows-1)
table.row();
i++;
Table tiptable = new Table();
Runnable run = ()->{
tiptable.clearChildren();
String description = r.result.description();
if(r.result.ammo != null){
description += "\n[SALMON]Ammo: " + r.result.ammo.name();
}
tiptable.background("button");
tiptable.add("[PURPLE]" + r.result.name(), 0.75f).left().padBottom(2f);
ItemStack[] req = r.requirements;
for(ItemStack s : req){
tiptable.row();
int amount = Math.min(main.items.get(s.item, 0), s.amount);
tiptable.add(
(amount >= s.amount ? "[YELLOW]" : "[RED]")
+s.item + ": " + amount + " / " +s.amount, 0.5f).left();
}
tiptable.row();
tiptable.add().size(10);
tiptable.row();
tiptable.add("[ORANGE]" + description).left();
tiptable.pad(10f);
};
run.run();
Tooltip tip = new Tooltip(tiptable, run);
tip.setInstant(true);
image.addListener(tip);
}
//additional padding
for(int j = 0; j < maxcol - (int)((float)recipes.size/rows+1); j ++){
table.row();
table.add().size(size);
}
if(sec == Section.distribution){
table.row();
table.add().size(size);
}
table.setVisible(()->{
return button.isChecked();
});
stack.add(table);
}
row();
add(stack).colspan(3);
get().pad(10f);
}}.right().bottom();
get().setVisible(play);
}}.end();
new table(){{
atop();
aleft();
itemtable = new table().top().left().get();
itemtable.background("button");
get().setVisible(play);
Label fps = new Label("");
fps.update(()->{
fps.setText(Settings.getBool("fps") ? (Gdx.graphics.getFramesPerSecond() + " FPS") : "");
});
row();
add(fps);
}}.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(12);
}};
get().setVisible(play);
}}.end();
//+- table
new table(){{
aleft();
abottom();
Control c = main.get(Control.class);
new button("+", ()->{
if(c.cameraScale < 4f){
c.cameraScale = 4f;
c.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
}).size(40);
new button("-", ()->{
if(c.cameraScale > 3f){
c.cameraScale = 3f;
c.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
}).size(40);
get().setVisible(play);
}}.end();
//menu table
new table(){{
float w = 200;
new button("Play", () -> {
main.play();
}).width(w);
row();
new button("Settings", () -> {
prefs.show(scene);
}).width(w);
row();
new button("Controls", () -> {
keys.show(scene);
}).width(w);
row();
new button("About", () -> {
about.show(scene);
}).width(w);
get().setVisible(nplay);
}};
updateItems();
build.end();
}
public void showRestart(){
restart.show(scene);
}
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(Graphics.mouseWorld().x, TileType.tilesize);
}
float roundy(){
return Mathf.round2(Graphics.mouseWorld().y, TileType.tilesize);
}
int tilex(){
return Mathf.scl2(Graphics.mouseWorld().x, TileType.tilesize);
}
int tiley(){
return Mathf.scl2(Graphics.mouseWorld().y, TileType.tilesize);
}
}
@@ -0,0 +1,22 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.pfa.Heuristic;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.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;
}
}
@@ -0,0 +1,38 @@
package io.anuke.mindustry.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.mindustry.Moment;
import io.anuke.mindustry.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;
}
}
@@ -0,0 +1,100 @@
package io.anuke.mindustry.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.mindustry.Moment;
import io.anuke.mindustry.entities.Enemy;
import io.anuke.mindustry.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 reset(){
paths.clear();
}
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;
}
}
@@ -0,0 +1,30 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.pfa.Connection;
import io.anuke.mindustry.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;
}
}
@@ -0,0 +1,36 @@
package io.anuke.mindustry.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.mindustry.Moment;
import io.anuke.mindustry.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;
}
}
@@ -0,0 +1,26 @@
package io.anuke.mindustry.entities;
import io.anuke.ucore.core.Draw;
public class BossEnemy extends Enemy{
public BossEnemy(int spawn) {
super(spawn);
reload = 8;
bullet = BulletType.smallfast;
rotatespeed = 30f;
maxhealth = 260;
hitsize = 8;
speed = 0.27f;
heal();
range = 70;
}
@Override
public void draw(){
Draw.rect("bossmech", x, y, direction.angle()-90);
}
}
@@ -0,0 +1,52 @@
package io.anuke.mindustry.entities;
import io.anuke.mindustry.Moment;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.TileType;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.util.Mathf;
public class Bullet extends BulletEntity{
BulletType type;
public Bullet(BulletType type, Entity owner, float x, float y, float angle){
super(type, owner, angle);
set(x, y);
this.type = type;
}
public void draw(){
type.draw(this);
}
@Override
public void update(){
int tilex = Mathf.scl2(x, TileType.tilesize);
int tiley = Mathf.scl2(y, TileType.tilesize);
Tile tile = Moment.i.tile(tilex, tiley);
if(tile != null && tile.entity != null &&
tile.entity.collide(this) && !tile.entity.dead){
tile.entity.collision(this);
remove();
type.removed(this);
}
super.update();
}
@Override
public void collision(SolidEntity other){
super.collision(other);
type.removed(this);
}
@Override
public int getDamage(){
return type.damage;
}
}
@@ -0,0 +1,82 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.entities.BaseBulletType;
public abstract class BulletType extends BaseBulletType<Bullet>{
public static final BulletType
stone = new BulletType(1.5f, 2){
public void draw(Bullet b){
Draw.color("gray");
Draw.square(b.x, b.y, 1f);
Draw.clear();
}
},
iron = new BulletType(1.7f, 2){
public void draw(Bullet b){
Draw.color("gray");
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
sniper = new BulletType(3f, 17){
public void draw(Bullet b){
Draw.color("light gray");
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
small = new BulletType(1.5f, 1){
public void draw(Bullet b){
Draw.color("orange");
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
smallfast = new BulletType(1.6f, 2){
Color color = new Color(0x8b5ec9ff);
public void draw(Bullet b){
Draw.color(color);
Draw.rect("bullet", b.x, b.y, b.angle());
Draw.clear();
}
},
flame = new BulletType(0.6f, 4){
public void draw(Bullet b){
Draw.color(Color.YELLOW, Color.SCARLET, b.time/lifetime);
float size = 6f-b.time/lifetime*5f;
Draw.rect("circle", b.x, b.y, size, size);
Draw.clear();
}
},
flameshot = new BulletType(0.5f, 3){
public void draw(Bullet b){
Draw.color(Color.ORANGE, Color.SCARLET, b.time/lifetime);
float size = 6f-b.time/lifetime*5f;
Draw.rect("circle", b.x, b.y, size, size);
Draw.clear();
}
},
shot = new BulletType(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();
}
};
private BulletType(float speed, int damage){
this.speed = speed;
this.damage = damage;
}
@Override
public void removed(Bullet b){
Effects.effect("hit", b);
}
}
@@ -0,0 +1,112 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Control;
import io.anuke.mindustry.Moment;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.world.TileType;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Sounds;
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 float range = 60;
public BulletType bullet = BulletType.small;
public float length = 4;
public float rotatespeed = 8f;
public String shootsound = "enemyshoot";
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);
//if(Timers.get(this, 10))
target = TileType.findTileTarget(x, y, null, range, false);
//no tile found
if(target == null)
target = Entities.getClosest(x, y, range, e->{
return e instanceof Player;
});
if(target != null){
if(Timers.get(this, reload)){
shoot();
Sounds.play(shootsound);
}
}
}
public void shoot(){
vector.set(length, 0).rotate(direction.angle());
new Bullet(bullet, this, x+vector.x, y+vector.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);
Sounds.play("explosion");
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*rotatespeed);
}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);
}
}
@@ -0,0 +1,22 @@
package io.anuke.mindustry.entities;
import io.anuke.ucore.core.Draw;
public class FastEnemy extends Enemy{
public FastEnemy(int spawn) {
super(spawn);
speed = 0.7f;
reload = 30;
maxhealth = 20;
heal();
}
@Override
public void draw(){
Draw.rect("fastmech", x, y, direction.angle()-90);
}
}
@@ -0,0 +1,27 @@
package io.anuke.mindustry.entities;
import io.anuke.ucore.core.Draw;
public class FlameEnemy extends Enemy{
public FlameEnemy(int spawn) {
super(spawn);
speed = 0.35f;
maxhealth = 150;
reload = 6;
bullet = BulletType.flameshot;
shootsound = "flame";
range = 40;
heal();
}
@Override
public void draw(){
Draw.rect("firemech", x, y, direction.angle()-90);
}
}
@@ -0,0 +1,89 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Control;
import io.anuke.mindustry.Moment;
import io.anuke.mindustry.UI;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Timers;
public class Player extends DestructibleEntity{
Vector2 direction = new Vector2();
float speed = 1f;
float rotation;
float reload;
Weapon weapon = Weapon.blaster;
public Player(){
hitsize = 5;
maxhealth = 100;
heal();
}
@Override
public void onDeath(){
remove();
Effects.effect("explosion", this);
Effects.shake(4f, 5f);
Effects.effect("respawn", this);
Timers.run(Moment.i.respawntime, ()->{
set(Moment.i.core.worldx(), Moment.i.core.worldy()-8);
heal();
add();
});
}
@Override
public void removed(){
}
@Override
public void draw(){
Draw.rect("player", x, y, direction.angle()-90);
}
@Override
public void update(){
if(health < maxhealth && Timers.get(this, 50))
health ++;
vector.set(0, 0);
if(Inputs.keyDown("up"))
vector.y += speed;
if(Inputs.keyDown("down"))
vector.y -= speed;
if(Inputs.keyDown("left"))
vector.x -= speed;
if(Inputs.keyDown("right"))
vector.x += speed;
reload -= delta;
boolean shooting = Inputs.buttonDown(Buttons.LEFT) && Moment.i.recipe == null && !Moment.module(UI.class).hasMouse();
if(shooting && reload <= 0){
weapon.shoot(this);
Sounds.play("shoot");
reload = weapon.reload;
}
vector.limit(speed);
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);
}
}
}
@@ -0,0 +1,105 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.utils.DelayedRemovalArray;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.Moment;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.TileType;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Sounds;
import io.anuke.ucore.entities.Entity;
public class TileEntity extends Entity{
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 int maxhealth, health;
public boolean dead = false;
public TileEntity(Tile tile){
this.tile = tile;
x = tile.worldx();
y = tile.worldy();
maxhealth = tile.block().health;
health = maxhealth;
}
public void onDeath(){
dead = true;
if(tile.block() == TileType.core){
Moment.i.coreDestroyed();
}
tile.setBlock(TileType.air);
Pathfind.updatePath();
Effects.shake(4f, 4f);
Effects.effect("explosion", this);
Sounds.play("break");
}
public void collision(Bullet other){
health -= other.getDamage();
if(health <= 0) onDeath();
}
public boolean collide(Bullet other){
return other.owner instanceof Enemy;
}
@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;
}
}
}
@@ -0,0 +1,28 @@
package io.anuke.mindustry.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();
}
}
@@ -0,0 +1,5 @@
package io.anuke.mindustry.resource;
public enum Item{
stone, iron, coal, steel;
}
@@ -0,0 +1,12 @@
package io.anuke.mindustry.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;
}
}
@@ -0,0 +1,55 @@
package io.anuke.mindustry.resource;
import static io.anuke.mindustry.resource.Section.*;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.world.TileType;
public enum Recipe{
stonewall(distribution, TileType.stonewall, stack(Item.stone, 5)),
ironwall(distribution, TileType.ironwall, stack(Item.iron, 5)),
steelwall(distribution, TileType.steelwall, stack(Item.steel, 5)),
conveyor(distribution, TileType.conveyor, stack(Item.stone, 1)),
fastconveyor(distribution, TileType.steelconveyor, stack(Item.steel, 1)),
router(distribution, TileType.router, stack(Item.stone, 3)),
turret(defense, TileType.turret, stack(Item.stone, 8)),
dturret(defense, TileType.doubleturret, stack(Item.stone, 12)),
machineturret(defense, TileType.machineturret, stack(Item.iron, 15), stack(Item.stone, 20)),
shotgunturret(defense, TileType.shotgunturret, stack(Item.iron, 15), stack(Item.steel, 24)),
flameturret(defense, TileType.flameturret, stack(Item.iron, 25), stack(Item.steel, 18)),
sniperturret(defense, TileType.sniperturret, stack(Item.iron, 30), stack(Item.steel, 20)),
healturret(defense, TileType.repairturret, stack(Item.iron, 40)),
megahealturret(defense, TileType.megarepairturret, stack(Item.iron, 30), stack(Item.steel, 40)),
drill(production, TileType.stonedrill, stack(Item.stone, 6)),
irondrill(production, TileType.irondrill, stack(Item.stone, 40)),
coaldrill(production, TileType.coaldrill, stack(Item.stone, 40), stack(Item.iron, 40)),
smelter(production, TileType.smelter, stack(Item.stone, 80), stack(Item.iron, 80));
public TileType result;
public ItemStack[] requirements;
public Section section;
private Recipe(Section section, TileType result, ItemStack... requirements){
this.result = result;
this.requirements = requirements;
this.section = section;
}
private static ItemStack stack(Item item, int amount){
return new ItemStack(item, amount);
}
public static Array<Recipe> getBy(Section section, Array<Recipe> r){
for(Recipe recipe : Recipe.values()){
if(recipe.section == section)
r.add(recipe);
}
return r;
}
}
@@ -0,0 +1,5 @@
package io.anuke.mindustry.resource;
public enum Section{
defense, production, distribution;
}
@@ -0,0 +1,53 @@
package io.anuke.mindustry.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.mindustry.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.stoneblock;
}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();
}
}
@@ -0,0 +1,75 @@
package io.anuke.mindustry.world;
import io.anuke.mindustry.Moment;
import io.anuke.mindustry.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(){
if(entity != null){
entity.remove();
entity = null;
}
if(block.update)
entity = new TileEntity(this).add();
}
}
@@ -0,0 +1,735 @@
package io.anuke.mindustry.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.mindustry.Moment;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.TileEntity.ItemPos;
import io.anuke.mindustry.resource.Item;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Sounds;
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;}},
steelwall(true, true){{health = 110;}},
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\nFaster 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, 10) && 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 = 13f;
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.";
}
@Override
void shoot(Tile tile){
vector.set(4, -2).rotate(tile.entity.rotation);
bullet(tile, tile.entity.rotation);
vector.set(4, 2).rotate(tile.entity.rotation);
bullet(tile, tile.entity.rotation);
}
},
machineturret(true, true, false){
{
range = 65;
reload = 7f;
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.";
}
},
flameturret(true, true, false){
{
range = 35f;
reload = 5f;
bullet = BulletType.flame;
ammo = Item.coal;
health = 85;
}
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 "Burns things.";
}
},
sniperturret(true, true, false){
{
range = 100;
reload = 60f;
bullet = BulletType.sniper;
ammo = Item.steel;
health = 60;
}
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.";
}
},
shotgunturret(true, true, false){
{
range = 50;
reload = 40f;
bullet = BulletType.iron;
ammo = Item.iron;
health = 70;
}
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.";
}
@Override
void shoot(Tile tile){
for(int i = 0; i < 6; i ++)
Timers.run(i/1.5f, ()->{
vector.set(4, 0).setAngle(tile.entity.rotation);
bullet(tile, tile.entity.rotation + Mathf.range(16));
});
}
},
repairturret(true, true, false){
{
range = 30;
reload = 40f;
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.worldx(), tile.worldy(), tile, range, true);
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()) + 1f) / 14f));
Draw.alpha(0.3f);
Draw.thickness(4f);
Draw.line(x, y, x2, y2);
Draw.thickness(2f);
Draw.rect("circle", x2, y2, 7f, 7f);
Draw.alpha(1f);
Draw.thickness(2f);
Draw.line(x, y, x2, y2);
Draw.thickness(1f);
Draw.rect("circle", x2, y2, 5f, 5f);
Draw.clear();
}
Draw.rect(name(), tile.worldx(), tile.worldy(), tile.entity.rotation - 90);
}
public String description(){
return "Heals nearby tiles.";
}
},
megarepairturret(true, true, false){
{
range = 30;
reload = 20f;
health = 80;
}
public void update(Tile tile){
tile.entity.link = findTileTarget(tile.worldx(), tile.worldy(), tile, range, true);
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(132, 242, 242, (MathUtils.sin(Timers.time()) + 1f) / 13f));
Draw.alpha(0.3f);
Draw.thickness(4f);
Draw.line(x, y, x2, y2);
Draw.thickness(2f);
Draw.rect("circle", x2, y2, 7f, 7f);
Draw.alpha(1f);
Draw.thickness(2f);
Draw.line(x, y, x2, y2);
Draw.thickness(1f);
Draw.rect("circle", x2, y2, 5f, 5f);
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)){
Sounds.play("shoot");
shoot(tile);
tile.entity.shots--;
}
}
}
}
void shoot(Tile tile){
vector.set(0, 4).setAngle(tile.entity.rotation);
new Bullet(bullet, tile.entity, tile.worldx()+vector.x, tile.worldy()+vector.y, tile.entity.rotation).add();
}
void bullet(Tile tile, float angle){
new Bullet(bullet, tile.entity, tile.worldx()+vector.x, tile.worldy()+vector.y, angle).add();
}
Enemy findTarget(Tile tile, float range){
Entity closest = null;
float dst = 0;
Array<SolidEntity> array = Entities.getNearby(tile.worldx(), tile.worldy(), range*2);
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;
}
public static TileEntity findTileTarget(float x, float y, Tile tile, float range, boolean damaged){
Entity closest = null;
float dst = 0;
int rad = (int)(range/tilesize)+1;
int tilex = Mathf.scl2(x, tilesize);
int tiley = Mathf.scl2(y, tilesize);
for(int rx = -rad; rx <= rad; rx ++){
for(int ry = -rad; ry <= rad; ry ++){
Tile other = Moment.i.tile(rx+tilex, ry+tiley);
if(other == null || other.entity == null ||(tile != null && other.entity == tile.entity)) continue;
TileEntity e = other.entity;
if(damaged && ((TileEntity) e).health >= ((TileEntity) e).tile.block().health)
continue;
float ndst = Vector2.dst(x, y, 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){
}
}