Better launch / Better spawns / Tweaks

This commit is contained in:
Anuken
2019-01-27 18:09:59 -05:00
parent da9278ad8d
commit db2e6b6973
27 changed files with 1636 additions and 1479 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

+3 -1
View File
@@ -247,8 +247,10 @@ locked = Locked
complete = [LIGHT_GRAY]Complete: complete = [LIGHT_GRAY]Complete:
resume = Resume Zone:\n[LIGHT_GRAY]{0} resume = Resume Zone:\n[LIGHT_GRAY]{0}
bestwave = [LIGHT_GRAY]Best: {0} bestwave = [LIGHT_GRAY]Best: {0}
launch = Launch launch = < LAUNCH >
launch.title = Launch Successful launch.title = Launch Successful
launch.next = [LIGHT_GRAY]next opportunity at wave {0}
launch.unable = [scarlet]Unable to LAUNCH.[] Enemies.
zone.unlocked = [LIGHT_GRAY]{0} unlocked. zone.unlocked = [LIGHT_GRAY]{0} unlocked.
connectfail = [crimson]Failed to connect to server:\n\n[accent]{0} connectfail = [crimson]Failed to connect to server:\n\n[accent]{0}
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1020 KiB

@@ -2,13 +2,24 @@ package io.anuke.mindustry.ai;
import io.anuke.arc.Events; import io.anuke.arc.Events;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.IntArray;
import io.anuke.arc.entities.Effects;
import io.anuke.arc.math.Angles; import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Time;
import io.anuke.arc.util.Tmp;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Damage;
import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.Squad; import io.anuke.mindustry.entities.units.Squad;
import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.SpawnGroup; import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.world.Pos;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -16,11 +27,31 @@ public class WaveSpawner{
private Array<SpawnGroup> groups; private Array<SpawnGroup> groups;
private Array<FlyerSpawn> flySpawns = new Array<>(); private Array<FlyerSpawn> flySpawns = new Array<>();
private Array<GroundSpawn> groundSpawns = new Array<>(); private Array<GroundSpawn> groundSpawns = new Array<>();
private IntArray loadedSpawns = new IntArray();
public WaveSpawner(){ public WaveSpawner(){
Events.on(WorldLoadEvent.class, e -> reset()); Events.on(WorldLoadEvent.class, e -> reset());
} }
public void write(DataOutput stream) throws IOException{
stream.writeInt(groundSpawns.size);
for(GroundSpawn spawn : groundSpawns){
stream.writeInt(Pos.get(spawn.x, spawn.y));
}
}
public void read(DataInput stream) throws IOException{
flySpawns.clear();
groundSpawns.clear();
loadedSpawns.clear();
int amount = stream.readInt();
for(int i = 0; i < amount; i++){
loadedSpawns.add(stream.readInt());
}
}
public void spawnEnemies(){ public void spawnEnemies(){
for(SpawnGroup group : groups){ for(SpawnGroup group : groups){
@@ -51,15 +82,23 @@ public class WaveSpawner{
Squad squad = new Squad(); Squad squad = new Squad();
spawnX = spawn.x * tilesize; spawnX = spawn.x * tilesize;
spawnY = spawn.y * tilesize; spawnY = spawn.y * tilesize;
spread = tilesize; spread = tilesize*3;
for(int i = 0; i < spawned; i++){ for(int i = 0; i < spawned; i++){
Tmp.v1.rnd(spread);
BaseUnit unit = group.createUnit(waveTeam); BaseUnit unit = group.createUnit(waveTeam);
unit.setWave(); unit.setWave();
unit.setSquad(squad); unit.setSquad(squad);
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
unit.add();
Time.run(i*5, () -> {
shockwave(unit);
});
} }
Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize));
//would be interesting to see player structures survive this without hacks
Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, 350f + Mathf.random(80f), 99999999f));
} }
} }
} }
@@ -73,6 +112,23 @@ public class WaveSpawner{
for(int x = 0; x < world.width(); x++){ for(int x = 0; x < world.width(); x++){
for(int y = 0; y < world.height(); y++){ for(int y = 0; y < world.height(); y++){
if(world.tile(x, y).block() == Blocks.spawn){ if(world.tile(x, y).block() == Blocks.spawn){
addSpawns(x, y);
//hide spawnpoints, they have served their purpose
world.tile(x, y).setBlock(Blocks.air);
}
}
}
for(int i = 0; i < loadedSpawns.size; i++){
int pos = loadedSpawns.get(i);
addSpawns(Pos.x(pos), Pos.y(pos));
}
loadedSpawns.clear();
}
private void addSpawns(int x, int y){
GroundSpawn spawn = new GroundSpawn(); GroundSpawn spawn = new GroundSpawn();
spawn.x = x; spawn.x = x;
spawn.y = y; spawn.y = y;
@@ -82,8 +138,13 @@ public class WaveSpawner{
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y); fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
flySpawns.add(fspawn); flySpawns.add(fspawn);
} }
}
} private void shockwave(BaseUnit unit){
Effects.effect(Fx.unitSpawn, unit.x, unit.y, 0f, unit);
Time.run(30f, () -> {
unit.add();
Effects.effect(Fx.spawn, unit);
});
} }
private class FlyerSpawn{ private class FlyerSpawn{
@@ -33,7 +33,7 @@ public class Blocks implements ContentList{
//environment //environment
air, part, spawn, space, metalfloor, deepwater, water, tar, stone, craters, charr, blackstone, dirt, sand, ice, snow, air, part, spawn, space, metalfloor, deepwater, water, tar, stone, craters, charr, blackstone, dirt, sand, ice, snow,
grass, shrub, rock, icerock, blackrock, rocks, cliffs, pine, grass, shrub, rock, icerock, blackrock, rocks, cliffs, pine, whiteTree,
//crafting //crafting
siliconSmelter, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer, siliconSmelter, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
@@ -223,6 +223,9 @@ public class Blocks implements ContentList{
variants = 0; variants = 0;
}}; }};
whiteTree = new TreeBlock("white-tree-dead"){{
}};
//endregion //endregion
//region crafting //region crafting
@@ -860,9 +863,6 @@ public class Blocks implements ContentList{
health = 1100; health = 1100;
itemCapacity = 1000; itemCapacity = 1000;
launchThreshold = 500;
launchTime = 60f * 10;
launchChunkSize = 100;
}}; }};
vault = new Vault("vault"){{ vault = new Vault("vault"){{
+25 -3
View File
@@ -10,6 +10,7 @@ import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Tmp; import io.anuke.arc.util.Tmp;
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect; import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.ContentList; import io.anuke.mindustry.game.ContentList;
import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shapes; import io.anuke.mindustry.graphics.Shapes;
@@ -32,13 +33,27 @@ public class Fx implements ContentList{
bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke,
shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium, shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium,
shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot, shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot,
launchFull; launchFull, unitSpawn, spawnShockwave;
@Override @Override
public void load(){ public void load(){
none = new Effect(0, 0f, e -> {}); none = new Effect(0, 0f, e -> {});
unitSpawn = new Effect(30f, e -> {
if(!(e.data instanceof BaseUnit)) return;
Draw.alpha(e.fin());
float scl = 1f + e.fout()*2f;
BaseUnit unit = (BaseUnit)e.data;
Draw.rect(unit.getIconRegion(), e.x, e.y,
unit.getIconRegion().getWidth() * Draw.scl * scl, unit.getIconRegion().getWidth() * Draw.scl * scl, 180f);
Draw.reset();
});
placeBlock = new Effect(16, e -> { placeBlock = new Effect(16, e -> {
Draw.color(Palette.accent); Draw.color(Palette.accent);
Lines.stroke(3f - e.fin() * 2f); Lines.stroke(3f - e.fin() * 2f);
@@ -78,10 +93,10 @@ public class Fx implements ContentList{
Draw.reset(); Draw.reset();
}); });
spawn = new Effect(23, e -> { spawn = new Effect(30, e -> {
Lines.stroke(2f * e.fout()); Lines.stroke(2f * e.fout());
Draw.color(Palette.accent); Draw.color(Palette.accent);
Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f); Lines.poly(e.x, e.y, 4, 5f + e.fin() * 12f);
Draw.reset(); Draw.reset();
}); });
@@ -545,6 +560,13 @@ public class Fx implements ContentList{
Draw.reset(); Draw.reset();
}); });
spawnShockwave = new Effect(20f, 400f, e -> {
Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin());
Lines.stroke(e.fout() * 3f + 0.5f);
Lines.poly(e.x, e.y, 60, e.fin() * 450f);
Draw.reset();
});
explosion = new Effect(30, e -> { explosion = new Effect(30, e -> {
e.scaled(7, i -> { e.scaled(7, i -> {
Lines.stroke(3f * i.fout()); Lines.stroke(3f * i.fout());
@@ -59,8 +59,6 @@ public class Zones implements ContentList{
}}; }};
craters = new Zone("craters", new MapGenerator("craters", 1){{ distortion = 0; }}){{ craters = new Zone("craters", new MapGenerator("craters", 1){{ distortion = 0; }}){{
alwaysUnlocked = true;
deployCost = ItemStack.with(Items.copper, 300); deployCost = ItemStack.with(Items.copper, 300);
startingItems = ItemStack.with(Items.copper, 200); startingItems = ItemStack.with(Items.copper, 200);
conditionWave = 15; conditionWave = 15;
@@ -108,7 +106,8 @@ public class Zones implements ContentList{
}}; }};
}}; }};
frozenForest = new Zone("frozenForest", new MapGenerator("groundZero", 1)){{ //TODO implement frozenForest = new Zone("frozenForest", new MapGenerator("frozenForest")){{ //TODO implement
alwaysUnlocked = true;
deployCost = ItemStack.with(Items.copper, 300); deployCost = ItemStack.with(Items.copper, 300);
startingItems = ItemStack.with(Items.copper, 200); startingItems = ItemStack.with(Items.copper, 200);
conditionWave = 15; conditionWave = 15;
@@ -112,10 +112,10 @@ public class BlockRenderer{
Draw.flush(); Draw.flush();
shadows.begin(); shadows.begin();
Core.graphics.clear(Color.CLEAR); Core.graphics.clear(Color.CLEAR);
Draw.color(shadowColor);
floor.beginDraw(); floor.beginDraw();
floor.drawLayer(CacheLayer.walls); floor.drawLayer(CacheLayer.walls);
floor.endDraw(); floor.endDraw();
drawBlocks(Layer.shadow); drawBlocks(Layer.shadow);
EntityDraw.drawWith(playerGroup, player -> !player.isDead(), Unit::draw); EntityDraw.drawWith(playerGroup, player -> !player.isDead(), Unit::draw);
@@ -164,11 +164,12 @@ public class BlockRenderer{
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){ if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){
if(!expanded){ if(!expanded){
addRequest(tile, Layer.shadow);
addRequest(tile, Layer.block); addRequest(tile, Layer.block);
} }
if(block.expanded || !expanded){ if(block.expanded || !expanded){
addRequest(tile, Layer.shadow);
if(block.layer != null && block.isLayer(tile)){ if(block.layer != null && block.isLayer(tile)){
addRequest(tile, block.layer); addRequest(tile, block.layer);
} }
@@ -205,7 +206,9 @@ public class BlockRenderer{
Block block = req.tile.block(); Block block = req.tile.block();
if(req.layer == Layer.shadow){ if(req.layer == Layer.shadow){
Draw.color(0f, 0f, 0f, 0.45f);
block.drawShadow(req.tile); block.drawShadow(req.tile);
Draw.color();
}else if(req.layer == Layer.block){ }else if(req.layer == Layer.block){
block.draw(req.tile); block.draw(req.tile);
if(block.synthetic() && req.tile.getTeam() != players[0].getTeam()){ if(block.synthetic() && req.tile.getTeam() != players[0].getTeam()){
@@ -43,6 +43,7 @@ public class Save16 extends SaveFileVersion{
state.wave = wave; state.wave = wave;
state.wavetime = wavetime; state.wavetime = wavetime;
state.stats = Serialization.readStats(stream); state.stats = Serialization.readStats(stream);
world.spawner.read(stream);
content.setTemporaryMapper(readContentHeader(stream)); content.setTemporaryMapper(readContentHeader(stream));
@@ -66,6 +67,7 @@ public class Save16 extends SaveFileVersion{
stream.writeFloat(state.wavetime); //wave countdown stream.writeFloat(state.wavetime); //wave countdown
Serialization.writeStats(stream, state.stats); Serialization.writeStats(stream, state.stats);
world.spawner.write(stream);
writeContentHeader(stream); writeContentHeader(stream);
@@ -83,11 +83,11 @@ public class MapGenerator extends Generator{
} }
} }
if(enemySpawns != -1){
if(enemySpawns > enemies.size){ if(enemySpawns > enemies.size){
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number."); throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
} }
if(enemySpawns != -1){
enemies.shuffle(); enemies.shuffle();
for(int i = 0; i < enemySpawns; i++){ for(int i = 0; i < enemySpawns; i++){
Point2 point = enemies.get(i); Point2 point = enemies.get(i);
@@ -22,6 +22,7 @@ public class Zone extends UnlockableContent{
public Supplier<Rules> rules = Rules::new; public Supplier<Rules> rules = Rules::new;
public boolean alwaysUnlocked; public boolean alwaysUnlocked;
public int conditionWave = Integer.MAX_VALUE; public int conditionWave = Integer.MAX_VALUE;
public int launchPeriod = 10;
public Zone(String name, Generator generator){ public Zone(String name, Generator generator){
this.name = name; this.name = name;
@@ -52,9 +52,8 @@ public class TechTreeDialog extends FloatingDialog{
recipes.sort(Structs.comparing(r -> r.buildCost)); recipes.sort(Structs.comparing(r -> r.buildCost));
if(recipes.size > 0){ if(recipes.size > 0){
Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.blocks().select(Block::isVisible).size * 100)); Log.info("Missing recipe tree items! ");
Log.info("Missing items: "); recipes.forEach(r -> Log.info("> {0}", r));
recipes.forEach(r -> Log.info(" {0}", r));
} }
} }
@@ -16,9 +16,11 @@ import io.anuke.arc.scene.ui.TextButton;
import io.anuke.arc.scene.ui.layout.Stack; import io.anuke.arc.scene.ui.layout.Stack;
import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.scene.ui.layout.Unit; import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.scene.utils.Elements;
import io.anuke.arc.util.Align; import io.anuke.arc.util.Align;
import io.anuke.arc.util.Scaling; import io.anuke.arc.util.Scaling;
import io.anuke.arc.util.Time; import io.anuke.arc.util.Time;
import io.anuke.arc.util.Tmp;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.EventType.StateChangeEvent; import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
@@ -196,8 +198,40 @@ public class HudFragment extends Fragment{
.update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f)))); .update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f))));
}); });
parent.fill(t -> t.top().right().addRowImageTextButton("$launch", "icon-arrow-up", 8*3, Call::launchZone) parent.fill(t -> {
.size(94f, 70f).visible(() -> world.isZone() && world.getZone().metCondition() && !Net.client())); t.top().right();
TextButton button = Elements.newButton("$launch", Call::launchZone);
button.getStyle().disabledFontColor = Color.WHITE;
button.visible(() ->
world.isZone() &&
world.getZone().metCondition() &&
!Net.client() &&
state.wave % world.getZone().launchPeriod == 0);
button.update(() -> {
if(world.getZone() == null){
button.setText("");
return;
}
button.setText(Core.bundle.get(state.enemies() > 0 ? "launch.unable" : "launch") + "\n" +
Core.bundle.format("launch.next", state.wave + world.getZone().launchPeriod));
button.getLabel().setColor(Tmp.c1.set(Color.WHITE).lerp(state.enemies() > 0 ? Color.WHITE : Palette.accent,
Mathf.absin(Time.time(), 7f, 1f)));
});
button.setDisabled(() -> state.enemies() > 0);
button.getLabelCell().left().get().setAlignment(Align.left, Align.left);
t.add(button).size(350f, 80f);
//.addRowImageTextButton("$launch", "icon-arrow-up", 8*3, Call::launchZone)
//.size(94f, 70f).visible(() -> world.isZone() && world.getZone().metCondition() && !Net.client());
});
//'saving' indicator //'saving' indicator
parent.fill(t -> { parent.fill(t -> {
@@ -6,15 +6,19 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
public class TreeBlock extends Block{ public class TreeBlock extends Block{
static final float shadowOffset = 5f;
public TreeBlock(String name){ public TreeBlock(String name){
super(name); super(name);
solid = true; solid = true;
layer = Layer.power; layer = Layer.power;
expanded = true;
} }
@Override @Override
public void draw(Tile tile){} public void drawShadow(Tile tile){
Draw.rect(region, tile.drawx() - shadowOffset, tile.drawy() - shadowOffset);
}
@Override @Override
public void drawLayer(Tile tile){ public void drawLayer(Tile tile){
@@ -25,10 +25,8 @@ import io.anuke.mindustry.world.meta.BlockFlag;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class CoreBlock extends LaunchPad{ public class CoreBlock extends StorageBlock{
protected TextureRegion topRegion; protected TextureRegion topRegion;
protected int launchThreshold;
protected int launchChunkSize;
public CoreBlock(String name){ public CoreBlock(String name){
super(name); super(name);
@@ -148,16 +146,6 @@ public class CoreBlock extends LaunchPad{
public void update(Tile tile){ public void update(Tile tile){
CoreEntity entity = tile.entity(); CoreEntity entity = tile.entity();
for(Item item : Vars.content.items()){
if(entity.items.get(item) >= launchThreshold + launchChunkSize && entity.timer.get(timerLaunch, launchTime)){
//TODO play animation of some sort
Effects.effect(Fx.dooropenlarge, tile);
//items sent are split evenly across every player in the game
data.addItem(item, launchChunkSize / Math.max(playerGroup.size(), 1));
entity.items.remove(item, launchChunkSize);
}
}
if(entity.currentUnit != null){ if(entity.currentUnit != null){
if(!entity.currentUnit.isDead()){ if(!entity.currentUnit.isDead()){
entity.currentUnit = null; entity.currentUnit = null;