Gamemodes removed

This commit is contained in:
Anuken
2019-01-12 16:55:24 -05:00
parent 777bd60f88
commit 8aa1509f47
49 changed files with 741 additions and 678 deletions

View File

@@ -12,6 +12,7 @@ import javax.lang.model.util.ElementFilter;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -60,14 +61,12 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
.returns(void.class) .returns(void.class)
.addParameter(DataOutput.class, "stream") .addParameter(DataOutput.class, "stream")
.addParameter(type, "object") .addParameter(type, "object")
.addAnnotation(Override.class)
.addException(IOException.class) .addException(IOException.class)
.addModifiers(Modifier.PUBLIC); .addModifiers(Modifier.PUBLIC);
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("read") MethodSpec.Builder readMethod = MethodSpec.methodBuilder("read")
.returns(type) .returns(type)
.addParameter(DataInput.class, "stream") .addParameter(DataInput.class, "stream")
.addAnnotation(Override.class)
.addException(IOException.class) .addException(IOException.class)
.addModifiers(Modifier.PUBLIC); .addModifiers(Modifier.PUBLIC);
@@ -96,6 +95,17 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
serializer.addMethod(readMethod.build()); serializer.addMethod(readMethod.build());
method.addStatement("io.anuke.arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); method.addStatement("io.anuke.arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build());
String sname = type.toString().substring(type.toString().lastIndexOf('.') + 1);
name(writeMethod, "write" + sname);
name(readMethod, "read" + sname);
writeMethod.addModifiers(Modifier.STATIC);
readMethod.addModifiers(Modifier.STATIC);
classBuilder.addMethod(writeMethod.build());
classBuilder.addMethod(readMethod.build());
} }
classBuilder.addMethod(method.build()); classBuilder.addMethod(method.build());
@@ -109,4 +119,14 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
static void name(MethodSpec.Builder builder, String name){
try{
Field field = builder.getClass().getDeclaredField("name");
field.setAccessible(true);
field.set(builder, name);
}catch(Exception e){
throw new RuntimeException(e);
}
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 338 KiB

View File

@@ -39,12 +39,8 @@ public class Vars{
public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors"; public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors";
/**URL for sending crash reports to*/ /**URL for sending crash reports to*/
public static final String crashReportURL = "http://mindustry.us.to/report"; public static final String crashReportURL = "http://mindustry.us.to/report";
/**time between waves in ticks (on normal mode)*/
public static final float wavespace = 60 * 60 * 1.5f;
/**maximum distance between mine and core that supports automatic transferring*/ /**maximum distance between mine and core that supports automatic transferring*/
public static final float mineTransferRange = 220f; public static final float mineTransferRange = 220f;
/**maximum distance from core that the player can be before it is no longer used for building*/
public static final float coreBuildRange = 999999f;
/**team of the player by default*/ /**team of the player by default*/
public static final Team defaultTeam = Team.blue; public static final Team defaultTeam = Team.blue;
/**team of the enemy in waves/sectors*/ /**team of the enemy in waves/sectors*/

View File

@@ -82,7 +82,7 @@ public class Pathfinder{
} }
public float getValueforTeam(Team team, int x, int y){ public float getValueforTeam(Team team, int x, int y){
return paths == null || team.ordinal() >= paths.length ? 0 : Structs.inBounds(x, y, paths[team.ordinal()].weights) ? paths[team.ordinal()].weights[x][y] : 0; return paths == null || paths[team.ordinal()].weights == null || team.ordinal() >= paths.length ? 0 : Structs.inBounds(x, y, paths[team.ordinal()].weights) ? paths[team.ordinal()].weights[x][y] : 0;
} }
private boolean passable(Tile tile, Team team){ private boolean passable(Tile tile, Team team){

View File

@@ -31,7 +31,7 @@ public class Blocks implements ContentList{
//environment //environment
air, blockpart, spawn, space, metalfloor, deepwater, water, tar, stone, blackstone, dirt, sand, ice, snow, air, blockpart, spawn, space, metalfloor, deepwater, water, tar, stone, blackstone, dirt, sand, ice, snow,
grass, shrub, rock, icerock, blackrock, grass, shrub, rock, icerock, blackrock, rocksSmall, rocksMedium,
//crafting //crafting
siliconSmelter, plastaniumCompressor, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer, siliconSmelter, plastaniumCompressor, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
@@ -210,6 +210,18 @@ public class Blocks implements ContentList{
variants = 1; variants = 1;
}}; }};
rocksSmall = new Rock("rocks-small"){{
variants = 2;
breakable = alwaysReplace = false;
solid = true;
}};
rocksMedium = new Rock("rocks-medium"){{
variants = 2;
breakable = alwaysReplace = false;
solid = true;
}};
//endregion //endregion
//region crafting //region crafting

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.content; package io.anuke.mindustry.content;
import io.anuke.mindustry.game.ContentList; import io.anuke.mindustry.game.ContentList;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Recipe.RecipeVisibility; import io.anuke.mindustry.type.Recipe.RecipeVisibility;
@@ -13,11 +12,11 @@ public class Recipes implements ContentList{
@Override @Override
public void load(){ public void load(){
//DEBUG //DEBUG
new Recipe(distribution, Blocks.itemSource).setMode(GameMode.sandbox).setHidden(true).setAlwaysUnlocked(true); new Recipe(distribution, Blocks.itemSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
new Recipe(distribution, Blocks.itemVoid).setMode(GameMode.sandbox).setHidden(true).setAlwaysUnlocked(true); new Recipe(distribution, Blocks.itemVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
new Recipe(liquid, Blocks.liquidSource).setMode(GameMode.sandbox).setHidden(true).setAlwaysUnlocked(true); new Recipe(liquid, Blocks.liquidSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
new Recipe(power, Blocks.powerVoid).setMode(GameMode.sandbox).setHidden(true).setAlwaysUnlocked(true); new Recipe(power, Blocks.powerVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
new Recipe(power, Blocks.powerSource).setMode(GameMode.sandbox).setHidden(true).setAlwaysUnlocked(true); new Recipe(power, Blocks.powerSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
//DEFENSE //DEFENSE

View File

@@ -113,18 +113,7 @@ public class Control implements ApplicationListener{
saves.resetSave(); saves.resetSave();
}); });
Events.on(WaveEvent.class, event -> { //todo high scores for custom maps, as well as other statistics
int last = Core.settings.getInt("hiscore" + world.getMap().name, 0);
if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){
Core.settings.put("hiscore" + world.getMap().name, state.wave);
Core.settings.save();
hiscore = true;
}
Platform.instance.updateRPC();
});
Events.on(GameOverEvent.class, event -> { Events.on(GameOverEvent.class, event -> {
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y); Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
@@ -134,7 +123,7 @@ public class Control implements ApplicationListener{
//autohost for pvp sectors //autohost for pvp sectors
Events.on(WorldLoadEvent.class, event -> { Events.on(WorldLoadEvent.class, event -> {
if(state.mode.isPvp && !Net.active()){ if(state.rules.pvp && !Net.active()){
try{ try{
Net.host(port); Net.host(port);
players[0].isAdmin = true; players[0].isAdmin = true;

View File

@@ -1,11 +1,10 @@
package io.anuke.mindustry.core; package io.anuke.mindustry.core;
import io.anuke.mindustry.game.Difficulty; import io.anuke.arc.Events;
import io.anuke.mindustry.game.EventType.StateChangeEvent; import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.Teams; import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.arc.Events;
import static io.anuke.mindustry.Vars.unitGroups; import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.waveTeam; import static io.anuke.mindustry.Vars.waveTeam;
@@ -13,14 +12,12 @@ import static io.anuke.mindustry.Vars.waveTeam;
public class GameState{ public class GameState{
/**Current wave number, can be anything in non-wave modes.*/ /**Current wave number, can be anything in non-wave modes.*/
public int wave = 1; public int wave = 1;
/**Wave countdown in ticks.*/ /**Wave time in ticks.*/
public float wavetime; public float wavetime;
/**Whether the game is in game over state.*/ /**Whether the game is in game over state.*/
public boolean gameOver = false; public boolean gameOver = false;
/**The current game mode.*/ /**The current game rules.*/
public GameMode mode = GameMode.waves; public Rules rules = new Rules();
/**The current difficulty for wave modes.*/
public Difficulty difficulty = Difficulty.normal;
/**Team data. Gets reset every new game.*/ /**Team data. Gets reset every new game.*/
public Teams teams = new Teams(); public Teams teams = new Teams();
/**Number of enemies in the game; only used clientside in servers.*/ /**Number of enemies in the game; only used clientside in servers.*/

View File

@@ -11,6 +11,7 @@ import io.anuke.arc.util.Time;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams; import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.game.UnlockableContent;
@@ -56,16 +57,17 @@ public class Logic implements ApplicationListener{
public void play(){ public void play(){
state.set(State.playing); state.set(State.playing);
state.wavetime = wavespace * state.difficulty.timeScaling * 2; state.wavetime = 0;
Events.fire(new PlayEvent()); Events.fire(new PlayEvent());
} }
public void reset(){ public void reset(){
state.wave = 1; state.wave = 1;
state.wavetime = wavespace * state.difficulty.timeScaling; state.wavetime = 0;
state.gameOver = false; state.gameOver = false;
state.teams = new Teams(); state.teams = new Teams();
state.rules = new Rules();
Time.clear(); Time.clear();
Entities.clear(); Entities.clear();
@@ -77,16 +79,16 @@ public class Logic implements ApplicationListener{
public void runWave(){ public void runWave(){
world.spawner.spawnEnemies(); world.spawner.spawnEnemies();
state.wave++; state.wave++;
state.wavetime = wavespace * state.difficulty.timeScaling; state.wavetime = 0;
Events.fire(new WaveEvent()); Events.fire(new WaveEvent());
} }
private void checkGameOver(){ private void checkGameOver(){
if(!state.mode.isPvp && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){ if(!state.rules.pvp && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
state.gameOver = true; state.gameOver = true;
Events.fire(new GameOverEvent(waveTeam)); Events.fire(new GameOverEvent(waveTeam));
}else if(state.mode.isPvp){ }else if(state.rules.pvp){
Team alive = null; Team alive = null;
for(Team team : Team.all){ for(Team team : Team.all){
@@ -119,16 +121,17 @@ public class Logic implements ApplicationListener{
if(!state.isPaused()){ if(!state.isPaused()){
Time.update(); Time.update();
if(!state.mode.disableWaveTimer && !state.mode.disableWaves && !state.gameOver){ if(state.rules.waves && state.rules.waveTimer && !state.gameOver){
state.wavetime -= Time.delta(); state.wavetime += Time.delta();
} }
if(!Net.client() && state.wavetime <= 0 && !state.mode.disableWaves){ if(!Net.client() && state.wavetime >= state.rules.waveSpacing && state.rules.waves){
runWave(); runWave();
} }
if(!Entities.defaultGroup().isEmpty()) if(!Entities.defaultGroup().isEmpty()){
throw new RuntimeException("Do not add anything to the default group!"); throw new IllegalArgumentException("Do not add anything to the default group!");
}
if(!headless){ if(!headless){
Entities.update(effectGroup); Entities.update(effectGroup);

View File

@@ -193,7 +193,8 @@ public class NetServer implements ApplicationListener{
return; return;
} }
if(state.mode.isPvp){ //playing in pvp mode automatically assigns players to teams
if(state.rules.pvp){
//find team with minimum amount of players and auto-assign player to that. //find team with minimum amount of players and auto-assign player to that.
Team min = Structs.findMin(Team.all, team -> { Team min = Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team)){ if(state.teams.isActive(team)){
@@ -382,7 +383,7 @@ public class NetServer implements ApplicationListener{
} }
public boolean isWaitingForPlayers(){ public boolean isWaitingForPlayers(){
if(state.mode.isPvp){ if(state.rules.pvp){
int used = 0; int used = 0;
for(Team t : Team.all){ for(Team t : Team.all){
if(playerGroup.count(p -> p.getTeam() == t) > 0){ if(playerGroup.count(p -> p.getTeam() == t) > 0){

View File

@@ -235,7 +235,7 @@ public class World implements ApplicationListener{
if(state.teams.get(players[0].getTeam()).cores.size == 0){ if(state.teams.get(players[0].getTeam()).cores.size == 0){
ui.showError("$map.nospawn"); ui.showError("$map.nospawn");
invalidMap = true; invalidMap = true;
}else if(state.mode.isPvp){ }else if(state.rules.pvp){ //pvp maps need two cores to be valid
invalidMap = true; invalidMap = true;
for(Team team : Team.all){ for(Team team : Team.all){
if(state.teams.get(team).cores.size != 0 && team != players[0].getTeam()){ if(state.teams.get(team).cores.size != 0 && team != players[0].getTeam()){

View File

@@ -12,7 +12,7 @@ public class UnitDrops{
public static void dropItems(BaseUnit unit){ public static void dropItems(BaseUnit unit){
//items only dropped in waves for enemy team //items only dropped in waves for enemy team
if(unit.getTeam() != Vars.waveTeam || Vars.state.mode.disableWaves){ if(unit.getTeam() != Vars.waveTeam || !Vars.state.rules.unitDrops){
return; return;
} }

View File

@@ -2,23 +2,21 @@ package io.anuke.mindustry.game;
import io.anuke.arc.Core; import io.anuke.arc.Core;
/**Presets for time between waves.
* TODO specify correct time*/
public enum Difficulty{ public enum Difficulty{
training(3f, 3f), easy(1.4f),
easy(1.4f, 1.5f), normal(1f),
normal(1f, 1f), hard(0.5f),
hard(0.5f, 0.75f), insane(0.25f);
insane(0.25f, 0.5f);
/**Multiplier of the time between waves.*/ /**Multiplier of the time between waves.*/
public final float timeScaling; public final float waveTime;
/**Multiplier of spawner grace period.*/
public final float spawnerScaling;
private String value; private String value;
Difficulty(float timeScaling, float spawnerScaling){ Difficulty(float waveTime){
this.timeScaling = timeScaling; this.waveTime = waveTime;
this.spawnerScaling = spawnerScaling;
} }
@Override @Override

View File

@@ -1,44 +0,0 @@
package io.anuke.mindustry.game;
import io.anuke.arc.Core;
public enum GameMode{
waves,
sandbox{{
infiniteResources = true;
disableWaveTimer = true;
}},
freebuild{{
disableWaveTimer = true;
}},
attack{{
disableWaves = true;
enemyCheat = true;
}},
victory{{
disableWaves = true;
hidden = true;
enemyCheat = false;
showMission = false;
}},
pvp{{
disableWaves = true;
isPvp = true;
enemyCoreBuildRadius = 600f;
respawnTime = 60 * 10;
}};
public boolean infiniteResources, disableWaveTimer, disableWaves, showMission = true, hidden, enemyCheat, isPvp;
public float enemyCoreBuildRadius = 400f;
public float respawnTime = 60 * 4;
public String description(){
return Core.bundle.get("mode." + name() + ".description");
}
@Override
public String toString(){
return Core.bundle.get("mode." + name() + ".name");
}
}

View File

@@ -0,0 +1,46 @@
package io.anuke.mindustry.game;
import io.anuke.arc.Core;
import io.anuke.arc.function.Supplier;
/**Defines preset rule sets..*/
public enum RulePreset{
survival(() -> new Rules(){{
waveTimer = true;
waves = true;
unitDrops = true;
}}),
sandbox(() -> new Rules(){{
infiniteResources = true;
waves = true;
waveTimer = false;
}}),
attack(() -> new Rules(){{
enemyCheat = true;
unitDrops = true;
}}),
pvp(() -> new Rules(){{
pvp = true;
enemyCoreBuildRadius = 600f;
respawnTime = 60 * 10;
}});
private final Supplier<Rules> rules;
RulePreset(Supplier<Rules> rules){
this.rules = rules;
}
public Rules get(){
return rules.get();
}
public String description(){
return Core.bundle.get("mode." + name() + ".description");
}
@Override
public String toString(){
return Core.bundle.get("mode." + name() + ".name");
}
}

View File

@@ -0,0 +1,27 @@
package io.anuke.mindustry.game;
import io.anuke.annotations.Annotations.Serialize;
/**Defines current rules on how the game should function.
* Does not store game state, just configuration.*/
@Serialize
public class Rules{
/**Whether the player has infinite resources.*/
public boolean infiniteResources;
/**Whether the waves come automatically on a timer. If not, waves come when the play button is pressed.*/
public boolean waveTimer = true;
/**Whether waves are spawnable at all.*/
public boolean waves;
/**Whether the enemy AI has infinite resources in most of their buildings and turrets.*/
public boolean enemyCheat;
/**Whether the game objective is PvP. Note that this enables automatic hosting.*/
public boolean pvp;
/**Whether enemy units drop random items on death.*/
public boolean unitDrops;
/**No-build zone around enemy core radius.*/
public float enemyCoreBuildRadius = 400f;
/**Player respawn time in ticks.*/
public float respawnTime = 60 * 4;
/**Time between waves in ticks.*/
public float waveSpacing = 60 * 60;
}

View File

@@ -215,10 +215,6 @@ public class Saves{
return meta.difficulty; return meta.difficulty;
} }
public GameMode getMode(){
return meta.mode;
}
public boolean isAutosave(){ public boolean isAutosave(){
return Core.settings.getBool("save-" + index + "-autosave", true); return Core.settings.getBool("save-" + index + "-autosave", true);
} }

View File

@@ -35,7 +35,7 @@ public class Teams{
/**Returns whether a team is active, e.g. whether it has any cores remaining.*/ /**Returns whether a team is active, e.g. whether it has any cores remaining.*/
public boolean isActive(Team team){ public boolean isActive(Team team){
//the enemy wave team is always active //the enemy wave team is always active
return (!Vars.state.mode.disableWaves && team == Vars.waveTeam) || get(team).cores.size > 0; return (Vars.state.rules.waves && team == Vars.waveTeam) || get(team).cores.size > 0;
} }
/**Returns a set of all teams that are enemies of this team.*/ /**Returns a set of all teams that are enemies of this team.*/

View File

@@ -76,11 +76,11 @@ public class OverlayRenderer{
for(Team enemy : state.teams.enemiesOf(player.getTeam())){ for(Team enemy : state.teams.enemiesOf(player.getTeam())){
for(Tile core : state.teams.get(enemy).cores){ for(Tile core : state.teams.get(enemy).cores){
float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy()); float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy());
if(dst < state.mode.enemyCoreBuildRadius * 1.5f){ if(dst < state.rules.enemyCoreBuildRadius * 1.5f){
Draw.color(Color.DARK_GRAY); Draw.color(Color.DARK_GRAY);
Lines.poly(core.drawx(), core.drawy() - 2, 200, state.mode.enemyCoreBuildRadius); Lines.poly(core.drawx(), core.drawy() - 2, 200, state.rules.enemyCoreBuildRadius);
Draw.color(Palette.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); Draw.color(Palette.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f));
Lines.poly(core.drawx(), core.drawy(), 200, state.mode.enemyCoreBuildRadius); Lines.poly(core.drawx(), core.drawy(), 200, state.rules.enemyCoreBuildRadius);
} }
} }
} }

View File

@@ -330,10 +330,8 @@ public abstract class InputHandler implements InputProcessor{
public boolean validPlace(int x, int y, Block type, int rotation){ public boolean validPlace(int x, int y, Block type, int rotation){
for(Tile tile : state.teams.get(player.getTeam()).cores){ for(Tile tile : state.teams.get(player.getTeam()).cores){
if(tile.dst(x * tilesize, y * tilesize) < coreBuildRange){ return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
return Build.validPlace(player.getTeam(), x, y, type, rotation) && Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
}
} }
return false; return false;

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.io; package io.anuke.mindustry.io;
import io.anuke.mindustry.game.Difficulty; import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import static io.anuke.mindustry.Vars.world; import static io.anuke.mindustry.Vars.world;
@@ -11,7 +10,6 @@ public class SaveMeta{
public int build; public int build;
public long timestamp; public long timestamp;
public long timePlayed; public long timePlayed;
public GameMode mode;
public Map map; public Map map;
public int wave; public int wave;
public Difficulty difficulty; public Difficulty difficulty;
@@ -21,7 +19,6 @@ public class SaveMeta{
this.build = build; this.build = build;
this.timestamp = timestamp; this.timestamp = timestamp;
this.timePlayed = timePlayed; this.timePlayed = timePlayed;
this.mode = GameMode.values()[mode];
this.map = world.maps.getByName(map); this.map = world.maps.getByName(map);
this.wave = wave; this.wave = wave;
this.difficulty = difficulty; this.difficulty = difficulty;

View File

@@ -1,9 +1,8 @@
package io.anuke.mindustry.io.versions; package io.anuke.mindustry.io.versions;
import io.anuke.arc.util.Time; import io.anuke.arc.util.Time;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Version; import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.io.SaveFileVersion; import io.anuke.mindustry.io.SaveFileVersion;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
@@ -26,18 +25,15 @@ public class Save16 extends SaveFileVersion{
stream.readInt(); //build stream.readInt(); //build
//general state //general state
byte mode = stream.readByte(); state.rules = Serialization.readRules(stream);
String mapname = stream.readUTF(); String mapname = stream.readUTF();
Map map = world.maps.getByName(mapname); Map map = world.maps.getByName(mapname);
if(map == null) map = new Map("unknown", 1, 1); if(map == null) map = new Map("unknown", 1, 1);
world.setMap(map); world.setMap(map);
int wave = stream.readInt(); int wave = stream.readInt();
byte difficulty = stream.readByte();
float wavetime = stream.readFloat(); float wavetime = stream.readFloat();
state.difficulty = Difficulty.values()[difficulty];
state.mode = GameMode.values()[mode];
state.wave = wave; state.wave = wave;
state.wavetime = wavetime; state.wavetime = wavetime;
@@ -59,11 +55,10 @@ public class Save16 extends SaveFileVersion{
stream.writeInt(Version.build); //build stream.writeInt(Version.build); //build
//--GENERAL STATE-- //--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode Serialization.writeRules(stream, state.rules);
stream.writeUTF(world.getMap().name); //map ID stream.writeUTF(world.getMap().name); //map name
stream.writeInt(state.wave); //wave stream.writeInt(state.wave); //wave
stream.writeByte(state.difficulty.ordinal()); //difficulty ordinal
stream.writeFloat(state.wavetime); //wave countdown stream.writeFloat(state.wavetime); //wave countdown
writeContentHeader(stream); writeContentHeader(stream);

View File

@@ -4,6 +4,7 @@ import io.anuke.arc.Core;
import io.anuke.arc.collection.IntIntMap; import io.anuke.arc.collection.IntIntMap;
import io.anuke.arc.collection.ObjectMap; import io.anuke.arc.collection.ObjectMap;
//todo: specify preferred game rules here; can be overriden
public class MapMeta{ public class MapMeta{
public final int version; public final int version;
public final ObjectMap<String, String> tags; public final ObjectMap<String, String> tags;

View File

@@ -21,6 +21,7 @@ public class BasicGenerator extends RandomGenerator{
@Override @Override
public void generate(Tile[][] tiles){ public void generate(Tile[][] tiles){
//todo use set seed
int seed = Mathf.random(99999999); int seed = Mathf.random(99999999);
sim.setSeed(seed); sim.setSeed(seed);
sim2.setSeed(seed + 1); sim2.setSeed(seed + 1);
@@ -42,5 +43,17 @@ public class BasicGenerator extends RandomGenerator{
} }
} }
} }
//rock outcrops
double rocks = sim.octaveNoise2D(3, 0.7, 1f / 70f, x, y);
double edgeDist = Math.min(x, Math.min(y, Math.min(Math.abs(x - (width - 1)), Math.abs(y - (height - 1)))));
double transition = 8;
if(edgeDist < transition){
rocks += (transition - edgeDist) / transition / 1.5;
}
if(rocks > 0.64){
block = Blocks.rocksSmall;
}
} }
} }

View File

@@ -1,7 +1,5 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import io.anuke.mindustry.game.GameMode;
public class Host{ public class Host{
public final String name; public final String name;
public final String address; public final String address;
@@ -10,9 +8,8 @@ public class Host{
public final int players; public final int players;
public final int version; public final int version;
public final String versionType; public final String versionType;
public final GameMode mode;
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, GameMode mode){ public Host(String name, String address, String mapname, int wave, int players, int version, String versionType){
this.name = name; this.name = name;
this.address = address; this.address = address;
this.players = players; this.players = players;
@@ -20,6 +17,5 @@ public class Host{
this.wave = wave; this.wave = wave;
this.version = version; this.version = version;
this.versionType = versionType; this.versionType = versionType;
this.mode = mode;
} }
} }

View File

@@ -8,11 +8,11 @@ import io.anuke.arc.util.Pack;
import io.anuke.arc.util.Time; import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams; import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.Teams.TeamData; import io.anuke.mindustry.game.Teams.TeamData;
import io.anuke.mindustry.game.Version; import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.maps.MapMeta; import io.anuke.mindustry.maps.MapMeta;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
@@ -30,7 +30,7 @@ public class NetworkIO{
try(DataOutputStream stream = new DataOutputStream(os)){ try(DataOutputStream stream = new DataOutputStream(os)){
//--GENERAL STATE-- //--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode Serialization.writeRules(stream, state.rules);
stream.writeUTF(world.getMap().name); //map name stream.writeUTF(world.getMap().name); //map name
//write tags //write tags
@@ -121,7 +121,7 @@ public class NetworkIO{
Time.clear(); Time.clear();
//general state //general state
byte mode = stream.readByte(); state.rules = Serialization.readRules(stream);
String map = stream.readUTF(); String map = stream.readUTF();
ObjectMap<String, String> tags = new ObjectMap<>(); ObjectMap<String, String> tags = new ObjectMap<>();
@@ -138,7 +138,6 @@ public class NetworkIO{
state.wave = wave; state.wave = wave;
state.wavetime = wavetime; state.wavetime = wavetime;
state.mode = GameMode.values()[mode];
Entities.clear(); Entities.clear();
int id = stream.readInt(); int id = stream.readInt();
@@ -256,7 +255,6 @@ public class NetworkIO{
buffer.putInt(Version.build); buffer.putInt(Version.build);
buffer.put((byte)Version.type.getBytes(StandardCharsets.UTF_8).length); buffer.put((byte)Version.type.getBytes(StandardCharsets.UTF_8).length);
buffer.put(Version.type.getBytes(StandardCharsets.UTF_8)); buffer.put(Version.type.getBytes(StandardCharsets.UTF_8));
buffer.put((byte)state.mode.ordinal());
return buffer; return buffer;
} }
@@ -279,8 +277,7 @@ public class NetworkIO{
byte[] tb = new byte[tlength]; byte[] tb = new byte[tlength];
buffer.get(tb); buffer.get(tb);
String vertype = new String(tb, StandardCharsets.UTF_8); String vertype = new String(tb, StandardCharsets.UTF_8);
GameMode mode = GameMode.values()[buffer.get()];
return new Host(host, hostAddress, map, wave, players, version, vertype, mode); return new Host(host, hostAddress, map, wave, players, version, vertype);
} }
} }

View File

@@ -9,7 +9,6 @@ import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Log; import io.anuke.arc.util.Log;
import io.anuke.arc.util.Strings; import io.anuke.arc.util.Strings;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.ui.ContentDisplay; import io.anuke.mindustry.ui.ContentDisplay;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
@@ -31,13 +30,9 @@ public class Recipe extends UnlockableContent{
public final float cost; public final float cost;
public RecipeVisibility visibility = RecipeVisibility.all; public RecipeVisibility visibility = RecipeVisibility.all;
//the only gamemode in which the recipe shows up
public GameMode mode;
public boolean hidden; public boolean hidden;
public boolean alwaysUnlocked; public boolean alwaysUnlocked;
private UnlockableContent[] dependencies;
public Recipe(Category category, Block result, ItemStack... requirements){ public Recipe(Category category, Block result, ItemStack... requirements){
this.result = result; this.result = result;
this.requirements = requirements; this.requirements = requirements;
@@ -59,7 +54,7 @@ public class Recipe extends UnlockableContent{
public static Array<Recipe> getByCategory(Category category){ public static Array<Recipe> getByCategory(Category category){
returnArray.clear(); returnArray.clear();
for(Recipe recipe : content.recipes()){ for(Recipe recipe : content.recipes()){
if(recipe.category == category && recipe.visibility.shown() && (recipe.mode == state.mode || recipe.mode == null)){ if(recipe.category == category && recipe.visibility.shown()){
returnArray.add(recipe); returnArray.add(recipe);
} }
} }
@@ -75,11 +70,6 @@ public class Recipe extends UnlockableContent{
return this; return this;
} }
public Recipe setMode(GameMode mode){
this.mode = mode;
return this;
}
public Recipe setHidden(boolean hidden){ public Recipe setHidden(boolean hidden){
this.hidden = hidden; this.hidden = hidden;
return this; return this;
@@ -153,7 +143,13 @@ public class Recipe extends UnlockableContent{
public enum RecipeVisibility{ public enum RecipeVisibility{
mobileOnly(true, false), mobileOnly(true, false),
desktopOnly(false, true), desktopOnly(false, true),
all(true, true); all(true, true),
sandboxOnly(true, true){
@Override
public boolean usable(){
return state.rules.infiniteResources;
}
};
public final boolean mobile, desktop; public final boolean mobile, desktop;
@@ -162,8 +158,12 @@ public class Recipe extends UnlockableContent{
this.desktop = desktop; this.desktop = desktop;
} }
public boolean usable(){
return true;
}
public boolean shown(){ public boolean shown(){
return (Vars.mobile && mobile) || (!Vars.mobile && desktop); return usable() && ((Vars.mobile && mobile) || (!Vars.mobile && desktop));
} }
} }
} }

View File

@@ -12,13 +12,14 @@ import io.anuke.arc.scene.ui.layout.Table;
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.mindustry.game.Difficulty; import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.RulePreset;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.ui.BorderImage; import io.anuke.mindustry.ui.BorderImage;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class CustomGameDialog extends FloatingDialog{ public class CustomGameDialog extends FloatingDialog{
Difficulty difficulty = Difficulty.normal;
public CustomGameDialog(){ public CustomGameDialog(){
super("$customgame"); super("$customgame");
@@ -46,11 +47,11 @@ public class CustomGameDialog extends FloatingDialog{
Table modes = new Table(); Table modes = new Table();
modes.marginBottom(5); modes.marginBottom(5);
for(GameMode mode : GameMode.values()){ for(RulePreset mode : RulePreset.values()){
if(mode.hidden) continue;
modes.addButton("$mode." + mode.name() + ".name", "toggle", () -> state.mode = mode) //todo fix presets
.update(b -> b.setChecked(state.mode == mode)).group(group).size(140f, 54f); modes.addButton(mode.toString(), "toggle", () -> state.rules = mode.get())/*
.update(b -> b.setChecked(state.rules == mode))*/.group(group).size(140f, 54f);
if(i++ % 2 == 1) modes.row(); if(i++ % 2 == 1) modes.row();
} }
selmode.add(modes); selmode.add(modes);
@@ -66,20 +67,21 @@ public class CustomGameDialog extends FloatingDialog{
Table sdif = new Table(); Table sdif = new Table();
sdif.add("$setting.difficulty.name").padRight(15f); sdif.add("$setting.difficulty.name").padRight(15f);
sdif.defaults().height(s + 4); sdif.defaults().height(s + 4);
sdif.addImageButton("icon-arrow-left", 10 * 3, () -> { sdif.addImageButton("icon-arrow-left", 10 * 3, () -> {
state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() - 1, ds.length)]); difficulty = (ds[Mathf.mod(difficulty.ordinal() - 1, ds.length)]);
state.wavetime = difficulty.waveTime;
}).width(s); }).width(s);
sdif.addButton("", () -> {}) sdif.addButton("", () -> {})
.update(t -> { .update(t -> {
t.setText(state.difficulty.toString()); t.setText(difficulty.toString());
t.touchable(Touchable.disabled); t.touchable(Touchable.disabled);
}).width(180f); }).width(180f);
sdif.addImageButton("icon-arrow-right", 10 * 3, () -> { sdif.addImageButton("icon-arrow-right", 10 * 3, () -> {
state.difficulty = (ds[Mathf.mod(state.difficulty.ordinal() + 1, ds.length)]); difficulty = (ds[Mathf.mod(difficulty.ordinal() + 1, ds.length)]);
state.wavetime = difficulty.waveTime;
}).width(s); }).width(s);
cont.add(sdif); cont.add(sdif);
@@ -141,8 +143,7 @@ public class CustomGameDialog extends FloatingDialog{
ScrollPane pane = new ScrollPane(table); ScrollPane pane = new ScrollPane(table);
pane.setFadeScrollBars(false); pane.setFadeScrollBars(false);
table.row(); table.row();
for(GameMode mode : GameMode.values()){ for(RulePreset mode : RulePreset.values()){
if(mode.hidden) continue;
table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f); table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f);
table.row(); table.row();
} }

View File

@@ -112,9 +112,7 @@ public class LoadDialog extends FloatingDialog{
button.defaults().padBottom(3); button.defaults().padBottom(3);
button.row(); button.row();
button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? "Unknown" : slot.getMap().meta.name()))); button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().meta.name())));
button.row();
button.add(Core.bundle.get("level.mode") + " " + color + slot.getMode());
button.row(); button.row();
button.add(Core.bundle.format("save.wave", color + slot.getWave())); button.add(Core.bundle.format("save.wave", color + slot.getWave()));
button.row(); button.row();

View File

@@ -26,7 +26,7 @@ public class RestartDialog extends FloatingDialog{
buttons.margin(10); buttons.margin(10);
if(state.mode.isPvp){ if(state.rules.pvp){
cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6); cont.add(Core.bundle.format("gameover.pvp",winner.localized())).pad(6);
buttons.addButton("$menu", () -> { buttons.addButton("$menu", () -> {
hide(); hide();

View File

@@ -369,18 +369,18 @@ public class HudFragment extends Fragment{
table.touchable(Touchable.enabled); table.touchable(Touchable.enabled);
table.labelWrap(() -> table.labelWrap(() ->
(state.enemies() > 0 && state.mode.disableWaveTimer ? (state.enemies() > 0 && !state.rules.waveTimer ?
wavef.get(state.wave) + "\n" + (state.enemies() == 1 ? wavef.get(state.wave) + "\n" + (state.enemies() == 1 ?
enemyf.get(state.enemies()) : enemyf.get(state.enemies()) :
enemiesf.get(state.enemies())) : enemiesf.get(state.enemies())) :
wavef.get(state.wave) + "\n" + wavef.get(state.wave) + "\n" +
(!state.mode.disableWaveTimer ? (state.rules.waveTimer ?
Core.bundle.format("wave.waiting", (int)(state.wavetime/60)) : Core.bundle.format("wave.waiting", (int)(state.wavetime/60)) :
Core.bundle.get("waiting"))) Core.bundle.get("waiting")))
).growX().pad(8f); ).growX().pad(8f);
table.setDisabled(true); table.setDisabled(true);
table.visible(() -> !(state.mode.disableWaves || !state.mode.showMission)); table.visible(() -> state.rules.waves);
} }
private void addPlayButton(Table table){ private void addPlayButton(Table table){
@@ -391,11 +391,11 @@ public class HudFragment extends Fragment{
state.wavetime = 0f; state.wavetime = 0f;
} }
}).growY().fillX().right().width(40f).update(l -> { }).growY().fillX().right().width(40f).update(l -> {
boolean vis = state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()); boolean vis = !state.rules.waveTimer && ((Net.server() || players[0].isAdmin) || !Net.active());
boolean paused = state.is(State.paused) || !vis; boolean paused = state.is(State.paused) || !vis;
l.getStyle().imageUp = Core.scene.skin.getDrawable(vis ? "icon-play" : "clear"); l.getStyle().imageUp = Core.scene.skin.getDrawable(vis ? "icon-play" : "clear");
l.touchable(!paused ? Touchable.enabled : Touchable.disabled); l.touchable(!paused ? Touchable.enabled : Touchable.disabled);
}).visible(() -> state.mode.disableWaveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()) && unitGroups[Team.red.ordinal()].size() == 0); }).visible(() -> !state.rules.waveTimer && ((Net.server() || players[0].isAdmin) || !Net.active()) && unitGroups[Team.red.ordinal()].size() == 0);
} }
} }

View File

@@ -134,7 +134,7 @@ public class PlacementFragment extends Fragment{
button.update(() -> { //color unplacable things gray button.update(() -> { //color unplacable things gray
boolean ulock = data.isUnlocked(recipe); boolean ulock = data.isUnlocked(recipe);
TileEntity core = players[0].getClosestCore(); TileEntity core = players[0].getClosestCore();
Color color = core != null && (core.items.has(recipe.requirements) || state.mode.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE; Color color = core != null && (core.items.has(recipe.requirements) || state.rules.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE;
button.forEach(elem -> elem.setColor(color)); button.forEach(elem -> elem.setColor(color));
button.setChecked(input.recipe == recipe); button.setChecked(input.recipe == recipe);
@@ -196,7 +196,7 @@ public class PlacementFragment extends Fragment{
line.add(stack.item.localizedName()).color(Color.LIGHT_GRAY).padLeft(2).left(); line.add(stack.item.localizedName()).color(Color.LIGHT_GRAY).padLeft(2).left();
line.labelWrap(() -> { line.labelWrap(() -> {
TileEntity core = players[0].getClosestCore(); TileEntity core = players[0].getClosestCore();
if(core == null || state.mode.infiniteResources) return "*/*"; if(core == null || state.rules.infiniteResources) return "*/*";
int amount = core.items.get(stack.item); int amount = core.items.get(stack.item);
String color = (amount < stack.amount / 2f ? "[red]" : amount < stack.amount ? "[accent]" : "[white]"); String color = (amount < stack.amount / 2f ? "[red]" : amount < stack.amount ? "[accent]" : "[white]");

View File

@@ -1,13 +1,6 @@
package io.anuke.mindustry.ui.fragments; package io.anuke.mindustry.ui.fragments;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.util.Interval;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.Lines; import io.anuke.arc.graphics.g2d.Lines;
import io.anuke.arc.scene.Group; import io.anuke.arc.scene.Group;
@@ -15,7 +8,13 @@ import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.ui.Image; import io.anuke.arc.scene.ui.Image;
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.util.Timer; import io.anuke.arc.util.Interval;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.net.Packets.AdminAction;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -137,7 +136,7 @@ public class PlayerListFragment extends Fragment{
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14); content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
content.row(); content.row();
content.addImage("blank").height(3f).color(state.mode.isPvp ? player.getTeam().color : Palette.accent).growX(); content.addImage("blank").height(3f).color(state.rules.pvp ? player.getTeam().color : Palette.accent).growX();
content.row(); content.row();
}); });

View File

@@ -109,7 +109,7 @@ public class Build{
public static boolean validPlace(Team team, int x, int y, Block type, int rotation){ public static boolean validPlace(Team team, int x, int y, Block type, int rotation){
Recipe recipe = Recipe.getByResult(type); Recipe recipe = Recipe.getByResult(type);
if(recipe == null || (recipe.mode != null && recipe.mode != state.mode)){ if(recipe == null || (!recipe.visibility.usable())){
return false; return false;
} }
@@ -121,7 +121,7 @@ public class Build{
//check for enemy cores //check for enemy cores
for(Team enemy : state.teams.enemiesOf(team)){ for(Team enemy : state.teams.enemiesOf(team)){
for(Tile core : state.teams.get(enemy).cores){ for(Tile core : state.teams.get(enemy).cores){
if(Mathf.dst(x*tilesize + type.offset(), y*tilesize + type.offset(), core.drawx(), core.drawy()) < state.mode.enemyCoreBuildRadius + type.size*tilesize/2f){ if(Mathf.dst(x*tilesize + type.offset(), y*tilesize + type.offset(), core.drawx(), core.drawy()) < state.rules.enemyCoreBuildRadius + type.size*tilesize/2f){
return false; return false;
} }
} }

View File

@@ -205,7 +205,7 @@ public class Tile implements Position, TargetTrait{
} }
public boolean isEnemyCheat(){ public boolean isEnemyCheat(){
return getTeam() == waveTeam && !state.mode.isPvp; return getTeam() == waveTeam && !state.rules.pvp;
} }
public boolean isLinked(){ public boolean isLinked(){

View File

@@ -195,7 +195,7 @@ public class BuildBlock extends Block{
builderID = builder.getID(); builderID = builder.getID();
} }
if(progress >= 1f || state.mode.infiniteResources){ if(progress >= 1f || state.rules.infiniteResources){
Call.onConstructFinish(tile, recipe.result, builderID, tile.getRotation(), builder.getTeam()); Call.onConstructFinish(tile, recipe.result, builderID, tile.getRotation(), builder.getTeam());
} }
} }
@@ -226,7 +226,7 @@ public class BuildBlock extends Block{
progress = Mathf.clamp(progress - amount); progress = Mathf.clamp(progress - amount);
if(progress <= 0 || state.mode.infiniteResources){ if(progress <= 0 || state.rules.infiniteResources){
Call.onDeconstructFinish(tile, this.recipe == null ? previous : this.recipe.result); Call.onDeconstructFinish(tile, this.recipe == null ? previous : this.recipe.result);
} }
} }

View File

@@ -185,7 +185,7 @@ public class CoreBlock extends StorageBlock{
} }
entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.1f); entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.1f);
entity.time += entity.delta(); entity.time += entity.delta();
entity.progress += 1f / state.mode.respawnTime * entity.delta(); entity.progress += 1f / state.rules.respawnTime * entity.delta();
if(entity.progress >= 1f){ if(entity.progress >= 1f){
Call.onUnitRespawn(tile, entity.currentUnit); Call.onUnitRespawn(tile, entity.currentUnit);

View File

@@ -154,8 +154,8 @@ public class UnitFactory extends Block{
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 0f, 0.05f); entity.speedScl = Mathf.lerpDelta(entity.speedScl, 0f, 0.05f);
} }
//check if grace period had passed //check if grace period had passed
}else if(entity.warmup > produceTime*gracePeriodMultiplier * Vars.state.difficulty.spawnerScaling){ }else if(entity.warmup > produceTime*gracePeriodMultiplier){
float speedMultiplier = Math.min(0.1f + (entity.warmup - produceTime * gracePeriodMultiplier * Vars.state.difficulty.spawnerScaling) / speedupTime, maxSpeedup); float speedMultiplier = Math.min(0.1f + (entity.warmup - produceTime * gracePeriodMultiplier) / speedupTime, maxSpeedup);
//otherwise, it's an enemy, cheat by not requiring resources //otherwise, it's an enemy, cheat by not requiring resources
entity.buildTime += entity.delta() * speedMultiplier; entity.buildTime += entity.delta() * speedMultiplier;
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.05f); entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.05f);

View File

@@ -77,7 +77,6 @@ public class CrashHandler{
ex(() -> value.addChild("build", new JsonValue(Version.build))); ex(() -> value.addChild("build", new JsonValue(Version.build)));
ex(() -> value.addChild("net", new JsonValue(fn))); ex(() -> value.addChild("net", new JsonValue(fn)));
ex(() -> value.addChild("server", new JsonValue(fs))); ex(() -> value.addChild("server", new JsonValue(fs)));
ex(() -> value.addChild("gamemode", new JsonValue(Vars.state.mode.name())));
ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name()))); ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name())));
ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name")))); ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name"))));
ex(() -> value.addChild("trace", new JsonValue(parseException(e)))); ex(() -> value.addChild("trace", new JsonValue(parseException(e))));

View File

@@ -11,7 +11,6 @@ import io.anuke.arc.util.Strings;
import io.anuke.arc.util.serialization.Base64Coder; import io.anuke.arc.util.serialization.Base64Coder;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser; import io.anuke.mindustry.ui.dialogs.FileChooser;
@@ -51,22 +50,18 @@ public class DesktopPlatform extends Platform{
DiscordRichPresence presence = new DiscordRichPresence(); DiscordRichPresence presence = new DiscordRichPresence();
if(!state.is(State.menu)){ if(!state.is(State.menu)){
presence.state = Strings.capitalize(state.mode.name()); presence.state = state.rules.waves ? "Survival" : "Attack";
if(world.getMap() == null){ if(world.getMap() == null){
presence.details = "Unknown Map"; presence.details = "Unknown Map";
}else if(state.mode.disableWaves){ }else if(!state.rules.waves){
presence.details = Strings.capitalize(world.getMap().name); presence.details = Strings.capitalize(world.getMap().name);
}else{ }else{
presence.details = Strings.capitalize(world.getMap().name) + " | Wave " + state.wave; presence.details = Strings.capitalize(world.getMap().name) + " | Wave " + state.wave;
presence.largeImageText = "Wave " + state.wave; presence.largeImageText = "Wave " + state.wave;
} }
if(state.mode != GameMode.attack){ presence.state = unitGroups[players[0].getTeam().ordinal()].size() == 1 ? "1 Unit Active" :
presence.state = Strings.capitalize(state.mode.name()); (unitGroups[players[0].getTeam().ordinal()].size() + " Units Active");
}else{
presence.state = unitGroups[players[0].getTeam().ordinal()].size() == 1 ? "1 Unit Active" :
(unitGroups[players[0].getTeam().ordinal()].size() + " Units Active");
}
if(Net.active()){ if(Net.active()){
presence.partyMax = 16; presence.partyMax = 16;

View File

@@ -48,9 +48,7 @@ public class CrashHandler{
ex(() -> value.addChild("versionNumber", new JsonValue(Version.number))); ex(() -> value.addChild("versionNumber", new JsonValue(Version.number)));
ex(() -> value.addChild("versionModifier", new JsonValue(Version.modifier))); ex(() -> value.addChild("versionModifier", new JsonValue(Version.modifier)));
ex(() -> value.addChild("build", new JsonValue(Version.build))); ex(() -> value.addChild("build", new JsonValue(Version.build)));
ex(() -> value.addChild("mode", new JsonValue(Vars.state.mode.name())));
ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name()))); ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name())));
ex(() -> value.addChild("difficulty", new JsonValue(Vars.state.difficulty.name())));
ex(() -> value.addChild("players", new JsonValue(Vars.playerGroup.size()))); ex(() -> value.addChild("players", new JsonValue(Vars.playerGroup.size())));
ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name")))); ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name"))));
ex(() -> value.addChild("trace", new JsonValue(parseException(e)))); ex(() -> value.addChild("trace", new JsonValue(parseException(e))));

View File

@@ -16,8 +16,6 @@ import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.game.Difficulty; import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.EventType.GameOverEvent; import io.anuke.mindustry.game.EventType.GameOverEvent;
import io.anuke.mindustry.game.EventType.SectorCompleteEvent;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version; import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.gen.Call;
@@ -139,7 +137,7 @@ public class ServerControl implements ApplicationListener{
while(map == previous) map = maps.random(); while(map == previous) map = maps.random();
} }
Call.onInfoMessage((state.mode.isPvp Call.onInfoMessage((state.rules.pvp
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]") ? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
+ "\nNext selected map:[accent] "+map.name+"[]" + "\nNext selected map:[accent] "+map.name+"[]"
+ (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+ + (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+
@@ -188,7 +186,7 @@ public class ServerControl implements ApplicationListener{
info("Stopped server."); info("Stopped server.");
}); });
handler.register("host", "[mapname] [mode]", "Open the server with a specific map.", arg -> { handler.register("host", "[mapname]", "Open the server with a specific map.", arg -> {
if(state.is(State.playing)){ if(state.is(State.playing)){
err("Already hosting. Type 'stop' to stop hosting first."); err("Already hosting. Type 'stop' to stop hosting first.");
return; return;
@@ -212,18 +210,7 @@ public class ServerControl implements ApplicationListener{
info("Loading map..."); info("Loading map...");
err("TODO select gamemode");
if(arg.length > 1){
GameMode mode;
try{
mode = GameMode.valueOf(arg[1]);
}catch(IllegalArgumentException e){
err("No gamemode '{0}' found.", arg[1]);
return;
}
state.mode = mode;
}
logic.reset(); logic.reset();
world.loadMap(result); world.loadMap(result);
@@ -231,7 +218,7 @@ public class ServerControl implements ApplicationListener{
}else{ }else{
//TODO //TODO
info("TODO play generated map"); err("TODO play generated map");
} }
info("Map loaded."); info("Map loaded.");
@@ -266,9 +253,9 @@ public class ServerControl implements ApplicationListener{
info("Status: &rserver closed"); info("Status: &rserver closed");
}else{ }else{
info("Status:"); info("Status:");
info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1} &lb/&ly {2} &lb/&ly {3}", Strings.capitalize(world.getMap().name), state.wave, Strings.capitalize(state.difficulty.name()), Strings.capitalize(state.mode.name())); info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1} &lb/&ly {2} &lb/&ly {3}", Strings.capitalize(world.getMap().name), state.wave);
if(state.mode.disableWaveTimer){ if(!state.rules.waves){
info("&ly {0} enemies.", unitGroups[Team.red.ordinal()].size()); info("&ly {0} enemies.", unitGroups[Team.red.ordinal()].size());
}else{ }else{
info("&ly {0} seconds until next wave.", (int) (state.wavetime / 60)); info("&ly {0} seconds until next wave.", (int) (state.wavetime / 60));
@@ -301,7 +288,7 @@ public class ServerControl implements ApplicationListener{
handler.register("difficulty", "<difficulty>", "Set game difficulty.", arg -> { handler.register("difficulty", "<difficulty>", "Set game difficulty.", arg -> {
try{ try{
state.difficulty = Difficulty.valueOf(arg[0]); state.rules.waveSpacing = Difficulty.valueOf(arg[0]).waveTime;
info("Difficulty set to '{0}'.", arg[0]); info("Difficulty set to '{0}'.", arg[0]);
}catch(IllegalArgumentException e){ }catch(IllegalArgumentException e){
err("No difficulty with name '{0}' found.", arg[0]); err("No difficulty with name '{0}' found.", arg[0]);

View File

@@ -198,7 +198,7 @@ public class ApplicationTests{
@Test @Test
void inventoryDeposit(){ void inventoryDeposit(){
depositTest(Blocks.smelter, Items.copper); depositTest(Blocks.surgeSmelter, Items.copper);
depositTest(Blocks.vault, Items.copper); depositTest(Blocks.vault, Items.copper);
depositTest(Blocks.thoriumReactor, Items.thorium); depositTest(Blocks.thoriumReactor, Items.thorium);
} }