Sprite cleanup / Stats / More balancing / New events

This commit is contained in:
Anuken
2019-01-17 15:30:50 -05:00
parent ccc20a9716
commit c6af151bf3
89 changed files with 1144 additions and 1047 deletions

View File

@@ -725,8 +725,8 @@ public class Blocks implements ContentList{
core = new CoreBlock("core"){{
health = 1100;
itemCapacity = 2000;
launchThreshold = 1000;
itemCapacity = 1000;
launchThreshold = 500;
launchTime = 60f * 10;
launchChunkSize = 100;
}};
@@ -763,12 +763,12 @@ public class Blocks implements ContentList{
Items.pyratite, Bullets.standardIncendiary,
Items.silicon, Bullets.standardHoming
);
reload = 25f;
reload = 20f;
restitution = 0.03f;
range = 90f;
shootCone = 15f;
ammoUseEffect = Fx.shellEjectSmall;
health = 80;
health = 110;
inaccuracy = 2f;
rotatespeed = 10f;
}};

View File

@@ -51,8 +51,8 @@ public class Recipes implements ContentList{
new Recipe(effect, Blocks.shockMine, new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 25));
//TURRETS
new Recipe(turret, Blocks.duo, new ItemStack(Items.copper, 40)).setAlwaysUnlocked(true);
new Recipe(turret, Blocks.arc, new ItemStack(Items.copper, 50), new ItemStack(Items.lead, 40));
new Recipe(turret, Blocks.duo, new ItemStack(Items.copper, 60)).setAlwaysUnlocked(true);
new Recipe(turret, Blocks.arc, new ItemStack(Items.copper, 70), new ItemStack(Items.lead, 60));
new Recipe(turret, Blocks.hail, new ItemStack(Items.copper, 60), new ItemStack(Items.graphite, 35));
new Recipe(turret, Blocks.lancer, new ItemStack(Items.copper, 50), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 90));
new Recipe(turret, Blocks.wave, new ItemStack(Items.titanium, 70), new ItemStack(Items.lead, 150));

View File

@@ -27,14 +27,9 @@ public class Zones implements ContentList{
unitScaling = 2;
}},
new SpawnGroup(UnitTypes.dagger){{
begin = 5;
unitScaling = 2;
}},
new SpawnGroup(UnitTypes.dagger){{
begin = 10;
unitScaling = 1;
unitScaling = 2;
}},
new SpawnGroup(UnitTypes.dagger){{
@@ -50,6 +45,11 @@ public class Zones implements ContentList{
new SpawnGroup(UnitTypes.dagger){{
begin = 25;
unitScaling = 1;
}},
new SpawnGroup(UnitTypes.dagger){{
begin = 30;
unitScaling = 1;
}}
);
}};

View File

