Added outpost schematic system

This commit is contained in:
Anuken 2018-08-04 14:51:33 -04:00
parent f30ea80b42
commit 8ec87872c8
10 changed files with 242 additions and 40 deletions

View File

@ -20,6 +20,7 @@ public class Blocks extends BlockList implements ContentList{
air = new Floor("air"){
{
blend = false;
alwaysReplace = true;
}
//don't draw

View File

@ -9,6 +9,8 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
import io.anuke.mindustry.maps.generation.StructureFormat;
import io.anuke.mindustry.maps.generation.StructureFormat.StructBlock;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
@ -19,7 +21,9 @@ import io.anuke.ucore.core.KeyBinds;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.input.Input;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.*;
@ -63,6 +67,23 @@ public class DesktopInput extends InputHandler{
}
}
void printArea(NormalizeResult result){
StructBlock[][] blocks = new StructBlock[Math.abs(result.x2 - result.x) + 1][Math.abs(result.y2 - result.y) + 1];
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = result.x + x;
int wy = result.y + y;
Block block = world.tile(wx, wy).block();
blocks[x][y] = new StructBlock(block == Blocks.blockpart ? Blocks.air : block, world.tile(wx, wy).getRotation());
}
}
Log.info(StructureFormat.writeBase64(blocks));
}
@Override
public boolean isDrawing(){
return mode != none || recipe != null;
@ -259,12 +280,16 @@ public class DesktopInput extends InputHandler{
}else if(mode == breaking){ //touch up while breaking, break everything in selection
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursor.x, cursor.y, rotation, false, maxLength);
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = selectX + x * Mathf.sign(cursor.x - selectX);
int wy = selectY + y * Mathf.sign(cursor.y - selectY);
if(debug && Inputs.keyDown(Input.CONTROL_LEFT)){
printArea(result);
}else{
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = selectX + x * Mathf.sign(cursor.x - selectX);
int wy = selectY + y * Mathf.sign(cursor.y - selectY);
tryBreakBlock(wx, wy);
tryBreakBlock(wx, wy);
}
}
}
}

View File

