diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0b7b0ab168..b8e85c6ef5 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -328,6 +328,8 @@ zone.ruinousShores.name = Ruinous Shores zone.stainedMountains.name = Stained Mountains zone.desolateRift.name = Desolate Rift zone.nuclearComplex.name = Nuclear Production Complex +zone.overgrowth.name = Overgrowth +zone.tarFields.name = Tar Fields settings.language = Language settings.reset = Reset to Defaults diff --git a/core/assets/maps/overgrowth.mmap b/core/assets/maps/overgrowth.mmap new file mode 100644 index 0000000000..1bbb742e2f Binary files /dev/null and b/core/assets/maps/overgrowth.mmap differ diff --git a/core/assets/maps/ruinousShores.mmap b/core/assets/maps/ruinousShores.mmap index 8723b5daad..f863ac1f6f 100644 Binary files a/core/assets/maps/ruinousShores.mmap and b/core/assets/maps/ruinousShores.mmap differ diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index d481b96624..191d5a65a5 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -47,10 +47,6 @@ public class Vars{ public static final Team defaultTeam = Team.blue; /** team of the enemy in waves/sectors */ public static final Team waveTeam = Team.red; - /** how many times longer a boss wave takes */ - public static final float bossWaveMultiplier = 3f; - /** how many times longer a launch wave takes */ - public static final float launchWaveMultiplier = 2f; /** max chat message length */ public static final int maxTextLength = 150; /** max player name length in bytes */ diff --git a/core/src/io/anuke/mindustry/content/Mechs.java b/core/src/io/anuke/mindustry/content/Mechs.java index f736f4fd38..b6fffbc3e5 100644 --- a/core/src/io/anuke/mindustry/content/Mechs.java +++ b/core/src/io/anuke/mindustry/content/Mechs.java @@ -26,7 +26,6 @@ public class Mechs implements ContentList{ public void load(){ alpha = new Mech("alpha-mech", false){ - { drillPower = 1; mineSpeed = 1.5f; @@ -224,9 +223,9 @@ public class Mechs implements ContentList{ { drillPower = 1; mineSpeed = 0.9f; - speed = 0.45f; - drag = 0.1f; - health = 180f; + speed = 0.5f; + drag = 0.09f; + health = 200f; weaponOffsetX = -1; weaponOffsetY = -1; engineColor = Pal.lightTrail; @@ -234,17 +233,12 @@ public class Mechs implements ContentList{ buildPower = 1.1f; weapon = new Weapon("blaster"){{ length = 1.5f; - reload = 20f; + reload = 15f; roundrobin = true; ejectEffect = Fx.shellEjectSmall; bullet = Bullets.standardCopper; }}; } - - @Override - public boolean alwaysUnlocked(){ - return true; - } }; javelin = new Mech("javelin-ship", true){ diff --git a/core/src/io/anuke/mindustry/content/Zones.java b/core/src/io/anuke/mindustry/content/Zones.java index 9f5bb80536..ae405dcf52 100644 --- a/core/src/io/anuke/mindustry/content/Zones.java +++ b/core/src/io/anuke/mindustry/content/Zones.java @@ -1,11 +1,10 @@ package io.anuke.mindustry.content; -import io.anuke.mindustry.game.ContentList; -import io.anuke.mindustry.game.Rules; -import io.anuke.mindustry.maps.zonegen.DesertWastesGenerator; +import io.anuke.arc.collection.Array; +import io.anuke.mindustry.game.*; import io.anuke.mindustry.maps.generators.MapGenerator; import io.anuke.mindustry.maps.generators.MapGenerator.Decoration; -import io.anuke.mindustry.maps.zonegen.OvergrowthGenerator; +import io.anuke.mindustry.maps.zonegen.DesertWastesGenerator; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.Block; @@ -35,17 +34,49 @@ public class Zones implements ContentList{ desertWastes = new Zone("desertWastes", new DesertWastesGenerator(260, 260)){{ startingItems = ItemStack.list(Items.copper, 200); - conditionWave = 10; + conditionWave = 20; + launchPeriod = 10; + loadout = Loadouts.advancedShard; zoneRequirements = ZoneRequirement.with(groundZero, 15); blockRequirements = new Block[]{Blocks.router}; resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.sand}; rules = () -> new Rules(){{ waves = true; waveTimer = true; - waveSpacing = 60 * 60 * 1.5f; + launchWaveMultiplier = 3f; + waveSpacing = 60 * 30f; + spawns = Array.with( + new SpawnGroup(UnitTypes.crawler){{ + unitScaling = 3f; + }}, + new SpawnGroup(UnitTypes.dagger){{ + unitScaling = 4f; + begin = 2; + spacing = 2; + }}, + new SpawnGroup(UnitTypes.wraith){{ + unitScaling = 3f; + begin = 11; + spacing = 3; + }}, + new SpawnGroup(UnitTypes.ghoul){{ + unitScaling = 3f; + begin = 22; + unitAmount = 1; + spacing = 3; + }}, + new SpawnGroup(UnitTypes.lich){{ + unitScaling = 2f; + effect = StatusEffects.boss; + begin = 41; + spacing = 20; + }} + ); }}; }}; + //to be implemented as an attack map + /* saltFlats = new Zone("saltFlats", new DesertWastesGenerator(260, 260)){{ startingItems = ItemStack.list(Items.copper, 200); conditionWave = 10; @@ -57,20 +88,7 @@ public class Zones implements ContentList{ waveTimer = true; waveSpacing = 60 * 60 * 1.5f; }}; - }}; - - overgrowth = new Zone("overgrowth", new OvergrowthGenerator(320, 320)){{ - startingItems = ItemStack.list(Items.copper, 200); - conditionWave = 10; - zoneRequirements = ZoneRequirement.with(craters, 15); - blockRequirements = new Block[]{Blocks.router}; - resources = new Item[]{Items.copper, Items.lead, Items.coal}; - rules = () -> new Rules(){{ - waves = true; - waveTimer = true; - waveSpacing = 60 * 60 * 1.5f; - }}; - }}; + }};*/ craters = new Zone("craters", new MapGenerator("craters", 1).dist(0).decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ startingItems = ItemStack.list(Items.copper, 200); @@ -100,13 +118,28 @@ public class Zones implements ContentList{ }}; }}; + overgrowth = new Zone("overgrowth", new MapGenerator("overgrowth")){{ + startingItems = ItemStack.list(Items.copper, 3000, Items.lead, 2000, Items.silicon, 1000, Items.metaglass, 500); + conditionWave = 12; + launchPeriod = 4; + loadout = Loadouts.basicNucleus; + zoneRequirements = ZoneRequirement.with(frozenForest, 40); + blockRequirements = new Block[]{Blocks.router}; + resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.titanium, Items.sand, Items.thorium, Items.scrap}; + rules = () -> new Rules(){{ + waves = true; + waveTimer = true; + waveSpacing = 60 * 100f; + }}; + }}; + ruinousShores = new Zone("ruinousShores", new MapGenerator("ruinousShores", 1).dist(3f, true)){{ loadout = Loadouts.basicFoundation; baseLaunchCost = ItemStack.with(); startingItems = ItemStack.list(Items.copper, 400); conditionWave = 20; launchPeriod = 20; - zoneRequirements = ZoneRequirement.with(desertWastes, 10, craters, 15); + zoneRequirements = ZoneRequirement.with(desertWastes, 30, craters, 15); blockRequirements = new Block[]{Blocks.graphitePress, Blocks.combustionGenerator}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.sand}; rules = () -> new Rules(){{ @@ -155,7 +188,7 @@ public class Zones implements ContentList{ conditionWave = 15; launchPeriod = 10; zoneRequirements = ZoneRequirement.with(ruinousShores, 20); - blockRequirements = new Block[]{Blocks.pneumaticDrill}; + blockRequirements = new Block[]{Blocks.coalCentrifuge}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.sand}; rules = () -> new Rules(){{ waves = true; @@ -181,14 +214,13 @@ public class Zones implements ContentList{ }}; nuclearComplex = new Zone("nuclearComplex", new MapGenerator("nuclearProductionComplex", 1) - .drops(ItemStack.with(Items.copper, 2000, Items.lead, 1500, Items.silicon, 1000, Items.graphite, 1000, Items.thorium, 200, Items.titanium, 2000, Items.metaglass, 1000)) .decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ loadout = Loadouts.basicNucleus; baseLaunchCost = ItemStack.with(); startingItems = ItemStack.list(Items.copper, 2500, Items.lead, 3000, Items.silicon, 800, Items.metaglass, 400); conditionWave = 30; launchPeriod = 15; - zoneRequirements = ZoneRequirement.with(frozenForest, 20); + zoneRequirements = ZoneRequirement.with(stainedMountains, 20); blockRequirements = new Block[]{Blocks.thermalGenerator}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.thorium, Items.sand}; rules = () -> new Rules(){{ diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index f698bd8da5..a81d3c2702 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -58,7 +58,11 @@ public class Logic implements ApplicationListener{ public void play(){ state.set(State.playing); state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts - state.rules.spawns = world.getMap().getWaves(); + + //sometimes a map has no waves defined, they're defined in the zone rules + if(world.getMap().getWaves() != DefaultWaves.get() || !world.isZone()){ + state.rules.spawns = world.getMap().getWaves(); + } Events.fire(new PlayEvent()); } @@ -81,8 +85,8 @@ public class Logic implements ApplicationListener{ public void runWave(){ world.spawner.spawnEnemies(); state.wave++; - state.wavetime = world.isZone() && world.getZone().isBossWave(state.wave) ? state.rules.waveSpacing * bossWaveMultiplier : - world.isZone() && world.getZone().isLaunchWave(state.wave) ? state.rules.waveSpacing * launchWaveMultiplier : state.rules.waveSpacing; + state.wavetime = world.isZone() && world.getZone().isBossWave(state.wave) ? state.rules.waveSpacing * state.rules.bossWaveMultiplier : + world.isZone() && world.getZone().isLaunchWave(state.wave) ? state.rules.waveSpacing * state.rules.launchWaveMultiplier : state.rules.waveSpacing; Events.fire(new WaveEvent()); } diff --git a/core/src/io/anuke/mindustry/entities/type/Unit.java b/core/src/io/anuke/mindustry/entities/type/Unit.java index 43a46b5911..8bb69e72e1 100644 --- a/core/src/io/anuke/mindustry/entities/type/Unit.java +++ b/core/src/io/anuke/mindustry/entities/type/Unit.java @@ -354,7 +354,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public void drawStats(){ - Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), healthf() * 5f, 1f - healthf())); + Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), Math.max(healthf() * 5f, 1f), 1f - healthf())); Draw.rect(getPowerCellRegion(), x, y, rotation - 90); Draw.color(); } diff --git a/core/src/io/anuke/mindustry/game/Rules.java b/core/src/io/anuke/mindustry/game/Rules.java index bc610088f9..95faf1c90a 100644 --- a/core/src/io/anuke/mindustry/game/Rules.java +++ b/core/src/io/anuke/mindustry/game/Rules.java @@ -43,6 +43,10 @@ public class Rules{ public float respawnTime = 60 * 4; /** Time between waves in ticks. */ public float waveSpacing = 60 * 60 * 2; + /** How many times longer a boss wave takes. */ + public float bossWaveMultiplier = 3f; + /** How many times longer a launch wave takes. */ + public float launchWaveMultiplier = 2f; /** Zone ID, -1 for invalid zone. */ public byte zone = -1; /** Spawn layout. Should be assigned on save load based on map or zone. */ diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 053deef1ed..cafd2fb798 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -77,8 +77,14 @@ public class BlockRenderer implements Disposable{ for(int x = 0; x < world.width(); x++){ for(int y = 0; y < world.height(); y++){ Tile tile = world.rawTile(x, y); - if(tile.getRotation() > 0 && tile.block().solid && tile.block().fillsTile && !tile.block().synthetic()){ - Draw.color(0f, 0f, 0f, Math.min((tile.getRotation() + 0.5f) / 4f, 1f)); + int edgeBlend = 2; + float rot = tile.getRotation(); + int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (world.width() - 1)), Math.abs(y - (world.height() - 1))))); + if(edgeDst <= edgeBlend){ + rot = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), rot); + } + if(rot > 0 && ((tile.block().solid && tile.block().fillsTile && !tile.block().synthetic()) || edgeDst <= edgeBlend)){ + Draw.color(0f, 0f, 0f, Math.min((rot + 0.5f) / 4f, 1f)); Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } } diff --git a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java index 9f244d01de..93bd2e6bdb 100644 --- a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java @@ -6,10 +6,9 @@ import io.anuke.arc.math.geom.Point2; import io.anuke.arc.util.Structs; import io.anuke.arc.util.noise.Simplex; import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.content.Items; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.type.ItemStack; +import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Loadout; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; @@ -35,8 +34,6 @@ public class MapGenerator extends Generator{ public int enemySpawns = -1; /** Whether floor is distorted along with blocks. */ public boolean distortFloor = false; - /** Items randomly added to containers and vaults. */ - public ItemStack[] storageDrops = ItemStack.with(Items.copper, 300, Items.lead, 300, Items.silicon, 200, Items.graphite, 200, Items.blastCompound, 200); public MapGenerator(String mapName){ this.mapName = mapName; @@ -47,11 +44,6 @@ public class MapGenerator extends Generator{ this.enemySpawns = enemySpawns; } - public MapGenerator drops(ItemStack[] drops){ - this.storageDrops = drops; - return this; - } - public MapGenerator decor(Decoration... decor){ this.decorations.addAll(decor); return this; @@ -140,10 +132,10 @@ public class MapGenerator extends Generator{ } } - if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ - for(ItemStack stack : storageDrops){ + 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(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); + tile.entity.items.add(item, Math.min(Mathf.random(500), tile.block().itemCapacity)); } } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java index 2bb98b5cd9..38a27083f6 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java @@ -13,20 +13,16 @@ import io.anuke.arc.scene.ui.layout.Unit; import io.anuke.arc.scene.utils.UIUtils; import io.anuke.arc.util.*; import io.anuke.arc.util.pooling.Pools; -import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.Platform; import java.util.Arrays; public class FileChooser extends FloatingDialog{ - public static Predicate pngFilter = file -> file.extension().equalsIgnoreCase("png"); - public static Predicate mapFilter = file -> file.extension().equalsIgnoreCase(Vars.mapExtension); - public static Predicate jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg"); - public static Predicate defaultFilter = file -> true; + private static final FileHandle homeDirectory = Core.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : Core.files.getExternalStoragePath()); + private static FileHandle lastDirectory = homeDirectory; + private Table files; - private FileHandle homeDirectory = Core.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : - Core.files.getExternalStoragePath()); - private FileHandle directory = homeDirectory; + private FileHandle directory = lastDirectory; private ScrollPane pane; private TextField navigation, filefield; private TextButton ok; @@ -117,6 +113,7 @@ public class FileChooser extends FloatingDialog{ home.resizeImage(isize); home.clicked(() -> { directory = homeDirectory; + lastDirectory = directory; updateFiles(true); }); @@ -198,6 +195,7 @@ public class FileChooser extends FloatingDialog{ TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle"); upbutton.clicked(() -> { directory = directory.parent(); + lastDirectory = directory; updateFiles(true); }); @@ -226,6 +224,7 @@ public class FileChooser extends FloatingDialog{ updateFileFieldStatus(); }else{ directory = directory.child(filename); + lastDirectory = directory; updateFiles(true); } }); @@ -296,12 +295,14 @@ public class FileChooser extends FloatingDialog{ if(!canBack()) return; index--; directory = history.get(index - 1); + lastDirectory = directory; updateFiles(false); } public void forward(){ if(!canForward()) return; directory = history.get(index); + lastDirectory = directory; index++; updateFiles(false); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java index 3f7fcc2fe3..71a633707b 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java @@ -116,7 +116,7 @@ public class BlockInventoryFragment extends Fragment{ int row = 0; table.margin(6f); - table.defaults().size(8 * 5).space(6f); + table.defaults().size(8 * 5).space(8f); if(tile.block().hasItems){ diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index 939eac3aa2..91d5211133 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -136,6 +136,8 @@ public class ServerControl implements ApplicationListener{ Map map = previous; if(maps.size > 1){ while(map == previous) map = maps.random(); + }else if(!previous.custom && !world.maps.customMaps().isEmpty()){ + map = maps.first(); } Call.onInfoMessage((state.rules.pvp