mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-25 22:58:47 +07:00
Added outpost schematic system
This commit is contained in:
parent
f30ea80b42
commit
8ec87872c8
@ -20,6 +20,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
air = new Floor("air"){
|
||||
{
|
||||
blend = false;
|
||||
alwaysReplace = true;
|
||||
}
|
||||
|
||||
//don't draw
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(){
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 -> {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -21,6 +21,10 @@ public class ItemTurret extends CooledTurret{
|
||||
hasItems = true;
|
||||
}
|
||||
|
||||
public AmmoType[] getAmmoTypes(){
|
||||
return ammoTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
Loading…
Reference in New Issue
Block a user