@ -33,7 +33,7 @@ public class Sector{
public transient int difficulty;
public Mission currentMission(){
return missions.get(completedMissions);
return missions.get(Math.min(completedMissions, missions.size - 1));
}
public int getSeed(){

View File

@ -1,29 +1,67 @@
package io.anuke.mindustry.maps.generation;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.blocks.DefenseBlocks;
import io.anuke.mindustry.content.blocks.ProductionBlocks;
import io.anuke.mindustry.content.blocks.TurretBlocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.generation.StructureFormat.StructBlock;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.util.Geometry;
import io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret;
import io.anuke.mindustry.world.blocks.defense.turrets.PowerTurret;
import io.anuke.mindustry.world.blocks.defense.turrets.Turret;
import static io.anuke.mindustry.Vars.world;
public class FortressGenerator{
private final Block[] turretBlocks = {TurretBlocks.duo, TurretBlocks.hail, TurretBlocks.wave};
private final Block[] drillBlocks = {ProductionBlocks.tungstenDrill, ProductionBlocks.carbideDrill};
private final Block[] armorBlocks = {DefenseBlocks.tungstenWall, DefenseBlocks.carbideWall, DefenseBlocks.thoriumWall};
private final int minCoreDst = 50;
private final static int minCoreDst = 50;
private static Structure[] structures;
private int enemyX, enemyY, coreX, coreY;
private Team team;
private Generation gen;
private static void init(){
if(structures != null) return;
String vaults = "BQMADWNhcmJpZGUtZHJpbGwCAA10dW5nc3Rlbi13YWxsAQATdHVuZ3N0ZW4td2FsbC1sYXJnZQAAA2FpcgQABXZhdWx0CQUAAgABAAEAAQABAAIAAAABAAAAAAACAAAAAQAAAAABAQABAgEBAQAAAAIAAgMBAAEAAAICAAAAAAAAAgACAgAABAIAAAIAAgIAAAAAAAACAAICAgMCAwIDAgM=";
structures = new Structure[]{
//tiny duo outpost
new Structure(Items.tungsten, "BAMADnR1bmdzdGVuLWRyaWxsAgADZHVvAQANdHVuZ3N0ZW4td2FsbAAAA2FpcgMFAQABAwEDAQMBAAEAAgMDAwIDAQABAAEBAQEBAQEA"),
//basic outposts with duos
new Structure(Items.tungsten, "BAIAA2R1bwMADWNhcmJpZGUtZHJpbGwBAA10dW5nc3Rlbi13YWxsAAADYWlyBQUAAAEAAQABAAAAAQABAAIAAQABAAEAAgADAwIAAQABAAEAAgABAAEAAAABAAEAAQAAAA=="),
//more advanced duo outpost
new Structure(Items.lead, "BwYADnR1bmdzdGVuLWRyaWxsAwADZHVvBAAIc3BsaXR0ZXIBAA10dW5nc3Rlbi13YWxsAgATdHVuZ3N0ZW4td2FsbC1sYXJnZQAAA2FpcgUACGNvbnZleW9yCQkAAAAAAQEBAQEBAQEBAgAAAAAAAAICAAEDAAQDAwACAgAAAAABAgACAAABAgUCAQEAAAAAAQABAgMAAQIBAgUCAQEBAQMAAQABAgQCBQMFAwYCBQEFAQQDAQABAgMAAQEBAQUAAQMBAwMAAQABAwICAAMBAQUAAQMCAgADAQMAAAAAAAIDAAQDAwAAAwADAAAAAAAAAQIBAwEDAQMBAwAAAAA="),
//material storage
new Structure(Items.lead, vaults),
new Structure(Items.coal, vaults),
new Structure(Items.titanium, vaults),
//salvo outpost
new Structure(Items.tungsten, "BAIABXNhbHZvAwANY2FyYmlkZS1kcmlsbAAAA2FpcgEADGNhcmJpZGUtd2FsbAcHAAAAAAEDAQMBAwEDAAABAwEDAQMCAAAAAQMAAAEAAgAAAAAAAAABAwEDAQAAAAAAAwACAAAAAQIBAAEBAgAAAAAAAAABAgAAAQEAAAAAAQEBAQEBAAABAQEBAQEBAQAAAAA="),
//advanced laser outpost
new Structure(null, "BQIABmxhbmNlcgEAEmNhcmJpZGUtd2FsbC1sYXJnZQQAEXNvbGFyLXBhbmVsLWxhcmdlAAADYWlyAwALc29sYXItcGFuZWwLCwAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMAAwAAAAAAAwABAAAAAAABAAAAAgAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAQAAAACAAAAAQAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAIAAAADAAMAAQAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
//coal laser outpost
new Structure(null, "BgEADHRob3JpdW0td2FsbAMABmxhbmNlcgUAFGNvbWJ1c3Rpb24tZ2VuZXJhdG9yBAANY2FyYmlkZS1kcmlsbAAAA2FpcgIAC3NvbGFyLXBhbmVsBwcAAAEAAQABAQEBAQEBAAAAAQACAgMAAAACAAEAAAABAAICAAAAAAIAAQAAAAEAAQAEAQUAAQABAAAAAQACAAMBAAMCAAEAAAABAAIAAAMAAwIAAQAAAAEAAQABAwEDAQABAA=="),
//ultimate laser outpost
new Structure(null, "BgMABmxhbmNlcgIAEmNhcmJpZGUtd2FsbC1sYXJnZQUAEXNvbGFyLXBhbmVsLWxhcmdlAAADYWlyBAALc29sYXItcGFuZWwBAAxjYXJiaWRlLXdhbGwPDwAAAAAAAAAAAAABAwIDAAABAwAAAAAAAAAAAAAAAAAAAAACAwAAAgMAAAAAAAACAwAAAgMAAAAAAAAAAAAAAQMAAAAAAAAAAAMDAAAAAAAAAAAAAAIDAAAAAAAAAgMAAAMDAAAEAwAAAAADAwAAAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIDAAAAAAAAAgMAAAMDAAAAAAUDAAAAAAAAAAAEAwAAAAABAwEDAAAAAAAAAAAAAAAAAAAAAAUDAAADAwAAAgMAAAIDAAADAwAAAAAAAAAABAMAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAFAwAAAAAAAAAAAwMAAAIDAAABAwEDAgMAAAQDAAAAAAAAAAAFAwAAAAAAAAAAAAAAAAAAAAAAAAMDAAADAwAAAAAAAAAAAwMAAAIDAAAAAAAAAgMAAAAAAAAAAAAAAwMAAAQDAAAAAAAAAAAAAAAAAAAAAAIDAAACAwAAAAAAAAIDAAACAwAAAQMAAAAAAAABAwAAAAAAAAAAAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEDAAAAAAEDAAAAAAAAAAAAAA=="),
};
}
public void generate(Generation gen, Team team, int coreX, int coreY, int enemyX, int enemyY){
init();
this.enemyX = enemyX;
this.enemyY = enemyY;
this.coreX = coreX;
@ -35,29 +73,39 @@ public class FortressGenerator{
}
void genOutposts(){
int index = 0;
Block turret = turretBlocks[index], drill = drillBlocks[index], armor = armorBlocks[index];
Item ore = Items.tungsten;
int padding = 10;
Array<Rectangle> used = new Array<>();
Rectangle rect = new Rectangle();
for(int x = 2; x < gen.width - 2; x++){
for(int y = 2; y < gen.height - 2; y++){
if(Vector2.dst(x, y, coreX, coreY) > minCoreDst &&
gen.tiles[x][y].floor().dropsItem(ore) && gen.random.chance(0.02)){
int elevation = gen.tiles[x][y].getElevation();
gen.tiles[x][y].setBlock(drill, team);
for(Structure struct : structures){
for(int x = padding; x < gen.width - padding; x++){
loop:
for(int y = padding; y < gen.height - padding; y++){
rect.set(x - struct.layout.length, y - struct.layout[0].length, struct.layout.length, struct.layout[0].length);
if(Vector2.dst(x, y, coreX, coreY) > minCoreDst && Vector2.dst(x, y, enemyX, enemyY) > 30 &&
(struct.ore == null || gen.tiles[x][y].floor().dropsItem(struct.ore)) && gen.random.chance(0.03)){
for(Rectangle other : used){
if(other.overlaps(rect)){
continue loop;
}
}
used.add(new Rectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 2));
int elevation = world.tile(x, y).getElevation();
for(int cx = 0; cx < struct.layout.length; cx++){
for(int cy = 0; cy < struct.layout[0].length; cy++){
int wx = x + cx - struct.layout.length/2;
int wy = y + cy - struct.layout[0].length/2;
StructBlock block = struct.layout[cx][cy];
Tile tile = world.tile(wx, wy);
if(block.block != Blocks.air && tile.block().alwaysReplace){
tile.setElevation(elevation);
tile.setRotation(block.rotation);
tile.setBlock(block.block, team);
for(GridPoint2 point : Geometry.d4){
gen.tiles[x + point.x][y + point.y].setBlock(turret, team);
gen.tiles[x + point.x][y + point.y].setElevation(elevation);
}
for(int cx = -2; cx <= 2; cx++){
for(int cy = -2; cy <= 2; cy++){
Tile tile = gen.tiles[x + cx][y + cy];
if(tile.block().alwaysReplace || tile.block() == Blocks.air){
tile.setElevation(elevation);
tile.setBlock(armor, team);
if(block.block instanceof Turret){
fillTurret(tile);
}
}
}
}
}
@ -65,4 +113,29 @@ public class FortressGenerator{
}
}
}
void setBlock(Block block){
}
void fillTurret(Tile tile){
Block block = tile.block();
if(block instanceof PowerTurret){
tile.entity.power.amount = block.powerCapacity;
}else if(block instanceof ItemTurret){
ItemTurret turret = (ItemTurret)block;
AmmoType[] type = turret.getAmmoTypes();
block.handleStack(type[0].item, block.acceptStack(type[0].item, 1000, tile, null), tile, null);
}
}
static class Structure{
public final StructBlock[][] layout;
public final Item ore;
public Structure(Item ore, String encoding){
this.ore = ore;
this.layout = StructureFormat.read(encoding);
}
}
}

View File

@ -0,0 +1,96 @@
package io.anuke.mindustry.maps.generation;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectIntMap.Entry;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.world.Block;
import java.io.*;
public class StructureFormat{
public static byte[] write(StructBlock[][] blocks){
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream stream = new DataOutputStream(out);
ObjectIntMap<Block> mapping = new ObjectIntMap<>();
int lastid = 1;
mapping.put(Blocks.air, 0);
for(int x = 0; x < blocks.length; x++){
for(int y = 0; y < blocks[0].length; y++){
Block block = blocks[x][y].block;
if(!mapping.containsKey(block)){
mapping.put(block, lastid++);
}
}
}
stream.writeByte(mapping.size);
for(Entry<Block> entry : mapping){
stream.writeByte(entry.value);
stream.writeUTF(entry.key.name);
}
stream.writeByte(blocks.length);
stream.writeByte(blocks[0].length);
for(int x = 0; x < blocks.length; x++){
for(int y = 0; y < blocks[0].length; y++){
StructBlock block = blocks[x][y];
stream.writeByte(mapping.get(block.block, 0));
stream.writeByte(block.rotation);
}
}
return out.toByteArray();
}catch(IOException e){
throw new RuntimeException(e);
}
}
public static String writeBase64(StructBlock[][] blocks){
return new String(Base64Coder.encode(write(blocks)));
}
public static StructBlock[][] read(byte[] bytes){
try{
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes));
byte size = stream.readByte();
IntMap<Block> map = new IntMap<>();
for(int i = 0; i < size; i++){
map.put(stream.readByte(), Block.getByName(stream.readUTF()));
}
byte width = stream.readByte(), height = stream.readByte();
StructBlock[][] blocks = new StructBlock[width][height];
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
blocks[x][y] = new StructBlock(map.get(stream.readByte()), stream.readByte());
}
}
return blocks;
}catch(IOException e){
throw new RuntimeException(e);
}
}
public static StructBlock[][] read(String base64){
return read(Base64Coder.decode(base64));
}
public static class StructBlock{
public final Block block;
public final byte rotation;
public StructBlock(Block block, byte rotation){
this.block = block;
this.rotation = rotation;
}
}
}

View File

@ -129,7 +129,7 @@ public class WorldGenerator{
tile.updateOcclusion();
//fix things on cliffs that shouldn't be
if(tile.block() != Blocks.air && tile.hasCliffs()){
if(tile.block() != Blocks.air && tile.hasCliffs() && !tile.block().isMultiblock() && tile.block() != Blocks.blockpart){
tile.setBlock(Blocks.air);
}
}

View File

@ -22,7 +22,7 @@ public class PausedDialog extends FloatingDialog{
void rebuild(){
missionTable.clear();
if(world.getSector() != null){
if(world.getSector() != null && !world.getSector().complete){
missionTable.add("[LIGHT_GRAY]" + Bundles.format("text.mission", ""));
missionTable.row();
missionTable.table(t -> {

View File

@ -27,7 +27,7 @@ public class SaveDialog extends LoadDialog{
ui.showTextInput("$text.save", "$text.save.newslot", "", text -> {
ui.loadAnd("$text.saving", () -> {
control.getSaves().addSave(text);
setup();
threads.runGraphics(() -> threads.run(() -> threads.runGraphics(this::setup)));
});
})
).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);

View File

@ -22,7 +22,10 @@ public class ColorMapper implements ContentList{
}
public static int colorFor(Block floor, Block wall, Team team, int elevation){
int color = wall.breakable ? team.intColor : getBlockColor(wall);
if(wall.synthetic()){
return team.intColor;
}
int color = getBlockColor(wall);
if(color == 0) color = ColorMapper.getBlockColor(floor);
if(elevation > 0){
if(tmpColors.get() == null) tmpColors.set(new Color());

View File

@ -21,6 +21,10 @@ public class ItemTurret extends CooledTurret{
hasItems = true;
}
public AmmoType[] getAmmoTypes(){
return ammoTypes;
}
@Override
public void setStats(){
super.setStats();