Experimental positional spawn support / WIP map

This commit is contained in:
Anuken 2021-09-10 13:56:12 -04:00
parent 10c3f9e44a
commit 7c028ffcb8
8 changed files with 59 additions and 14 deletions

Binary file not shown.

Binary file not shown.

View file

@ -56,7 +56,7 @@ public class WaveSpawner{
public void spawnEnemies(){
spawning = true;
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
eachGroundSpawn(-1, (spawnX, spawnY, doShockwave) -> {
if(doShockwave){
doShockwave(spawnX, spawnY);
}
@ -70,7 +70,7 @@ public class WaveSpawner{
if(group.type.flying){
float spread = margin / 1.5f;
eachFlyerSpawn((spawnX, spawnY) -> {
eachFlyerSpawn(group.spawn, (spawnX, spawnY) -> {
for(int i = 0; i < spawned; i++){
Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1);
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
@ -80,7 +80,7 @@ public class WaveSpawner{
}else{
float spread = tilesize * 2;
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
eachGroundSpawn(group.spawn, (spawnX, spawnY, doShockwave) -> {
for(int i = 0; i < spawned; i++){
Tmp.v1.rnd(spread);
@ -102,12 +102,14 @@ public class WaveSpawner{
}
public void eachGroundSpawn(Intc2 cons){
eachGroundSpawn((x, y, shock) -> cons.get(World.toTile(x), World.toTile(y)));
eachGroundSpawn(-1, (x, y, shock) -> cons.get(World.toTile(x), World.toTile(y)));
}
private void eachGroundSpawn(SpawnConsumer cons){
private void eachGroundSpawn(int filterPos, SpawnConsumer cons){
if(state.hasSpawns()){
for(Tile spawn : spawns){
if(filterPos != -1 && filterPos != spawn.pos()) continue;
cons.accept(spawn.worldx(), spawn.worldy(), true);
}
}
@ -115,6 +117,8 @@ public class WaveSpawner{
if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){
Building firstCore = state.teams.playerCores().first();
for(Building core : state.rules.waveTeam.cores()){
if(filterPos != -1 && filterPos != core.pos()) continue;
Tmp.v1.set(firstCore).sub(core).limit(coreMargin + core.block.size * tilesize /2f * Mathf.sqrt2);
boolean valid = false;
@ -147,8 +151,10 @@ public class WaveSpawner{
}
}
private void eachFlyerSpawn(Floatc2 cons){
private void eachFlyerSpawn(int filterPos, Floatc2 cons){
for(Tile tile : spawns){
if(filterPos != -1 && filterPos != tile.pos()) continue;
float angle = Angles.angle(world.width() / 2f, world.height() / 2f, tile.x, tile.y);
float trns = Math.max(world.width(), world.height()) * Mathf.sqrt2 * tilesize;
float spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(angle, trns), -margin, world.width() * tilesize + margin);
@ -158,6 +164,8 @@ public class WaveSpawner{
if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){
for(Building core : state.rules.waveTeam.data().cores){
if(filterPos != -1 && filterPos != core.pos()) continue;
cons.get(core.x, core.y);
}
}
@ -171,7 +179,7 @@ public class WaveSpawner{
public int countFlyerSpawns(){
tmpCount = 0;
eachFlyerSpawn((x, y) -> tmpCount ++);
eachFlyerSpawn(-1, (x, y) -> tmpCount ++);
return tmpCount;
}

View file

@ -70,9 +70,8 @@ public class SectorPresets implements ContentList{
difficulty = 5;
}};
//TODO
if(false)
navalFortress = new SectorPreset("navalFortress", serpulo, 216){{
//TODO AI or not?
useAI = true;
difficulty = 8;
}};

View file

@ -3,6 +3,7 @@ package mindustry.editor;
import arc.*;
import arc.graphics.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
@ -316,7 +317,30 @@ public class WaveInfoDialog extends BaseDialog{
t.check("@waves.guardian", b -> {
group.effect = (b ? StatusEffects.boss : null);
buildGroups();
}).padTop(4).update(b -> b.setChecked(group.effect == StatusEffects.boss)).padBottom(8f);
}).padTop(4).update(b -> b.setChecked(group.effect == StatusEffects.boss)).padBottom(8f).row();
//spawn positions are clunky and thus experimental for now
if(experimental){
t.table(a -> {
a.add("spawn at ");
a.field(group.spawn == -1 ? "" : Point2.x(group.spawn) + "", TextFieldFilter.digitsOnly, text -> {
if(Strings.canParsePositiveInt(text)){
group.spawn = Point2.pack(Strings.parseInt(text), Point2.y(group.spawn));
Log.info(group.spawn);
}
}).width(70f);
a.add(",");
a.field(group.spawn == -1 ? "" : Point2.y(group.spawn) + "", TextFieldFilter.digitsOnly, text -> {
if(Strings.canParsePositiveInt(text)){
group.spawn = Point2.pack(Point2.x(group.spawn), Strings.parseInt(text));
Log.info(group.spawn);
}
}).width(70f);
}).padBottom(8f).padTop(-8f).row();
}
}
}).width(340f).pad(8);

View file

@ -36,10 +36,12 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
public float unitScaling = never;
/** Shield points that this unit has. */
public float shields = 0f;
/** How much shields get increased per wave. */
/** How much shields get increased by per wave. */
public float shieldScaling = 0f;
/** Amount of enemies spawned initially, with no scaling */
public int unitAmount = 1;
/** If not -1, the unit will only spawn in spawnpoints with these packed coordinates. */
public int spawn = -1;
/** Seq of payloads that this unit will spawn with. */
public @Nullable Seq<UnitType> payloads;
/** Status effect applied to the spawned unit. Null to disable. */
@ -55,6 +57,10 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
//serialization use only
}
public boolean canSpawn(int position){
return spawn == -1 || spawn == position;
}
/** @return amount of units spawned on a specific wave. */
public int getSpawned(int wave){
if(spacing == 0) spacing = 1;
@ -111,6 +117,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
if(shieldScaling != 0) json.writeValue("shieldScaling", shieldScaling);
if(unitAmount != 1) json.writeValue("amount", unitAmount);
if(effect != null) json.writeValue("effect", effect.name);
if(spawn != -1) json.writeValue("spawn", spawn);
if(payloads != null && payloads.size > 0){
json.writeValue("payloads", payloads.map(u -> u.name).toArray(String.class));
}
@ -130,6 +137,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
shields = data.getFloat("shields", 0);
shieldScaling = data.getFloat("shieldScaling", 0);
unitAmount = data.getInt("amount", 1);
spawn = data.getInt("spawn", -1);
if(data.has("payloads")){
payloads = Seq.with(json.readValue(String[].class, data.get("payloads"))).map(s -> content.getByName(ContentType.unit, s));
}

View file

@ -321,14 +321,20 @@ public class SectorDamage{
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);
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);
int spawned = group.getSpawned(wave) * spawnCount;
//save the boss group
if(group.effect == StatusEffects.boss){
bossGroup = group;

View file

@ -8,7 +8,7 @@ import static mindustry.maps.filters.FilterOption.*;
public class BlendFilter extends GenerateFilter{
float radius = 2f;
Block block = Blocks.stone, floor = Blocks.ice, ignore = Blocks.air;
Block block = Blocks.sand, floor = Blocks.sandWater, ignore = Blocks.air;
@Override
public FilterOption[] options(){
@ -16,7 +16,7 @@ public class BlendFilter extends GenerateFilter{
new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f),
new BlockOption("block", () -> block, b -> block = b, anyOptional),
new BlockOption("floor", () -> floor, b -> floor = b, anyOptional),
new BlockOption("ignore", () -> ignore, b -> ignore = b, floorsOptional)
new BlockOption("ignore", () -> ignore, b -> ignore = b, anyOptional)
};
}