@@ -116,15 +116,16 @@ public class Control implements ApplicationListener{
//todo high scores for custom maps, as well as other statistics
Events.on(GameOverEvent.class, event -> {
state.stats.wavesLasted = state.wave;
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
//the restart dialog can show info for any number of scenarios
Call.onGameOver(event.winner);
if(state.rules.zone != -1){
//remove zone save on game over
if(saves.getZoneSlot() != null){
saves.getZoneSlot().delete();
}
}
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
//the restart dialog can show info for any number of scenarios
Call.onGameOver(event.winner);
});
//autohost for pvp sectors
@@ -141,6 +142,28 @@ public class Control implements ApplicationListener{
});
Events.on(UnlockEvent.class, e -> ui.hudfrag.showUnlock(e.content));
Events.on(BlockBuildEndEvent.class, e -> {
if(e.team == players[0].getTeam()){
if(e.breaking){
state.stats.buildingsDeconstructed++;
}else{
state.stats.buildingsBuilt ++;
}
}
});
Events.on(BlockDestroyEvent.class, e -> {
if(e.tile.getTeam() == players[0].getTeam()){
state.stats.buildingsDestroyed ++;
}
});
Events.on(UnitDestroyEvent.class, e -> {
if(e.unit.getTeam() != players[0].getTeam()){
state.stats.enemyUnitsDestroyed ++;
}
});
}
public void addPlayer(int index){

View File

@@ -3,6 +3,7 @@ package io.anuke.mindustry.core;
import io.anuke.arc.Events;
import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.Stats;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.net.Net;
@@ -18,6 +19,8 @@ public class GameState{
public boolean gameOver = false;
/**The current game rules.*/
public Rules rules = new Rules();
/**Statistics for this save/game. Displayed after game over.*/
public Stats stats = new Stats();
/**Team data. Gets reset every new game.*/
public Teams teams = new Teams();
/**Number of enemies in the game; only used clientside in servers.*/

View File

@@ -10,11 +10,8 @@ import io.anuke.arc.entities.EntityQuery;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Tile;
@@ -68,6 +65,7 @@ public class Logic implements ApplicationListener{
state.gameOver = false;
state.teams = new Teams();
state.rules = new Rules();
state.stats = new Stats();
Time.clear();
Entities.clear();

View File

@@ -47,7 +47,7 @@ public class UI implements ApplicationListener{
public LoadingFragment loadfrag;
public AboutDialog about;
public RestartDialog restart;
public GameOverDialog restart;
public CustomGameDialog levels;
public MapsDialog maps;
public LoadDialog load;
@@ -158,7 +158,7 @@ public class UI implements ApplicationListener{
editor = new MapEditorDialog();
controls = new ControlsDialog();
restart = new RestartDialog();
restart = new GameOverDialog();
join = new JoinDialog();
discord = new DiscordDialog();
load = new LoadDialog();

View File

@@ -26,6 +26,7 @@ import io.anuke.mindustry.maps.MapTileData;
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
import io.anuke.mindustry.maps.Maps;
import io.anuke.mindustry.maps.generators.Generator;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Zone;
import io.anuke.mindustry.world.Block;
@@ -195,7 +196,11 @@ public class World implements ApplicationListener{
}
public boolean isZone(){
return state.rules.zone != -1;
return getZone() != null;
}
public Zone getZone(){
return content.getByID(ContentType.zone, state.rules.zone);
}
public void playZone(Zone zone){

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.entities;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.ObjectSet;
import io.anuke.arc.entities.Effects;
@@ -16,6 +17,7 @@ import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.EventType.BlockDestroyEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.world.Block;
@@ -244,6 +246,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
dead = true;
Block block = tile.block();
Events.fire(new BlockDestroyEvent(tile));
block.onDestroyed(tile);
world.removeBlock(tile);
block.afterDestroyed(tile, this);

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.entities;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.entities.Effects;
import io.anuke.arc.entities.impl.DestructibleEntity;
import io.anuke.arc.entities.trait.DamageTrait;
@@ -17,6 +18,7 @@ import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.EventType.UnitDestroyEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams.TeamData;
import io.anuke.mindustry.net.Interpolator;
@@ -121,6 +123,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
inventory.clear();
drownTime = 0f;
status.clear();
Events.fire(new UnitDestroyEvent(this));
}
@Override

View File

@@ -31,12 +31,16 @@ public class ScorchDecal extends Decal{
@Override
public void drawDecal(){
for(int i = 0; i < 5; i++){
TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches - 1)];
float rotation = Mathf.randomSeed(id + i, 0, 360);
float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20) / 10f;
Draw.rect(region, x + Angles.trnsx(rotation, space), y + Angles.trnsy(rotation, space) + region.getHeight()/2f, region.getWidth()/2f, 0, rotation - 90);
Draw.rect(region,
x + Angles.trnsx(rotation, space),
y + Angles.trnsy(rotation, space) + region.getHeight()/2f*Draw.scl,
region.getWidth() * Draw.scl,
region.getHeight() * Draw.scl,
region.getWidth()/2f*Draw.scl, 0, rotation - 90);
}
}
}

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.game;
import io.anuke.arc.Events.Event;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.world.Tile;
@@ -81,6 +82,18 @@ public class EventType{
}
}
public static class BlockBuildEndEvent implements Event{
public final Tile tile;
public final Team team;
public final boolean breaking;
public BlockBuildEndEvent(Tile tile, Team team, boolean breaking){
this.tile = tile;
this.team = team;
this.breaking = breaking;
}
}
/**Called when a player or drone begins building something.
* This does not necessarily happen when a new BuildBlock is created.*/
public static class BuildSelectEvent implements Event{
@@ -97,6 +110,22 @@ public class EventType{
}
}
public static class BlockDestroyEvent implements Event{
public final Tile tile;
public BlockDestroyEvent(Tile tile){
this.tile = tile;
}
}
public static class UnitDestroyEvent implements Event{
public final Unit unit;
public UnitDestroyEvent(Unit unit){
this.unit = unit;
}
}
public static class ResizeEvent implements Event{
}

View File

@@ -28,6 +28,7 @@ public class GlobalData{
public void addItem(Item item, int amount){
modified = true;
items.getAndIncrement(item, 0, amount);
state.stats.itemsDelivered.getAndIncrement(item, 0, amount);
}
public boolean hasItems(ItemStack[] stacks){

View File

@@ -0,0 +1,23 @@
package io.anuke.mindustry.game;
import io.anuke.annotations.Annotations.Serialize;
import io.anuke.arc.collection.ObjectIntMap;
import io.anuke.mindustry.type.Item;
@Serialize
public class Stats{
/**Items delivered to global resoure counter. Zones only.*/
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
/**Enemy (red team) units destroyed.*/
public int enemyUnitsDestroyed;
/**Total waves lasted.*/
public int wavesLasted;
/**Total (ms) time lasted in this save/zone.*/
public long timeLasted;
/**Friendly buildings fully built.*/
public int buildingsBuilt;
/**Friendly buildings fully deconstructed.*/
public int buildingsDeconstructed;
/**Friendly buildings destroyed.*/
public int buildingsDestroyed;
}

View File

@@ -38,10 +38,6 @@ public class Palette{
stoneGray = Color.valueOf("8f8f8f"),
portalLight = Color.valueOf("9054ea"),
portal = Color.valueOf("6344d7"),
portalDark = Color.valueOf("3f3dac"),
heal = Color.valueOf("98ffa9"),
bar = Color.SLATE,
accent = Color.valueOf("ffd37f"),

View File

@@ -80,11 +80,19 @@ public class DesktopInput extends InputHandler{
int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX());
if(i + recipe.result.size > result.getLength() && recipe.result.rotate){
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.remove : Palette.placeRotate);
Draw.rect(Core.atlas.find("place-arrow"), x * tilesize + recipe.result.offset(),
y * tilesize + recipe.result.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getHeight() * Draw.scl,
x * tilesize + recipe.result.offset()/2f, 0f, result.rotation * 90 - 90);
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.removeBack : Palette.accentBack);
Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + recipe.result.offset(),
y * tilesize + recipe.result.offset() - 1,
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.remove : Palette.accent);
Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + recipe.result.offset(),
y * tilesize + recipe.result.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
}
drawPlace(x, y, recipe.result, result.rotation);
@@ -114,12 +122,19 @@ public class DesktopInput extends InputHandler{
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}else if(isPlacing()){
if(recipe.result.rotate){
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.remove : Palette.placeRotate);
Draw.rect(Core.atlas.find("place-arrow"), cursorX * tilesize + recipe.result.offset(),
cursorY * tilesize + recipe.result.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl,
cursorX * tilesize + recipe.result.offset()/2f, 0, rotation * 90 - 90);
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.removeBack : Palette.accentBack);
Draw.rect(Core.atlas.find("place-arrow"),
cursorX * tilesize + recipe.result.offset(),
cursorY * tilesize + recipe.result.offset() - 1,
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.remove : Palette.accent);
Draw.rect(Core.atlas.find("place-arrow"),
cursorX * tilesize + recipe.result.offset(),
cursorY * tilesize + recipe.result.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
}
drawPlace(cursorX, cursorY, recipe.result, rotation);
recipe.result.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, recipe.result, rotation));

