Better launch / Better spawns / Tweaks
BIN
core/assets-raw/sprites/blocks/environment/ice-snow.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 108 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 93 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 99 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 94 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 241 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -247,8 +247,10 @@ locked = Locked
|
||||
complete = [LIGHT_GRAY]Complete:
|
||||
resume = Resume Zone:\n[LIGHT_GRAY]{0}
|
||||
bestwave = [LIGHT_GRAY]Best: {0}
|
||||
launch = Launch
|
||||
launch = < LAUNCH >
|
||||
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.
|
||||
|
||||
connectfail = [crimson]Failed to connect to server:\n\n[accent]{0}
|
||||
|
BIN
core/assets/maps/frozenForest.mmap
Normal file
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.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.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
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.Squad;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
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.*;
|
||||
|
||||
@ -16,11 +27,31 @@ public class WaveSpawner{
|
||||
private Array<SpawnGroup> groups;
|
||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||
private IntArray loadedSpawns = new IntArray();
|
||||
|
||||
public WaveSpawner(){
|
||||
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(){
|
||||
|
||||
for(SpawnGroup group : groups){
|
||||
@ -51,15 +82,23 @@ public class WaveSpawner{
|
||||
Squad squad = new Squad();
|
||||
spawnX = spawn.x * tilesize;
|
||||
spawnY = spawn.y * tilesize;
|
||||
spread = tilesize;
|
||||
spread = tilesize*3;
|
||||
|
||||
for(int i = 0; i < spawned; i++){
|
||||
Tmp.v1.rnd(spread);
|
||||
|
||||
BaseUnit unit = group.createUnit(waveTeam);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
|
||||
|
||||
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,17 +112,39 @@ public class WaveSpawner{
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
if(world.tile(x, y).block() == Blocks.spawn){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
addSpawns(x, y);
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
|
||||
flySpawns.add(fspawn);
|
||||
//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();
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
|
||||
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{
|
||||
|
@ -33,7 +33,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
//environment
|
||||
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
|
||||
siliconSmelter, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
|
||||
@ -223,6 +223,9 @@ public class Blocks implements ContentList{
|
||||
variants = 0;
|
||||
}};
|
||||
|
||||
whiteTree = new TreeBlock("white-tree-dead"){{
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region crafting
|
||||
|
||||
@ -860,9 +863,6 @@ public class Blocks implements ContentList{
|
||||
|
||||
health = 1100;
|
||||
itemCapacity = 1000;
|
||||
launchThreshold = 500;
|
||||
launchTime = 60f * 10;
|
||||
launchChunkSize = 100;
|
||||
}};
|
||||
|
||||
vault = new Vault("vault"){{
|
||||
|
@ -10,6 +10,7 @@ import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
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.graphics.Palette;
|
||||
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,
|
||||
shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium,
|
||||
shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot,
|
||||
launchFull;
|
||||
launchFull, unitSpawn, spawnShockwave;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
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 -> {
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
@ -78,10 +93,10 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawn = new Effect(23, e -> {
|
||||
spawn = new Effect(30, e -> {
|
||||
Lines.stroke(2f * e.fout());
|
||||
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();
|
||||
});
|
||||
|
||||
@ -545,6 +560,13 @@ public class Fx implements ContentList{
|
||||
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 -> {
|
||||
e.scaled(7, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
|
@ -59,8 +59,6 @@ public class Zones implements ContentList{
|
||||
}};
|
||||
|
||||
craters = new Zone("craters", new MapGenerator("craters", 1){{ distortion = 0; }}){{
|
||||
alwaysUnlocked = true;
|
||||
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
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);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
|
@ -112,10 +112,10 @@ public class BlockRenderer{
|
||||
Draw.flush();
|
||||
shadows.begin();
|
||||
Core.graphics.clear(Color.CLEAR);
|
||||
Draw.color(shadowColor);
|
||||
floor.beginDraw();
|
||||
floor.drawLayer(CacheLayer.walls);
|
||||
floor.endDraw();
|
||||
|
||||
drawBlocks(Layer.shadow);
|
||||
|
||||
EntityDraw.drawWith(playerGroup, player -> !player.isDead(), Unit::draw);
|
||||
@ -164,11 +164,12 @@ public class BlockRenderer{
|
||||
|
||||
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){
|
||||
if(!expanded){
|
||||
addRequest(tile, Layer.shadow);
|
||||
addRequest(tile, Layer.block);
|
||||
}
|
||||
|
||||
if(block.expanded || !expanded){
|
||||
addRequest(tile, Layer.shadow);
|
||||
|
||||
if(block.layer != null && block.isLayer(tile)){
|
||||
addRequest(tile, block.layer);
|
||||
}
|
||||
@ -205,7 +206,9 @@ public class BlockRenderer{
|
||||
Block block = req.tile.block();
|
||||
|
||||
if(req.layer == Layer.shadow){
|
||||
Draw.color(0f, 0f, 0f, 0.45f);
|
||||
block.drawShadow(req.tile);
|
||||
Draw.color();
|
||||
}else if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
if(block.synthetic() && req.tile.getTeam() != players[0].getTeam()){
|
||||
|
@ -43,6 +43,7 @@ public class Save16 extends SaveFileVersion{
|
||||
state.wave = wave;
|
||||
state.wavetime = wavetime;
|
||||
state.stats = Serialization.readStats(stream);
|
||||
world.spawner.read(stream);
|
||||
|
||||
content.setTemporaryMapper(readContentHeader(stream));
|
||||
|
||||
@ -66,6 +67,7 @@ public class Save16 extends SaveFileVersion{
|
||||
stream.writeFloat(state.wavetime); //wave countdown
|
||||
|
||||
Serialization.writeStats(stream, state.stats);
|
||||
world.spawner.write(stream);
|
||||
|
||||
writeContentHeader(stream);
|
||||
|
||||
|
@ -83,11 +83,11 @@ public class MapGenerator extends Generator{
|
||||
}
|
||||
}
|
||||
|
||||
if(enemySpawns > enemies.size){
|
||||
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
|
||||
}
|
||||
|
||||
if(enemySpawns != -1){
|
||||
if(enemySpawns > enemies.size){
|
||||
throw new IllegalArgumentException("Enemy spawn pool greater than map spawn number.");
|
||||
}
|
||||
|
||||
enemies.shuffle();
|
||||
for(int i = 0; i < enemySpawns; i++){
|
||||
Point2 point = enemies.get(i);
|
||||
|
@ -22,6 +22,7 @@ public class Zone extends UnlockableContent{
|
||||
public Supplier<Rules> rules = Rules::new;
|
||||
public boolean alwaysUnlocked;
|
||||
public int conditionWave = Integer.MAX_VALUE;
|
||||
public int launchPeriod = 10;
|
||||
|
||||
public Zone(String name, Generator generator){
|
||||
this.name = name;
|
||||
|
@ -52,9 +52,8 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
recipes.sort(Structs.comparing(r -> r.buildCost));
|
||||
|
||||
if(recipes.size > 0){
|
||||
Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.blocks().select(Block::isVisible).size * 100));
|
||||
Log.info("Missing items: ");
|
||||
recipes.forEach(r -> Log.info(" {0}", r));
|
||||
Log.info("Missing recipe tree items! ");
|
||||
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.Table;
|
||||
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.Scaling;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
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))));
|
||||
});
|
||||
|
||||
parent.fill(t -> t.top().right().addRowImageTextButton("$launch", "icon-arrow-up", 8*3, Call::launchZone)
|
||||
.size(94f, 70f).visible(() -> world.isZone() && world.getZone().metCondition() && !Net.client()));
|
||||
parent.fill(t -> {
|
||||
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
|
||||
parent.fill(t -> {
|
||||
|
@ -6,15 +6,19 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public class TreeBlock extends Block{
|
||||
static final float shadowOffset = 5f;
|
||||
|
||||
public TreeBlock(String name){
|
||||
super(name);
|
||||
solid = true;
|
||||
layer = Layer.power;
|
||||
expanded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){}
|
||||
public void drawShadow(Tile tile){
|
||||
Draw.rect(region, tile.drawx() - shadowOffset, tile.drawy() - shadowOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLayer(Tile tile){
|
||||
|
@ -25,10 +25,8 @@ import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class CoreBlock extends LaunchPad{
|
||||
public class CoreBlock extends StorageBlock{
|
||||
protected TextureRegion topRegion;
|
||||
protected int launchThreshold;
|
||||
protected int launchChunkSize;
|
||||
|
||||
public CoreBlock(String name){
|
||||
super(name);
|
||||
@ -148,16 +146,6 @@ public class CoreBlock extends LaunchPad{
|
||||
public void update(Tile tile){
|
||||
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.isDead()){
|
||||
entity.currentUnit = null;
|
||||
|