Fixed #10177
This commit is contained in:
@@ -346,7 +346,7 @@ public class BulletType extends Content implements Cloneable{
|
|||||||
return spawnUnit.estimateDps();
|
return spawnUnit.estimateDps();
|
||||||
}
|
}
|
||||||
|
|
||||||
float sum = damage * (pierce ? pierceCap == -1 ? 2 : Mathf.clamp(pierceCap, 1, 2) : 1f) * splashDamage*0.75f;
|
float sum = (damage + splashDamage*0.75f) * (pierce ? pierceCap == -1 ? 2 : Mathf.clamp(pierceCap, 1, 2) : 1f);
|
||||||
if(fragBullet != null && fragBullet != this){
|
if(fragBullet != null && fragBullet != this){
|
||||||
sum += fragBullet.estimateDPS() * fragBullets / 2f;
|
sum += fragBullet.estimateDPS() * fragBullets / 2f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class SectorInfo{
|
|||||||
public transient ItemSeq lastImported = new ItemSeq();
|
public transient ItemSeq lastImported = new ItemSeq();
|
||||||
|
|
||||||
/** Special variables for simulation. */
|
/** Special variables for simulation. */
|
||||||
public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope, bossHealth, bossDps, curEnemyHealth, curEnemyDps;
|
public float sumHealth, sumRps, sumDps, bossHealth, bossDps, curEnemyHealth, curEnemyDps;
|
||||||
/** Wave where first boss shows up. */
|
/** Wave where first boss shows up. */
|
||||||
public int bossWave = -1;
|
public int bossWave = -1;
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ package mindustry.maps;
|
|||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
|
||||||
import mindustry.ai.*;
|
import mindustry.ai.*;
|
||||||
|
import mindustry.ai.types.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.core.*;
|
import mindustry.core.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.entities.abilities.*;
|
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.logic.*;
|
import mindustry.logic.*;
|
||||||
@@ -22,7 +21,7 @@ import mindustry.world.blocks.storage.*;
|
|||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class SectorDamage{
|
public class SectorDamage{
|
||||||
public static final int maxRetWave = 40, maxWavesSimulated = 50;
|
public static final int maxRetWave = 50, maxWavesSimulated = 60;
|
||||||
|
|
||||||
//direct damage is for testing only
|
//direct damage is for testing only
|
||||||
private static final boolean rubble = true;
|
private static final boolean rubble = true;
|
||||||
@@ -42,7 +41,7 @@ public class SectorDamage{
|
|||||||
return (int)getDamage(info, maxRetWave, true);
|
return (int)getDamage(info, maxRetWave, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return calculated capture progress of the enemy if retWave if false, otherwise return the maximum waves survived as int.
|
/** @return calculated capture progress of the enemy if retWave is false, otherwise return the maximum waves survived as int.
|
||||||
* if it survives all the waves, returns maxRetWave. */
|
* if it survives all the waves, returns maxRetWave. */
|
||||||
public static float getDamage(SectorInfo info, int wavesPassed, boolean retWave){
|
public static float getDamage(SectorInfo info, int wavesPassed, boolean retWave){
|
||||||
float health = info.sumHealth;
|
float health = info.sumHealth;
|
||||||
@@ -60,15 +59,29 @@ public class SectorDamage{
|
|||||||
waveBegin = waveEnd - maxWavesSimulated;
|
waveBegin = waveEnd - maxWavesSimulated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int groundSpawns = Math.max(spawner.countFlyerSpawns(), 1), airSpawns = Math.max(spawner.countGroundSpawns(), 1);
|
||||||
|
|
||||||
for(int i = waveBegin; i <= waveEnd; i++){
|
for(int i = waveBegin; i <= waveEnd; i++){
|
||||||
|
float enemyDps = 0f, enemyHealth = 0f;
|
||||||
|
|
||||||
|
for(SpawnGroup group : state.rules.spawns){
|
||||||
|
//calculate the amount of spawn points used
|
||||||
|
//if there's a spawn position override, there is only one potential place they spawn
|
||||||
|
//assume that all overridden positions are valid, should always be true in properly designed campaign maps
|
||||||
|
int spawnCount = group.spawn != -1 ? 1 : group.type.flying ? airSpawns : groundSpawns;
|
||||||
|
|
||||||
|
float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
|
||||||
|
StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
|
||||||
|
int spawned = group.getSpawned(i) * spawnCount;
|
||||||
|
if(spawned <= 0) continue;
|
||||||
|
enemyHealth += spawned * (group.getShield(i) + group.type.health * effect.healthMultiplier * healthMult);
|
||||||
|
enemyDps += spawned * group.type.dpsEstimate * effect.damageMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
float efficiency = health / info.sumHealth;
|
float efficiency = health / info.sumHealth;
|
||||||
float dps = info.sumDps * efficiency;
|
float dps = info.sumDps * efficiency;
|
||||||
float rps = info.sumRps * efficiency;
|
float rps = info.sumRps * efficiency;
|
||||||
|
|
||||||
float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i);
|
|
||||||
float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i);
|
|
||||||
|
|
||||||
if(info.bossWave == i){
|
if(info.bossWave == i){
|
||||||
enemyDps += info.bossDps;
|
enemyDps += info.bossDps;
|
||||||
enemyHealth += info.bossHealth;
|
enemyHealth += info.bossHealth;
|
||||||
@@ -320,13 +333,9 @@ public class SectorDamage{
|
|||||||
if(unit.team == state.rules.defaultTeam){
|
if(unit.team == state.rules.defaultTeam){
|
||||||
sumHealth += unit.health*healthMult + unit.shield;
|
sumHealth += unit.health*healthMult + unit.shield;
|
||||||
sumDps += unit.type.dpsEstimate;
|
sumDps += unit.type.dpsEstimate;
|
||||||
if(Structs.find(unit.abilities, a -> a instanceof RepairFieldAbility) instanceof RepairFieldAbility h){
|
sumRps += unit.type.weapons.sumf(w -> w.shotsPerSec() * (w.bullet.healPercent/100f * 20f + w.bullet.healAmount));
|
||||||
sumRps += h.amount / h.reload * 60f;
|
if(unit.controller() instanceof CommandAI ai && ai.command == UnitCommand.rebuildCommand){
|
||||||
}
|
sumRps += unit.type.buildSpeed * 20f;
|
||||||
sumRps += unit.type.weapons.sumf(w -> w.shotsPerSec() * (w.bullet.healPercent * 60f + w.bullet.healAmount));
|
|
||||||
if(unit.canBuild()){
|
|
||||||
//assume it rebuilds 1 block with 'standard' build cost (20) and health (50) every 2 seconds
|
|
||||||
sumRps += unit.type.buildSpeed * (60f / 20f) * (1f / 2f) * 50f;
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
float bossMult = unit.isBoss() ? 3f : 1f;
|
float bossMult = unit.isBoss() ? 3f : 1f;
|
||||||
@@ -335,41 +344,11 @@ public class SectorDamage{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//calculate DPS and health for the next few waves and store in list
|
SpawnGroup bossGroup = state.rules.spawns.find(s -> s.effect == StatusEffects.boss);
|
||||||
var reg = new LinearRegression();
|
|
||||||
SpawnGroup bossGroup = null;
|
|
||||||
Seq<Vec2> waveDps = new Seq<>(), waveHealth = new Seq<>();
|
|
||||||
int groundSpawns = Math.max(spawner.countFlyerSpawns(), 1), airSpawns = Math.max(spawner.countGroundSpawns(), 1);
|
|
||||||
|
|
||||||
//TODO storing all this is dumb when you can just calculate it exactly from the rules...
|
|
||||||
for(int wave = state.wave; wave < state.wave + 10; wave ++){
|
|
||||||
float sumWaveDps = 0f, sumWaveHealth = 0f;
|
|
||||||
|
|
||||||
for(SpawnGroup group : state.rules.spawns){
|
|
||||||
//calculate the amount of spawn points used
|
|
||||||
//if there's a spawn position override, there is only one potential place they spawn
|
|
||||||
//assume that all overridden positions are valid, should always be true in properly designed campaign maps
|
|
||||||
int spawnCount = group.spawn != -1 ? 1 : group.type.flying ? airSpawns : groundSpawns;
|
|
||||||
|
|
||||||
float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
|
|
||||||
StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
|
|
||||||
int spawned = group.getSpawned(wave) * spawnCount;
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
waveDps.add(new Vec2(wave, sumWaveDps));
|
|
||||||
waveHealth.add(new Vec2(wave, sumWaveHealth));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bossGroup != null){
|
if(bossGroup != null){
|
||||||
float bossMult = 1.2f;
|
float bossMult = 1.2f;
|
||||||
//calculate first boss appearaance
|
//calculate first boss appearance
|
||||||
for(int wave = state.wave; wave < state.wave + 60; wave++){
|
for(int wave = state.wave; wave < state.wave + 60; wave++){
|
||||||
int spawned = bossGroup.getSpawned(wave - 1);
|
int spawned = bossGroup.getSpawned(wave - 1);
|
||||||
if(spawned > 0){
|
if(spawned > 0){
|
||||||
@@ -382,15 +361,6 @@ public class SectorDamage{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//calculate linear regression of the wave data and store it
|
|
||||||
reg.calculate(waveHealth);
|
|
||||||
info.waveHealthBase = reg.intercept;
|
|
||||||
info.waveHealthSlope = reg.slope;
|
|
||||||
|
|
||||||
reg.calculate(waveDps);
|
|
||||||
info.waveDpsBase = reg.intercept;
|
|
||||||
info.waveDpsSlope = reg.slope;
|
|
||||||
|
|
||||||
info.sumHealth = sumHealth * 0.9f;
|
info.sumHealth = sumHealth * 0.9f;
|
||||||
info.sumDps = sumDps;
|
info.sumDps = sumDps;
|
||||||
info.sumRps = sumRps;
|
info.sumRps = sumRps;
|
||||||
|
|||||||
@@ -892,7 +892,7 @@ public class UnitType extends UnlockableContent implements Senseable{
|
|||||||
//suicide enemy
|
//suicide enemy
|
||||||
if(weapons.contains(w -> w.bullet.killShooter)){
|
if(weapons.contains(w -> w.bullet.killShooter)){
|
||||||
//scale down DPS to be insignificant
|
//scale down DPS to be insignificant
|
||||||
dpsEstimate /= 25f;
|
dpsEstimate /= 15f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user