mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-25 05:51:47 -08:00
Experimental positional spawn support / WIP map
This commit is contained in:
parent
10c3f9e44a
commit
7c028ffcb8
8 changed files with 59 additions and 14 deletions
Binary file not shown.
BIN
core/assets/maps/navalFortress.msav
Normal file
BIN
core/assets/maps/navalFortress.msav
Normal file
Binary file not shown.
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue