Merge branches 'master' and 'new-map-format' of https://github.com/Anuken/Mindustry into new-map-format
# Conflicts: # core/src/io/anuke/mindustry/editor/MapEditorDialog.java # core/src/io/anuke/mindustry/io/MapIO.java # core/src/io/anuke/mindustry/maps/MapTileData.java
This commit is contained in:
@@ -205,7 +205,7 @@ public class BlockIndexer{
|
||||
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){
|
||||
for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){
|
||||
Tile res = world.tile(x, y);
|
||||
if(res.block() == Blocks.air && res.floor().drops != null && res.floor().drops.item == item){
|
||||
if(res.block() == Blocks.air && res.floor().itemDrop == item){
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -243,9 +243,9 @@ public class BlockIndexer{
|
||||
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
||||
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
||||
Tile result = world.tile(x, y);
|
||||
if( result == null || result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
|
||||
if( result == null || result.floor().itemDrop == null || !scanOres.contains(result.floor().itemDrop)) continue;
|
||||
|
||||
itemSet.add(result.block().drops.item);
|
||||
itemSet.add(result.floor().itemDrop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,8 +322,8 @@ public class BlockIndexer{
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
//add position of quadrant to list when an ore is found
|
||||
if(tile.floor().drops != null && scanOres.contains(tile.floor().drops.item) && tile.block() == Blocks.air){
|
||||
ores.get(tile.floor().drops.item).add(world.tile(
|
||||
if(tile.floor().itemDrop != null && scanOres.contains(tile.floor().itemDrop) && tile.block() == Blocks.air){
|
||||
ores.get(tile.floor().itemDrop).add(world.tile(
|
||||
//make sure to clamp quadrant middle position, since it might go off bounds
|
||||
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
|
||||
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)));
|
||||
|
||||
@@ -182,8 +182,6 @@ public class Pathfinder{
|
||||
createFor(team);
|
||||
}
|
||||
}
|
||||
|
||||
world.spawner.checkAllQuadrants();
|
||||
}
|
||||
|
||||
class PathData{
|
||||
|
||||
@@ -2,32 +2,18 @@ package io.anuke.mindustry.ai;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.GridBits;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.Squad;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Waves;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class WaveSpawner{
|
||||
private static final int quadsize = 6;
|
||||
|
||||
private GridBits quadrants;
|
||||
|
||||
private Array<SpawnGroup> groups;
|
||||
private boolean dynamicSpawn;
|
||||
|
||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||
|
||||
@@ -35,273 +21,76 @@ public class WaveSpawner{
|
||||
Events.on(WorldLoadEvent.class, e -> reset());
|
||||
}
|
||||
|
||||
public void write(DataOutput output) throws IOException{
|
||||
output.writeShort(flySpawns.size);
|
||||
for(FlyerSpawn spawn : flySpawns){
|
||||
output.writeFloat(spawn.angle);
|
||||
}
|
||||
|
||||
output.writeShort(groundSpawns.size);
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
output.writeShort((short) spawn.x);
|
||||
output.writeShort((short) spawn.y);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInput input) throws IOException{
|
||||
short flya = input.readShort();
|
||||
|
||||
for(int i = 0; i < flya; i++){
|
||||
FlyerSpawn spawn = new FlyerSpawn();
|
||||
spawn.angle = input.readFloat();
|
||||
flySpawns.add(spawn);
|
||||
}
|
||||
|
||||
short grounda = input.readShort();
|
||||
for(int i = 0; i < grounda; i++){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = input.readShort();
|
||||
spawn.y = input.readShort();
|
||||
groundSpawns.add(spawn);
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnEnemies(){
|
||||
int flyGroups = 0;
|
||||
int groundGroups = 0;
|
||||
|
||||
//count total subgroups spawned by flying/group types
|
||||
for(SpawnGroup group : groups){
|
||||
int amount = group.getGroupsSpawned(state.wave);
|
||||
if(group.type.isFlying){
|
||||
flyGroups += amount;
|
||||
}else if(dynamicSpawn){
|
||||
groundGroups += amount;
|
||||
}
|
||||
}
|
||||
|
||||
int addGround = groundGroups - groundSpawns.size, addFly = flyGroups - flySpawns.size;
|
||||
|
||||
//add extra groups if the total exceeds it
|
||||
if(dynamicSpawn){
|
||||
for(int i = 0; i < addGround; i++){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
findLocation(spawn);
|
||||
groundSpawns.add(spawn);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < addFly; i++){
|
||||
FlyerSpawn spawn = new FlyerSpawn();
|
||||
findLocation(spawn);
|
||||
flySpawns.add(spawn);
|
||||
}
|
||||
|
||||
//store index of last used fly/ground spawn locations
|
||||
int flyCount = 0, groundCount = 0;
|
||||
|
||||
for(SpawnGroup group : groups){
|
||||
int groups = group.getGroupsSpawned(state.wave);
|
||||
int spawned = group.getUnitsSpawned(state.wave);
|
||||
|
||||
for(int i = 0; i < groups; i++){
|
||||
Squad squad = new Squad();
|
||||
float spawnX, spawnY;
|
||||
float spread;
|
||||
|
||||
if(!group.type.isFlying && groundCount >= groundSpawns.size) continue;
|
||||
|
||||
if(group.type.isFlying){
|
||||
FlyerSpawn spawn = flySpawns.get(flyCount);
|
||||
float spawnX, spawnY;
|
||||
float spread;
|
||||
|
||||
if(group.type.isFlying){
|
||||
for(FlyerSpawn spawn : flySpawns){
|
||||
Squad squad = new Squad();
|
||||
float margin = 40f; //how far away from the edge flying units spawn
|
||||
spawnX = world.width() * tilesize / 2f + sqrwavex(spawn.angle) * (world.width() / 2f * tilesize + margin);
|
||||
spawnY = world.height() * tilesize / 2f + sqrwavey(spawn.angle) * (world.height() / 2f * tilesize + margin);
|
||||
float trns = (world.width() + world.height()) * tilesize;
|
||||
spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(spawn.angle, trns), -margin, world.width() * tilesize + margin);
|
||||
spawnY = Mathf.clamp(world.height() * tilesize / 2f + Angles.trnsy(spawn.angle, trns), -margin, world.height() * tilesize + margin);
|
||||
spread = margin / 1.5f;
|
||||
|
||||
flyCount++;
|
||||
}else{ //make sure it works for non-dynamic spawns
|
||||
GroundSpawn spawn = groundSpawns.get(groundCount);
|
||||
|
||||
if(dynamicSpawn){
|
||||
checkQuadrant(spawn.x, spawn.y);
|
||||
if(!getQuad(spawn.x, spawn.y)){
|
||||
findLocation(spawn);
|
||||
}
|
||||
for(int i = 0; i < spawned; i++){
|
||||
BaseUnit unit = group.createUnit(waveTeam);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
}
|
||||
|
||||
spawnX = spawn.x * quadsize * tilesize + quadsize * tilesize / 2f;
|
||||
spawnY = spawn.y * quadsize * tilesize + quadsize * tilesize / 2f;
|
||||
spread = quadsize * tilesize / 3f;
|
||||
|
||||
groundCount++;
|
||||
}
|
||||
}else{
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
Squad squad = new Squad();
|
||||
spawnX = spawn.x * tilesize;
|
||||
spawnY = spawn.y * tilesize;
|
||||
spread = tilesize;
|
||||
|
||||
for(int j = 0; j < spawned; j++){
|
||||
BaseUnit unit = group.createUnit(Team.red);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkAllQuadrants(){
|
||||
for(int x = 0; x < quadWidth(); x++){
|
||||
for(int y = 0; y < quadHeight(); y++){
|
||||
checkQuadrant(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkQuadrant(int quadx, int quady){
|
||||
setQuad(quadx, quady, true);
|
||||
|
||||
outer:
|
||||
for(int x = quadx * quadsize; x < world.width() && x < (quadx + 1) * quadsize; x++){
|
||||
for(int y = quady * quadsize; y < world.height() && y < (quady + 1) * quadsize; y++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
if(tile == null || tile.solid() || tile.getTeam() == defaultTeam || world.pathfinder.getValueforTeam(Team.red, x, y) == Float.MAX_VALUE || tile.floor().isLiquid){
|
||||
setQuad(quadx, quady, false);
|
||||
break outer;
|
||||
for(int i = 0; i < spawned; i++){
|
||||
BaseUnit unit = group.createUnit(waveTeam);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reset(){
|
||||
dynamicSpawn = false;
|
||||
flySpawns.clear();
|
||||
groundSpawns.clear();
|
||||
quadrants = new GridBits(quadWidth(), quadHeight());
|
||||
groups = Waves.getSpawns();
|
||||
|
||||
dynamicSpawn = true;
|
||||
groups = state.rules.spawns;
|
||||
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
if(world.tile(x, y).block() == Blocks.spawn){
|
||||
dynamicSpawn = false;
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = x/quadsize;
|
||||
spawn.y = y/quadsize;
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
|
||||
flySpawns.add(fspawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getQuad(int quadx, int quady){
|
||||
return quadrants.get(quadx, quady);
|
||||
}
|
||||
|
||||
private void setQuad(int quadx, int quady, boolean valid){
|
||||
if(quadrants == null){
|
||||
quadrants = new GridBits(quadWidth(), quadHeight());
|
||||
}
|
||||
|
||||
if(!Structs.inBounds(quadx, quady, quadWidth(), quadHeight())){
|
||||
return;
|
||||
}
|
||||
|
||||
quadrants.set(quadx, quady, valid);
|
||||
}
|
||||
|
||||
//TODO instead of randomly scattering locations around the map, find spawns close to each other
|
||||
private void findLocation(GroundSpawn spawn){
|
||||
spawn.x = Mathf.random(quadWidth()-1);
|
||||
spawn.y = Mathf.random(quadHeight()-1);
|
||||
|
||||
int shellWidth = quadWidth() * 2 + quadHeight() * 2 * 6;
|
||||
shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth);
|
||||
|
||||
traverseSpiral(quadWidth(), quadHeight(), Mathf.random(shellWidth), (x, y) -> {
|
||||
if(getQuad(x, y)){
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
//TODO instead of randomly scattering locations around the map, find spawns close to each other
|
||||
private void findLocation(FlyerSpawn spawn){
|
||||
spawn.angle = Mathf.random(360f);
|
||||
}
|
||||
|
||||
private int quadWidth(){
|
||||
return Mathf.ceil(world.width() / (float) quadsize);
|
||||
}
|
||||
|
||||
private int quadHeight(){
|
||||
return Mathf.ceil(world.height() / (float) quadsize);
|
||||
}
|
||||
|
||||
private class FlyerSpawn{
|
||||
//square angle
|
||||
float angle;
|
||||
}
|
||||
|
||||
private class GroundSpawn{
|
||||
//quadrant spawn coordinates
|
||||
int x, y;
|
||||
}
|
||||
|
||||
//utility methods
|
||||
|
||||
float sqrwavex(float degrees){
|
||||
degrees = Mathf.mod(degrees, 360f);
|
||||
if(degrees < 45){
|
||||
return 1;
|
||||
}else if(degrees < 135){
|
||||
return 1f - (degrees - 45f) / 90f;
|
||||
}else if(degrees < 225){
|
||||
return -1f;
|
||||
}else if(degrees < 315){
|
||||
return (degrees - 225) / 90f;
|
||||
}else{
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
float sqrwavey(float degrees){
|
||||
return sqrwavex(degrees + 90f);
|
||||
}
|
||||
|
||||
void traverseSpiral(int width, int height, int offset, SpiralTraverser con){
|
||||
int directionIdx = 0;
|
||||
int curRow = 0, curCol = 0;
|
||||
for(int i = 0; i < height * width; i++){
|
||||
|
||||
if(i >= offset && con.accept(curCol, curRow)) break;
|
||||
|
||||
int same = 1, row = curRow, col = curCol;
|
||||
if(row > height - 1 - row){
|
||||
row = height - 1 - row;
|
||||
same = 0;
|
||||
}
|
||||
if(col >= width - 1 - col){
|
||||
col = width - 1 - col;
|
||||
same = 0;
|
||||
}
|
||||
row -= same;
|
||||
|
||||
if(row == col){
|
||||
directionIdx = (directionIdx + 1) % 4;
|
||||
}
|
||||
curRow += directions[directionIdx][0];
|
||||
curCol += directions[directionIdx][1];
|
||||
}
|
||||
}
|
||||
|
||||
interface SpiralTraverser{
|
||||
boolean accept(int x, int y);
|
||||
}
|
||||
|
||||
private static int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.graphics.CacheLayer;
|
||||
import io.anuke.mindustry.type.Category;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -22,16 +20,20 @@ import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
import io.anuke.mindustry.world.blocks.storage.LaunchPad;
|
||||
import io.anuke.mindustry.world.blocks.storage.SortedUnloader;
|
||||
import io.anuke.mindustry.world.blocks.storage.Vault;
|
||||
import io.anuke.mindustry.world.blocks.units.*;
|
||||
import io.anuke.mindustry.world.blocks.units.MechPad;
|
||||
import io.anuke.mindustry.world.blocks.units.Reconstructor;
|
||||
import io.anuke.mindustry.world.blocks.units.RepairPoint;
|
||||
import io.anuke.mindustry.world.blocks.units.UnitFactory;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
|
||||
public class Blocks implements ContentList{
|
||||
public static Block
|
||||
|
||||
//environment
|
||||
air, blockpart, spawn, space, metalfloor, deepwater, water, tar, stone, blackstone, dirt, sand, ice, snow,
|
||||
grass, shrub, rock, icerock, blackrock, rocksSmall, rocksMedium,
|
||||
air, part, spawn, space, metalfloor, deepwater, water, tar, stone, craters, blackstone, dirt, sand, ice, snow,
|
||||
grass, shrub, rock, icerock, blackrock, rocks,
|
||||
|
||||
//crafting
|
||||
siliconSmelter, plastaniumCompressor, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
|
||||
@@ -61,7 +63,7 @@ public class Blocks implements ContentList{
|
||||
core, vault, container, unloader, launchPad,
|
||||
|
||||
//turrets
|
||||
duo, scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
|
||||
duo, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
|
||||
|
||||
//units
|
||||
spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, titanFactory,
|
||||
@@ -74,9 +76,7 @@ public class Blocks implements ContentList{
|
||||
public void load(){
|
||||
//region environment
|
||||
|
||||
air = new Floor("air"){
|
||||
{
|
||||
blend = false;
|
||||
air = new Floor("air"){{
|
||||
alwaysReplace = true;
|
||||
}
|
||||
|
||||
@@ -85,17 +85,10 @@ public class Blocks implements ContentList{
|
||||
public void init(){}
|
||||
};
|
||||
|
||||
blockpart = new BlockPart();
|
||||
part = new BlockPart();
|
||||
|
||||
spawn = new Block("spawn"){
|
||||
|
||||
public void drawShadow(Tile tile){}
|
||||
|
||||
public void draw(Tile tile){
|
||||
Draw.color(Color.SCARLET);
|
||||
Lines.circle(tile.worldx(), tile.worldy(), 4f +Mathf.absin(Time.time(), 6f, 6f));
|
||||
Draw.color();
|
||||
}
|
||||
};
|
||||
|
||||
//Registers build blocks from size 1-6
|
||||
@@ -109,7 +102,6 @@ public class Blocks implements ContentList{
|
||||
variants = 0;
|
||||
cacheLayer = CacheLayer.space;
|
||||
solid = true;
|
||||
blend = false;
|
||||
minimapColor = Color.valueOf("000001");
|
||||
}};
|
||||
|
||||
@@ -157,9 +149,11 @@ public class Blocks implements ContentList{
|
||||
|
||||
stone = new Floor("stone"){{
|
||||
hasOres = true;
|
||||
blends = block -> block != this && !(block instanceof OreBlock);
|
||||
minimapColor = Color.valueOf("323232");
|
||||
playerUnmineable = true;
|
||||
}};
|
||||
|
||||
craters = new Floor("craters"){{
|
||||
minimapColor = Color.valueOf("323232");
|
||||
}};
|
||||
|
||||
blackstone = new Floor("blackstone"){{
|
||||
@@ -173,7 +167,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
sand = new Floor("sand"){{
|
||||
drops = new ItemStack(Items.sand, 1);
|
||||
itemDrop = Items.sand;
|
||||
minimapColor = Color.valueOf("988a67");
|
||||
hasOres = true;
|
||||
playerUnmineable = true;
|
||||
@@ -210,22 +204,15 @@ public class Blocks implements ContentList{
|
||||
variants = 1;
|
||||
}};
|
||||
|
||||
rocksSmall = new Rock("rocks-small"){{
|
||||
variants = 2;
|
||||
breakable = alwaysReplace = false;
|
||||
solid = true;
|
||||
rocks = new StaticWall("rocks"){{
|
||||
variants = 2;
|
||||
}};
|
||||
|
||||
rocksMedium = new Rock("rocks-medium"){{
|
||||
variants = 2;
|
||||
breakable = alwaysReplace = false;
|
||||
solid = true;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region crafting
|
||||
|
||||
siliconSmelter = new PowerSmelter("silicon-smelter"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.lead, 50));
|
||||
health = 90;
|
||||
craftEffect = Fx.smeltsmoke;
|
||||
result = Items.silicon;
|
||||
@@ -239,6 +226,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.silicon, 160, Items.lead, 230, Items.graphite, 120, Items.titanium, 160));
|
||||
hasItems = true;
|
||||
liquidCapacity = 60f;
|
||||
craftTime = 60f;
|
||||
@@ -255,6 +243,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
phaseWeaver = new PhaseWeaver("phase-weaver"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.silicon, 260, Items.lead, 240, Items.thorium, 150));
|
||||
craftEffect = Fx.smeltsmoke;
|
||||
result = Items.phasefabric;
|
||||
craftTime = 120f;
|
||||
@@ -265,6 +254,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
surgeSmelter = new PowerSmelter("alloy-smelter"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.silicon, 160, Items.lead, 160, Items.thorium, 140));
|
||||
craftEffect = Fx.smeltsmoke;
|
||||
result = Items.surgealloy;
|
||||
craftTime = 75f;
|
||||
@@ -278,6 +268,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
cryofluidMixer = new LiquidMixer("cryofluidmixer"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.lead, 130, Items.silicon, 80, Items.thorium, 90));
|
||||
outputLiquid = Liquids.cryofluid;
|
||||
liquidPerItem = 50f;
|
||||
size = 2;
|
||||
@@ -289,6 +280,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
blastMixer = new GenericCrafter("blast-mixer"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.lead, 60, Items.titanium, 40));
|
||||
hasItems = true;
|
||||
hasPower = true;
|
||||
hasLiquids = true;
|
||||
@@ -301,6 +293,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
pyratiteMixer = new PowerSmelter("pyratite-mixer"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.copper, 100, Items.lead, 50));
|
||||
flameColor = Color.CLEAR;
|
||||
hasItems = true;
|
||||
hasPower = true;
|
||||
@@ -313,6 +306,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
melter = new PowerCrafter("melter"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.lead, 70, Items.graphite, 90));
|
||||
health = 200;
|
||||
outputLiquid = Liquids.slag;
|
||||
outputLiquidAmount = 1.5f;
|
||||
@@ -324,11 +318,12 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
separator = new Separator("separator"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.titanium, 50));
|
||||
results = new ItemStack[]{
|
||||
new ItemStack(Items.copper, 5),
|
||||
new ItemStack(Items.lead, 3),
|
||||
new ItemStack(Items.titanium, 2),
|
||||
new ItemStack(Items.thorium, 1)
|
||||
new ItemStack(Items.copper, 5),
|
||||
new ItemStack(Items.lead, 3),
|
||||
new ItemStack(Items.titanium, 2),
|
||||
new ItemStack(Items.thorium, 1)
|
||||
};
|
||||
hasPower = true;
|
||||
filterTime = 15f;
|
||||
@@ -343,6 +338,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
biomatterCompressor = new Compressor("biomattercompressor"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.lead, 70, Items.silicon, 60));
|
||||
liquidCapacity = 60f;
|
||||
craftTime = 20f;
|
||||
outputLiquid = Liquids.oil;
|
||||
@@ -356,6 +352,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
pulverizer = new Pulverizer("pulverizer"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.copper, 60, Items.lead, 50));
|
||||
output = Items.sand;
|
||||
craftEffect = Fx.pulverize;
|
||||
craftTime = 40f;
|
||||
@@ -367,73 +364,107 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
incinerator = new Incinerator("incinerator"){{
|
||||
requirements(Category.crafting, ItemStack.with(Items.graphite, 10, Items.lead, 30));
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region sandbox
|
||||
|
||||
powerVoid = new PowerVoid("power-void");
|
||||
powerSource = new PowerSource("power-source");
|
||||
itemSource = new ItemSource("item-source");
|
||||
itemVoid = new ItemVoid("item-void");
|
||||
liquidSource = new LiquidSource("liquid-source");
|
||||
|
||||
|
||||
powerVoid = new PowerVoid("power-void"){{
|
||||
requirements(Category.power, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
powerSource = new PowerSource("power-source"){{
|
||||
requirements(Category.power, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemSource = new ItemSource("item-source"){{
|
||||
requirements(Category.distribution, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemVoid = new ItemVoid("item-void"){{
|
||||
requirements(Category.distribution, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
liquidSource = new LiquidSource("liquid-source"){{
|
||||
requirements(Category.liquid, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region defense
|
||||
|
||||
int wallHealthMultiplier = 3;
|
||||
|
||||
copperWall = new Wall("copper-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.copper, 12));
|
||||
health = 80 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
copperWallLarge = new Wall("copper-wall-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.copper, 12 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.copper, 12));
|
||||
health = 80 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
titaniumWall = new Wall("titanium-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12));
|
||||
health = 110 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
titaniumWallLarge = new Wall("titanium-wall-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12));
|
||||
health = 110 * wallHealthMultiplier * 4;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
thoriumWall = new Wall("thorium-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.thorium, 12));
|
||||
health = 200 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
thoriumWallLarge = new Wall("thorium-wall-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.thorium, 12 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.thorium, 12));
|
||||
health = 200 * wallHealthMultiplier * 4;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
phaseWall = new DeflectorWall("phase-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.phasefabric, 12));
|
||||
health = 150 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
phaseWallLarge = new DeflectorWall("phase-wall-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.phasefabric, 12 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.phasefabric, 12));
|
||||
health = 150 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
surgeWall = new SurgeWall("surge-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.surgealloy, 12));
|
||||
health = 230 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
surgeWallLarge = new SurgeWall("surge-wall-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.surgealloy, 12 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.surgealloy, 12));
|
||||
health = 230 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
door = new Door("door"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12, Items.silicon, 8));
|
||||
health = 100 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
doorLarge = new Door("door-large"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12 * 4, Items.silicon, 8 * 4));
|
||||
requirements(Category.defense, ItemStack.with(Items.titanium, 12, Items.silicon, 8));
|
||||
openfx = Fx.dooropenlarge;
|
||||
closefx = Fx.doorcloselarge;
|
||||
health = 100 * 4 * wallHealthMultiplier;
|
||||
@@ -441,85 +472,107 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
mendProjector = new MendProjector("mend-projector"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 150, Items.titanium, 50, Items.silicon, 180));
|
||||
consumes.power(0.2f, 1.0f);
|
||||
size = 2;
|
||||
consumes.item(Items.phasefabric).optional(true);
|
||||
}};
|
||||
|
||||
overdriveProjector = new OverdriveProjector("overdrive-projector"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 150, Items.titanium, 150, Items.silicon, 250));
|
||||
consumes.power(0.35f, 1.0f);
|
||||
size = 2;
|
||||
consumes.item(Items.phasefabric).optional(true);
|
||||
}};
|
||||
|
||||
forceProjector = new ForceProjector("force-projector"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 150, Items.titanium, 150, Items.silicon, 250));
|
||||
size = 3;
|
||||
consumes.item(Items.phasefabric).optional(true);
|
||||
}};
|
||||
|
||||
shockMine = new ShockMine("shock-mine"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.lead, 50, Items.silicon, 25));
|
||||
health = 40;
|
||||
damage = 11;
|
||||
tileDamage = 7f;
|
||||
length = 10;
|
||||
tendrils = 5;
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region distribution
|
||||
|
||||
conveyor = new Conveyor("conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.copper, 1), true);
|
||||
health = 45;
|
||||
speed = 0.03f;
|
||||
}};
|
||||
|
||||
titaniumConveyor = new Conveyor("titanium-conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.copper, 2, Items.titanium, 1));
|
||||
health = 65;
|
||||
speed = 0.07f;
|
||||
}};
|
||||
|
||||
junction = new Junction("junction"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.copper, 2));
|
||||
speed = 26;
|
||||
capacity = 32;
|
||||
}};
|
||||
|
||||
itemBridge = new BufferedItemBridge("bridge-conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 8, Items.copper, 8));
|
||||
range = 4;
|
||||
speed = 60f;
|
||||
bufferCapacity = 15;
|
||||
}};
|
||||
|
||||
phaseConveyor = new ItemBridge("phase-conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.phasefabric, 10, Items.silicon, 15, Items.lead, 20, Items.graphite, 20));
|
||||
range = 12;
|
||||
hasPower = true;
|
||||
consumes.power(0.03f, 1.0f);
|
||||
}};
|
||||
|
||||
sorter = new Sorter("sorter");
|
||||
sorter = new Sorter("sorter"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 4, Items.copper, 4));
|
||||
|
||||
router = new Router("router");
|
||||
}};
|
||||
|
||||
router = new Router("router"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.copper, 6));
|
||||
|
||||
}};
|
||||
|
||||
distributor = new Router("distributor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 8, Items.copper, 8));
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
overflowGate = new OverflowGate("overflow-gate");
|
||||
overflowGate = new OverflowGate("overflow-gate"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 4, Items.copper, 8));
|
||||
|
||||
}};
|
||||
|
||||
massDriver = new MassDriver("mass-driver"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 250, Items.silicon, 150, Items.lead, 250, Items.thorium, 100));
|
||||
size = 3;
|
||||
itemCapacity = 60;
|
||||
range = 440f;
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region liquid
|
||||
|
||||
mechanicalPump = new Pump("mechanical-pump"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.copper, 30, Items.lead, 20));
|
||||
pumpAmount = 0.1f;
|
||||
tier = 0;
|
||||
}};
|
||||
|
||||
rotaryPump = new Pump("rotary-pump"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.copper, 140, Items.lead, 100, Items.silicon, 40, Items.titanium, 70));
|
||||
pumpAmount = 0.2f;
|
||||
consumes.power(0.015f);
|
||||
liquidCapacity = 30f;
|
||||
@@ -529,6 +582,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
thermalPump = new Pump("thermal-pump"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.copper, 160, Items.lead, 130, Items.silicon, 60, Items.titanium, 80, Items.thorium, 70));
|
||||
pumpAmount = 0.275f;
|
||||
consumes.power(0.03f);
|
||||
liquidCapacity = 40f;
|
||||
@@ -538,47 +592,83 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
conduit = new Conduit("conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.lead, 1));
|
||||
health = 45;
|
||||
}};
|
||||
|
||||
pulseConduit = new Conduit("pulse-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 1, Items.lead, 1));
|
||||
liquidCapacity = 16f;
|
||||
liquidFlowFactor = 4.9f;
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
liquidRouter = new LiquidRouter("liquid-router"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 4, Items.lead, 4));
|
||||
liquidCapacity = 20f;
|
||||
}};
|
||||
|
||||
liquidTank = new LiquidTank("liquid-tank"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 50, Items.lead, 50));
|
||||
size = 3;
|
||||
liquidCapacity = 1500f;
|
||||
health = 500;
|
||||
}};
|
||||
|
||||
liquidJunction = new LiquidJunction("liquid-junction");
|
||||
liquidJunction = new LiquidJunction("liquid-junction"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 4, Items.lead, 4));
|
||||
}};
|
||||
|
||||
bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 8, Items.lead, 8));
|
||||
range = 4;
|
||||
hasPower = false;
|
||||
}};
|
||||
|
||||
phaseConduit = new LiquidBridge("phase-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.phasefabric, 10, Items.silicon, 15, Items.lead, 20, Items.titanium, 20));
|
||||
range = 12;
|
||||
hasPower = true;
|
||||
consumes.power(0.03f, 1.0f);
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region power
|
||||
|
||||
powerNode = new PowerNode("power-node"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 2, Items.lead, 6));
|
||||
maxNodes = 4;
|
||||
laserRange = 6;
|
||||
}};
|
||||
|
||||
powerNodeLarge = new PowerNode("power-node-large"){{
|
||||
requirements(Category.power, ItemStack.with(Items.titanium, 10, Items.lead, 20, Items.silicon, 6));
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 2, Items.lead, 6));
|
||||
size = 2;
|
||||
maxNodes = 6;
|
||||
laserRange = 9.5f;
|
||||
}};
|
||||
|
||||
battery = new Battery("battery"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 8, Items.lead, 30, Items.silicon, 4));
|
||||
consumes.powerBuffered(320f, 1f);
|
||||
}};
|
||||
|
||||
batteryLarge = new Battery("battery-large"){{
|
||||
requirements(Category.power, ItemStack.with(Items.titanium, 40, Items.lead, 80, Items.silicon, 30));
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 8, Items.lead, 30, Items.silicon, 4));
|
||||
size = 3;
|
||||
consumes.powerBuffered(2000f, 1f);
|
||||
}};
|
||||
|
||||
combustionGenerator = new BurnerGenerator("combustion-generator"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 50, Items.lead, 30));
|
||||
powerProduction = 0.09f;
|
||||
itemDuration = 40f;
|
||||
}};
|
||||
|
||||
thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 80, Items.graphite, 70, Items.lead, 100, Items.silicon, 70, Items.thorium, 70));
|
||||
maxLiquidGenerate = 2f;
|
||||
powerProduction = 2f;
|
||||
generateEffect = Fx.redgeneratespark;
|
||||
@@ -586,6 +676,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
turbineGenerator = new TurbineGenerator("turbine-generator"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 70, Items.graphite, 50, Items.lead, 80, Items.silicon, 60));
|
||||
powerProduction = 0.28f;
|
||||
itemDuration = 30f;
|
||||
consumes.liquid(Liquids.water, 0.05f);
|
||||
@@ -593,21 +684,25 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
rtgGenerator = new DecayGenerator("rtg-generator"){{
|
||||
requirements(Category.power, ItemStack.with(Items.lead, 200, Items.silicon, 150, Items.phasefabric, 50, Items.plastanium, 150, Items.thorium, 100));
|
||||
size = 2;
|
||||
powerProduction = 0.3f;
|
||||
itemDuration = 220f;
|
||||
}};
|
||||
|
||||
solarPanel = new SolarGenerator("solar-panel"){{
|
||||
requirements(Category.power, ItemStack.with(Items.lead, 20, Items.silicon, 30));
|
||||
powerProduction = 0.0045f;
|
||||
}};
|
||||
|
||||
largeSolarPanel = new SolarGenerator("solar-panel-large"){{
|
||||
requirements(Category.power, ItemStack.with(Items.lead, 200, Items.silicon, 290, Items.phasefabric, 30));
|
||||
size = 3;
|
||||
powerProduction = 0.055f;
|
||||
}};
|
||||
|
||||
thoriumReactor = new NuclearReactor("thorium-reactor"){{
|
||||
requirements(Category.power, ItemStack.with(Items.lead, 600, Items.silicon, 400, Items.graphite, 300, Items.thorium, 300));
|
||||
size = 3;
|
||||
health = 700;
|
||||
powerProduction = 1.1f;
|
||||
@@ -618,45 +713,28 @@ public class Blocks implements ContentList{
|
||||
health = 600;
|
||||
}};
|
||||
|
||||
battery = new Battery("battery"){{
|
||||
consumes.powerBuffered(320f, 1f);
|
||||
}};
|
||||
|
||||
batteryLarge = new Battery("battery-large"){{
|
||||
size = 3;
|
||||
consumes.powerBuffered(2000f, 1f);
|
||||
}};
|
||||
|
||||
powerNode = new PowerNode("power-node"){{
|
||||
maxNodes = 4;
|
||||
laserRange = 6;
|
||||
}};
|
||||
|
||||
powerNodeLarge = new PowerNode("power-node-large"){{
|
||||
size = 2;
|
||||
maxNodes = 6;
|
||||
laserRange = 9.5f;
|
||||
}};
|
||||
|
||||
//endregion power
|
||||
//region production
|
||||
|
||||
mechanicalDrill = new Drill("mechanical-drill"){{
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 20), true);
|
||||
tier = 2;
|
||||
drillTime = 300;
|
||||
drillTime = 600;
|
||||
size = 2;
|
||||
drawMineItem = true;
|
||||
}};
|
||||
|
||||
pneumaticDrill = new Drill("pneumatic-drill"){{
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 60, Items.graphite, 50));
|
||||
tier = 3;
|
||||
drillTime = 240;
|
||||
drillTime = 480;
|
||||
size = 2;
|
||||
drawMineItem = true;
|
||||
}};
|
||||
|
||||
laserDrill = new Drill("laser-drill"){{
|
||||
drillTime = 140;
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 70, Items.graphite, 90, Items.silicon, 60, Items.titanium, 50));
|
||||
drillTime = 280;
|
||||
size = 2;
|
||||
hasPower = true;
|
||||
tier = 4;
|
||||
@@ -667,7 +745,8 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
blastDrill = new Drill("blast-drill"){{
|
||||
drillTime = 60;
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 130, Items.silicon, 120, Items.titanium, 100, Items.thorium, 60));
|
||||
drillTime = 120;
|
||||
size = 3;
|
||||
drawRim = true;
|
||||
hasPower = true;
|
||||
@@ -683,7 +762,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
plasmaDrill = new Drill("plasma-drill"){{
|
||||
heatColor = Color.valueOf("ff461b");
|
||||
drillTime = 50;
|
||||
drillTime = 100;
|
||||
size = 4;
|
||||
hasLiquids = true;
|
||||
hasPower = true;
|
||||
@@ -699,6 +778,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
waterExtractor = new SolidPump("water-extractor"){{
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 50, Items.graphite, 50, Items.lead, 40));
|
||||
result = Liquids.water;
|
||||
pumpAmount = 0.065f;
|
||||
size = 2;
|
||||
@@ -709,6 +789,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
oilExtractor = new Fracker("oil-extractor"){{
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 300, Items.graphite, 350, Items.lead, 230, Items.thorium, 230, Items.silicon, 150));
|
||||
result = Liquids.oil;
|
||||
updateEffect = Fx.pulverize;
|
||||
liquidCapacity = 50f;
|
||||
@@ -723,6 +804,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
cultivator = new Cultivator("cultivator"){{
|
||||
requirements(Category.production, ItemStack.with(Items.copper, 20, Items.lead, 50, Items.silicon, 20));
|
||||
result = Items.biomatter;
|
||||
drillTime = 200;
|
||||
size = 2;
|
||||
@@ -732,61 +814,74 @@ public class Blocks implements ContentList{
|
||||
consumes.power(0.08f);
|
||||
consumes.liquid(Liquids.water, 0.15f);
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region storage
|
||||
|
||||
core = new CoreBlock("core"){{
|
||||
requirements(Category.effect, () -> false, ItemStack.with(Items.titanium, 2000));
|
||||
alwaysUnlocked = true;
|
||||
|
||||
health = 1100;
|
||||
itemCapacity = 2000;
|
||||
itemCapacity = 1000;
|
||||
launchThreshold = 500;
|
||||
launchTime = 60f * 10;
|
||||
launchChunkSize = 100;
|
||||
}};
|
||||
|
||||
vault = new Vault("vault"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.titanium, 500, Items.thorium, 250));
|
||||
size = 3;
|
||||
itemCapacity = 1000;
|
||||
}};
|
||||
|
||||
container = new Vault("container"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.titanium, 200));
|
||||
size = 2;
|
||||
itemCapacity = 300;
|
||||
}};
|
||||
|
||||
unloader = new SortedUnloader("unloader"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.titanium, 50, Items.silicon, 60));
|
||||
speed = 7f;
|
||||
}};
|
||||
|
||||
launchPad = new LaunchPad("launch-pad"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.copper, 500));
|
||||
size = 3;
|
||||
itemCapacity = 100;
|
||||
launchTime = 60f * 6;
|
||||
hasPower = true;
|
||||
consumes.power(0.1f);
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region turrets
|
||||
|
||||
duo = new DoubleTurret("duo"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 60), true);
|
||||
ammo(
|
||||
Items.copper, Bullets.standardCopper,
|
||||
Items.graphite, Bullets.standardDense,
|
||||
Items.pyratite, Bullets.standardIncendiary,
|
||||
Items.silicon, Bullets.standardHoming
|
||||
);
|
||||
reload = 25f;
|
||||
reload = 20f;
|
||||
restitution = 0.03f;
|
||||
range = 90f;
|
||||
shootCone = 15f;
|
||||
ammoUseEffect = Fx.shellEjectSmall;
|
||||
health = 80;
|
||||
health = 110;
|
||||
inaccuracy = 2f;
|
||||
rotatespeed = 10f;
|
||||
}};
|
||||
|
||||
hail = new ArtilleryTurret("hail"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 60, Items.graphite, 35));
|
||||
ammo(
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary
|
||||
);
|
||||
reload = 60f;
|
||||
recoil = 2f;
|
||||
@@ -796,21 +891,13 @@ public class Blocks implements ContentList{
|
||||
health = 120;
|
||||
}};
|
||||
|
||||
scorch = new LiquidTurret("scorch"){{
|
||||
ammo(Liquids.oil, Bullets.basicFlame);
|
||||
recoil = 0f;
|
||||
reload = 4f;
|
||||
shootCone = 50f;
|
||||
ammoUseEffect = Fx.shellEjectSmall;
|
||||
health = 160;
|
||||
}};
|
||||
|
||||
wave = new LiquidTurret("wave"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.titanium, 70, Items.lead, 150));
|
||||
ammo(
|
||||
Liquids.water, Bullets.waterShot,
|
||||
Liquids.slag, Bullets.slagShot,
|
||||
Liquids.cryofluid, Bullets.cryoShot,
|
||||
Liquids.oil, Bullets.oilShot
|
||||
Liquids.water, Bullets.waterShot,
|
||||
Liquids.slag, Bullets.slagShot,
|
||||
Liquids.cryofluid, Bullets.cryoShot,
|
||||
Liquids.oil, Bullets.oilShot
|
||||
);
|
||||
size = 2;
|
||||
recoil = 0f;
|
||||
@@ -832,6 +919,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
lancer = new ChargeTurret("lancer"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 50, Items.lead, 100, Items.silicon, 90));
|
||||
range = 90f;
|
||||
chargeTime = 60f;
|
||||
chargeMaxDelay = 30f;
|
||||
@@ -854,6 +942,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
arc = new PowerTurret("arc"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 70, Items.lead, 60));
|
||||
shootType = Bullets.arc;
|
||||
reload = 85f;
|
||||
shootShake = 1f;
|
||||
@@ -869,10 +958,11 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
swarmer = new BurstTurret("swarmer"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.graphite, 70, Items.titanium, 70, Items.plastanium, 90, Items.silicon, 60));
|
||||
ammo(
|
||||
Items.blastCompound, Bullets.missileExplosive,
|
||||
Items.pyratite, Bullets.missileIncendiary,
|
||||
Items.surgealloy, Bullets.missileSurge
|
||||
Items.blastCompound, Bullets.missileExplosive,
|
||||
Items.pyratite, Bullets.missileIncendiary,
|
||||
Items.surgealloy, Bullets.missileSurge
|
||||
);
|
||||
reload = 50f;
|
||||
shots = 4;
|
||||
@@ -885,12 +975,13 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
salvo = new BurstTurret("salvo"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 210, Items.graphite, 190, Items.thorium, 130));
|
||||
ammo(
|
||||
Items.copper, Bullets.standardCopper,
|
||||
Items.graphite, Bullets.standardDense,
|
||||
Items.pyratite, Bullets.standardIncendiary,
|
||||
Items.silicon, Bullets.standardHoming,
|
||||
Items.thorium, Bullets.standardThorium
|
||||
Items.copper, Bullets.standardCopper,
|
||||
Items.graphite, Bullets.standardDense,
|
||||
Items.pyratite, Bullets.standardIncendiary,
|
||||
Items.silicon, Bullets.standardHoming,
|
||||
Items.thorium, Bullets.standardThorium
|
||||
);
|
||||
|
||||
size = 2;
|
||||
@@ -908,12 +999,13 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
ripple = new ArtilleryTurret("ripple"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 300, Items.graphite, 220, Items.thorium, 120));
|
||||
ammo(
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary,
|
||||
Items.blastCompound, Bullets.artilleryExplosive,
|
||||
Items.plastanium, Bullets.arilleryPlastic
|
||||
Items.graphite, Bullets.artilleryDense,
|
||||
Items.silicon, Bullets.artilleryHoming,
|
||||
Items.pyratite, Bullets.artlleryIncendiary,
|
||||
Items.blastCompound, Bullets.artilleryExplosive,
|
||||
Items.plastanium, Bullets.arilleryPlastic
|
||||
);
|
||||
size = 3;
|
||||
shots = 4;
|
||||
@@ -932,10 +1024,11 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
cyclone = new ItemTurret("cyclone"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 400, Items.surgealloy, 200, Items.plastanium, 150));
|
||||
ammo(
|
||||
Items.blastCompound, Bullets.flakExplosive,
|
||||
Items.plastanium, Bullets.flakPlastic,
|
||||
Items.surgealloy, Bullets.flakSurge
|
||||
Items.blastCompound, Bullets.flakExplosive,
|
||||
Items.plastanium, Bullets.flakPlastic,
|
||||
Items.surgealloy, Bullets.flakSurge
|
||||
);
|
||||
xRand = 4f;
|
||||
reload = 8f;
|
||||
@@ -950,6 +1043,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
fuse = new ItemTurret("fuse"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 450, Items.graphite, 450, Items.surgealloy, 250));
|
||||
ammo(Items.graphite, Bullets.fuseShot);
|
||||
reload = 50f;
|
||||
shootShake = 4f;
|
||||
@@ -962,10 +1056,11 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
spectre = new DoubleTurret("spectre"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 700, Items.graphite, 600, Items.surgealloy, 500, Items.plastanium, 350, Items.thorium, 500));
|
||||
ammo(
|
||||
Items.graphite, Bullets.standardDenseBig,
|
||||
Items.pyratite, Bullets.standardIncendiaryBig,
|
||||
Items.thorium, Bullets.standardThoriumBig
|
||||
Items.graphite, Bullets.standardDenseBig,
|
||||
Items.pyratite, Bullets.standardIncendiaryBig,
|
||||
Items.thorium, Bullets.standardThoriumBig
|
||||
);
|
||||
reload = 6f;
|
||||
coolantMultiplier = 0.5f;
|
||||
@@ -986,6 +1081,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
meltdown = new LaserTurret("meltdown"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 500, Items.lead, 700, Items.graphite, 600, Items.surgealloy, 650, Items.silicon, 650));
|
||||
shootType = Bullets.meltdownLaser;
|
||||
shootEffect = Fx.shootBigSmoke2;
|
||||
shootCone = 40f;
|
||||
@@ -1001,11 +1097,12 @@ public class Blocks implements ContentList{
|
||||
|
||||
health = 165 * size * size;
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region units
|
||||
|
||||
spiritFactory = new UnitFactory("spirit-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.copper, 70, Items.lead, 110, Items.silicon, 130));
|
||||
type = UnitTypes.spirit;
|
||||
produceTime = 5700;
|
||||
size = 2;
|
||||
@@ -1014,6 +1111,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
phantomFactory = new UnitFactory("phantom-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.titanium, 90, Items.thorium, 80, Items.lead, 110, Items.silicon, 210));
|
||||
type = UnitTypes.phantom;
|
||||
produceTime = 7300;
|
||||
size = 2;
|
||||
@@ -1022,6 +1120,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
wraithFactory = new UnitFactory("wraith-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.titanium, 60, Items.lead, 80, Items.silicon, 90));
|
||||
type = UnitTypes.wraith;
|
||||
produceTime = 1800;
|
||||
size = 2;
|
||||
@@ -1030,6 +1129,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
ghoulFactory = new UnitFactory("ghoul-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.plastanium, 80, Items.titanium, 100, Items.lead, 130, Items.silicon, 220));
|
||||
type = UnitTypes.ghoul;
|
||||
produceTime = 3600;
|
||||
size = 3;
|
||||
@@ -1038,6 +1138,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
revenantFactory = new UnitFactory("revenant-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.plastanium, 300, Items.titanium, 400, Items.lead, 300, Items.silicon, 400, Items.surgealloy, 100));
|
||||
type = UnitTypes.revenant;
|
||||
produceTime = 8000;
|
||||
size = 4;
|
||||
@@ -1046,6 +1147,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
daggerFactory = new UnitFactory("dagger-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.lead, 90, Items.silicon, 70));
|
||||
type = UnitTypes.dagger;
|
||||
produceTime = 1700;
|
||||
size = 2;
|
||||
@@ -1054,6 +1156,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
titanFactory = new UnitFactory("titan-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.thorium, 90, Items.lead, 140, Items.silicon, 90));
|
||||
type = UnitTypes.titan;
|
||||
produceTime = 3400;
|
||||
size = 3;
|
||||
@@ -1062,6 +1165,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
fortressFactory = new UnitFactory("fortress-factory"){{
|
||||
requirements(Category.units, ItemStack.with(Items.thorium, 200, Items.lead, 220, Items.silicon, 150, Items.surgealloy, 100, Items.phasefabric, 50));
|
||||
type = UnitTypes.fortress;
|
||||
produceTime = 5000;
|
||||
size = 3;
|
||||
@@ -1070,64 +1174,73 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
repairPoint = new RepairPoint("repair-point"){{
|
||||
requirements(Category.units, ItemStack.with(Items.lead, 30, Items.copper, 30, Items.silicon, 30));
|
||||
repairSpeed = 0.1f;
|
||||
}};
|
||||
|
||||
reconstructor = new Reconstructor("reconstructor"){{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region upgrades
|
||||
|
||||
alphaPad = new MechPad("alpha-mech-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 200, Items.graphite, 100, Items.copper, 150));
|
||||
mech = Mechs.alpha;
|
||||
size = 2;
|
||||
consumes.powerBuffered(50f);
|
||||
}};
|
||||
|
||||
deltaPad = new MechPad("delta-mech-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.titanium, 350, Items.copper, 400, Items.silicon, 450, Items.thorium, 300));
|
||||
mech = Mechs.delta;
|
||||
size = 2;
|
||||
consumes.powerBuffered(70f);
|
||||
}};
|
||||
|
||||
tauPad = new MechPad("tau-mech-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.titanium, 250, Items.copper, 250, Items.silicon, 250));
|
||||
mech = Mechs.tau;
|
||||
size = 2;
|
||||
consumes.powerBuffered(100f);
|
||||
}};
|
||||
|
||||
omegaPad = new MechPad("omega-mech-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.graphite, 550, Items.silicon, 650, Items.thorium, 600, Items.surgealloy, 240));
|
||||
mech = Mechs.omega;
|
||||
size = 3;
|
||||
consumes.powerBuffered(120f);
|
||||
}};
|
||||
|
||||
dartPad = new MechPad("dart-ship-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 150, Items.copper, 150, Items.silicon, 200, Items.titanium, 240));
|
||||
mech = Mechs.dart;
|
||||
size = 2;
|
||||
consumes.powerBuffered(50f);
|
||||
}};
|
||||
|
||||
javelinPad = new MechPad("javelin-ship-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.silicon, 450, Items.titanium, 500, Items.plastanium, 400, Items.phasefabric, 200));
|
||||
mech = Mechs.javelin;
|
||||
size = 2;
|
||||
consumes.powerBuffered(80f);
|
||||
}};
|
||||
|
||||
tridentPad = new MechPad("trident-ship-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.copper, 250, Items.silicon, 250, Items.titanium, 300, Items.plastanium, 200));
|
||||
mech = Mechs.trident;
|
||||
size = 2;
|
||||
consumes.powerBuffered(100f);
|
||||
}};
|
||||
|
||||
glaivePad = new MechPad("glaive-ship-pad"){{
|
||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.silicon, 650, Items.titanium, 700, Items.plastanium, 600, Items.surgealloy, 200));
|
||||
mech = Mechs.glaive;
|
||||
size = 3;
|
||||
consumes.powerBuffered(120f);
|
||||
}};
|
||||
|
||||
|
||||
//endregion
|
||||
//region ores
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ public class Bullets implements ContentList{
|
||||
bulletHeight = 9f;
|
||||
homingPower = 5f;
|
||||
reloadMultiplier = 1.4f;
|
||||
ammoMultiplier = 5;
|
||||
ammoMultiplier = 3;
|
||||
}};
|
||||
|
||||
standardIncendiary = new BasicBulletType(3.2f, 11, "bullet"){{
|
||||
|
||||
@@ -24,14 +24,15 @@ public class Fx implements ContentList{
|
||||
vtolHover, unitDrop, unitPickup, unitLand, pickup, healWave, heal, landShock, reactorsmoke, nuclearsmoke, nuclearcloud,
|
||||
redgeneratespark, generatespark, fuelburn, plasticburn, pulverize, pulverizeRed, pulverizeRedder, pulverizeSmall, pulverizeMedium,
|
||||
producesmoke, smeltsmoke, formsmoke, blastsmoke, lava, doorclose, dooropen, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate,
|
||||
mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble, commandSend,
|
||||
mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble, launch,
|
||||
healBlock, healBlockFull, healWaveMend, overdriveWave, overdriveBlockFull, shieldBreak, hitBulletSmall, hitFuse,
|
||||
hitBulletBig, hitFlameSmall, hitLiquid, hitLaser, hitLancer, hitMeltdown, despawn, flakExplosion, blastExplosion,
|
||||
plasticExplosion, artilleryTrail, incendTrail, missileTrail, absorb, flakExplosionBig, plasticExplosionFlak, burning, fire,
|
||||
fireSmoke, steam, fireballsmoke, ballfire, freezing, melting, wet, oily, overdriven, dropItem, shockwave,
|
||||
bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke,
|
||||
shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium,
|
||||
shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot;
|
||||
shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot,
|
||||
launchFull;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -1060,7 +1061,7 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
commandSend = new Effect(28, e -> {
|
||||
launch = new Effect(28, e -> {
|
||||
Draw.color(Palette.command);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.poly(e.x, e.y, 40, 4f + e.finpow() * 120f);
|
||||
@@ -1108,5 +1109,12 @@ public class Fx implements ContentList{
|
||||
Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
launchFull = new Effect(60, 9999999999f, e -> {
|
||||
Draw.color();
|
||||
Draw.alpha(e.fslope());
|
||||
Fill.rect(Core.camera.position.x, Core.camera.position.y, Core.camera.width + 10, Core.camera.height + 10);
|
||||
Draw.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.anuke.mindustry.type.ItemType;
|
||||
|
||||
public class Items implements ContentList{
|
||||
public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phasefabric, surgealloy,
|
||||
biomatter, sand, blastCompound, pyratite, bioglass;
|
||||
biomatter, sand, blastCompound, pyratite, metaglass;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -26,6 +26,11 @@ public class Items implements ContentList{
|
||||
genOre = true;
|
||||
}};
|
||||
|
||||
metaglass = new Item("metaglass", Color.valueOf("648b55")){{
|
||||
type = ItemType.material;
|
||||
cost = 2f;
|
||||
}};
|
||||
|
||||
graphite = new Item("graphite", Color.valueOf("b2c6d2")){{
|
||||
type = ItemType.material;
|
||||
cost = 1.3f;
|
||||
@@ -55,7 +60,7 @@ public class Items implements ContentList{
|
||||
}};
|
||||
|
||||
scrap = new Item("scrap", Color.valueOf("777777")){{
|
||||
|
||||
genOre = true;
|
||||
}};
|
||||
|
||||
silicon = new Item("silicon", Color.valueOf("53565c")){{
|
||||
@@ -99,10 +104,5 @@ public class Items implements ContentList{
|
||||
flammability = 0.7f;
|
||||
explosiveness = 0.2f;
|
||||
}};
|
||||
|
||||
bioglass = new Item("bioglass", Color.valueOf("648b55")){{
|
||||
type = ItemType.material;
|
||||
cost = 2f;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
|
||||
public class Liquids implements ContentList{
|
||||
public static Liquid water, slag, oil, cryofluid, acid;
|
||||
public static Liquid water, slag, oil, cryofluid;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -16,7 +16,7 @@ public class Liquids implements ContentList{
|
||||
effect = StatusEffects.wet;
|
||||
}};
|
||||
|
||||
slag = new Liquid("slag", Color.valueOf("e37341")){{
|
||||
slag = new Liquid("slag", Color.valueOf("ffcd66")){{
|
||||
temperature = 1f;
|
||||
viscosity = 0.8f;
|
||||
tier = 2;
|
||||
@@ -38,10 +38,5 @@ public class Liquids implements ContentList{
|
||||
tier = 1;
|
||||
effect = StatusEffects.freezing;
|
||||
}};
|
||||
|
||||
acid = new Liquid("acid", Color.valueOf("e9f9b3")){{
|
||||
heatCapacity = 0.1f; //don't use acid as coolant, it's bad
|
||||
effect = StatusEffects.corroded;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ public class Mechs implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAlt(Player player){
|
||||
|
||||
public boolean alwaysUnlocked(){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -182,18 +182,25 @@ public class Mechs implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
dart = new Mech("dart-ship", true){{
|
||||
drillPower = 1;
|
||||
mineSpeed = 0.9f;
|
||||
speed = 0.4f;
|
||||
drag = 0.1f;
|
||||
armor = 10f;
|
||||
weapon = Weapons.blasterSmall;
|
||||
weaponOffsetX = -1;
|
||||
weaponOffsetY = -1;
|
||||
trailColor = Palette.lightTrail;
|
||||
cellTrnsY = 1f;
|
||||
}};
|
||||
dart = new Mech("dart-ship", true){
|
||||
{
|
||||
drillPower = 1;
|
||||
mineSpeed = 0.9f;
|
||||
speed = 0.4f;
|
||||
drag = 0.1f;
|
||||
armor = 10f;
|
||||
weapon = Weapons.blasterSmall;
|
||||
weaponOffsetX = -1;
|
||||
weaponOffsetY = -1;
|
||||
trailColor = Palette.lightTrail;
|
||||
cellTrnsY = 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
javelin = new Mech("javelin-ship", true){
|
||||
float minV = 3.6f;
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.type.Recipe.RecipeVisibility;
|
||||
|
||||
import static io.anuke.mindustry.type.Category.*;
|
||||
|
||||
public class Recipes implements ContentList{
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
//DEBUG
|
||||
new Recipe(distribution, Blocks.itemSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
|
||||
new Recipe(distribution, Blocks.itemVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
|
||||
new Recipe(liquid, Blocks.liquidSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
|
||||
new Recipe(power, Blocks.powerVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
|
||||
new Recipe(power, Blocks.powerSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
|
||||
|
||||
//DEFENSE
|
||||
|
||||
//walls
|
||||
new Recipe(defense, Blocks.copperWall, new ItemStack(Items.copper, 12)).setAlwaysUnlocked(true);
|
||||
new Recipe(defense, Blocks.copperWallLarge, new ItemStack(Items.copper, 12 * 4)).setAlwaysUnlocked(true);
|
||||
|
||||
new Recipe(defense, Blocks.titaniumWall, new ItemStack(Items.titanium, 12));
|
||||
new Recipe(defense, Blocks.titaniumWallLarge, new ItemStack(Items.titanium, 12 * 4));
|
||||
|
||||
new Recipe(defense, Blocks.door, new ItemStack(Items.titanium, 12), new ItemStack(Items.silicon, 8));
|
||||
new Recipe(defense, Blocks.doorLarge, new ItemStack(Items.titanium, 12 * 4), new ItemStack(Items.silicon, 8 * 4));
|
||||
|
||||
new Recipe(defense, Blocks.thoriumWall, new ItemStack(Items.thorium, 12));
|
||||
new Recipe(defense, Blocks.thoriumWallLarge, new ItemStack(Items.thorium, 12 * 4));
|
||||
|
||||
new Recipe(defense, Blocks.phaseWall, new ItemStack(Items.phasefabric, 12));
|
||||
new Recipe(defense, Blocks.phaseWallLarge, new ItemStack(Items.phasefabric, 12 * 4));
|
||||
|
||||
new Recipe(defense, Blocks.surgeWall, new ItemStack(Items.surgealloy, 12));
|
||||
new Recipe(defense, Blocks.surgeWallLarge, new ItemStack(Items.surgealloy, 12 * 4));
|
||||
|
||||
new Recipe(effect, Blocks.container, new ItemStack(Items.titanium, 200));
|
||||
new Recipe(effect, Blocks.vault, new ItemStack(Items.titanium, 500), new ItemStack(Items.thorium, 250));
|
||||
new Recipe(effect, Blocks.launchPad, new ItemStack(Items.copper, 500));
|
||||
|
||||
//projectors
|
||||
new Recipe(effect, Blocks.mendProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.titanium, 150), new ItemStack(Items.titanium, 50), new ItemStack(Items.silicon, 180));
|
||||
new Recipe(effect, Blocks.overdriveProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.titanium, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250));
|
||||
new Recipe(effect, Blocks.forceProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.titanium, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250));
|
||||
|
||||
new Recipe(effect, Blocks.shockMine, new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 25));
|
||||
|
||||
//TURRETS
|
||||
new Recipe(turret, Blocks.duo, new ItemStack(Items.copper, 40)).setAlwaysUnlocked(true);
|
||||
new Recipe(turret, Blocks.arc, new ItemStack(Items.copper, 50), new ItemStack(Items.lead, 40));
|
||||
new Recipe(turret, Blocks.hail, new ItemStack(Items.copper, 60), new ItemStack(Items.graphite, 35));
|
||||
new Recipe(turret, Blocks.lancer, new ItemStack(Items.copper, 50), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 90));
|
||||
new Recipe(turret, Blocks.wave, new ItemStack(Items.titanium, 70), new ItemStack(Items.lead, 150));
|
||||
new Recipe(turret, Blocks.salvo, new ItemStack(Items.copper, 210), new ItemStack(Items.graphite, 190), new ItemStack(Items.thorium, 130));
|
||||
new Recipe(turret, Blocks.swarmer, new ItemStack(Items.graphite, 70), new ItemStack(Items.titanium, 70), new ItemStack(Items.plastanium, 90), new ItemStack(Items.silicon, 60));
|
||||
new Recipe(turret, Blocks.ripple, new ItemStack(Items.copper, 300), new ItemStack(Items.graphite, 220), new ItemStack(Items.thorium, 120));
|
||||
new Recipe(turret, Blocks.cyclone, new ItemStack(Items.copper, 400), new ItemStack(Items.surgealloy, 200), new ItemStack(Items.plastanium, 150));
|
||||
new Recipe(turret, Blocks.fuse, new ItemStack(Items.copper, 450), new ItemStack(Items.graphite, 450), new ItemStack(Items.surgealloy, 250));
|
||||
new Recipe(turret, Blocks.spectre, new ItemStack(Items.copper, 700), new ItemStack(Items.graphite, 600), new ItemStack(Items.surgealloy, 500), new ItemStack(Items.plastanium, 350), new ItemStack(Items.thorium, 500));
|
||||
new Recipe(turret, Blocks.meltdown, new ItemStack(Items.copper, 500), new ItemStack(Items.lead, 700), new ItemStack(Items.graphite, 600), new ItemStack(Items.surgealloy, 650), new ItemStack(Items.silicon, 650));
|
||||
|
||||
//DISTRIBUTION
|
||||
new Recipe(distribution, Blocks.conveyor, new ItemStack(Items.copper, 1)).setAlwaysUnlocked(true);
|
||||
new Recipe(distribution, Blocks.titaniumConveyor, new ItemStack(Items.copper, 2), new ItemStack(Items.titanium, 1));
|
||||
new Recipe(distribution, Blocks.phaseConveyor, new ItemStack(Items.phasefabric, 10), new ItemStack(Items.silicon, 15), new ItemStack(Items.lead, 20), new ItemStack(Items.graphite, 20));
|
||||
|
||||
//starter transport
|
||||
new Recipe(distribution, Blocks.junction, new ItemStack(Items.copper, 2)).setAlwaysUnlocked(true);
|
||||
new Recipe(distribution, Blocks.router, new ItemStack(Items.copper, 6)).setAlwaysUnlocked(true);
|
||||
|
||||
//more advanced transport
|
||||
new Recipe(distribution, Blocks.distributor, new ItemStack(Items.titanium, 8), new ItemStack(Items.copper, 8));
|
||||
new Recipe(distribution, Blocks.sorter, new ItemStack(Items.titanium, 4), new ItemStack(Items.copper, 4));
|
||||
new Recipe(distribution, Blocks.overflowGate, new ItemStack(Items.titanium, 4), new ItemStack(Items.copper, 8));
|
||||
new Recipe(distribution, Blocks.itemBridge, new ItemStack(Items.titanium, 8), new ItemStack(Items.copper, 8));
|
||||
new Recipe(distribution, Blocks.unloader, new ItemStack(Items.titanium, 50), new ItemStack(Items.silicon, 60));
|
||||
new Recipe(distribution, Blocks.massDriver, new ItemStack(Items.titanium, 250), new ItemStack(Items.silicon, 150), new ItemStack(Items.lead, 250), new ItemStack(Items.thorium, 100));
|
||||
|
||||
//CRAFTING
|
||||
|
||||
//smelting
|
||||
new Recipe(crafting, Blocks.siliconSmelter, new ItemStack(Items.copper, 60), new ItemStack(Items.lead, 50));
|
||||
|
||||
//advanced fabrication
|
||||
new Recipe(crafting, Blocks.plastaniumCompressor, new ItemStack(Items.silicon, 160), new ItemStack(Items.lead, 230), new ItemStack(Items.graphite, 120), new ItemStack(Items.titanium, 160));
|
||||
new Recipe(crafting, Blocks.phaseWeaver, new ItemStack(Items.silicon, 260), new ItemStack(Items.lead, 240), new ItemStack(Items.thorium, 150));
|
||||
new Recipe(crafting, Blocks.surgeSmelter, new ItemStack(Items.silicon, 160), new ItemStack(Items.lead, 160), new ItemStack(Items.thorium, 140));
|
||||
|
||||
//misc
|
||||
new Recipe(crafting, Blocks.pulverizer, new ItemStack(Items.copper, 60), new ItemStack(Items.lead, 50));
|
||||
new Recipe(crafting, Blocks.pyratiteMixer, new ItemStack(Items.copper, 100), new ItemStack(Items.lead, 50));
|
||||
new Recipe(crafting, Blocks.blastMixer, new ItemStack(Items.lead, 60), new ItemStack(Items.titanium, 40));
|
||||
new Recipe(crafting, Blocks.cryofluidMixer, new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 80), new ItemStack(Items.thorium, 90));
|
||||
|
||||
new Recipe(crafting, Blocks.melter, new ItemStack(Items.copper, 60), new ItemStack(Items.lead, 70), new ItemStack(Items.graphite, 90));
|
||||
new Recipe(crafting, Blocks.incinerator, new ItemStack(Items.graphite, 10), new ItemStack(Items.lead, 30));
|
||||
|
||||
//processing
|
||||
new Recipe(crafting, Blocks.biomatterCompressor, new ItemStack(Items.lead, 70), new ItemStack(Items.silicon, 60));
|
||||
new Recipe(crafting, Blocks.separator, new ItemStack(Items.copper, 60), new ItemStack(Items.titanium, 50));
|
||||
|
||||
//POWER
|
||||
new Recipe(power, Blocks.powerNode, new ItemStack(Items.copper, 2), new ItemStack(Items.lead, 6));
|
||||
new Recipe(power, Blocks.powerNodeLarge, new ItemStack(Items.titanium, 10), new ItemStack(Items.lead, 20), new ItemStack(Items.silicon, 6));
|
||||
new Recipe(power, Blocks.battery, new ItemStack(Items.copper, 8), new ItemStack(Items.lead, 30), new ItemStack(Items.silicon, 4));
|
||||
new Recipe(power, Blocks.batteryLarge, new ItemStack(Items.titanium, 40), new ItemStack(Items.lead, 80), new ItemStack(Items.silicon, 30));
|
||||
|
||||
//generators - combustion
|
||||
new Recipe(power, Blocks.combustionGenerator, new ItemStack(Items.copper, 50), new ItemStack(Items.lead, 30));
|
||||
new Recipe(power, Blocks.turbineGenerator, new ItemStack(Items.copper, 70), new ItemStack(Items.graphite, 50), new ItemStack(Items.lead, 80), new ItemStack(Items.silicon, 60));
|
||||
new Recipe(power, Blocks.thermalGenerator, new ItemStack(Items.copper, 80), new ItemStack(Items.graphite, 70), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 70), new ItemStack(Items.thorium, 70));
|
||||
|
||||
//generators - solar
|
||||
new Recipe(power, Blocks.solarPanel, new ItemStack(Items.lead, 20), new ItemStack(Items.silicon, 30));
|
||||
new Recipe(power, Blocks.largeSolarPanel, new ItemStack(Items.lead, 200), new ItemStack(Items.silicon, 290), new ItemStack(Items.phasefabric, 30));
|
||||
|
||||
//generators - nuclear
|
||||
new Recipe(power, Blocks.thoriumReactor, new ItemStack(Items.lead, 600), new ItemStack(Items.silicon, 400), new ItemStack(Items.graphite, 300), new ItemStack(Items.thorium, 300));
|
||||
new Recipe(power, Blocks.rtgGenerator, new ItemStack(Items.lead, 200), new ItemStack(Items.silicon, 150), new ItemStack(Items.phasefabric, 50), new ItemStack(Items.plastanium, 150), new ItemStack(Items.thorium, 100));
|
||||
|
||||
//DRILLS, PRODUCERS
|
||||
new Recipe(production, Blocks.mechanicalDrill, new ItemStack(Items.copper, 20)).setAlwaysUnlocked(true);
|
||||
new Recipe(production, Blocks.pneumaticDrill, new ItemStack(Items.copper, 60), new ItemStack(Items.graphite, 50));
|
||||
new Recipe(production, Blocks.laserDrill, new ItemStack(Items.copper, 70), new ItemStack(Items.graphite, 90), new ItemStack(Items.silicon, 60), new ItemStack(Items.titanium, 50));
|
||||
new Recipe(production, Blocks.blastDrill, new ItemStack(Items.copper, 130), new ItemStack(Items.silicon, 120), new ItemStack(Items.titanium, 100), new ItemStack(Items.thorium, 60));
|
||||
|
||||
new Recipe(production, Blocks.waterExtractor, new ItemStack(Items.copper, 50), new ItemStack(Items.graphite, 50), new ItemStack(Items.lead, 40));
|
||||
new Recipe(production, Blocks.cultivator, new ItemStack(Items.copper, 20), new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 20));
|
||||
new Recipe(production, Blocks.oilExtractor, new ItemStack(Items.copper, 300), new ItemStack(Items.graphite, 350), new ItemStack(Items.lead, 230), new ItemStack(Items.thorium, 230), new ItemStack(Items.silicon, 150));
|
||||
|
||||
//UNITS
|
||||
|
||||
//upgrades
|
||||
new Recipe(upgrade, Blocks.dartPad, new ItemStack(Items.lead, 150), new ItemStack(Items.copper, 150), new ItemStack(Items.silicon, 200), new ItemStack(Items.titanium, 240)).setVisible(RecipeVisibility.desktopOnly);
|
||||
new Recipe(upgrade, Blocks.tridentPad, new ItemStack(Items.lead, 250), new ItemStack(Items.copper, 250), new ItemStack(Items.silicon, 250), new ItemStack(Items.titanium, 300), new ItemStack(Items.plastanium, 200));
|
||||
new Recipe(upgrade, Blocks.javelinPad, new ItemStack(Items.lead, 350), new ItemStack(Items.silicon, 450), new ItemStack(Items.titanium, 500), new ItemStack(Items.plastanium, 400), new ItemStack(Items.phasefabric, 200));
|
||||
new Recipe(upgrade, Blocks.glaivePad, new ItemStack(Items.lead, 450), new ItemStack(Items.silicon, 650), new ItemStack(Items.titanium, 700), new ItemStack(Items.plastanium, 600), new ItemStack(Items.surgealloy, 200));
|
||||
|
||||
new Recipe(upgrade, Blocks.alphaPad, new ItemStack(Items.lead, 200), new ItemStack(Items.graphite, 100), new ItemStack(Items.copper, 150)).setVisible(RecipeVisibility.mobileOnly);
|
||||
new Recipe(upgrade, Blocks.tauPad, new ItemStack(Items.lead, 250), new ItemStack(Items.titanium, 250), new ItemStack(Items.copper, 250), new ItemStack(Items.silicon, 250));
|
||||
new Recipe(upgrade, Blocks.deltaPad, new ItemStack(Items.lead, 350), new ItemStack(Items.titanium, 350), new ItemStack(Items.copper, 400), new ItemStack(Items.silicon, 450), new ItemStack(Items.thorium, 300));
|
||||
new Recipe(upgrade, Blocks.omegaPad, new ItemStack(Items.lead, 450), new ItemStack(Items.graphite, 550), new ItemStack(Items.silicon, 650), new ItemStack(Items.thorium, 600), new ItemStack(Items.surgealloy, 240));
|
||||
|
||||
//unit factories
|
||||
new Recipe(units, Blocks.spiritFactory, new ItemStack(Items.copper, 70), new ItemStack(Items.lead, 110), new ItemStack(Items.silicon, 130));
|
||||
new Recipe(units, Blocks.phantomFactory, new ItemStack(Items.titanium, 90), new ItemStack(Items.thorium, 80), new ItemStack(Items.lead, 110), new ItemStack(Items.silicon, 210));
|
||||
|
||||
new Recipe(units, Blocks.daggerFactory, new ItemStack(Items.lead, 90), new ItemStack(Items.silicon, 70));
|
||||
new Recipe(units, Blocks.titanFactory, new ItemStack(Items.thorium, 90), new ItemStack(Items.lead, 140), new ItemStack(Items.silicon, 90));
|
||||
new Recipe(units, Blocks.fortressFactory, new ItemStack(Items.thorium, 200), new ItemStack(Items.lead, 220), new ItemStack(Items.silicon, 150), new ItemStack(Items.surgealloy, 100), new ItemStack(Items.phasefabric, 50));
|
||||
|
||||
new Recipe(units, Blocks.wraithFactory, new ItemStack(Items.titanium, 60), new ItemStack(Items.lead, 80), new ItemStack(Items.silicon, 90));
|
||||
new Recipe(units, Blocks.ghoulFactory, new ItemStack(Items.plastanium, 80), new ItemStack(Items.titanium, 100), new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 220));
|
||||
new Recipe(units, Blocks.revenantFactory, new ItemStack(Items.plastanium, 300), new ItemStack(Items.titanium, 400), new ItemStack(Items.lead, 300), new ItemStack(Items.silicon, 400), new ItemStack(Items.surgealloy, 100));
|
||||
|
||||
new Recipe(units, Blocks.repairPoint, new ItemStack(Items.lead, 30), new ItemStack(Items.copper, 30), new ItemStack(Items.silicon, 30));
|
||||
|
||||
//removed for testing MOBA-style unit production
|
||||
//new Recipe(units, Blocks.commandCenter, new ItemStack(Items.lead, 100), new ItemStack(Items.densealloy, 100), new ItemStack(Items.silicon, 200));
|
||||
|
||||
//LIQUIDS
|
||||
new Recipe(liquid, Blocks.conduit, new ItemStack(Items.lead, 1));
|
||||
new Recipe(liquid, Blocks.pulseConduit, new ItemStack(Items.titanium, 1), new ItemStack(Items.lead, 1));
|
||||
new Recipe(liquid, Blocks.phaseConduit, new ItemStack(Items.phasefabric, 10), new ItemStack(Items.silicon, 15), new ItemStack(Items.lead, 20), new ItemStack(Items.titanium, 20));
|
||||
|
||||
new Recipe(liquid, Blocks.liquidRouter, new ItemStack(Items.titanium, 4), new ItemStack(Items.lead, 4));
|
||||
new Recipe(liquid, Blocks.liquidTank, new ItemStack(Items.titanium, 50), new ItemStack(Items.lead, 50));
|
||||
new Recipe(liquid, Blocks.liquidJunction, new ItemStack(Items.titanium, 4), new ItemStack(Items.lead, 4));
|
||||
new Recipe(liquid, Blocks.bridgeConduit, new ItemStack(Items.titanium, 8), new ItemStack(Items.lead, 8));
|
||||
|
||||
new Recipe(liquid, Blocks.mechanicalPump, new ItemStack(Items.copper, 30), new ItemStack(Items.lead, 20));
|
||||
new Recipe(liquid, Blocks.rotaryPump, new ItemStack(Items.copper, 140), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 70));
|
||||
new Recipe(liquid, Blocks.thermalPump, new ItemStack(Items.copper, 160), new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 60), new ItemStack(Items.titanium, 80), new ItemStack(Items.thorium, 70));
|
||||
}
|
||||
}
|
||||
285
core/src/io/anuke/mindustry/content/TechTree.java
Normal file
285
core/src/io/anuke/mindustry/content/TechTree.java
Normal file
@@ -0,0 +1,285 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.content.Blocks.*;
|
||||
|
||||
public class TechTree implements ContentList{
|
||||
public static TechNode root;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
root = node(core, () -> {
|
||||
|
||||
node(conveyor, () -> {
|
||||
node(launchPad, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(junction, () -> {
|
||||
node(itemBridge);
|
||||
node(router, () -> {
|
||||
node(distributor);
|
||||
node(overflowGate);
|
||||
node(sorter);
|
||||
node(container, () -> {
|
||||
node(unloader);
|
||||
node(vault, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
node(titaniumConveyor, () -> {
|
||||
node(phaseConveyor, () -> {
|
||||
node(massDriver, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(duo, () -> {
|
||||
node(hail, () -> {
|
||||
|
||||
node(salvo, () -> {
|
||||
node(swarmer, () -> {
|
||||
node(cyclone, () -> {
|
||||
node(spectre, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(ripple, () -> {
|
||||
node(fuse, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(arc, () -> {
|
||||
node(wave, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(lancer, () -> {
|
||||
node(meltdown, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(shockMine, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(copperWall, () -> {
|
||||
node(copperWallLarge);
|
||||
node(titaniumWall, () -> {
|
||||
node(door, () -> {
|
||||
node(doorLarge);
|
||||
});
|
||||
node(titaniumWallLarge);
|
||||
node(thoriumWall, () -> {
|
||||
node(thoriumWallLarge);
|
||||
node(surgeWall, () -> {
|
||||
node(surgeWallLarge);
|
||||
node(phaseWall, () -> {
|
||||
node(phaseWallLarge);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(mechanicalDrill, () -> {
|
||||
node(pneumaticDrill, () -> {
|
||||
node(cultivator, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(laserDrill, () -> {
|
||||
node(blastDrill, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(waterExtractor, () -> {
|
||||
node(oilExtractor, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(siliconSmelter, () -> {
|
||||
|
||||
node(pyratiteMixer, () -> {
|
||||
node(blastMixer, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(biomatterCompressor, () -> {
|
||||
node(plastaniumCompressor, () -> {
|
||||
node(phaseWeaver, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(incinerator, () -> {
|
||||
node(melter, () -> {
|
||||
node(surgeSmelter, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(separator, () -> {
|
||||
node(pulverizer, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(cryofluidMixer, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(mechanicalPump, () -> {
|
||||
node(conduit, () -> {
|
||||
node(liquidJunction, () -> {
|
||||
node(liquidRouter, () -> {
|
||||
node(liquidTank);
|
||||
|
||||
node(pulseConduit, () -> {
|
||||
node(phaseConduit, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(rotaryPump, () -> {
|
||||
node(thermalPump, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
node(bridgeConduit);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(powerNode, () -> {
|
||||
node(combustionGenerator, () -> {
|
||||
node(powerNodeLarge, () -> {
|
||||
node(battery, () -> {
|
||||
node(batteryLarge, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(mendProjector, () -> {
|
||||
node(forceProjector, () -> {
|
||||
node(overdriveProjector, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(repairPoint, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(turbineGenerator, () -> {
|
||||
node(thermalGenerator, () -> {
|
||||
node(rtgGenerator, () -> {
|
||||
node(thoriumReactor, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(solarPanel, () -> {
|
||||
node(largeSolarPanel, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(alphaPad, () -> {
|
||||
node(dartPad);
|
||||
node(deltaPad, () -> {
|
||||
node(javelinPad);
|
||||
node(tauPad, () -> {
|
||||
node(tridentPad);
|
||||
node(omegaPad, () -> {
|
||||
node(glaivePad);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(spiritFactory, () -> {
|
||||
node(daggerFactory, () -> {
|
||||
node(daggerFactory, () -> {
|
||||
node(titanFactory, () -> {
|
||||
node(fortressFactory);
|
||||
});
|
||||
node(wraithFactory, () -> {
|
||||
node(phantomFactory);
|
||||
node(ghoulFactory, () -> {
|
||||
node(revenantFactory);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private TechNode node(Block block, Runnable children){
|
||||
ItemStack[] requirements = new ItemStack[block.buildRequirements.length];
|
||||
for(int i = 0; i < requirements.length; i++){
|
||||
requirements[i] = new ItemStack(block.buildRequirements[i].item, block.buildRequirements[i].amount * 50);
|
||||
}
|
||||
|
||||
return new TechNode(block, requirements, children);
|
||||
}
|
||||
|
||||
private TechNode node(Block block){
|
||||
return node(block, () -> {});
|
||||
}
|
||||
|
||||
public static class TechNode{
|
||||
static TechNode context;
|
||||
|
||||
public final Block block;
|
||||
public final ItemStack[] requirements;
|
||||
public final Array<TechNode> children = new Array<>();
|
||||
|
||||
TechNode(Block block, ItemStack[] requirements, Runnable children){
|
||||
if(context != null){
|
||||
context.children.add(this);
|
||||
}
|
||||
|
||||
//TODO remove requirements... for now
|
||||
this.block = block;
|
||||
this.requirements = requirements;
|
||||
|
||||
TechNode last = context;
|
||||
context = this;
|
||||
children.run();
|
||||
context = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class Weapons implements ContentList{
|
||||
|
||||
blasterSmall = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 15f;
|
||||
reload = 20f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardCopper;
|
||||
@@ -28,7 +28,7 @@ public class Weapons implements ContentList{
|
||||
|
||||
glaiveBlaster = new Weapon("bomber"){{
|
||||
length = 1.5f;
|
||||
reload = 10f;
|
||||
reload = 13f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardGlaive;
|
||||
@@ -54,7 +54,7 @@ public class Weapons implements ContentList{
|
||||
|
||||
missiles = new Weapon("missiles"){{
|
||||
length = 1.5f;
|
||||
reload = 60f;
|
||||
reload = 70f;
|
||||
shots = 4;
|
||||
inaccuracy = 2f;
|
||||
roundrobin = true;
|
||||
|
||||
@@ -1,25 +1,207 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.maps.generators.BasicGenerator;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.maps.generators.MapGenerator;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
public class Zones implements ContentList{
|
||||
public Zone wasteland;
|
||||
public static Zone groundZero, craters, frozenForest, ruinousShores, crags, stainedMountains,
|
||||
impact, desolateRift, arcticDesert, dryWastes, nuclearComplex, moltenFault;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
wasteland = new Zone("wasteland", new BasicGenerator(256, 256, Items.lead, Items.copper)){{
|
||||
deployCost = ItemStack.with(Items.copper, 100);
|
||||
groundZero = new Zone("groundZero", new MapGenerator("groundZero", 1)){{
|
||||
deployCost = ItemStack.with(Items.copper, 60);
|
||||
startingItems = ItemStack.with(Items.copper, 50);
|
||||
alwaysUnlocked = true;
|
||||
conditionWave = 10;
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 60;
|
||||
waveSpacing = 60 * 60 * 2; //2 mins
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 10;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 15;
|
||||
unitScaling = 1;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 20;
|
||||
unitScaling = 1;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 25;
|
||||
unitScaling = 1;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 30;
|
||||
unitScaling = 1;
|
||||
}}
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
craters = new Zone("craters", new MapGenerator("craters", 1){{ distortion = 1.44f; }}){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
itemRequirements = ItemStack.with(Items.copper, 2000);
|
||||
zoneRequirements = new Zone[]{groundZero};
|
||||
blockRequirements = new Block[]{Blocks.router};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
frozenForest = new Zone("frozenForest", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
ruinousShores = new Zone("ruinousShores", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
crags = new Zone("crags", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
stainedMountains = new Zone("stainedMountains", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
impact = new Zone("impact", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
desolateRift = new Zone("desolateRift", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
arcticDesert = new Zone("arcticDesert", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
dryWastes = new Zone("dryWastes", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
nuclearComplex = new Zone("nuclearComplex", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
moltenFault = new Zone("moltenFault", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
frozenForest.zoneRequirements = new Zone[]{frozenForest};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ContentLoader{
|
||||
new Mechs(),
|
||||
new UnitTypes(),
|
||||
new Blocks(),
|
||||
new Recipes(),
|
||||
new TechTree(),
|
||||
new Zones(),
|
||||
|
||||
//these are not really content classes, but this makes initialization easier
|
||||
@@ -165,7 +165,7 @@ public class ContentLoader{
|
||||
}
|
||||
|
||||
if(id >= contentMap[type.ordinal()].size || id < 0){
|
||||
throw new RuntimeException("No " + type.name() + " with ID '" + id + "' found!");
|
||||
return null;
|
||||
}
|
||||
return (T)contentMap[type.ordinal()].get(id);
|
||||
}
|
||||
@@ -184,14 +184,6 @@ public class ContentLoader{
|
||||
return (Block) getByID(ContentType.block, id);
|
||||
}
|
||||
|
||||
public Array<Recipe> recipes(){
|
||||
return getBy(ContentType.recipe);
|
||||
}
|
||||
|
||||
public Recipe recipe(int id){
|
||||
return (Recipe) getByID(ContentType.recipe, id);
|
||||
}
|
||||
|
||||
public Array<Item> items(){
|
||||
return getBy(ContentType.item);
|
||||
}
|
||||
|
||||
@@ -116,9 +116,16 @@ public class Control implements ApplicationListener{
|
||||
//todo high scores for custom maps, as well as other statistics
|
||||
|
||||
Events.on(GameOverEvent.class, event -> {
|
||||
state.stats.wavesLasted = state.wave;
|
||||
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
||||
//the restart dialog can show info for any number of scenarios
|
||||
Call.onGameOver(event.winner);
|
||||
if(state.rules.zone != -1){
|
||||
//remove zone save on game over
|
||||
if(saves.getZoneSlot() != null){
|
||||
saves.getZoneSlot().delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//autohost for pvp sectors
|
||||
@@ -133,6 +140,30 @@ public class Control implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(UnlockEvent.class, e -> ui.hudfrag.showUnlock(e.content));
|
||||
|
||||
Events.on(BlockBuildEndEvent.class, e -> {
|
||||
if(e.team == players[0].getTeam()){
|
||||
if(e.breaking){
|
||||
state.stats.buildingsDeconstructed++;
|
||||
}else{
|
||||
state.stats.buildingsBuilt ++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(BlockDestroyEvent.class, e -> {
|
||||
if(e.tile.getTeam() == players[0].getTeam()){
|
||||
state.stats.buildingsDestroyed ++;
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(UnitDestroyEvent.class, e -> {
|
||||
if(e.unit.getTeam() != players[0].getTeam()){
|
||||
state.stats.enemyUnitsDestroyed ++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addPlayer(int index){
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.Stats;
|
||||
import io.anuke.mindustry.game.Teams;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
@@ -15,9 +16,11 @@ public class GameState{
|
||||
/**Wave countdown in ticks.*/
|
||||
public float wavetime;
|
||||
/**Whether the game is in game over state.*/
|
||||
public boolean gameOver = false;
|
||||
public boolean gameOver = false, launched = false;
|
||||
/**The current game rules.*/
|
||||
public Rules rules = new Rules();
|
||||
/**Statistics for this save/game. Displayed after game over.*/
|
||||
public Stats stats = new Stats();
|
||||
/**Team data. Gets reset every new game.*/
|
||||
public Teams teams = new Teams();
|
||||
/**Number of enemies in the game; only used clientside in servers.*/
|
||||
|
||||
@@ -11,12 +11,8 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Teams;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -33,8 +29,14 @@ public class Logic implements ApplicationListener{
|
||||
|
||||
public Logic(){
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
if(event.tile.getTeam() == defaultTeam && Recipe.getByResult(event.tile.block()) != null){
|
||||
handleContent(Recipe.getByResult(event.tile.block()));
|
||||
if(event.tile.getTeam() == defaultTeam && event.tile.block().isVisible()){
|
||||
handleContent(event.tile.block());
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(WaveEvent.class, event -> {
|
||||
if(world.isZone()){
|
||||
data.updateWaveScore(world.getZone(), state.wave);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -65,9 +67,11 @@ public class Logic implements ApplicationListener{
|
||||
public void reset(){
|
||||
state.wave = 1;
|
||||
state.wavetime = state.rules.waveSpacing;
|
||||
state.gameOver = false;
|
||||
state.gameOver = state.launched = false;
|
||||
state.teams = new Teams();
|
||||
state.rules = new Rules();
|
||||
state.rules.spawns = Waves.getDefaultSpawns();
|
||||
state.stats = new Stats();
|
||||
|
||||
Time.clear();
|
||||
Entities.clear();
|
||||
|
||||
@@ -296,7 +296,7 @@ public class NetServer implements ApplicationListener{
|
||||
//auto-skip done requests
|
||||
if(req.breaking && world.tile(req.x, req.y).block() == Blocks.air){
|
||||
continue;
|
||||
}else if(!req.breaking && world.tile(req.x, req.y).block() == req.recipe.result && (!req.recipe.result.rotate || world.tile(req.x, req.y).getRotation() == req.rotation)){
|
||||
}else if(!req.breaking && world.tile(req.x, req.y).block() == req.block && (!req.block.rotate || world.tile(req.x, req.y).getRotation() == req.rotation)){
|
||||
continue;
|
||||
}
|
||||
player.getPlaceQueue().addLast(req);
|
||||
|
||||
@@ -47,7 +47,7 @@ public class UI implements ApplicationListener{
|
||||
public LoadingFragment loadfrag;
|
||||
|
||||
public AboutDialog about;
|
||||
public RestartDialog restart;
|
||||
public GameOverDialog restart;
|
||||
public CustomGameDialog levels;
|
||||
public MapsDialog maps;
|
||||
public LoadDialog load;
|
||||
@@ -64,16 +64,17 @@ public class UI implements ApplicationListener{
|
||||
public TraceDialog traces;
|
||||
public ChangelogDialog changelog;
|
||||
public LocalPlayerDialog localplayers;
|
||||
public UnlocksDialog unlocks;
|
||||
public DatabaseDialog database;
|
||||
public ContentInfoDialog content;
|
||||
public DeployDialog deploy;
|
||||
public TechTreeDialog tech;
|
||||
|
||||
public Cursor drillCursor, unloadCursor;
|
||||
|
||||
public UI(){
|
||||
Skin skin = new Skin(Core.atlas);
|
||||
generateFonts(skin);
|
||||
skin.load(Core.files.internal("ui/uiskin.json"));
|
||||
skin.load(Core.files.internal("sprites/uiskin.json"));
|
||||
|
||||
for(BitmapFont font : skin.getAll(BitmapFont.class).values()){
|
||||
font.setUseIntegerPositions(true);
|
||||
@@ -158,13 +159,13 @@ public class UI implements ApplicationListener{
|
||||
|
||||
editor = new MapEditorDialog();
|
||||
controls = new ControlsDialog();
|
||||
restart = new RestartDialog();
|
||||
restart = new GameOverDialog();
|
||||
join = new JoinDialog();
|
||||
discord = new DiscordDialog();
|
||||
load = new LoadDialog();
|
||||
levels = new CustomGameDialog();
|
||||
language = new LanguageDialog();
|
||||
unlocks = new UnlocksDialog();
|
||||
database = new DatabaseDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
host = new HostDialog();
|
||||
paused = new PausedDialog();
|
||||
@@ -177,6 +178,7 @@ public class UI implements ApplicationListener{
|
||||
localplayers = new LocalPlayerDialog();
|
||||
content = new ContentInfoDialog();
|
||||
deploy = new DeployDialog();
|
||||
tech = new TechTreeDialog();
|
||||
|
||||
Group group = Core.scene.root;
|
||||
|
||||
@@ -236,7 +238,7 @@ public class UI implements ApplicationListener{
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
table.top().add(info).padTop(8);
|
||||
table.top().add(info).padTop(40);
|
||||
Core.scene.add(table);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,15 +5,21 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.collection.ObjectSet.ObjectSetIterator;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.ai.BlockIndexer;
|
||||
import io.anuke.mindustry.ai.Pathfinder;
|
||||
import io.anuke.mindustry.ai.WaveSpawner;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
@@ -22,6 +28,8 @@ import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.maps.Maps;
|
||||
import io.anuke.mindustry.maps.generators.Generator;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -178,6 +186,8 @@ public class World implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
addDarkness(tiles);
|
||||
|
||||
EntityQuery.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize);
|
||||
|
||||
generating = false;
|
||||
@@ -188,6 +198,32 @@ public class World implements ApplicationListener{
|
||||
return generating;
|
||||
}
|
||||
|
||||
public void launchZone(){
|
||||
Effects.effect(Fx.launchFull, 0, 0);
|
||||
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
Effects.effect(Fx.launch, tile);
|
||||
}
|
||||
|
||||
Time.runTask(30f, () -> {
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
for(Item item : content.items()){
|
||||
data.addItem(item, tile.entity.items.get(item));
|
||||
}
|
||||
world.removeBlock(tile);
|
||||
}
|
||||
state.launched = true;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isZone(){
|
||||
return getZone() != null;
|
||||
}
|
||||
|
||||
public Zone getZone(){
|
||||
return content.getByID(ContentType.zone, state.rules.zone);
|
||||
}
|
||||
|
||||
public void playZone(Zone zone){
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
@@ -198,6 +234,8 @@ public class World implements ApplicationListener{
|
||||
core.entity.items.add(stack.item, stack.amount);
|
||||
}
|
||||
}
|
||||
state.rules.zone = zone.id;
|
||||
control.saves.zoneSave();
|
||||
logic.play();
|
||||
});
|
||||
}
|
||||
@@ -394,13 +432,60 @@ public class World implements ApplicationListener{
|
||||
for(int x = 0; x < data.width(); x++){
|
||||
data.read(marker);
|
||||
|
||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.blockpart.id ? 0 : marker.wall, marker.rotation, marker.team);
|
||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team);
|
||||
}
|
||||
}
|
||||
|
||||
prepareTiles(tiles);
|
||||
}
|
||||
|
||||
public void addDarkness(Tile[][] tiles){
|
||||
|
||||
byte[][] dark = new byte[tiles.length][tiles[0].length];
|
||||
byte[][] writeBuffer = new byte[tiles.length][tiles[0].length];
|
||||
|
||||
byte darkIterations = 4;
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
Tile tile = tiles[x][y];
|
||||
if(tile.block().solid && !tile.block().update){
|
||||
dark[x][y] = darkIterations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < darkIterations; i++){
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
boolean min = false;
|
||||
for(Point2 point : Geometry.d4){
|
||||
int newX = x + point.x, newY = y + point.y;
|
||||
if(Structs.inBounds(newX, newY, tiles) && dark[newX][newY] < dark[x][y]){
|
||||
min = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
writeBuffer[x][y] = (byte)Math.max(0, dark[x][y] - Mathf.num(min));
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
dark[x][y] = writeBuffer[x][y];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
Tile tile = tiles[x][y];
|
||||
if(tile.block().solid && !tile.block().update){
|
||||
tiles[x][y].setRotation(dark[x][y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**'Prepares' a tile array by:<br>
|
||||
* - setting up multiblocks<br>
|
||||
* - updating occlusion<br>
|
||||
|
||||
@@ -1,70 +1,28 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.collection.LongArray;
|
||||
import io.anuke.arc.util.Pack;
|
||||
|
||||
public class DrawOperation{
|
||||
/**
|
||||
* Data to apply operation to.
|
||||
*/
|
||||
private MapTileData data;
|
||||
/**
|
||||
* List of per-tile operations that occurred.
|
||||
*/
|
||||
private Array<TileOperation> operations = new Array<>();
|
||||
/**
|
||||
* Checks for duplicate operations, useful for brushes.
|
||||
*/
|
||||
private IntSet checks = new IntSet();
|
||||
|
||||
public DrawOperation(MapTileData data){
|
||||
this.data = data;
|
||||
}
|
||||
private LongArray array = new LongArray();
|
||||
|
||||
public boolean isEmpty(){
|
||||
return operations.size == 0;
|
||||
return array.isEmpty();
|
||||
}
|
||||
|
||||
public boolean checkDuplicate(short x, short y){
|
||||
int i = Pack.shortInt(x, y);
|
||||
if(checks.contains(i)) return true;
|
||||
|
||||
checks.add(i);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addOperation(TileOperation op){
|
||||
operations.add(op);
|
||||
public void addOperation(int xy, byte type, byte from, byte to){
|
||||
array.add(Pack.longInt(xy, Pack.intBytes(type, from, to, (byte)0)));
|
||||
}
|
||||
|
||||
public void undo(MapEditor editor){
|
||||
for(int i = operations.size - 1; i >= 0; i--){
|
||||
TileOperation op = operations.get(i);
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.from);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
for(int i = 0; i < array.size; i++){
|
||||
long l = array.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor){
|
||||
for(TileOperation op : operations){
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.to);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TileOperation{
|
||||
public short x, y;
|
||||
public TileDataMarker from;
|
||||
public TileDataMarker to;
|
||||
|
||||
public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
for(int i = 0; i < array.size; i++){
|
||||
long l = array.get(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.ui;
|
||||
public enum EditorTool{
|
||||
pick{
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
if(!Structs.inBounds(x, y, editor.getMap().width(), editor.getMap().height())) return;
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
|
||||
|
||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
@@ -54,7 +54,7 @@ public enum EditorTool{
|
||||
editor.draw(x, y, Blocks.air);
|
||||
}
|
||||
},
|
||||
elevation{
|
||||
spray{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
@@ -62,7 +62,7 @@ public enum EditorTool{
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.elevate(x, y);
|
||||
editor.draw(x, y, editor.getDrawBlock(), 0.012);
|
||||
}
|
||||
},
|
||||
line{
|
||||
@@ -82,7 +82,7 @@ public enum EditorTool{
|
||||
MapTileData data;
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
if(!Structs.inBounds(x, y, editor.getMap().width(), editor.getMap().height())) return;
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
|
||||
|
||||
if(editor.getDrawBlock().isMultiblock()){
|
||||
//don't fill multiblocks, thanks
|
||||
@@ -96,7 +96,6 @@ public enum EditorTool{
|
||||
|
||||
byte bf = data.read(x, y, DataPosition.floor);
|
||||
byte bw = data.read(x, y, DataPosition.wall);
|
||||
be = data.read(x, y, DataPosition.elevation);
|
||||
boolean synth = editor.getDrawBlock().synthetic();
|
||||
byte brt = Pack.byteByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal());
|
||||
|
||||
@@ -107,8 +106,8 @@ public enum EditorTool{
|
||||
return;
|
||||
}
|
||||
|
||||
width = editor.getMap().width();
|
||||
int height = editor.getMap().height();
|
||||
width = world.width();
|
||||
int height = world.height();
|
||||
|
||||
int x1;
|
||||
boolean spanAbove, spanBelow;
|
||||
|
||||
@@ -9,54 +9,42 @@ import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.DrawOperation.TileOperation;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapEditor{
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15};
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
||||
|
||||
private MapTileData map;
|
||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
||||
private MapRenderer renderer = new MapRenderer(this);
|
||||
|
||||
private int brushSize = 1;
|
||||
private byte elevation;
|
||||
private int rotation;
|
||||
private Block drawBlock = Blocks.stone;
|
||||
private Team drawTeam = Team.blue;
|
||||
|
||||
public MapTileData getMap(){
|
||||
return map;
|
||||
}
|
||||
|
||||
public ObjectMap<String, String> getTags(){
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void beginEdit(MapTileData map, ObjectMap<String, String> tags, boolean clear){
|
||||
this.map = map;
|
||||
public void beginEdit(Tile[][] map, ObjectMap<String, String> tags, boolean clear){
|
||||
|
||||
this.brushSize = 1;
|
||||
this.tags = tags;
|
||||
|
||||
if(clear){
|
||||
for(int x = 0; x < map.width(); x++){
|
||||
for(int y = 0; y < map.height(); y++){
|
||||
map.write(x, y, DataPosition.floor, Blocks.stone.id);
|
||||
for(int x = 0; x < map.length; x++){
|
||||
for(int y = 0; y < map[0].length; y++){
|
||||
map[x][y].setFloor((Floor)Blocks.stone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBlock = Blocks.stone;
|
||||
renderer.resize(map.width(), map.height());
|
||||
}
|
||||
|
||||
public byte getDrawElevation(){
|
||||
return elevation;
|
||||
}
|
||||
|
||||
public void setDrawElevation(int elevation){
|
||||
this.elevation = (byte) elevation;
|
||||
renderer.resize(map.length, map[0].length);
|
||||
}
|
||||
|
||||
public int getDrawRotation(){
|
||||
@@ -96,19 +84,19 @@ public class MapEditor{
|
||||
}
|
||||
|
||||
public void draw(int x, int y, Block drawBlock){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
draw(x, y, drawBlock, 1.0);
|
||||
}
|
||||
|
||||
public void draw(int x, int y, Block drawBlock, double chance){
|
||||
byte writeID = drawBlock.id;
|
||||
byte partID = Blocks.blockpart.id;
|
||||
byte partID = Blocks.part.id;
|
||||
byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
||||
|
||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||
|
||||
if(drawBlock.isMultiblock()){
|
||||
x = Mathf.clamp(x, (drawBlock.size-1)/2, map.width() - drawBlock.size/2 - 1);
|
||||
y = Mathf.clamp(y, (drawBlock.size-1)/2, map.height() - drawBlock.size/2 - 1);
|
||||
x = Mathf.clamp(x, (drawBlock.size-1)/2, world.width() - drawBlock.size/2 - 1);
|
||||
y = Mathf.clamp(y, (drawBlock.size-1)/2, world.height() - drawBlock.size/2 - 1);
|
||||
|
||||
int offsetx = -(drawBlock.size - 1) / 2;
|
||||
int offsety = -(drawBlock.size - 1) / 2;
|
||||
@@ -119,7 +107,7 @@ public class MapEditor{
|
||||
int worldx = dx + offsetx + x;
|
||||
int worldy = dy + offsety + y;
|
||||
|
||||
if(Structs.inBounds(worldx, worldy, map.width(), map.height())){
|
||||
if(Structs.inBounds(worldx, worldy, world.width(), world.height())){
|
||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
||||
|
||||
if(i == 1){
|
||||
@@ -151,10 +139,9 @@ public class MapEditor{
|
||||
|
||||
onWrite(x, y, prev);
|
||||
}else{
|
||||
|
||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f){
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
||||
int wx = x + rx, wy = y + ry;
|
||||
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){
|
||||
@@ -175,7 +162,6 @@ public class MapEditor{
|
||||
|
||||
if(isfloor){
|
||||
map.write(wx, wy, DataPosition.floor, writeID);
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
}else{
|
||||
map.write(wx, wy, DataPosition.wall, writeID);
|
||||
map.write(wx, wy, DataPosition.link, (byte) 0);
|
||||
@@ -189,30 +175,6 @@ public class MapEditor{
|
||||
}
|
||||
}
|
||||
|
||||
public void elevate(int x, int y){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
|
||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f){
|
||||
int wx = x + rx, wy = y + ry;
|
||||
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){
|
||||
continue;
|
||||
}
|
||||
|
||||
TileDataMarker prev = getPrev(wx, wy, true);
|
||||
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
|
||||
onWrite(x + rx, y + ry, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLinked(int x, int y){
|
||||
Block block = content.block(map.read(x, y, DataPosition.wall));
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
@@ -11,21 +12,21 @@ import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.scene.utils.UIUtils;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -42,6 +43,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
private FloatingDialog menu;
|
||||
private boolean saved = false;
|
||||
private boolean shownWithMap = false;
|
||||
private Array<Block> blocksOut = new Array<>();
|
||||
|
||||
private ButtonGroup<ImageButton> blockgroup;
|
||||
|
||||
@@ -146,7 +148,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
||||
|
||||
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
||||
if(!(editor.getMap().width() == x && editor.getMap().height() == y)){
|
||||
if(!(world.width() == x && world.height() == y)){
|
||||
ui.loadAnd(() -> {
|
||||
editor.resize(x, y);
|
||||
view.clearStack();
|
||||
@@ -386,7 +388,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
tools.row();
|
||||
|
||||
addTool.accept(EditorTool.fill);
|
||||
addTool.accept(EditorTool.elevation);
|
||||
addTool.accept(EditorTool.spray);
|
||||
|
||||
ImageButton rotate = tools.addImageButton("icon-arrow-16", "clear", 16 * 2f, () -> editor.setDrawRotation((editor.getDrawRotation() + 1) % 4)).get();
|
||||
rotate.getImage().update(() -> {
|
||||
@@ -497,29 +499,21 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(Block block : Vars.content.blocks()){
|
||||
TextureRegion[] regions = block.getCompactIcon();
|
||||
if((block.synthetic() && (Recipe.getByResult(block) == null || !data.isUnlocked(Recipe.getByResult(block))))
|
||||
&& block != Blocks.core){
|
||||
continue;
|
||||
}
|
||||
blocksOut.clear();
|
||||
blocksOut.addAll(Vars.content.blocks());
|
||||
blocksOut.sort((b1, b2) -> b1.synthetic() && !b2.synthetic() ? 1 : b2.synthetic() && !b1.synthetic() ? -1 :
|
||||
b1 instanceof OreBlock && !(b2 instanceof OreBlock) ? 1 : !(b1 instanceof OreBlock) && b2 instanceof OreBlock ? -1 :
|
||||
Integer.compare(b1.id, b2.id));
|
||||
|
||||
if(Recipe.getByResult(block) != null && !Recipe.getByResult(block).visibility.shown()){
|
||||
continue;
|
||||
}
|
||||
for(Block block : blocksOut){
|
||||
TextureRegion region = block.icon(Icon.medium);
|
||||
|
||||
if(regions.length == 0 || regions[0] == Core.atlas.find("jjfgj")) continue;
|
||||
|
||||
Stack stack = new Stack();
|
||||
|
||||
for(TextureRegion region : regions){
|
||||
stack.add(new Image(region));
|
||||
}
|
||||
if(region == Core.atlas.find("jjfgj")) continue;
|
||||
|
||||
ImageButton button = new ImageButton("white", "clear-toggle");
|
||||
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
||||
button.clicked(() -> editor.setDrawBlock(block));
|
||||
button.resizeImage(8 * 4f);
|
||||
button.replaceImage(stack);
|
||||
button.update(() -> button.setChecked(editor.getDrawBlock() == block));
|
||||
group.add(button);
|
||||
content.add(button).size(50f);
|
||||
|
||||
@@ -8,9 +8,11 @@ import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.util.Disposable;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
@@ -22,7 +24,6 @@ public class MapRenderer implements Disposable{
|
||||
private IntSet delayedUpdates = new IntSet();
|
||||
private MapEditor editor;
|
||||
private int width, height;
|
||||
private Color tmpColor = Color.WHITE.cpy();
|
||||
|
||||
public MapRenderer(MapEditor editor){
|
||||
this.editor = editor;
|
||||
@@ -109,33 +110,38 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
TextureRegion region;
|
||||
|
||||
if(bw != 0){
|
||||
region = wall.getEditorIcon();
|
||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||
|
||||
if(bw != 0 && (wall.synthetic() || wall == Blocks.part)){
|
||||
region = wall.icon(Icon.full) == Core.atlas.find("____") ? Core.atlas.find("clear") : wall.icon(Icon.full);
|
||||
|
||||
if(wall.rotate){
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region,
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, rotation * 90 - 90);
|
||||
}else{
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region,
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
|
||||
wy * tilesize + wall.offset() + (tilesize - region.getHeight() * Draw.scl)/2f,
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
}
|
||||
}else{
|
||||
region = floor.getEditorIcon();
|
||||
region = floor.icon(Icon.full);
|
||||
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
}
|
||||
|
||||
if(wall.update || wall.destructible){
|
||||
mesh.setColor(team.color);
|
||||
region = Core.atlas.find("block-border");
|
||||
}else if(!wall.synthetic() && bw != 0){
|
||||
region = wall.icon(Icon.full) == Core.atlas.find("____") ? Core.atlas.find("clear") : wall.icon(Icon.full);
|
||||
}else{
|
||||
region = Core.atlas.find("clear");
|
||||
}
|
||||
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize, region,
|
||||
mesh.draw(idxDecal, region,
|
||||
wx * tilesize - (wall.size/3) * tilesize, wy * tilesize - (wall.size/3) * tilesize,
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
mesh.setColor(Color.WHITE);
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.GridBits;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
@@ -18,19 +19,19 @@ import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.editor.DrawOperation.TileOperation;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.ui.GridImage;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MapView extends Element implements GestureListener{
|
||||
private MapEditor editor;
|
||||
private EditorTool tool = EditorTool.pencil;
|
||||
private OperationStack stack = new OperationStack();
|
||||
private DrawOperation op;
|
||||
private GridBits used;
|
||||
private Bresenham2 br = new Bresenham2();
|
||||
private boolean updated = false;
|
||||
private float offsetx, offsety;
|
||||
@@ -86,7 +87,12 @@ public class MapView extends Element implements GestureListener{
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
|
||||
op = new DrawOperation(editor.getMap());
|
||||
op = new DrawOperation();
|
||||
if(used == null || used.width() != world.width() || used.height() != world.height()){
|
||||
used = new GridBits(world.width(), world.height());
|
||||
}else{
|
||||
used.clear();
|
||||
}
|
||||
|
||||
updated = false;
|
||||
|
||||
@@ -146,7 +152,7 @@ public class MapView extends Element implements GestureListener{
|
||||
|
||||
Point2 p = project(x, y);
|
||||
|
||||
if(drawing && tool.draggable){
|
||||
if(drawing && tool.draggable && !(p.x == lastx && p.y == lasty)){
|
||||
ui.editor.resetSaved();
|
||||
Array<Point2> points = br.line(lastx, lasty, p.x, p.y);
|
||||
for(Point2 point : points){
|
||||
@@ -196,12 +202,13 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
}
|
||||
|
||||
public void addTileOp(TileOperation t){
|
||||
op.addOperation(t);
|
||||
public void addTileOp(int xy, byte type, byte from, byte to){
|
||||
used.set(Pos.x(xy), Pos.y(xy));
|
||||
op.addOperation(xy, type, from, to);
|
||||
}
|
||||
|
||||
public boolean checkForDuplicates(short x, short y){
|
||||
return op.checkDuplicate(x, y);
|
||||
return used.get(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,12 +234,12 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
|
||||
private Point2 project(float x, float y){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float ratio = 1f / ((float) world.width() / world.height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.getMap().width();
|
||||
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.getMap().height();
|
||||
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * world.width();
|
||||
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * world.height();
|
||||
|
||||
if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){
|
||||
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
|
||||
@@ -242,26 +249,26 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
|
||||
private Vector2 unproject(int x, int y){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float ratio = 1f / ((float) world.width() / world.height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float px = ((float) x / editor.getMap().width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
||||
float py = ((float) (y) / editor.getMap().height()) * sclheight
|
||||
float px = ((float) x / world.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
||||
float py = ((float) (y) / world.height()) * sclheight
|
||||
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
||||
return vec.set(px, py);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float ratio = 1f / ((float) world.width() / world.height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float centerx = x + width / 2 + offsetx * zoom;
|
||||
float centery = y + height / 2 + offsety * zoom;
|
||||
|
||||
image.setImageSize(editor.getMap().width(), editor.getMap().height());
|
||||
image.setImageSize(world.width(), world.height());
|
||||
|
||||
if(!ScissorStack.pushScissors(rect.set(x, y, width, height))){
|
||||
return;
|
||||
@@ -292,7 +299,7 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
}
|
||||
|
||||
float scaling = zoom * Math.min(width, height) / editor.getMap().width();
|
||||
float scaling = zoom * Math.min(width, height) / world.width();
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(1f * zoom));
|
||||
|
||||
@@ -26,12 +26,14 @@ import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.io.TypeIO;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock.CoreEntity;
|
||||
@@ -109,6 +111,31 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
rectangle.setSize(mech.hitsize * 2f / 3f).setCenter(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRespawn(Tile tile){
|
||||
boostHeat = 1f;
|
||||
achievedFlight = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(float x, float y){
|
||||
if(!mech.flying){
|
||||
EntityQuery.collisions().move(this, x, y);
|
||||
}else{
|
||||
moveBy(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collidesGrid(int x, int y){
|
||||
Tile tile = world.tile(x, y);
|
||||
if(!isFlying()) return true;
|
||||
if(!mech.flying && tile != null && !tile.block().synthetic() && tile.block().solid){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drag(){
|
||||
return mech.drag;
|
||||
@@ -304,7 +331,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
Draw.color();
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
Draw.alpha(Draw.getShader() != Shaders.mix ? 1f : hitTime / hitDuration);
|
||||
|
||||
if(!mech.flying){
|
||||
if(floor.isLiquid){
|
||||
@@ -422,7 +449,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
Lines.stroke(2f, Palette.removeBack);
|
||||
|
||||
float rad = Mathf.absin(Time.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
request.y * tilesize + block.offset() - 1,
|
||||
@@ -435,21 +461,28 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
request.y * tilesize + block.offset(),
|
||||
rad);
|
||||
}else{
|
||||
//draw place request
|
||||
Lines.stroke(2f, Palette.accentBack);
|
||||
float rad = Mathf.absin(Time.time(), 7f, 1f) - 1.5f + request.block.size * tilesize / 2f;
|
||||
|
||||
float rad = Mathf.absin(Time.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f;
|
||||
//draw place request
|
||||
Lines.stroke(1f, Palette.accentBack);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset() - 1,
|
||||
request.x * tilesize + request.block.offset(),
|
||||
request.y * tilesize + request.block.offset() - 1,
|
||||
rad);
|
||||
|
||||
Draw.color();
|
||||
|
||||
Draw.rect(request.block.icon(Icon.full),
|
||||
request.x * tilesize + request.block.offset(),
|
||||
request.y * tilesize + request.block.offset(), rad*2, rad*2, request.rotation * 90);
|
||||
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset(),
|
||||
request.x * tilesize + request.block.offset(),
|
||||
request.y * tilesize + request.block.offset(),
|
||||
rad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
@@ -16,6 +17,7 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.game.EventType.BlockDestroyEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -244,6 +246,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
dead = true;
|
||||
Block block = tile.block();
|
||||
|
||||
Events.fire(new BlockDestroyEvent(tile));
|
||||
block.onDestroyed(tile);
|
||||
world.removeBlock(tile);
|
||||
block.afterDestroyed(tile, this);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.impl.DestructibleEntity;
|
||||
import io.anuke.arc.entities.trait.DamageTrait;
|
||||
@@ -17,6 +18,7 @@ import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.EventType.UnitDestroyEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Teams.TeamData;
|
||||
import io.anuke.mindustry.net.Interpolator;
|
||||
@@ -72,6 +74,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
return carrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collidesGrid(int x, int y){
|
||||
return !isFlying();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarrier(CarryTrait carrier){
|
||||
this.carrier = carrier;
|
||||
@@ -121,6 +128,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
inventory.clear();
|
||||
drownTime = 0f;
|
||||
status.clear();
|
||||
Events.fire(new UnitDestroyEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,6 +225,8 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
return tile == null ? (Floor) Blocks.air : tile.floor();
|
||||
}
|
||||
|
||||
public void onRespawn(Tile tile){}
|
||||
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return !isDead() && isAdded();
|
||||
@@ -239,8 +249,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier()-1f) * Time.delta());
|
||||
|
||||
if(isFlying()){
|
||||
x += velocity.x * Time.delta();
|
||||
y += velocity.y * Time.delta();
|
||||
move(velocity.x * Time.delta(), velocity.y * Time.delta());
|
||||
}else{
|
||||
boolean onLiquid = floor.isLiquid;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.groundEffectGroup;
|
||||
* Class for creating block rubble on the ground.
|
||||
*/
|
||||
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{
|
||||
private static final Color color = Color.valueOf("52504e");
|
||||
private static final Color color = Color.valueOf("3a3635");
|
||||
|
||||
@Override
|
||||
public float lifetime(){
|
||||
|
||||
@@ -105,13 +105,9 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float length = fslope() * 6f;
|
||||
float angle = current.set(x, y).sub(from).angle();
|
||||
Lines.stroke(fslope() * 2f, Palette.accent);
|
||||
|
||||
Lines.circle(x, y, fslope() * 2f);
|
||||
Lines.lineAngleCenter(x, y, angle, length);
|
||||
Lines.lineAngle(x, y, angle, fout() * 6f);
|
||||
|
||||
Draw.color(item.color);
|
||||
Fill.circle(x, y, fslope() * 1.5f);
|
||||
|
||||
@@ -31,12 +31,16 @@ public class ScorchDecal extends Decal{
|
||||
|
||||
@Override
|
||||
public void drawDecal(){
|
||||
|
||||
for(int i = 0; i < 5; i++){
|
||||
TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches - 1)];
|
||||
float rotation = Mathf.randomSeed(id + i, 0, 360);
|
||||
float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20) / 10f;
|
||||
Draw.rect(region, x + Angles.trnsx(rotation, space), y + Angles.trnsy(rotation, space) + region.getHeight()/2f, region.getWidth()/2f, 0, rotation - 90);
|
||||
Draw.rect(region,
|
||||
x + Angles.trnsx(rotation, space),
|
||||
y + Angles.trnsy(rotation, space) + region.getHeight()/2f*Draw.scl,
|
||||
region.getWidth() * Draw.scl,
|
||||
region.getHeight() * Draw.scl,
|
||||
region.getWidth()/2f*Draw.scl, 0, rotation - 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shapes;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Build;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -81,7 +81,7 @@ public interface BuilderTrait extends Entity{
|
||||
output.writeInt(Pos.get(request.x, request.y));
|
||||
output.writeFloat(request.progress);
|
||||
if(!request.breaking){
|
||||
output.writeByte(request.recipe.id);
|
||||
output.writeByte(request.block.id);
|
||||
output.writeByte(request.rotation);
|
||||
}
|
||||
}else{
|
||||
@@ -105,9 +105,9 @@ public interface BuilderTrait extends Entity{
|
||||
if(type == 1){ //remove
|
||||
request = new BuildRequest(Pos.x(position), Pos.y(position));
|
||||
}else{ //place
|
||||
byte recipe = input.readByte();
|
||||
byte block = input.readByte();
|
||||
byte rotation = input.readByte();
|
||||
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe));
|
||||
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
|
||||
}
|
||||
|
||||
request.progress = progress;
|
||||
@@ -129,7 +129,7 @@ public interface BuilderTrait extends Entity{
|
||||
* If a place request matching this signature is present, it is removed.
|
||||
* Otherwise, a new place request is added to the queue.
|
||||
*/
|
||||
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
||||
default void replaceBuilding(int x, int y, int rotation, Block block){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == x && request.y == y){
|
||||
clearBuilding();
|
||||
@@ -138,7 +138,7 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
}
|
||||
|
||||
addBuildRequest(new BuildRequest(x, y, rotation, recipe));
|
||||
addBuildRequest(new BuildRequest(x, y, rotation, block));
|
||||
}
|
||||
|
||||
/**Clears the placement queue.*/
|
||||
@@ -184,8 +184,8 @@ public interface BuilderTrait extends Entity{
|
||||
for(BuildRequest request : removal){
|
||||
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
|
||||
(!request.breaking &&
|
||||
(world.tile(request.x, request.y).getRotation() == request.rotation || !request.recipe.result.rotate)
|
||||
&& world.tile(request.x, request.y).block() == request.recipe.result))){
|
||||
(world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
|
||||
&& world.tile(request.x, request.y).block() == request.block))){
|
||||
getPlaceQueue().addLast(request);
|
||||
}
|
||||
}
|
||||
@@ -209,8 +209,8 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
if(!(tile.block() instanceof BuildBlock)){
|
||||
if(canCreateBlocks() && !current.breaking && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){
|
||||
Build.beginPlace(unit.getTeam(), current.x, current.y, current.recipe, current.rotation);
|
||||
if(canCreateBlocks() && !current.breaking && Build.validPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation)){
|
||||
Build.beginPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation);
|
||||
}else if(canCreateBlocks() && current.breaking && Build.validBreak(unit.getTeam(), current.x, current.y)){
|
||||
Build.beginBreak(unit.getTeam(), current.x, current.y);
|
||||
}else{
|
||||
@@ -264,10 +264,10 @@ public interface BuilderTrait extends Entity{
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
if(core == null || tile.block() != Blocks.air || unit.dst(tile.worldx(), tile.worldy()) > mineDistance
|
||||
|| tile.floor().drops == null || !unit.inventory.canAcceptItem(tile.floor().drops.item) || !canMine(tile.floor().drops.item)){
|
||||
|| tile.floor().itemDrop == null || !unit.inventory.canAcceptItem(tile.floor().itemDrop) || !canMine(tile.floor().itemDrop)){
|
||||
setMineTile(null);
|
||||
}else{
|
||||
Item item = tile.floor().drops.item;
|
||||
Item item = tile.floor().itemDrop;
|
||||
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.worldx(), tile.worldy()), 0.4f);
|
||||
|
||||
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
|
||||
@@ -370,18 +370,18 @@ public interface BuilderTrait extends Entity{
|
||||
/**Class for storing build requests. Can be either a place or remove request.*/
|
||||
class BuildRequest{
|
||||
public final int x, y, rotation;
|
||||
public final Recipe recipe;
|
||||
public final Block block;
|
||||
public final boolean breaking;
|
||||
|
||||
public float progress;
|
||||
public boolean initialized;
|
||||
|
||||
/**This creates a build request.*/
|
||||
public BuildRequest(int x, int y, int rotation, Recipe recipe){
|
||||
public BuildRequest(int x, int y, int rotation, Block block){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rotation = rotation;
|
||||
this.recipe = recipe;
|
||||
this.block = block;
|
||||
this.breaking = false;
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ public interface BuilderTrait extends Entity{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rotation = -1;
|
||||
this.recipe = Recipe.getByResult(world.tile(x, y).block());
|
||||
this.block = world.tile(x, y).block();
|
||||
this.breaking = true;
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ public interface BuilderTrait extends Entity{
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", rotation=" + rotation +
|
||||
", recipe=" + recipe +
|
||||
", recipe=" + block +
|
||||
", breaking=" + breaking +
|
||||
", progress=" + progress +
|
||||
", initialized=" + initialized +
|
||||
|
||||
@@ -88,9 +88,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
return type.drag;
|
||||
}
|
||||
|
||||
/**Called when a command is recieved from the command center.*/
|
||||
public abstract void onCommand(UnitCommand command);
|
||||
|
||||
/**Initialize the type and team of this unit. Only call once!*/
|
||||
public void init(UnitType type, Team team){
|
||||
if(this.type != null) throw new RuntimeException("This unit is already initialized!");
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.traits.CarriableTrait;
|
||||
import io.anuke.mindustry.entities.traits.CarryTrait;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
@@ -120,11 +121,8 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.patrol ? patrol :
|
||||
null);
|
||||
public void move(float x, float y){
|
||||
moveBy(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +152,7 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
Draw.alpha(Draw.getShader() != Shaders.mix ? 1f : hitTime / hitDuration);
|
||||
|
||||
Draw.rect(type.name, x, y, rotation - 90);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -78,14 +79,6 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.patrol ? patrol :
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(UnitType type, Team team){
|
||||
super.init(type, team);
|
||||
@@ -140,7 +133,7 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
Draw.alpha(Draw.getShader() != Shaders.mix ? 1f : hitTime / hitDuration);
|
||||
|
||||
float ft = Mathf.sin(walkTime * type.speed*5f, 6f, 2f);
|
||||
|
||||
@@ -272,7 +265,9 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
float angle = angleTo(targetTile);
|
||||
|
||||
velocity.add(vec.trns(angleTo(targetTile), type.speed*Time.delta()));
|
||||
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
|
||||
}
|
||||
}
|
||||
|
||||
protected void moveAwayFromCore(){
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
|
||||
public enum UnitCommand{
|
||||
attack, retreat, patrol;
|
||||
|
||||
private final String localized;
|
||||
|
||||
UnitCommand(){
|
||||
localized = Core.bundle.get("command." + name());
|
||||
}
|
||||
|
||||
public String localized(){
|
||||
return localized;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnit;
|
||||
import io.anuke.mindustry.entities.units.UnitCommand;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
@@ -66,13 +65,13 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
if(isBreaking){
|
||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
|
||||
}else{
|
||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.recipe));
|
||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.block));
|
||||
}
|
||||
}
|
||||
|
||||
//if it's missing requirements, try and mine them
|
||||
if(entity.recipe != null){
|
||||
for(ItemStack stack : entity.recipe.requirements){
|
||||
if(entity.block != null){
|
||||
for(ItemStack stack : entity.block.buildRequirements){
|
||||
if(!core.items.has(stack.item, stack.amount) && type.toMine.contains(stack.item)){
|
||||
targetItem = stack.item;
|
||||
getPlaceQueue().clear();
|
||||
@@ -262,11 +261,6 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
//no
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMine(Item item){
|
||||
return type.toMine.contains(item);
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.game;
|
||||
|
||||
import io.anuke.arc.Events.Event;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
@@ -60,9 +61,9 @@ public class EventType{
|
||||
}
|
||||
|
||||
public static class UnlockEvent implements Event{
|
||||
public final Content content;
|
||||
public final UnlockableContent content;
|
||||
|
||||
public UnlockEvent(Content content){
|
||||
public UnlockEvent(UnlockableContent content){
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +82,18 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockBuildEndEvent implements Event{
|
||||
public final Tile tile;
|
||||
public final Team team;
|
||||
public final boolean breaking;
|
||||
|
||||
public BlockBuildEndEvent(Tile tile, Team team, boolean breaking){
|
||||
this.tile = tile;
|
||||
this.team = team;
|
||||
this.breaking = breaking;
|
||||
}
|
||||
}
|
||||
|
||||
/**Called when a player or drone begins building something.
|
||||
* This does not necessarily happen when a new BuildBlock is created.*/
|
||||
public static class BuildSelectEvent implements Event{
|
||||
@@ -97,6 +110,22 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockDestroyEvent implements Event{
|
||||
public final Tile tile;
|
||||
|
||||
public BlockDestroyEvent(Tile tile){
|
||||
this.tile = tile;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnitDestroyEvent implements Event{
|
||||
public final Unit unit;
|
||||
|
||||
public UnitDestroyEvent(Unit unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResizeEvent implements Event{
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@ import io.anuke.arc.collection.ObjectIntMap;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.Items;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.UnlockEvent;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Stores player unlocks. Clientside only.*/
|
||||
public class GlobalData{
|
||||
@@ -19,11 +24,33 @@ public class GlobalData{
|
||||
|
||||
public GlobalData(){
|
||||
Core.settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]);
|
||||
Core.settings.setSerializer(Item.class, (stream, t) -> stream.writeUTF(t.name), stream -> content.getByName(ContentType.item, stream.readUTF()));
|
||||
}
|
||||
|
||||
public void updateWaveScore(Zone zone, int wave){
|
||||
int value = Core.settings.getInt(zone.name + "-wave", 0);
|
||||
if(value < wave){
|
||||
Core.settings.put(zone.name + "-wave", wave);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getWaveScore(Zone zone){
|
||||
return Core.settings.getInt(zone.name + "-wave", 0);
|
||||
}
|
||||
|
||||
public boolean isCompleted(Zone zone){
|
||||
return getWaveScore(zone) >= zone.conditionWave;
|
||||
}
|
||||
|
||||
public int getItem(Item item){
|
||||
return items.get(item, 0);
|
||||
}
|
||||
|
||||
public void addItem(Item item, int amount){
|
||||
modified = true;
|
||||
items.getAndIncrement(item, 0, amount);
|
||||
state.stats.itemsDelivered.getAndIncrement(item, 0, amount);
|
||||
}
|
||||
|
||||
public boolean hasItems(ItemStack[] stacks){
|
||||
@@ -42,37 +69,34 @@ public class GlobalData{
|
||||
modified = true;
|
||||
}
|
||||
|
||||
public boolean has(Item item, int amount){
|
||||
return items.get(item, 0) >= amount;
|
||||
}
|
||||
|
||||
public ObjectIntMap<Item> items(){
|
||||
return items;
|
||||
}
|
||||
|
||||
/** Returns whether or not this piece of content is unlocked yet.*/
|
||||
public boolean isUnlocked(UnlockableContent content){
|
||||
return true;
|
||||
//return content.alwaysUnlocked() || unlocked.getOr(content.getContentType(), ObjectSet::new).contains(content.getContentName());
|
||||
return (!state.is(State.menu) && !world.isZone()) || content.alwaysUnlocked() || unlocked.getOr(content.getContentType(), ObjectSet::new).contains(content.getContentName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this piece of content 'unlocked', if possible.
|
||||
* If this piece of content is already unlocked or cannot be unlocked due to dependencies, nothing changes.
|
||||
* Results are not saved until you call {@link #save()}.
|
||||
*
|
||||
* @return whether or not this content was newly unlocked.
|
||||
*/
|
||||
public boolean unlockContent(UnlockableContent content){
|
||||
if(!content.canBeUnlocked() || content.alwaysUnlocked()) return false;
|
||||
|
||||
boolean ret = unlocked.getOr(content.getContentType(), ObjectSet::new).add(content.getContentName());
|
||||
public void unlockContent(UnlockableContent content){
|
||||
if(content.alwaysUnlocked()) return;
|
||||
|
||||
//fire unlock event so other classes can use it
|
||||
if(ret){
|
||||
if(unlocked.getOr(content.getContentType(), ObjectSet::new).add(content.getContentName())){
|
||||
modified = true;
|
||||
content.onUnlock();
|
||||
Events.fire(new UnlockEvent(content));
|
||||
save();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Clears all unlocked content. Automatically saves.*/
|
||||
@@ -93,6 +117,11 @@ public class GlobalData{
|
||||
for(Item item : Vars.content.items()){
|
||||
items.put(item, Core.settings.getInt("item-" + item.name, 0));
|
||||
}
|
||||
|
||||
//set up default values
|
||||
if(!Core.settings.has("item-" + Items.copper)){
|
||||
addItem(Items.copper, 500);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(){
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.game;
|
||||
|
||||
import io.anuke.annotations.Annotations.Serialize;
|
||||
import io.anuke.arc.collection.Array;
|
||||
|
||||
/**Defines current rules on how the game should function.
|
||||
* Does not store game state, just configuration.*/
|
||||
@@ -24,4 +25,8 @@ public class Rules{
|
||||
public float respawnTime = 60 * 4;
|
||||
/**Time between waves in ticks.*/
|
||||
public float waveSpacing = 60 * 60;
|
||||
/**Zone ID, -1 for invalid zone.*/
|
||||
public byte zone = -1;
|
||||
/**Spawn layout. Since only zones modify this, it should be assigned on save load.*/
|
||||
public transient Array<SpawnGroup> spawns = new Array<>();
|
||||
}
|
||||
|
||||
@@ -11,8 +11,11 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||
import io.anuke.mindustry.io.SaveMeta;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -105,6 +108,16 @@ public class Saves{
|
||||
return saving;
|
||||
}
|
||||
|
||||
public void zoneSave(){
|
||||
SaveSlot slot = new SaveSlot(-1);
|
||||
slot.setName("zone");
|
||||
saves.remove(s -> s.index == -1);
|
||||
saves.add(slot);
|
||||
saveMap.put(slot.index, slot);
|
||||
slot.save();
|
||||
saveSlots();
|
||||
}
|
||||
|
||||
public SaveSlot addSave(String name){
|
||||
SaveSlot slot = new SaveSlot(nextSlot);
|
||||
nextSlot++;
|
||||
@@ -129,6 +142,11 @@ public class Saves{
|
||||
return slot;
|
||||
}
|
||||
|
||||
public SaveSlot getZoneSlot(){
|
||||
SaveSlot slot = getByID(-1);
|
||||
return slot == null || slot.getZone() == null ? null : slot;
|
||||
}
|
||||
|
||||
public SaveSlot getByID(int id){
|
||||
return saveMap.get(id);
|
||||
}
|
||||
@@ -153,11 +171,15 @@ public class Saves{
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void load(){
|
||||
SaveIO.loadFromSlot(index);
|
||||
meta = SaveIO.getData(index);
|
||||
current = this;
|
||||
totalPlaytime = meta.timePlayed;
|
||||
public void load() throws SaveException{
|
||||
try{
|
||||
SaveIO.loadFromSlot(index);
|
||||
meta = SaveIO.getData(index);
|
||||
current = this;
|
||||
totalPlaytime = meta.timePlayed;
|
||||
}catch(Exception e){
|
||||
throw new SaveException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(){
|
||||
@@ -203,6 +225,10 @@ public class Saves{
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
public Zone getZone(){
|
||||
return content.getByID(ContentType.zone, meta.rules.zone);
|
||||
}
|
||||
|
||||
public int getBuild(){
|
||||
return meta.build;
|
||||
}
|
||||
@@ -211,10 +237,6 @@ public class Saves{
|
||||
return meta.wave;
|
||||
}
|
||||
|
||||
public Difficulty getDifficulty(){
|
||||
return meta.difficulty;
|
||||
}
|
||||
|
||||
public boolean isAutosave(){
|
||||
return Core.settings.getBool("save-" + index + "-autosave", true);
|
||||
}
|
||||
|
||||
@@ -13,53 +13,25 @@ import io.anuke.mindustry.type.Weapon;
|
||||
* Each spawn group can have multiple sub-groups spawned in different areas of the map.
|
||||
*/
|
||||
public class SpawnGroup{
|
||||
/**
|
||||
* The unit type spawned
|
||||
*/
|
||||
/**The unit type spawned*/
|
||||
public final UnitType type;
|
||||
/**
|
||||
* When this spawn should end
|
||||
*/
|
||||
/**When this spawn should end*/
|
||||
protected int end = Integer.MAX_VALUE;
|
||||
/**
|
||||
* When this spawn should start
|
||||
*/
|
||||
/**When this spawn should start*/
|
||||
protected int begin;
|
||||
/**
|
||||
* The spacing, in waves, of spawns. For example, 2 = spawns every other wave
|
||||
*/
|
||||
/**The spacing, in waves, of spawns. For example, 2 = spawns every other wave*/
|
||||
protected int spacing = 1;
|
||||
/**
|
||||
* Maximum amount of units that spawn
|
||||
*/
|
||||
/**Maximum amount of units that spawn*/
|
||||
protected int max = 60;
|
||||
/**
|
||||
* How many waves need to pass before the amount of units spawned increases by 1
|
||||
*/
|
||||
/**How many waves need to pass before the amount of units spawned increases by 1*/
|
||||
protected float unitScaling = 9999f;
|
||||
/**
|
||||
* How many waves need to pass before the amount of instances of this group increases by 1
|
||||
*/
|
||||
protected float groupScaling = 9999f;
|
||||
/**
|
||||
* Amount of enemies spawned initially, with no scaling
|
||||
*/
|
||||
/**Amount of enemies spawned initially, with no scaling*/
|
||||
protected int unitAmount = 1;
|
||||
/**
|
||||
* Amount of enemies spawned initially, with no scaling
|
||||
*/
|
||||
protected int groupAmount = 1;
|
||||
/**
|
||||
* Weapon used by the spawned unit. Null to disable. Only applicable to ground units.
|
||||
*/
|
||||
/**Weapon used by the spawned unit. Null to disable. Only applicable to ground units.*/
|
||||
protected Weapon weapon;
|
||||
/**
|
||||
* Status effect applied to the spawned unit. Null to disable.
|
||||
*/
|
||||
/**Status effect applied to the spawned unit. Null to disable.*/
|
||||
protected StatusEffect effect;
|
||||
/**
|
||||
* Items this unit spawns with. Null to disable.
|
||||
*/
|
||||
/**Items this unit spawns with. Null to disable.*/
|
||||
protected ItemStack items;
|
||||
|
||||
public SpawnGroup(UnitType type){
|
||||
@@ -75,18 +47,7 @@ public class SpawnGroup{
|
||||
}
|
||||
float scaling = this.unitScaling;
|
||||
|
||||
return Math.min(unitAmount - 1 + Math.max((int) ((wave / spacing) / scaling), 1), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of different unit groups at a specific wave.
|
||||
*/
|
||||
public int getGroupsSpawned(int wave){
|
||||
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.min(groupAmount - 1 + Math.max((int) ((wave / spacing) / groupScaling), 1), max);
|
||||
return Math.min(unitAmount - 1 + Math.max((int) (((wave - begin) / spacing) / scaling), 1), max);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,4 +71,20 @@ public class SpawnGroup{
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "SpawnGroup{" +
|
||||
"type=" + type +
|
||||
", end=" + end +
|
||||
", begin=" + begin +
|
||||
", spacing=" + spacing +
|
||||
", max=" + max +
|
||||
", unitScaling=" + unitScaling +
|
||||
", unitAmount=" + unitAmount +
|
||||
", weapon=" + weapon +
|
||||
", effect=" + effect +
|
||||
", items=" + items +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
23
core/src/io/anuke/mindustry/game/Stats.java
Normal file
23
core/src/io/anuke/mindustry/game/Stats.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package io.anuke.mindustry.game;
|
||||
|
||||
import io.anuke.annotations.Annotations.Serialize;
|
||||
import io.anuke.arc.collection.ObjectIntMap;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
|
||||
@Serialize
|
||||
public class Stats{
|
||||
/**Items delivered to global resoure counter. Zones only.*/
|
||||
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
/**Enemy (red team) units destroyed.*/
|
||||
public int enemyUnitsDestroyed;
|
||||
/**Total waves lasted.*/
|
||||
public int wavesLasted;
|
||||
/**Total (ms) time lasted in this save/zone.*/
|
||||
public long timeLasted;
|
||||
/**Friendly buildings fully built.*/
|
||||
public int buildingsBuilt;
|
||||
/**Friendly buildings fully deconstructed.*/
|
||||
public int buildingsDeconstructed;
|
||||
/**Friendly buildings destroyed.*/
|
||||
public int buildingsDestroyed;
|
||||
}
|
||||
@@ -3,8 +3,6 @@ package io.anuke.mindustry.game;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.data;
|
||||
|
||||
/**Base interface for an unlockable content type.*/
|
||||
public abstract class UnlockableContent extends MappableContent{
|
||||
/**Returns the localized name of this content.*/
|
||||
@@ -28,24 +26,4 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
public boolean alwaysUnlocked(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**Lists the content that must be unlocked in order for this specific content to become unlocked. May return null.*/
|
||||
public UnlockableContent[] getDependencies(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**Returns whether dependencies are satisfied for unlocking this content.*/
|
||||
public boolean canBeUnlocked(){
|
||||
UnlockableContent[] depend = getDependencies();
|
||||
if(depend == null){
|
||||
return true;
|
||||
}else{
|
||||
for(UnlockableContent cont : depend){
|
||||
if(!data.isUnlocked(cont)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ import io.anuke.mindustry.content.Weapons;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
public class Waves{
|
||||
private static Array<SpawnGroup> spawns;
|
||||
|
||||
public static Array<SpawnGroup> getSpawns(){
|
||||
return Array.with(
|
||||
public static Array<SpawnGroup> getDefaultSpawns(){
|
||||
if(spawns == null){
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
end = 8;
|
||||
unitScaling = 3;
|
||||
@@ -82,7 +84,6 @@ public class Waves{
|
||||
begin = 82;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
groupAmount = 2;
|
||||
unitScaling = 3;
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
@@ -108,7 +109,6 @@ public class Waves{
|
||||
begin = 35;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
groupAmount = 2;
|
||||
effect = StatusEffects.overdrive;
|
||||
items = new ItemStack(Items.blastCompound, 60);
|
||||
end = 60;
|
||||
@@ -118,7 +118,6 @@ public class Waves{
|
||||
begin = 42;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
groupAmount = 2;
|
||||
effect = StatusEffects.overdrive;
|
||||
items = new ItemStack(Items.pyratite, 100);
|
||||
end = 130;
|
||||
@@ -137,7 +136,6 @@ public class Waves{
|
||||
unitAmount = 4;
|
||||
unitScaling = 3;
|
||||
spacing = 5;
|
||||
groupAmount = 2;
|
||||
effect = StatusEffects.overdrive;
|
||||
max = 8;
|
||||
}},
|
||||
@@ -147,7 +145,6 @@ public class Waves{
|
||||
unitAmount = 4;
|
||||
unitScaling = 3;
|
||||
spacing = 5;
|
||||
groupAmount = 2;
|
||||
max = 8;
|
||||
}},
|
||||
|
||||
@@ -168,16 +165,17 @@ public class Waves{
|
||||
max = 8;
|
||||
end = 74;
|
||||
}}
|
||||
);
|
||||
);
|
||||
}
|
||||
return spawns;
|
||||
}
|
||||
|
||||
public static void testWaves(int from, int to){
|
||||
Array<SpawnGroup> spawns = getSpawns();
|
||||
public static void testWaves(Array<SpawnGroup> spawns, int from, int to){
|
||||
for(int i = from; i <= to; i++){
|
||||
System.out.print(i + ": ");
|
||||
int total = 0;
|
||||
for(SpawnGroup spawn : spawns){
|
||||
int a = spawn.getUnitsSpawned(i) * spawn.getGroupsSpawned(i);
|
||||
int a = spawn.getUnitsSpawned(i);
|
||||
total += a;
|
||||
|
||||
if(a > 0){
|
||||
|
||||
@@ -4,11 +4,14 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.Sort;
|
||||
import io.anuke.arc.entities.EntityDraw;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.glutils.FrameBuffer;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
@@ -57,7 +60,7 @@ public class BlockRenderer{
|
||||
public void drawShadows(){
|
||||
if(disableShadows) return;
|
||||
|
||||
if(shadows.getWidth() != Core.graphics.getWidth() || shadows.getHeight() != Core.graphics.getHeight()){
|
||||
if(!Core.graphics.isHidden() && (shadows.getWidth() != Core.graphics.getWidth() || shadows.getHeight() != Core.graphics.getHeight())){
|
||||
shadows.resize(Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
}
|
||||
|
||||
@@ -70,7 +73,16 @@ public class BlockRenderer{
|
||||
shadows.begin();
|
||||
Core.graphics.clear(Color.CLEAR);
|
||||
Draw.color(shadowColor);
|
||||
floor.beginDraw();
|
||||
floor.drawLayer(CacheLayer.walls);
|
||||
floor.endDraw();
|
||||
drawBlocks(Layer.shadow);
|
||||
|
||||
EntityDraw.drawWith(playerGroup, player -> !player.isDead(), Unit::draw);
|
||||
for(EntityGroup group : unitGroups){
|
||||
EntityDraw.drawWith(group, unit -> !unit.isDead(), Unit::draw);
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
Draw.flush();
|
||||
shadows.end();
|
||||
@@ -110,11 +122,11 @@ public class BlockRenderer{
|
||||
Tile tile = world.rawTile(x, y);
|
||||
Block block = tile.block();
|
||||
|
||||
if(!expanded && block != Blocks.air && world.isAccessible(x, y)){
|
||||
if(!expanded && block != Blocks.air && block.cacheLayer == CacheLayer.normal && world.isAccessible(x, y)){
|
||||
tile.block().drawShadow(tile);
|
||||
}
|
||||
|
||||
if(block != Blocks.air){
|
||||
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){
|
||||
if(!expanded){
|
||||
addRequest(tile, Layer.shadow);
|
||||
addRequest(tile, Layer.block);
|
||||
@@ -139,6 +151,10 @@ public class BlockRenderer{
|
||||
lastCamY = avgy;
|
||||
lastRangeX = rangex;
|
||||
lastRangeY = rangey;
|
||||
|
||||
floor.beginDraw();
|
||||
floor.drawLayer(CacheLayer.walls);
|
||||
floor.endDraw();
|
||||
}
|
||||
|
||||
public void drawBlocks(Layer stopAt){
|
||||
@@ -154,8 +170,13 @@ public class BlockRenderer{
|
||||
|
||||
if(req.layer == Layer.shadow){
|
||||
block.drawShadow(req.tile);
|
||||
}else if(req.layer == Layer.block){
|
||||
}else if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
if(block.synthetic() && req.tile.getTeam() != players[0].getTeam()){
|
||||
Draw.color(req.tile.getTeam().color);
|
||||
Draw.rect("block-border", req.tile.drawx() - block.size * tilesize/2f + 4, req.tile.drawy() - block.size * tilesize/2f + 4);
|
||||
Draw.color();
|
||||
}
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.graphics;
|
||||
|
||||
//TODO implement effects again
|
||||
public enum CacheLayer{
|
||||
water{
|
||||
},
|
||||
@@ -9,7 +10,9 @@ public enum CacheLayer{
|
||||
},
|
||||
space{
|
||||
},
|
||||
normal;
|
||||
normal,
|
||||
walls{ //TODO implement walls
|
||||
};
|
||||
|
||||
public void begin(){
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class FloorRenderer{
|
||||
private final static int chunksize = 64;
|
||||
@@ -156,7 +157,11 @@ public class FloorRenderer{
|
||||
Tile tile = world.tile(tilex, tiley);
|
||||
|
||||
if(tile != null){
|
||||
used.add(tile.floor().cacheLayer);
|
||||
if(tile.block().cacheLayer != CacheLayer.normal){
|
||||
used.add(tile.block().cacheLayer);
|
||||
}else{
|
||||
used.add(tile.floor().cacheLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +188,9 @@ public class FloorRenderer{
|
||||
floor = tile.floor();
|
||||
}
|
||||
|
||||
if(floor.cacheLayer == layer){
|
||||
if(tile.block().cacheLayer == layer && layer == CacheLayer.walls){
|
||||
tile.block().draw(tile);
|
||||
}else if(floor.cacheLayer == layer && tile.block().cacheLayer != CacheLayer.walls){
|
||||
floor.draw(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IndexedRenderer implements Disposable{
|
||||
program.setUniformMatrix4("u_projTrans", BatchShader.copyTransform(combined));
|
||||
program.setUniformi("u_texture", 0);
|
||||
|
||||
mesh.render(program, GL20.GL_TRIANGLES, 0, vertices.length / 5);
|
||||
mesh.render(program, GL20.GL_TRIANGLES, 0, vertices.length / vsize);
|
||||
|
||||
program.end();
|
||||
}
|
||||
@@ -187,14 +187,6 @@ public class IndexedRenderer implements Disposable{
|
||||
return transMatrix;
|
||||
}
|
||||
|
||||
public void setTransformMatrix(Matrix3 matrix){
|
||||
transMatrix = matrix;
|
||||
}
|
||||
|
||||
public Matrix3 getProjectionMatrix(){
|
||||
return projMatrix;
|
||||
}
|
||||
|
||||
public void setProjectionMatrix(Matrix3 matrix){
|
||||
projMatrix = matrix;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ public class MinimapRenderer implements Disposable{
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
ScissorStack.popScissors();
|
||||
}
|
||||
|
||||
public TextureRegion getRegion(){
|
||||
|
||||
@@ -89,7 +89,7 @@ public class OverlayRenderer{
|
||||
Draw.reset();
|
||||
|
||||
//draw selected block bars and info
|
||||
if(input.recipe == null && !Core.scene.hasMouse()){
|
||||
if(input.block == null && !Core.scene.hasMouse()){
|
||||
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||
Tile tile = world.tileWorld(vec.x, vec.y);
|
||||
|
||||
|
||||
@@ -38,13 +38,11 @@ public class Palette{
|
||||
|
||||
stoneGray = Color.valueOf("8f8f8f"),
|
||||
|
||||
portalLight = Color.valueOf("9054ea"),
|
||||
portal = Color.valueOf("6344d7"),
|
||||
portalDark = Color.valueOf("3f3dac"),
|
||||
|
||||
health = Color.valueOf("ff341c"),
|
||||
heal = Color.valueOf("98ffa9"),
|
||||
bar = Color.SLATE,
|
||||
accent = Color.valueOf("ffd37f"),
|
||||
locked = Color.valueOf("989aa4"),
|
||||
accentBack = Color.valueOf("d4816b"),
|
||||
place = Color.valueOf("6335f8"),
|
||||
remove = Color.valueOf("e55454"),
|
||||
@@ -54,7 +52,7 @@ public class Palette{
|
||||
range = Color.valueOf("f4ba6e"),
|
||||
power = Color.valueOf("fbad67"),
|
||||
powerLight = Color.valueOf("fbd367"),
|
||||
placing = Color.valueOf("616161"),
|
||||
placing = accent,
|
||||
|
||||
lightTrail = Color.valueOf("ffe2a9"),
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
|
||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -45,13 +46,10 @@ public class DesktopInput extends InputHandler{
|
||||
if(validPlace(x, y, block, rotation)){
|
||||
Draw.color();
|
||||
|
||||
TextureRegion[] regions = block.getBlockIcon();
|
||||
|
||||
for(TextureRegion region : regions){
|
||||
Draw.rect(region, x * tilesize + block.offset(), y * tilesize + block.offset(),
|
||||
region.getWidth() * selectScale * Draw.scl,
|
||||
region.getHeight() * selectScale * Draw.scl, block.rotate ? rotation * 90 : 0);
|
||||
}
|
||||
TextureRegion region = block.icon(Icon.full);
|
||||
Draw.rect(region, x * tilesize + block.offset(), y * tilesize + block.offset(),
|
||||
region.getWidth() * selectScale * Draw.scl,
|
||||
region.getHeight() * selectScale * Draw.scl, block.rotate ? rotation * 90 : 0);
|
||||
}else{
|
||||
Draw.color(Palette.removeBack);
|
||||
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f);
|
||||
@@ -62,7 +60,7 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
@Override
|
||||
public boolean isDrawing(){
|
||||
return mode != none || recipe != null;
|
||||
return mode != none || block != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,22 +70,30 @@ public class DesktopInput extends InputHandler{
|
||||
int cursorY = tileY(Core.input.mouseY());
|
||||
|
||||
//draw selection(s)
|
||||
if(mode == placing && recipe != null){
|
||||
if(mode == placing && block != null){
|
||||
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength);
|
||||
|
||||
for(int i = 0; i <= result.getLength(); i += recipe.result.size){
|
||||
for(int i = 0; i <= result.getLength(); i += block.size){
|
||||
int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX());
|
||||
int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX());
|
||||
|
||||
if(i + recipe.result.size > result.getLength() && recipe.result.rotate){
|
||||
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.remove : Palette.placeRotate);
|
||||
Draw.rect(Core.atlas.find("place-arrow"), x * tilesize + recipe.result.offset(),
|
||||
y * tilesize + recipe.result.offset(),
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getHeight() * Draw.scl,
|
||||
x * tilesize + recipe.result.offset()/2f, 0f, result.rotation * 90 - 90);
|
||||
if(i + block.size > result.getLength() && block.rotate){
|
||||
Draw.color(!validPlace(x, y, block, result.rotation) ? Palette.removeBack : Palette.accentBack);
|
||||
Draw.rect(Core.atlas.find("place-arrow"),
|
||||
x * tilesize + block.offset(),
|
||||
y * tilesize + block.offset() - 1,
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
|
||||
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
|
||||
|
||||
Draw.color(!validPlace(x, y, block, result.rotation) ? Palette.remove : Palette.accent);
|
||||
Draw.rect(Core.atlas.find("place-arrow"),
|
||||
x * tilesize + block.offset(),
|
||||
y * tilesize + block.offset(),
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
|
||||
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
|
||||
}
|
||||
|
||||
drawPlace(x, y, recipe.result, result.rotation);
|
||||
drawPlace(x, y, block, result.rotation);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
@@ -113,16 +119,23 @@ public class DesktopInput extends InputHandler{
|
||||
Draw.color(Palette.remove);
|
||||
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
|
||||
}else if(isPlacing()){
|
||||
if(recipe.result.rotate){
|
||||
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.remove : Palette.placeRotate);
|
||||
Draw.rect(Core.atlas.find("place-arrow"), cursorX * tilesize + recipe.result.offset(),
|
||||
cursorY * tilesize + recipe.result.offset(),
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
|
||||
Core.atlas.find("place-arrow").getHeight() * Draw.scl,
|
||||
cursorX * tilesize + recipe.result.offset()/2f, 0, rotation * 90 - 90);
|
||||
if(block.rotate){
|
||||
Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Palette.removeBack : Palette.accentBack);
|
||||
Draw.rect(Core.atlas.find("place-arrow"),
|
||||
cursorX * tilesize + block.offset(),
|
||||
cursorY * tilesize + block.offset() - 1,
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
|
||||
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
|
||||
|
||||
Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Palette.remove : Palette.accent);
|
||||
Draw.rect(Core.atlas.find("place-arrow"),
|
||||
cursorX * tilesize + block.offset(),
|
||||
cursorY * tilesize + block.offset(),
|
||||
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
|
||||
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
|
||||
}
|
||||
drawPlace(cursorX, cursorY, recipe.result, rotation);
|
||||
recipe.result.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, recipe.result, rotation));
|
||||
drawPlace(cursorX, cursorY, block, rotation);
|
||||
block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation));
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
@@ -167,7 +180,7 @@ public class DesktopInput extends InputHandler{
|
||||
selectScale = 0f;
|
||||
}
|
||||
|
||||
rotation = Mathf.mod(rotation + (int) Core.input.axis(Binding.rotate), 4);
|
||||
rotation = Mathf.mod(rotation + (int) Core.input.axisTap(Binding.rotate), 4);
|
||||
|
||||
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
||||
|
||||
@@ -221,13 +234,13 @@ public class DesktopInput extends InputHandler{
|
||||
}else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine
|
||||
player.isShooting = true;
|
||||
}
|
||||
}else if(Core.input.keyTap(Binding.deselect) && (recipe != null || mode != none || player.isBuilding()) &&
|
||||
}else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) &&
|
||||
!(player.getCurrentRequest() != null && player.getCurrentRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){
|
||||
if(recipe == null){
|
||||
if(block == null){
|
||||
player.clearBuilding();
|
||||
}
|
||||
|
||||
recipe = null;
|
||||
block = null;
|
||||
mode = none;
|
||||
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
|
||||
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset
|
||||
@@ -239,10 +252,10 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){
|
||||
|
||||
if(mode == placing && recipe != null){ //touch up while placing, place everything in selection
|
||||
if(mode == placing && block != null){ //touch up while placing, place everything in selection
|
||||
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength);
|
||||
|
||||
for(int i = 0; i <= result.getLength(); i += recipe.result.size){
|
||||
for(int i = 0; i <= result.getLength(); i += block.size){
|
||||
int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX());
|
||||
int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX());
|
||||
|
||||
@@ -286,11 +299,6 @@ public class DesktopInput extends InputHandler{
|
||||
return !controlling ? Core.input.mouseY() : controly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCursorVisible(){
|
||||
return controlling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateController(){
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.ValidateException;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.fragments.OverlayFragment;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Build;
|
||||
@@ -41,7 +40,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
public final Player player;
|
||||
public final OverlayFragment frag = new OverlayFragment(this);
|
||||
|
||||
public Recipe recipe;
|
||||
public Block block;
|
||||
public int rotation;
|
||||
public boolean droppingItem;
|
||||
|
||||
@@ -130,14 +129,6 @@ public abstract class InputHandler implements InputProcessor{
|
||||
return Core.input.mouseY();
|
||||
}
|
||||
|
||||
public void resetCursor(){
|
||||
|
||||
}
|
||||
|
||||
public boolean isCursorVisible(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public void buildUI(Table table){
|
||||
|
||||
}
|
||||
@@ -162,7 +153,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
boolean tileTapped(Tile tile){
|
||||
tile = tile.target();
|
||||
|
||||
boolean consumed = false, showedInventory = false, showedConsume = false;
|
||||
boolean consumed = false, showedInventory = false;
|
||||
|
||||
//check if tapped block is configurable
|
||||
if(tile.block().configurable && tile.getTeam() == player.getTeam()){
|
||||
@@ -207,7 +198,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
|
||||
if(!consumed && player.isBuilding()){
|
||||
player.clearBuilding();
|
||||
recipe = null;
|
||||
block = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,9 +230,9 @@ public abstract class InputHandler implements InputProcessor{
|
||||
|
||||
boolean canMine(Tile tile){
|
||||
return !Core.scene.hasMouse()
|
||||
&& tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower
|
||||
&& tile.floor().itemDrop != null && tile.floor().itemDrop.hardness <= player.mech.drillPower
|
||||
&& !tile.floor().playerUnmineable
|
||||
&& player.inventory.canAcceptItem(tile.floor().drops.item)
|
||||
&& player.inventory.canAcceptItem(tile.floor().itemDrop)
|
||||
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
||||
}
|
||||
|
||||
@@ -253,7 +244,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
int tileX(float cursorX){
|
||||
Vector2 vec = Core.input.mouseWorld(cursorX, 0);
|
||||
if(selectedBlock()){
|
||||
vec.sub(recipe.result.offset(), recipe.result.offset());
|
||||
vec.sub(block.offset(), block.offset());
|
||||
}
|
||||
return world.toTile(vec.x);
|
||||
}
|
||||
@@ -261,7 +252,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
int tileY(float cursorY){
|
||||
Vector2 vec = Core.input.mouseWorld(0, cursorY);
|
||||
if(selectedBlock()){
|
||||
vec.sub(recipe.result.offset(), recipe.result.offset());
|
||||
vec.sub(block.offset(), block.offset());
|
||||
}
|
||||
return world.toTile(vec.y);
|
||||
}
|
||||
@@ -271,7 +262,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
}
|
||||
|
||||
public boolean isPlacing(){
|
||||
return recipe != null;
|
||||
return block != null;
|
||||
}
|
||||
|
||||
public float mouseAngle(float x, float y){
|
||||
@@ -284,7 +275,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
}
|
||||
|
||||
public boolean canShoot(){
|
||||
return recipe == null && !Core.scene.hasMouse() && !onConfigurable() && !isDroppingItem();
|
||||
return block == null && !Core.scene.hasMouse() && !onConfigurable() && !isDroppingItem();
|
||||
}
|
||||
|
||||
public boolean onConfigurable(){
|
||||
@@ -317,8 +308,8 @@ public abstract class InputHandler implements InputProcessor{
|
||||
}
|
||||
|
||||
public void tryPlaceBlock(int x, int y){
|
||||
if(recipe != null && validPlace(x, y, recipe.result, rotation) && cursorNear()){
|
||||
placeBlock(x, y, recipe, rotation);
|
||||
if(block != null && validPlace(x, y, block, rotation) && cursorNear()){
|
||||
placeBlock(x, y, block, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,20 +320,16 @@ public abstract class InputHandler implements InputProcessor{
|
||||
}
|
||||
|
||||
public boolean validPlace(int x, int y, Block type, int rotation){
|
||||
for(Tile tile : state.teams.get(player.getTeam()).cores){
|
||||
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
|
||||
Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
|
||||
}
|
||||
|
||||
return false;
|
||||
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
|
||||
Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
|
||||
}
|
||||
|
||||
public boolean validBreak(int x, int y){
|
||||
return Build.validBreak(player.getTeam(), x, y) && Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
|
||||
}
|
||||
|
||||
public void placeBlock(int x, int y, Recipe recipe, int rotation){
|
||||
player.addBuildRequest(new BuildRequest(x, y, rotation, recipe));
|
||||
public void placeBlock(int x, int y, Block block, int rotation){
|
||||
player.addBuildRequest(new BuildRequest(x, y, rotation, block));
|
||||
}
|
||||
|
||||
public void breakBlock(int x, int y){
|
||||
|
||||
@@ -30,9 +30,9 @@ import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
|
||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -72,7 +72,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
/** Current place mode. */
|
||||
private PlaceMode mode = none;
|
||||
/** Whether no recipe was available when switching to break mode. */
|
||||
private Recipe lastRecipe;
|
||||
private Block lastBlock;
|
||||
/** Last placed request. Used for drawing block overlay. */
|
||||
private PlaceRequest lastPlaced;
|
||||
|
||||
@@ -120,8 +120,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
if(other == null || req.remove) continue;
|
||||
|
||||
r1.setSize(req.recipe.result.size * tilesize);
|
||||
r1.setCenter(other.worldx() + req.recipe.result.offset(), other.worldy() + req.recipe.result.offset());
|
||||
r1.setSize(req.block.size * tilesize);
|
||||
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
|
||||
|
||||
if(r2.overlaps(r1)){
|
||||
return true;
|
||||
@@ -141,8 +141,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
if(other == null) continue;
|
||||
|
||||
if(!req.remove){
|
||||
r1.setSize(req.recipe.result.size * tilesize);
|
||||
r1.setCenter(other.worldx() + req.recipe.result.offset(), other.worldy() + req.recipe.result.offset());
|
||||
r1.setSize(req.block.size * tilesize);
|
||||
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
|
||||
|
||||
if(r2.overlaps(r1)){
|
||||
return req;
|
||||
@@ -170,18 +170,16 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
if(!request.remove){
|
||||
//draw placing request
|
||||
float offset = request.recipe.result.offset();
|
||||
TextureRegion[] regions = request.recipe.result.getBlockIcon();
|
||||
float offset = request.block.offset();
|
||||
TextureRegion region = request.block.icon(Icon.full);
|
||||
|
||||
Draw.alpha(Mathf.clamp((1f - request.scale) / 0.5f));
|
||||
Draw.tint(Color.WHITE, Palette.breakInvalid, request.redness);
|
||||
|
||||
for(TextureRegion region : regions){
|
||||
Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset,
|
||||
region.getWidth() * request.scale * Draw.scl,
|
||||
region.getHeight() * request.scale * Draw.scl,
|
||||
request.recipe.result.rotate ? request.rotation * 90 : 0);
|
||||
}
|
||||
Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset,
|
||||
region.getWidth() * request.scale * Draw.scl,
|
||||
region.getHeight() * request.scale * Draw.scl,
|
||||
request.block.rotate ? request.rotation * 90 : 0);
|
||||
}else{
|
||||
float rad = (tile.block().size * tilesize / 2f - 1) * request.scale;
|
||||
Draw.alpha(0f);
|
||||
@@ -220,8 +218,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
table.left().margin(0f).defaults().size(48f);
|
||||
|
||||
table.addImageButton("icon-break", "clear-toggle-partial", 16 * 2f, () -> {
|
||||
mode = mode == breaking ? recipe == null ? none : placing : breaking;
|
||||
lastRecipe = recipe;
|
||||
mode = mode == breaking ? block == null ? none : placing : breaking;
|
||||
lastBlock = block;
|
||||
if(mode == breaking){
|
||||
showGuide("deconstruction");
|
||||
}
|
||||
@@ -231,13 +229,13 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> {
|
||||
player.clearBuilding();
|
||||
mode = none;
|
||||
recipe = null;
|
||||
}).visible(() -> player.isBuilding() || recipe != null || mode == breaking);
|
||||
block = null;
|
||||
}).visible(() -> player.isBuilding() || block != null || mode == breaking);
|
||||
|
||||
//rotate button
|
||||
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
|
||||
.update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center))
|
||||
.visible(() -> recipe != null && recipe.result.rotate);
|
||||
.visible(() -> block != null && block.rotate);
|
||||
|
||||
//confirm button
|
||||
table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> {
|
||||
@@ -248,10 +246,10 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
if(tile != null){
|
||||
if(!request.remove){
|
||||
rotation = request.rotation;
|
||||
Recipe before = recipe;
|
||||
recipe = request.recipe;
|
||||
Block before = block;
|
||||
block = request.block;
|
||||
tryPlaceBlock(tile.x, tile.y);
|
||||
recipe = before;
|
||||
block = before;
|
||||
}else{
|
||||
tryBreakBlock(tile.x, tile.y);
|
||||
}
|
||||
@@ -300,7 +298,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
if(tile == null) continue;
|
||||
|
||||
if((!request.remove && validPlace(tile.x, tile.y, request.recipe.result, request.rotation))
|
||||
if((!request.remove && validPlace(tile.x, tile.y, request.block, request.rotation))
|
||||
|| (request.remove && validBreak(tile.x, tile.y))){
|
||||
request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f);
|
||||
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f);
|
||||
@@ -313,8 +311,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
drawRequest(request);
|
||||
|
||||
//draw last placed request
|
||||
if(!request.remove && request == lastPlaced && request.recipe != null){
|
||||
request.recipe.result.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.recipe.result, rotation));
|
||||
if(!request.remove && request == lastPlaced && request.block != null){
|
||||
request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,34 +326,32 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
int tileY = tileY(Core.input.mouseY());
|
||||
|
||||
//draw placing
|
||||
if(mode == placing && recipe != null){
|
||||
NormalizeDrawResult dresult = PlaceUtils.normalizeDrawArea(recipe.result, lineStartX, lineStartY, tileX, tileY, true, maxLength, lineScale);
|
||||
if(mode == placing && block != null){
|
||||
NormalizeDrawResult dresult = PlaceUtils.normalizeDrawArea(block, lineStartX, lineStartY, tileX, tileY, true, maxLength, lineScale);
|
||||
|
||||
Lines.rect(dresult.x, dresult.y, dresult.x2 - dresult.x, dresult.y2 - dresult.y);
|
||||
|
||||
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, maxLength);
|
||||
|
||||
//go through each cell and draw the block to place if valid
|
||||
for(int i = 0; i <= result.getLength(); i += recipe.result.size){
|
||||
for(int i = 0; i <= result.getLength(); i += block.size){
|
||||
int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX());
|
||||
int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX());
|
||||
|
||||
if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){
|
||||
if(!checkOverlapPlacement(x, y, block) && validPlace(x, y, block, result.rotation)){
|
||||
Draw.color();
|
||||
|
||||
TextureRegion[] regions = recipe.result.getBlockIcon();
|
||||
TextureRegion region = block.icon(Icon.full);
|
||||
|
||||
for(TextureRegion region : regions){
|
||||
Draw.rect(region, x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(),
|
||||
region.getWidth() * lineScale * Draw.scl,
|
||||
region.getHeight() * lineScale * Draw.scl,
|
||||
recipe.result.rotate ? result.rotation * 90 : 0);
|
||||
}
|
||||
Draw.rect(region, x * tilesize + block.offset(), y * tilesize + block.offset(),
|
||||
region.getWidth() * lineScale * Draw.scl,
|
||||
region.getHeight() * lineScale * Draw.scl,
|
||||
block.rotate ? result.rotation * 90 : 0);
|
||||
}else{
|
||||
Draw.color(Palette.removeBack);
|
||||
Lines.square(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset() - 1, recipe.result.size * tilesize / 2f);
|
||||
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f);
|
||||
Draw.color(Palette.remove);
|
||||
Lines.square(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), recipe.result.size * tilesize / 2f);
|
||||
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,7 +440,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
int tileX = tileX(screenX);
|
||||
int tileY = tileY(screenY);
|
||||
|
||||
if(mode == placing && recipe != null){
|
||||
if(mode == placing && block != null){
|
||||
|
||||
//normalize area
|
||||
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, 100);
|
||||
@@ -452,12 +448,12 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
rotation = result.rotation;
|
||||
|
||||
//place blocks on line
|
||||
for(int i = 0; i <= result.getLength(); i += recipe.result.size){
|
||||
for(int i = 0; i <= result.getLength(); i += block.size){
|
||||
int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX());
|
||||
int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX());
|
||||
|
||||
if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){
|
||||
PlaceRequest request = new PlaceRequest(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), recipe, result.rotation);
|
||||
if(!checkOverlapPlacement(x, y, block) && validPlace(x, y, block, result.rotation)){
|
||||
PlaceRequest request = new PlaceRequest(x * tilesize + block.offset(), y * tilesize + block.offset(), block, result.rotation);
|
||||
request.scale = 1f;
|
||||
selection.add(request);
|
||||
}
|
||||
@@ -520,8 +516,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
if(mode == breaking){
|
||||
Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f);
|
||||
}else if(recipe != null){
|
||||
Effects.effect(Fx.tapBlock, cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe.result.size);
|
||||
}else if(block != null){
|
||||
Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -544,9 +540,9 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
//remove if request present
|
||||
if(hasRequest(cursor)){
|
||||
removeRequest(getRequest(cursor));
|
||||
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, recipe.result, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, recipe.result)){
|
||||
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
|
||||
//add to selection queue if it's a valid place position
|
||||
selection.add(lastPlaced = new PlaceRequest(cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe, rotation));
|
||||
selection.add(lastPlaced = new PlaceRequest(cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block, rotation));
|
||||
}else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){
|
||||
//add to selection queue if it's a valid BREAK position
|
||||
cursor = cursor.target();
|
||||
@@ -593,27 +589,27 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
selection.clear();
|
||||
}
|
||||
|
||||
if(lineMode && mode == placing && recipe == null){
|
||||
if(lineMode && mode == placing && block == null){
|
||||
lineMode = false;
|
||||
}
|
||||
|
||||
//if there is no mode and there's a recipe, switch to placing
|
||||
if(recipe != null && mode == none){
|
||||
if(block != null && mode == none){
|
||||
mode = placing;
|
||||
}
|
||||
|
||||
if(recipe != null){
|
||||
if(block != null){
|
||||
showGuide("construction");
|
||||
}
|
||||
|
||||
if(recipe == null && mode == placing){
|
||||
if(block == null && mode == placing){
|
||||
mode = none;
|
||||
}
|
||||
|
||||
//automatically switch to placing after a new recipe is selected
|
||||
if(lastRecipe != recipe && mode == breaking && recipe != null){
|
||||
if(lastBlock != block && mode == breaking && block != null){
|
||||
mode = placing;
|
||||
lastRecipe = recipe;
|
||||
lastBlock = block;
|
||||
}
|
||||
|
||||
if(lineMode){
|
||||
@@ -715,7 +711,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
|
||||
class PlaceRequest{
|
||||
float x, y;
|
||||
Recipe recipe;
|
||||
Block block;
|
||||
int rotation;
|
||||
boolean remove;
|
||||
|
||||
@@ -723,10 +719,10 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
float scale;
|
||||
float redness;
|
||||
|
||||
PlaceRequest(float x, float y, Recipe recipe, int rotation){
|
||||
PlaceRequest(float x, float y, Block block, int rotation){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.recipe = recipe;
|
||||
this.block = block;
|
||||
this.rotation = rotation;
|
||||
this.remove = false;
|
||||
}
|
||||
@@ -738,7 +734,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
}
|
||||
|
||||
Tile tile(){
|
||||
return world.tileWorld(x - (recipe == null ? 0 : recipe.result.offset()), y - (recipe == null ? 0 : recipe.result.offset()));
|
||||
return world.tileWorld(x - (block == null ? 0 : block.offset()), y - (block == null ? 0 : block.offset()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.traits.SaveTrait;
|
||||
import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.MappableContent;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
@@ -33,11 +35,11 @@ public abstract class SaveFileVersion{
|
||||
long time = stream.readLong();
|
||||
long playtime = stream.readLong();
|
||||
int build = stream.readInt();
|
||||
byte mode = stream.readByte();
|
||||
|
||||
Rules rules = Serialization.readRules(stream);
|
||||
String map = stream.readUTF();
|
||||
int wave = stream.readInt();
|
||||
byte difficulty = stream.readByte();
|
||||
return new SaveMeta(version, time, playtime, build, mode, map, wave, Difficulty.values()[difficulty]);
|
||||
return new SaveMeta(version, time, playtime, build, map, wave, rules);
|
||||
}
|
||||
|
||||
public void writeMap(DataOutputStream stream) throws IOException{
|
||||
@@ -99,7 +101,7 @@ public abstract class SaveFileVersion{
|
||||
|
||||
Tile tile = new Tile(x, y, floorid, wallid);
|
||||
|
||||
if(wallid == Blocks.blockpart.id){
|
||||
if(wallid == Blocks.part.id){
|
||||
tile.link = stream.readByte();
|
||||
}else if(tile.entity != null){
|
||||
byte tr = stream.readByte();
|
||||
@@ -122,7 +124,7 @@ public abstract class SaveFileVersion{
|
||||
tile.entity.readConfig(stream);
|
||||
tile.entity.read(stream);
|
||||
|
||||
if(tile.block() == Blocks.core){
|
||||
if(tile.block() instanceof CoreBlock){
|
||||
state.teams.get(t).cores.add(tile);
|
||||
}
|
||||
}else if(wallid == 0){
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadFromSlot(int slot){
|
||||
public static void loadFromSlot(int slot) throws SaveException{
|
||||
load(fileFor(slot));
|
||||
}
|
||||
|
||||
@@ -117,40 +117,41 @@ public class SaveIO{
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(FileHandle file){
|
||||
public static void load(FileHandle file) throws SaveException{
|
||||
try{
|
||||
//try and load; if any exception at all occurs
|
||||
load(new InflaterInputStream(file.read()));
|
||||
}catch(RuntimeException e){
|
||||
}catch(SaveException e){
|
||||
e.printStackTrace();
|
||||
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
|
||||
if(backup.exists()){
|
||||
load(new InflaterInputStream(backup.read()));
|
||||
}else{
|
||||
throw new RuntimeException(e);
|
||||
throw new SaveException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(InputStream is){
|
||||
logic.reset();
|
||||
|
||||
DataInputStream stream;
|
||||
|
||||
try{
|
||||
stream = new DataInputStream(is);
|
||||
public static void load(InputStream is) throws SaveException{
|
||||
try(DataInputStream stream = new DataInputStream(is)){
|
||||
logic.reset();
|
||||
int version = stream.readInt();
|
||||
SaveFileVersion ver = versions.get(version);
|
||||
|
||||
ver.read(stream);
|
||||
|
||||
stream.close();
|
||||
}catch(Exception e){
|
||||
content.setTemporaryMapper(null);
|
||||
throw new RuntimeException(e);
|
||||
throw new SaveException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SaveFileVersion getVersion(){
|
||||
return versionArray.peek();
|
||||
}
|
||||
|
||||
public static class SaveException extends RuntimeException{
|
||||
public SaveException(Throwable throwable){
|
||||
super(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
@@ -12,15 +12,15 @@ public class SaveMeta{
|
||||
public long timePlayed;
|
||||
public Map map;
|
||||
public int wave;
|
||||
public Difficulty difficulty;
|
||||
public Rules rules;
|
||||
|
||||
public SaveMeta(int version, long timestamp, long timePlayed, int build, int mode, String map, int wave, Difficulty difficulty){
|
||||
public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules){
|
||||
this.version = version;
|
||||
this.build = build;
|
||||
this.timestamp = timestamp;
|
||||
this.timePlayed = timePlayed;
|
||||
this.map = world.maps.getByName(map);
|
||||
this.wave = wave;
|
||||
this.difficulty = difficulty;
|
||||
this.rules = rules;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.annotations.Annotations.ReadClass;
|
||||
import io.anuke.annotations.Annotations.WriteClass;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
@@ -12,7 +15,6 @@ import io.anuke.mindustry.entities.traits.CarriableTrait;
|
||||
import io.anuke.mindustry.entities.traits.CarryTrait;
|
||||
import io.anuke.mindustry.entities.traits.ShooterTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.UnitCommand;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.net.Packets.AdminAction;
|
||||
import io.anuke.mindustry.net.Packets.KickReason;
|
||||
@@ -20,9 +22,6 @@ import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -173,7 +172,7 @@ public class TypeIO{
|
||||
buffer.put(request.breaking ? (byte) 1 : 0);
|
||||
buffer.putInt(Pos.get(request.x, request.y));
|
||||
if(!request.breaking){
|
||||
buffer.put(request.recipe.id);
|
||||
buffer.put(request.block.id);
|
||||
buffer.put((byte) request.rotation);
|
||||
}
|
||||
}
|
||||
@@ -191,9 +190,9 @@ public class TypeIO{
|
||||
if(type == 1){ //remove
|
||||
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position));
|
||||
}else{ //place
|
||||
byte recipe = buffer.get();
|
||||
byte block = buffer.get();
|
||||
byte rotation = buffer.get();
|
||||
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe));
|
||||
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
|
||||
}
|
||||
|
||||
reqs[i] = (currentRequest);
|
||||
@@ -232,16 +231,6 @@ public class TypeIO{
|
||||
return AdminAction.values()[buffer.get()];
|
||||
}
|
||||
|
||||
@WriteClass(UnitCommand.class)
|
||||
public static void writeCommand(ByteBuffer buffer, UnitCommand reason){
|
||||
buffer.put((byte) reason.ordinal());
|
||||
}
|
||||
|
||||
@ReadClass(UnitCommand.class)
|
||||
public static UnitCommand readCommand(ByteBuffer buffer){
|
||||
return UnitCommand.values()[buffer.get()];
|
||||
}
|
||||
|
||||
@WriteClass(Effect.class)
|
||||
public static void writeEffect(ByteBuffer buffer, Effect effect){
|
||||
buffer.putShort((short) effect.id);
|
||||
@@ -313,16 +302,6 @@ public class TypeIO{
|
||||
return id == -1 ? null : content.item(id);
|
||||
}
|
||||
|
||||
@WriteClass(Recipe.class)
|
||||
public static void writeRecipe(ByteBuffer buffer, Recipe recipe){
|
||||
buffer.put(recipe.id);
|
||||
}
|
||||
|
||||
@ReadClass(Recipe.class)
|
||||
public static Recipe readRecipe(ByteBuffer buffer){
|
||||
return content.recipe(buffer.get());
|
||||
}
|
||||
|
||||
@WriteClass(String.class)
|
||||
public static void writeString(ByteBuffer buffer, String string){
|
||||
if(string != null){
|
||||
|
||||
@@ -5,6 +5,8 @@ import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.io.SaveFileVersion;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
@@ -26,6 +28,10 @@ public class Save16 extends SaveFileVersion{
|
||||
|
||||
//general state
|
||||
state.rules = Serialization.readRules(stream);
|
||||
//load zone spawn patterns if applicable
|
||||
if(content.getByID(ContentType.zone, state.rules.zone) != null){
|
||||
state.rules.spawns = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get().spawns;
|
||||
}
|
||||
String mapname = stream.readUTF();
|
||||
Map map = world.maps.getByName(mapname);
|
||||
if(map == null) map = new Map("unknown", 1, 1);
|
||||
@@ -36,13 +42,11 @@ public class Save16 extends SaveFileVersion{
|
||||
|
||||
state.wave = wave;
|
||||
state.wavetime = wavetime;
|
||||
state.stats = Serialization.readStats(stream);
|
||||
|
||||
content.setTemporaryMapper(readContentHeader(stream));
|
||||
|
||||
world.spawner.read(stream);
|
||||
|
||||
readEntities(stream);
|
||||
|
||||
readMap(stream);
|
||||
}
|
||||
|
||||
@@ -61,9 +65,9 @@ public class Save16 extends SaveFileVersion{
|
||||
stream.writeInt(state.wave); //wave
|
||||
stream.writeFloat(state.wavetime); //wave countdown
|
||||
|
||||
writeContentHeader(stream);
|
||||
Serialization.writeStats(stream, state.stats);
|
||||
|
||||
world.spawner.write(stream); //spawnes
|
||||
writeContentHeader(stream);
|
||||
|
||||
//--ENTITIES--
|
||||
|
||||
|
||||
@@ -63,14 +63,7 @@ public class Maps implements Disposable{
|
||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||
|
||||
try(DataInputStream ds = new DataInputStream(file.read())) {
|
||||
MapMeta meta = MapIO.readMapMeta(ds);
|
||||
Map map = new Map(name, meta, false, file::read);
|
||||
|
||||
if (!headless){
|
||||
map.texture = new Texture(MapIO.generatePixmap(MapIO.readTileData(ds, meta, true)));
|
||||
}
|
||||
|
||||
return map;
|
||||
return new Map(name, MapIO.readMapMeta(ds), false, file::read);
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class BasicGenerator extends RandomGenerator{
|
||||
}
|
||||
|
||||
if(rocks > 0.64){
|
||||
block = Blocks.rocksSmall;
|
||||
block = Blocks.rocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,5 +12,9 @@ public abstract class Generator{
|
||||
|
||||
public Generator(){}
|
||||
|
||||
public void init(){
|
||||
|
||||
}
|
||||
|
||||
public abstract void generate(Tile[][] tiles);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,39 @@
|
||||
package io.anuke.mindustry.maps.generators;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.noise.Simplex;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MapGenerator extends Generator{
|
||||
private final Map map;
|
||||
private Map map;
|
||||
private String mapName;
|
||||
|
||||
/**How much the landscape is randomly distorted.*/
|
||||
public float distortion = 3;
|
||||
|
||||
/**The amount of final enemy spawns used. -1 to use everything in the map.
|
||||
* This amount of enemy spawns is selected randomly from the map.*/
|
||||
public int enemySpawns = -1;
|
||||
|
||||
public MapGenerator(String mapName){
|
||||
this.mapName = mapName;
|
||||
}
|
||||
|
||||
public MapGenerator(String mapName, int enemySpawns){
|
||||
this.mapName = mapName;
|
||||
this.enemySpawns = enemySpawns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
map = world.maps.loadInternalMap(mapName);
|
||||
width = map.meta.width;
|
||||
height = map.meta.height;
|
||||
@@ -22,15 +45,60 @@ public class MapGenerator extends Generator{
|
||||
|
||||
data.position(0, 0);
|
||||
TileDataMarker marker = data.newDataMarker();
|
||||
Array<Point2> players = new Array<>();
|
||||
Array<Point2> enemies = new Array<>();
|
||||
|
||||
for(int y = 0; y < data.height(); y++){
|
||||
for(int x = 0; x < data.width(); x++){
|
||||
data.read(marker);
|
||||
|
||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.blockpart.id ? 0 : marker.wall, marker.rotation, marker.team);
|
||||
if(content.block(marker.wall) instanceof CoreBlock){
|
||||
players.add(new Point2(x, y));
|
||||
marker.wall = 0;
|
||||
}
|
||||
|
||||
if(enemySpawns != -1 && content.block(marker.wall) == Blocks.spawn){
|
||||
enemies.add(new Point2(x, y));
|
||||
marker.wall = 0;
|
||||
}
|
||||
|
||||
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.part.id ? 0 : marker.wall, marker.rotation, marker.team);
|
||||
}
|
||||
}
|
||||
|
||||
Simplex simplex = new Simplex(Mathf.random(99999));
|
||||
|
||||
for(int x = 0; x < data.width(); x++){
|
||||
for(int y = 0; y < data.height(); y++){
|
||||
final double scl = 10;
|
||||
int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, data.width()-1);
|
||||
int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, data.height()-1);
|
||||
if(tiles[newX][newY].block() != Blocks.spawn && !tiles[x][y].block().synthetic()&& !tiles[newX][newY].block().synthetic()){
|
||||
tiles[x][y].setBlock(tiles[newX][newY].block());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(enemySpawns > enemies.size){
|
||||
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
|
||||
}
|
||||
|
||||
if(enemySpawns != -1){
|
||||
enemies.shuffle();
|
||||
for(int i = 0; i < enemySpawns; i++){
|
||||
Point2 point = enemies.get(i);
|
||||
tiles[point.x][point.y].setBlock(Blocks.spawn);
|
||||
}
|
||||
}
|
||||
|
||||
Point2 core = players.random();
|
||||
if(core == null){
|
||||
throw new IllegalArgumentException("All zone maps must have a core.");
|
||||
}
|
||||
|
||||
//TODO set specific core block?
|
||||
tiles[core.x][core.y].setBlock(Blocks.core, defaultTeam);
|
||||
|
||||
world.prepareTiles(tiles);
|
||||
world.setMap(map);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.anuke.mindustry.type;
|
||||
/**Do not rearrange, ever!*/
|
||||
public enum ContentType {
|
||||
item,
|
||||
recipe,
|
||||
block,
|
||||
mech,
|
||||
bullet,
|
||||
|
||||
@@ -30,7 +30,7 @@ public class Item extends UnlockableContent implements Comparable<Item>{
|
||||
public float fluxiness = 0f;
|
||||
/**drill hardness of the item*/
|
||||
public int hardness = 0;
|
||||
/**the burning color of this item*/
|
||||
/**the burning color of this item. TODO unused; implement*/
|
||||
public Color flameColor = Palette.darkFlame.cpy();
|
||||
/**
|
||||
* base material cost of this item, used for calculating place times
|
||||
@@ -49,7 +49,7 @@ public class Item extends UnlockableContent implements Comparable<Item>{
|
||||
|
||||
if(!Core.bundle.has("item." + this.name + ".name")){
|
||||
Log.err("Warning: item '" + name + "' is missing a localized name. Add the following to bundle.properties:");
|
||||
Log.err("item." + this.name + ".name=" + Strings.capitalize(name.replace('-', '_')));
|
||||
Log.err("item." + this.name + ".name = " + Strings.capitalize(name.replace('-', '_')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +97,8 @@ public class Item extends UnlockableContent implements Comparable<Item>{
|
||||
return ContentType.item;
|
||||
}
|
||||
|
||||
/**Allocates a new array containing all items the generate ores.*/
|
||||
public static Array<Item> getAllOres(){
|
||||
Array<Item> arr = new Array<>();
|
||||
for(Item item : Vars.content.items()){
|
||||
if(item.genOre) arr.add(item);
|
||||
}
|
||||
return arr;
|
||||
return Vars.content.items().select(i -> i.genOre);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
package io.anuke.mindustry.type;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.OrderedMap;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.ui.ContentDisplay;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.ContentStatValue;
|
||||
import io.anuke.mindustry.world.meta.StatValue;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Recipe extends UnlockableContent{
|
||||
private static ObjectMap<Block, Recipe> recipeMap = new ObjectMap<>();
|
||||
private static Array<Recipe> returnArray = new Array<>();
|
||||
|
||||
public final Block result;
|
||||
public final ItemStack[] requirements;
|
||||
public final Category category;
|
||||
public final float cost;
|
||||
|
||||
public RecipeVisibility visibility = RecipeVisibility.all;
|
||||
public boolean hidden;
|
||||
public boolean alwaysUnlocked;
|
||||
|
||||
public Recipe(Category category, Block result, ItemStack... requirements){
|
||||
this.result = result;
|
||||
this.requirements = requirements;
|
||||
this.category = category;
|
||||
|
||||
Arrays.sort(requirements, (a, b) -> Integer.compare(a.item.id, b.item.id));
|
||||
|
||||
float timeToPlace = 0f;
|
||||
for(ItemStack stack : requirements){
|
||||
timeToPlace += stack.amount * stack.item.cost;
|
||||
}
|
||||
|
||||
this.cost = timeToPlace;
|
||||
|
||||
recipeMap.put(result, this);
|
||||
}
|
||||
|
||||
/**Returns all non-hidden recipes in a category.*/
|
||||
public static Array<Recipe> getByCategory(Category category){
|
||||
returnArray.clear();
|
||||
for(Recipe recipe : content.recipes()){
|
||||
if(recipe.category == category && recipe.visibility.shown()){
|
||||
returnArray.add(recipe);
|
||||
}
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
public static Recipe getByResult(Block block){
|
||||
return recipeMap.get(block);
|
||||
}
|
||||
|
||||
public Recipe setVisible(RecipeVisibility visibility){
|
||||
this.visibility = visibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Recipe setHidden(boolean hidden){
|
||||
this.hidden = hidden;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Recipe setAlwaysUnlocked(boolean unlocked){
|
||||
this.alwaysUnlocked = unlocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return alwaysUnlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(){
|
||||
return !visibility.shown() || hidden;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayRecipe(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return result.formalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getContentIcon(){
|
||||
return result.getEditorIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
if(!Core.bundle.has("block." + result.name + ".name")){
|
||||
Log.err("WARNING: Recipe block '{0}' does not have a formal name defined. Add the following to bundle.properties:", result.name);
|
||||
Log.err("block.{0}.name={1}", result.name, Strings.capitalize(result.name.replace('-', '_')));
|
||||
}/*else if(result.fullDescription == null){
|
||||
Log.err("WARNING: Recipe block '{0}' does not have a description defined.", result.name);
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentName(){
|
||||
return result.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.recipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlock(){
|
||||
for(OrderedMap<BlockStat, StatValue> map : result.stats.toMap().values()){
|
||||
for(StatValue value : map.values()){
|
||||
if(value instanceof ContentStatValue){
|
||||
ContentStatValue stat = (ContentStatValue) value;
|
||||
UnlockableContent[] content = stat.getValueContent();
|
||||
for(UnlockableContent c : content){
|
||||
data.unlockContent(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RecipeVisibility{
|
||||
mobileOnly(true, false),
|
||||
desktopOnly(false, true),
|
||||
all(true, true),
|
||||
sandboxOnly(true, true){
|
||||
@Override
|
||||
public boolean usable(){
|
||||
return state.rules.infiniteResources;
|
||||
}
|
||||
};
|
||||
|
||||
public final boolean mobile, desktop;
|
||||
|
||||
RecipeVisibility(boolean mobile, boolean desktop){
|
||||
this.mobile = mobile;
|
||||
this.desktop = desktop;
|
||||
}
|
||||
|
||||
public boolean usable(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean shown(){
|
||||
return usable() && ((Vars.mobile && mobile) || (!Vars.mobile && desktop));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,42 @@ import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.maps.generators.Generator;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
|
||||
public class Zone extends UnlockableContent{
|
||||
public final String name;
|
||||
public final Generator generator;
|
||||
public ItemStack[] deployCost = {};
|
||||
public ItemStack[] startingItems = {};
|
||||
public Block[] blockRequirements = {};
|
||||
public ItemStack[] itemRequirements = {};
|
||||
public Zone[] zoneRequirements = {};
|
||||
public Supplier<Rules> rules = Rules::new;
|
||||
public boolean alwaysUnlocked;
|
||||
public int conditionWave = Integer.MAX_VALUE;
|
||||
|
||||
public Zone(String name, Generator generator){
|
||||
this.name = name;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
/**Whether this zone has met its condition; if true, the player can leave.*/
|
||||
public boolean metCondition(){
|
||||
return state.wave >= conditionWave;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
generator.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return alwaysUnlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(){
|
||||
return true;
|
||||
@@ -46,4 +69,5 @@ public class Zone extends UnlockableContent{
|
||||
public ContentType getContentType(){
|
||||
return ContentType.zone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
82
core/src/io/anuke/mindustry/ui/Bar.java
Normal file
82
core/src/io/anuke/mindustry/ui/Bar.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.function.FloatProvider;
|
||||
import io.anuke.arc.function.Supplier;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.BitmapFont;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.GlyphLayout;
|
||||
import io.anuke.arc.graphics.g2d.ScissorStack;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.style.Drawable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
|
||||
public class Bar extends Element{
|
||||
private static Rectangle scissor = new Rectangle();
|
||||
|
||||
private FloatProvider fraction;
|
||||
private String name = "";
|
||||
private float value, lastValue, blink;
|
||||
private Color blinkColor = new Color();
|
||||
|
||||
public Bar(String name, Color color, FloatProvider fraction){
|
||||
this.fraction = fraction;
|
||||
this.name = Core.bundle.get(name);
|
||||
this.blinkColor.set(color);
|
||||
lastValue = value = fraction.get();
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
public Bar(Supplier<String> name, Supplier<Color> color, FloatProvider fraction){
|
||||
this.fraction = fraction;
|
||||
update(() -> {
|
||||
this.name = name.get();
|
||||
setColor(color.get());
|
||||
});
|
||||
}
|
||||
|
||||
public Bar blink(Color color){
|
||||
blinkColor.set(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
if(!Mathf.isEqual(lastValue, fraction.get())){
|
||||
blink = 1f;
|
||||
lastValue = fraction.get();
|
||||
}
|
||||
|
||||
blink = Mathf.lerpDelta(blink, 0f, 0.2f);
|
||||
value = Mathf.lerpDelta(value, fraction.get(), 0.15f);
|
||||
|
||||
Draw.colorl(0.1f);
|
||||
Draw.drawable("bar", x, y, width, height);
|
||||
Draw.color(color, blinkColor, blink);
|
||||
|
||||
Drawable top = Core.scene.skin.getDrawable("bar-top");
|
||||
float topWidth = width * value;
|
||||
|
||||
if(topWidth > Core.atlas.find("bar-top").getWidth()){
|
||||
top.draw(x, y, topWidth, height);
|
||||
}else{
|
||||
if(ScissorStack.pushScissors(scissor.set(x, y, topWidth, height))){
|
||||
top.draw(x, y, Core.atlas.find("bar-top").getWidth(), height);
|
||||
ScissorStack.popScissors();
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
BitmapFont font = Core.scene.skin.getFont("default-font");
|
||||
GlyphLayout lay = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
lay.setText(font, name);
|
||||
|
||||
font.draw(name, x + width/2f - lay.width/2f, y + height/2f + lay.height/2f + 1);
|
||||
|
||||
Pools.free(lay);
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.type.Mech;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.BlockStats;
|
||||
import io.anuke.mindustry.world.meta.StatCategory;
|
||||
@@ -19,19 +19,18 @@ import io.anuke.mindustry.world.meta.StatValue;
|
||||
|
||||
public class ContentDisplay{
|
||||
|
||||
public static void displayRecipe(Table table, Recipe recipe){
|
||||
Block block = recipe.result;
|
||||
public static void displayBlock(Table table, Block block){
|
||||
|
||||
table.table(title -> {
|
||||
int size = 8 * 6;
|
||||
|
||||
title.addImage(Core.atlas.find("block-icon-" + block.name)).size(size);
|
||||
title.addImage(block.icon(Icon.large)).size(size);
|
||||
title.add("[accent]" + block.formalName).padLeft(5);
|
||||
});
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX();
|
||||
|
||||
table.row();
|
||||
|
||||
@@ -39,7 +38,7 @@ public class ContentDisplay{
|
||||
table.add(block.fullDescription).padLeft(5).padRight(5).width(400f).wrap().fillX();
|
||||
table.row();
|
||||
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX();
|
||||
table.addImage("white").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX();
|
||||
table.row();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
|
||||
public class ImageStack extends Stack{
|
||||
|
||||
public ImageStack(TextureRegion... regions){
|
||||
for(TextureRegion region : regions){
|
||||
add(new Image(region));
|
||||
}
|
||||
}
|
||||
}
|
||||
310
core/src/io/anuke/mindustry/ui/TreeLayout.java
Normal file
310
core/src/io/anuke/mindustry/ui/TreeLayout.java
Normal file
@@ -0,0 +1,310 @@
|
||||
|
||||
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.collection.FloatArray;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
|
||||
/**
|
||||
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
|
||||
*/
|
||||
public class TreeLayout{
|
||||
public TreeLocation rootLocation = TreeLocation.top;
|
||||
public TreeAlignment alignment = TreeAlignment.awayFromRoot;
|
||||
public float gapBetweenLevels = 10;
|
||||
public float gapBetweenNodes = 10f;
|
||||
|
||||
private final FloatArray sizeOfLevel = new FloatArray();
|
||||
private float boundsLeft = Float.MAX_VALUE;
|
||||
private float boundsRight = Float.MIN_VALUE;
|
||||
private float boundsTop = Float.MAX_VALUE;
|
||||
private float boundsBottom = Float.MIN_VALUE;
|
||||
|
||||
public void layout(TreeNode root){
|
||||
firstWalk(root, null);
|
||||
calcSizeOfLevels(root, 0);
|
||||
secondWalk(root, -root.prelim, 0, 0);
|
||||
}
|
||||
|
||||
private float getWidthOrHeightOfNode(TreeNode treeNode, boolean returnWidth){
|
||||
return returnWidth ? treeNode.width : treeNode.height;
|
||||
}
|
||||
|
||||
private float getNodeThickness(TreeNode treeNode){
|
||||
return getWidthOrHeightOfNode(treeNode, !isLevelChangeInYAxis());
|
||||
}
|
||||
|
||||
private float getNodeSize(TreeNode treeNode){
|
||||
return getWidthOrHeightOfNode(treeNode, isLevelChangeInYAxis());
|
||||
}
|
||||
|
||||
private boolean isLevelChangeInYAxis(){
|
||||
return rootLocation == TreeLocation.top || rootLocation == TreeLocation.bottom;
|
||||
}
|
||||
|
||||
private int getLevelChangeSign(){
|
||||
return rootLocation == TreeLocation.bottom || rootLocation == TreeLocation.right ? -1 : 1;
|
||||
}
|
||||
|
||||
private void updateBounds(TreeNode node, float centerX, float centerY){
|
||||
float width = node.width;
|
||||
float height = node.height;
|
||||
float left = centerX - width / 2;
|
||||
float right = centerX + width / 2;
|
||||
float top = centerY - height / 2;
|
||||
float bottom = centerY + height / 2;
|
||||
if(boundsLeft > left){
|
||||
boundsLeft = left;
|
||||
}
|
||||
if(boundsRight < right){
|
||||
boundsRight = right;
|
||||
}
|
||||
if(boundsTop > top){
|
||||
boundsTop = top;
|
||||
}
|
||||
if(boundsBottom < bottom){
|
||||
boundsBottom = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle getBounds(){
|
||||
return new Rectangle(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom);
|
||||
}
|
||||
|
||||
private void calcSizeOfLevels(TreeNode node, int level){
|
||||
float oldSize;
|
||||
if(sizeOfLevel.size <= level){
|
||||
sizeOfLevel.add(0);
|
||||
oldSize = 0;
|
||||
}else{
|
||||
oldSize = sizeOfLevel.get(level);
|
||||
}
|
||||
|
||||
float size = getNodeThickness(node);
|
||||
if(oldSize < size){
|
||||
sizeOfLevel.set(level, size);
|
||||
}
|
||||
|
||||
if(!node.isLeaf()){
|
||||
for(TreeNode child : node.children){
|
||||
calcSizeOfLevels(child, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getLevelCount(){
|
||||
return sizeOfLevel.size;
|
||||
}
|
||||
|
||||
public float getGapBetweenNodes(TreeNode a, TreeNode b){
|
||||
return gapBetweenNodes;
|
||||
}
|
||||
|
||||
public float getSizeOfLevel(int level){
|
||||
if(!(level >= 0)) throw new IllegalArgumentException("level must be >= 0");
|
||||
if(!(level < getLevelCount())) throw new IllegalArgumentException("level must be < levelCount");
|
||||
|
||||
return sizeOfLevel.get(level);
|
||||
}
|
||||
|
||||
private TreeNode getAncestor(TreeNode node){
|
||||
return node.ancestor != null ? node.ancestor : node;
|
||||
}
|
||||
|
||||
private float getDistance(TreeNode v, TreeNode w){
|
||||
float sizeOfNodes = getNodeSize(v) + getNodeSize(w);
|
||||
|
||||
return sizeOfNodes / 2 + getGapBetweenNodes(v, w);
|
||||
}
|
||||
|
||||
private TreeNode nextLeft(TreeNode v){
|
||||
return v.isLeaf() ? v.thread : v.children[0];
|
||||
}
|
||||
|
||||
private TreeNode nextRight(TreeNode v){
|
||||
return v.isLeaf() ? v.thread : v.children[v.children.length - 1];
|
||||
}
|
||||
|
||||
private int getNumber(TreeNode node, TreeNode parentNode){
|
||||
if(node.number == -1){
|
||||
int number = 1;
|
||||
for(TreeNode child : parentNode.children){
|
||||
child.number = number++;
|
||||
}
|
||||
}
|
||||
return node.number;
|
||||
}
|
||||
|
||||
private TreeNode ancestor(TreeNode vIMinus, TreeNode parentOfV, TreeNode defaultAncestor){
|
||||
TreeNode ancestor = getAncestor(vIMinus);
|
||||
return ancestor.parent == parentOfV ? ancestor : defaultAncestor;
|
||||
}
|
||||
|
||||
private void moveSubtree(TreeNode wMinus, TreeNode wPlus, TreeNode parent, float shift){
|
||||
int subtrees = getNumber(wPlus, parent) - getNumber(wMinus, parent);
|
||||
wPlus.change = wPlus.change - shift / subtrees;
|
||||
wPlus.shift = wPlus.shift + shift;
|
||||
wMinus.change = wMinus.change + shift / subtrees;
|
||||
wPlus.prelim = wPlus.prelim + shift;
|
||||
wPlus.mode = wPlus.mode + shift;
|
||||
}
|
||||
|
||||
private TreeNode apportion(TreeNode v, TreeNode defaultAncestor,
|
||||
TreeNode leftSibling, TreeNode parentOfV){
|
||||
if(leftSibling == null){
|
||||
return defaultAncestor;
|
||||
}
|
||||
|
||||
TreeNode vOPlus = v;
|
||||
TreeNode vIPlus = v;
|
||||
TreeNode vIMinus = leftSibling;
|
||||
|
||||
TreeNode vOMinus = parentOfV.children[0];
|
||||
|
||||
float sIPlus = (vIPlus).mode;
|
||||
float sOPlus = (vOPlus).mode;
|
||||
float sIMinus = (vIMinus).mode;
|
||||
float sOMinus = (vOMinus).mode;
|
||||
|
||||
TreeNode nextRightVIMinus = nextRight(vIMinus);
|
||||
TreeNode nextLeftVIPlus = nextLeft(vIPlus);
|
||||
|
||||
while(nextRightVIMinus != null && nextLeftVIPlus != null){
|
||||
vIMinus = nextRightVIMinus;
|
||||
vIPlus = nextLeftVIPlus;
|
||||
vOMinus = nextLeft(vOMinus);
|
||||
vOPlus = nextRight(vOPlus);
|
||||
vOPlus.ancestor = v;
|
||||
float shift = (vIMinus.prelim + sIMinus)
|
||||
- (vIPlus.prelim + sIPlus)
|
||||
+ getDistance(vIMinus, vIPlus);
|
||||
|
||||
if(shift > 0){
|
||||
moveSubtree(ancestor(vIMinus, parentOfV, defaultAncestor),
|
||||
v, parentOfV, shift);
|
||||
sIPlus = sIPlus + shift;
|
||||
sOPlus = sOPlus + shift;
|
||||
}
|
||||
sIMinus += vIMinus.mode;
|
||||
sIPlus += vIPlus.mode;
|
||||
sOMinus += vOMinus.mode;
|
||||
sOPlus += vOPlus.mode;
|
||||
|
||||
nextRightVIMinus = nextRight(vIMinus);
|
||||
nextLeftVIPlus = nextLeft(vIPlus);
|
||||
}
|
||||
|
||||
if(nextRightVIMinus != null && nextRight(vOPlus) == null){
|
||||
vOPlus.thread = nextRightVIMinus;
|
||||
vOPlus.mode += sIMinus - sOPlus;
|
||||
}
|
||||
|
||||
if(nextLeftVIPlus != null && nextLeft(vOMinus) == null){
|
||||
vOMinus.thread = nextLeftVIPlus;
|
||||
vOMinus.mode += sIPlus - sOMinus;
|
||||
defaultAncestor = v;
|
||||
}
|
||||
return defaultAncestor;
|
||||
}
|
||||
|
||||
private void executeShifts(TreeNode v){
|
||||
float shift = 0;
|
||||
float change = 0;
|
||||
|
||||
for(int i = v.children.length - 1; i >= 0; i --){
|
||||
TreeNode w = v.children[i];
|
||||
change = change + w.change;
|
||||
w.prelim += shift;
|
||||
w.mode += shift;
|
||||
shift += w.shift + change;
|
||||
}
|
||||
}
|
||||
|
||||
private void firstWalk(TreeNode v, TreeNode leftSibling){
|
||||
if(v.isLeaf()){
|
||||
if(leftSibling != null){
|
||||
v.prelim = leftSibling.prelim + getDistance(v, leftSibling);
|
||||
}
|
||||
|
||||
}else{
|
||||
TreeNode defaultAncestor = v.children[0];
|
||||
TreeNode previousChild = null;
|
||||
for(TreeNode w : v.children){
|
||||
firstWalk(w, previousChild);
|
||||
defaultAncestor = apportion(w, defaultAncestor, previousChild,
|
||||
v);
|
||||
previousChild = w;
|
||||
}
|
||||
executeShifts(v);
|
||||
float midpoint = (v.children[0].prelim + v.children[v.children.length-1].prelim) / 2f;
|
||||
TreeNode w = leftSibling;
|
||||
if(w != null){
|
||||
v.prelim = w.prelim + getDistance(v, w);
|
||||
v.mode = v.prelim - midpoint;
|
||||
}else{
|
||||
v.prelim = midpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void secondWalk(TreeNode v, float m, int level, float levelStart){
|
||||
float levelChangeSign = getLevelChangeSign();
|
||||
boolean levelChangeOnYAxis = isLevelChangeInYAxis();
|
||||
float levelSize = getSizeOfLevel(level);
|
||||
|
||||
float x = v.prelim + m;
|
||||
|
||||
float y;
|
||||
if(alignment == TreeAlignment.center){
|
||||
y = levelStart + levelChangeSign * (levelSize / 2);
|
||||
}else if(alignment == TreeAlignment.towardsRoot){
|
||||
y = levelStart + levelChangeSign * (getNodeThickness(v) / 2);
|
||||
}else{
|
||||
y = levelStart + levelSize - levelChangeSign
|
||||
* (getNodeThickness(v) / 2);
|
||||
}
|
||||
|
||||
if(!levelChangeOnYAxis){
|
||||
float t = x;
|
||||
x = y;
|
||||
y = t;
|
||||
}
|
||||
|
||||
v.x = x;
|
||||
v.y = y;
|
||||
updateBounds(v, x, y);
|
||||
|
||||
if(!v.isLeaf()){
|
||||
float nextLevelStart = levelStart
|
||||
+ (levelSize + gapBetweenLevels)
|
||||
* levelChangeSign;
|
||||
for(TreeNode w : v.children){
|
||||
secondWalk(w, m + v.mode, level + 1, nextLevelStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TreeLocation{
|
||||
top, left, bottom, right
|
||||
}
|
||||
|
||||
public enum TreeAlignment{
|
||||
center, towardsRoot, awayFromRoot
|
||||
}
|
||||
|
||||
public static class TreeNode{
|
||||
public float width, height, x, y;
|
||||
|
||||
//should be initialized by user
|
||||
public TreeNode[] children;
|
||||
public TreeNode parent;
|
||||
|
||||
private float mode, prelim, change, shift;
|
||||
private int number = -1;
|
||||
private TreeNode thread, ancestor;
|
||||
|
||||
boolean isLeaf(){
|
||||
return children == null || children.length == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class AboutDialog extends FloatingDialog{
|
||||
continue;
|
||||
}
|
||||
|
||||
Table table = new Table("underline-2");
|
||||
Table table = new Table("underline");
|
||||
table.margin(0);
|
||||
table.table(img -> {
|
||||
img.addImage("white").height(h - 5).width(40f).color(link.color);
|
||||
|
||||
@@ -15,10 +15,10 @@ import io.anuke.arc.scene.utils.UIUtils;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class UnlocksDialog extends FloatingDialog{
|
||||
public class DatabaseDialog extends FloatingDialog{
|
||||
|
||||
public UnlocksDialog(){
|
||||
super("$unlocks");
|
||||
public DatabaseDialog(){
|
||||
super("database");
|
||||
|
||||
shouldPause = true;
|
||||
addCloseButton();
|
||||
@@ -58,7 +58,7 @@ public class UnlocksDialog extends FloatingDialog{
|
||||
|
||||
if(unlock.isHidden()) continue;
|
||||
|
||||
Image image = data.isUnlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-locked");
|
||||
Image image = data.isUnlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-tree-locked");
|
||||
image.addListener(new HandCursorListener());
|
||||
list.add(image).size(size).pad(3);
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.ObjectIntMap;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.ScrollPane;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Saves.SaveSlot;
|
||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.ItemType;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -23,41 +31,192 @@ public class DeployDialog extends FloatingDialog{
|
||||
cont.clear();
|
||||
|
||||
addCloseButton();
|
||||
buttons.addImageTextButton("$techtree", "icon-tree", 16 * 2, () -> ui.tech.show()).size(230f, 64f);
|
||||
|
||||
cont.stack(new Table(){{
|
||||
top().left().margin(10);
|
||||
|
||||
ObjectIntMap<Item> items = data.items();
|
||||
for(Item item : Vars.content.items()){
|
||||
for(Item item : content.items()){
|
||||
if(item.type == ItemType.material && data.isUnlocked(item)){
|
||||
add(items.get(item, 0) + "").left();
|
||||
label(() -> items.get(item, 0) + "").left();
|
||||
addImage(item.region).size(8*4).pad(4);
|
||||
add("[LIGHT_GRAY]" + item.localizedName()).left();
|
||||
row();
|
||||
}
|
||||
}
|
||||
|
||||
}}, new Table(){{
|
||||
}}, new ScrollPane(new Table(){{
|
||||
|
||||
for(Zone zone : Vars.content.zones()){
|
||||
if(data.isUnlocked(zone)){
|
||||
if(control.saves.getZoneSlot() == null){
|
||||
|
||||
int i = 0;
|
||||
for(Zone zone : content.zones()){
|
||||
table(t -> {
|
||||
t.addButton(zone.localizedName(), () -> {
|
||||
data.removeItems(zone.deployCost);
|
||||
hide();
|
||||
world.playZone(zone);
|
||||
}).size(150f)/*.disabled(b -> !data.hasItems(zone.deployCost))*/;
|
||||
t.row();
|
||||
t.table(req -> {
|
||||
req.left();
|
||||
for(ItemStack stack : zone.deployCost){
|
||||
req.addImage(stack.item.region).size(8*3);
|
||||
req.add(stack.amount + "").left();
|
||||
TextButton button = t.addButton("", () -> {
|
||||
if(!data.isUnlocked(zone)){
|
||||
data.removeItems(zone.itemRequirements);
|
||||
data.unlockContent(zone);
|
||||
setup();
|
||||
}else{
|
||||
data.removeItems(zone.deployCost);
|
||||
hide();
|
||||
world.playZone(zone);
|
||||
}
|
||||
}).pad(3).growX();
|
||||
}).pad(3);
|
||||
}).size(250f).disabled(b -> !canUnlock(zone)).get();
|
||||
|
||||
button.clearChildren();
|
||||
|
||||
if(data.isUnlocked(zone)){
|
||||
button.table(title -> {
|
||||
title.addImage("icon-zone").padRight(3);
|
||||
title.add(zone.localizedName());
|
||||
});
|
||||
button.row();
|
||||
|
||||
if(data.getWaveScore(zone) > 0){
|
||||
button.add(Core.bundle.format("bestwave", data.getWaveScore(zone)));
|
||||
}
|
||||
|
||||
button.row();
|
||||
|
||||
button.add("$launch").color(Color.LIGHT_GRAY).pad(4);
|
||||
button.row();
|
||||
button.table(req -> {
|
||||
for(ItemStack stack : zone.deployCost){
|
||||
req.addImage(stack.item.region).size(8 * 3);
|
||||
req.add(stack.amount + "").left();
|
||||
}
|
||||
}).pad(3).growX();
|
||||
}else{
|
||||
button.addImage("icon-zone-locked");
|
||||
button.row();
|
||||
button.add("$locked").padBottom(6);
|
||||
|
||||
if(!hidden(zone)){
|
||||
button.row();
|
||||
|
||||
button.table(req -> {
|
||||
req.defaults().left();
|
||||
|
||||
if(zone.zoneRequirements.length > 0){
|
||||
req.table(r -> {
|
||||
r.add("$complete").colspan(2).left();
|
||||
r.row();
|
||||
for(Zone other : zone.zoneRequirements){
|
||||
r.addImage("icon-zone").padRight(4);
|
||||
r.add(other.localizedName()).color(Color.LIGHT_GRAY);
|
||||
r.addImage(data.isCompleted(zone) ? "icon-check-2" : "icon-cancel-2")
|
||||
.color(data.isCompleted(zone) ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3);
|
||||
r.row();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
req.row();
|
||||
|
||||
if(zone.itemRequirements.length > 0){
|
||||
req.table(r -> {
|
||||
for(ItemStack stack : zone.itemRequirements){
|
||||
r.addImage(stack.item.region).size(8 * 3).padRight(4);
|
||||
r.add(Math.min(data.getItem(stack.item), stack.amount) + "/" + stack.amount)
|
||||
.color(stack.amount > data.getItem(stack.item) ? Color.SCARLET : Color.LIGHT_GRAY).left();
|
||||
r.row();
|
||||
}
|
||||
}).padTop(10);
|
||||
}
|
||||
|
||||
req.row();
|
||||
|
||||
if(zone.blockRequirements.length > 0){
|
||||
req.table(r -> {
|
||||
r.add("$research.list").colspan(2).left();
|
||||
r.row();
|
||||
for(Block block : zone.blockRequirements){
|
||||
r.addImage(block.icon(Icon.small)).size(8 * 3).padRight(4);
|
||||
r.add(block.formalName).color(Color.LIGHT_GRAY);
|
||||
r.addImage(data.isUnlocked(block) ? "icon-check-2" : "icon-cancel-2")
|
||||
.color(data.isUnlocked(block) ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3);
|
||||
r.row();
|
||||
}
|
||||
|
||||
}).padTop(10);
|
||||
}
|
||||
}).growX();
|
||||
}
|
||||
}
|
||||
}).pad(4);
|
||||
|
||||
if(++i % 2 == 0){
|
||||
row();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
SaveSlot slot = control.saves.getZoneSlot();
|
||||
|
||||
TextButton b[] = {null};
|
||||
|
||||
TextButton button = addButton(Core.bundle.format("resume", slot.getZone().localizedName()), () -> {
|
||||
if(b[0].childrenPressed()) return;
|
||||
|
||||
hide();
|
||||
ui.loadAnd(() -> {
|
||||
try{
|
||||
control.saves.getZoneSlot().load();
|
||||
state.set(State.playing);
|
||||
}catch(SaveException e){ //make sure to handle any save load errors!
|
||||
e.printStackTrace();
|
||||
if(control.saves.getZoneSlot() != null) control.saves.getZoneSlot().delete();
|
||||
ui.showInfo("$save.corrupted");
|
||||
show();
|
||||
}
|
||||
});
|
||||
}).size(200f).get();
|
||||
b[0] = button;
|
||||
|
||||
String color = "[lightgray]";
|
||||
|
||||
button.defaults().colspan(2);
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
|
||||
button.row();
|
||||
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
|
||||
button.row();
|
||||
button.add().grow();
|
||||
button.row();
|
||||
|
||||
button.addButton("$abandon", () -> {
|
||||
ui.showConfirm("$warning", "$abandon.text", () -> {
|
||||
slot.delete();
|
||||
setup();
|
||||
});
|
||||
}).growX().height(50f).pad(-12).padTop(10);
|
||||
}
|
||||
}}).grow();
|
||||
}})).grow();
|
||||
}
|
||||
|
||||
boolean hidden(Zone zone){
|
||||
for(Zone other : zone.zoneRequirements){
|
||||
if(!data.isUnlocked(other)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canUnlock(Zone zone){
|
||||
for(Zone other : zone.zoneRequirements){
|
||||
if(!data.isCompleted(other)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(Block other : zone.blockRequirements){
|
||||
if(!data.isUnlocked(other)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return data.hasItems(zone.itemRequirements);
|
||||
}
|
||||
}
|
||||
|
||||
87
core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java
Normal file
87
core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class GameOverDialog extends FloatingDialog{
|
||||
private Team winner;
|
||||
|
||||
public GameOverDialog(){
|
||||
super("$gameover");
|
||||
setFillParent(false);
|
||||
shown(this::rebuild);
|
||||
}
|
||||
|
||||
public void show(Team winner){
|
||||
this.winner = winner;
|
||||
show();
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
title.setText(state.launched ? "$launch.title" : "$gameover");
|
||||
buttons.clear();
|
||||
cont.clear();
|
||||
|
||||
buttons.margin(10);
|
||||
|
||||
if(state.rules.pvp){
|
||||
cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6);
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}else{
|
||||
if(control.isHighScore()){
|
||||
cont.add("$highscore").pad(6);
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.table(t -> {
|
||||
cont.left().defaults().left();
|
||||
cont.add(Core.bundle.format("stat.wave", state.stats.wavesLasted));
|
||||
cont.row();
|
||||
cont.add(Core.bundle.format("stat.enemiesDestroyed", state.stats.enemyUnitsDestroyed));
|
||||
cont.row();
|
||||
cont.add(Core.bundle.format("stat.built", state.stats.buildingsBuilt));
|
||||
cont.row();
|
||||
cont.add(Core.bundle.format("stat.destroyed", state.stats.buildingsDestroyed));
|
||||
cont.row();
|
||||
cont.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed));
|
||||
cont.row();
|
||||
if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){
|
||||
cont.add("$stat.delivered");
|
||||
cont.row();
|
||||
for(Item item : content.items()){
|
||||
if(state.stats.itemsDelivered.get(item, 0) > 0){
|
||||
cont.table(items -> {
|
||||
items.add(" [LIGHT_GRAY]" + state.stats.itemsDelivered.get(item, 0));
|
||||
items.addImage(item.region).size(8 *3).pad(4);
|
||||
}).left();
|
||||
cont.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
}).pad(12);
|
||||
|
||||
if(world.isZone()){
|
||||
buttons.addButton("$continue", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
ui.deploy.show();
|
||||
}).size(130f, 60f);
|
||||
}else{
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -116,8 +117,6 @@ public class LoadDialog extends FloatingDialog{
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
|
||||
button.row();
|
||||
button.add(Core.bundle.format("save.difficulty", color + slot.getDifficulty()));
|
||||
button.row();
|
||||
button.label(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
|
||||
button.row();
|
||||
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
|
||||
@@ -175,7 +174,7 @@ public class LoadDialog extends FloatingDialog{
|
||||
try{
|
||||
slot.load();
|
||||
state.set(State.playing);
|
||||
}catch(Exception e){
|
||||
}catch(SaveException e){
|
||||
Log.err(e);
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
|
||||
@@ -2,8 +2,6 @@ package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.style.Drawable;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
@@ -12,12 +10,10 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class PausedDialog extends FloatingDialog{
|
||||
private SaveDialog save = new SaveDialog();
|
||||
private LoadDialog load = new LoadDialog();
|
||||
private Table missionTable;
|
||||
|
||||
public PausedDialog(){
|
||||
super("$menu");
|
||||
shouldPause = true;
|
||||
setup();
|
||||
|
||||
shown(this::rebuild);
|
||||
|
||||
@@ -29,20 +25,14 @@ public class PausedDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
missionTable.clear();
|
||||
missionTable.background((Drawable) null);
|
||||
}
|
||||
cont.clear();
|
||||
|
||||
void setup(){
|
||||
update(() -> {
|
||||
if(state.is(State.menu) && isShown()){
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
cont.table(t -> missionTable = t).colspan(mobile ? 3 : 2);
|
||||
cont.row();
|
||||
|
||||
if(!mobile){
|
||||
float dw = 210f;
|
||||
cont.defaults().width(dw).height(50).pad(5f);
|
||||
@@ -50,12 +40,14 @@ public class PausedDialog extends FloatingDialog{
|
||||
cont.addButton("$back", this::hide).colspan(2).width(dw*2 + 20f);
|
||||
|
||||
cont.row();
|
||||
cont.addButton("$unlocks", ui.unlocks::show);
|
||||
cont.addButton("database", ui.database::show);
|
||||
cont.addButton("$settings", ui.settings::show);
|
||||
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
if(!world.isZone()){
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
}
|
||||
|
||||
cont.row();
|
||||
|
||||
@@ -77,11 +69,15 @@ public class PausedDialog extends FloatingDialog{
|
||||
|
||||
cont.addRowImageTextButton("$back", "icon-play-2", isize, this::hide);
|
||||
cont.addRowImageTextButton("$settings", "icon-tools", isize, ui.settings::show);
|
||||
cont.addRowImageTextButton("$save", "icon-save", isize, save::show);
|
||||
|
||||
cont.row();
|
||||
if(!world.isZone()){
|
||||
cont.addRowImageTextButton("$save", "icon-save", isize, save::show);
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> Net.active());
|
||||
}
|
||||
|
||||
cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> Net.active());
|
||||
cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> Net.active());
|
||||
cont.addRowImageTextButton("$quit", "icon-quit", isize, () -> {
|
||||
ui.showConfirm("$confirm", "$quit.confirm", () -> {
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class RestartDialog extends FloatingDialog{
|
||||
private Team winner;
|
||||
|
||||
public RestartDialog(){
|
||||
super("$gameover");
|
||||
setFillParent(false);
|
||||
shown(this::rebuild);
|
||||
}
|
||||
|
||||
public void show(Team winner){
|
||||
this.winner = winner;
|
||||
show();
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
buttons.clear();
|
||||
cont.clear();
|
||||
|
||||
buttons.margin(10);
|
||||
|
||||
if(state.rules.pvp){
|
||||
cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6);
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}else{
|
||||
if(control.isHighScore()){
|
||||
cont.add("$highscore").pad(6);
|
||||
cont.row();
|
||||
}
|
||||
cont.add(Core.bundle.format("wave.lasted", state.wave)).pad(12);
|
||||
|
||||
buttons.addButton("$menu", () -> {
|
||||
hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
}).size(130f, 60f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
if(mobile){
|
||||
game.checkPref("autotarget", true);
|
||||
}
|
||||
game.sliderPref("saveinterval", 120, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
|
||||
game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
|
||||
|
||||
if(!mobile){
|
||||
game.checkPref("crashreport", true);
|
||||
|
||||
284
core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java
Normal file
284
core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java
Normal file
@@ -0,0 +1,284 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.event.InputEvent;
|
||||
import io.anuke.arc.scene.event.InputListener;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.TechTree;
|
||||
import io.anuke.mindustry.content.TechTree.TechNode;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.ui.TreeLayout;
|
||||
import io.anuke.mindustry.ui.TreeLayout.TreeNode;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class TechTreeDialog extends FloatingDialog{
|
||||
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
|
||||
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
|
||||
private static final float nodeSize = 60f;
|
||||
|
||||
public TechTreeDialog(){
|
||||
super("");
|
||||
|
||||
cont.setFillParent(true);
|
||||
|
||||
TreeLayout layout = new TreeLayout();
|
||||
layout.gapBetweenLevels = 60f;
|
||||
layout.gapBetweenNodes = 40f;
|
||||
layout.layout(root);
|
||||
|
||||
cont.add(new View()).grow();
|
||||
|
||||
{ //debug code; TODO remove
|
||||
ObjectSet<Block> used = new ObjectSet<Block>().select(t -> true);
|
||||
for(TechTreeNode node : nodes){
|
||||
used.add(node.node.block);
|
||||
}
|
||||
Array<Block> recipes = content.blocks().select(r -> r.isVisible() && !used.contains(r));
|
||||
recipes.sort(Structs.comparing(r -> r.buildCost));
|
||||
|
||||
if(recipes.size > 0){
|
||||
Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.blocks().select(Block::isVisible).size * 100));
|
||||
Log.info("Missing items: ");
|
||||
recipes.forEach(r -> Log.info(" {0}", r));
|
||||
}
|
||||
}
|
||||
|
||||
shown(() -> checkNodes(root));
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground(float x, float y){
|
||||
drawDefaultBackground(x, y);
|
||||
}
|
||||
|
||||
void checkNodes(TechTreeNode node){
|
||||
boolean locked = locked(node);
|
||||
if(!locked) node.visible = true;
|
||||
for(TreeNode child : node.children){
|
||||
TechTreeNode l = (TechTreeNode)child;
|
||||
l.visible = !locked && l.node.block.isVisible();
|
||||
checkNodes(l);
|
||||
}
|
||||
}
|
||||
|
||||
void showToast(String info){
|
||||
int maxIndex = 0;
|
||||
|
||||
for(Element e : Core.scene.root.getChildren()){
|
||||
if("toast".equals(e.getName())){
|
||||
maxIndex = Math.max(maxIndex, (Integer)e.getUserObject() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int m = maxIndex;
|
||||
|
||||
Table table = new Table();
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
table.top().add(info);
|
||||
table.setName("toast");
|
||||
table.setUserObject(maxIndex);
|
||||
table.update(() -> {
|
||||
table.toFront();
|
||||
table.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight() - 21 - m*20f, Align.top);
|
||||
});
|
||||
Core.scene.add(table);
|
||||
}
|
||||
|
||||
boolean locked(TreeNode node){
|
||||
return locked(((TechTreeNode)node).node);
|
||||
}
|
||||
|
||||
boolean locked(TechNode node){
|
||||
return !data.isUnlocked(node.block);
|
||||
}
|
||||
|
||||
class TechTreeNode extends TreeNode{
|
||||
final TechNode node;
|
||||
boolean visible = true;
|
||||
|
||||
public TechTreeNode(TechNode node, TreeNode parent){
|
||||
this.node = node;
|
||||
this.parent = parent;
|
||||
this.width = this.height = nodeSize;
|
||||
nodes.add(this);
|
||||
if(node.children != null){
|
||||
children = new TechTreeNode[node.children.size];
|
||||
for(int i = 0; i < children.length; i++){
|
||||
children[i] = new TechTreeNode(node.children.get(i), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class View extends Group{
|
||||
float panX = 0, panY = -200;
|
||||
boolean moved = false;
|
||||
Rectangle clip = new Rectangle();
|
||||
ImageButton hoverNode;
|
||||
Table infoTable = new Table();
|
||||
|
||||
{
|
||||
infoTable.touchable(Touchable.enabled);
|
||||
|
||||
for(TechTreeNode node : nodes){
|
||||
ImageButton button = new ImageButton(node.node.block.icon(Icon.medium), "node");
|
||||
button.clicked(() -> {
|
||||
if(mobile){
|
||||
hoverNode = button;
|
||||
rebuild();
|
||||
}else if(data.hasItems(node.node.requirements) && locked(node)){
|
||||
unlock(node.node);
|
||||
}
|
||||
});
|
||||
button.hovered(() -> {
|
||||
if(!mobile && hoverNode != button && node.visible){
|
||||
hoverNode = button;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
button.exited(() -> {
|
||||
if(hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled);
|
||||
button.setUserObject(node.node);
|
||||
button.tapped(() -> moved = false);
|
||||
button.setSize(nodeSize, nodeSize);
|
||||
button.update(() -> {
|
||||
button.setPosition(node.x + panX + width/2f, node.y + panY + height/2f, Align.center);
|
||||
button.getStyle().up = Core.scene.skin.getDrawable(!locked(node) ? "content-background" : "content-background-locked");
|
||||
((TextureRegionDrawable)button.getStyle().imageUp)
|
||||
.setRegion(node.visible ? node.node.block.icon(Icon.medium) : Core.atlas.find("icon-tree-locked"));
|
||||
button.getImage().setColor(!locked(node) ? Color.WHITE : Color.GRAY);
|
||||
});
|
||||
addChild(button);
|
||||
}
|
||||
|
||||
addListener(new InputListener(){
|
||||
float lastX, lastY;
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float mx, float my, int pointer){
|
||||
panX -= lastX - mx;
|
||||
panY -= lastY - my;
|
||||
lastX = mx;
|
||||
lastY = my;
|
||||
moved = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void unlock(TechNode node){
|
||||
data.unlockContent(node.block);
|
||||
data.removeItems(node.requirements);
|
||||
showToast(Core.bundle.format("researched", node.block.formalName));
|
||||
checkNodes(root);
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
ImageButton button = hoverNode;
|
||||
|
||||
infoTable.remove();
|
||||
infoTable.clear();
|
||||
infoTable.update(null);
|
||||
|
||||
if(button == null) return;
|
||||
|
||||
TechNode node = (TechNode)button.getUserObject();
|
||||
|
||||
infoTable.exited(() -> {
|
||||
if(hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
|
||||
hoverNode = null;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
|
||||
infoTable.background("content-background");
|
||||
infoTable.update(() -> infoTable.setPosition(button.getX() + button.getWidth(), button.getY() + button.getHeight(), Align.topLeft));
|
||||
|
||||
infoTable.margin(0).left().defaults().left();
|
||||
|
||||
infoTable.addImageButton("icon-info", "node", 14*2, () -> ui.content.show(node.block)).growY().width(50f);
|
||||
|
||||
infoTable.add().grow();
|
||||
|
||||
infoTable.table(desc -> {
|
||||
desc.left().defaults().left();
|
||||
desc.add(node.block.formalName);
|
||||
desc.row();
|
||||
if(locked(node)){
|
||||
desc.table(t -> {
|
||||
t.left();
|
||||
for(ItemStack req : node.requirements){
|
||||
t.table(list -> {
|
||||
list.left();
|
||||
list.addImage(req.item.getContentIcon()).size(8 * 3).padRight(3);
|
||||
list.add(req.item.localizedName()).color(Color.LIGHT_GRAY);
|
||||
list.add(" " + Math.min(data.items().get(req.item, 0), req.amount) + " / " + req.amount)
|
||||
.color(data.has(req.item, req.amount) ? Color.LIGHT_GRAY : Color.SCARLET);
|
||||
}).fillX().left();
|
||||
t.row();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
desc.add("$completed");
|
||||
}
|
||||
}).pad(9);
|
||||
|
||||
if(mobile && locked(node)){
|
||||
infoTable.row();
|
||||
infoTable.addImageTextButton("$research", "icon-check", "node", 16*2, () -> unlock(node))
|
||||
.disabled(b -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
|
||||
}
|
||||
|
||||
addChild(infoTable);
|
||||
infoTable.pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float offsetX = panX + width/2f + x, offsetY = panY + height/2f + y;
|
||||
|
||||
for(TreeNode node : nodes){
|
||||
for(TreeNode child : node.children){
|
||||
Lines.stroke(3f, locked(node) || locked(child) ? Palette.locked : Palette.accent);
|
||||
|
||||
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.consumers.Consume;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class BlockConsumeFragment extends Fragment{
|
||||
private Table table;
|
||||
private Tile lastTile;
|
||||
private boolean visible;
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
table = new Table();
|
||||
table.visible(() -> !state.is(State.menu) && visible);
|
||||
table.setTransform(true);
|
||||
|
||||
parent.addChild(new Element(){{update(() -> {
|
||||
if(!Core.scene.hasMouse()){
|
||||
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(tile == null) return;
|
||||
tile = tile.target();
|
||||
|
||||
if(tile != lastTile){
|
||||
if(tile.getTeam() == players[0].getTeam() && tile.block().consumes.hasAny()){
|
||||
show(tile);
|
||||
}else if(visible){
|
||||
hide();
|
||||
}
|
||||
lastTile = tile;
|
||||
}
|
||||
}
|
||||
});}});
|
||||
|
||||
parent.setTransform(true);
|
||||
parent.addChild(table);
|
||||
}
|
||||
|
||||
public void show(Tile tile){
|
||||
ObjectSet<Consume> consumers = new ObjectSet<>();
|
||||
TileEntity entity = tile.entity;
|
||||
Block block = tile.block();
|
||||
|
||||
table.clearChildren();
|
||||
|
||||
rebuild(block, entity);
|
||||
visible = true;
|
||||
|
||||
table.update(() -> {
|
||||
|
||||
if(tile.entity == null || state.is(State.menu)){
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean rebuild = false;
|
||||
|
||||
for(Consume c : block.consumes.array()){
|
||||
boolean valid = c.isOptional() || c.valid(block, entity);
|
||||
|
||||
if(consumers.contains(c) == valid){
|
||||
if(valid){
|
||||
consumers.remove(c);
|
||||
}else{
|
||||
consumers.add(c);
|
||||
}
|
||||
rebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(rebuild){
|
||||
rebuild(block, entity);
|
||||
}
|
||||
|
||||
Vector2 v = Core.input.mouseScreen(tile.drawx() - tile.block().size * tilesize / 2f + 0.25f, tile.drawy() + tile.block().size * tilesize / 2f);
|
||||
table.pack();
|
||||
table.setPosition(v.x, v.y, Align.topRight);
|
||||
});
|
||||
|
||||
table.act(Core.graphics.getDeltaTime());
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
table.clear();
|
||||
table.update(() -> {});
|
||||
visible = false;
|
||||
}
|
||||
|
||||
private void rebuild(Block block, TileEntity entity){
|
||||
table.clearChildren();
|
||||
table.left();
|
||||
|
||||
int scale = mobile ? 4 : 3;
|
||||
|
||||
for(Consume c : block.consumes.array()){
|
||||
if(!c.isOptional() && !c.valid(block, entity)){
|
||||
boolean[] hovered = {false};
|
||||
|
||||
table.table("inventory", c::buildTooltip).visible(() -> hovered[0]).height(scale * 10 + 6).padBottom(-4).right().update(t -> {
|
||||
if(t.getChildren().size == 0) t.remove();
|
||||
}).get().act(0);
|
||||
|
||||
Table result = table.table(out -> {
|
||||
out.addImage(c.getIcon()).size(10 * scale).color(Color.DARK_GRAY).padRight(-10 * scale).padBottom(-scale * 2);
|
||||
out.addImage(c.getIcon()).size(10 * scale).color(Palette.accent);
|
||||
out.addImage("icon-missing").size(10 * scale).color(Palette.remove).padLeft(-10 * scale);
|
||||
}).size(10 * scale).get();
|
||||
|
||||
result.hovered(() -> hovered[0] = true);
|
||||
if(!mobile){
|
||||
result.exited(() -> hovered[0] = false);
|
||||
}
|
||||
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.Element;
|
||||
@@ -13,7 +12,6 @@ import io.anuke.arc.scene.actions.Actions;
|
||||
import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.Image;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.scene.ui.Label;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Stack;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
@@ -24,12 +22,12 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Packets.AdminAction;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.IntFormat;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
|
||||
@@ -76,7 +74,7 @@ public class HudFragment extends Fragment{
|
||||
if(Net.active()){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-players");
|
||||
}else{
|
||||
i.setDisabled(Net.active());
|
||||
i.setDisabled(false);
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause");
|
||||
}
|
||||
}).get();
|
||||
@@ -89,7 +87,7 @@ public class HudFragment extends Fragment{
|
||||
ui.chatfrag.toggle();
|
||||
}
|
||||
}else{
|
||||
ui.unlocks.show();
|
||||
ui.database.show();
|
||||
}
|
||||
}).update(i -> {
|
||||
if(Net.active() && mobile){
|
||||
@@ -131,7 +129,6 @@ public class HudFragment extends Fragment{
|
||||
//fps display
|
||||
infolabel = cont.table(t -> {
|
||||
IntFormat fps = new IntFormat("fps");
|
||||
IntFormat tps = new IntFormat("tps");
|
||||
IntFormat ping = new IntFormat("ping");
|
||||
t.label(() -> fps.get(Core.graphics.getFramesPerSecond())).padRight(10);
|
||||
t.row();
|
||||
@@ -199,6 +196,9 @@ public class HudFragment extends Fragment{
|
||||
.update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f))));
|
||||
});
|
||||
|
||||
parent.fill(t -> t.top().right().addRowImageTextButton("$launch", "icon-arrow-up", 8*3, () -> world.launchZone())
|
||||
.size(94f, 70f).visible(() -> world.isZone() && world.getZone().metCondition()));
|
||||
|
||||
//'saving' indicator
|
||||
parent.fill(t -> {
|
||||
t.bottom().visible(() -> !state.is(State.menu) && control.saves.isSaving());
|
||||
@@ -230,7 +230,9 @@ public class HudFragment extends Fragment{
|
||||
}
|
||||
|
||||
/** Show unlock notification for a new recipe. */
|
||||
public void showUnlock(Recipe recipe){
|
||||
public void showUnlock(UnlockableContent content){
|
||||
//some content may not have icons... yet
|
||||
if(content.getContentIcon() == null) return;
|
||||
|
||||
//if there's currently no unlock notification...
|
||||
if(lastUnlockTable == null){
|
||||
@@ -247,14 +249,10 @@ public class HudFragment extends Fragment{
|
||||
Table in = new Table();
|
||||
|
||||
//create texture stack for displaying
|
||||
Stack stack = new Stack();
|
||||
for(TextureRegion region : recipe.result.getCompactIcon()){
|
||||
Image image = new Image(region);
|
||||
image.setScaling(Scaling.fit);
|
||||
stack.add(image);
|
||||
}
|
||||
Image image = new Image(content.getContentIcon());
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
in.add(stack).size(48f).pad(2);
|
||||
in.add(image).size(48f).pad(2);
|
||||
|
||||
//add to table
|
||||
table.add(in).padRight(8);
|
||||
@@ -290,11 +288,6 @@ public class HudFragment extends Fragment{
|
||||
//get size of each element
|
||||
float size = 48f / Math.min(elements.size + 1, col);
|
||||
|
||||
//correct plurals if needed
|
||||
if(esize == 1){
|
||||
((Label) lastUnlockLayout.getParent().find(e -> e instanceof Label)).setText("$unlocked.plural");
|
||||
}
|
||||
|
||||
lastUnlockLayout.clearChildren();
|
||||
lastUnlockLayout.defaults().size(size).pad(2);
|
||||
|
||||
@@ -309,14 +302,10 @@ public class HudFragment extends Fragment{
|
||||
//if there's space, add it
|
||||
if(esize < cap){
|
||||
|
||||
Stack stack = new Stack();
|
||||
for(TextureRegion region : recipe.result.getCompactIcon()){
|
||||
Image image = new Image(region);
|
||||
image.setScaling(Scaling.fit);
|
||||
stack.add(image);
|
||||
}
|
||||
Image image = new Image(content.getContentIcon());
|
||||
image.setScaling(Scaling.fit);
|
||||
|
||||
lastUnlockLayout.add(stack);
|
||||
lastUnlockLayout.add(image);
|
||||
}else{ //else, add a specific icon to denote no more space
|
||||
lastUnlockLayout.addImage("icon-add");
|
||||
}
|
||||
@@ -364,20 +353,32 @@ public class HudFragment extends Fragment{
|
||||
IntFormat wavef = new IntFormat("wave");
|
||||
IntFormat enemyf = new IntFormat("wave.enemy");
|
||||
IntFormat enemiesf = new IntFormat("wave.enemies");
|
||||
IntFormat waitingf = new IntFormat("wave.waiting");
|
||||
|
||||
table.clearChildren();
|
||||
table.touchable(Touchable.enabled);
|
||||
|
||||
table.labelWrap(() ->
|
||||
(state.enemies() > 0 && !state.rules.waveTimer ?
|
||||
wavef.get(state.wave) + "\n" + (state.enemies() == 1 ?
|
||||
enemyf.get(state.enemies()) :
|
||||
enemiesf.get(state.enemies())) :
|
||||
wavef.get(state.wave) + "\n" +
|
||||
(state.rules.waveTimer ?
|
||||
Core.bundle.format("wave.waiting", (int)(state.wavetime/60)) :
|
||||
Core.bundle.get("waiting")))
|
||||
).growX().pad(8f);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
table.labelWrap(() -> {
|
||||
builder.setLength(0);
|
||||
builder.append(wavef.get(state.wave));
|
||||
builder.append("\n");
|
||||
|
||||
if(state.enemies() > 0 && !state.rules.waveTimer){
|
||||
if(state.enemies() == 1){
|
||||
builder.append(enemyf.get(state.enemies()));
|
||||
}else{
|
||||
builder.append(enemiesf.get(state.enemies()));
|
||||
}
|
||||
}else if(state.rules.waveTimer){
|
||||
builder.append(waitingf.get((int)(state.wavetime/60)));
|
||||
}else{
|
||||
builder.append(Core.bundle.get("waiting"));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}).growX().pad(8f);
|
||||
|
||||
table.setDisabled(true);
|
||||
table.visible(() -> state.rules.waves);
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MenuFragment extends Fragment{
|
||||
join = new MobileButton("icon-add", isize, "$joingame", ui.join::show),
|
||||
editor = new MobileButton("icon-editor", isize, "$editor", () -> ui.loadAnd(ui.editor::show)),
|
||||
tools = new MobileButton("icon-tools", isize, "$settings", ui.settings::show),
|
||||
unlocks = new MobileButton("icon-unlocks", isize, "$unlocks", ui.unlocks::show),
|
||||
unlocks = new MobileButton("icon-unlocks", isize, "database", ui.database::show),
|
||||
donate = new MobileButton("icon-donate", isize, "$donate", Platform.instance::openDonations);
|
||||
|
||||
if(Core.graphics.getWidth() > Core.graphics.getHeight()){
|
||||
@@ -127,12 +127,6 @@ public class MenuFragment extends Fragment{
|
||||
|
||||
out.row();
|
||||
|
||||
out.add(new MenuButton("icon-menu", "$changelog.title", ui.changelog::show));
|
||||
|
||||
out.add(new MenuButton("icon-unlocks", "$unlocks", ui.unlocks::show));
|
||||
|
||||
out.row();
|
||||
|
||||
out.add(new MenuButton("icon-exit", "$quit", Core.app::exit)).width(bw).colspan(2);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,20 +3,16 @@ package io.anuke.mindustry.ui.fragments;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.arc.scene.Group;
|
||||
|
||||
/**
|
||||
* Fragment for displaying overlays such as block inventories. One is created for each input handler.
|
||||
*/
|
||||
/**Fragment for displaying overlays such as block inventories. One is created for each input handler.*/
|
||||
public class OverlayFragment extends Fragment{
|
||||
public final BlockInventoryFragment inv;
|
||||
public final BlockConfigFragment config;
|
||||
public final BlockConsumeFragment consume;
|
||||
|
||||
private Group group = new Group();
|
||||
|
||||
public OverlayFragment(InputHandler input){
|
||||
inv = new BlockInventoryFragment(input);
|
||||
config = new BlockConfigFragment(input);
|
||||
consume = new BlockConsumeFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -26,9 +22,6 @@ public class OverlayFragment extends Fragment{
|
||||
|
||||
inv.build(group);
|
||||
config.build(group);
|
||||
consume.build(group);
|
||||
|
||||
//input.buildUI(group);
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
|
||||
@@ -22,9 +22,8 @@ import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.type.Category;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.ImageStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
|
||||
@@ -33,8 +32,10 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class PlacementFragment extends Fragment{
|
||||
final int rowWidth = 4;
|
||||
|
||||
Category currentCategory = Category.turret;
|
||||
Array<Block> returnArray = new Array<>();
|
||||
Category currentCategory = Category.distribution;
|
||||
Block hovered, lastDisplay;
|
||||
Tile lastHover;
|
||||
Tile hoverTile;
|
||||
Table blockTable, toggler, topTable;
|
||||
boolean shown = true;
|
||||
@@ -68,8 +69,8 @@ public class PlacementFragment extends Fragment{
|
||||
int i = 0;
|
||||
for(KeyCode key : inputCatGrid){
|
||||
if(Core.input.keyDown(key)){
|
||||
input.recipe = Recipe.getByCategory(Category.values()[i]).first();
|
||||
currentCategory = input.recipe.category;
|
||||
input.block = getByCategory(Category.values()[i]).first();
|
||||
currentCategory = input.block.buildCategory;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -79,19 +80,19 @@ public class PlacementFragment extends Fragment{
|
||||
|
||||
if(tile != null){
|
||||
tile = tile.target();
|
||||
Recipe tryRecipe = Recipe.getByResult(tile.block());
|
||||
if(tryRecipe != null && data.isUnlocked(tryRecipe)){
|
||||
input.recipe = tryRecipe;
|
||||
currentCategory = input.recipe.category;
|
||||
Block tryRecipe = tile.block();
|
||||
if(tryRecipe.isVisible() && data.isUnlocked(tryRecipe)){
|
||||
input.block = tryRecipe;
|
||||
currentCategory = input.block.buildCategory;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else{ //select block
|
||||
int i = 0;
|
||||
Array<Recipe> recipes = Recipe.getByCategory(currentCategory);
|
||||
Array<Block> recipes = getByCategory(currentCategory);
|
||||
for(KeyCode key : inputGrid){
|
||||
if(Core.input.keyDown(key))
|
||||
input.recipe = (i < recipes.size && data.isUnlocked(recipes.get(i))) ? recipes.get(i) : null;
|
||||
input.block = (i < recipes.size && data.isUnlocked(recipes.get(i))) ? recipes.get(i) : null;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +118,7 @@ public class PlacementFragment extends Fragment{
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
group.setMinCheckCount(0);
|
||||
|
||||
for(Recipe recipe : Recipe.getByCategory(currentCategory)){
|
||||
for(Block block : getByCategory(currentCategory)){
|
||||
|
||||
if(index++ % rowWidth == 0){
|
||||
blockTable.row();
|
||||
@@ -126,17 +127,17 @@ public class PlacementFragment extends Fragment{
|
||||
boolean[] unlocked = {false};
|
||||
|
||||
ImageButton button = blockTable.addImageButton("icon-locked", "select", 8 * 4, () -> {
|
||||
if(data.isUnlocked(recipe)){
|
||||
input.recipe = input.recipe == recipe ? null : recipe;
|
||||
if(data.isUnlocked(block)){
|
||||
input.block = input.block == block ? null : block;
|
||||
}
|
||||
}).size(46f).group(group).get();
|
||||
|
||||
button.update(() -> { //color unplacable things gray
|
||||
boolean ulock = data.isUnlocked(recipe);
|
||||
boolean ulock = data.isUnlocked(block);
|
||||
TileEntity core = players[0].getClosestCore();
|
||||
Color color = core != null && (core.items.has(recipe.requirements) || state.rules.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE;
|
||||
Color color = core != null && (core.items.has(block.buildRequirements) || state.rules.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE;
|
||||
button.forEach(elem -> elem.setColor(color));
|
||||
button.setChecked(input.recipe == recipe);
|
||||
button.setChecked(input.block == block);
|
||||
|
||||
if(ulock == unlocked[0]) return;
|
||||
unlocked[0] = ulock;
|
||||
@@ -144,13 +145,13 @@ public class PlacementFragment extends Fragment{
|
||||
if(!ulock){
|
||||
button.replaceImage(new Image("icon-locked"));
|
||||
}else{
|
||||
button.replaceImage(new ImageStack(recipe.result.getCompactIcon()));
|
||||
button.replaceImage(new Image(block.icon(Icon.medium)));
|
||||
}
|
||||
});
|
||||
|
||||
button.hovered(() -> hovered = recipe.result);
|
||||
button.hovered(() -> hovered = block);
|
||||
button.exited(() -> {
|
||||
if(hovered == recipe.result){
|
||||
if(hovered == block){
|
||||
hovered = null;
|
||||
}
|
||||
});
|
||||
@@ -162,25 +163,29 @@ public class PlacementFragment extends Fragment{
|
||||
frame.table("button-edge-2", top -> {
|
||||
topTable = top;
|
||||
top.add(new Table()).growX().update(topTable -> {
|
||||
if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround) || (tileDisplayBlock() != null && lastDisplay == tileDisplayBlock() && lastGround))
|
||||
//don't refresh unnecessarily
|
||||
if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround)
|
||||
|| (tileDisplayBlock() != null && lastHover == hoverTile && lastGround))
|
||||
return;
|
||||
|
||||
topTable.clear();
|
||||
topTable.top().left().margin(5);
|
||||
|
||||
lastHover = hoverTile;
|
||||
lastDisplay = getSelected();
|
||||
lastGround = tileDisplayBlock() != null;
|
||||
|
||||
if(lastDisplay != null){ //show selected recipe
|
||||
lastGround = false;
|
||||
|
||||
topTable.table(header -> {
|
||||
header.left();
|
||||
header.add(new ImageStack(lastDisplay.getCompactIcon())).size(8 * 4);
|
||||
header.labelWrap(() ->
|
||||
!data.isUnlocked(Recipe.getByResult(lastDisplay)) ? Core.bundle.get("blocks.unknown") : lastDisplay.formalName)
|
||||
header.add(new Image(lastDisplay.icon(Icon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !data.isUnlocked(lastDisplay) ? Core.bundle.get("blocks.unknown") : lastDisplay.formalName)
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(data.isUnlocked(Recipe.getByResult(lastDisplay))){
|
||||
header.addButton("?", "clear-partial", () -> ui.content.show(Recipe.getByResult(lastDisplay)))
|
||||
if(data.isUnlocked(lastDisplay)){
|
||||
header.addButton("?", "clear-partial", () -> ui.content.show(lastDisplay))
|
||||
.size(8 * 5).padTop(-5).padRight(-5).right().grow();
|
||||
}
|
||||
}).growX().left();
|
||||
@@ -189,7 +194,7 @@ public class PlacementFragment extends Fragment{
|
||||
topTable.table(req -> {
|
||||
req.top().left();
|
||||
|
||||
for(ItemStack stack : Recipe.getByResult(lastDisplay).requirements){
|
||||
for(ItemStack stack : lastDisplay.buildRequirements){
|
||||
req.table(line -> {
|
||||
line.left();
|
||||
line.addImage(stack.item.region).size(8 * 2);
|
||||
@@ -210,8 +215,18 @@ public class PlacementFragment extends Fragment{
|
||||
|
||||
}else if(tileDisplayBlock() != null){ //show selected tile
|
||||
lastDisplay = tileDisplayBlock();
|
||||
topTable.add(new ImageStack(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4);
|
||||
topTable.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5);
|
||||
topTable.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4);
|
||||
t.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
if(hoverTile.getTeam() == players[0].getTeam()){
|
||||
topTable.row();
|
||||
topTable.table(t -> {
|
||||
t.left().defaults().left();
|
||||
lastDisplay.display(hoverTile, t);
|
||||
}).left().growX();
|
||||
}
|
||||
}
|
||||
});
|
||||
}).colspan(3).fillX().visible(() -> getSelected() != null || tileDisplayBlock() != null).touchable(Touchable.enabled);
|
||||
@@ -230,7 +245,7 @@ public class PlacementFragment extends Fragment{
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
for(Category cat : Category.values()){
|
||||
if(Recipe.getByCategory(cat).isEmpty()) continue;
|
||||
if(getByCategory(cat).isEmpty()) continue;
|
||||
|
||||
categories.addImageButton("icon-" + cat.name(), "clear-toggle", 16 * 2, () -> {
|
||||
currentCategory = cat;
|
||||
@@ -248,6 +263,16 @@ public class PlacementFragment extends Fragment{
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Array<Block> getByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.buildCategory == cat && block.isVisible()){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
/** Returns the currently displayed block in the top box. */
|
||||
Block getSelected(){
|
||||
@@ -268,8 +293,8 @@ public class PlacementFragment extends Fragment{
|
||||
}
|
||||
|
||||
//block currently selected
|
||||
if(control.input(0).recipe != null){
|
||||
toDisplay = control.input(0).recipe.result;
|
||||
if(control.input(0).block != null){
|
||||
toDisplay = control.input(0).block;
|
||||
}
|
||||
|
||||
//block hovered on in build menu
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.anuke.arc.Graphics.Cursor.SystemCursor;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.EnumSet;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.function.BooleanProvider;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
@@ -20,20 +21,27 @@ import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.effect.Puddle;
|
||||
import io.anuke.mindustry.entities.effect.RubbleDecal;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.graphics.CacheLayer;
|
||||
import io.anuke.mindustry.graphics.Layer;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.Category;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.ui.Bar;
|
||||
import io.anuke.mindustry.ui.ContentDisplay;
|
||||
import io.anuke.mindustry.world.consumers.ConsumePower;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.StatUnit;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Block extends BaseBlock {
|
||||
public class Block extends BlockStorage{
|
||||
/** internal name */
|
||||
public final String name;
|
||||
/** display name */
|
||||
@@ -58,10 +66,8 @@ public class Block extends BaseBlock {
|
||||
public int health = -1;
|
||||
/** base block explosiveness */
|
||||
public float baseExplosiveness = 0f;
|
||||
/** whether this block can be placed on liquids. */
|
||||
/** whether this block can be placed on edges of liquids. */
|
||||
public boolean floating = false;
|
||||
/** stuff that drops when broken */
|
||||
public ItemStack drops = null;
|
||||
/** multiblock size */
|
||||
public int size = 1;
|
||||
/** Whether to draw this block in the expanded draw range. */
|
||||
@@ -80,34 +86,33 @@ public class Block extends BaseBlock {
|
||||
public boolean instantTransfer = false;
|
||||
/** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */
|
||||
public BlockGroup group = BlockGroup.none;
|
||||
/** List of block stats. */
|
||||
public BlockStats stats = new BlockStats(this);
|
||||
/** List of block flags. Used for AI indexing. */
|
||||
public EnumSet<BlockFlag> flags;
|
||||
/** Whether to automatically set the entity to 'sleeping' when created. */
|
||||
public boolean autoSleep;
|
||||
/** Whether the block can be tapped and selected to configure. */
|
||||
public boolean configurable;
|
||||
/** Whether this block consumes touchDown events when tapped. */
|
||||
public boolean consumesTap;
|
||||
/** The color of this block when displayed on the minimap or map preview. */
|
||||
public Color minimapColor = Color.CLEAR;
|
||||
/** View range of this block type. Use a value < 0 to disable. */
|
||||
public float viewRange = 10;
|
||||
/**Whether the top icon is outlined, like a turret.*/
|
||||
public boolean turretIcon = false;
|
||||
/**Whether units target this block.*/
|
||||
public boolean targetable = true;
|
||||
/**Whether the overdrive core has any effect on this block.*/
|
||||
public boolean canOverdrive = true;
|
||||
|
||||
protected Array<Tile> tempTiles = new Array<>();
|
||||
protected TextureRegion[] blockIcon;
|
||||
protected TextureRegion[] icon;
|
||||
protected TextureRegion[] compactIcon;
|
||||
protected TextureRegion editorIcon;
|
||||
/**Cost of constructing this block.*/
|
||||
public ItemStack[] buildRequirements = new ItemStack[]{};
|
||||
/**Category in place menu.*/
|
||||
public Category buildCategory = Category.distribution;
|
||||
/**Cost of building this block; do not modify directly!*/
|
||||
public float buildCost;
|
||||
/**Whether this block is visible and can currently be built.*/
|
||||
public BooleanProvider buildVisibility = () -> false;
|
||||
public boolean alwaysUnlocked = false;
|
||||
|
||||
public TextureRegion region;
|
||||
protected Array<Tile> tempTiles = new Array<>();
|
||||
protected TextureRegion[] icons = new TextureRegion[Icon.values().length];
|
||||
protected TextureRegion[] generatedIcons;
|
||||
protected TextureRegion region;
|
||||
|
||||
public Block(String name){
|
||||
this.name = name;
|
||||
@@ -116,24 +121,10 @@ public class Block extends BaseBlock {
|
||||
this.solid = false;
|
||||
}
|
||||
|
||||
/**Populates the array with all blocks that produce this content.*/
|
||||
public static void getByProduction(Array<Block> arr, Content result){
|
||||
arr.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.produces.get() == result){
|
||||
arr.add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBreak(Tile tile){
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean dropsItem(Item item){
|
||||
return drops != null && drops.item == item;
|
||||
}
|
||||
|
||||
public void onProximityRemoved(Tile tile){
|
||||
if(tile.entity.power != null){
|
||||
tile.block().powerGraphRemoved(tile);
|
||||
@@ -210,6 +201,14 @@ public class Block extends BaseBlock {
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
}
|
||||
|
||||
public void draw(Tile tile){
|
||||
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0);
|
||||
}
|
||||
|
||||
public void drawShadow(Tile tile){
|
||||
draw(tile);
|
||||
}
|
||||
|
||||
/** Called after the block is placed by this client. */
|
||||
public void playerPlaced(Tile tile){
|
||||
}
|
||||
@@ -237,6 +236,21 @@ public class Block extends BaseBlock {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String localizedName(){
|
||||
return formalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getContentIcon(){
|
||||
return icon(Icon.medium);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayBlock(table, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.block;
|
||||
@@ -255,6 +269,11 @@ public class Block extends BaseBlock {
|
||||
health = size * size * 40;
|
||||
}
|
||||
|
||||
buildCost = 0f;
|
||||
for(ItemStack stack : buildRequirements){
|
||||
buildCost += stack.amount * stack.item.cost;
|
||||
}
|
||||
|
||||
setStats();
|
||||
|
||||
consumes.checkRequired(this);
|
||||
@@ -314,7 +333,7 @@ public class Block extends BaseBlock {
|
||||
}
|
||||
|
||||
public boolean synthetic(){
|
||||
return update || destructible || solid;
|
||||
return update || destructible;
|
||||
}
|
||||
|
||||
public void drawConfigure(Tile tile){
|
||||
@@ -335,10 +354,6 @@ public class Block extends BaseBlock {
|
||||
if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items);
|
||||
}
|
||||
|
||||
public String name(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isSolidFor(Tile tile){
|
||||
return false;
|
||||
}
|
||||
@@ -445,55 +460,51 @@ public class Block extends BaseBlock {
|
||||
}
|
||||
|
||||
public TextureRegion getDisplayIcon(Tile tile){
|
||||
return getEditorIcon();
|
||||
return icon(Icon.medium);
|
||||
}
|
||||
|
||||
public TextureRegion getEditorIcon(){
|
||||
if(editorIcon == null){
|
||||
editorIcon = Core.atlas.find("block-icon-" + name, Core.atlas.find("clear"));
|
||||
public void display(Tile tile, Table table){
|
||||
TileEntity entity = tile.entity;
|
||||
|
||||
if(entity != null){
|
||||
table.table(bars -> {
|
||||
bars.defaults().growX().height(18f).pad(4);
|
||||
|
||||
displayBars(tile, bars);
|
||||
}).growX();
|
||||
|
||||
table.marginBottom(-5);
|
||||
}
|
||||
return editorIcon;
|
||||
}
|
||||
|
||||
/** Returns the icon used for displaying this block in the place menu */
|
||||
public TextureRegion[] getIcon(){
|
||||
if(icon == null){
|
||||
if(Core.atlas.has(name + "-icon")){
|
||||
icon = new TextureRegion[]{Core.atlas.find(name + "-icon")};
|
||||
}else if(Core.atlas.has(name)){
|
||||
icon = new TextureRegion[]{Core.atlas.find(name)};
|
||||
}else if(Core.atlas.has(name + "1")){
|
||||
icon = new TextureRegion[]{Core.atlas.find(name + "1")};
|
||||
}else{
|
||||
icon = new TextureRegion[]{};
|
||||
}
|
||||
public void displayBars(Tile tile, Table bars){
|
||||
TileEntity entity = tile.entity;
|
||||
|
||||
bars.add(new Bar("blocks.health", Palette.health, entity::healthf).blink(Color.WHITE));
|
||||
bars.row();
|
||||
|
||||
if(entity.liquids != null){
|
||||
bars.add(new Bar(() -> entity.liquids.current().localizedName(), () -> entity.liquids.current().color, () -> entity.liquids.total() / liquidCapacity)).growX();
|
||||
bars.row();
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/** Returns a list of regions that represent this block in the world */
|
||||
public TextureRegion[] getBlockIcon(){
|
||||
return getIcon();
|
||||
}
|
||||
|
||||
/** Returns a list of icon regions that have been cropped to 8x8 */
|
||||
public TextureRegion[] getCompactIcon(){
|
||||
if(compactIcon == null){
|
||||
compactIcon = new TextureRegion[getIcon().length];
|
||||
for(int i = 0; i < compactIcon.length; i++){
|
||||
compactIcon[i] = iconRegion(getIcon()[i]);
|
||||
}
|
||||
public TextureRegion icon(Icon icon){
|
||||
if(icons[icon.ordinal()] == null){
|
||||
icons[icon.ordinal()] = Core.atlas.find(name + "-icon-" + icon.name());
|
||||
}
|
||||
return compactIcon;
|
||||
return icons[icon.ordinal()];
|
||||
}
|
||||
|
||||
/** Crops a regionto 8x8 */
|
||||
protected TextureRegion iconRegion(TextureRegion src){
|
||||
TextureRegion region = new TextureRegion(src);
|
||||
region.setWidth((int)(8 / Draw.scl));
|
||||
region.setHeight((int)(8 / Draw.scl));
|
||||
return region;
|
||||
protected TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name)};
|
||||
}
|
||||
|
||||
public TextureRegion[] getGeneratedIcons(){
|
||||
if(generatedIcons == null){
|
||||
generatedIcons = generateIcons();
|
||||
}
|
||||
return generatedIcons;
|
||||
}
|
||||
|
||||
public boolean hasEntity(){
|
||||
@@ -504,14 +515,6 @@ public class Block extends BaseBlock {
|
||||
return new TileEntity();
|
||||
}
|
||||
|
||||
public void draw(Tile tile){
|
||||
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0);
|
||||
}
|
||||
|
||||
public void drawShadow(Tile tile){
|
||||
draw(tile);
|
||||
}
|
||||
|
||||
/** Offset for placing and drawing multiblocks. */
|
||||
public float offset(){
|
||||
return ((size + 1) % 2) * tilesize / 2f;
|
||||
@@ -521,18 +524,44 @@ public class Block extends BaseBlock {
|
||||
return size > 1;
|
||||
}
|
||||
|
||||
public Array<Object> getDebugInfo(Tile tile){
|
||||
return Array.with(
|
||||
"block", tile.block().name,
|
||||
"floor", tile.floor().name,
|
||||
"x", tile.x,
|
||||
"y", tile.y,
|
||||
"entity.name", tile.entity.getClass(),
|
||||
"entity.x", tile.entity.x,
|
||||
"entity.y", tile.entity.y,
|
||||
"entity.id", tile.entity.id,
|
||||
"entity.items.total", hasItems ? tile.entity.items.total() : null,
|
||||
"entity.graph", tile.entity.power != null && tile.entity.power.graph != null ? tile.entity.power.graph.getID() : null
|
||||
);
|
||||
public boolean isVisible(){
|
||||
return buildVisibility.get() && !isHidden();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysUnlocked(){
|
||||
return alwaysUnlocked;
|
||||
}
|
||||
|
||||
protected void requirements(Category cat, ItemStack[] stacks, boolean unlocked){
|
||||
requirements(cat, () -> true, stacks);
|
||||
this.alwaysUnlocked = unlocked;
|
||||
}
|
||||
|
||||
protected void requirements(Category cat, ItemStack[] stacks){
|
||||
requirements(cat, () -> true, stacks);
|
||||
}
|
||||
|
||||
/**Sets up requirements. Use only this method to set up requirements.*/
|
||||
protected void requirements(Category cat, BooleanProvider visible, ItemStack[] stacks){
|
||||
this.buildCategory = cat;
|
||||
this.buildRequirements = stacks;
|
||||
this.buildVisibility = visible;
|
||||
|
||||
Arrays.sort(buildRequirements, (a, b) -> Integer.compare(a.item.id, b.item.id));
|
||||
}
|
||||
|
||||
public enum Icon{
|
||||
small(8 * 3),
|
||||
medium(8 * 4),
|
||||
large(8 * 6),
|
||||
/**uses whatever the size of the block is*/
|
||||
full(0);
|
||||
|
||||
public final int size;
|
||||
|
||||
Icon(int size){
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,16 @@ import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.effect.Puddle;
|
||||
import io.anuke.mindustry.game.MappableContent;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.consumers.ConsumeItem;
|
||||
import io.anuke.mindustry.world.consumers.ConsumeLiquid;
|
||||
import io.anuke.mindustry.world.consumers.Consumers;
|
||||
import io.anuke.mindustry.world.meta.BlockStats;
|
||||
import io.anuke.mindustry.world.meta.Producers;
|
||||
|
||||
public abstract class BaseBlock extends MappableContent{
|
||||
public abstract class BlockStorage extends UnlockableContent{
|
||||
public boolean hasItems;
|
||||
public boolean hasLiquids;
|
||||
public boolean hasPower;
|
||||
@@ -32,6 +33,7 @@ public abstract class BaseBlock extends MappableContent{
|
||||
public float liquidCapacity = 10f;
|
||||
public float liquidFlowFactor = 4.9f;
|
||||
|
||||
public BlockStats stats = new BlockStats();
|
||||
public Consumers consumes = new Consumers();
|
||||
public Producers produces = new Producers();
|
||||
|
||||
@@ -269,4 +271,9 @@ public abstract class BaseBlock extends MappableContent{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns whether this block's inventory has space and is ready for production.*/
|
||||
public boolean canProduce(Tile tile){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildBeginEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -64,8 +63,8 @@ public class Build{
|
||||
}
|
||||
|
||||
/**Places a BuildBlock at this location.*/
|
||||
public static void beginPlace(Team team, int x, int y, Recipe recipe, int rotation){
|
||||
if(!validPlace(team, x, y, recipe.result, rotation)){
|
||||
public static void beginPlace(Team team, int x, int y, Block result, int rotation){
|
||||
if(!validPlace(team, x, y, result, rotation)){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,13 +73,12 @@ public class Build{
|
||||
//just in case
|
||||
if(tile == null) return;
|
||||
|
||||
Block result = recipe.result;
|
||||
Block previous = tile.block();
|
||||
|
||||
Block sub = content.getByName(ContentType.block, "build" + result.size);
|
||||
|
||||
tile.setBlock(sub, rotation);
|
||||
tile.<BuildEntity>entity().setConstruct(previous, recipe);
|
||||
tile.<BuildEntity>entity().setConstruct(previous, result);
|
||||
tile.setTeam(team);
|
||||
|
||||
if(result.isMultiblock()){
|
||||
@@ -107,9 +105,7 @@ public class Build{
|
||||
|
||||
/**Returns whether a tile can be placed at this location by this team.*/
|
||||
public static boolean validPlace(Team team, int x, int y, Block type, int rotation){
|
||||
Recipe recipe = Recipe.getByResult(type);
|
||||
|
||||
if(recipe == null || (!recipe.visibility.usable())){
|
||||
if(!type.isVisible() || type.isHidden()){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,9 +212,9 @@ public class Tile implements Position, TargetTrait{
|
||||
return link != 0;
|
||||
}
|
||||
|
||||
/** Sets this to a linked tile, which sets the block to a blockpart. dx and dy can only be -8-7. */
|
||||
/** Sets this to a linked tile, which sets the block to a part. dx and dy can only be -8-7. */
|
||||
public void setLinked(byte dx, byte dy){
|
||||
setBlock(Blocks.blockpart);
|
||||
setBlock(Blocks.part);
|
||||
link = Pack.byteByte((byte)(dx + 8), (byte)(dy + 8));
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ public class Tile implements Position, TargetTrait{
|
||||
Block block = block();
|
||||
Block floor = floor();
|
||||
|
||||
return floor.name() + ":" + block.name() + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) +
|
||||
return floor.name + ":" + block.name + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) +
|
||||
(link != 0 ? " link=[" + (Pack.leftByte(link) - 8) + ", " + (Pack.rightByte(link) - 8) + "]" : "");
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,16 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
/**
|
||||
* Used for multiblocks. Each block that is not the center of the multiblock is a blockpart.
|
||||
* Used for multiblocks. Each block that is not the center of the multiblock is a part.
|
||||
* Think of these as delegates to the actual block; all events are passed to the target block.
|
||||
* They are made to share all properties from the linked tile/block.
|
||||
*/
|
||||
public class BlockPart extends Block{
|
||||
|
||||
public BlockPart(){
|
||||
super("blockpart");
|
||||
super("part");
|
||||
solid = false;
|
||||
hasPower = hasItems = hasLiquids = true;
|
||||
viewRange = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.world.blocks;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.Graphics.Cursor;
|
||||
import io.anuke.arc.Graphics.Cursor.SystemCursor;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
@@ -15,13 +16,13 @@ import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.effect.RubbleDecal;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildEndEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Layer;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.modules.ItemModule;
|
||||
@@ -46,8 +47,10 @@ public class BuildBlock extends Block{
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void onDeconstructFinish(Tile tile, Block block){
|
||||
Team team = tile.getTeam();
|
||||
Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size);
|
||||
world.removeBlock(tile);
|
||||
Events.fire(new BlockBuildEndEvent(tile, team, true));
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@@ -64,24 +67,25 @@ public class BuildBlock extends Block{
|
||||
//event first before they can recieve the placed() event modification results
|
||||
Core.app.post(() -> tile.block().playerPlaced(tile));
|
||||
}
|
||||
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, team, false)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
return Core.bundle.format("block.constructing", entity.recipe == null ? entity.previous.formalName : entity.recipe.result.formalName);
|
||||
return Core.bundle.format("block.constructing", entity.block == null ? entity.previous.formalName : entity.block.formalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getDisplayIcon(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
return (entity.recipe == null ? entity.previous : entity.recipe.result).getEditorIcon();
|
||||
return (entity.block == null ? entity.previous : entity.block).icon(Icon.full);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolidFor(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
return entity == null || (entity.recipe != null && entity.recipe.result.solid) || entity.previous == null || entity.previous.solid;
|
||||
return entity == null || (entity.block != null && entity.block.solid) || entity.previous == null || entity.previous.solid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,9 +98,9 @@ public class BuildBlock extends Block{
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
//if the target is constructible, begin constructing
|
||||
if(entity.recipe != null){
|
||||
if(entity.block != null){
|
||||
player.clearBuilding();
|
||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.recipe));
|
||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.block));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,15 +118,13 @@ public class BuildBlock extends Block{
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
//When breaking, don't draw the previous block... since it's the thing you were breaking
|
||||
if(entity.recipe != null && entity.previous == entity.recipe.result){
|
||||
if(entity.block != null && entity.previous == entity.block){
|
||||
return;
|
||||
}
|
||||
|
||||
if(entity.previous == null) return;
|
||||
|
||||
for(TextureRegion region : entity.previous.getBlockIcon()){
|
||||
Draw.rect(region, tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.getRotation() * 90 : 0);
|
||||
}
|
||||
Draw.rect(entity.previous.icon(Icon.full), tile.drawx(), tile.drawy(), entity.previous.rotate ? tile.getRotation() * 90 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,11 +134,11 @@ public class BuildBlock extends Block{
|
||||
|
||||
Shaders.blockbuild.color = Palette.accent;
|
||||
|
||||
Block target = entity.recipe == null ? entity.previous : entity.recipe.result;
|
||||
Block target = entity.block == null ? entity.previous : entity.block;
|
||||
|
||||
if(target == null) return;
|
||||
|
||||
for(TextureRegion region : target.getBlockIcon()){
|
||||
for(TextureRegion region : target.getGeneratedIcons()){
|
||||
Shaders.blockbuild.region = region;
|
||||
Shaders.blockbuild.progress = entity.progress;
|
||||
|
||||
@@ -148,6 +150,7 @@ public class BuildBlock extends Block{
|
||||
@Override
|
||||
public void drawShadow(Tile tile){
|
||||
//don't
|
||||
//TODO maybe do
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,7 +163,7 @@ public class BuildBlock extends Block{
|
||||
* The recipe of the block that is being constructed.
|
||||
* If there is no recipe for this block, as is the case with rocks, 'previous' is used.
|
||||
*/
|
||||
public Recipe recipe;
|
||||
public Block block;
|
||||
|
||||
public float progress = 0;
|
||||
public float buildCost;
|
||||
@@ -175,16 +178,16 @@ public class BuildBlock extends Block{
|
||||
private float[] totalAccumulator;
|
||||
|
||||
public void construct(Unit builder, TileEntity core, float amount){
|
||||
if(recipe == null){
|
||||
if(block == null){
|
||||
damage(99999);
|
||||
return;
|
||||
}
|
||||
|
||||
float maxProgress = checkRequired(core.items, amount, false);
|
||||
|
||||
for(int i = 0; i < recipe.requirements.length; i++){
|
||||
accumulator[i] += Math.min(recipe.requirements[i].amount * maxProgress, recipe.requirements[i].amount - totalAccumulator[i] + 0.00001f); //add min amount progressed to the accumulator
|
||||
totalAccumulator[i] = Math.min(totalAccumulator[i] + recipe.requirements[i].amount * maxProgress, recipe.requirements[i].amount);
|
||||
for(int i = 0; i < block.buildRequirements.length; i++){
|
||||
accumulator[i] += Math.min(block.buildRequirements[i].amount * maxProgress, block.buildRequirements[i].amount - totalAccumulator[i] + 0.00001f); //add min amount progressed to the accumulator
|
||||
totalAccumulator[i] = Math.min(totalAccumulator[i] + block.buildRequirements[i].amount * maxProgress, block.buildRequirements[i].amount);
|
||||
}
|
||||
|
||||
maxProgress = checkRequired(core.items, maxProgress, true);
|
||||
@@ -196,24 +199,23 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
|
||||
if(progress >= 1f || state.rules.infiniteResources){
|
||||
Call.onConstructFinish(tile, recipe.result, builderID, tile.getRotation(), builder.getTeam());
|
||||
Call.onConstructFinish(tile, block, builderID, tile.getRotation(), builder.getTeam());
|
||||
}
|
||||
}
|
||||
|
||||
public void deconstruct(Unit builder, TileEntity core, float amount){
|
||||
Recipe recipe = Recipe.getByResult(previous);
|
||||
|
||||
if(recipe != null){
|
||||
ItemStack[] requirements = recipe.requirements;
|
||||
if(block != null){
|
||||
ItemStack[] requirements = block.buildRequirements;
|
||||
if(requirements.length != accumulator.length || totalAccumulator.length != requirements.length){
|
||||
setDeconstruct(previous);
|
||||
}
|
||||
|
||||
for(int i = 0; i < requirements.length; i++){
|
||||
accumulator[i] += Math.min(requirements[i].amount * amount / 2f, requirements[i].amount/2f - totalAccumulator[i]); //add scaled amount progressed to the accumulator
|
||||
accumulator[i] += Math.min(requirements[i].amount * amount / 2f, requirements[i].amount / 2f - totalAccumulator[i]); //add scaled amount progressed to the accumulator
|
||||
totalAccumulator[i] = Math.min(totalAccumulator[i] + requirements[i].amount * amount / 2f, requirements[i].amount);
|
||||
|
||||
int accumulated = (int) (accumulator[i]); //get amount
|
||||
int accumulated = (int)(accumulator[i]); //get amount
|
||||
|
||||
if(amount > 0 && accumulated > 0){ //if it's positive, add it to the core
|
||||
int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder);
|
||||
@@ -227,21 +229,21 @@ public class BuildBlock extends Block{
|
||||
progress = Mathf.clamp(progress - amount);
|
||||
|
||||
if(progress <= 0 || state.rules.infiniteResources){
|
||||
Call.onDeconstructFinish(tile, this.recipe == null ? previous : this.recipe.result);
|
||||
Call.onDeconstructFinish(tile, this.block == null ? previous : this.block);
|
||||
}
|
||||
}
|
||||
|
||||
private float checkRequired(ItemModule inventory, float amount, boolean remove){
|
||||
float maxProgress = amount;
|
||||
|
||||
for(int i = 0; i < recipe.requirements.length; i++){
|
||||
for(int i = 0; i < block.buildRequirements.length; i++){
|
||||
int required = (int) (accumulator[i]); //calculate items that are required now
|
||||
|
||||
if(inventory.get(recipe.requirements[i].item) == 0){
|
||||
if(inventory.get(block.buildRequirements[i].item) == 0){
|
||||
maxProgress = 0f;
|
||||
}else if(required > 0){ //if this amount is positive...
|
||||
//calculate how many items it can actually use
|
||||
int maxUse = Math.min(required, inventory.get(recipe.requirements[i].item));
|
||||
int maxUse = Math.min(required, inventory.get(block.buildRequirements[i].item));
|
||||
//get this as a fraction
|
||||
float fraction = maxUse / (float) required;
|
||||
|
||||
@@ -252,7 +254,7 @@ public class BuildBlock extends Block{
|
||||
|
||||
//remove stuff that is actually used
|
||||
if(remove){
|
||||
inventory.remove(recipe.requirements[i].item, maxUse);
|
||||
inventory.remove(block.buildRequirements[i].item, maxUse);
|
||||
}
|
||||
}
|
||||
//else, no items are required yet, so just keep going
|
||||
@@ -265,24 +267,24 @@ public class BuildBlock extends Block{
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void setConstruct(Block previous, Recipe recipe){
|
||||
this.recipe = recipe;
|
||||
public void setConstruct(Block previous, Block block){
|
||||
this.block = block;
|
||||
this.previous = previous;
|
||||
this.accumulator = new float[recipe.requirements.length];
|
||||
this.totalAccumulator = new float[recipe.requirements.length];
|
||||
this.buildCost = recipe.cost;
|
||||
this.accumulator = new float[block.buildRequirements.length];
|
||||
this.totalAccumulator = new float[block.buildRequirements.length];
|
||||
this.buildCost = block.buildCost;
|
||||
}
|
||||
|
||||
public void setDeconstruct(Block previous){
|
||||
this.previous = previous;
|
||||
this.progress = 1f;
|
||||
if(Recipe.getByResult(previous) != null){
|
||||
this.recipe = Recipe.getByResult(previous);
|
||||
this.accumulator = new float[Recipe.getByResult(previous).requirements.length];
|
||||
this.totalAccumulator = new float[Recipe.getByResult(previous).requirements.length];
|
||||
this.buildCost = Recipe.getByResult(previous).cost;
|
||||
if(previous.buildCost > 1f){
|
||||
this.block = previous;
|
||||
this.accumulator = new float[previous.buildRequirements.length];
|
||||
this.totalAccumulator = new float[previous.buildRequirements.length];
|
||||
this.buildCost = previous.buildCost;
|
||||
}else{
|
||||
this.buildCost = 20f; //default no-recipe build cost is 20
|
||||
this.buildCost = 20f; //default no-requirement build cost is 20
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +292,7 @@ public class BuildBlock extends Block{
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeFloat(progress);
|
||||
stream.writeShort(previous == null ? -1 : previous.id);
|
||||
stream.writeShort(recipe == null ? -1 : recipe.result.id);
|
||||
stream.writeShort(block == null ? -1 : block.id);
|
||||
|
||||
if(accumulator == null){
|
||||
stream.writeByte(-1);
|
||||
@@ -320,10 +322,10 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
|
||||
if(pid != -1) previous = content.block(pid);
|
||||
if(rid != -1) recipe = Recipe.getByResult(content.block(rid));
|
||||
if(rid != -1) block = content.block(rid);
|
||||
|
||||
if(recipe != null){
|
||||
buildCost = recipe.cost;
|
||||
if(block != null){
|
||||
buildCost = block.buildCost;
|
||||
}else{
|
||||
buildCost = 20f;
|
||||
}
|
||||
|
||||
@@ -2,22 +2,18 @@ package io.anuke.mindustry.world.blocks;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class Floor extends Block{
|
||||
/** number of different variant regions to use */
|
||||
public int variants;
|
||||
@@ -43,18 +39,15 @@ public class Floor extends Block{
|
||||
public Color liquidColor;
|
||||
/** liquids that drop from this block, used for pumps */
|
||||
public Liquid liquidDrop = null;
|
||||
/** item that drops from this block, used for drills */
|
||||
public Item itemDrop = null;
|
||||
/** Whether ores generate on this block. */
|
||||
public boolean hasOres = false;
|
||||
/** whether this block can be drowned in */
|
||||
public boolean isLiquid;
|
||||
/** if true, this block cannot be mined by players. useful for annoying things like stone. */
|
||||
/** if true, this block cannot be mined by players. useful for annoying things like sand. */
|
||||
public boolean playerUnmineable = false;
|
||||
protected TextureRegion edgeRegion;
|
||||
protected TextureRegion[] edgeRegions;
|
||||
protected TextureRegion[] variantRegions;
|
||||
protected Vector2[] offsets;
|
||||
protected Predicate<Floor> blends = block -> block != this && !block.blendOverride(this);
|
||||
protected boolean blend = true;
|
||||
|
||||
public Floor(String name){
|
||||
super(name);
|
||||
@@ -65,36 +58,6 @@ public class Floor extends Block{
|
||||
public void load(){
|
||||
super.load();
|
||||
|
||||
if(blend){
|
||||
edgeRegion = Core.atlas.has(name + "edge") ? Core.atlas.find(name + "edge") : Core.atlas.find(edge + "edge");
|
||||
edgeRegions = new TextureRegion[8];
|
||||
offsets = new Vector2[8];
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
int dx = Geometry.d8[i].x, dy = Geometry.d8[i].y;
|
||||
|
||||
TextureRegion result = new TextureRegion();
|
||||
|
||||
int padSize = (int)(tilesize/Draw.scl/2);
|
||||
int texSize = (int)(tilesize/Draw.scl);
|
||||
int totSize = padSize + texSize;
|
||||
|
||||
int sx = -dx * texSize + padSize/2, sy = -dy * texSize + padSize/2;
|
||||
int x = Mathf.clamp(sx, 0, totSize);
|
||||
int y = Mathf.clamp(sy, 0, totSize);
|
||||
int w = Mathf.clamp(sx + texSize, 0, totSize) - x, h = Mathf.clamp(sy + texSize, 0, totSize) - y;
|
||||
|
||||
float rx = Mathf.clamp(dx * texSize, 0, texSize - w);
|
||||
float ry = Mathf.clamp(dy * texSize, 0, texSize - h);
|
||||
|
||||
result.setTexture(edgeRegion.getTexture());
|
||||
result.set(edgeRegion.getX() + x, edgeRegion.getY() + y + h, w, -h);
|
||||
|
||||
edgeRegions[i] = result;
|
||||
offsets[i] = new Vector2(-padSize + rx, -padSize + ry);
|
||||
}
|
||||
}
|
||||
|
||||
//load variant regions for drawing
|
||||
if(variants > 0){
|
||||
variantRegions = new TextureRegion[variants];
|
||||
@@ -124,34 +87,11 @@ public class Floor extends Block{
|
||||
Mathf.random.setSeed(tile.pos());
|
||||
|
||||
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
||||
|
||||
/*
|
||||
if(tile.hasCliffs() && cliffRegions != null){
|
||||
for(int i = 0; i < 4; i++){
|
||||
if((tile.getCliffs() & (1 << i * 2)) != 0){
|
||||
Draw.colorl(i > 1 ? 0.6f : 1f);
|
||||
|
||||
boolean above = (tile.getCliffs() & (1 << ((i + 1) % 4) * 2)) != 0, below = (tile.getCliffs() & (1 << (Mathf.mod(i - 1, 4)) * 2)) != 0;
|
||||
|
||||
if(above && below){
|
||||
Draw.rect(cliffRegions[0], tile.worldx(), tile.worldy(), i * 90);
|
||||
}else if(above){
|
||||
Draw.rect(cliffRegions[1], tile.worldx(), tile.worldy(), i * 90);
|
||||
}else if(below){
|
||||
Draw.rect(cliffRegions[2], tile.worldx(), tile.worldy(), i * 90);
|
||||
}else{
|
||||
Draw.rect(cliffRegions[3], tile.worldx(), tile.worldy(), i * 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Draw.reset();
|
||||
|
||||
drawEdges(tile, false);*/
|
||||
}
|
||||
|
||||
public boolean blendOverride(Block block){
|
||||
return false;
|
||||
@Override
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,8 +30,8 @@ public class LiquidBlock extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] getIcon(){
|
||||
return new TextureRegion[]{Core.atlas.find(name() + "-bottom"), Core.atlas.find(name() + "-top")};
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name + "-top")};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,10 +2,8 @@ package io.anuke.mindustry.world.blocks;
|
||||
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
@@ -17,7 +15,7 @@ public class OreBlock extends Floor{
|
||||
public OreBlock(Item ore, Floor base){
|
||||
super("ore-" + ore.name + "-" + base.name);
|
||||
this.formalName = ore.localizedName() + " " + base.formalName;
|
||||
this.drops = new ItemStack(ore, 1);
|
||||
this.itemDrop = ore;
|
||||
this.base = base;
|
||||
this.variants = 3;
|
||||
this.minimapColor = ore.color;
|
||||
@@ -28,15 +26,7 @@ public class OreBlock extends Floor{
|
||||
|
||||
@Override
|
||||
public String getDisplayName(Tile tile){
|
||||
return drops.item.localizedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getEditorIcon(){
|
||||
if(editorIcon == null){
|
||||
editorIcon = variantRegions[0];
|
||||
}
|
||||
return editorIcon;
|
||||
return itemDrop.localizedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,11 +19,18 @@ public class Rock extends Block{
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
Draw.colorl(1f - tile.getRotation() / 4f);
|
||||
if(variants > 0){
|
||||
Draw.rect(regions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy());
|
||||
}else{
|
||||
Draw.rect(region, tile.worldx(), tile.worldy());
|
||||
}
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name + "1")};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
13
core/src/io/anuke/mindustry/world/blocks/StaticWall.java
Normal file
13
core/src/io/anuke/mindustry/world/blocks/StaticWall.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package io.anuke.mindustry.world.blocks;
|
||||
|
||||
import io.anuke.mindustry.graphics.CacheLayer;
|
||||
|
||||
public class StaticWall extends Rock{
|
||||
|
||||
public StaticWall(String name){
|
||||
super(name);
|
||||
breakable = alwaysReplace = false;
|
||||
solid = true;
|
||||
cacheLayer = CacheLayer.walls;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ItemTurret extends CooledTurret{
|
||||
protected int maxAmmo = 50;
|
||||
protected int maxAmmo = 30;
|
||||
protected ObjectMap<Item, BulletType> ammo = new ObjectMap<>();
|
||||
|
||||
public ItemTurret(String name){
|
||||
|
||||
@@ -83,7 +83,6 @@ public abstract class Turret extends Block{
|
||||
solid = true;
|
||||
layer = Layer.turret;
|
||||
group = BlockGroup.turrets;
|
||||
turretIcon = true;
|
||||
flags = EnumSet.of(BlockFlag.turret);
|
||||
}
|
||||
|
||||
@@ -92,11 +91,6 @@ public abstract class Turret extends Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
viewRange = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -110,10 +104,6 @@ public abstract class Turret extends Block{
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
/*
|
||||
if(ammo != null) stats.add("ammo", ammo);
|
||||
if(ammo != null) stats.add("ammocapacity", maxAmmo);
|
||||
if(ammo != null) stats.add("ammoitem", ammoMultiplier);*/
|
||||
|
||||
stats.add(BlockStat.shootRange, range, StatUnit.blocks);
|
||||
stats.add(BlockStat.inaccuracy, (int) inaccuracy, StatUnit.degrees);
|
||||
@@ -142,19 +132,8 @@ public abstract class Turret extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] getBlockIcon(){
|
||||
if(blockIcon == null){
|
||||
blockIcon = new TextureRegion[]{Core.atlas.find("block-icon-" + name)};
|
||||
}
|
||||
return blockIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] getCompactIcon(){
|
||||
if(compactIcon == null){
|
||||
compactIcon = new TextureRegion[]{iconRegion(Core.atlas.find("block-icon-" + name))};
|
||||
}
|
||||
return compactIcon;
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find("block-" + size), Core.atlas.find(name)};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user