Fixed sector damage calculations / Campaign balance

This commit is contained in:
Anuken
2020-11-23 18:09:20 -05:00
parent 06929ee8f3
commit 2282cb89b1
6 changed files with 21 additions and 16 deletions

View File

@@ -88,7 +88,7 @@ public class Vars implements Loadable{
/** duration of time between turns in ticks */ /** duration of time between turns in ticks */
public static final float turnDuration = 2 * Time.toMinutes; public static final float turnDuration = 2 * Time.toMinutes;
/** chance of an invasion per turn, 1 = 100% */ /** chance of an invasion per turn, 1 = 100% */
public static final float baseInvasionChance = 1f / 55f; public static final float baseInvasionChance = 1f / 60f;
/** how many turns have to pass before invasions start */ /** how many turns have to pass before invasions start */
public static final int invasionGracePeriod = 20; public static final int invasionGracePeriod = 20;
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */ /** min armor fraction damage; e.g. 0.05 = at least 5% damage */

View File

@@ -484,6 +484,7 @@ public class TechTree implements ContentList{
new Research(bryde), new Research(bryde),
new Research(spectre), new Research(spectre),
new Research(launchPad), new Research(launchPad),
new Research(massDriver),
new Research(impactReactor), new Research(impactReactor),
new Research(additiveReconstructor), new Research(additiveReconstructor),
new Research(exponentialReconstructor) new Research(exponentialReconstructor)

View File

@@ -1413,12 +1413,12 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.missile; shootSound = Sounds.missile;
bullet = new MissileBulletType(2.7f, 12, "missile"){{ bullet = new MissileBulletType(2.7f, 12, "missile"){{
keepVelocity = true;
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.003f; drag = -0.003f;
homingRange = 60f; homingRange = 60f;
keepVelocity = false;
splashDamageRadius = 25f; splashDamageRadius = 25f;
splashDamage = 10f; splashDamage = 10f;
lifetime = 80f; lifetime = 80f;

View File

@@ -277,7 +277,7 @@ public class Waves{
int cap = 150; int cap = 150;
float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f; float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f;
float[] scaling = {1, 1.2f, 1.5f, 3f, 4f}; float[] scaling = {1, 1.2f, 2f, 3f, 4f};
Intc createProgression = start -> { Intc createProgression = start -> {
//main sequence //main sequence

View File

@@ -111,23 +111,26 @@ public class SectorDamage{
float damage = getDamage(state.rules.sector.info); float damage = getDamage(state.rules.sector.info);
//scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier) //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
float scaled = Mathf.pow(damage, 1.6f); float scaled = Mathf.pow(damage, 1.2f);
//apply damage to units
float unitDamage = damage * state.rules.sector.info.sumHealth;
Tile spawn = spawner.getFirstSpawn(); Tile spawn = spawner.getFirstSpawn();
//damage only units near the spawn point //damage only units near the spawn point
if(spawn != null){ if(spawn != null){
Seq<Unit> allies = new Seq<>(); Seq<Unit> allies = new Seq<>();
float sumUnitHealth = 0f;
for(Unit ally : Groups.unit){ for(Unit ally : Groups.unit){
if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){ if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){
allies.add(ally); allies.add(ally);
sumUnitHealth += ally.health;
} }
} }
allies.sort(u -> u.dst2(spawn)); allies.sort(u -> u.dst2(spawn));
//apply damage to units
float unitDamage = damage * sumUnitHealth;
//damage units one by one, not uniformly //damage units one by one, not uniformly
for(var u : allies){ for(var u : allies){
if(u.health < unitDamage){ if(u.health < unitDamage){
@@ -335,9 +338,9 @@ public class SectorDamage{
info.waveDpsSlope = reg.slope; info.waveDpsSlope = reg.slope;
//enemy units like to aim for a lot of non-essential things, so increase resulting health slightly //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly
info.sumHealth = sumHealth * 1.18f; info.sumHealth = sumHealth * 1.2f;
//players tend to have longer range units/turrets, so assume DPS is higher //players tend to have longer range units/turrets, so assume DPS is higher
info.sumDps = sumDps * 1.18f; info.sumDps = sumDps * 1.2f;
info.sumRps = sumRps; info.sumRps = sumRps;
info.wavesSurvived = getWavesSurvived(info); info.wavesSurvived = getWavesSurvived(info);
@@ -348,13 +351,12 @@ public class SectorDamage{
Queue<Tile> frontier = new Queue<>(); Queue<Tile> frontier = new Queue<>();
float[][] values = new float[tiles.width][tiles.height]; float[][] values = new float[tiles.width][tiles.height];
float damage = fraction*80; //arbitrary damage value
//phase one: find all spawnpoints //phase one: find all spawnpoints
for(Tile tile : tiles){ for(Tile tile : tiles){
if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){ if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){
frontier.add(tile); frontier.add(tile);
values[tile.x][tile.y] = damage; values[tile.x][tile.y] = fraction * 80;
} }
} }
@@ -368,14 +370,16 @@ public class SectorDamage{
int radius = 3; int radius = 3;
//only penetrate a certain % by health, not by distance //only penetrate a certain % by health, not by distance
float totalHealth = damage >= 1f ? 1f : path.sumf(t -> { float totalHealth = fraction >= 1f ? 1f : path.sumf(t -> {
float s = 0; float s = 0;
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
for(int dy = -radius; dy <= radius; dy++){ for(int dy = -radius; dy <= radius; dy++){
int wx = dx + t.x, wy = dy + t.y; int wx = dx + t.x, wy = dy + t.y;
if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){
Tile other = world.rawTile(wx, wy); Tile other = world.rawTile(wx, wy);
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f; if(!(other.block() instanceof CoreBlock)){
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f;
}
} }
} }
} }
@@ -385,7 +389,7 @@ public class SectorDamage{
float healthCount = 0; float healthCount = 0;
out: out:
for(int i = 0; i < path.size && (healthCount < targetHealth || damage >= 1f); i++){ for(int i = 0; i < path.size && (healthCount < targetHealth || fraction >= 1f); i++){
Tile t = path.get(i); Tile t = path.get(i);
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
@@ -405,7 +409,7 @@ public class SectorDamage{
removal.add(other.build); removal.add(other.build);
if(healthCount >= targetHealth && damage < 0.999f){ if(healthCount >= targetHealth && fraction < 0.999f){
break out; break out;
} }
} }
@@ -430,10 +434,10 @@ public class SectorDamage{
} }
} }
float falloff = (damage) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2); float falloff = (fraction) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2);
int peak = 0; int peak = 0;
if(damage > 0.1f){ if(fraction > 0.1f){
//phase two: propagate the damage //phase two: propagate the damage
while(!frontier.isEmpty()){ while(!frontier.isEmpty()){
peak = Math.max(peak, frontier.size); peak = Math.max(peak, frontier.size);