diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index a5303bc3d6..72736cae65 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1460,7 +1460,7 @@ unit.reign.description = Fires a barrage of massive piercing bullets at all near unit.nova.description = Fires laser bolts that damage enemies and repair allied structures. Capable of flight. unit.pulsar.description = Fires arcs of electricity that damage enemies and repair allied structures. Capable of flight. unit.quasar.description = Fires piercing laser beams that damage enemies and repair allied structures. Capable of flight. Shielded. -unit.vela.description = Fires a massive continuous laser beam that damages enemies, causes fires and repair allied structures. Capable of flight. +unit.vela.description = Fires a massive continuous laser beam that damages enemies, causes fires and repairs allied structures. Capable of flight. unit.corvus.description = Fires a massive laser blast that damages enemies and repairs allied structures. Can step over most terrain. unit.crawler.description = Runs toward enemies and self-destructs, causing a large explosion. unit.atrax.description = Fires debilitating orbs of slag at ground targets. Can step over most terrain. diff --git a/core/assets/maps/biomassFacility.msav b/core/assets/maps/biomassFacility.msav index bf16a3b7ea..738d890f70 100644 Binary files a/core/assets/maps/biomassFacility.msav and b/core/assets/maps/biomassFacility.msav differ diff --git a/core/assets/maps/craters.msav b/core/assets/maps/craters.msav index 94bba211ac..c52303c3a1 100644 Binary files a/core/assets/maps/craters.msav and b/core/assets/maps/craters.msav differ diff --git a/core/assets/maps/desolateRift.msav b/core/assets/maps/desolateRift.msav index ca3181301a..71c433d81a 100644 Binary files a/core/assets/maps/desolateRift.msav and b/core/assets/maps/desolateRift.msav differ diff --git a/core/assets/maps/impact0078.msav b/core/assets/maps/impact0078.msav index 44279fec16..08a71a5673 100644 Binary files a/core/assets/maps/impact0078.msav and b/core/assets/maps/impact0078.msav differ diff --git a/core/assets/maps/nuclearComplex.msav b/core/assets/maps/nuclearComplex.msav index b56ea9a866..1b15a5878b 100644 Binary files a/core/assets/maps/nuclearComplex.msav and b/core/assets/maps/nuclearComplex.msav differ diff --git a/core/assets/maps/planetaryTerminal.msav b/core/assets/maps/planetaryTerminal.msav index c705da368f..f5a7df9a00 100644 Binary files a/core/assets/maps/planetaryTerminal.msav and b/core/assets/maps/planetaryTerminal.msav differ diff --git a/core/assets/maps/ruinousShores.msav b/core/assets/maps/ruinousShores.msav index 48727feae4..441fb2044d 100644 Binary files a/core/assets/maps/ruinousShores.msav and b/core/assets/maps/ruinousShores.msav differ diff --git a/core/assets/maps/stainedMountains.msav b/core/assets/maps/stainedMountains.msav index 082f96ad7b..b5ec28c9d4 100644 Binary files a/core/assets/maps/stainedMountains.msav and b/core/assets/maps/stainedMountains.msav differ diff --git a/core/assets/maps/tarFields.msav b/core/assets/maps/tarFields.msav index 1ec074997c..04055ac8b7 100644 Binary files a/core/assets/maps/tarFields.msav and b/core/assets/maps/tarFields.msav differ diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 12819feff6..d0995ca3a8 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -88,7 +88,7 @@ public class Vars implements Loadable{ /** duration of time between turns in ticks */ public static final float turnDuration = 2 * Time.toMinutes; /** chance of an invasion per turn, 1 = 100% */ - public static final float baseInvasionChance = 1f / 85f; + public static final float baseInvasionChance = 1f / 100f; /** how many turns have to pass before invasions start */ public static final int invasionGracePeriod = 20; /** min armor fraction damage; e.g. 0.05 = at least 5% damage */ diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java index 395493d57f..dd34626dcb 100644 --- a/core/src/mindustry/ai/BaseAI.java +++ b/core/src/mindustry/ai/BaseAI.java @@ -55,11 +55,12 @@ public class BaseAI{ public void update(){ if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){ CoreBlock block = (CoreBlock)data.core().block; + int coreUnits = Groups.unit.count(u -> u.team == data.team && u.type == block.unitType); - //create AI core unit - if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type == block.unitType)){ + //create AI core unit(s) + if(!state.isEditor() && coreUnits < data.cores.size){ Unit unit = block.unitType.create(data.team); - unit.set(data.core()); + unit.set(data.cores.random()); unit.add(); Fx.spawn.at(unit); } diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java index dbfddbc142..e84547dd5f 100644 --- a/core/src/mindustry/content/SectorPresets.java +++ b/core/src/mindustry/content/SectorPresets.java @@ -83,7 +83,7 @@ public class SectorPresets implements ContentList{ }}; desolateRift = new SectorPreset("desolateRift", serpulo, 123){{ - captureWave = 30; + captureWave = 18; difficulty = 8; }}; diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java index 6d82895b97..a20917c054 100644 --- a/core/src/mindustry/content/TechTree.java +++ b/core/src/mindustry/content/TechTree.java @@ -471,7 +471,8 @@ public class TechTree implements ContentList{ node(desolateRift, Seq.with( new SectorComplete(impact0078), new Research(thermalGenerator), - new Research(thoriumReactor) + new Research(thoriumReactor), + new Research(coreNucleus) ), () -> { node(planetaryTerminal, Seq.with( new SectorComplete(desolateRift), diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 3dd1d1f20f..ca74a26868 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -620,7 +620,7 @@ public class UnitTypes implements ContentList{ drag = 0.4f; hitSize = 12f; rotateSpeed = 3f; - health = 800; + health = 900; immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); legCount = 6; legLength = 13f; @@ -651,7 +651,7 @@ public class UnitTypes implements ContentList{ bullet = new SapBulletType(){{ sapStrength = 0.4f; length = 75f; - damage = 18; + damage = 20; shootEffect = Fx.shootSmall; hitColor = color = Color.valueOf("bf92f9"); despawnEffect = Fx.none; @@ -671,7 +671,7 @@ public class UnitTypes implements ContentList{ bullet = new SapBulletType(){{ sapStrength = 0.8f; length = 40f; - damage = 15; + damage = 16; shootEffect = Fx.shootSmall; hitColor = color = Color.valueOf("bf92f9"); despawnEffect = Fx.none; @@ -1252,8 +1252,8 @@ public class UnitTypes implements ContentList{ mineTier = 3; mineSpeed = 4f; - health = 500; - armor = 5f; + health = 460; + armor = 3f; speed = 2.5f; accel = 0.06f; drag = 0.017f; diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java index 0d5c47e56a..2006e6fb05 100644 --- a/core/src/mindustry/content/Weathers.java +++ b/core/src/mindustry/content/Weathers.java @@ -53,7 +53,7 @@ public class Weathers implements ContentList{ baseSpeed = 5.4f; attrs.set(Attribute.light, -0.1f); attrs.set(Attribute.water, -0.1f); - opacityMultiplier = 0.4f; + opacityMultiplier = 0.35f; force = 0.1f; sound = Sounds.wind; soundVol = 0.8f; diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 2a1c79f107..4f4f45bd64 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -336,6 +336,8 @@ public class Control implements ApplicationListener, Loadable{ state.wavetime = state.rules.waveSpacing * 2f; //reset captured state sector.info.wasCaptured = false; + //re-enable waves + state.rules.waves = true; //reset win wave?? state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : 40; diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index c4819ed222..a167a32ecb 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -311,7 +311,7 @@ public class World{ //TODO bad code boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow"); boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand"); - boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand"); + boolean hasDesert = !hasSnow && !hasRain && floors[0] == Blocks.sand; boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted"); if(hasSnow){ diff --git a/core/src/mindustry/editor/WaveGraph.java b/core/src/mindustry/editor/WaveGraph.java index e908e7d934..d6a33bf6ff 100644 --- a/core/src/mindustry/editor/WaveGraph.java +++ b/core/src/mindustry/editor/WaveGraph.java @@ -17,7 +17,7 @@ import mindustry.ui.*; public class WaveGraph extends Table{ public Seq groups = new Seq<>(); - public int from, to = 20; + public int from = 0, to = 20; private Mode mode = Mode.counts; private int[][] values; @@ -114,7 +114,7 @@ public class WaveGraph extends Table{ Lines.line(cx, cy, cx, cy + len); if(i == values.length/2){ - font.draw("" + (i + from), cx, cy - 2f, Align.center); + font.draw("" + (i + from + 1), cx, cy - 2f, Align.center); } } font.setColor(Color.white); diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java index 50425ec4af..2701fc1dcb 100644 --- a/core/src/mindustry/game/SectorInfo.java +++ b/core/src/mindustry/game/SectorInfo.java @@ -71,7 +71,9 @@ public class SectorInfo{ public boolean shown = false; /** Special variables for simulation. */ - public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope; + public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope, bossHealth, bossDps; + /** Wave where first boss shows up. */ + public int bossWave = -1; /** Counter refresh state. */ private transient Interval time = new Interval(); diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java index 9c3a614350..0aa1407879 100644 --- a/core/src/mindustry/game/Universe.java +++ b/core/src/mindustry/game/Universe.java @@ -6,6 +6,7 @@ import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.game.EventType.*; +import mindustry.game.SectorInfo.*; import mindustry.maps.*; import mindustry.type.*; import mindustry.world.blocks.storage.*; @@ -199,6 +200,13 @@ public class Universe{ } } + sector.info.export.each((item, amount) -> { + if(sector.info.items.get(item) <= 0 && sector.info.production.get(item, ExportStat::new).mean <= 0){ + //disable export when production is negative. + sector.info.export.get(item).mean = 0f; + } + }); + //add production, making sure that it's capped sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item)))); //prevent negative values with unloaders diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java index 128ec3fcd2..e2da570bf8 100644 --- a/core/src/mindustry/maps/SectorDamage.java +++ b/core/src/mindustry/maps/SectorDamage.java @@ -68,6 +68,11 @@ public class SectorDamage{ float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i); float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i); + if(info.bossWave == i){ + enemyDps += info.bossDps; + enemyHealth += info.bossHealth; + } + //happens due to certain regressions if(enemyHealth < 0 || enemyDps < 0) continue; @@ -305,6 +310,7 @@ public class SectorDamage{ //calculate DPS and health for the next few waves and store in list var reg = new LinearRegression(); + SpawnGroup bossGroup = null; Seq waveDps = new Seq<>(), waveHealth = new Seq<>(); for(int wave = state.wave; wave < state.wave + 10; wave ++){ @@ -320,6 +326,11 @@ public class SectorDamage{ float healthMult = 1f + Mathf.clamp(group.type.armor / 20f); StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect); int spawned = group.getSpawned(wave); + //save the boss group + if(group.effect == StatusEffects.boss){ + bossGroup = group; + continue; + } if(spawned <= 0) continue; sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult); sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier; @@ -328,6 +339,21 @@ public class SectorDamage{ waveHealth.add(new Vec2(wave, sumWaveHealth)); } + if(bossGroup != null){ + float bossMult = 1.1f; + //calculate first boss appearaance + for(int wave = state.wave; wave < state.wave + 60; wave++){ + int spawned = bossGroup.getSpawned(wave - 1); + if(spawned > 0){ + //set up relevant stats + info.bossWave = wave; + info.bossDps = spawned * bossGroup.type.dpsEstimate * StatusEffects.boss.damageMultiplier * bossMult; + info.bossHealth = spawned * (bossGroup.getShield(wave) + bossGroup.type.health * StatusEffects.boss.healthMultiplier * (1f + Mathf.clamp(bossGroup.type.armor / 20f))) * bossMult; + break; + } + } + } + //calculate linear regression of the wave data and store it reg.calculate(waveHealth); info.waveHealthBase = reg.intercept; @@ -356,7 +382,7 @@ public class SectorDamage{ for(Tile tile : tiles){ if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){ frontier.add(tile); - values[tile.x][tile.y] = fraction * 26; + values[tile.x][tile.y] = fraction * 24; } } diff --git a/core/src/mindustry/maps/planet/TantrosPlanetGenerator.java b/core/src/mindustry/maps/planet/TantrosPlanetGenerator.java index 934291dab8..d74f94e250 100644 --- a/core/src/mindustry/maps/planet/TantrosPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/TantrosPlanetGenerator.java @@ -3,6 +3,8 @@ package mindustry.maps.planet; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; +import mindustry.content.*; +import mindustry.game.*; import mindustry.maps.generators.*; public class TantrosPlanetGenerator extends PlanetGenerator{ @@ -18,4 +20,13 @@ public class TantrosPlanetGenerator extends PlanetGenerator{ float depth = (float)noise.octaveNoise3D(2, 0.56, 1.7f, position.x, position.y, position.z) / 2f; return c1.write(out).lerp(c2, Mathf.clamp(Mathf.round(depth, 0.15f))).a(0.6f); } + + @Override + protected void generate(){ + pass((x, y) -> { + floor = Blocks.deepwater; + }); + + Schematics.placeLaunchLoadout(width / 2, height / 2); + } } diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java index a9741b5241..bb6b444746 100644 --- a/core/src/mindustry/type/Weather.java +++ b/core/src/mindustry/type/Weather.java @@ -262,7 +262,7 @@ public abstract class Weather extends UnlockableContent{ /** Creates a weather entry with some approximate weather values. */ public WeatherEntry(Weather weather){ - this(weather, weather.duration * 3f, weather.duration * 6f, weather.duration / 2f, weather.duration * 1.5f); + this(weather, weather.duration * 2f, weather.duration * 6f, weather.duration / 2f, weather.duration * 1.5f); } public WeatherEntry(Weather weather, float minFrequency, float maxFrequency, float minDuration, float maxDuration){ diff --git a/core/src/mindustry/ui/Bar.java b/core/src/mindustry/ui/Bar.java index 8e3bd511de..8051b67678 100644 --- a/core/src/mindustry/ui/Bar.java +++ b/core/src/mindustry/ui/Bar.java @@ -78,6 +78,9 @@ public class Bar extends Element{ lastValue = computed; } + if(Float.isNaN(computed)) computed = 0; + if(Float.isInfinite(computed)) computed = 1f; + blink = Mathf.lerpDelta(blink, 0f, 0.2f); value = Mathf.lerpDelta(value, computed, 0.15f); diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index b3218ea7be..0b6181c80d 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -311,7 +311,7 @@ public class Conveyor extends Block implements Autotiler{ if(len >= capacity) return false; Tile facing = Edges.getFacingEdge(source.tile, tile); int direction = Math.abs(facing.relativeTo(tile.x, tile.y) - rotation); - return (((direction == 0) && minitem >= itemSpace) || ((direction % 2 == 1) && minitem > 0.7f)) && !(source.block.rotate && (source.rotation + 2) % 4 == rotation); + return (((direction == 0) && minitem >= itemSpace) || ((direction % 2 == 1) && minitem > 0.7f)) && !(source.block.rotate && next == source); } @Override diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index 6e310d0e55..efaeaec5ba 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -93,7 +93,7 @@ public class ItemBridge extends Block{ Draw.reset(); Draw.color(Pal.placing); Lines.stroke(1f); - if(link != null){ + if(link != null && Math.abs(link.x - x) + Math.abs(link.y - y) > 1){ int rot = link.absoluteRelativeTo(x, y); float w = (link.x == x ? tilesize : Math.abs(link.x - x) * tilesize - tilesize); float h = (link.y == y ? tilesize : Math.abs(link.y - y) * tilesize - tilesize); @@ -145,7 +145,7 @@ public class ItemBridge extends Block{ if(config != null) return; Tile link = findLink(tile.x, tile.y); - if(linkValid(tile, link)){ + if(linkValid(tile, link) && !proximity.contains(link.build)){ link.build.configure(tile.pos()); } diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index b7581b4dfb..7bfda601d1 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -10,6 +10,8 @@ import mindustry.world.*; import mindustry.world.blocks.storage.CoreBlock.*; import mindustry.world.meta.*; +import static mindustry.Vars.*; + public class StorageBlock extends Block{ public StorageBlock(String name){ @@ -57,6 +59,24 @@ public class StorageBlock extends Block{ } } + @Override + public void itemTaken(Item item){ + if(linkedCore != null){ + linkedCore.itemTaken(item); + } + } + + @Override + public int removeStack(Item item, int amount){ + int result = super.removeStack(item, amount); + + if(linkedCore != null && team == state.rules.defaultTeam && state.isCampaign()){ + state.rules.sector.info.handleCoreItem(item, -result); + } + + return result; + } + @Override public int getMaximumAccepted(Item item){ return itemCapacity; diff --git a/gradle.properties b/gradle.properties index e5c7e5fe4d..c95e0534b6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=7a2a357f6cfdc3725ce581093a0ced91f4474222 +archash=2d451f0c342755ef84e609c951a8fca654ef41b5