diff --git a/.gitignore b/.gitignore index 17c1aab8e5..8017b41b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ changelog *.gif /core/assets/saves/ /out/ +/core/assets-raw/fontgen/out/ version.properties diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index 6faa60a9ee..2070f7c93b 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -144,7 +144,6 @@ public class AndroidLauncher extends AndroidApplication{ }, new AndroidApplicationConfiguration(){{ useImmersiveMode = true; - depth = 0; hideStatusBar = true; errorHandler = CrashSender::log; }}); diff --git a/build.gradle b/build.gradle index 113ef06226..f8dc4a97c2 100644 --- a/build.gradle +++ b/build.gradle @@ -249,6 +249,7 @@ project(":core"){ compile "org.lz4:lz4-java:1.4.1" compile arcModule("arc-core") compile arcModule("extensions:freetype") + compile arcModule("extensions:g3d") compile arcModule("extensions:arcnet") compile "org.mozilla:rhino:1.7.11" if(localArc() && debugged()) compile arcModule("extensions:recorder") diff --git a/core/assets-raw/sprites/blocks/environment/slag.png b/core/assets-raw/sprites/blocks/environment/slag.png new file mode 100644 index 0000000000..1467a11fa5 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/slag.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 8d7cd69fc5..15b6910930 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -394,6 +394,8 @@ toolmode.drawteams.description = Draw teams instead of blocks. filters.empty = [lightgray]No filters! Add one with the button below. filter.distort = Distort filter.noise = Noise +filter.enemyspawn = Enemy Spawn Select +filter.corespawn = Core Select filter.median = Median filter.oremedian = Ore Median filter.blend = Blend @@ -413,6 +415,7 @@ filter.option.circle-scale = Circle Scale filter.option.octaves = Octaves filter.option.falloff = Falloff filter.option.angle = Angle +filter.option.amount = Amount filter.option.block = Block filter.option.floor = Floor filter.option.flooronto = Target Floor @@ -850,6 +853,7 @@ liquid.temperature = [lightgray]Temperature: {0} block.sand-boulder.name = Sand Boulder block.grass.name = Grass +block.slag.name = Slag block.salt.name = Salt block.saltrocks.name = Salt Rocks block.pebbles.name = Pebbles diff --git a/core/assets/planets/colors.png b/core/assets/planets/colors.png new file mode 100644 index 0000000000..5efd5d38e0 Binary files /dev/null and b/core/assets/planets/colors.png differ diff --git a/core/assets/shaders/planet.fragment.glsl b/core/assets/shaders/planet.fragment.glsl new file mode 100755 index 0000000000..17602c704f --- /dev/null +++ b/core/assets/shaders/planet.fragment.glsl @@ -0,0 +1,9 @@ +#ifdef GL_ES +precision mediump float; +#endif + +varying vec4 v_col; + +void main(){ + gl_FragColor = v_col; +} diff --git a/core/assets/shaders/planet.vertex.glsl b/core/assets/shaders/planet.vertex.glsl new file mode 100755 index 0000000000..db8e3e130c --- /dev/null +++ b/core/assets/shaders/planet.vertex.glsl @@ -0,0 +1,18 @@ +attribute vec4 a_position; +attribute vec3 a_normal; +attribute vec4 a_color; +uniform mat4 u_projModelView; +varying vec4 v_col; + +const vec3 ambientColor = vec3(1.0); +const vec3 ambientDir = normalize(vec3(1.0, 1.0, 1.0)); +const vec3 diffuse = vec3(0.5); +const vec3 v1 = vec3(1.0, 0.0, 1.0); +const vec3 v2 = vec3(1.0, 0.5, 0.0); + +void main(){ + vec3 norc = ambientColor * clamp((dot(a_normal, ambientDir) + 1.0) / 2.0, 0.0, 1.0); + + v_col = a_color * vec4(norc, 1.0); + gl_Position = u_projModelView * a_position; +} diff --git a/core/assets/shaders/slag.fragment.glsl b/core/assets/shaders/slag.fragment.glsl new file mode 100755 index 0000000000..afb161de6d --- /dev/null +++ b/core/assets/shaders/slag.fragment.glsl @@ -0,0 +1,86 @@ +#ifdef GL_ES +precision highp float; +precision mediump int; +#endif + +//shade 1 + 2 +#define s2 vec3(100.0, 93.0, 49.0) / 100.0 +#define s1 vec3(100.0, 60.0, 25.0) / 100.0 + +uniform sampler2D u_texture; + +uniform vec2 camerapos; +uniform vec2 screensize; +uniform float time; + +varying vec4 v_color; +varying vec2 v_texCoord; + +vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); } + +float snoise(vec2 v){ + const vec4 C = vec4(0.211324865405187, 0.366025403784439, + -0.577350269189626, 0.024390243902439); + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + i = mod(i, 289.0); + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), + dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} + +void main(){ + + vec2 c = v_texCoord.xy; + vec4 color = texture2D(u_texture, c); + + vec2 v = vec2(1.0/screensize.x, 1.0/screensize.y); + vec2 coords = c / v + camerapos; + + float stime = time / 5.0; + + float mscl = 30.0; + float mth = 5.0; + + //if there's something actually there + if(color.r > 0.01){ + vec4 old = color; + color = texture2D(u_texture, c + vec2(sin(stime/3.0 + coords.y/0.75) * v.x, 0.0)) * vec4(0.9, 0.9, 1, 1.0); + + if(color.r < 0.01){ + color = old; + } + + const float bs = 1.1; + + float n1 = snoise(coords / (30.0 * bs) + vec2(time) / 280.0); + float n2 = snoise((coords + vec2(632.0)) / (14.0 * bs) + vec2(0.0, -time) / 290.0); + float n3 = snoise((coords + vec2(2233.0)) / (25.0 * bs) + vec2(time, 0.0) / 380.0); + + float r = (n1 + n2 + n3) / 3.0; + + if(r < -0.5){ + color = vec4(s2, color.a); + }else if(r < -0.2){ + color = vec4(s1, color.a); + } + } + + gl_FragColor = color; +} diff --git a/core/assets/sprites/sprites2.png b/core/assets/sprites/sprites2.png index 1776b09b12..8fe2b79b25 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/src/mindustry/ClientLauncher.java b/core/src/mindustry/ClientLauncher.java index d1819b3a8f..6c5909a798 100644 --- a/core/src/mindustry/ClientLauncher.java +++ b/core/src/mindustry/ClientLauncher.java @@ -90,10 +90,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform assets.load(mods); assets.load(schematics); - assets.loadRun("contentinit", ContentLoader.class, () -> { - content.init(); - content.load(); - }); + assets.loadRun("contentinit", ContentLoader.class, () -> content.init(), () -> content.load()); } @Override diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 1c33a1a1fc..b22e72ea21 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -33,7 +33,7 @@ public class Blocks implements ContentList{ public static Block //environment - air, spawn, deepwater, water, taintedWater, tar, stone, craters, charr, sand, darksand, ice, snow, darksandTaintedWater, + air, spawn, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, ice, snow, darksandTaintedWater, holostone, rocks, sporerocks, icerocks, cliffs, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, iceSnow, sandWater, darksandWater, duneRocks, sandRocks, moss, sporeMoss, shale, shaleRocks, shaleBoulder, sandBoulder, grass, salt, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks, rock, snowrock, saltRocks, @@ -202,6 +202,17 @@ public class Blocks implements ContentList{ cacheLayer = CacheLayer.tar; }}; + slag = new Floor("slag"){{ + drownTime = 150f; + status = StatusEffects.melting; + statusDuration = 240f; + speedMultiplier = 0.19f; + variants = 0; + liquidDrop = Liquids.slag; + isLiquid = true; + cacheLayer = CacheLayer.slag; + }}; + stone = new Floor("stone"){{ }}; diff --git a/core/src/mindustry/content/Planets.java b/core/src/mindustry/content/Planets.java new file mode 100644 index 0000000000..c3812268d6 --- /dev/null +++ b/core/src/mindustry/content/Planets.java @@ -0,0 +1,18 @@ +package mindustry.content; + +import mindustry.ctype.*; +import mindustry.maps.planet.*; +import mindustry.type.*; + +public class Planets implements ContentList{ + //TODO make all names + public static Planet starter; + + @Override + public void load(){ + starter = new Planet("//TODO"){{ + detail = 6; + generator = new TestPlanetGenerator(); + }}; + } +} diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java new file mode 100644 index 0000000000..6b08fd12a9 --- /dev/null +++ b/core/src/mindustry/content/Weathers.java @@ -0,0 +1,15 @@ +package mindustry.content; + +import mindustry.ctype.*; +import mindustry.type.*; + +public class Weathers implements ContentList{ + public static Weather + rain, + snow; + + @Override + public void load(){ + + } +} diff --git a/core/src/mindustry/content/Zones.java b/core/src/mindustry/content/Zones.java index 1bc988f955..0c337151b9 100644 --- a/core/src/mindustry/content/Zones.java +++ b/core/src/mindustry/content/Zones.java @@ -1,15 +1,15 @@ package mindustry.content; -import mindustry.ctype.ContentList; -import mindustry.game.*; +import mindustry.ctype.*; import mindustry.game.Objectives.*; +import mindustry.game.*; import mindustry.maps.generators.*; -import mindustry.maps.generators.MapGenerator.*; import mindustry.maps.zonegen.*; import mindustry.type.*; import static arc.struct.Array.with; import static mindustry.content.Items.*; +import static mindustry.content.Planets.starter; import static mindustry.type.ItemStack.list; public class Zones implements ContentList{ @@ -22,7 +22,7 @@ public class Zones implements ContentList{ @Override public void load(){ - groundZero = new Zone("groundZero", new MapGenerator("groundZero", 1)){{ + groundZero = new Zone("groundZero", starter, new MapGenerator("groundZero")){{ baseLaunchCost = list(copper, -60); startingItems = list(copper, 60); alwaysUnlocked = true; @@ -31,7 +31,7 @@ public class Zones implements ContentList{ resources = with(copper, scrap, lead); }}; - desertWastes = new Zone("desertWastes", new DesertWastesGenerator(260, 260)){{ + desertWastes = new Zone("desertWastes", starter, new DesertWastesGenerator(260, 260)){{ startingItems = list(copper, 120); conditionWave = 20; launchPeriod = 10; @@ -82,7 +82,7 @@ public class Zones implements ContentList{ ); }}; - saltFlats = new Zone("saltFlats", new MapGenerator("saltFlats")){{ + saltFlats = new Zone("saltFlats", starter, new MapGenerator("saltFlats")){{ startingItems = list(copper, 200, Items.silicon, 200, lead, 200); loadout = Loadouts.basicFoundation; conditionWave = 10; @@ -98,8 +98,7 @@ public class Zones implements ContentList{ ); }}; - frozenForest = new Zone("frozenForest", new MapGenerator("frozenForest", 1) - .decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.02))){{ + frozenForest = new Zone("frozenForest", starter, new MapGenerator("frozenForest")){{ loadout = Loadouts.basicFoundation; startingItems = list(copper, 250); conditionWave = 10; @@ -111,7 +110,7 @@ public class Zones implements ContentList{ ); }}; - craters = new Zone("craters", new MapGenerator("craters", 1).decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.004))){{ + craters = new Zone("craters", starter, new MapGenerator("craters")){{ startingItems = list(copper, 100); conditionWave = 10; resources = with(copper, lead, coal, sand, scrap); @@ -122,7 +121,7 @@ public class Zones implements ContentList{ ); }}; - ruinousShores = new Zone("ruinousShores", new MapGenerator("ruinousShores", 1)){{ + ruinousShores = new Zone("ruinousShores", starter, new MapGenerator("ruinousShores")){{ loadout = Loadouts.basicFoundation; startingItems = list(copper, 140, lead, 50); conditionWave = 20; @@ -138,8 +137,7 @@ public class Zones implements ContentList{ ); }}; - stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2) - .decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{ + stainedMountains = new Zone("stainedMountains", starter, new MapGenerator("stainedMountains")){{ loadout = Loadouts.basicFoundation; startingItems = list(copper, 200, lead, 50); conditionWave = 10; @@ -153,7 +151,7 @@ public class Zones implements ContentList{ ); }}; - fungalPass = new Zone("fungalPass", new MapGenerator("fungalPass")){{ + fungalPass = new Zone("fungalPass", starter, new MapGenerator("fungalPass")){{ startingItems = list(copper, 250, lead, 250, Items.metaglass, 100, Items.graphite, 100); resources = with(copper, lead, coal, titanium, sand); configureObjective = new Launched(this); @@ -166,7 +164,7 @@ public class Zones implements ContentList{ ); }}; - overgrowth = new Zone("overgrowth", new MapGenerator("overgrowth")){{ + overgrowth = new Zone("overgrowth", starter, new MapGenerator("overgrowth")){{ startingItems = list(copper, 1500, lead, 1000, Items.silicon, 500, Items.metaglass, 250); conditionWave = 12; launchPeriod = 4; @@ -183,8 +181,7 @@ public class Zones implements ContentList{ ); }}; - tarFields = new Zone("tarFields", new MapGenerator("tarFields") - .decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{ + tarFields = new Zone("tarFields", starter, new MapGenerator("tarFields")){{ loadout = Loadouts.basicFoundation; startingItems = list(copper, 250, lead, 100); conditionWave = 15; @@ -198,7 +195,7 @@ public class Zones implements ContentList{ ); }}; - desolateRift = new Zone("desolateRift", new MapGenerator("desolateRift")){{ + desolateRift = new Zone("desolateRift", starter, new MapGenerator("desolateRift")){{ loadout = Loadouts.basicNucleus; startingItems = list(copper, 1000, lead, 1000, Items.graphite, 250, titanium, 250, Items.silicon, 250); conditionWave = 3; @@ -223,8 +220,7 @@ public class Zones implements ContentList{ resources = Array.with(Items.copper, Items.scrap, Items.lead, Items.coal, Items.sand}; }};*/ - nuclearComplex = new Zone("nuclearComplex", new MapGenerator("nuclearProductionComplex", 1) - .decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ + nuclearComplex = new Zone("nuclearComplex", starter, new MapGenerator("nuclearProductionComplex")){{ loadout = Loadouts.basicNucleus; startingItems = list(copper, 1250, lead, 1500, Items.silicon, 400, Items.metaglass, 250); conditionWave = 30; diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index dc1e21e917..0a1d9c1db2 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -39,6 +39,8 @@ public class ContentLoader{ new Blocks(), new Loadouts(), new TechTree(), + new Weathers(), + new Planets(), new Zones(), new TypeIDs(), diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 45aea7a816..b988dc969a 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -249,7 +249,9 @@ public class Control implements ApplicationListener, Loadable{ }); } - public void playZone(Zone zone){ + //TODO remove, make it viable on a server + /*public void playZone(Zone zone){ + ui.loadAnd(() -> { logic.reset(); net.reset(); @@ -267,6 +269,16 @@ public class Control implements ApplicationListener, Loadable{ logic.play(); Events.fire(Trigger.newGame); }); + }*/ + + public void playSector(Sector sector){ + ui.loadAnd(() -> { + logic.reset(); + world.loadSector(sector); + state.set(State.playing); + logic.play(); + ui.planet.hide(); + }); } public void playTutorial(){ @@ -277,8 +289,8 @@ public class Control implements ApplicationListener, Loadable{ world.beginMapLoad(); - world.createTiles(zone.generator.width, zone.generator.height); - zone.generator.generate(world.getTiles()); + world.resize(zone.generator.width, zone.generator.height); + zone.generator.generate(world.tiles); Tile coreb = null; diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 5028ba3f12..65f7084ff2 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -236,6 +236,7 @@ public class Logic implements ApplicationListener{ bulletGroup.update(); tileGroup.update(); fireGroup.update(); + weatherGroup.update(); }else{ unitGroup.updateEvents(); collisions.updatePhysics(unitGroup); diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index c28a5f5fe1..d3c416ee31 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -63,7 +63,7 @@ public class UI implements ApplicationListener, Loadable{ public TraceDialog traces; public DatabaseDialog database; public ContentInfoDialog content; - public DeployDialog deploy; + public PlanetDialog planet; public TechTreeDialog tech; //public MinimapDialog minimap; public SchematicsDialog schematics; @@ -176,7 +176,7 @@ public class UI implements ApplicationListener, Loadable{ traces = new TraceDialog(); maps = new MapsDialog(); content = new ContentInfoDialog(); - deploy = new DeployDialog(); + planet = new PlanetDialog(); tech = new TechTreeDialog(); mods = new ModsDialog(); schematics = new SchematicsDialog(); diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index bbc3f4074c..04fec3d240 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -1,11 +1,13 @@ package mindustry.core; import arc.*; +import arc.func.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; +import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -14,7 +16,6 @@ import mindustry.io.*; import mindustry.maps.*; import mindustry.maps.filters.*; import mindustry.maps.filters.GenerateFilter.*; -import mindustry.maps.generators.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -25,7 +26,7 @@ public class World{ public final Context context = new Context(); private Map currentMap; - private Tile[][] tiles; + public @NonNull Tiles tiles = new Tiles(0, 0); private boolean generating, invalidMap; @@ -67,11 +68,11 @@ public class World{ } public int width(){ - return tiles == null ? 0 : tiles.length; + return tiles.width(); } public int height(){ - return tiles == null ? 0 : tiles[0].length; + return tiles.height(); } public int unitWidth(){ @@ -88,11 +89,7 @@ public class World{ } public @Nullable Tile tile(int x, int y){ - if(tiles == null){ - return null; - } - if(!Structs.inBounds(x, y, tiles)) return null; - return tiles[x][y]; + return tiles.get(x, y); } public @Nullable Tile ltile(int x, int y){ @@ -102,7 +99,7 @@ public class World{ } public Tile rawTile(int x, int y){ - return tiles[x][y]; + return tiles.getn(x, y); } public @Nullable Tile tileWorld(float x, float y){ @@ -117,16 +114,10 @@ public class World{ return Math.round(coord / tilesize); } - public Tile[][] getTiles(){ - return tiles; - } - private void clearTileEntities(){ - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - if(tiles[x][y] != null && tiles[x][y].entity != null){ - tiles[x][y].entity.remove(); - } + for(Tile tile : tiles){ + if(tile != null && tile.entity != null){ + tile.entity.remove(); } } } @@ -135,15 +126,11 @@ public class World{ * Resizes the tile array to the specified size and returns the resulting tile array. * Only use for loading saves! */ - public Tile[][] createTiles(int width, int height){ - if(tiles != null){ - clearTileEntities(); + public Tiles resize(int width, int height){ + clearTileEntities(); - if(tiles.length != width || tiles[0].length != height){ - tiles = new Tile[width][height]; - } - }else{ - tiles = new Tile[width][height]; + if(tiles.width() != width || tiles.height() != height){ + tiles = new Tiles(width, height); } return tiles; @@ -164,14 +151,11 @@ public class World{ public void endMapLoad(){ prepareTiles(tiles); - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - Tile tile = tiles[x][y]; - tile.updateOcclusion(); + for(Tile tile : tiles){ + tile.updateOcclusion(); - if(tile.entity != null){ - tile.entity.updateProximity(); - } + if(tile.entity != null){ + tile.entity.updateProximity(); } } @@ -179,7 +163,7 @@ public class World{ addDarkness(tiles); } - entities.all().each(group -> group.resize(-finalWorldBounds, -finalWorldBounds, tiles.length * tilesize + finalWorldBounds * 2, tiles[0].length * tilesize + finalWorldBounds * 2)); + entities.all().each(group -> group.resize(-finalWorldBounds, -finalWorldBounds, tiles.width() * tilesize + finalWorldBounds * 2, tiles.height() * tilesize + finalWorldBounds * 2)); generating = false; Events.fire(new WorldLoadEvent()); @@ -201,15 +185,32 @@ public class World{ return state.rules.zone; } - public void loadGenerator(Generator generator){ + public void loadGenerator(int width, int height, Cons generator){ beginMapLoad(); - createTiles(generator.width, generator.height); - generator.generate(tiles); + resize(width, height); + generator.get(tiles); endMapLoad(); } + public void loadSector(Sector sector){ + int size = (int)(sector.rect.radius * 2500); + + loadGenerator(size, size, tiles -> { + TileGen gen = new TileGen(); + tiles.each((x, y) -> { + gen.reset(); + Vec3 position = sector.rect.project(x / (float)size, y / (float)size); + + sector.planet.generator.generate(position, gen); + tiles.set(x, y, new Tile(x, y, gen.floor, gen.overlay, gen.block)); + }); + + tiles.get(size/2, size/2).setBlock(Blocks.coreShard, Team.sharded); + }); + } + public void loadMap(Map map){ loadMap(map, new Rules()); } @@ -297,58 +298,56 @@ public class World{ } } - public void addDarkness(Tile[][] tiles){ - byte[][] dark = new byte[tiles.length][tiles[0].length]; - byte[][] writeBuffer = new byte[tiles.length][tiles[0].length]; + public void addDarkness(Tiles tiles){ + byte[] dark = new byte[tiles.width() * tiles.height()]; + byte[] writeBuffer = new byte[tiles.width() * tiles.height()]; 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.isDarkened()){ - dark[x][y] = darkIterations; - } + + for(int i = 0; i < dark.length; i++){ + Tile tile = tiles.geti(i); + if(tile.isDarkened()){ + dark[i] = 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; - } + for(Tile tile : tiles){ + int idx = tile.y * tiles.width() + tile.x; + boolean min = false; + for(Point2 point : Geometry.d4){ + int newX = tile.x + point.x, newY = tile.y + point.y; + int nidx = newY * tiles.width() + newX; + if(tiles.in(newX, newY) && dark[nidx] < dark[idx]){ + min = true; + break; } - writeBuffer[x][y] = (byte)Math.max(0, dark[x][y] - Mathf.num(min)); } + writeBuffer[idx] = (byte)Math.max(0, dark[idx] - Mathf.num(min)); } - for(int x = 0; x < tiles.length; x++){ - System.arraycopy(writeBuffer[x], 0, dark[x], 0, tiles[0].length); - } + System.arraycopy(writeBuffer, 0, dark, 0, writeBuffer.length); } - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - Tile tile = tiles[x][y]; - if(tile.isDarkened()){ - tiles[x][y].rotation(dark[x][y]); - } - if(dark[x][y] == 4){ - boolean full = true; - for(Point2 p : Geometry.d4){ - int px = p.x + x, py = p.y + y; - if(Structs.inBounds(px, py, tiles) && !(tiles[px][py].isDarkened() && dark[px][py] == 4)){ - full = false; - break; - } - } + for(Tile tile : tiles){ + int idx = tile.y * tiles.width() + tile.x; - if(full) tiles[x][y].rotation(5); + if(tile.isDarkened()){ + tile.rotation(dark[idx]); + } + + if(dark[idx] == 4){ + boolean full = true; + for(Point2 p : Geometry.d4){ + int px = p.x + tile.x, py = p.y + tile.y; + int nidx = py * tiles.width() + px; + if(tiles.in(px, py) && !(tile.isDarkened() && dark[nidx] == 4)){ + full = false; + break; + } } + + if(full) tile.rotation(5); } } } @@ -359,18 +358,13 @@ public class World{ * - updating occlusion
* Usually used before placing structures on a tile array. */ - public void prepareTiles(Tile[][] tiles){ + public void prepareTiles(Tiles tiles){ //find multiblocks IntArray multiblocks = new IntArray(); - - 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().isMultiblock()){ - multiblocks.add(tile.pos()); - } + for(Tile tile : tiles){ + if(tile.block().isMultiblock()){ + multiblocks.add(tile.pos()); } } @@ -380,9 +374,10 @@ public class World{ int x = Pos.x(pos); int y = Pos.y(pos); + Tile tile = tiles.getn(x, y); - Block result = tiles[x][y].block(); - Team team = tiles[x][y].getTeam(); + Block result = tile.block(); + Team team = tile.getTeam(); int offsetx = -(result.size - 1) / 2; int offsety = -(result.size - 1) / 2; @@ -409,17 +404,19 @@ public class World{ private class Context implements WorldContext{ @Override public Tile tile(int x, int y){ - return tiles[x][y]; + return tiles.get(x, y); } @Override public void resize(int width, int height){ - createTiles(width, height); + World.this.resize(width, height); } @Override public Tile create(int x, int y, int floorID, int overlayID, int wallID){ - return (tiles[x][y] = new Tile(x, y, floorID, overlayID, wallID)); + Tile tile = new Tile(x, y, floorID, overlayID, wallID); + tiles.set(x, y, tile); + return tile; } @Override @@ -454,23 +451,8 @@ public class World{ GenerateInput input = new GenerateInput(); for(GenerateFilter filter : filters){ - input.begin(filter, width(), height(), (x, y) -> tiles[x][y]); - - //actually apply the filter - for(int x = 0; x < width(); x++){ - for(int y = 0; y < height(); y++){ - Tile tile = rawTile(x, y); - input.apply(x, y, tile.floor(), tile.block(), tile.overlay()); - filter.apply(input); - - tile.setFloor((Floor)input.floor); - tile.setOverlay(input.ore); - - if(!tile.block().synthetic() && !input.block.synthetic()){ - tile.setBlock(input.block); - } - } - } + input.begin(filter, width(), height(), (x, y) -> tiles.getn(x, y)); + filter.apply(tiles, input); } } diff --git a/core/src/mindustry/ctype/ContentType.java b/core/src/mindustry/ctype/ContentType.java index 05c70484e3..31061e256b 100644 --- a/core/src/mindustry/ctype/ContentType.java +++ b/core/src/mindustry/ctype/ContentType.java @@ -14,7 +14,8 @@ public enum ContentType{ zone, loadout, typeid, - error; + error, + planet; public static final ContentType[] all = values(); } diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index 3e23ac146d..825891c31f 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -54,7 +54,7 @@ public abstract class UnlockableContent extends MappableContent{ public void onUnlock(){ } - /** Whether this content is always hidden in the content info dialog. */ + /** Whether this content is always hidden in the content database dialog. */ public boolean isHidden(){ return false; } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index cc064873c3..fec3cb9a79 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -13,7 +13,6 @@ import mindustry.world.modules.*; import static mindustry.Vars.state; import static mindustry.Vars.ui; -//TODO somehow remove or replace this class with a more flexible solution public class EditorTile extends Tile{ public EditorTile(int x, int y, int floor, int overlay, int wall){ diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 7cab015b1f..d38c6d14cc 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -69,25 +69,23 @@ public class MapEditor{ } //adds missing blockparts + //TODO remove, may not be necessary with blockpart refactor later public void checkLinkedTiles(){ - Tile[][] tiles = world.getTiles(); + Tiles tiles = world.tiles; - //clear block parts first - for(int x = 0; x < width(); x++){ - for(int y = 0; y < height(); y++){ - if(tiles[x][y].block() instanceof BlockPart){ - tiles[x][y].setBlock(Blocks.air); - } + //clear old parts + for(Tile tile : tiles){ + if(tile.block() instanceof BlockPart){ + tile.setBlock(Blocks.air); } } - //set up missing blockparts - for(int x = 0; x < width(); x++){ - for(int y = 0; y < height(); y++){ - if(tiles[x][y].block().isMultiblock()){ - tiles[x][y].set(tiles[x][y].block(), tiles[x][y].getTeam()); - } + //re-add them + for(Tile tile : tiles){ + if(tile.block().isMultiblock()){ + tile.set(tile.block(), tile.getTeam()); } + } } @@ -99,11 +97,11 @@ public class MapEditor{ /** Creates a 2-D array of EditorTiles with stone as the floor block. */ private void createTiles(int width, int height){ - Tile[][] tiles = world.createTiles(width, height); + Tiles tiles = world.resize(width, height); for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ - tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0); + tiles.set(x, y, new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0)); } } } @@ -119,8 +117,8 @@ public class MapEditor{ tags = new StringMap(); } - public Tile[][] tiles(){ - return world.getTiles(); + public Tiles tiles(){ + return world.tiles; } public Tile tile(int x, int y){ @@ -245,20 +243,20 @@ public class MapEditor{ public void resize(int width, int height){ clearOp(); - Tile[][] previous = world.getTiles(); + Tiles previous = world.tiles; int offsetX = -(width - width()) / 2, offsetY = -(height - height()) / 2; loading = true; - Tile[][] tiles = world.createTiles(width, height); + Tiles tiles = world.resize(width, height); for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ int px = offsetX + x, py = offsetY + y; - if(Structs.inBounds(px, py, previous.length, previous[0].length)){ - tiles[x][y] = previous[px][py]; - tiles[x][y].x = (short)x; - tiles[x][y].y = (short)y; + if(previous.in(px, py)){ + tiles.set(x, y, previous.getn(px, py)); + tiles.getn(x, y).x = (short)x; + tiles.getn(x, y).y = (short)y; }else{ - tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0); + tiles.set(x, y, new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0)); } } } @@ -314,12 +312,14 @@ public class MapEditor{ @Override public void resize(int width, int height){ - world.createTiles(width, height); + world.resize(width, height); } @Override public Tile create(int x, int y, int floorID, int overlayID, int wallID){ - return (tiles()[x][y] = new EditorTile(x, y, floorID, overlayID, wallID)); + Tile tile = new EditorTile(x, y, floorID, overlayID, wallID); + tiles().set(x, y, tile); + return tile; } @Override diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 7d6791f846..da32ad259b 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -30,7 +30,7 @@ public class MapGenerateDialog extends FloatingDialog{ private final Prov[] filterTypes = new Prov[]{ NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new, - BlendFilter::new, MirrorFilter::new, ClearFilter::new + BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new, EnemySpawnFilter::new }; private final MapEditor editor; private final boolean applied; @@ -263,7 +263,7 @@ public class MapGenerateDialog extends FloatingDialog{ //all the options c.table(f -> { f.left().top(); - for(FilterOption option : filter.options){ + for(FilterOption option : filter.options()){ option.changed = this::update; f.table(t -> { @@ -292,7 +292,7 @@ public class MapGenerateDialog extends FloatingDialog{ for(Prov gen : filterTypes){ GenerateFilter filter = gen.get(); - if(!applied && filter.buffered) continue; + if((!applied && filter.isBuffered()) || (filter.isPost() && applied)) continue; selection.cont.addButton(filter.name(), () -> { filters.add(filter); @@ -360,21 +360,17 @@ public class MapGenerateDialog extends FloatingDialog{ for(GenerateFilter filter : copy){ input.begin(filter, editor.width(), editor.height(), (x, y) -> buffer1[Mathf.clamp(x / scaling, 0, pixmap.getWidth()-1)][Mathf.clamp(y / scaling, 0, pixmap.getHeight()-1)].tile()); + //read from buffer1 and write to buffer2 - for(int px = 0; px < pixmap.getWidth(); px++){ - for(int py = 0; py < pixmap.getHeight(); py++){ - int x = px * scaling, y = py * scaling; - GenTile tile = buffer1[px][py]; - input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); - filter.apply(input); - buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team), tile.rotation); - } - } - for(int px = 0; px < pixmap.getWidth(); px++){ - for(int py = 0; py < pixmap.getHeight(); py++){ - buffer1[px][py].set(buffer2[px][py]); - } - } + pixmap.each((px, py) -> { + int x = px * scaling, y = py * scaling; + GenTile tile = buffer1[px][py]; + input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); + filter.apply(input); + buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team), tile.rotation); + }); + + pixmap.each((px, py) -> buffer1[px][py].set(buffer2[px][py])); } for(int px = 0; px < pixmap.getWidth(); px++){ diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index c5d007c92a..2bd889006c 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -109,7 +109,7 @@ public class MapRenderer implements Disposable{ private void render(int wx, int wy){ int x = wx / chunkSize, y = wy / chunkSize; IndexedRenderer mesh = chunks[x][y]; - Tile tile = editor.tiles()[wx][wy]; + Tile tile = editor.tiles().getn(wx, wy); Team team = tile.getTeam(); Block floor = tile.floor(); diff --git a/core/src/mindustry/entities/Saveable.java b/core/src/mindustry/entities/Saveable.java index 0eb4bb143d..0cabc2437e 100644 --- a/core/src/mindustry/entities/Saveable.java +++ b/core/src/mindustry/entities/Saveable.java @@ -2,6 +2,7 @@ package mindustry.entities; import java.io.*; +/** Marks something as saveable; not necessarily used for entities. */ public interface Saveable{ void writeSave(DataOutput stream) throws IOException; void readSave(DataInput stream, byte version) throws IOException; diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index 2d506a2c85..dc1eda2591 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -48,7 +48,7 @@ public class MusicControl{ public void update(){ if(state.is(State.menu)){ silenced = false; - if(ui.deploy.isShown()){ + if(ui.planet.isShown()){ play(Musics.launch); }else if(ui.editor.isShown()){ play(Musics.editor); diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index b91ca5b110..4f886d4001 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -31,6 +31,17 @@ public enum CacheLayer{ endShader(Shaders.tar); } }, + slag{ + @Override + public void begin(){ + beginShader(); + } + + @Override + public void end(){ + endShader(Shaders.slag); + } + }, normal, walls; diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 3519edc31f..5a32ea6ec2 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -43,7 +43,7 @@ public class MenuRenderer implements Disposable{ } private void generate(){ - Tile[][] tiles = world.createTiles(width, height); + Tiles tiles = world.resize(width, height); Array ores = content.blocks().select(b -> b instanceof OreBlock); shadows = new FrameBuffer(width, height); int offset = Mathf.random(100000); @@ -154,10 +154,10 @@ public class MenuRenderer implements Disposable{ } Tile tile; - tiles[x][y] = (tile = new CachedTile()); + tiles.set(x, y, (tile = new CachedTile())); tile.x = (short)x; tile.y = (short)y; - tile.setFloor((Floor) floor); + tile.setFloor(floor.asFloor()); tile.setBlock(wall); tile.setOverlay(ore); } diff --git a/core/src/mindustry/graphics/PlanetGrid.java b/core/src/mindustry/graphics/PlanetGrid.java new file mode 100644 index 0000000000..9328b4e8f8 --- /dev/null +++ b/core/src/mindustry/graphics/PlanetGrid.java @@ -0,0 +1,266 @@ +package mindustry.graphics; + +import arc.math.*; +import arc.math.geom.*; +import arc.util.*; + +//TODO clean this up somehow +public class PlanetGrid{ + private static final PlanetGrid[] cache = new PlanetGrid[10]; + + private static final float x = -0.525731112119133606f; + private static final float z = -0.850650808352039932f; + + private static final Vec3[] iTiles = { + new Vec3(-x, 0, z), new Vec3(x, 0, z), new Vec3(-x, 0, -z), new Vec3(x, 0, -z), + new Vec3(0, z, x), new Vec3(0, z, -x), new Vec3(0, -z, x), new Vec3(0, -z, -x), + new Vec3(z, x, 0), new Vec3(-z, x, 0), new Vec3(z, -x, 0), new Vec3(-z, -x, 0) + }; + + private static final int[][] iTilesP = { + {9, 4, 1, 6, 11}, {4, 8, 10, 6, 0}, {11, 7, 3, 5, 9}, {2, 7, 10, 8, 5}, + {9, 5, 8, 1, 0}, {2, 3, 8, 4, 9}, {0, 1, 10, 7, 11}, {11, 6, 10, 3, 2}, + {5, 3, 10, 1, 4}, {2, 5, 4, 0, 11}, {3, 7, 6, 1, 8}, {7, 2, 9, 0, 6} + }; + + public final int size; + public final Ptile[] tiles; + public final Corner[] corners; + public final Edge[] edges; + + PlanetGrid(int size){ + this.size = size; + + tiles = new Ptile[tileCount(size)]; + for(int i = 0; i < tiles.length; i++){ + tiles[i] = new Ptile(i, i < 12 ? 5 : 6); + } + + corners = new Corner[cornerCount(size)]; + for(int i = 0; i < corners.length; i++){ + corners[i] = new Corner(i); + } + + edges = new Edge[edgeCount(size)]; + for(int i = 0; i < edges.length; i++){ + edges[i] = new Edge(i); + } + } + + public static PlanetGrid newGrid(int size){ + //cache grids between calls, since only ~5 different grids total are needed + if(size < cache.length && cache[size] != null){ + return cache[size]; + } + + PlanetGrid result; + if(size == 0){ + result = initialGrid(); + }else{ + result = subdividedGrid(newGrid(size - 1)); + } + + //store grid in cache + if(size < cache.length){ + cache[size] = result; + } + + return result; + } + + static PlanetGrid initialGrid(){ + PlanetGrid grid = new PlanetGrid(0); + + for(Ptile t : grid.tiles){ + t.v = iTiles[t.id]; + for(int k = 0; k < 5; k++){ + t.tiles[k] = grid.tiles[iTilesP[t.id][k]]; + } + } + for(int i = 0; i < 5; i++){ + addCorner(i, grid, 0, iTilesP[0][(i + 4) % 5], iTilesP[0][i]); + } + for(int i = 0; i < 5; i++){ + addCorner(i + 5, grid, 3, iTilesP[3][(i + 4) % 5], iTilesP[3][i]); + } + addCorner(10, grid, 10, 1, 8); + addCorner(11, grid, 1, 10, 6); + addCorner(12, grid, 6, 10, 7); + addCorner(13, grid, 6, 7, 11); + addCorner(14, grid, 11, 7, 2); + addCorner(15, grid, 11, 2, 9); + addCorner(16, grid, 9, 2, 5); + addCorner(17, grid, 9, 5, 4); + addCorner(18, grid, 4, 5, 8); + addCorner(19, grid, 4, 8, 1); + + //add corners to corners + for(Corner c : grid.corners){ + for(int k = 0; k < 3; k++){ + c.corners[k] = c.tiles[k].corners[(pos(c.tiles[k], c) + 1) % 5]; + } + } + //new edges + int nextEdge = 0; + for(Ptile t : grid.tiles){ + for(int k = 0; k < 5; k++){ + if(t.edges[k] == null){ + addEdge(nextEdge++, grid, t.id, iTilesP[t.id][k]); + } + } + } + return grid; + } + + static PlanetGrid subdividedGrid(PlanetGrid prev){ + PlanetGrid grid = new PlanetGrid(prev.size + 1); + + int prevTiles = prev.tiles.length; + int prevCorners = prev.corners.length; + + //old tiles + for(int i = 0; i < prevTiles; i++){ + grid.tiles[i].v = prev.tiles[i].v; + for(int k = 0; k < grid.tiles[i].edgeCount; k++){ + + grid.tiles[i].tiles[k] = grid.tiles[prev.tiles[i].corners[k].id + prevTiles]; + } + } + //old corners become tiles + for(int i = 0; i < prevCorners; i++){ + grid.tiles[i + prevTiles].v = prev.corners[i].v; + for(int k = 0; k < 3; k++){ + grid.tiles[i + prevTiles].tiles[2 * k] = grid.tiles[prev.corners[i].corners[k].id + prevTiles]; + grid.tiles[i + prevTiles].tiles[2 * k + 1] = grid.tiles[prev.corners[i].tiles[k].id]; + } + } + //new corners + int nextCorner = 0; + for(Ptile n : prev.tiles){ + Ptile t = grid.tiles[n.id]; + for(int k = 0; k < t.edgeCount; k++){ + addCorner(nextCorner, grid, t.id, t.tiles[(k + t.edgeCount - 1) % t.edgeCount].id, t.tiles[k].id); + nextCorner++; + } + } + //connect corners + for(Corner c : grid.corners){ + for(int k = 0; k < 3; k++){ + c.corners[k] = c.tiles[k].corners[(pos(c.tiles[k], c) + 1) % (c.tiles[k].edgeCount)]; + } + } + //new edges + int nextEdge = 0; + for(Ptile t : grid.tiles){ + for(int k = 0; k < t.edgeCount; k++){ + if(t.edges[k] == null){ + addEdge(nextEdge, grid, t.id, t.tiles[k].id); + nextEdge++; + } + } + } + + return grid; + } + + static void addCorner(int id, PlanetGrid grid, int t1, int t2, int t3){ + Corner c = grid.corners[id]; + Ptile[] t = {grid.tiles[t1], grid.tiles[t2], grid.tiles[t3]}; + c.v = Tmp.v31.set(t[0].v).add(t[1].v).add(t[2].v).cpy().nor(); + for(int i = 0; i < 3; i++){ + t[i].corners[pos(t[i], t[(i + 2) % 3])] = c; + c.tiles[i] = t[i]; + } + } + + static void addEdge(int id, PlanetGrid grid, int t1, int t2){ + Edge e = grid.edges[id]; + Ptile[] t = {grid.tiles[t1], grid.tiles[t2]}; + Corner[] c = { + grid.corners[t[0].corners[pos(t[0], t[1])].id], + grid.corners[t[0].corners[(pos(t[0], t[1]) + 1) % t[0].edgeCount].id]}; + for(int i = 0; i < 2; i++){ + t[i].edges[pos(t[i], t[(i + 1) % 2])] = e; + e.tiles[i] = t[i]; + c[i].edges[pos(c[i], c[(i + 1) % 2])] = e; + e.corners[i] = c[i]; + } + } + + static int pos(Ptile t, Ptile n){ + for(int i = 0; i < t.edgeCount; i++) + if(t.tiles[i] == n) + return i; + return -1; + } + + static int pos(Ptile t, Corner c){ + for(int i = 0; i < t.edgeCount; i++) + if(t.corners[i] == c) + return i; + return -1; + } + + static int pos(Corner c, Corner n){ + for(int i = 0; i < 3; i++) + if(c.corners[i] == n) + return i; + return -1; + } + + static int tileCount(int size){ + return 10 * Mathf.pow(3, size) + 2; + } + + static int cornerCount(int size){ + return 20 * Mathf.pow(3, size); + } + + static int edgeCount(int size){ + return 30 * Mathf.pow(3, size); + } + + public static class Ptile{ + public final int id; + public final int edgeCount; + + public final Ptile[] tiles; + public final Corner[] corners; + public final Edge[] edges; + + public Vec3 v = new Vec3(); + + public Ptile(int id, int edgeCount){ + this.id = id; + this.edgeCount = edgeCount; + + tiles = new Ptile[edgeCount]; + corners = new Corner[edgeCount]; + edges = new Edge[edgeCount]; + } + } + + public static class Corner{ + public final int id; + public final Ptile[] tiles = new Ptile[3]; + public final Corner[] corners = new Corner[3]; + public final Edge[] edges = new Edge[3]; + + public Vec3 v = new Vec3(); + public Vec3 bv = new Vec3(); + + public Corner(int id){ + this.id = id; + } + } + + public static class Edge{ + public final int id; + public final Ptile[] tiles = new Ptile[2]; + public final Corner[] corners = new Corner[2]; + + public Edge(int id){ + this.id = id; + } + } +} diff --git a/core/src/mindustry/graphics/PlanetMesh.java b/core/src/mindustry/graphics/PlanetMesh.java new file mode 100644 index 0000000000..60abdbf371 --- /dev/null +++ b/core/src/mindustry/graphics/PlanetMesh.java @@ -0,0 +1,140 @@ +package mindustry.graphics; + +import arc.graphics.*; +import arc.graphics.VertexAttributes.*; +import arc.graphics.gl.*; +import arc.math.geom.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.graphics.PlanetGrid.*; +import mindustry.maps.planet.*; + +public class PlanetMesh{ + private float[] floats = new float[3 + 3 + 1]; + private Vec3 vec = new Vec3(); + private Mesh mesh; + private PlanetGrid grid; + private Vec3 center = new Vec3(); + + private boolean lines; + private float radius, intensity = 0.2f; + + private final PlanetGenerator gen; + + public PlanetMesh(int divisions, PlanetGenerator gen){ + this(divisions, gen, 1f, false); + } + + public PlanetMesh(int divisions, PlanetGenerator gen, float radius, boolean lines){ + this.gen = gen; + this.radius = radius; + this.grid = PlanetGrid.newGrid(divisions); + this.lines = lines; + + int vertices = grid.tiles.length * 12 * (3 + 3 + 1); + + mesh = new Mesh(true, vertices, 0, + new VertexAttribute(Usage.position, 3, Shader.positionAttribute), + new VertexAttribute(Usage.normal, 3, Shader.normalAttribute), + new VertexAttribute(Usage.colorPacked, 4, Shader.colorAttribute)); + + mesh.getVerticesBuffer().limit(mesh.getMaxVertices()); + mesh.getVerticesBuffer().position(0); + + generateMesh(); + } + + /** @return the sector that is hit by this ray, or null if nothing intersects it. */ + public @Nullable Ptile getTile(Ray ray){ + boolean found = Intersector3D.intersectRaySphere(ray, center, radius, Tmp.v33); + if(!found) return null; + return Structs.findMin(grid.tiles, t -> t.v.dst(Tmp.v33)); + } + + public void render(Mat3D mat){ + Shaders.planet.begin(); + Shaders.planet.setUniformMatrix4("u_projModelView", mat.val); + mesh.render(Shaders.planet, lines ? Gl.lines : Gl.triangles); + Shaders.planet.end(); + } + + private void generateMesh(){ + + for(Ptile tile : grid.tiles){ + + Vec3 nor = Tmp.v31.setZero(); + Corner[] c = tile.corners; + + for(Corner corner : c){ + corner.bv.set(corner.v).setLength(radius); + } + + for(Corner corner : c){ + corner.v.setLength(radius + elevation(corner.bv)*intensity); + } + + for(Corner corner : c){ + nor.add(corner.v); + } + nor.nor(); + + Vec3 realNormal = normal(c[0].v, c[2].v, c[4].v); + nor.set(realNormal); + + Color color = color(tile.v); + + if(lines){ + nor.set(1f, 1f, 1f); + + for(int i = 0; i < c.length; i++){ + Vec3 v1 = c[i].v; + Vec3 v2 = c[(i + 1) % c.length].v; + + vert(v1, nor, color); + vert(v2, nor, color); + } + }else{ + verts(c[0].v, c[1].v, c[2].v, nor, color); + verts(c[0].v, c[2].v, c[3].v, nor, color); + verts(c[0].v, c[3].v, c[4].v, nor, color); + + if(c.length > 5){ + verts(c[0].v, c[4].v, c[5].v, nor, color); + }else{ + verts(c[0].v, c[3].v, c[4].v, nor, color); + } + } + } + } + + private Vec3 normal(Vec3 v1, Vec3 v2, Vec3 v3){ + return Tmp.v32.set(v2).sub(v1).crs(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z).nor(); + } + + private float elevation(Vec3 v){ + return gen.getHeight(vec.set(v).scl(1f / radius)); + } + + private Color color(Vec3 v){ + return gen.getColor(vec.set(v).scl(1f / radius)); + } + + private void verts(Vec3 a, Vec3 b, Vec3 c, Vec3 normal, Color color){ + vert(a, normal, color); + vert(b, normal, color); + vert(c, normal, color); + } + + private void vert(Vec3 a, Vec3 normal, Color color){ + floats[0] = a.x; + floats[1] = a.y; + floats[2] = a.z; + + floats[3] = normal.x; + floats[4] = normal.y; + floats[5] = normal.z; + + floats[6] = color.toFloatBits(); + mesh.getVerticesBuffer().put(floats); + } +} diff --git a/core/src/mindustry/graphics/PlanetRenderer.java b/core/src/mindustry/graphics/PlanetRenderer.java new file mode 100644 index 0000000000..c504c21865 --- /dev/null +++ b/core/src/mindustry/graphics/PlanetRenderer.java @@ -0,0 +1,123 @@ +package mindustry.graphics; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.graphics.g3d.*; +import arc.input.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.graphics.PlanetGrid.*; +import mindustry.maps.planet.*; +import mindustry.type.*; +import mindustry.type.Sector.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class PlanetRenderer implements PlanetGenerator{ + private final Color outlineColor = Pal.accent.cpy().a(0.7f); + private final float camLength = 4f, outlineRad = 1.15f; + private final boolean drawnRect = true; + + private final PlanetMesh[] outlines = new PlanetMesh[10]; + private final Camera3D cam = new Camera3D(); + private final VertexBatch3D batch = new VertexBatch3D(false, true, 0); + + private float lastX, lastY; + + public PlanetRenderer(){ + Tmp.v1.trns(0, camLength); + cam.position.set(Tmp.v1.x, 0f, Tmp.v1.y); + } + + public void render(Planet planet){ + Draw.flush(); + Gl.clear(Gl.depthBufferBit); + Gl.enable(Gl.depthTest); + + input(); + + cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); + cam.update(); + cam.lookAt(0, 0, 0); + cam.update(); + + PlanetMesh outline = outline(planet.size); + + planet.mesh.render(cam.combined()); + outline.render(cam.combined()); + + Ptile tile = outline.getTile(cam.getPickRay(Core.input.mouseX(), Core.input.mouseY())); + if(tile != null){ + + Sector sector = planet.getSector(tile); + for(int i = 0; i < sector.tile.corners.length; i++){ + batch.color(outlineColor); + batch.vertex(sector.tile.corners[i].v); + } + batch.flush(cam.combined(), Gl.triangleFan); + + if(drawnRect){ + //TODO hack. + SectorRect rect = sector.rect; + rect.center.scl(outlineRad); + rect.right.scl(outlineRad); + rect.top.scl(outlineRad); + + batch.color(Pal.place); + batch.vertex(rect.project(0, 0)); + batch.color(Pal.place); + batch.vertex(rect.project(1, 0)); + batch.color(Pal.place); + batch.vertex(rect.project(1, 1)); + batch.color(Pal.place); + batch.vertex(rect.project(0, 1)); + batch.flush(cam.combined(), Gl.lineLoop); + + rect.center.scl(1f / outlineRad); + rect.right.scl(1f / outlineRad); + rect.top.scl(1f / outlineRad); + + if(Core.input.keyTap(KeyCode.SPACE)){ + control.playSector(sector); + ui.planet.hide(); + } + } + } + + Gl.disable(Gl.depthTest); + } + + private PlanetMesh outline(int size){ + if(outlines[size] == null){ + outlines[size] = new PlanetMesh(size, this, outlineRad, true); + } + return outlines[size]; + } + + private void input(){ + Vec3 v = Tmp.v33.set(Core.input.mouseX(), Core.input.mouseY(), 0); + + if(Core.input.keyDown(KeyCode.MOUSE_LEFT)){ + cam.position.rotate(Vec3.Y, (v.x - lastX) / 10); + } + lastX = v.x; + lastY = v.y; + } + + @Override + public float getHeight(Vec3 position){ + return 0; + } + + @Override + public Color getColor(Vec3 position){ + return outlineColor; + } + + @Override + public void generate(Vec3 position, TileGen tile){ + + } +} diff --git a/core/src/mindustry/graphics/Shaders.java b/core/src/mindustry/graphics/Shaders.java index 7c37935352..0aa0d7c4af 100644 --- a/core/src/mindustry/graphics/Shaders.java +++ b/core/src/mindustry/graphics/Shaders.java @@ -11,13 +11,13 @@ import arc.util.Time; public class Shaders{ public static Shadow shadow; public static BlockBuild blockbuild; - public static @Nullable - Shield shield; + public static @Nullable Shield shield; public static UnitBuild build; public static FogShader fog; public static MenuShader menu; public static LightShader light; - public static SurfaceShader water, tar; + public static SurfaceShader water, tar, slag; + public static Shader planet; public static void init(){ shadow = new Shadow(); @@ -35,6 +35,8 @@ public class Shaders{ light = new LightShader(); water = new SurfaceShader("water"); tar = new SurfaceShader("tar"); + slag = new SurfaceShader("slag"); + planet = new LoadShader("planet", "planet"); } public static class LightShader extends LoadShader{ diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 85c5cc9cb7..0ffe03d777 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -133,11 +133,11 @@ public class MapIO{ } } - public static Pixmap generatePreview(Tile[][] tiles){ - Pixmap pixmap = new Pixmap(tiles.length, tiles[0].length, Format.RGBA8888); + public static Pixmap generatePreview(Tiles tiles){ + Pixmap pixmap = new Pixmap(tiles.width(), tiles.height(), Format.RGBA8888); for(int x = 0; x < pixmap.getWidth(); x++){ for(int y = 0; y < pixmap.getHeight(); y++){ - Tile tile = tiles[x][y]; + Tile tile = tiles.getn(x, y); pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam())); } } @@ -152,12 +152,12 @@ public class MapIO{ } /** Reads a pixmap in the 3.5 pixmap format. */ - public static void readPixmap(Pixmap pixmap, Tile[][] tiles){ + public static void readPixmap(Pixmap pixmap, Tiles tiles){ for(int x = 0; x < pixmap.getWidth(); x++){ for(int y = 0; y < pixmap.getHeight(); y++){ int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y); LegacyBlock block = LegacyColorMapper.get(color); - Tile tile = tiles[x][y]; + Tile tile = tiles.getn(x, y); tile.setFloor(block.floor); tile.setBlock(block.wall); diff --git a/core/src/mindustry/maps/Maps.java b/core/src/mindustry/maps/Maps.java index d94852cf0d..4279ebc765 100644 --- a/core/src/mindustry/maps/Maps.java +++ b/core/src/mindustry/maps/Maps.java @@ -212,7 +212,7 @@ public class Maps{ for(int x = 0; x < map.width; x++){ for(int y = 0; y < map.height; y++){ - Tile tile = world.getTiles()[x][y]; + Tile tile = world.rawTile(x, y); if(tile.block() instanceof CoreBlock){ map.teams.add(tile.getTeamID()); @@ -228,7 +228,7 @@ public class Maps{ Core.assets.unload(map.previewFile().path() + "." + mapExtension); } - Pixmap pix = MapIO.generatePreview(world.getTiles()); + Pixmap pix = MapIO.generatePreview(world.tiles); executor.submit(() -> map.previewFile().writePNG(pix)); writeCache(map); diff --git a/core/src/mindustry/maps/filters/BlendFilter.java b/core/src/mindustry/maps/filters/BlendFilter.java index a60ab71fa9..405ed2b46b 100644 --- a/core/src/mindustry/maps/filters/BlendFilter.java +++ b/core/src/mindustry/maps/filters/BlendFilter.java @@ -1,6 +1,7 @@ package mindustry.maps.filters; import arc.math.*; +import arc.util.*; import mindustry.content.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; @@ -11,16 +12,21 @@ public class BlendFilter extends GenerateFilter{ float radius = 2f; Block block = Blocks.stone, floor = Blocks.ice, ignore = Blocks.air; - { - buffered = true; - options( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), - new BlockOption("block", () -> block, b -> block = b, anyOptional), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly), - new BlockOption("ignore", () -> ignore, b -> ignore = b, floorsOptional) + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), + new BlockOption("block", () -> block, b -> block = b, anyOptional), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly), + new BlockOption("ignore", () -> ignore, b -> ignore = b, floorsOptional) ); } + @Override + public boolean isBuffered(){ + return true; + } + @Override public void apply(){ if(in.floor == block || block == Blocks.air || in.floor == ignore) return; @@ -31,7 +37,7 @@ public class BlendFilter extends GenerateFilter{ outer: for(int x = -rad; x <= rad; x++){ for(int y = -rad; y <= rad; y++){ - if(Mathf.dst2(x, y) > rad*rad) continue; + if(Mathf.within(x, y, rad)) continue; Tile tile = in.tile(in.x + x, in.y + y); if(tile.floor() == block || tile.block() == block || tile.overlay() == block){ diff --git a/core/src/mindustry/maps/filters/ClearFilter.java b/core/src/mindustry/maps/filters/ClearFilter.java index c35cdee8e2..3769d7f77d 100644 --- a/core/src/mindustry/maps/filters/ClearFilter.java +++ b/core/src/mindustry/maps/filters/ClearFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.content.*; import mindustry.world.*; @@ -8,10 +9,9 @@ import static mindustry.maps.filters.FilterOption.*; public class ClearFilter extends GenerateFilter{ protected Block block = Blocks.air; - { - options( - new BlockOption("block", () -> block, b -> block = b, wallsOnly) - ); + @Override + public FilterOption[] options(){ + return Structs.arr(new BlockOption("block", () -> block, b -> block = b, wallsOnly)); } @Override diff --git a/core/src/mindustry/maps/filters/CoreSpawnFilter.java b/core/src/mindustry/maps/filters/CoreSpawnFilter.java new file mode 100644 index 0000000000..8386c5cfa9 --- /dev/null +++ b/core/src/mindustry/maps/filters/CoreSpawnFilter.java @@ -0,0 +1,43 @@ +package mindustry.maps.filters; + +import arc.struct.*; +import arc.util.*; +import mindustry.maps.filters.FilterOption.*; +import mindustry.world.*; +import mindustry.world.blocks.storage.*; + +import static mindustry.Vars.*; + +/** Selects X spawns from the core spawn pool.*/ +public class CoreSpawnFilter extends GenerateFilter{ + int amount = 1; + + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("amount", () -> amount, f -> amount = (int)f, 1, 10).display() + ); + } + + @Override + public void apply(Tiles tiles, GenerateInput in){ + IntArray spawns = new IntArray(); + for(Tile tile : tiles){ + if(tile.getTeam() == state.rules.defaultTeam && tile.block() instanceof CoreBlock){ + spawns.add(tile.pos()); + } + } + + spawns.shuffle(); + + int used = Math.min(spawns.size, amount); + for(int i = used; i < spawns.size; i++){ + tiles.getp(spawns.get(i)).remove(); + } + } + + @Override + public boolean isPost(){ + return true; + } +} diff --git a/core/src/mindustry/maps/filters/DistortFilter.java b/core/src/mindustry/maps/filters/DistortFilter.java index 6757af9cc2..e1fecffc3c 100644 --- a/core/src/mindustry/maps/filters/DistortFilter.java +++ b/core/src/mindustry/maps/filters/DistortFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -7,14 +8,19 @@ import mindustry.world.blocks.*; public class DistortFilter extends GenerateFilter{ float scl = 40, mag = 5; - { - buffered = true; - options( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 200f), - new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 200f), + new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) ); } + @Override + public boolean isBuffered(){ + return true; + } + @Override public void apply(){ Tile tile = in.tile(in.x + noise(in.x, in.y, scl, mag) - mag / 2f, in.y + noise(in.x, in.y + o, scl, mag) - mag / 2f); diff --git a/core/src/mindustry/maps/filters/EnemySpawnFilter.java b/core/src/mindustry/maps/filters/EnemySpawnFilter.java new file mode 100644 index 0000000000..53f97e488c --- /dev/null +++ b/core/src/mindustry/maps/filters/EnemySpawnFilter.java @@ -0,0 +1,42 @@ +package mindustry.maps.filters; + +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.maps.filters.FilterOption.*; +import mindustry.world.*; + +/** Selects X spawns from the spawn pool.*/ +public class EnemySpawnFilter extends GenerateFilter{ + int amount = 1; + + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("amount", () -> amount, f -> amount = (int)f, 1, 10).display() + ); + } + + @Override + public void apply(Tiles tiles, GenerateInput in){ + IntArray spawns = new IntArray(); + for(Tile tile : tiles){ + if(tile.overlay() == Blocks.spawn){ + spawns.add(tile.pos()); + } + } + + spawns.shuffle(); + + int used = Math.min(spawns.size, amount); + for(int i = used; i < spawns.size; i++){ + Tile tile = tiles.getp(spawns.get(i)); + tile.clearOverlay(); + } + } + + @Override + public boolean isPost(){ + return true; + } +} diff --git a/core/src/mindustry/maps/filters/FilterOption.java b/core/src/mindustry/maps/filters/FilterOption.java index 93ba8af56f..a91d471a82 100644 --- a/core/src/mindustry/maps/filters/FilterOption.java +++ b/core/src/mindustry/maps/filters/FilterOption.java @@ -35,6 +35,8 @@ public abstract class FilterOption{ final Floatc setter; final float min, max, step; + boolean display; + SliderOption(String name, Floatp getter, Floatc setter, float min, float max){ this(name, getter, setter, min, max, (max - min) / 200); } @@ -48,9 +50,18 @@ public abstract class FilterOption{ this.step = step; } + public SliderOption display(){ + display = true; + return this; + } + @Override public void build(Table table){ - table.add("$filter.option." + name); + if(!display){ + table.add("$filter.option." + name); + }else{ + table.label(() -> Core.bundle.get("filter.option." + name) + ": " + (int)getter.get()); + } table.row(); Slider slider = table.addSlider(min, max, step, setter).growX().get(); slider.setValue(getter.get()); diff --git a/core/src/mindustry/maps/filters/GenerateFilter.java b/core/src/mindustry/maps/filters/GenerateFilter.java index f24672b8d0..6193dfa704 100644 --- a/core/src/mindustry/maps/filters/GenerateFilter.java +++ b/core/src/mindustry/maps/filters/GenerateFilter.java @@ -7,32 +7,37 @@ import arc.util.*; import arc.util.noise.*; import mindustry.content.*; import mindustry.world.*; -import mindustry.world.blocks.*; public abstract class GenerateFilter{ protected transient float o = (float)(Math.random() * 10000000.0); protected transient long seed; protected transient GenerateInput in; - public transient boolean buffered = false; - public transient FilterOption[] options; + public void apply(Tiles tiles, GenerateInput in){ + this.in = in; + for(Tile tile : tiles){ + in.apply(tile.x, tile.y, tile.floor(), tile.block(), tile.overlay()); + apply(); + + tile.setFloor(in.floor.asFloor()); + tile.setOverlay(in.floor.asFloor().isLiquid ? Blocks.air : in.ore); + + if(!tile.block().synthetic() && !in.block.synthetic()){ + tile.setBlock(in.block); + } + } + } public final void apply(GenerateInput in){ this.in = in; apply(); - //remove extra ores on liquids - if(((Floor)in.floor).isLiquid){ - in.ore = Blocks.air; - } } - /** sets up the options; this is necessary since the constructor can't access subclass variables. */ - protected void options(FilterOption... options){ - this.options = options; - } + /** @return a new array of options for configuring this filter */ + public abstract FilterOption[] options(); /** apply the actual filter on the input */ - protected abstract void apply(); + protected void apply(){} /** draw any additional guides */ public void draw(Image image){} @@ -47,6 +52,16 @@ public abstract class GenerateFilter{ seed = Mathf.random(99999999); } + /** @return whether this filter needs a read/write buffer (e.g. not a 1:1 tile mapping). */ + public boolean isBuffered(){ + return false; + } + + /** @return whether this filter can *only* be used while generating the map, e.g. is not undoable. */ + public boolean isPost(){ + return false; + } + //utility generation functions protected float noise(float x, float y, float scl, float mag){ diff --git a/core/src/mindustry/maps/filters/MedianFilter.java b/core/src/mindustry/maps/filters/MedianFilter.java index 1d169b998b..cf3fbc2b29 100644 --- a/core/src/mindustry/maps/filters/MedianFilter.java +++ b/core/src/mindustry/maps/filters/MedianFilter.java @@ -2,6 +2,7 @@ package mindustry.maps.filters; import arc.struct.*; import arc.math.*; +import arc.util.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; @@ -12,14 +13,19 @@ public class MedianFilter extends GenerateFilter{ float percentile = 0.5f; IntArray blocks = new IntArray(), floors = new IntArray(); - { - buffered = true; - options( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), - new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), + new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) ); } + @Override + public boolean isBuffered(){ + return true; + } + @Override public void apply(){ int rad = (int)radius; diff --git a/core/src/mindustry/maps/filters/MirrorFilter.java b/core/src/mindustry/maps/filters/MirrorFilter.java index b9bf2a70d8..d4c96a7e07 100644 --- a/core/src/mindustry/maps/filters/MirrorFilter.java +++ b/core/src/mindustry/maps/filters/MirrorFilter.java @@ -15,8 +15,11 @@ public class MirrorFilter extends GenerateFilter{ int angle = 45; - { - options(new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45)); + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45) + ); } @Override diff --git a/core/src/mindustry/maps/filters/NoiseFilter.java b/core/src/mindustry/maps/filters/NoiseFilter.java index e532de69a8..8635966486 100644 --- a/core/src/mindustry/maps/filters/NoiseFilter.java +++ b/core/src/mindustry/maps/filters/NoiseFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.content.Blocks; import mindustry.maps.filters.FilterOption.BlockOption; import mindustry.maps.filters.FilterOption.SliderOption; @@ -12,8 +13,9 @@ public class NoiseFilter extends GenerateFilter{ float scl = 40, threshold = 0.5f, octaves = 3f, falloff = 0.5f; Block floor = Blocks.stone, block = Blocks.rocks; - { - options( + @Override + public FilterOption[] options(){ + return Structs.arr( new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), diff --git a/core/src/mindustry/maps/filters/OreFilter.java b/core/src/mindustry/maps/filters/OreFilter.java index eeca4c04b8..91c989e151 100644 --- a/core/src/mindustry/maps/filters/OreFilter.java +++ b/core/src/mindustry/maps/filters/OreFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.content.Blocks; import mindustry.maps.filters.FilterOption.SliderOption; import mindustry.world.Block; @@ -11,13 +12,14 @@ public class OreFilter extends GenerateFilter{ public float scl = 23, threshold = 0.81f, octaves = 2f, falloff = 0.3f; public Block ore = Blocks.oreCopper; - { - options( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), - new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), - new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), - new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("ore", () -> ore, b -> ore = b, oresOnly) + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), + new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), + new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), + new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), + new BlockOption("ore", () -> ore, b -> ore = b, oresOnly) ); } diff --git a/core/src/mindustry/maps/filters/OreMedianFilter.java b/core/src/mindustry/maps/filters/OreMedianFilter.java index 843909ba7b..519b642ab4 100644 --- a/core/src/mindustry/maps/filters/OreMedianFilter.java +++ b/core/src/mindustry/maps/filters/OreMedianFilter.java @@ -2,6 +2,7 @@ package mindustry.maps.filters; import arc.struct.*; import arc.math.*; +import arc.util.*; import mindustry.*; import mindustry.content.*; import mindustry.maps.filters.FilterOption.*; @@ -13,14 +14,19 @@ public class OreMedianFilter extends GenerateFilter{ private IntArray blocks = new IntArray(); - { - buffered = true; - options( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), - new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), + new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) ); } + @Override + public boolean isBuffered(){ + return true; + } + @Override public void apply(){ if(in.ore == Blocks.spawn) return; diff --git a/core/src/mindustry/maps/filters/RandomItemFilter.java b/core/src/mindustry/maps/filters/RandomItemFilter.java new file mode 100644 index 0000000000..d4f163d6db --- /dev/null +++ b/core/src/mindustry/maps/filters/RandomItemFilter.java @@ -0,0 +1,35 @@ +package mindustry.maps.filters; + +import arc.math.*; +import arc.struct.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.storage.*; + +public class RandomItemFilter extends GenerateFilter{ + public Array drops = new Array<>(); + public float chance = 0.3f; + + @Override + public FilterOption[] options(){ + return new FilterOption[0]; + } + + @Override + public void apply(Tiles tiles, GenerateInput in){ + for(Tile tile : tiles){ + if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ + for(ItemStack stack : drops){ + if(Mathf.chance(chance)){ + tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); + } + } + } + } + } + + @Override + public boolean isPost(){ + return true; + } +} diff --git a/core/src/mindustry/maps/filters/RiverNoiseFilter.java b/core/src/mindustry/maps/filters/RiverNoiseFilter.java index 1257bcf8b3..79755e1e8e 100644 --- a/core/src/mindustry/maps/filters/RiverNoiseFilter.java +++ b/core/src/mindustry/maps/filters/RiverNoiseFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.content.Blocks; import mindustry.maps.filters.FilterOption.BlockOption; import mindustry.maps.filters.FilterOption.SliderOption; @@ -12,8 +13,9 @@ public class RiverNoiseFilter extends GenerateFilter{ float scl = 40, threshold = 0f, threshold2 = 0.1f; Block floor = Blocks.water, floor2 = Blocks.deepwater, block = Blocks.sandRocks; - { - options( + @Override + public FilterOption[] options(){ + return Structs.arr( new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), new SliderOption("threshold", () -> threshold, f -> threshold = f, -1f, 0.3f), new SliderOption("threshold2", () -> threshold2, f -> threshold2 = f, -1f, 0.3f), diff --git a/core/src/mindustry/maps/filters/ScatterFilter.java b/core/src/mindustry/maps/filters/ScatterFilter.java index 7573c0a06a..dd4f0cc7b7 100644 --- a/core/src/mindustry/maps/filters/ScatterFilter.java +++ b/core/src/mindustry/maps/filters/ScatterFilter.java @@ -1,5 +1,6 @@ package mindustry.maps.filters; +import arc.util.*; import mindustry.content.Blocks; import mindustry.maps.filters.FilterOption.BlockOption; import mindustry.maps.filters.FilterOption.SliderOption; @@ -11,8 +12,9 @@ public class ScatterFilter extends GenerateFilter{ protected float chance = 0.014f; protected Block flooronto = Blocks.air, floor = Blocks.air, block = Blocks.air; - { - options( + @Override + public FilterOption[] options(){ + return Structs.arr( new SliderOption("chance", () -> chance, f -> chance = f, 0f, 1f), new BlockOption("flooronto", () -> flooronto, b -> flooronto = b, floorsOptional), new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), diff --git a/core/src/mindustry/maps/filters/TerrainFilter.java b/core/src/mindustry/maps/filters/TerrainFilter.java index d8ad659f8a..b51e938633 100644 --- a/core/src/mindustry/maps/filters/TerrainFilter.java +++ b/core/src/mindustry/maps/filters/TerrainFilter.java @@ -1,6 +1,7 @@ package mindustry.maps.filters; import arc.math.Mathf; +import arc.util.*; import mindustry.content.Blocks; import mindustry.maps.filters.FilterOption.BlockOption; import mindustry.maps.filters.FilterOption.SliderOption; @@ -13,8 +14,9 @@ public class TerrainFilter extends GenerateFilter{ float scl = 40, threshold = 0.9f, octaves = 3f, falloff = 0.5f, magnitude = 1f, circleScl = 2.1f; Block floor = Blocks.stone, block = Blocks.rocks; - { - options( + @Override + public FilterOption[] options(){ + return Structs.arr( new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), new SliderOption("mag", () -> magnitude, f -> magnitude = f, 0f, 2f), new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java new file mode 100644 index 0000000000..4128e1a162 --- /dev/null +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -0,0 +1,4 @@ +package mindustry.maps.generators; + +public class BaseGenerator{ +} diff --git a/core/src/mindustry/maps/generators/BasicGenerator.java b/core/src/mindustry/maps/generators/BasicGenerator.java index b75c50a01a..a4a22e1095 100644 --- a/core/src/mindustry/maps/generators/BasicGenerator.java +++ b/core/src/mindustry/maps/generators/BasicGenerator.java @@ -26,14 +26,14 @@ public abstract class BasicGenerator extends RandomGenerator{ } @Override - public void generate(Tile[][] tiles){ + public void generate(Tiles tiles){ int seed = Mathf.random(99999999); sim.setSeed(seed); sim2.setSeed(seed + 1); super.generate(tiles); } - public void ores(Tile[][] tiles){ + public void ores(Tiles tiles){ pass(tiles, (x, y) -> { if(ores != null){ int offsetX = x - 4, offsetY = y + 23; @@ -49,7 +49,7 @@ public abstract class BasicGenerator extends RandomGenerator{ }); } - public void terrain(Tile[][] tiles, Block dst, float scl, float mag, float cmag){ + public void terrain(Tiles tiles, Block dst, float scl, float mag, float cmag){ pass(tiles, (x, y) -> { double rocks = sim.octaveNoise2D(5, 0.5, 1f / scl, x, y) * mag + Mathf.dst((float)x / width, (float)y / height, 0.5f, 0.5f) * cmag; @@ -66,11 +66,11 @@ public abstract class BasicGenerator extends RandomGenerator{ }); } - public void noise(Tile[][] tiles, Block floor, Block block, int octaves, float falloff, float scl, float threshold){ + public void noise(Tiles tiles, Block floor, Block block, int octaves, float falloff, float scl, float threshold){ sim.setSeed(Mathf.random(99999)); pass(tiles, (x, y) -> { if(sim.octaveNoise2D(octaves, falloff, 1f / scl, x, y) > threshold){ - Tile tile = tiles[x][y]; + Tile tile = tiles.getn(x, y); this.floor = floor; if(tile.block().solid){ this.block = block; @@ -79,16 +79,16 @@ public abstract class BasicGenerator extends RandomGenerator{ }); } - public void overlay(Tile[][] tiles, Block floor, Block block, float chance, int octaves, float falloff, float scl, float threshold){ + public void overlay(Tiles tiles, Block floor, Block block, float chance, int octaves, float falloff, float scl, float threshold){ sim.setSeed(Mathf.random(99999)); pass(tiles, (x, y) -> { - if(sim.octaveNoise2D(octaves, falloff, 1f / scl, x, y) > threshold && Mathf.chance(chance) && tiles[x][y].floor() == floor){ + if(sim.octaveNoise2D(octaves, falloff, 1f / scl, x, y) > threshold && Mathf.chance(chance) && tiles.getn(x, y).floor() == floor){ ore = block; } }); } - public void tech(Tile[][] tiles){ + public void tech(Tiles tiles){ Block[] blocks = {Blocks.darkPanel3}; int secSize = 20; pass(tiles, (x, y) -> { @@ -109,13 +109,13 @@ public abstract class BasicGenerator extends RandomGenerator{ }); } - public void distort(Tile[][] tiles, float scl, float mag){ + public void distort(Tiles tiles, float scl, float mag){ Block[][] blocks = new Block[width][height]; Floor[][] floors = new Floor[width][height]; each((x, y) -> { float cx = x + noise(x, y, scl, mag) - mag / 2f, cy = y + noise(x, y + 1525215f, scl, mag) - mag / 2f; - Tile other = tiles[Mathf.clamp((int)cx, 0, width-1)][Mathf.clamp((int)cy, 0, height-1)]; + Tile other = tiles.getn(Mathf.clamp((int)cx, 0, width-1), Mathf.clamp((int)cy, 0, height-1)); blocks[x][y] = other.block(); floors[x][y] = other.floor(); }); @@ -126,7 +126,7 @@ public abstract class BasicGenerator extends RandomGenerator{ }); } - public void scatter(Tile[][] tiles, Block target, Block dst, float chance){ + public void scatter(Tiles tiles, Block target, Block dst, float chance){ pass(tiles, (x, y) -> { if(!Mathf.chance(chance)) return; if(floor == target){ @@ -149,40 +149,40 @@ public abstract class BasicGenerator extends RandomGenerator{ return (float)sim2.octaveNoise2D(1f, 0f, 1f / scl, x + 0x361266f, y + 0x251259f) * mag; } - public void pass(Tile[][] tiles, Intc2 r){ + public void pass(Tiles tiles, Intc2 r){ for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ - floor = tiles[x][y].floor(); - block = tiles[x][y].block(); - ore = tiles[x][y].overlay(); + floor = tiles.getn(x, y).floor(); + block = tiles.getn(x, y).block(); + ore = tiles.getn(x, y).overlay(); r.get(x, y); - tiles[x][y] = new Tile(x, y, floor.id, ore.id, block.id); + tiles.set(x, y, new Tile(x, y, floor, ore, block)); } } } - public void brush(Tile[][] tiles, Array path, int rad){ + public void brush(Tiles tiles, Array path, int rad){ path.each(tile -> erase(tiles, tile.x, tile.y, rad)); } - public void erase(Tile[][] tiles, int cx, int cy, int rad){ + public void erase(Tiles tiles, int cx, int cy, int rad){ for(int x = -rad; x <= rad; x++){ for(int y = -rad; y <= rad; y++){ int wx = cx + x, wy = cy + y; if(Structs.inBounds(wx, wy, width, height) && Mathf.dst(x, y, 0, 0) <= rad){ - Tile other = tiles[wx][wy]; + Tile other = tiles.getn(wx, wy); other.setBlock(Blocks.air); } } } } - public Array pathfind(Tile[][] tiles, int startX, int startY, int endX, int endY, TileHueristic th, DistanceHeuristic dh){ - Tile start = tiles[startX][startY]; - Tile end = tiles[endX][endY]; + public Array pathfind(Tiles tiles, int startX, int startY, int endX, int endY, TileHueristic th, DistanceHeuristic dh){ + Tile start = tiles.getn(startX, startY); + Tile end = tiles.getn(endX, endY); GridBits closed = new GridBits(width, height); IntFloatMap costs = new IntFloatMap(); - PriorityQueue queue = new PriorityQueue<>(tiles.length * tiles[0].length / 2, (a, b) -> Float.compare(costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y), costs.get(b.pos(), 0f) + dh.cost(b.x, b.y, end.x, end.y))); + PriorityQueue queue = new PriorityQueue<>(tiles.width() * tiles.height()/4, (a, b) -> Float.compare(costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y), costs.get(b.pos(), 0f) + dh.cost(b.x, b.y, end.x, end.y))); queue.add(start); boolean found = false; while(!queue.isEmpty()){ @@ -196,7 +196,7 @@ public abstract class BasicGenerator extends RandomGenerator{ for(Point2 point : Geometry.d4){ int newx = next.x + point.x, newy = next.y + point.y; if(Structs.inBounds(newx, newy, width, height)){ - Tile child = tiles[newx][newy]; + Tile child = tiles.getn(newx, newy); if(!closed.get(child.x, child.y)){ closed.set(child.x, child.y); child.rotation(child.relativeTo(next.x, next.y)); @@ -215,7 +215,7 @@ public abstract class BasicGenerator extends RandomGenerator{ while(current != start){ out.add(current); Point2 p = Geometry.d4(current.rotation()); - current = tiles[current.x + p.x][current.y + p.y]; + current = tiles.getn(current.x + p.x, current.y + p.y); } out.reverse(); @@ -223,17 +223,17 @@ public abstract class BasicGenerator extends RandomGenerator{ return out; } - public void inverseFloodFill(Tile[][] tiles, Tile start, Block block){ + public void inverseFloodFill(Tiles tiles, Tile start, Block block){ IntArray arr = new IntArray(); arr.add(start.pos()); while(!arr.isEmpty()){ int i = arr.pop(); int x = Pos.x(i), y = Pos.y(i); - tiles[x][y].cost = 2; + tiles.getn(x, y).cost = 2; for(Point2 point : Geometry.d4){ int newx = x + point.x, newy = y + point.y; - if(Structs.inBounds(newx, newy, width, height)){ - Tile child = tiles[newx][newy]; + if(tiles.in(newx, newy)){ + Tile child = tiles.getn(newx, newy); if(child.block() == Blocks.air && child.cost != 2){ child.cost = 2; arr.add(child.pos()); @@ -244,7 +244,7 @@ public abstract class BasicGenerator extends RandomGenerator{ for(int x = 0; x < width; x ++){ for(int y = 0; y < height; y++){ - Tile tile = tiles[x][y]; + Tile tile = tiles.getn(x, y); if(tile.cost != 2 && tile.block() == Blocks.air){ tile.setBlock(block); } diff --git a/core/src/mindustry/maps/generators/Generator.java b/core/src/mindustry/maps/generators/Generator.java index b2a09e94c0..4a535de45c 100644 --- a/core/src/mindustry/maps/generators/Generator.java +++ b/core/src/mindustry/maps/generators/Generator.java @@ -19,5 +19,5 @@ public abstract class Generator{ this.loadout = loadout; } - public abstract void generate(Tile[][] tiles); + public abstract void generate(Tiles tiles); } diff --git a/core/src/mindustry/maps/generators/MapGenerator.java b/core/src/mindustry/maps/generators/MapGenerator.java index a55222d758..da1276e28f 100644 --- a/core/src/mindustry/maps/generators/MapGenerator.java +++ b/core/src/mindustry/maps/generators/MapGenerator.java @@ -1,53 +1,33 @@ package mindustry.maps.generators; -import arc.struct.*; import arc.math.*; import arc.math.geom.*; -import arc.util.*; import mindustry.content.*; import mindustry.game.*; import mindustry.io.*; import mindustry.maps.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.*; import mindustry.world.blocks.storage.*; import static mindustry.Vars.*; +//TODO: +//- limited # of enemy spawns as filter +//- spawn loadout selection as filter +//- configure map loadout, make 1 core the default public class MapGenerator extends Generator{ private Map map; private String mapName; - private Array decorations = Array.with(new Decoration(Blocks.stone, Blocks.rock, 0.003f)); - /** - * 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; - /** Whether floor is distorted along with blocks. */ - public boolean distortFloor = false; public MapGenerator(String mapName){ this.mapName = mapName; } - public MapGenerator(String mapName, int enemySpawns){ - this.mapName = mapName; - this.enemySpawns = enemySpawns; - } - - public MapGenerator decor(Decoration... decor){ - this.decorations.addAll(decor); - return this; - } public void removePrefix(String name){ this.mapName = this.mapName.substring(name.length() + 1); } - { - decor(new Decoration(Blocks.snow, Blocks.snowrock, 0.01), new Decoration(Blocks.ignarock, Blocks.pebbles, 0.03f)); - } - public Map getMap(){ return map; } @@ -61,110 +41,44 @@ public class MapGenerator extends Generator{ } @Override - public void generate(Tile[][] tiles){ - for(int x = 0; x < width; x++){ - for(int y = 0; y < height; y++){ - tiles[x][y] = new Tile(x, y); - } - } + public void generate(Tiles tiles){ + tiles.fill(); SaveIO.load(map.file); - Array players = new Array<>(); - Array enemies = new Array<>(); - for(int x = 0; x < width; x++){ - for(int y = 0; y < height; y++){ - if(tiles[x][y].block() instanceof CoreBlock && tiles[x][y].getTeam() == state.rules.defaultTeam){ - players.add(new Point2(x, y)); - tiles[x][y].setBlock(Blocks.air); - } - - if(tiles[x][y].overlay() == Blocks.spawn && enemySpawns != -1){ - enemies.add(new Point2(x, y)); - tiles[x][y].setOverlay(Blocks.air); - } - - if(tiles[x][y].block() instanceof BlockPart){ - tiles[x][y].setBlock(Blocks.air); - } - } - } - - for(int x = 0; x < width; x++){ - for(int y = 0; y < height; y++){ - Tile tile = tiles[x][y]; - - for(Decoration decor : decorations){ - if(x > 0 && y > 0 && (tiles[x - 1][y].block() == decor.wall || tiles[x][y - 1].block() == decor.wall)){ - continue; - } - - if(tile.block() == Blocks.air && !(decor.wall instanceof Floor) && tile.floor() == decor.floor && Mathf.chance(decor.chance)){ - tile.setBlock(decor.wall); - }else if(tile.floor() == decor.floor && decor.wall.isOverlay() && Mathf.chance(decor.chance)){ - tile.setOverlay(decor.wall); - }else if(tile.floor() == decor.floor && decor.wall.isFloor() && !decor.wall.isOverlay() && Mathf.chance(decor.chance)){ - tile.setFloor((Floor)decor.wall); - } - } - - if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock) && world.getZone() != null){ - for(Item item : world.getZone().resources){ - if(Mathf.chance(0.3)){ - tile.entity.items().add(item, Math.min(Mathf.random(500), tile.block().itemCapacity)); - } + for(Tile tile : tiles){ + if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock) && world.getZone() != null){ + for(Item item : world.getZone().resources){ + if(Mathf.chance(0.3)){ + tile.entity.items().add(item, Math.min(Mathf.random(500), tile.block().itemCapacity)); } } } } - if(enemySpawns != -1){ - if(enemySpawns > enemies.size){ - throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number for map: " + mapName); + boolean anyCores = false; + + for(Tile tile : tiles){ + if(tile.overlay() == Blocks.spawn){ + int rad = 10; + Geometry.circle(tile.x, tile.y, tiles.width(), tiles.height(), rad, (wx, wy) -> { + if(tile.overlay().itemDrop != null){ + tile.clearOverlay(); + } + }); } - enemies.shuffle(); - for(int i = 0; i < enemySpawns; i++){ - Point2 point = enemies.get(i); - tiles[point.x][point.y].setOverlay(Blocks.spawn); - - int rad = 10, frad = 12; - - for(int x = -rad; x <= rad; x++){ - for(int y = -rad; y <= rad; y++){ - int wx = x + point.x, wy = y + point.y; - double dst = Mathf.dst(x, y); - if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){ - Tile tile = tiles[wx][wy]; - if(tile.overlay() != Blocks.spawn){ - tile.clearOverlay(); - } - } - } - } + if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ + schematics.placeLoadout(loadout, tile.x, tile.y); + anyCores = true; } } - Point2 core = players.random(); - if(core == null){ + if(!anyCores){ throw new IllegalArgumentException("All zone maps must have a core."); } - schematics.placeLoadout(loadout, core.x, core.y); - world.prepareTiles(tiles); world.setMap(map); } - - public static class Decoration{ - public final Block floor; - public final Block wall; - public final double chance; - - public Decoration(Block floor, Block wall, double chance){ - this.floor = floor; - this.wall = wall; - this.chance = chance; - } - } } diff --git a/core/src/mindustry/maps/generators/RandomGenerator.java b/core/src/mindustry/maps/generators/RandomGenerator.java index 039d923172..ea8b0d15ad 100644 --- a/core/src/mindustry/maps/generators/RandomGenerator.java +++ b/core/src/mindustry/maps/generators/RandomGenerator.java @@ -1,10 +1,9 @@ package mindustry.maps.generators; -import arc.struct.StringMap; -import mindustry.content.Blocks; -import mindustry.maps.Map; -import mindustry.world.Block; -import mindustry.world.Tile; +import arc.struct.*; +import mindustry.content.*; +import mindustry.maps.*; +import mindustry.world.*; import static mindustry.Vars.world; @@ -18,14 +17,14 @@ public abstract class RandomGenerator extends Generator{ } @Override - public void generate(Tile[][] tiles){ + public void generate(Tiles tiles){ for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ floor = Blocks.air; block = Blocks.air; ore = Blocks.air; generate(x, y); - tiles[x][y] = new Tile(x, y, floor.id, ore.id, block.id); + tiles.set(x, y, new Tile(x, y, floor, ore, block)); } } @@ -34,7 +33,7 @@ public abstract class RandomGenerator extends Generator{ world.setMap(new Map(new StringMap())); } - public abstract void decorate(Tile[][] tiles); + public abstract void decorate(Tiles tiles); /** * Sets {@link #floor} and {@link #block} to the correct values as output. diff --git a/core/src/mindustry/maps/planet/PlanetGenerator.java b/core/src/mindustry/maps/planet/PlanetGenerator.java new file mode 100644 index 0000000000..e0635f5553 --- /dev/null +++ b/core/src/mindustry/maps/planet/PlanetGenerator.java @@ -0,0 +1,11 @@ +package mindustry.maps.planet; + +import arc.graphics.*; +import arc.math.geom.*; +import mindustry.world.*; + +public interface PlanetGenerator{ + float getHeight(Vec3 position); + Color getColor(Vec3 position); + void generate(Vec3 position, TileGen tile); +} diff --git a/core/src/mindustry/maps/planet/TestPlanetGenerator.java b/core/src/mindustry/maps/planet/TestPlanetGenerator.java new file mode 100644 index 0000000000..a3df52e0ee --- /dev/null +++ b/core/src/mindustry/maps/planet/TestPlanetGenerator.java @@ -0,0 +1,60 @@ +package mindustry.maps.planet; + +import arc.graphics.*; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import arc.util.noise.*; +import mindustry.content.*; +import mindustry.world.*; + +public class TestPlanetGenerator implements PlanetGenerator{ + Pixmap pix; + Simplex noise = new Simplex(); + int waterLevel = 5; + float water; + float scl = 5f; + Array blocks = Array.with(Blocks.sporeMoss, Blocks.moss, Blocks.ice, Blocks.snow, Blocks.sand, Blocks.darksand, Blocks.darksandWater, Blocks.darksandTaintedWater); + + public TestPlanetGenerator(){ + try{ + pix = new Pixmap("planets/colors.png"); + water = waterLevel / (float)(pix.getHeight()); + }catch(Exception ignored){ + + } + } + + @Override + public float getHeight(Vec3 position){ + position = Tmp.v33.set(position).scl(scl); + + float height = Mathf.pow((float)noise.octaveNoise3D(7, 0.48f, 1f/3f, position.x, position.y, position.z), 2.4f); + if(height <= water){ + return water; + } + return height; + } + + @Override + public Color getColor(Vec3 position){ + float height = getHeight(position); + position = Tmp.v33.set(position).scl(scl); + float rad = scl; + float temp = Mathf.clamp(Math.abs(position.y * 2f) / (rad)); + float tnoise = (float)noise.octaveNoise3D(7, 0.48f, 1f/3f, position.x, position.y + 999f, position.z); + temp = Mathf.lerp(temp, tnoise, 0.5f); + height *= 1.2f; + height = Mathf.clamp(height); + + Color color = Tmp.c1.set(pix.getPixel((int)(temp * (pix.getWidth()-1)), (int)((1f-height) * (pix.getHeight()-1)))); + return blocks.min(c -> color.diff(c.color)).color; + } + + @Override + public void generate(Vec3 position, TileGen tile){ + Color color = getColor(position); + tile.floor = blocks.min(c -> color.diff(c.color)); + } +} diff --git a/core/src/mindustry/maps/zonegen/DesertWastesGenerator.java b/core/src/mindustry/maps/zonegen/DesertWastesGenerator.java index cf7e435825..a3ee4b6004 100644 --- a/core/src/mindustry/maps/zonegen/DesertWastesGenerator.java +++ b/core/src/mindustry/maps/zonegen/DesertWastesGenerator.java @@ -3,7 +3,7 @@ package mindustry.maps.zonegen; import arc.math.Mathf; import mindustry.content.Blocks; import mindustry.maps.generators.BasicGenerator; -import mindustry.world.Tile; +import mindustry.world.*; import static mindustry.Vars.schematics; @@ -19,7 +19,7 @@ public class DesertWastesGenerator extends BasicGenerator{ } @Override - public void decorate(Tile[][] tiles){ + public void decorate(Tiles tiles){ ores(tiles); terrain(tiles, Blocks.sandRocks, 60f, 1.5f, 0.9f); @@ -34,7 +34,7 @@ public class DesertWastesGenerator extends BasicGenerator{ erase(tiles, endX, endY, 10); erase(tiles, spawnX, spawnY, 20); distort(tiles, 20f, 4f); - inverseFloodFill(tiles, tiles[spawnX][spawnY], Blocks.sandRocks); + inverseFloodFill(tiles, tiles.getn(spawnX, spawnY), Blocks.sandRocks); noise(tiles, Blocks.salt, Blocks.saltRocks, 5, 0.6f, 200f, 0.55f); noise(tiles, Blocks.darksand, Blocks.duneRocks, 5, 0.7f, 120f, 0.5f); @@ -43,7 +43,7 @@ public class DesertWastesGenerator extends BasicGenerator{ overlay(tiles, Blocks.sand, Blocks.pebbles, 0.15f, 5, 0.8f, 30f, 0.62f); //scatter(tiles, Blocks.sandRocks, Blocks.creeptree, 1f); - tiles[endX][endY].setOverlay(Blocks.spawn); + tiles.getn(endX, endY).setOverlay(Blocks.spawn); schematics.placeLoadout(loadout, spawnX, spawnY); } } diff --git a/core/src/mindustry/maps/zonegen/OvergrowthGenerator.java b/core/src/mindustry/maps/zonegen/OvergrowthGenerator.java index e2aa0e96ca..d62eeaf076 100644 --- a/core/src/mindustry/maps/zonegen/OvergrowthGenerator.java +++ b/core/src/mindustry/maps/zonegen/OvergrowthGenerator.java @@ -1,9 +1,9 @@ package mindustry.maps.zonegen; -import arc.math.Mathf; -import mindustry.content.Blocks; -import mindustry.maps.generators.BasicGenerator; -import mindustry.world.Tile; +import arc.math.*; +import mindustry.content.*; +import mindustry.maps.generators.*; +import mindustry.world.*; import static mindustry.Vars.schematics; @@ -19,7 +19,7 @@ public class OvergrowthGenerator extends BasicGenerator{ } @Override - public void decorate(Tile[][] tiles){ + public void decorate(Tiles tiles){ ores(tiles); terrain(tiles, Blocks.sporePine, 70f, 1.4f, 1f); @@ -34,12 +34,12 @@ public class OvergrowthGenerator extends BasicGenerator{ erase(tiles, endX, endY, 10); erase(tiles, spawnX, spawnY, 20); distort(tiles, 20f, 4f); - inverseFloodFill(tiles, tiles[spawnX][spawnY], Blocks.sporerocks); + inverseFloodFill(tiles, tiles.getn(spawnX, spawnY), Blocks.sporerocks); noise(tiles, Blocks.darksandTaintedWater, Blocks.duneRocks, 4, 0.7f, 120f, 0.64f); //scatter(tiles, Blocks.sporePine, Blocks.whiteTreeDead, 1f); - tiles[endX][endY].setOverlay(Blocks.spawn); + tiles.getn(endX, endY).setOverlay(Blocks.spawn); schematics.placeLoadout(loadout, spawnX, spawnY); } } diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java new file mode 100644 index 0000000000..93a7ccb08f --- /dev/null +++ b/core/src/mindustry/type/Planet.java @@ -0,0 +1,76 @@ +package mindustry.type; + +import arc.math.geom.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.ctype.*; +import mindustry.graphics.*; +import mindustry.graphics.PlanetGrid.*; +import mindustry.maps.planet.*; + +public class Planet extends UnlockableContent{ + /** Mesh used for rendering. Created on load() - will be null on the server! */ + public PlanetMesh mesh; + /** Grid used for the sectors on the planet. */ + public @NonNull PlanetGrid grid; + /** Generator that will make the planet. */ + public @NonNull PlanetGenerator generator; + /** Array of sectors; directly maps to tiles in the grid. */ + public @NonNull Array sectors; + /** Detail in divisions. Must be between 1 and 10. 6 is a good number for this.*/ + public int detail = 3; + /** Size in terms of divisions. This only controls the amount of sectors on the planet, not the visuals. */ + public int size = 3; + /** Radius of the mesh/sphere. */ + public float radius = 1f; + + public Planet(String name){ + super(name); + } + + @Override + public void load(){ + mesh = new PlanetMesh(detail, generator); + } + + @Override + public void init(){ + grid = PlanetGrid.newGrid(size); + sectors = new Array<>(grid.tiles.length); + for(int i = 0; i < grid.tiles.length; i++){ + sectors.add(new Sector(this, grid.tiles[i])); + } + } + + /** Gets a sector a tile position. */ + public Sector getSector(Ptile tile){ + return sectors.get(tile.id); + } + + /** @return the sector that is hit by this ray, or null if nothing intersects it. + * @param center the center of this planet in 3D space, usually (0,0,0). */ + public @Nullable Sector getSector(Vec3 center, Ray ray){ + boolean found = Intersector3D.intersectRaySphere(ray, center, radius, Tmp.v33); + if(!found) return null; + //TODO fix O(N) search + return sectors.min(t -> t.tile.v.dst(Tmp.v33)); + } + + /** Planets cannot be viewed in the database dialog. */ + @Override + public boolean isHidden(){ + return true; + } + + @Override + public void displayInfo(Table table){ + + } + + @Override + public ContentType getContentType(){ + return ContentType.planet; + } +} diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java new file mode 100644 index 0000000000..3ebe6af7eb --- /dev/null +++ b/core/src/mindustry/type/Sector.java @@ -0,0 +1,66 @@ +package mindustry.type; + +import arc.math.geom.*; +import arc.util.*; +import mindustry.graphics.PlanetGrid.*; + +/** A small section of a planet. */ +//TODO should this be content? +public class Sector{ + public final SectorRect rect; + public final Planet planet; + public final Ptile tile; + + public Sector(Planet planet, Ptile tile){ + this.planet = planet; + this.tile = tile; + this.rect = makeRect(); + } + + /** Projects this sector onto a 4-corner square for use in map gen. + * Allocates a new object. Do not call in the main loop. */ + private SectorRect makeRect(){ + Vec3[] corners = new Vec3[tile.corners.length]; + for(int i = 0; i < corners.length; i++){ + corners[i] = tile.corners[i].v.cpy().setLength(planet.radius); + } + + Tmp.v33.setZero(); + for(Vec3 c : corners){ + Tmp.v33.add(c); + } + //v33 is now the center of this shape + Vec3 center = Tmp.v33.scl(1f / corners.length).cpy(); + //radius of circle + float radius = Tmp.v33.dst(corners[0]) * 0.9f; + + //get plane that these points are on + Plane plane = new Plane(); + plane.set(corners[0], corners[2], corners[4]); + + Vec3 planeTop = plane.project(center.cpy().add(0f, 1f, 0f)).sub(center).setLength(radius).add(center); + Vec3 planeRight = plane.project(center.cpy().rotate(Vec3.Y, -4f)).sub(center).setLength(radius).add(center); + + return new SectorRect(radius, center, planeTop.sub(center), planeRight.sub(center)); + } + + public static class SectorRect{ + public final Vec3 center, top, right; + public final Vec3 result = new Vec3(); + public final float radius; + + public SectorRect(float radius, Vec3 center, Vec3 top, Vec3 right){ + this.center = center; + this.top = top; + this.right = right; + this.radius = radius; + } + + /** Project a coordinate into 3D space. + * Both coordinates should be normalized to floats in the range [0, 1] */ + public Vec3 project(float x, float y){ + float nx = (x - 0.5f) * 2f, ny = (y - 0.5f) * 2f; + return result.set(center).add(right, nx).add(top, ny); + } + } +} diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java new file mode 100644 index 0000000000..b83be04262 --- /dev/null +++ b/core/src/mindustry/type/Weather.java @@ -0,0 +1,81 @@ +package mindustry.type; + +import arc.util.ArcAnnotate.*; +import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; +import mindustry.entities.*; +import mindustry.entities.traits.*; +import mindustry.entities.type.*; +import mindustry.type.Weather.*; + +import java.io.*; + +import static mindustry.Vars.*; + +public abstract class Weather extends MappableContent{ + protected float duration = 100f; + + public Weather(String name){ + super(name); + } + + public abstract void update(T entity); + + public abstract void draw(T entity); + + @Override + public ContentType getContentType(){ + return ContentType.weather; + } + + /** Represents the in-game state of a weather event. */ + @SuppressWarnings("unchecked") + public static class WeatherEntity extends BaseEntity implements SaveTrait, DrawTrait{ + /** How long this event has been occuring in ticks. */ + protected float life; + /** Type of weather that is being simulated. */ + protected @NonNull + Weather weather; + + public WeatherEntity(Weather weather){ + this.weather = weather; + } + + @Override + public void update(){ + weather.update(this); + } + + @Override + public void draw(){ + weather.draw(this); + } + + @CallSuper + @Override + public void writeSave(DataOutput stream) throws IOException{ + stream.writeShort(weather.id); + } + + @CallSuper + @Override + public void readSave(DataInput stream, byte version) throws IOException{ + weather = content.getByID(ContentType.weather, stream.readShort()); + } + + @Override + public byte version(){ + return 0; + } + + @Override + public TypeID getTypeID(){ + return null; + } + + @Override + public EntityGroup targetGroup(){ + return weatherGroup; + } + } +} diff --git a/core/src/mindustry/type/WeatherEvent.java b/core/src/mindustry/type/WeatherEvent.java deleted file mode 100644 index 05e75fabdd..0000000000 --- a/core/src/mindustry/type/WeatherEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package mindustry.type; - -import mindustry.ctype.Content; -import mindustry.ctype.ContentType; - -//currently unimplemented, see trello for implementation plans -public class WeatherEvent extends Content{ - public final String name; - - public WeatherEvent(String name){ - this.name = name; - } - - @Override - public ContentType getContentType(){ - return ContentType.weather; - } -} diff --git a/core/src/mindustry/type/Zone.java b/core/src/mindustry/type/Zone.java index d17b359546..2b8aa9a1dc 100644 --- a/core/src/mindustry/type/Zone.java +++ b/core/src/mindustry/type/Zone.java @@ -1,14 +1,12 @@ package mindustry.type; import arc.*; -import arc.struct.*; import arc.func.*; -import arc.graphics.g2d.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.ctype.UnlockableContent; +import mindustry.ctype.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Objectives.*; @@ -19,6 +17,7 @@ import static mindustry.Vars.*; public class Zone extends UnlockableContent{ public @NonNull Generator generator; public @NonNull Objective configureObjective = new ZoneWave(this, 15); + public @NonNull Planet planet; public Array requirements = new Array<>(); //TODO autogenerate public Array resources = new Array<>(); @@ -28,7 +27,6 @@ public class Zone extends UnlockableContent{ public int conditionWave = Integer.MAX_VALUE; public int launchPeriod = 10; public Schematic loadout = Loadouts.basicShard; - public TextureRegion preview; protected Array baseLaunchCost = new Array<>(); protected Array startingItems = new Array<>(); @@ -36,18 +34,14 @@ public class Zone extends UnlockableContent{ private Array defaultStartingItems = new Array<>(); - public Zone(String name, Generator generator){ + public Zone(String name, Planet planet, Generator generator){ super(name); this.generator = generator; + this.planet = planet; } public Zone(String name){ - this(name, new MapGenerator(name)); - } - - @Override - public void load(){ - preview = Core.atlas.find("zone-" + name, Core.atlas.find(name + "-zone")); + this(name, Planets.starter, new MapGenerator(name)); } public Rules getRules(){ diff --git a/core/src/mindustry/ui/dialogs/DeployDialog.java b/core/src/mindustry/ui/dialogs/DeployDialog.java index 189b451f71..462fbd1915 100644 --- a/core/src/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/mindustry/ui/dialogs/DeployDialog.java @@ -1,7 +1,6 @@ package mindustry.ui.dialogs; import arc.*; -import arc.struct.*; import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; @@ -10,10 +9,10 @@ import arc.math.*; import arc.math.geom.*; import arc.scene.*; import arc.scene.event.*; -import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.scene.utils.*; +import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.core.GameState.*; @@ -29,6 +28,7 @@ import mindustry.ui.layout.TreeLayout.*; import static mindustry.Vars.*; +//TODO remove (legacy, no longer needed) public class DeployDialog extends FloatingDialog{ private final float nodeSize = Scl.scl(230f); private ObjectSet nodes = new ObjectSet<>(); @@ -105,7 +105,7 @@ public class DeployDialog extends FloatingDialog{ bounds.y += nodeSize*0.4f; } - public void setup(){ + void setup(){ platform.updateRPC(); cont.clear(); @@ -122,7 +122,7 @@ public class DeployDialog extends FloatingDialog{ setFilter(TextureFilter.Linear); }}){{ float[] time = {0}; - setColor(Color.grays(0.3f)); + setColor(Color.gray(0.3f)); setScale(1.5f); update(() -> { setOrigin(Align.center); @@ -140,19 +140,19 @@ public class DeployDialog extends FloatingDialog{ Stack sub = new Stack(); if(slot.getZone() != null){ - sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.grays(0.1f)).grow())); + sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.gray(0.1f)).grow())); - sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> { - TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable(); - if(draw.getRegion().getTexture().isDisposed()){ - draw.setRegion(slot.getZone().preview); - } + //sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> { + //TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable(); + //if(draw.getRegion().getTexture().isDisposed()){ + // draw.setRegion(slot.getZone().preview); + // } Texture text = slot.previewTexture(); - if(draw.getRegion() == slot.getZone().preview && text != null){ - draw.setRegion(new TextureRegion(text)); - } - }).color(Color.darkGray).grow())); + //if(draw.getRegion() == slot.getZone().preview && text != null){ + // draw.setRegion(new TextureRegion(text)); + //} + // }).color(Color.darkGray).grow())); } TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName), Styles.squaret, () -> { @@ -249,12 +249,12 @@ public class DeployDialog extends FloatingDialog{ for(ZoneNode node : nodes){ Stack stack = new Stack(); Tmp.v1.set(node.width, node.height); - if(node.zone.preview != null){ - Tmp.v1.set(Scaling.fit.apply(node.zone.preview.getWidth(), node.zone.preview.getHeight(), node.width, node.height)); - } + //if(node.zone.preview != null){ + // Tmp.v1.set(Scaling.fit.apply(node.zone.preview.getWidth(), node.zone.preview.getHeight(), node.width, node.height)); + //} - stack.setSize(Tmp.v1.x, Tmp.v1.y); - stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.grays(0.2f)).grow())); + // stack.setSize(Tmp.v1.x, Tmp.v1.y); + // stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.gray(0.2f)).grow())); stack.update(() -> stack.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center)); Button button = new Button(Styles.squaret); diff --git a/core/src/mindustry/ui/dialogs/FileChooser.java b/core/src/mindustry/ui/dialogs/FileChooser.java index d877d87bdf..0b12900fed 100644 --- a/core/src/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/mindustry/ui/dialogs/FileChooser.java @@ -200,7 +200,6 @@ public class FileChooser extends FloatingDialog{ files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2); files.row(); - ButtonGroup group = new ButtonGroup<>(); group.setMinCheckCount(0); diff --git a/core/src/mindustry/ui/dialogs/GameOverDialog.java b/core/src/mindustry/ui/dialogs/GameOverDialog.java index 580f2a474a..27d4066522 100644 --- a/core/src/mindustry/ui/dialogs/GameOverDialog.java +++ b/core/src/mindustry/ui/dialogs/GameOverDialog.java @@ -92,7 +92,7 @@ public class GameOverDialog extends FloatingDialog{ hide(); state.set(State.menu); logic.reset(); - ui.deploy.show(); + ui.planet.show(); }).size(130f, 60f); }else{ buttons.addButton("$menu", () -> { diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java new file mode 100644 index 0000000000..5a8e4e7084 --- /dev/null +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -0,0 +1,30 @@ +package mindustry.ui.dialogs; + +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; + +import static mindustry.Vars.ui; + +public class PlanetDialog extends FloatingDialog{ + private PlanetRenderer renderer = new PlanetRenderer(); + + public PlanetDialog(){ + super("", Styles.fullDialog); + + addCloseButton(); + buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f); + + shown(this::setup); + } + + void setup(){ + cont.clear(); + titleTable.remove(); + + cont.addRect((x, y, w, h) -> { + renderer.render(Planets.starter); + }).grow(); + } +} diff --git a/core/src/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/mindustry/ui/dialogs/TechTreeDialog.java index c35a5899b3..0c942c7647 100644 --- a/core/src/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/mindustry/ui/dialogs/TechTreeDialog.java @@ -59,7 +59,7 @@ public class TechTreeDialog extends FloatingDialog{ treeLayout(); }); - hidden(ui.deploy::setup); + hidden(ui.planet::setup); addCloseButton(); diff --git a/core/src/mindustry/ui/dialogs/ZoneInfoDialog.java b/core/src/mindustry/ui/dialogs/ZoneInfoDialog.java index 08e0b23130..914db8c7db 100644 --- a/core/src/mindustry/ui/dialogs/ZoneInfoDialog.java +++ b/core/src/mindustry/ui/dialogs/ZoneInfoDialog.java @@ -14,6 +14,7 @@ import mindustry.ui.Cicon; import static mindustry.Vars.*; +//TODO remove public class ZoneInfoDialog extends FloatingDialog{ private LoadoutDialog loadout = new LoadoutDialog(); @@ -152,13 +153,13 @@ public class ZoneInfoDialog extends FloatingDialog{ if(!data.isUnlocked(zone)){ Sounds.unlock.play(); data.unlockContent(zone); - ui.deploy.setup(); + ui.planet.setup(); setup(zone); }else{ - ui.deploy.hide(); + ui.planet.hide(); data.removeItems(zone.getLaunchCost()); hide(); - control.playZone(zone); + //control.playZone(zone); } }).minWidth(200f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !zone.canUnlock() : !data.hasItems(zone.getLaunchCost())).uniformY().get(); diff --git a/core/src/mindustry/ui/fragments/FadeInFragment.java b/core/src/mindustry/ui/fragments/FadeInFragment.java index d6ce32541f..e34f234c46 100644 --- a/core/src/mindustry/ui/fragments/FadeInFragment.java +++ b/core/src/mindustry/ui/fragments/FadeInFragment.java @@ -21,9 +21,9 @@ public class FadeInFragment extends Fragment{ @Override public void draw(){ - Draw.color(0f, 0f, 0f, Mathf.clamp(1f - time)); - Fill.crect(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight()); - Draw.color(); + Draw.color(0f, 0f, 0f, Mathf.clamp(1f - time)); + Fill.crect(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight()); + Draw.color(); } @Override diff --git a/core/src/mindustry/ui/fragments/MenuFragment.java b/core/src/mindustry/ui/fragments/MenuFragment.java index eb3283e8df..6642847ab5 100644 --- a/core/src/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/mindustry/ui/fragments/MenuFragment.java @@ -100,7 +100,7 @@ public class MenuFragment extends Fragment{ container.defaults().size(size).pad(5).padTop(4f); MobileButton - play = new MobileButton(Icon.play, "$campaign", () -> checkPlay(ui.deploy::show)), + play = new MobileButton(Icon.play, "$campaign", () -> checkPlay(ui.planet::show)), custom = new MobileButton(Icon.rightOpenOut, "$customgame", () -> checkPlay(ui.custom::show)), maps = new MobileButton(Icon.download, "$loadgame", () -> checkPlay(ui.load::show)), join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)), @@ -165,7 +165,7 @@ public class MenuFragment extends Fragment{ buttons(t, new Buttoni("$play", Icon.play, - new Buttoni("$campaign", Icon.play, () -> checkPlay(ui.deploy::show)), + new Buttoni("$campaign", Icon.play, () -> checkPlay(ui.planet::show)), new Buttoni("$joingame", Icon.add, () -> checkPlay(ui.join::show)), new Buttoni("$customgame", Icon.terrain, () -> checkPlay(ui.custom::show)), new Buttoni("$loadgame", Icon.download, () -> checkPlay(ui.load::show)), diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index aa1626c3e9..ef296d11a3 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -35,17 +35,21 @@ public class Tile implements Position{ block = floor = overlay = (Floor)Blocks.air; } - public Tile(int x, int y, int floor, int overlay, int wall){ + public Tile(int x, int y, Block floor, Block overlay, Block wall){ this.x = (short)x; this.y = (short)y; - this.floor = (Floor)content.block(floor); - this.overlay = (Floor)content.block(overlay); - this.block = content.block(wall); + this.floor = (Floor)floor; + this.overlay = (Floor)overlay; + this.block = wall; //update entity and create it if needed changed(); } + public Tile(int x, int y, int floor, int overlay, int wall){ + this(x, y, content.block(floor), content.block(overlay), content.block(wall)); + } + /** Returns this tile's position as a {@link Pos}. */ public int pos(){ return Pos.get(x, y); diff --git a/core/src/mindustry/world/TileGen.java b/core/src/mindustry/world/TileGen.java new file mode 100644 index 0000000000..a1afdee598 --- /dev/null +++ b/core/src/mindustry/world/TileGen.java @@ -0,0 +1,19 @@ +package mindustry.world; + +import mindustry.content.*; + +public class TileGen{ + public Block floor; + public Block block ; + public Block overlay; + + { + reset(); + } + + public void reset(){ + floor = Blocks.stone; + block = Blocks.air; + overlay = Blocks.air; + } +} diff --git a/core/src/mindustry/world/Tiles.java b/core/src/mindustry/world/Tiles.java new file mode 100644 index 0000000000..b751d3d51a --- /dev/null +++ b/core/src/mindustry/world/Tiles.java @@ -0,0 +1,93 @@ +package mindustry.world; + +import arc.func.*; +import arc.util.ArcAnnotate.*; + +import java.util.*; + +/** A tile container. */ +public class Tiles implements Iterable{ + private final Tile[] array; + private final int width, height; + private final TileIterator iterator = new TileIterator(); + + public Tiles(int width, int height){ + this.array = new Tile[width * height]; + this.width = width; + this.height = height; + } + + public void each(Intc2 cons){ + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ + cons.get(x, y); + } + } + } + + /** fills this tile set with empty air tiles. */ + public void fill(){ + for(int i = 0; i < array.length; i++){ + array[i] = new Tile(i % width, i / width); + } + } + + /** set a tile at a position; does not range-check. use with caution. */ + public void set(int x, int y, Tile tile){ + array[y*width + x] = tile; + } + + /** @return whether these coordinates are in bounds */ + public boolean in(int x, int y){ + return x >= 0 && x < width && y >= 0 && y < height; + } + + /** @return a tile at coordinates, or null if out of bounds */ + public @Nullable Tile get(int x, int y){ + return (x < 0 || x >= width || y < 0 || y >= height) ? null : array[y*width + x]; + } + + /** @return a tile at coordinates; throws an exception if out of bounds */ + public @NonNull Tile getn(int x, int y){ + if(x < 0 || x >= width || y < 0 || y >= height) throw new IllegalArgumentException(x + ", " + y + " out of bounds: width=" + width + ", height=" + height); + return array[y*width + x]; + } + + /** @return a tile at an iteration index [0, width * height] */ + public @NonNull Tile geti(int idx){ + return array[idx]; + } + + /** @return a tile at an int position (not equivalent to geti) */ + public @Nullable Tile getp(int pos){ + return get(Pos.x(pos), Pos.y(pos)); + } + + public int width(){ + return width; + } + + public int height(){ + return height; + } + + @Override + public Iterator iterator(){ + iterator.index = 0; + return iterator; + } + + private class TileIterator implements Iterator{ + int index = 0; + + @Override + public boolean hasNext(){ + return index < array.length; + } + + @Override + public Tile next(){ + return array[index++]; + } + } +} diff --git a/core/src/mindustry/world/blocks/Floor.java b/core/src/mindustry/world/blocks/Floor.java index ca0fa782cd..35a6990287 100644 --- a/core/src/mindustry/world/blocks/Floor.java +++ b/core/src/mindustry/world/blocks/Floor.java @@ -6,6 +6,7 @@ import arc.graphics.g2d.*; import arc.graphics.g2d.TextureAtlas.*; import arc.math.*; import arc.math.geom.*; +import arc.util.ArcAnnotate.*; import arc.struct.*; import mindustry.content.*; import mindustry.entities.*; @@ -35,13 +36,13 @@ public class Floor extends Block{ /** Effect displayed when drowning on this floor. */ public Effect drownUpdateEffect = Fx.bubble; /** Status effect applied when walking on. */ - public StatusEffect status = StatusEffects.none; + public @NonNull StatusEffect status = StatusEffects.none; /** Intensity of applied status effect. */ public float statusDuration = 60f; /** liquids that drop from this block, used for pumps */ - public Liquid liquidDrop = null; + public @Nullable Liquid liquidDrop = null; /** item that drops from this block, used for drills */ - public Item itemDrop = null; + public @Nullable Item itemDrop = null; /** whether this block can be drowned in */ public boolean isLiquid; /** if true, this block cannot be mined by players. useful for annoying things like sand. */ diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index 0ada554894..64b1b8a711 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -46,7 +46,6 @@ public class DesktopLauncher extends ClientLauncher{ new SdlApplication(new DesktopLauncher(arg), new SdlConfig(){{ title = "Mindustry"; maximized = true; - depth = 0; stencil = 0; width = 900; height = 700; @@ -267,7 +266,7 @@ public class DesktopLauncher extends ClientLauncher{ }else{ if(ui.editor != null && ui.editor.isShown()){ uiState = "In Editor"; - }else if(ui.deploy != null && ui.deploy.isShown()){ + }else if(ui.planet != null && ui.planet.isShown()){ uiState = "In Launch Selection"; }else{ uiState = "In Menu"; diff --git a/settings.gradle b/settings.gradle index 74b7b1af99..a7356fd3c9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -28,6 +28,7 @@ if(!hasProperty("release")){ use(':Arc:extensions:recorder') use(':Arc:extensions:arcnet') use(':Arc:extensions:packer') + use(':Arc:extensions:g3d') use(':Arc:backends') use(':Arc:backends:backend-sdl') use(':Arc:backends:backend-android') diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index be672cf72b..ccd55f5574 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -109,14 +109,10 @@ public class ApplicationTests{ @Test void createMap(){ - Tile[][] tiles = world.createTiles(8, 8); + Tiles tiles = world.resize(8, 8); world.beginMapLoad(); - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - tiles[x][y] = new Tile(x, y); - } - } + tiles.fill(); world.endMapLoad(); } @@ -379,29 +375,29 @@ public class ApplicationTests{ @Test void allBlockTest(){ - Tile[][] tiles = world.createTiles(256*2 + 20, 10); + Tiles tiles = world.resize(256*2 + 20, 10); world.beginMapLoad(); - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - tiles[x][y] = new Tile(x, y, Blocks.stone.id, (byte)0, (byte)0); + for(int x = 0; x < tiles.width(); x++){ + for(int y = 0; y < tiles.height(); y++){ + tiles.set(x, y, new Tile(x, y, Blocks.stone, Blocks.air, Blocks.air)); } } int i = 0; - for(int x = 5; x < tiles.length && i < content.blocks().size; ){ + for(int x = 5; x < tiles.width() && i < content.blocks().size; ){ Block block = content.block(i++); if(block.isBuildable()){ x += block.size; - tiles[x][5].setBlock(block); + tiles.get(x, 5).setBlock(block); x += block.size; } } world.endMapLoad(); - for(int x = 0; x < tiles.length; x++){ - for(int y = 0; y < tiles[0].length; y++){ - Tile tile = world.tile(x, y); + for(int x = 0; x < tiles.width(); x++){ + for(int y = 0; y < tiles.height(); y++){ + Tile tile = world.rawTile(x, y); if(tile.entity != null){ try{ tile.entity.update(); @@ -429,7 +425,7 @@ public class ApplicationTests{ void depositTest(Block block, Item item){ BaseUnit unit = UnitTypes.spirit.create(Team.derelict); - Tile tile = new Tile(0, 0, Blocks.air.id, (byte)0, block.id); + Tile tile = new Tile(0, 0, Blocks.air, Blocks.air, block); int capacity = tile.block().itemCapacity; assertNotNull(tile.entity, "Tile should have an entity, but does not: " + tile); diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index a238a815ee..2181de1cda 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -32,12 +32,14 @@ public class ZoneTests{ Array out = new Array<>(); if(world == null) world = new World(); + fail("Zone validity tests need to be refactored!"); + for(Zone zone : content.zones()){ out.add(dynamicTest(zone.name, () -> { zone.generator.init(zone.loadout); logic.reset(); try{ - world.loadGenerator(zone.generator); + //world.loadGenerator(zone.generator); }catch(SaveException e){ e.printStackTrace(); return;