diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 9a1b851118..b9189ec64e 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -872,7 +872,6 @@ public class UnitTypes implements ContentList{ drag = 0.01f; flying = true; health = 75; - faceTarget = false; engineOffset = 5.5f; range = 140f; @@ -1449,13 +1448,13 @@ public class UnitTypes implements ContentList{ trailMult = 0.8f; hitEffect = Fx.massiveExplosion; knockback = 1.5f; - lifetime = 140f; + lifetime = 100f; height = 15.5f; width = 15f; collidesTiles = false; ammoMultiplier = 4f; splashDamageRadius = 60f; - splashDamage = 85f; + splashDamage = 80f; backColor = Pal.missileYellowBack; frontColor = Pal.missileYellow; trailEffect = Fx.artilleryTrail; diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 88aeeabed9..c2274922de 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -96,6 +96,11 @@ public class Logic implements ApplicationListener{ Events.on(WorldLoadEvent.class, e -> { //enable infinite ammo for wave team by default state.rules.waveTeam.rules().infiniteAmmo = true; + if(state.isCampaign()){ + //enable building AI + state.rules.waveTeam.rules().ai = true; + state.rules.waveTeam.rules().infiniteResources = true; + } //save settings Core.settings.manualSave(); @@ -174,9 +179,12 @@ public class Logic implements ApplicationListener{ } //if there's a "win" wave and no enemies are present, win automatically - if(state.rules.waves && state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()){ + if(state.rules.waves && (state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()) || + (state.rules.attackMode && state.rules.waveTeam.cores().isEmpty())){ //the sector has been conquered - waves get disabled state.rules.waves = false; + //disable attack mode + state.rules.attackMode = false; //fire capture event Events.fire(new SectorCaptureEvent(state.rules.sector)); diff --git a/core/src/mindustry/game/DefaultWaves.java b/core/src/mindustry/game/DefaultWaves.java index 12d1d28dfe..f3c98f9fb4 100644 --- a/core/src/mindustry/game/DefaultWaves.java +++ b/core/src/mindustry/game/DefaultWaves.java @@ -81,7 +81,7 @@ public class DefaultWaves{ effect = StatusEffects.overdrive; }}, - new SpawnGroup(mace){{ + new SpawnGroup(pulsar){{ begin = 120; spacing = 2; unitScaling = 3; @@ -122,7 +122,7 @@ public class DefaultWaves{ shieldScaling = 30; }}, - new SpawnGroup(dagger){{ + new SpawnGroup(nova){{ begin = 35; spacing = 3; unitAmount = 4; @@ -233,7 +233,7 @@ public class DefaultWaves{ shieldScaling = 20f; }}, - new SpawnGroup(atrax){{ + new SpawnGroup(toxopid){{ begin = 210; unitAmount = 1; unitScaling = 1; @@ -258,7 +258,7 @@ public class DefaultWaves{ {nova, pulsar, quasar, vela, corvus}, {crawler, atrax, spiroct, arkyid, toxopid}, //{risso, minke, bryde, sei, omura}, //questionable choices - //{mono, poly, mega, quad, oct}, //do not attack + {poly, poly, mega, quad, quad}, {flare, horizon, zenith, antumbra, eclipse} }; diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java index 1d928b00cd..04e0be38ef 100644 --- a/core/src/mindustry/game/SectorInfo.java +++ b/core/src/mindustry/game/SectorInfo.java @@ -41,6 +41,8 @@ public class SectorInfo{ public Seq resources = new Seq<>(); /** Whether waves are enabled here. */ public boolean waves = true; + /** Whether attack mode is enabled here. */ + public boolean attack = false; /** Wave # from state */ public int wave = 1, winWave = -1; /** Time between waves. */ @@ -103,6 +105,7 @@ public class SectorInfo{ state.rules.waves = waves; state.rules.waveSpacing = waveSpacing; state.rules.winWave = winWave; + state.rules.attackMode = attack; CoreBuild entity = state.rules.defaultTeam.core(); if(entity != null){ @@ -135,6 +138,7 @@ public class SectorInfo{ wave = state.wave; winWave = state.rules.winWave; waves = state.rules.waves; + attack = state.rules.attackMode; hasCore = entity != null; bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block; storageCapacity = entity != null ? entity.storageCapacity : 0; diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 223540e601..afe2e3182b 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -38,7 +38,7 @@ public class BlockRenderer implements Disposable{ private FrameBuffer dark = new FrameBuffer(); private Seq outArray2 = new Seq<>(); private Seq shadowEvents = new Seq<>(); - private IntSet processedEntities = new IntSet(), processedLinks = new IntSet(); + private IntSet procEntities = new IntSet(), procLinks = new IntSet(), procLights = new IntSet(); private boolean displayStatus = false; public BlockRenderer(){ @@ -191,8 +191,9 @@ public class BlockRenderer implements Disposable{ tileview.clear(); lightview.clear(); - processedEntities.clear(); - processedLinks.clear(); + procEntities.clear(); + procLinks.clear(); + procLights.clear(); int minx = Math.max(avgx - rangex - expandr, 0); int miny = Math.max(avgy - rangey - expandr, 0); @@ -209,25 +210,25 @@ public class BlockRenderer implements Disposable{ tile = tile.build.tile; } - if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id))){ + if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !procEntities.contains(tile.build.id))){ if(block.expanded || !expanded){ - if(tile.build == null || processedLinks.add(tile.build.id)){ + if(tile.build == null || procLinks.add(tile.build.id)){ tileview.add(tile); if(tile.build != null){ - processedEntities.add(tile.build.id); - processedLinks.add(tile.build.id); + procEntities.add(tile.build.id); + procLinks.add(tile.build.id); } } } //lights are drawn even in the expanded range - if(tile.build != null || tile.block().emitLight){ + if(((tile.build != null && procLights.add(tile.build.pos())) || tile.block().emitLight)){ lightview.add(tile); } if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){ for(Building other : tile.build.getPowerConnections(outArray2)){ - if(other.block instanceof PowerNode && processedLinks.add(other.id)){ //TODO need a generic way to render connections! + if(other.block instanceof PowerNode && procLinks.add(other.id)){ //TODO need a generic way to render connections! tileview.add(other.tile); } } @@ -235,7 +236,7 @@ public class BlockRenderer implements Disposable{ } //special case for floors - if(block == Blocks.air && tile.floor().emitLight){ + if((block == Blocks.air && tile.floor().emitLight) && procLights.add(tile.pos())){ lightview.add(tile); } } diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java index 10ffa727b6..0a05c7409b 100644 --- a/core/src/mindustry/graphics/LightRenderer.java +++ b/core/src/mindustry/graphics/LightRenderer.java @@ -100,7 +100,6 @@ public class LightRenderer{ Draw.vert(ledge.texture, vertices, 0, vertices.length); - Vec2 v3 = Tmp.v2.trnsExact(rot, stroke); u = ledge.u; diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java index 52a129c0b7..325881760b 100644 --- a/core/src/mindustry/maps/SectorDamage.java +++ b/core/src/mindustry/maps/SectorDamage.java @@ -11,6 +11,7 @@ import mindustry.entities.abilities.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.logic.*; +import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.turrets.*; @@ -252,7 +253,10 @@ public class SectorDamage{ if(unit.isPlayer()) continue; if(unit.team == state.rules.defaultTeam){ - sumHealth += unit.health + unit.shield; + //scale health based on armor - yes, this is inaccurate, but better than nothing + float healthMult = 1f + Mathf.clamp(unit.armor / 20f); + + sumHealth += unit.health*healthMult + unit.shield; sumDps += unit.type().dpsEstimate; if(unit.abilities.find(a -> a instanceof HealFieldAbility) instanceof HealFieldAbility h){ sumRps += h.amount / h.reload * 60f; @@ -277,10 +281,12 @@ public class SectorDamage{ } for(SpawnGroup group : state.rules.spawns){ + float healthMult = 1f + Mathf.clamp(group.type.armor / 20f); + StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect); int spawned = group.getSpawned(wave); if(spawned <= 0) continue; - sumWaveHealth += spawned * (group.getShield(wave) + group.type.health); - sumWaveDps += spawned * group.type.dpsEstimate; + sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult); + sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier; } waveDps.add(new Vec2(wave, sumWaveDps)); waveHealth.add(new Vec2(wave, sumWaveHealth)); @@ -295,7 +301,8 @@ public class SectorDamage{ info.waveDpsBase = reg.intercept; info.waveDpsSlope = reg.slope; - info.sumHealth = sumHealth; + //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly + info.sumHealth = sumHealth * 1.2f; info.sumDps = sumDps; info.sumRps = sumRps; diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index b4bef2c05c..71045e166b 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -26,7 +26,7 @@ public class StorageBlock extends Block{ } public static void incinerateEffect(Building self, Building source){ - if(Mathf.chance(0.1)){ + if(Mathf.chance(0.3)){ Tile edge = Edges.getFacingEdge(source, self); Tile edge2 = Edges.getFacingEdge(self, source); if(edge != null && edge2 != null){