View File

@@ -42,11 +42,11 @@ public class Save16 extends SaveFileVersion{
state.wave = wave;
state.wavetime = wavetime;
state.stats = Serialization.readStats(stream);
content.setTemporaryMapper(readContentHeader(stream));
readEntities(stream);
readMap(stream);
}
@@ -65,6 +65,8 @@ public class Save16 extends SaveFileVersion{
stream.writeInt(state.wave); //wave
stream.writeFloat(state.wavetime); //wave countdown
Serialization.writeStats(stream, state.stats);
writeContentHeader(stream);
//--ENTITIES--

View File

@@ -8,6 +8,8 @@ import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.maps.generators.Generator;
import static io.anuke.mindustry.Vars.state;
public class Zone extends UnlockableContent{
public final String name;
public final Generator generator;
@@ -15,12 +17,18 @@ public class Zone extends UnlockableContent{
public ItemStack[] startingItems = {};
public Supplier<Rules> rules = Rules::new;
public boolean alwaysUnlocked;
public int conditionWave = Integer.MAX_VALUE;
public Zone(String name, Generator generator){
this.name = name;
this.generator = generator;
}
/**Whether this zone has met its condition; if true, the player can leave.*/
public boolean metCondition(){
return state.wave > conditionWave;
}
@Override
public void init(){
generator.init();

View File

@@ -0,0 +1,86 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Item;
import static io.anuke.mindustry.Vars.*;
public class GameOverDialog extends FloatingDialog{
private Team winner;
public GameOverDialog(){
super("$gameover");
setFillParent(false);
shown(this::rebuild);
}
public void show(Team winner){
this.winner = winner;
show();
}
void rebuild(){
buttons.clear();
cont.clear();
buttons.margin(10);
if(state.rules.pvp){
cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6);
buttons.addButton("$menu", () -> {
hide();
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}else{
if(control.isHighScore()){
cont.add("$highscore").pad(6);
cont.row();
}
cont.table(t -> {
cont.left().defaults().left();
cont.add(Core.bundle.format("stat.wave", state.stats.wavesLasted));
cont.row();
cont.add(Core.bundle.format("stat.enemiesDestroyed", state.stats.enemyUnitsDestroyed));
cont.row();
cont.add(Core.bundle.format("stat.built", state.stats.buildingsBuilt));
cont.row();
cont.add(Core.bundle.format("stat.destroyed", state.stats.buildingsDestroyed));
cont.row();
cont.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed));
cont.row();
if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){
cont.add("$stat.delivered");
cont.row();
for(Item item : content.items()){
if(state.stats.itemsDelivered.containsKey(item)){
cont.table(items -> {
items.add(" [LIGHT_GRAY]" + state.stats.itemsDelivered.get(item, 0));
items.addImage(item.region).size(8 *3).pad(4);
}).left();
cont.row();
}
}
}
}).pad(12);
if(world.isZone()){
buttons.addButton("$continue", () -> {
hide();
state.set(State.menu);
logic.reset();
ui.deploy.show();
}).size(130f, 60f);
}else{
buttons.addButton("$menu", () -> {
hide();
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}
}
}
}

View File

@@ -1,50 +0,0 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Team;
import static io.anuke.mindustry.Vars.*;
public class RestartDialog extends FloatingDialog{
private Team winner;
public RestartDialog(){
super("$gameover");
setFillParent(false);
shown(this::rebuild);
}
public void show(Team winner){
this.winner = winner;
show();
}
void rebuild(){
buttons.clear();
cont.clear();
buttons.margin(10);
if(state.rules.pvp){
cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6);
buttons.addButton("$menu", () -> {
hide();
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}else{
if(control.isHighScore()){
cont.add("$highscore").pad(6);
cont.row();
}
cont.add(Core.bundle.format("wave.lasted", state.wave)).pad(12);
buttons.addButton("$menu", () -> {
hide();
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}
}
}

View File

@@ -126,7 +126,7 @@ public class SettingsMenuDialog extends SettingsDialog{
if(mobile){
game.checkPref("autotarget", true);
}
game.sliderPref("saveinterval", 120, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
if(!mobile){
game.checkPref("crashreport", true);

View File

@@ -3,6 +3,7 @@ package io.anuke.mindustry.world.blocks;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.Graphics.Cursor;
import io.anuke.arc.Graphics.Cursor.SystemCursor;
import io.anuke.arc.entities.Effects;
@@ -15,6 +16,7 @@ import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.RubbleDecal;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.game.EventType.BlockBuildEndEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Layer;
@@ -46,8 +48,10 @@ public class BuildBlock extends Block{
@Remote(called = Loc.server)
public static void onDeconstructFinish(Tile tile, Block block){
Team team = tile.getTeam();
Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size);
world.removeBlock(tile);
Events.fire(new BlockBuildEndEvent(tile, team, true));
}
@Remote(called = Loc.server)
@@ -64,6 +68,7 @@ public class BuildBlock extends Block{
//event first before they can recieve the placed() event modification results
Core.app.post(() -> tile.block().playerPlaced(tile));
}
Core.app.post(() -> Events.fire(new BlockBuildEndEvent(tile, team, false)));
}
@Override