Add basic map editor, change map system
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/desktop/packr-out/
|
||||
/desktop/packr-export/
|
||||
/desktop/mindustry-saves/
|
||||
/destkop/mindustry-maps/
|
||||
/core/lib/
|
||||
*.gif
|
||||
|
||||
|
2
TODO.md
@ -16,6 +16,8 @@ _Keep in mind that this is just a basic outline of planned features, and will be
|
||||
- [DONE] Add link to Mindustry discord everywhere
|
||||
- Balancing to slow down progression
|
||||
- Map editor
|
||||
- Delete saves
|
||||
- Display playtime
|
||||
|
||||
### Major Bugs
|
||||
- Black screen when tabbing out on Android
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="io.anuke.mindustry"
|
||||
android:versionCode="37"
|
||||
android:versionName="3.1.1" >
|
||||
android:versionCode="38"
|
||||
android:versionName="3.1.2" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="25" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
|
@ -52,7 +52,7 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
Mindustry.donationsCallable = new Callable(){ @Override public void run(){ showDonations(); } };
|
||||
|
||||
if(doubleScaleTablets && isTablet(this.getContext())){
|
||||
Unit.dp.addition = 1f;
|
||||
Unit.dp.addition = 0.5f;
|
||||
}
|
||||
|
||||
config.hideStatusBar = true;
|
||||
|
BIN
core/assets-raw/sprites/ui/icon-terrain.png
Normal file
After Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 135 B |
BIN
core/assets-raw/sprites/ui/text-editor.png
Normal file
After Width: | Height: | Size: 322 B |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
95
core/assets/maps/maps.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"maps": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "maze",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "fortress",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "sinkhole",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "caves",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "volcano",
|
||||
"visible": true,
|
||||
"flipBase": true,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "caldera",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "scorch",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "e5d8bb"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "desert",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "island",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "e5d8bb"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "grassland",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "5ab464"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "tundra",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "spiral",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "f7feff"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "tutorial",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 77 KiB |
@ -49,6 +49,7 @@ io.anuke.ucore.scene.ui.ImageTextButton$ImageTextButtonStyle: {
|
||||
},
|
||||
io.anuke.ucore.scene.ui.ScrollPane$ScrollPaneStyle: {
|
||||
default: {background: border, vScroll: scroll, vScrollKnob: scroll-knob-vertical},
|
||||
volume: {background: button-map, vScroll: scroll, vScrollKnob: scroll-knob-vertical},
|
||||
clear: {vScroll: scroll, vScrollKnob: scroll-knob-vertical}
|
||||
},
|
||||
io.anuke.ucore.scene.ui.Window$WindowStyle: {
|
||||
|
@ -2,6 +2,7 @@ package io.anuke.mindustry;
|
||||
|
||||
import com.badlogic.gdx.Application.ApplicationType;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.I18NBundle;
|
||||
|
||||
import io.anuke.mindustry.core.*;
|
||||
@ -20,14 +21,18 @@ public class Vars{
|
||||
public static final float respawnduration = 60*4;
|
||||
//time between waves in frames (on normal mode)
|
||||
public static final float wavespace = 60*60*(android ? 1 : 1);
|
||||
//waves can last no longer than 2 minutes, otherwise the next one spawns
|
||||
public static final float maxwavespace = 60*60*2;
|
||||
//waves can last no longer than 3 minutes, otherwise the next one spawns
|
||||
public static final float maxwavespace = 60*60*4f;
|
||||
//advance time the pathfinding starts at
|
||||
public static final float aheadPathfinding = 60*20;
|
||||
//how far away from spawn points the player can't place blocks
|
||||
public static final float enemyspawnspace = 65;
|
||||
//discord group URL
|
||||
public static final String discordURL = "https://discord.gg/r8BkXNd";
|
||||
//directory for user-created map data
|
||||
public static final FileHandle customMapDirectory = Gdx.files.local("mindustry-maps/");
|
||||
//save file directory
|
||||
public static final FileHandle saveDirectory = Gdx.files.local("mindustry-saves/");
|
||||
//scale of the font
|
||||
public static float fontscale = Unit.dp.inPixels(1f)/2f;
|
||||
//camera zoom displayed on startup
|
||||
|
@ -42,11 +42,10 @@ public class Pathfind{
|
||||
if(Vars.world.raycastWorld(enemy.x, enemy.y, target.worldx(), target.worldy()) != null){
|
||||
if(enemy.node > 1)
|
||||
enemy.node = enemy.node - 1;
|
||||
enemy.idletime = 0;
|
||||
}else{
|
||||
//must be blocked by a playermade block
|
||||
//must be blocked by a playermade block, do nothing
|
||||
}
|
||||
|
||||
enemy.idletime = 0;
|
||||
}
|
||||
|
||||
//-1 is only possible here if both pathfindings failed, which should NOT happen
|
||||
|
@ -118,8 +118,8 @@ public class Control extends Module{
|
||||
|
||||
Settings.loadAll("io.anuke.moment");
|
||||
|
||||
for(Map map : Map.values()){
|
||||
Settings.defaults("hiscore" + map.name(), 0);
|
||||
for(Map map : Vars.world.maps().list()){
|
||||
Settings.defaults("hiscore" + map.name, 0);
|
||||
}
|
||||
|
||||
player = new Player();
|
||||
@ -278,10 +278,10 @@ public class Control extends Module{
|
||||
|
||||
wave ++;
|
||||
|
||||
int last = Settings.getInt("hiscore" + world.getMap().name());
|
||||
int last = Settings.getInt("hiscore" + world.getMap().name);
|
||||
|
||||
if(wave > last && mode != GameMode.sandbox){
|
||||
Settings.putInt("hiscore" + world.getMap().name(), wave);
|
||||
Settings.putInt("hiscore" + world.getMap().name, wave);
|
||||
Settings.save();
|
||||
hiscore = true;
|
||||
}
|
||||
@ -518,7 +518,6 @@ public class Control extends Module{
|
||||
}
|
||||
|
||||
if(!tutorial.active() && mode != GameMode.sandbox){
|
||||
extrawavetime -= delta();
|
||||
|
||||
if(enemies <= 0){
|
||||
wavetime -= delta();
|
||||
@ -531,10 +530,12 @@ public class Control extends Module{
|
||||
world.pathfinder().updatePath();
|
||||
lastUpdated = wave + 1;
|
||||
}
|
||||
}else{
|
||||
extrawavetime -= delta();
|
||||
}
|
||||
}
|
||||
|
||||
if(wavetime <= 0){
|
||||
if(wavetime <= 0 || extrawavetime <= 0){
|
||||
runWave();
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
import io.anuke.mindustry.resource.Weapon;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
@ -33,7 +32,7 @@ public class Tutorial{
|
||||
}
|
||||
|
||||
public boolean active(){
|
||||
return world.getMap() == Map.tutorial && !GameState.is(State.menu);
|
||||
return world.getMap().name.equals("tutorial") && !GameState.is(State.menu);
|
||||
}
|
||||
|
||||
public void buildUI(table table){
|
||||
|
@ -15,6 +15,8 @@ import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.Mindustry;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.mapeditor.MapEditor;
|
||||
import io.anuke.mindustry.mapeditor.MapEditorDialog;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@ -38,11 +40,13 @@ public class UI extends SceneModule{
|
||||
Table loadingtable, desctable, configtable;
|
||||
MindustrySettingsDialog prefs;
|
||||
MindustryKeybindDialog keys;
|
||||
MapEditorDialog editorDialog;
|
||||
Dialog about, restart, levels, upgrades, load, settingserror, gameerror, discord;
|
||||
MenuDialog menu;
|
||||
Tooltip tooltip;
|
||||
Tile configTile;
|
||||
Array<String> statlist = new Array<>();
|
||||
MapEditor editor = new MapEditor();
|
||||
boolean wasPaused = false;
|
||||
|
||||
private Fragment blockfrag = new BlocksFragment(),
|
||||
@ -118,7 +122,7 @@ public class UI extends SceneModule{
|
||||
Draw.color();
|
||||
|
||||
TextureRegion back = Draw.region("background");
|
||||
float backscl = 5f;
|
||||
float backscl = Unit.dp.inPixels(5f);
|
||||
|
||||
Draw.alpha(0.7f);
|
||||
Core.batch.draw(back, w/2 - back.getRegionWidth()*backscl/2 +240f, h/2 - back.getRegionHeight()*backscl/2 + 250f,
|
||||
@ -158,6 +162,8 @@ public class UI extends SceneModule{
|
||||
configtable = new Table();
|
||||
scene.add(configtable);
|
||||
|
||||
editorDialog = new MapEditorDialog(editor);
|
||||
|
||||
settingserror = new Dialog("Warning", "dialog");
|
||||
settingserror.content().add("[crimson]Failed to access local storage.\nSettings will not be saved.");
|
||||
settingserror.content().pad(10f);
|
||||
@ -439,6 +445,10 @@ public class UI extends SceneModule{
|
||||
discord.show();
|
||||
}
|
||||
|
||||
public void showEditor(){
|
||||
editorDialog.show();
|
||||
}
|
||||
|
||||
public void updateItems(){
|
||||
((HudFragment)hudfrag).updateItems();
|
||||
}
|
||||
|
@ -2,9 +2,6 @@ package io.anuke.mindustry.core;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
@ -25,15 +22,15 @@ import io.anuke.ucore.util.Tmp;
|
||||
public class World extends Module{
|
||||
private int seed;
|
||||
|
||||
private Pixmap[] mapPixmaps;
|
||||
private Texture[] mapTextures;
|
||||
private Map currentMap;
|
||||
private Tile[][] tiles;
|
||||
private Tile[] temptiles = new Tile[4];
|
||||
private Pathfind pathfind = new Pathfind();
|
||||
private Maps maps = new Maps();
|
||||
|
||||
public World(){
|
||||
loadMaps();
|
||||
maps.loadMaps();
|
||||
currentMap = maps.getMap(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -43,13 +40,11 @@ public class World extends Module{
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
for(Texture texture : mapTextures){
|
||||
texture.dispose();
|
||||
}
|
||||
maps.dispose();
|
||||
}
|
||||
|
||||
for(Pixmap pix : mapPixmaps){
|
||||
pix.dispose();
|
||||
}
|
||||
public Maps maps(){
|
||||
return maps;
|
||||
}
|
||||
|
||||
public Pathfind pathfinder(){
|
||||
@ -82,11 +77,11 @@ public class World extends Module{
|
||||
}
|
||||
|
||||
public int width(){
|
||||
return currentMap.width;
|
||||
return currentMap.getWidth();
|
||||
}
|
||||
|
||||
public int height(){
|
||||
return currentMap.height;
|
||||
return currentMap.getHeight();
|
||||
}
|
||||
|
||||
public Tile tile(int x, int y){
|
||||
@ -115,25 +110,6 @@ public class World extends Module{
|
||||
return temptiles;
|
||||
}
|
||||
|
||||
public Texture getTexture(Map map){
|
||||
return mapTextures[map.ordinal()];
|
||||
}
|
||||
|
||||
public void loadMaps(){
|
||||
Map[] maps = Map.values();
|
||||
|
||||
mapPixmaps = new Pixmap[maps.length];
|
||||
mapTextures = new Texture[maps.length];
|
||||
|
||||
for(int i = 0; i < maps.length; i ++){
|
||||
Pixmap pix = new Pixmap(Gdx.files.internal("maps/"+maps[i]+".png"));
|
||||
mapPixmaps[i] = pix;
|
||||
mapTextures[i] = new Texture(pix);
|
||||
maps[i].width = pix.getWidth();
|
||||
maps[i].height = pix.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
private void createTiles(){
|
||||
for(int x = 0; x < tiles.length; x ++){
|
||||
for(int y = 0; y < tiles[0].length; y ++){
|
||||
@ -164,28 +140,28 @@ public class World extends Module{
|
||||
if(tiles != null){
|
||||
clearTileEntities();
|
||||
|
||||
if(tiles.length != map.width || tiles[0].length != map.height){
|
||||
tiles = new Tile[map.width][map.height];
|
||||
if(tiles.length != map.getWidth() || tiles[0].length != map.getHeight()){
|
||||
tiles = new Tile[map.getWidth()][map.getHeight()];
|
||||
}
|
||||
|
||||
createTiles();
|
||||
}else{
|
||||
tiles = new Tile[map.width][map.height];
|
||||
tiles = new Tile[map.getWidth()][map.getHeight()];
|
||||
|
||||
createTiles();
|
||||
}
|
||||
|
||||
Vars.control.getSpawnPoints().clear();
|
||||
|
||||
Entities.resizeTree(0, 0, map.width * tilesize, map.height * tilesize);
|
||||
Entities.resizeTree(0, 0, map.getWidth() * tilesize, map.getHeight() * tilesize);
|
||||
|
||||
this.seed = seed;
|
||||
Generator.generate(mapPixmaps[map.ordinal()], tiles);
|
||||
Generator.generate(map.pixmap, tiles);
|
||||
|
||||
//TODO multiblock core
|
||||
control.getInput().placeBlock(control.getCore().x, control.getCore().y, ProductionBlocks.core, 0, false, false);
|
||||
|
||||
if(map != Map.tutorial){
|
||||
if(!map.name.equals("tutorial")){
|
||||
setDefaultBlocks();
|
||||
}else{
|
||||
Vars.control.getTutorial().setDefaultBlocks(control.getCore().x, control.getCore().y);
|
||||
|
@ -17,7 +17,7 @@ public class Enemy extends DestructibleEntity{
|
||||
public final static Color[] tierColors = { Color.valueOf("ffe451"), Color.valueOf("f48e20"), Color.valueOf("ff6757"), Color.valueOf("ff2d86") };
|
||||
public final static int maxtier = 4;
|
||||
public final static float maxIdle = 60*1.5f;
|
||||
public final static float maxIdleLife = 60f*15f; //15 seconds idle = death
|
||||
public final static float maxIdleLife = 60f*13f; //13 seconds idle = death
|
||||
|
||||
protected int timeid;
|
||||
protected Timer timer = new Timer(5);
|
||||
@ -238,7 +238,7 @@ public class Enemy extends DestructibleEntity{
|
||||
xvelocity = (x - lastx) / Timers.delta();
|
||||
yvelocity = (y - lasty) / Timers.delta();
|
||||
|
||||
float minv = 0.08f;
|
||||
float minv = 0.09f;
|
||||
|
||||
if(xvelocity < minv && yvelocity < minv && node > 0 && target == null){
|
||||
idletime += Timers.delta();
|
||||
|
@ -8,7 +8,6 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
@ -163,14 +162,14 @@ public class SaveIO{
|
||||
stream.readInt(); //read version
|
||||
stream.readLong(); //read last saved time
|
||||
stream.readByte(); //read the gamemode
|
||||
return Map.values()[stream.readByte()]; //read the map
|
||||
return Vars.world.maps().getMap(stream.readByte()); //read the map
|
||||
}catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static FileHandle fileFor(int slot){
|
||||
return Gdx.files.local("mindustry-saves/" + slot + ".mins");
|
||||
return Vars.saveDirectory.child(slot + ".mins");
|
||||
}
|
||||
|
||||
public static void write(FileHandle file){
|
||||
@ -183,7 +182,7 @@ public class SaveIO{
|
||||
|
||||
//--GENERAL STATE--
|
||||
stream.writeByte(Vars.control.getMode().ordinal()); //gamemode
|
||||
stream.writeByte(Vars.world.getMap().ordinal()); //map ID
|
||||
stream.writeByte(Vars.world.getMap().id); //map ID
|
||||
|
||||
stream.writeInt(Vars.control.getWave()); //wave
|
||||
stream.writeFloat(Vars.control.getWaveCountdown()); //wave countdown
|
||||
@ -399,7 +398,7 @@ public class SaveIO{
|
||||
int seed = stream.readInt();
|
||||
int tiles = stream.readInt();
|
||||
|
||||
Vars.world.loadMap(Map.values()[mapid], seed);
|
||||
Vars.world.loadMap(Vars.world.maps().getMap(mapid), seed);
|
||||
Vars.renderer.clearTiles();
|
||||
|
||||
for(Enemy enemy : enemiesToUpdate){
|
||||
|
123
core/src/io/anuke/mindustry/mapeditor/MapEditor.java
Normal file
@ -0,0 +1,123 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
|
||||
public class MapEditor{
|
||||
public static final int[] validMapSizes = {64, 128, 256};
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15};
|
||||
|
||||
private Pixmap[] brushPixmaps = new Pixmap[brushSizes.length];
|
||||
|
||||
private Map map;
|
||||
private Pixmap pixmap;
|
||||
private Texture texture;
|
||||
private int brushSize = 1;
|
||||
private Block drawBlock = Blocks.stone;
|
||||
|
||||
public MapEditor(){
|
||||
for(int i = 0; i < brushSizes.length; i ++){
|
||||
int s = brushSizes[i];
|
||||
brushPixmaps[i] = new Pixmap(s*2-1, s*2-1, Format.RGB888);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginEdit(Map map){
|
||||
this.map = map;
|
||||
this.brushSize = 1;
|
||||
if(map.pixmap == null){
|
||||
pixmap = new Pixmap(256, 256, Format.RGB888);
|
||||
pixmap.setColor(ColorMapper.getColor(Blocks.stone));
|
||||
pixmap.fill();
|
||||
texture = new Texture(pixmap);
|
||||
}else{
|
||||
pixmap = map.pixmap;
|
||||
pixmap.setColor(ColorMapper.getColor(Blocks.stone));
|
||||
texture = map.texture;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Block getDrawBlock(){
|
||||
return drawBlock;
|
||||
}
|
||||
|
||||
public void setDrawBlock(Block block){
|
||||
this.drawBlock = block;
|
||||
pixmap.setColor(ColorMapper.getColor(block));
|
||||
}
|
||||
|
||||
public void setBrushSize(int size){
|
||||
this.brushSize = size;
|
||||
}
|
||||
|
||||
public void draw(int dx, int dy){
|
||||
if(dx < 0 || dy < 0 || dx >= pixmap.getWidth() || dy >= pixmap.getHeight()){
|
||||
return;
|
||||
}
|
||||
|
||||
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, texture.getTextureObjectHandle());
|
||||
|
||||
int dstWidth = brushSize*2-1;
|
||||
int dstHeight = brushSize*2-1;
|
||||
int width = pixmap.getWidth(), height = pixmap.getHeight();
|
||||
|
||||
int x = dx - dstWidth/2;
|
||||
int y = dy - dstHeight/2;
|
||||
|
||||
if (x + dstWidth > width){
|
||||
//x = width - dstWidth;
|
||||
dstWidth = width - x;
|
||||
}else if (x < 0){
|
||||
dstWidth += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
//System.out.println(x + " " + y + " " + dstWidth + " " + dstHeight);
|
||||
|
||||
if (y + dstHeight > height){
|
||||
//y = height - dstHeight;
|
||||
dstHeight = height - y;
|
||||
}else if (y < 0){
|
||||
dstHeight += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
pixmap.fillCircle(dx, dy, brushSize);
|
||||
|
||||
Pixmap dst = brush(brushSize);
|
||||
dst.drawPixmap(pixmap, x, y, dstWidth, dstHeight, 0, 0, dstWidth, dstHeight);
|
||||
|
||||
Gdx.gl.glTexSubImage2D(GL20.GL_TEXTURE_2D, 0, x, y, dstWidth, dstHeight,
|
||||
dst.getGLFormat(), dst.getGLType(), dst.getPixels());
|
||||
}
|
||||
|
||||
private Pixmap brush(int size){
|
||||
for(int i = 0; i < brushSizes.length; i ++){
|
||||
if(brushSizes[i] == size){
|
||||
return brushPixmaps[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Texture texture(){
|
||||
return texture;
|
||||
}
|
||||
|
||||
public void resize(int mapSize){
|
||||
Pixmap out = Pixmaps.resize(pixmap, mapSize, mapSize);
|
||||
pixmap.dispose();
|
||||
pixmap = out;
|
||||
texture.draw(pixmap, 0, 0);
|
||||
}
|
||||
}
|
142
core/src/io/anuke/mindustry/mapeditor/MapEditorDialog.java
Normal file
@ -0,0 +1,142 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.core.Draw;
|
||||
import io.anuke.ucore.scene.builders.*;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
|
||||
public class MapEditorDialog extends Dialog{
|
||||
private MapEditor editor;
|
||||
private MapView view;
|
||||
|
||||
public MapEditorDialog(MapEditor editor){
|
||||
super("Map Editor", "dialog");
|
||||
this.editor = editor;
|
||||
view = new MapView(editor);
|
||||
|
||||
setFillParent(true);
|
||||
|
||||
clearChildren();
|
||||
pad(0);
|
||||
build.begin(this);
|
||||
build();
|
||||
build.end();
|
||||
|
||||
shown(() -> {
|
||||
editor.beginEdit(new Map());
|
||||
});
|
||||
}
|
||||
|
||||
public void build(){
|
||||
|
||||
new table(){{
|
||||
float isize = Unit.dp.inPixels(14*3f);
|
||||
aleft();
|
||||
|
||||
new table(){{
|
||||
defaults().growY().width(130f).units(Unit.dp).padBottom(-6);
|
||||
|
||||
new imagebutton("icon-load", isize, () -> {
|
||||
|
||||
}).text("load map");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-save", isize, ()->{
|
||||
|
||||
}).text("save map");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-load", isize, () -> {
|
||||
|
||||
}).text("load image");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-save", isize, () -> {
|
||||
|
||||
}).text("save image");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-cursor", 10f*3f, () -> {
|
||||
|
||||
}).text("resize").padTop(4f);
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-arrow-left", isize, () -> {
|
||||
|
||||
}).padBottom(0).text("back");
|
||||
|
||||
}}.left().growY().end();
|
||||
|
||||
new table("button"){{
|
||||
add(view).grow();
|
||||
}}.grow().end();
|
||||
|
||||
new table(){{
|
||||
new imagebutton("icon-terrain", isize, () -> {
|
||||
|
||||
}).margin(12f).text("generate...").width(148f).units(Unit.dp);
|
||||
|
||||
row();
|
||||
|
||||
new table("button"){{
|
||||
margin(10f);
|
||||
Slider slider = new Slider(0, MapEditor.brushSizes.length-1, 1, false);
|
||||
slider.moved(f -> {
|
||||
editor.setBrushSize(MapEditor.brushSizes[(int)(float)f]);
|
||||
});
|
||||
new label(() -> "Brush size: " + MapEditor.brushSizes[(int)slider.getValue()]).left();
|
||||
row();
|
||||
add(slider).growX().padTop(4f).units(Unit.dp);
|
||||
}}.growX().end();
|
||||
|
||||
row();
|
||||
|
||||
addBlockSelection(get());
|
||||
|
||||
row();
|
||||
|
||||
}}.right().growY().end();
|
||||
}}.grow().end();
|
||||
}
|
||||
|
||||
private void addBlockSelection(Table table){
|
||||
Table content = new Table();
|
||||
ScrollPane pane = new ScrollPane(content, "volume");
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setOverscroll(true, false);
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(BlockPair pair : ColorMapper.getPairs()){
|
||||
Block block = pair.wall == Blocks.air ? pair.floor : pair.wall;
|
||||
|
||||
ImageButton button = new ImageButton(Draw.hasRegion(block.name) ? Draw.region(block.name) : Draw.region(block.name + "1"), "toggle");
|
||||
button.clicked(() -> editor.setDrawBlock(block));
|
||||
button.resizeImage(Unit.dp.inPixels(8*4f));
|
||||
group.add(button);
|
||||
content.add(button).pad(4f).size(53f, 58f).units(Unit.dp);
|
||||
|
||||
if(i++ % 2 == 1){
|
||||
content.row();
|
||||
}
|
||||
}
|
||||
|
||||
Table extra = new Table("button");
|
||||
extra.addWrap(() -> editor.getDrawBlock().name).width(120f).center();
|
||||
table.add(extra).growX();
|
||||
table.row();
|
||||
table.add(pane).growY().fillX();
|
||||
}
|
||||
}
|
214
core/src/io/anuke/mindustry/mapeditor/MapFilter.java
Normal file
@ -0,0 +1,214 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import com.badlogic.gdx.utils.OrderedMap;
|
||||
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
import io.anuke.ucore.noise.RidgedPerlin;
|
||||
import io.anuke.ucore.noise.Simplex;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class MapFilter{
|
||||
private ObjectMap<String, Boolean> prefs = new OrderedMap<String, Boolean>(){
|
||||
{
|
||||
put("replace", true);
|
||||
put("terrain", false);
|
||||
put("circle", false);
|
||||
put("distort", false);
|
||||
put("sand", false);
|
||||
put("grass", false);
|
||||
put("stone", false);
|
||||
put("allgrass", false);
|
||||
put("allsnow", false);
|
||||
put("allsand", false);
|
||||
put("lavarock", false);
|
||||
put("water", false);
|
||||
put("oil", false);
|
||||
put("lavariver", false);
|
||||
put("slavariver", false);
|
||||
put("river", false);
|
||||
put("iceriver", false);
|
||||
put("oilriver", false);
|
||||
}
|
||||
};
|
||||
private Simplex sim = new Simplex();
|
||||
private RidgedPerlin rid = new RidgedPerlin(1, 10, 20f);
|
||||
private RidgedPerlin rid2 = new RidgedPerlin(1, 6, 1f);
|
||||
private RidgedPerlin rid3 = new RidgedPerlin(1, 6, 1f);
|
||||
|
||||
public void randomize(){
|
||||
sim.setSeed(Mathf.random(999999));
|
||||
rid.setSeed(Mathf.random(999999));
|
||||
rid2.setSeed(Mathf.random(999999));
|
||||
rid3.setSeed(Mathf.random(999999));
|
||||
}
|
||||
|
||||
public ObjectMap<String, Boolean> getPrefs(){
|
||||
return prefs;
|
||||
}
|
||||
|
||||
public Pixmap process(Pixmap pixmap){
|
||||
if(prefs.get("terrain")){
|
||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||
float dist = Vector2.dst((float) x / pixmap.getWidth(), (float) y / pixmap.getHeight(), 0.5f, 0.5f) * 2f;
|
||||
double noise = sim.octaveNoise2D(6, 0.6, 1 / 180.0, x, y + 9999) / (prefs.get("circle") ? 1.7 : 1f) + dist / 10f;
|
||||
|
||||
if(dist > 0.8){
|
||||
noise += 2 * (dist - 0.8);
|
||||
}
|
||||
|
||||
Block block = noise > 0.6 ? Blocks.stoneblock : Blocks.stone;
|
||||
|
||||
pixmap.drawPixel(x, y, ColorMapper.getColor(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pixmap src = Pixmaps.copy(pixmap);
|
||||
|
||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
if(prefs.get("distort")){
|
||||
double intensity = 12;
|
||||
double scale = 80;
|
||||
double octaves = 4;
|
||||
double falloff = 0.6;
|
||||
double nx = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y) - 0.5f) * intensity;
|
||||
double ny = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y + 99999) - 0.5f) * intensity;
|
||||
dx = (int) nx;
|
||||
dy = (int) ny;
|
||||
}
|
||||
|
||||
int pix = src.getPixel(x + dx, y + dy);
|
||||
|
||||
BlockPair pair = ColorMapper.get(pix);
|
||||
Block block = pair == null ? null : pair.wall == Blocks.air ? pair.floor : pair.wall;
|
||||
|
||||
if(block == null)
|
||||
continue;
|
||||
|
||||
boolean floor = block instanceof Floor;
|
||||
|
||||
double noise = sim.octaveNoise2D(4, 0.6, 1 / 170.0, x, y) + sim.octaveNoise2D(1, 1.0, 1 / 5.0, x, y) / 18.0;
|
||||
double nwater = sim.octaveNoise2D(1, 1.0, 1 / 130.0, x, y);
|
||||
noise += nwater / 5.0;
|
||||
|
||||
double noil = sim.octaveNoise2D(1, 1.0, 1 / 150.0, x + 9999, y) + sim.octaveNoise2D(1, 1.0, 1 / 2.0, x, y) / 290.0;
|
||||
|
||||
if(!floor || prefs.get("replace")){
|
||||
|
||||
if(prefs.get("allgrass")){
|
||||
block = floor ? Blocks.grass : Blocks.grassblock;
|
||||
}else if(prefs.get("allsnow")){
|
||||
block = floor ? Blocks.snow : Blocks.snowblock;
|
||||
}else if(prefs.get("allsand")){
|
||||
block = floor ? Blocks.sand : Blocks.sandblock;
|
||||
}else if(prefs.get("replace")){
|
||||
block = floor ? Blocks.stone : Blocks.stoneblock;
|
||||
}
|
||||
|
||||
if(noise > 0.7 && prefs.get("grass")){
|
||||
block = floor ? Blocks.grass : Blocks.grassblock;
|
||||
}
|
||||
if(noise > 0.7 && prefs.get("lavarock")){
|
||||
block = floor ? Blocks.blackstone : Blocks.blackstoneblock;
|
||||
}
|
||||
if(noise > 0.7 && prefs.get("sand")){
|
||||
block = floor ? Blocks.sand : Blocks.sandblock;
|
||||
}
|
||||
if(noise > 0.8 && prefs.get("stone")){
|
||||
block = floor ? Blocks.stone : Blocks.stoneblock;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor){
|
||||
if(nwater > 0.93 && prefs.get("water")){
|
||||
block = Blocks.water;
|
||||
if(nwater > 0.943){
|
||||
block = Blocks.deepwater;
|
||||
}
|
||||
}
|
||||
|
||||
if(noil > 0.95 && prefs.get("oil")){
|
||||
block = Blocks.dirt;
|
||||
if(noil > 0.955){
|
||||
block = Blocks.oil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("lavariver")){
|
||||
double lava = rid.getValue(x, y, 1 / 100f);
|
||||
double t = 0.6;
|
||||
if(lava > t){
|
||||
block = Blocks.lava;
|
||||
}else if(lava > t - 0.2){
|
||||
block = Blocks.blackstone;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("slavariver")){
|
||||
double lava = rid.getValue(x, y, 1 / 40f);
|
||||
double t = 0.7;
|
||||
if(lava > t){
|
||||
block = Blocks.lava;
|
||||
}else if(lava > t - 0.3){
|
||||
block = Blocks.blackstone;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("oilriver")){
|
||||
double lava = rid3.getValue(x, y, 1 / 100f);
|
||||
double t = 0.9;
|
||||
if(lava > t){
|
||||
block = Blocks.oil;
|
||||
}else if(lava > t - 0.2){
|
||||
block = Blocks.dirt;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("river")){
|
||||
double riv = rid2.getValue(x, y, 1 / 140f);
|
||||
double t = 0.4;
|
||||
|
||||
if(riv > t + 0.1){
|
||||
block = Blocks.deepwater;
|
||||
}else if(riv > t){
|
||||
block = Blocks.water;
|
||||
}else if(riv > t - 0.2){
|
||||
block = Blocks.grass;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("iceriver")){
|
||||
double riv = rid2.getValue(x, y, 1 / 140f);
|
||||
double t = 0.4;
|
||||
|
||||
if(riv > t + 0.1){
|
||||
block = Blocks.ice;
|
||||
}else if(riv > t){
|
||||
block = Blocks.ice;
|
||||
}else if(riv > t - 0.2){
|
||||
block = Blocks.snow;
|
||||
}
|
||||
}
|
||||
|
||||
pixmap.drawPixel(x, y, ColorMapper.getColor(block));
|
||||
}
|
||||
}
|
||||
|
||||
src.dispose();
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
}
|
66
core/src/io/anuke/mindustry/mapeditor/MapView.java
Normal file
@ -0,0 +1,66 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.math.Bresenham2;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.event.InputEvent;
|
||||
import io.anuke.ucore.scene.event.InputListener;
|
||||
import io.anuke.ucore.util.Tmp;
|
||||
|
||||
public class MapView extends Element{
|
||||
private MapEditor editor;
|
||||
private Bresenham2 br = new Bresenham2();
|
||||
|
||||
public MapView(MapEditor editor){
|
||||
this.editor = editor;
|
||||
addListener(new InputListener(){
|
||||
int lastx, lasty;
|
||||
boolean drawing;
|
||||
|
||||
@Override
|
||||
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
|
||||
GridPoint2 p = project(x, y);
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
editor.draw(p.x, p.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
|
||||
drawing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchDragged (InputEvent event, float x, float y, int pointer) {
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
if(drawing){
|
||||
Array<GridPoint2> points = br.line(lastx, lasty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
}
|
||||
}
|
||||
drawing = true;
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private GridPoint2 project(float x, float y){
|
||||
float size = Math.min(width, height);
|
||||
x = (x - getWidth()/2 + size/2) / size * editor.texture().getWidth();
|
||||
y = (y - getHeight()/2 + size/2) / size * editor.texture().getHeight();
|
||||
return Tmp.g1.set((int)x, editor.texture().getHeight() - 1 - (int)y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
float size = Math.min(width, height);
|
||||
batch.draw(editor.texture(), x + width/2 - size/2, y + height/2 - size/2, size, size);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.scene.utils.Elements;
|
||||
|
||||
public class LevelDialog extends FloatingDialog{
|
||||
private Map selectedMap = Map.maze;
|
||||
private Map selectedMap = Vars.world.maps().getMap(0);
|
||||
private TextureRegion region = new TextureRegion();
|
||||
|
||||
public LevelDialog(){
|
||||
@ -49,8 +49,8 @@ public class LevelDialog extends FloatingDialog{
|
||||
content().add(selmode);
|
||||
content().row();
|
||||
|
||||
for(int i = 0; i < Map.values().length; i ++){
|
||||
Map map = Map.values()[i];
|
||||
int i = 0;
|
||||
for(Map map : Vars.world.maps().list()){
|
||||
|
||||
if(!map.visible && !Vars.debug) continue;
|
||||
|
||||
@ -59,9 +59,9 @@ public class LevelDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
Table inset = new Table("pane-button");
|
||||
inset.add("[accent]"+map.name()).pad(3f).units(Unit.dp);
|
||||
inset.add("[accent]"+map.name).pad(3f).units(Unit.dp);
|
||||
inset.row();
|
||||
inset.add((StringSupplier)(()->"High Score: [accent]" + Settings.getInt("hiscore" + map.name())))
|
||||
inset.add((StringSupplier)(()->"High Score: [accent]" + Settings.getInt("hiscore" + map.name)))
|
||||
.pad(3f).units(Unit.dp);
|
||||
inset.pack();
|
||||
|
||||
@ -72,7 +72,7 @@ public class LevelDialog extends FloatingDialog{
|
||||
Image back = new Image("white");
|
||||
back.setColor(map.backgroundColor);
|
||||
|
||||
ImageButton image = new ImageButton(new TextureRegion(Vars.world.getTexture(map)), "togglemap");
|
||||
ImageButton image = new ImageButton(new TextureRegion(map.texture), "togglemap");
|
||||
image.row();
|
||||
image.add(inset).width(images+6).units(Unit.dp);
|
||||
image.clicked(()->{
|
||||
@ -88,6 +88,8 @@ public class LevelDialog extends FloatingDialog{
|
||||
maps.add(stack).width(170).pad(4f).units(Unit.dp);
|
||||
|
||||
maps.padRight(Unit.dp.inPixels(26));
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
content().add(pane).uniformX();
|
||||
|
@ -55,7 +55,9 @@ public class LoadDialog extends FloatingDialog{
|
||||
|
||||
button.row();
|
||||
|
||||
Label info = new Label("[gray]" + (!SaveIO.isSaveValid(i) ? "<empty>" : SaveIO.getMode(slot) + ", " + SaveIO.getMap(slot) + ", Wave " + SaveIO.getWave(slot) + "\nLast Saved: " + SaveIO.getTimeString(i)));
|
||||
Label info = new Label("[gray]" + (!SaveIO.isSaveValid(i) ? "<empty>" : SaveIO.getMode(slot) + ", "
|
||||
+ SaveIO.getMap(slot).name + ", Wave " + SaveIO.getWave(slot)
|
||||
+ "\nLast Saved: " + SaveIO.getTimeString(i)));
|
||||
info.setAlignment(Align.center, Align.center);
|
||||
|
||||
button.add(info).padBottom(3).padTop(7);
|
||||
|
@ -1,5 +0,0 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
public class MapEditor{
|
||||
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
|
||||
import io.anuke.mindustry.Mindustry;
|
||||
@ -7,16 +9,10 @@ import io.anuke.mindustry.core.GameState;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.ui.MenuButton;
|
||||
import io.anuke.mindustry.ui.PressGroup;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
|
||||
import static io.anuke.mindustry.Vars.android;
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.gwt;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class MenuFragment implements Fragment{
|
||||
|
||||
public void build(){
|
||||
@ -30,22 +26,25 @@ public class MenuFragment implements Fragment{
|
||||
float scale = 4f;
|
||||
defaults().size(100*scale, 21*scale).pad(-10f).units(Unit.dp);
|
||||
|
||||
add(new MenuButton("text-play", group, ()-> ui.showLevels()));
|
||||
add(new MenuButton("text-play", group, ui::showLevels));
|
||||
row();
|
||||
|
||||
add(new MenuButton("text-tutorial", group, ()-> control.playMap(Map.tutorial)));
|
||||
add(new MenuButton("text-tutorial", group, ()-> control.playMap(world.maps().getMap("tutorial"))));
|
||||
row();
|
||||
|
||||
if(!gwt){
|
||||
add(new MenuButton("text-load", group, ()-> ui.showLoadGame()));
|
||||
add(new MenuButton("text-load", group, ui::showLoadGame));
|
||||
row();
|
||||
|
||||
add(new MenuButton("text-editor", group, ui::showEditor));
|
||||
row();
|
||||
}
|
||||
|
||||
add(new MenuButton("text-settings", group, ()-> ui.showPrefs()));
|
||||
add(new MenuButton("text-settings", group, ui::showPrefs));
|
||||
row();
|
||||
|
||||
if(!gwt){
|
||||
add(new MenuButton("text-exit", group, ()-> Gdx.app.exit()));
|
||||
add(new MenuButton("text-exit", group, Gdx.app::exit));
|
||||
}
|
||||
get().pad(Unit.dp.inPixels(16));
|
||||
}}.end();
|
||||
@ -60,10 +59,14 @@ public class MenuFragment implements Fragment{
|
||||
|
||||
new imagebutton("icon-play-2", isize, () -> ui.showLevels()).text("Play").padTop(4f);
|
||||
|
||||
new imagebutton("icon-tutorial", isize, ()-> control.playMap(Map.tutorial)).text("Tutorial").padTop(4f);
|
||||
new imagebutton("icon-tutorial", isize, () -> control.playMap(world.maps().getMap("tutorial"))).text("Tutorial").padTop(4f);
|
||||
|
||||
new imagebutton("icon-load", isize, () -> ui.showLoadGame()).text("Load").padTop(4f);
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-terrain", isize, () -> ui.showEditor()).text("Editor").padTop(4f);
|
||||
|
||||
new imagebutton("icon-tools", isize, () -> ui.showPrefs()).text("Settings").padTop(4f);
|
||||
|
||||
if(Mindustry.donationsCallable != null){
|
||||
|
77
core/src/io/anuke/mindustry/world/ColorMapper.java
Normal file
@ -0,0 +1,77 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.IntMap.Entry;
|
||||
import com.badlogic.gdx.utils.ObjectIntMap;
|
||||
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
|
||||
public class ColorMapper{
|
||||
private static ObjectIntMap<Block> reverseColors = new ObjectIntMap<>();
|
||||
private static Array<BlockPair> pairs = new Array<>();
|
||||
private static IntMap<BlockPair> colors = map(
|
||||
"323232", pair(Blocks.stone),
|
||||
"646464", pair(Blocks.stone, Blocks.stoneblock),
|
||||
"50965a", pair(Blocks.grass),
|
||||
"5ab464", pair(Blocks.grass, Blocks.grassblock),
|
||||
"506eb4", pair(Blocks.water),
|
||||
"465a96", pair(Blocks.deepwater),
|
||||
"252525", pair(Blocks.blackstone),
|
||||
"575757", pair(Blocks.blackstone, Blocks.blackstoneblock),
|
||||
"988a67", pair(Blocks.sand),
|
||||
"e5d8bb", pair(Blocks.sand, Blocks.sandblock),
|
||||
"c2d1d2", pair(Blocks.snow),
|
||||
"c4e3e7", pair(Blocks.ice),
|
||||
"f7feff", pair(Blocks.snow, Blocks.snowblock),
|
||||
"6e501e", pair(Blocks.dirt),
|
||||
"ed5334", pair(Blocks.lava),
|
||||
"292929", pair(Blocks.oil)
|
||||
);
|
||||
|
||||
public static BlockPair get(int color){
|
||||
return colors.get(color);
|
||||
}
|
||||
|
||||
public static IntMap<BlockPair> getColors(){
|
||||
return colors;
|
||||
}
|
||||
|
||||
public static Array<BlockPair> getPairs(){
|
||||
return pairs;
|
||||
}
|
||||
|
||||
public static int getColor(Block block){
|
||||
return reverseColors.get(block, 0);
|
||||
}
|
||||
|
||||
private static BlockPair pair(Block floor, Block wall){
|
||||
return new BlockPair(floor, wall);
|
||||
}
|
||||
|
||||
private static BlockPair pair(Block floor){
|
||||
return new BlockPair(floor, Blocks.air);
|
||||
}
|
||||
|
||||
private static IntMap<BlockPair> map(Object...objects){
|
||||
IntMap<BlockPair> colors = new IntMap<>();
|
||||
for(int i = 0; i < objects.length/2; i ++){
|
||||
colors.put(Color.rgba8888(Color.valueOf((String)objects[i*2])), (BlockPair)objects[i*2+1]);
|
||||
pairs.add((BlockPair)objects[i*2+1]);
|
||||
}
|
||||
for(Entry<BlockPair> e : colors.entries()){
|
||||
reverseColors.put(e.value.wall == Blocks.air ? e.value.floor : e.value.wall, e.key);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
public static class BlockPair{
|
||||
public final Block floor, wall;
|
||||
|
||||
private BlockPair(Block floor, Block wall){
|
||||
this.floor = floor;
|
||||
this.wall = wall;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,42 +2,26 @@ package io.anuke.mindustry.world;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.enemies.TargetEnemy;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.graphics.Hue;
|
||||
import io.anuke.ucore.noise.Noise;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class Generator{
|
||||
public static boolean debugBlockspam = false;
|
||||
|
||||
static final int spawn = Color.rgba8888(Color.RED);
|
||||
static final int start = Color.rgba8888(Color.GREEN);
|
||||
|
||||
public static IntMap<Block> colors = map(
|
||||
Hue.rgb(80, 150, 90), Blocks.grass,
|
||||
Hue.rgb(90, 180, 100), Blocks.grassblock,
|
||||
Hue.rgb(80, 110, 180), Blocks.water,
|
||||
Hue.rgb(70, 90, 150), Blocks.deepwater,
|
||||
Hue.rgb(110, 80, 30), Blocks.dirt,
|
||||
Hue.rgb(160, 120, 70), Blocks.dirtblock,
|
||||
Hue.rgb(100, 100, 100), Blocks.stoneblock,
|
||||
Color.valueOf("323232"), Blocks.stone,
|
||||
Color.valueOf("575757"), Blocks.blackstoneblock,
|
||||
Color.valueOf("252525"), Blocks.blackstone,
|
||||
Color.valueOf("ed5334"), Blocks.lava,
|
||||
Color.valueOf("292929"), Blocks.oil,
|
||||
Color.valueOf("e5d8bb"), Blocks.sandblock,
|
||||
Color.valueOf("988a67"), Blocks.sand,
|
||||
Color.valueOf("f7feff"), Blocks.snowblock,
|
||||
Color.valueOf("c2d1d2"), Blocks.snow,
|
||||
Color.valueOf("c4e3e7"), Blocks.ice
|
||||
);
|
||||
static final ObjectMap<Block, Block> rocks = new ObjectMap(){{
|
||||
put(Blocks.stone, Blocks.rock);
|
||||
put(Blocks.snow, Blocks.icerock);
|
||||
put(Blocks.grass, Blocks.shrub);
|
||||
put(Blocks.blackstone, Blocks.blackrock);
|
||||
}};
|
||||
|
||||
/**Returns world size.*/
|
||||
public static void generate(Pixmap pixmap, Tile[][] tiles){
|
||||
@ -50,14 +34,11 @@ public class Generator{
|
||||
Block block = Blocks.air;
|
||||
|
||||
int color = pixmap.getPixel(x, pixmap.getHeight()-1-y);
|
||||
BlockPair pair = ColorMapper.get(color);
|
||||
|
||||
if(colors.containsKey(color)){
|
||||
//TODO less hacky method
|
||||
if(!(colors.get(color) instanceof Floor)){
|
||||
block = colors.get(color);
|
||||
}else{
|
||||
floor = colors.get(color);
|
||||
}
|
||||
if(pair != null){
|
||||
block = pair.wall;
|
||||
floor = pair.floor;
|
||||
}else if(color == start){
|
||||
Vars.control.setCore(Vars.world.tile(x, y));
|
||||
}else if(color == spawn){
|
||||
@ -65,18 +46,8 @@ public class Generator{
|
||||
floor = Blocks.dirt;
|
||||
}
|
||||
|
||||
if(block == Blocks.air){
|
||||
if(floor == Blocks.stone && Mathf.chance(0.02)){
|
||||
block = Blocks.rock;
|
||||
}
|
||||
|
||||
if(floor == Blocks.snow && Mathf.chance(0.02)){
|
||||
block = Blocks.icerock;
|
||||
}
|
||||
|
||||
if(floor == Blocks.blackstone && Mathf.chance(0.03)){
|
||||
block = Blocks.blackrock;
|
||||
}
|
||||
if(block == Blocks.air && Mathf.chance(0.025) && rocks.containsKey(floor)){
|
||||
block = rocks.get(floor);
|
||||
}
|
||||
|
||||
if(floor == Blocks.stone || floor == Blocks.grass || floor == Blocks.blackstone ||
|
||||
@ -98,32 +69,11 @@ public class Generator{
|
||||
}
|
||||
}
|
||||
|
||||
if(block == Blocks.grassblock){
|
||||
floor = Blocks.grass;
|
||||
}
|
||||
|
||||
if(block == Blocks.snowblock){
|
||||
floor = Blocks.snow;
|
||||
}
|
||||
|
||||
if(block == Blocks.sandblock){
|
||||
floor = Blocks.sand;
|
||||
}
|
||||
|
||||
if(floor == Blocks.grass && Mathf.chance(0.03) && block == Blocks.air){
|
||||
block = Blocks.shrub;
|
||||
}
|
||||
|
||||
if(color == Hue.rgb(Color.PURPLE)){
|
||||
if(!Vars.android) new TargetEnemy().set(x * Vars.tilesize, y * Vars.tilesize).add();
|
||||
floor = Blocks.stone;
|
||||
}
|
||||
|
||||
//preformance debugging
|
||||
if(debugBlockspam && Vector2.dst(0, 0, x, y) < 260){
|
||||
block = Mathf.choose(ProductionBlocks.omnidrill, DistributionBlocks.conveyor, DistributionBlocks.router, WeaponBlocks.turret);
|
||||
}
|
||||
|
||||
tiles[x][y].setBlock(block, 0);
|
||||
tiles[x][y].setFloor(floor);
|
||||
}
|
||||
|
@ -1,49 +1,25 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
|
||||
public enum Map{
|
||||
maze("desc"),
|
||||
fortress("desc"),
|
||||
sinkhole("desc"),
|
||||
caves("desc"),
|
||||
volcano("desc", true),
|
||||
caldera("desc"),
|
||||
scorch("desc", Color.valueOf("e5d8bb")),
|
||||
desert("desc"),
|
||||
islands("desc", Color.valueOf("e5d8bb")),
|
||||
grassland("desc", Color.valueOf("5ab464")),
|
||||
tundra("desc"),
|
||||
spiral("desc", Color.valueOf("f7feff")),
|
||||
tutorial(false),
|
||||
test1(false),
|
||||
test2(false),
|
||||
test3(false);
|
||||
|
||||
public final boolean visible;
|
||||
public final String description;
|
||||
public final boolean flipBase;
|
||||
public int width, height;
|
||||
public class Map{
|
||||
public int id;
|
||||
public String name;
|
||||
public boolean visible = true;
|
||||
public boolean flipBase = false;
|
||||
public boolean custom = false;
|
||||
public Color backgroundColor = Color.valueOf("646464");
|
||||
|
||||
private Map(boolean visible){
|
||||
this.visible = visible;
|
||||
this.flipBase = false;
|
||||
this.description = "Test map!";
|
||||
public transient Pixmap pixmap;
|
||||
public transient Texture texture;
|
||||
|
||||
public int getWidth(){
|
||||
return pixmap.getWidth();
|
||||
}
|
||||
|
||||
private Map(String description){
|
||||
this(description, false);
|
||||
}
|
||||
|
||||
private Map(String description, boolean flipBase){
|
||||
this.visible = true;
|
||||
this.flipBase = flipBase;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
private Map(String description, Color background){
|
||||
this(description);
|
||||
backgroundColor = background;
|
||||
public int getHeight(){
|
||||
return pixmap.getHeight();
|
||||
}
|
||||
}
|
||||
|
119
core/src/io/anuke/mindustry/world/Maps.java
Normal file
@ -0,0 +1,119 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.*;
|
||||
import com.badlogic.gdx.utils.Json.Serializer;
|
||||
import com.badlogic.gdx.utils.JsonWriter.OutputType;
|
||||
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
|
||||
public class Maps implements Disposable{
|
||||
private IntMap<Map> maps = new IntMap<>();
|
||||
private ObjectMap<String, Map> mapNames = new ObjectMap<>();
|
||||
private int lastID;
|
||||
private Json json = new Json();
|
||||
|
||||
public Maps() {
|
||||
json.setOutputType(OutputType.json);
|
||||
json.setElementType(ArrayContainer.class, "maps", Map.class);
|
||||
json.setSerializer(Color.class, new ColorSerializer());
|
||||
}
|
||||
|
||||
public Iterable<Map> list(){
|
||||
return maps.values();
|
||||
}
|
||||
|
||||
public Map getMap(int id){
|
||||
return maps.get(id);
|
||||
}
|
||||
|
||||
public Map getMap(String name){
|
||||
return mapNames.get(name);
|
||||
}
|
||||
|
||||
public void loadMaps(){
|
||||
if(!loadMapFile(Gdx.files.internal("maps/maps.json"))){
|
||||
throw new RuntimeException("Failed to load maps!");
|
||||
}
|
||||
|
||||
if(!loadMapFile(Vars.customMapDirectory.child("maps.json"))){
|
||||
try{
|
||||
Vars.customMapDirectory.child("maps.json").writeString("{}", false);
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException("Failed to create custom map directory!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveMaps(Array<Map> array, FileHandle file){
|
||||
json.toJson(new ArrayContainer(array), file);
|
||||
}
|
||||
|
||||
public void saveCustomMap(Map toSave){
|
||||
Array<Map> out = new Array<>();
|
||||
for(Map map : maps.values()){
|
||||
if(map.custom)
|
||||
out.add(map);
|
||||
}
|
||||
Pixmaps.write(toSave.pixmap, Vars.customMapDirectory.child(toSave.name + ".png"));
|
||||
saveMaps(out, Vars.customMapDirectory.child("maps.json"));
|
||||
}
|
||||
|
||||
private boolean loadMapFile(FileHandle file){
|
||||
try{
|
||||
Array<Map> arr = json.fromJson(ArrayContainer.class, file).maps;
|
||||
if(arr != null){ //can be an empty map file
|
||||
for(Map map : arr){
|
||||
map.pixmap = new Pixmap(file.sibling(map.name + ".png"));
|
||||
map.texture = new Texture(map.pixmap);
|
||||
maps.put(map.id, map);
|
||||
mapNames.put(map.name, map);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
Gdx.app.error("Mindustry-Maps", "Failed loading map file: " + file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
for(Map map : maps.values()){
|
||||
map.texture.dispose();
|
||||
map.pixmap.dispose();
|
||||
}
|
||||
maps.clear();
|
||||
}
|
||||
|
||||
private static class ArrayContainer{
|
||||
Array<Map> maps;
|
||||
|
||||
ArrayContainer() {
|
||||
}
|
||||
|
||||
ArrayContainer(Array<Map> maps) {
|
||||
this.maps = maps;
|
||||
}
|
||||
}
|
||||
|
||||
private class ColorSerializer implements Serializer<Color>{
|
||||
|
||||
@Override
|
||||
public void write(Json json, Color object, Class knownType){
|
||||
json.writeValue(object.toString().substring(0, 6));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color read(Json json, JsonValue jsonData, Class type){
|
||||
return Color.valueOf(jsonData.asString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1
desktop/mindustry-maps/maps.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -23,7 +23,7 @@ public class DesktopLauncher {
|
||||
config.setMaximized(true);
|
||||
config.setWindowedMode(960, 540);
|
||||
config.setWindowIcon("sprites/icon.png");
|
||||
config.useVsync(false);
|
||||
config.useVsync(true);
|
||||
|
||||
Mindustry.platforms = new PlatformFunction(){
|
||||
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm");
|
||||
|