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

@@ -39,12 +39,8 @@ public class Vars{
public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors";
/**URL for sending crash reports to*/
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*/
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*/
public static final Team defaultTeam = Team.blue;
/**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){
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){

View File

@@ -31,7 +31,7 @@ public class Blocks implements ContentList{
//environment
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
siliconSmelter, plastaniumCompressor, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
@@ -209,6 +209,18 @@ public class Blocks implements ContentList{
blackrock = new Rock("blackrock"){{
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
//region crafting

View File

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

View File

@@ -113,18 +113,7 @@ public class Control implements ApplicationListener{
saves.resetSave();
});
Events.on(WaveEvent.class, event -> {
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();
});
//todo high scores for custom maps, as well as other statistics
Events.on(GameOverEvent.class, event -> {
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
Events.on(WorldLoadEvent.class, event -> {
if(state.mode.isPvp && !Net.active()){
if(state.rules.pvp && !Net.active()){
try{
Net.host(port);
players[0].isAdmin = true;

View File

@@ -1,11 +1,10 @@
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.GameMode;
import io.anuke.mindustry.game.Rules;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.net.Net;
import io.anuke.arc.Events;
import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.waveTeam;
@@ -13,14 +12,12 @@ import static io.anuke.mindustry.Vars.waveTeam;
public class GameState{
/**Current wave number, can be anything in non-wave modes.*/
public int wave = 1;
/**Wave countdown in ticks.*/
/**Wave time in ticks.*/
public float wavetime;
/**Whether the game is in game over state.*/
public boolean gameOver = false;
/**The current game mode.*/
public GameMode mode = GameMode.waves;
/**The current difficulty for wave modes.*/
public Difficulty difficulty = Difficulty.normal;
/**The current game rules.*/
public Rules rules = new Rules();
/**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

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

View File

@@ -193,7 +193,8 @@ public class NetServer implements ApplicationListener{
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.
Team min = Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team)){
@@ -382,7 +383,7 @@ public class NetServer implements ApplicationListener{
}
public boolean isWaitingForPlayers(){
if(state.mode.isPvp){
if(state.rules.pvp){
int used = 0;
for(Team t : Team.all){
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){
ui.showError("$map.nospawn");
invalidMap = true;
}else if(state.mode.isPvp){
}else if(state.rules.pvp){ //pvp maps need two cores to be valid
invalidMap = true;
for(Team team : Team.all){
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){
//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;
}

View File

@@ -2,23 +2,21 @@ package io.anuke.mindustry.game;
import io.anuke.arc.Core;
/**Presets for time between waves.
* TODO specify correct time*/
public enum Difficulty{
training(3f, 3f),
easy(1.4f, 1.5f),
normal(1f, 1f),
hard(0.5f, 0.75f),
insane(0.25f, 0.5f);
easy(1.4f),
normal(1f),
hard(0.5f),
insane(0.25f);
/**Multiplier of the time between waves.*/
public final float timeScaling;
/**Multiplier of spawner grace period.*/
public final float spawnerScaling;
public final float waveTime;
private String value;
Difficulty(float timeScaling, float spawnerScaling){
this.timeScaling = timeScaling;
this.spawnerScaling = spawnerScaling;
Difficulty(float waveTime){
this.waveTime = waveTime;
}
@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;
}
public GameMode getMode(){
return meta.mode;
}
public boolean isAutosave(){
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.*/
public boolean isActive(Team team){
//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.*/

View File

@@ -76,11 +76,11 @@ public class OverlayRenderer{
for(Team enemy : state.teams.enemiesOf(player.getTeam())){
for(Tile core : state.teams.get(enemy).cores){
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);
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));
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){
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) &&
Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
}
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
}
return false;

View File

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

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ public class BasicGenerator extends RandomGenerator{
@Override
public void generate(Tile[][] tiles){
//todo use set seed
int seed = Mathf.random(99999999);
sim.setSeed(seed);
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;
import io.anuke.mindustry.game.GameMode;
public class Host{
public final String name;
public final String address;
@@ -10,9 +8,8 @@ public class Host{
public final int players;
public final int version;
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.address = address;
this.players = players;
@@ -20,6 +17,5 @@ public class Host{
this.wave = wave;
this.version = version;
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.mindustry.content.Blocks;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.Teams.TeamData;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.maps.MapMeta;
import io.anuke.mindustry.world.Tile;
@@ -30,7 +30,7 @@ public class NetworkIO{
try(DataOutputStream stream = new DataOutputStream(os)){
//--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode
Serialization.writeRules(stream, state.rules);
stream.writeUTF(world.getMap().name); //map name
//write tags
@@ -121,7 +121,7 @@ public class NetworkIO{
Time.clear();
//general state
byte mode = stream.readByte();
state.rules = Serialization.readRules(stream);
String map = stream.readUTF();
ObjectMap<String, String> tags = new ObjectMap<>();
@@ -138,7 +138,6 @@ public class NetworkIO{
state.wave = wave;
state.wavetime = wavetime;
state.mode = GameMode.values()[mode];
Entities.clear();
int id = stream.readInt();
@@ -256,7 +255,6 @@ public class NetworkIO{
buffer.putInt(Version.build);
buffer.put((byte)Version.type.getBytes(StandardCharsets.UTF_8).length);
buffer.put(Version.type.getBytes(StandardCharsets.UTF_8));
buffer.put((byte)state.mode.ordinal());
return buffer;
}
@@ -279,8 +277,7 @@ public class NetworkIO{
byte[] tb = new byte[tlength];
buffer.get(tb);
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.Strings;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.ui.ContentDisplay;
import io.anuke.mindustry.world.Block;
@@ -31,13 +30,9 @@ public class Recipe extends UnlockableContent{
public final float cost;
public RecipeVisibility visibility = RecipeVisibility.all;
//the only gamemode in which the recipe shows up
public GameMode mode;
public boolean hidden;
public boolean alwaysUnlocked;
private UnlockableContent[] dependencies;
public Recipe(Category category, Block result, ItemStack... requirements){
this.result = result;
this.requirements = requirements;
@@ -59,7 +54,7 @@ public class Recipe extends UnlockableContent{
public static Array<Recipe> getByCategory(Category category){
returnArray.clear();
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);
}
}
@@ -75,11 +70,6 @@ public class Recipe extends UnlockableContent{
return this;
}
public Recipe setMode(GameMode mode){
this.mode = mode;
return this;
}
public Recipe setHidden(boolean hidden){
this.hidden = hidden;
return this;
@@ -153,7 +143,13 @@ public class Recipe extends UnlockableContent{
public enum RecipeVisibility{
mobileOnly(true, false),
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;
@@ -162,8 +158,12 @@ public class Recipe extends UnlockableContent{
this.desktop = desktop;
}
public boolean usable(){
return true;
}
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.Scaling;
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.ui.BorderImage;
import static io.anuke.mindustry.Vars.*;
public class CustomGameDialog extends FloatingDialog{
Difficulty difficulty = Difficulty.normal;
public CustomGameDialog(){
super("$customgame");
@@ -46,11 +47,11 @@ public class CustomGameDialog extends FloatingDialog{
Table modes = new Table();
modes.marginBottom(5);
for(GameMode mode : GameMode.values()){
if(mode.hidden) continue;
for(RulePreset mode : RulePreset.values()){
modes.addButton("$mode." + mode.name() + ".name", "toggle", () -> state.mode = mode)
.update(b -> b.setChecked(state.mode == mode)).group(group).size(140f, 54f);
//todo fix presets
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();
}
selmode.add(modes);
@@ -66,20 +67,21 @@ public class CustomGameDialog extends FloatingDialog{
Table sdif = new Table();
sdif.add("$setting.difficulty.name").padRight(15f);
sdif.defaults().height(s + 4);
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);
sdif.addButton("", () -> {})
.update(t -> {
t.setText(state.difficulty.toString());
t.setText(difficulty.toString());
t.touchable(Touchable.disabled);
}).width(180f);
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);
cont.add(sdif);
@@ -141,8 +143,7 @@ public class CustomGameDialog extends FloatingDialog{
ScrollPane pane = new ScrollPane(table);
pane.setFadeScrollBars(false);
table.row();
for(GameMode mode : GameMode.values()){
if(mode.hidden) continue;
for(RulePreset mode : RulePreset.values()){
table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f);
table.row();
}

View File

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

View File

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

View File

@@ -369,18 +369,18 @@ public class HudFragment extends Fragment{
table.touchable(Touchable.enabled);
table.labelWrap(() ->
(state.enemies() > 0 && state.mode.disableWaveTimer ?
(state.enemies() > 0 && !state.rules.waveTimer ?
wavef.get(state.wave) + "\n" + (state.enemies() == 1 ?
enemyf.get(state.enemies()) :
enemiesf.get(state.enemies())) :
wavef.get(state.wave) + "\n" +
(!state.mode.disableWaveTimer ?
(state.rules.waveTimer ?
Core.bundle.format("wave.waiting", (int)(state.wavetime/60)) :
Core.bundle.get("waiting")))
).growX().pad(8f);
table.setDisabled(true);
table.visible(() -> !(state.mode.disableWaves || !state.mode.showMission));
table.visible(() -> state.rules.waves);
}
private void addPlayButton(Table table){
@@ -391,11 +391,11 @@ public class HudFragment extends Fragment{
state.wavetime = 0f;
}
}).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;
l.getStyle().imageUp = Core.scene.skin.getDrawable(vis ? "icon-play" : "clear");
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
boolean ulock = data.isUnlocked(recipe);
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.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.labelWrap(() -> {
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);
String color = (amount < stack.amount / 2f ? "[red]" : amount < stack.amount ? "[accent]" : "[white]");

View File

@@ -1,13 +1,6 @@
package io.anuke.mindustry.ui.fragments;
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.Lines;
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.layout.Table;
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.*;
@@ -137,7 +136,7 @@ public class PlayerListFragment extends Fragment{
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
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();
});

View File

@@ -109,7 +109,7 @@ public class Build{
public static boolean validPlace(Team team, int x, int y, Block type, int rotation){
Recipe recipe = Recipe.getByResult(type);
if(recipe == null || (recipe.mode != null && recipe.mode != state.mode)){
if(recipe == null || (!recipe.visibility.usable())){
return false;
}
@@ -121,7 +121,7 @@ public class Build{
//check for enemy cores
for(Team enemy : state.teams.enemiesOf(team)){
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;
}
}

View File

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

View File

@@ -195,7 +195,7 @@ public class BuildBlock extends Block{
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());
}
}
@@ -226,7 +226,7 @@ public class BuildBlock extends Block{
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);
}
}

View File

@@ -185,7 +185,7 @@ public class CoreBlock extends StorageBlock{
}
entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.1f);
entity.time += entity.delta();
entity.progress += 1f / state.mode.respawnTime * entity.delta();
entity.progress += 1f / state.rules.respawnTime * entity.delta();
if(entity.progress >= 1f){
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);
}
//check if grace period had passed
}else if(entity.warmup > produceTime*gracePeriodMultiplier * Vars.state.difficulty.spawnerScaling){
float speedMultiplier = Math.min(0.1f + (entity.warmup - produceTime * gracePeriodMultiplier * Vars.state.difficulty.spawnerScaling) / speedupTime, maxSpeedup);
}else if(entity.warmup > produceTime*gracePeriodMultiplier){
float speedMultiplier = Math.min(0.1f + (entity.warmup - produceTime * gracePeriodMultiplier) / speedupTime, maxSpeedup);
//otherwise, it's an enemy, cheat by not requiring resources
entity.buildTime += entity.delta() * speedMultiplier;
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.05f);