1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-11-10 15:05:23 +03:00

Re-structuring

This commit is contained in:
Anuken 2019-01-03 19:46:25 -05:00
parent e24d96da6f
commit 153e6c5f1b
46 changed files with 39 additions and 2384 deletions

View File

@ -13,8 +13,6 @@ text.linkfail = Failed to open link!\nThe URL has been copied to your clipboard.
text.screenshot = Screenshot saved to {0}
text.gameover = Game Over
text.gameover.pvp = The[accent] {0}[] team is victorious!
text.sector.gameover = This sector has been lost. Re-deploy?
text.sector.retry = Retry
text.highscore = [accent]New highscore!
text.wave.lasted = You lasted until wave [accent]{0}[].
text.level.highscore = High Score: [accent]{0}
@ -35,41 +33,11 @@ text.loadgame = Load Game
text.joingame = Join Game
text.addplayers = Add/Remove Players
text.customgame = Custom Game
text.sectors = Sectors
text.sector = Sector: [LIGHT_GRAY]{0}
text.sector.time = Time: [LIGHT_GRAY]{0}
text.sector.deploy = Deploy
text.sector.abandon = Abandon
text.sector.abandon.confirm = Are you sure you want to abandon all progress at this sector?\nThis cannot be undone!
text.sector.resume = Resume
text.sector.locked = [scarlet][[Incomplete]
text.sector.unexplored = [accent][[Unexplored]
text.missions = Missions:[LIGHT_GRAY] {0}
text.mission = Mission:[LIGHT_GRAY] {0}
text.mission.main = Main Mission:[LIGHT_GRAY] {0}
text.mission.info = Mission Info
text.mission.complete = Mission complete!
text.mission.complete.body = Sector {0},{1} has been conquered.
text.mission.wave = Survive[accent] {0}/{1} []waves\nWave in {2}
text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies
text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy
text.mission.wave.menu = Survive[accent] {0}[] waves
text.mission.battle = Destroy enemy core
text.mission.resource.menu = Obtain {0} x{1}
text.mission.resource = Obtain {0}:\n[accent]{1}/{2}[]
text.mission.block = Create {0}
text.mission.unit = Create {0} Unit
text.mission.command = Send Command {0} To Units
text.mission.linknode = Link Power Node
text.mission.display = [accent]Mission:\n[LIGHT_GRAY]{0}
text.mission.mech = Switch to mech[accent] {0}[]
text.mission.create = Create[accent] {0}[]
text.none = <none>
text.close = Close
text.quit = Quit
text.maps = Maps
text.continue = Continue
text.nextmission = Next Mission
text.maps.none = [LIGHT_GRAY]No maps found!
text.about.button = About
text.name = Name:
@ -82,8 +50,6 @@ text.players.single = {0} player online
text.server.closing = [accent]Closing server...
text.server.kicked.kick = You have been kicked from the server!
text.server.kicked.serverClose = Server closed.
text.server.kicked.sectorComplete = Sector completed.
text.server.kicked.sectorComplete.text = Your mission is complete.\nThe server will now continue at the next sector.
text.server.kicked.clientOutdated = Outdated client! Update your game!
text.server.kicked.serverOutdated = Outdated server! Ask the host to update!
text.server.kicked.banned = You are banned on this server.
@ -163,7 +129,6 @@ text.save.rename.text = New name:
text.selectslot = Select a save.
text.slot = [accent]Slot {0}
text.save.corrupted = [accent]Save file corrupted or invalid!\nIf you have just updated your game, this is probably a change in the save format and [scarlet]not[] a bug.
text.sector.corrupted = [accent]A save file for this sector was found, but loading failed.\nA new one has been created.
text.empty = <empty>
text.on = On
text.off = Off
@ -284,7 +249,6 @@ text.settings.graphics = Graphics
text.settings.cleardata = Clear Game Data...
text.settings.clear.confirm = Are you sure you want to clear this data?\nWhat is done cannot be undone!
text.settings.clearall.confirm = [scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit.
text.settings.clearsectors = Clear Sectors
text.settings.clearunlocks = Clear Unlocks
text.settings.clearall = Clear All
text.paused = [accent]< Paused >

View File

@ -177,12 +177,7 @@ public class WaveSpawner{
flySpawns.clear();
groundSpawns.clear();
quadrants = new GridBits(quadWidth(), quadHeight());
if(world.getSector() == null){
groups = Waves.getSpawns();
}else{
groups = world.getSector().spawns;
}
groups = Waves.getSpawns();
dynamicSpawn = true;

View File

@ -121,7 +121,7 @@ public class Control implements ApplicationListener{
int last = Core.settings.getInt("hiscore" + world.getMap().name, 0);
if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer && world.getSector() == null){
if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){
Core.settings.put("hiscore" + world.getMap().name, state.wave);
Core.settings.save();
hiscore = true;
@ -131,10 +131,6 @@ public class Control implements ApplicationListener{
});
Events.on(GameOverEvent.class, event -> {
//delete saves for game-over sectors
if(world.getSector() != null && world.getSector().hasSave()){
world.getSector().getSave().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);

View File

@ -4,7 +4,6 @@ import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.ApplicationListener;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.entities.Entities;
import io.anuke.arc.entities.EntityGroup;
import io.anuke.arc.entities.EntityQuery;
@ -12,13 +11,10 @@ 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.GameMode;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Tile;
@ -53,10 +49,6 @@ public class Logic implements ApplicationListener{
/**Handles the event of content being used by either the player or some block.*/
public void handleContent(UnlockableContent content){
if(world.getSector() != null){
world.getSector().currentMission().onContentUsed(content);
}
if(!headless){
control.unlocks.unlockContent(content);
}
@ -66,15 +58,6 @@ public class Logic implements ApplicationListener{
state.set(State.playing);
state.wavetime = wavespace * state.difficulty.timeScaling * 2;
for(Tile tile : state.teams.get(defaultTeam).cores){
if(world.getSector() != null){
Array<ItemStack> items = world.getSector().startingItems;
for(ItemStack stack : items){
tile.entity.items.add(stack.item, stack.amount);
}
}
}
Events.fire(new PlayEvent());
}
@ -122,52 +105,12 @@ public class Logic implements ApplicationListener{
}
}
private void updateSectors(){
if(world.getSector() == null || state.gameOver) return;
world.getSector().currentMission().update();
//check unlocked sectors
while(!world.getSector().complete && world.getSector().currentMission().isComplete()){
Call.onMissionFinish(world.getSector().completedMissions);
}
//check if all assigned missions are complete
if(!world.getSector().complete && world.getSector().completedMissions >= world.getSector().missions.size){
Call.onSectorComplete();
}
}
@Remote(called = Loc.both)
public static void onGameOver(Team winner){
ui.restart.show(winner);
netClient.setQuiet();
}
@Remote(called = Loc.server)
public static void onMissionFinish(int index){
world.getSector().missions.get(index).onComplete();
world.getSector().completedMissions = index + 1;
state.mode = world.getSector().currentMission().getMode();
world.getSector().currentMission().onBegin();
world.sectors.save();
}
@Remote(called = Loc.server)
public static void onSectorComplete(){
state.mode = GameMode.victory;
world.sectors.completeSector(world.getSector().x, world.getSector().y);
world.sectors.save();
if(!headless && !Net.client()){
ui.missions.show(world.getSector());
}
Events.fire(new SectorCompleteEvent());
}
@Override
public void update(){
@ -221,7 +164,6 @@ public class Logic implements ApplicationListener{
}
if(!Net.client() && !world.isInvalidMap()){
updateSectors();
checkGameOver();
}
}

View File

@ -66,8 +66,6 @@ public class UI implements ApplicationListener{
public LocalPlayerDialog localplayers;
public UnlocksDialog unlocks;
public ContentInfoDialog content;
public SectorsDialog sectors;
public MissionDialog missions;
public Cursor drillCursor, unloadCursor;
@ -177,8 +175,6 @@ public class UI implements ApplicationListener{
maps = new MapsDialog();
localplayers = new LocalPlayerDialog();
content = new ContentInfoDialog();
sectors = new SectorsDialog();
missions = new MissionDialog();
Group group = Core.scene.root;

View File

@ -4,13 +4,11 @@ import io.anuke.arc.ApplicationListener;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.entities.EntityQuery;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Structs;
import io.anuke.arc.util.Time;
import io.anuke.arc.util.Tmp;
import io.anuke.mindustry.ai.BlockIndexer;
import io.anuke.mindustry.ai.Pathfinder;
@ -21,8 +19,9 @@ import io.anuke.mindustry.game.EventType.TileChangeEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.maps.generation.WorldGenerator;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.maps.Maps;
import io.anuke.mindustry.maps.WorldGenerator;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
@ -32,14 +31,12 @@ import static io.anuke.mindustry.Vars.*;
public class World implements ApplicationListener{
public final Maps maps = new Maps();
public final Sectors sectors = new Sectors();
public final WorldGenerator generator = new WorldGenerator();
public final BlockIndexer indexer = new BlockIndexer();
public final WaveSpawner spawner = new WaveSpawner();
public final Pathfinder pathfinder = new Pathfinder();
private Map currentMap;
private Sector currentSector;
private Tile[][] tiles;
private Array<Tile> tempTiles = new Array<>();
@ -49,11 +46,6 @@ public class World implements ApplicationListener{
maps.load();
}
@Override
public void init(){
sectors.load();
}
@Override
public void dispose(){
maps.dispose();
@ -88,14 +80,6 @@ public class World implements ApplicationListener{
return currentMap;
}
public Sector getSector(){
return currentSector;
}
public void setSector(Sector currentSector){
this.currentSector = currentSector;
}
public void setMap(Map map){
this.currentMap = map;
}
@ -208,34 +192,7 @@ public class World implements ApplicationListener{
return generating;
}
/**Loads up a sector map. This does not call play(), but calls reset().*/
public void loadSector(Sector sector){
currentSector = sector;
state.difficulty = sectors.getDifficulty(sector);
state.mode = sector.currentMission().getMode();
Time.mark();
Time.mark();
logic.reset();
beginMapLoad();
int width = sectorSize, height = sectorSize;
Tile[][] tiles = createTiles(width, height);
Map map = new Map("Sector " + sector.x + ", " + sector.y, new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null);
setMap(map);
EntityQuery.resizeTree(0, 0, width * tilesize, height * tilesize);
generator.generateMap(tiles, sector);
endMapLoad();
}
public void loadMap(Map map){
currentSector = null;
beginMapLoad();
this.currentMap = map;

View File

@ -26,10 +26,6 @@ public class OverlayRenderer{
for(Player player : players){
InputHandler input = control.input(player.playerIndex);
if(world.getSector() != null){
world.getSector().currentMission().drawOverlay();
}
if(!input.isDrawing() || player.isDead()) continue;
Shaders.outline.color.set(Palette.accent);

View File

@ -92,12 +92,7 @@ public abstract class SaveFileVersion{
short width = stream.readShort();
short height = stream.readShort();
if(world.getSector() != null){
world.setMap(new Map("Sector " + world.getSector().x + ", " + world.getSector().y, width, height));
}else if(world.getMap() == null){
world.setMap(new Map("unknown", width, height));
}
world.setMap(new Map("unknown", width, height));
world.beginMapLoad();
Tile[][] tiles = world.createTiles(width, height);

View File

@ -24,7 +24,6 @@ public class Save16 extends SaveFileVersion{
stream.readLong(); //time
stream.readLong(); //total playtime
stream.readInt(); //build
int sector = stream.readInt(); //sector ID
//general state
byte mode = stream.readByte();
@ -32,8 +31,6 @@ public class Save16 extends SaveFileVersion{
Map map = world.maps.getByName(mapname);
world.setMap(map);
world.setSector(world.sectors.get(sector));
int wave = stream.readInt();
byte difficulty = stream.readByte();
float wavetime = stream.readFloat();
@ -59,7 +56,6 @@ public class Save16 extends SaveFileVersion{
stream.writeLong(Time.millis()); //last saved
stream.writeLong(headless ? 0 : control.saves.getTotalPlaytime()); //playtime
stream.writeInt(Version.build); //build
stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().pos()); //sector ID
//--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode

View File

@ -1,73 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.annotations.Annotations.Serialize;
import io.anuke.arc.collection.Array;
import io.anuke.arc.graphics.Texture;
import io.anuke.arc.util.Pack;
import io.anuke.mindustry.game.Saves.SaveSlot;
import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.maps.missions.*;
import io.anuke.mindustry.type.ItemStack;
import static io.anuke.mindustry.Vars.control;
import static io.anuke.mindustry.Vars.headless;
@Serialize
public class Sector{
private static final Mission victoryMission = new VictoryMission();
/**Position on the map, can be positive or negative.*/
public short x, y;
/**Whether this sector has already been completed.*/
public boolean complete;
/**Slot ID of this sector's save. -1 means no save has been created.*/
public int saveID = -1;
/**Num of missions in this sector that have been completed so far.*/
public int completedMissions;
/**Display texture. Needs to be disposed.*/
public transient Texture texture;
/**Missions of this sector-- what needs to be accomplished to unlock it.*/
public transient Array<Mission> missions = new Array<>();
/**Enemies spawned at this sector.*/
public transient Array<SpawnGroup> spawns;
/**Difficulty of the sector, measured by calculating distance from origin and applying scaling.*/
public transient int difficulty;
/**Items the player starts with on this sector.*/
public transient Array<ItemStack> startingItems;
public Mission getDominantMission(){
for(Mission mission : missions){
if(mission instanceof WaveMission || mission instanceof BattleMission){
return mission;
}
}
for(Mission mission : missions){
if(mission instanceof BlockMission){
return mission;
}
}
return missions.first();
}
public Mission currentMission(){
return completedMissions >= missions.size ? victoryMission : missions.get(completedMissions);
}
public int getSeed(){
return pos();
}
public SaveSlot getSave(){
return !hasSave() ? null : control.saves.getByID(saveID);
}
public boolean hasSave(){
return !headless && control.saves.getByID(saveID) != null;
}
public int pos(){
return Pack.shortInt(x, y);
}
}

View File

@ -1,91 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.GridMap;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.content.blocks.CraftingBlocks;
import io.anuke.mindustry.content.blocks.ProductionBlocks;
import io.anuke.mindustry.content.blocks.UnitBlocks;
import io.anuke.mindustry.content.blocks.UpgradeBlocks;
import io.anuke.mindustry.entities.units.UnitCommand;
import io.anuke.mindustry.maps.missions.*;
import io.anuke.mindustry.type.Item;
import static io.anuke.mindustry.Vars.mobile;
public class SectorPresets{
private final GridMap<SectorPreset> presets = new GridMap<>();
private final GridMap<Array<Item>> orePresets = new GridMap<>();
public SectorPresets(){
//base tutorial mission
add(new SectorPreset(0, 0,
TutorialSector.getMissions(),
Array.with(Items.copper, Items.coal, Items.lead)));
//command center mission
add(new SectorPreset(0, 1,
Array.ofRecursive(
Missions.blockRecipe(UnitBlocks.daggerFactory),
new UnitMission(UnitTypes.dagger),
Missions.blockRecipe(UnitBlocks.commandCenter),
new CommandMission(UnitCommand.retreat),
new CommandMission(UnitCommand.attack),
new BattleMission()
),
Array.with(Items.copper, Items.lead, Items.coal)));
//pad mission
add(new SectorPreset(0, -2,
Array.ofRecursive(
Missions.blockRecipe(mobile ? UpgradeBlocks.alphaPad : UpgradeBlocks.dartPad),
new MechMission(mobile ? Mechs.alpha : Mechs.dart),
new WaveMission(15)
),
Array.with(Items.copper, Items.lead, Items.coal, Items.titanium)));
//oil mission
add(new SectorPreset(-2, 0,
Array.ofRecursive(
Missions.blockRecipe(ProductionBlocks.cultivator),
Missions.blockRecipe(ProductionBlocks.waterExtractor),
new ContentMission(Items.biomatter),
Missions.blockRecipe(CraftingBlocks.biomatterCompressor),
new ContentMission(Liquids.oil),
new BattleMission()
),
Array.with(Items.copper, Items.lead, Items.coal, Items.titanium)));
}
public Array<Item> getOres(int x, int y){
return orePresets.get(x, y);
}
public SectorPreset get(int x, int y){
return presets.get(x, y);
}
public GridMap<SectorPreset> getPresets() { return presets; }
private void add(SectorPreset preset){
presets.put(preset.x, preset.y, preset);
orePresets.put(preset.x, preset.y, preset.ores);
}
public static class SectorPreset{
public final Array<Mission> missions;
public final Array<Item> ores;
public final int x, y;
public SectorPreset(int x, int y, Array<Mission> missions, Array<Item> ores){
this.missions = missions;
this.x = x;
this.y = y;
this.ores = ores;
}
}
}

View File

@ -1,323 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.Array.ArrayIterable;
import io.anuke.arc.collection.GridMap;
import io.anuke.arc.graphics.Pixmap;
import io.anuke.arc.graphics.Pixmap.Format;
import io.anuke.arc.graphics.Texture;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Pack;
import io.anuke.arc.util.async.AsyncExecutor;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.maps.SectorPresets.SectorPreset;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.maps.generation.WorldGenerator.GenResult;
import io.anuke.mindustry.maps.missions.BattleMission;
import io.anuke.mindustry.maps.missions.Mission;
import io.anuke.mindustry.maps.missions.Missions;
import io.anuke.mindustry.maps.missions.WaveMission;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Recipe.RecipeVisibility;
import io.anuke.mindustry.world.ColorMapper;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.defense.Wall;
import static io.anuke.mindustry.Vars.*;
public class Sectors{
public static final int sectorImageSize = 32;
private final GridMap<Sector> grid = new GridMap<>();
private final SectorPresets presets = new SectorPresets();
private final Array<Item> allOres = Item.getAllOres();
private final AsyncExecutor executor = new AsyncExecutor(6);
public void playSector(Sector sector){
if(!headless && sector.hasSave() && SaveIO.breakingVersions.contains(sector.getSave().getBuild())){
sector.getSave().delete();
ui.showInfo("$text.save.old");
}
if(!sector.hasSave()){
for(Mission mission : sector.missions){
mission.reset();
}
world.loadSector(sector);
logic.play();
if(!headless){
sector.saveID = control.saves.addSave("sector-" + sector.pos()).index;
}
world.sectors.save();
world.setSector(sector);
if(!sector.complete) sector.currentMission().onBegin();
}else if(SaveIO.breakingVersions.contains(sector.getSave().getBuild())){
ui.showInfo("$text.save.old");
}else try{
sector.getSave().load();
world.setSector(sector);
state.set(State.playing);
if(!sector.complete) sector.currentMission().onBegin();
}catch(Exception e){
Log.err(e);
sector.getSave().delete();
playSector(sector);
if(!headless){
ui.showError("$text.sector.corrupted");
}
}
}
/**If a sector is not yet unlocked, returns null.*/
public Sector get(int x, int y){
return grid.get(x, y);
}
public Sector get(int position){
return grid.get(Pack.leftShort(position), Pack.rightShort(position));
}
public Iterable<Sector> getSectors(){
return grid.values();
}
public Difficulty getDifficulty(Sector sector){
if(sector.difficulty == 0){
return Difficulty.hard;
}else if(sector.difficulty < 4){
return Difficulty.normal;
}else if(sector.difficulty < 9){
return Difficulty.hard;
}else{
return Difficulty.insane;
}
}
public Array<Item> getOres(int x, int y){
return presets.getOres(x, y) == null ? allOres : presets.getOres(x, y);
}
/**Unlocks a sector. This shows nearby sectors.*/
public void completeSector(int x, int y){
createSector(x, y);
Sector sector = get(x, y);
sector.complete = true;
for(Point2 g : Geometry.d4){
createSector(x + g.x, y + g.y);
}
}
/**Creates a sector at a location if it is not present, but does not complete it.*/
public void createSector(int x, int y){
if(grid.containsKey(x, y)) return;
Sector sector = new Sector();
sector.x = (short)x;
sector.y = (short)y;
sector.complete = false;
initSector(sector);
grid.put(sector.x, sector.y, sector);
if(sector.texture == null){
createTexture(sector);
}
if(sector.missions.size == 0){
completeSector(sector.x, sector.y);
}
}
public void abandonSector(Sector sector){
if(sector.hasSave()){
sector.getSave().delete();
}
sector.completedMissions = 0;
sector.complete = false;
initSector(sector);
grid.put(sector.x, sector.y, sector);
createTexture(sector);
save();
}
@SuppressWarnings("unchecked")
public void load(){
for(Sector sector : grid.values()){
sector.texture.dispose();
}
grid.clear();
Array<Sector> out = Core.settings.getObject("sector-data-2", Array.class, Array::new);
for(Sector sector : out){
createTexture(sector);
initSector(sector);
grid.put(sector.x, sector.y, sector);
}
if(out.size == 0){
createSector(0, 0);
}
}
public void clear(){
grid.clear();
save();
createSector(0, 0);
}
public void save(){
Array<Sector> out = new Array<>();
for(Sector sector : grid.values()){
if(sector != null && !out.contains(sector, true)){
out.add(sector);
}
}
Core.settings.putObject("sector-data-2", out);
Core.settings.save();
}
private void initSector(Sector sector){
sector.difficulty = (int)(Mathf.dst(sector.x, sector.y));
if(presets.get(sector.x, sector.y) != null){
SectorPreset p = presets.get(sector.x, sector.y);
sector.missions.addAll(p.missions);
sector.x = (short)p.x;
sector.y = (short)p.y;
}else{
generate(sector);
}
sector.spawns = new Array<>();
for(Mission mission : sector.missions){
sector.spawns.addAll(mission.getWaves(sector));
}
//set starter items
if(sector.difficulty > 12){ //now with titanium
sector.startingItems = Array.with(new ItemStack(Items.copper, 1900), new ItemStack(Items.lead, 500), new ItemStack(Items.densealloy, 470), new ItemStack(Items.silicon, 460), new ItemStack(Items.titanium, 230));
}else if(sector.difficulty > 8){ //just more resources
sector.startingItems = Array.with(new ItemStack(Items.copper, 1500), new ItemStack(Items.lead, 400), new ItemStack(Items.densealloy, 340), new ItemStack(Items.silicon, 250));
}else if(sector.difficulty > 5){ //now with silicon
sector.startingItems = Array.with(new ItemStack(Items.copper, 950), new ItemStack(Items.lead, 300), new ItemStack(Items.densealloy, 190), new ItemStack(Items.silicon, 140));
}else if(sector.difficulty > 3){ //now with carbide
sector.startingItems = Array.with(new ItemStack(Items.copper, 700), new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 130));
}else if(sector.difficulty > 2){ //more starter items for faster start
sector.startingItems = Array.with(new ItemStack(Items.copper, 400), new ItemStack(Items.lead, 100));
}else{ //empty default
sector.startingItems = Array.with();
}
}
/**Generates a mission for a sector. This is deterministic and the same for each client.*/
private void generate(Sector sector){
//50% chance to get a wave mission
if(Mathf.randomSeed(sector.getSeed() + 7) < 0.5){
//recipe mission (maybe)
addRecipeMission(sector, 3);
sector.missions.add(new WaveMission(sector.difficulty*5 + Mathf.randomSeed(sector.getSeed(), 1, 4)*5));
}else{
//battle missions don't get recipes
sector.missions.add(new BattleMission());
}
//possibly add another recipe mission
addRecipeMission(sector, 11);
Generation gen = new Generation(sector, null, sectorSize, sectorSize, null);
Array<Point2> points = new Array<>();
for(Mission mission : sector.missions){
points.addAll(mission.getSpawnPoints(gen));
}
GenResult result = new GenResult();
for(Point2 point : new ArrayIterable<>(points)){
world.generator.generateTile(result, sector.x, sector.y, point.x, point.y, true, null, null);
if(((Floor)result.floor).isLiquid || result.wall.solid){
sector.missions.clear();
break;
}
}
}
private void addRecipeMission(Sector sector, int offset){
//build list of locked recipes to add mission for obtaining it
if(Mathf.randomSeed(sector.getSeed() + offset) < 0.5){
Array<Recipe> recipes = new Array<>();
for(Recipe r : content.recipes()){
if(r.result instanceof Wall || (r.visibility != RecipeVisibility.all) || r.cost < 10f) continue;
recipes.add(r);
}
float maxdiff = 8f;
recipes.sort((r1, r2) -> Float.compare(r1.cost, r2.cost));
int end = (int)(Mathf.clamp(sector.difficulty / maxdiff + 0.25f) * (recipes.size - 1));
int start = (int)(Mathf.clamp(sector.difficulty / maxdiff) * (recipes.size / 2f));
if(recipes.size > 0 && end > start){
Recipe recipe = recipes.get(Mathf.randomSeed(sector.getSeed() + 10, start, end));
sector.missions.addAll(Missions.blockRecipe(recipe.result));
}
}
}
private void createTexture(Sector sector){
if(headless) return; //obviously not created or needed on server
if(sector.texture != null){
sector.texture.dispose();
}
executor.submit(() -> {
Pixmap pixmap = new Pixmap(sectorImageSize, sectorImageSize, Format.RGBA8888);
GenResult result = new GenResult();
GenResult secResult = new GenResult();
for(int x = 0; x < pixmap.getWidth(); x++){
for(int y = 0; y < pixmap.getHeight(); y++){
int toX = x * sectorSize / sectorImageSize;
int toY = y * sectorSize / sectorImageSize;
world.generator.generateTile(result, sector.x, sector.y, toX, toY, false, null, null);
world.generator.generateTile(secResult, sector.x, sector.y, toX, ((y+1) * sectorSize / sectorImageSize), false, null, null);
int color = ColorMapper.colorFor(result.floor, result.wall, Team.none, result.elevation, secResult.elevation > result.elevation ? (byte)(1 << 6) : (byte)0);
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color);
}
}
Core.app.post(() -> {
sector.texture = new Texture(pixmap);
pixmap.dispose();
});
return null;
});
}
}

View File

@ -1,125 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.blocks.CraftingBlocks;
import io.anuke.mindustry.content.blocks.ProductionBlocks;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.content.blocks.UnitBlocks;
import io.anuke.mindustry.maps.missions.BlockMission;
import io.anuke.mindustry.maps.missions.ItemMission;
import io.anuke.mindustry.maps.missions.Mission;
import io.anuke.mindustry.maps.missions.WaveMission;
import io.anuke.mindustry.world.Block;
import static io.anuke.mindustry.Vars.*;
/**Just a class for returning the list of tutorial missions.*/
public class TutorialSector{
private static int droneIndex;
public static Array<Mission> getMissions(){
/*
Array<Mission> missions = Array.with(
new ItemMission(Items.copper, 60).setMessage("$tutorial.begin"),
new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.drill"),
new BlockMission(DistributionBlocks.conveyor).setShowComplete(false).setMessage("$tutorial.conveyor"),
new ItemMission(Items.copper, 100).setMessage("$tutorial.morecopper"),
new BlockMission(TurretBlocks.duo).setMessage("$tutorial.turret"),
/
//new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.drillturret"),
// Create a wave mission which spawns the core at 60, 60 rather than in the center of the map
new WaveMission(2, 60, 60).setMessage("$tutorial.waves"),
new ItemMission(Items.lead, 150).setMessage("$tutorial.lead"),
new ItemMission(Items.copper, 250).setMessage("$tutorial.morecopper"),
new BlockMission(CraftingBlocks.smelter).setMessage("$tutorial.smelter"),
//drills for smelter
new BlockMission(ProductionBlocks.mechanicalDrill),
new BlockMission(ProductionBlocks.mechanicalDrill),
new BlockMission(ProductionBlocks.mechanicalDrill),
new ItemMission(Items.densealloy, 20).setMessage("$tutorial.densealloy"),
new MarkerBlockMission(CraftingBlocks.siliconsmelter).setMessage("$tutorial.siliconsmelter"),
//coal line
new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.silicondrill"),
//sand line
new BlockMission(ProductionBlocks.mechanicalDrill),
new BlockMission(ProductionBlocks.mechanicalDrill),
new BlockMission(PowerBlocks.combustionGenerator).setMessage("$tutorial.generator"),
new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.generatordrill"),
new BlockMission(PowerBlocks.powerNode).setMessage("$tutorial.node"),
//TODO fix positions
new ConditionMission(Core.bundle.get("text.mission.linknode"), () -> world.tile(54, 52).entity != null && world.tile(54, 52).entity.power != null && world.tile(54, 52).entity.power.amount >= 0.01f)
.setMessage("$tutorial.nodelink"),
new ItemMission(Items.silicon, 70).setMessage("$tutorial.silicon"),
new BlockMission(UnitBlocks.daggerFactory).setMessage("$tutorial.daggerfactory"),
//power for dagger factory
new BlockMission(PowerBlocks.powerNode),
new BlockMission(PowerBlocks.powerNode),
new UnitMission(UnitTypes.dagger).setMessage("$tutorial.dagger"),
new ActionMission(TutorialSector::generateBase),
new BattleMission(){
public void generate(Generation gen){} //no
}.setMessage("$tutorial.battle")
);
//find drone marker mission
for(int i = 0; i < missions.size; i++){
if(missions.get(i) instanceof MarkerBlockMission){
droneIndex = i;
break;
}
}*/
return Array.with(
//intentionally unlocalized
new ItemMission(Items.copper, 50).setMessage("An updated tutorial will return next build.\nFor now, you'll have to deal with... this."),
new BlockMission(ProductionBlocks.mechanicalDrill),
new ItemMission(Items.copper, 100),
new ItemMission(Items.lead, 50),
new BlockMission(CraftingBlocks.smelter),
new ItemMission(Items.densealloy, 10),
new WaveMission(5)
);
}
public static boolean supressDrone(){
return world.getSector() != null && world.getSector().x == 0 && world.getSector().y == 0 && world.getSector().completedMissions < droneIndex;
}
private static void generateBase(){
int x = sectorSize - 50, y = sectorSize - 50;
world.setBlock(world.tile(x, y), StorageBlocks.core, waveTeam);
world.setBlock(world.tile(x - 1, y + 2), UnitBlocks.daggerFactory, waveTeam);
world.setBlock(world.tile(x - 1, y - 3), UnitBlocks.daggerFactory, waveTeam);
//since placed() is not called here, add core manually
state.teams.get(waveTeam).cores.add(world.tile(x, y));
}
private static class MarkerBlockMission extends BlockMission{
public MarkerBlockMission(Block block){
super(block);
}
}
}

View File

@ -1,4 +1,4 @@
package io.anuke.mindustry.maps.generation;
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.IntArray;
@ -15,11 +15,7 @@ import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.blocks.OreBlocks;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.maps.MapTileData;
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.missions.Mission;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
@ -141,7 +137,6 @@ public class WorldGenerator{
public void playRandomMap(){
ui.loadLogic(() -> {
world.setSector(null);
logic.reset();
int sx = (short)Mathf.range(Short.MAX_VALUE/2);
@ -246,57 +241,6 @@ public class WorldGenerator{
}
}
public void generateMap(Tile[][] tiles, Sector sector){
int width = tiles.length, height = tiles[0].length;
RandomXS128 rnd = new RandomXS128(sector.getSeed());
Generation gena = new Generation(sector, tiles, tiles.length, tiles[0].length, rnd);
Array<Point2> spawnpoints = sector.currentMission().getSpawnPoints(gena);
Array<Item> ores = world.sectors.getOres(sector.x, sector.y);
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
GenResult result = generateTile(this.result, sector.x, sector.y, x, y, true, spawnpoints, ores);
Tile tile = new Tile(x, y, result.floor.id, result.wall.id, (byte)0, (byte)0, result.elevation);
tiles[x][y] = tile;
}
}
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = tiles[x][y];
byte elevation = tile.getElevation();
for(Point2 point : Geometry.d4){
if(!Structs.inBounds(x + point.x, y + point.y, width, height)) continue;
if(tiles[x + point.x][y + point.y].getElevation() < elevation){
if(sim2.octaveNoise2D(1, 1, 1.0 / 8, x, y) > 0.8){
tile.setElevation(-1);
}
break;
}
}
}
}
for(int x = 0; x < tiles.length; x++){
for(int y = 0; y < tiles[0].length; y++){
Tile tile = tiles[x][y];
tile.updateOcclusion();
}
}
Generation gen = new Generation(sector, tiles, tiles.length, tiles[0].length, random);
for(Mission mission : sector.missions){
mission.generate(gen);
}
prepareTiles(tiles);
}
public GenResult generateTile(int sectorX, int sectorY, int localX, int localY){
return generateTile(sectorX, sectorY, localX, localY, true);
}

View File

@ -1,219 +0,0 @@
package io.anuke.mindustry.maps.generation;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.IntIntMap;
import io.anuke.arc.function.BiFunction;
import io.anuke.arc.function.IntPositionConsumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.function.TriFunction;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.math.geom.Point2;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.content.blocks.*;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Edges;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.PowerBlock;
import io.anuke.mindustry.world.blocks.defense.Door;
import io.anuke.mindustry.world.blocks.defense.ForceProjector;
import io.anuke.mindustry.world.blocks.defense.MendProjector;
import io.anuke.mindustry.world.blocks.defense.Wall;
import io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret;
import io.anuke.mindustry.world.blocks.defense.turrets.LiquidTurret;
import io.anuke.mindustry.world.blocks.defense.turrets.PowerTurret;
import io.anuke.mindustry.world.blocks.defense.turrets.Turret;
import io.anuke.mindustry.world.blocks.power.NuclearReactor;
import io.anuke.mindustry.world.blocks.power.PowerGenerator;
import io.anuke.mindustry.world.blocks.power.SolarGenerator;
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
import io.anuke.mindustry.world.blocks.storage.StorageBlock;
import io.anuke.mindustry.world.blocks.units.UnitFactory;
import static io.anuke.mindustry.Vars.content;
public class FortressGenerator{
private final static int coreDst = 60;
private int enemyX, enemyY, coreX, coreY;
private Team team;
private Generation gen;
public void generate(Generation gen, Team team, int coreX, int coreY, int enemyX, int enemyY){
this.enemyX = enemyX;
this.enemyY = enemyY;
this.coreX = coreX;
this.coreY = coreY;
this.gen = gen;
this.team = team;
gen();
}
void gen(){
gen.setBlock(enemyX, enemyY, StorageBlocks.core, team);
gen.random.nextBoolean();
float difficultyScl = Mathf.clamp(gen.sector.difficulty / 20f + gen.random.range(0.25f), 0f, 0.9999f);
float dscl2 = Mathf.clamp(0.5f + gen.sector.difficulty / 20f + gen.random.range(0.1f), 0f, 1.5f);
Array<Block> turrets = find(b -> b instanceof ItemTurret);
Array<Block> powerTurrets = find(b -> b instanceof PowerTurret);
Array<Block> walls = find(b -> b instanceof Wall && !(b instanceof Door) && b.size == 1);
Block wall = walls.get((int)(difficultyScl * walls.size));
Turret powerTurret = (Turret) powerTurrets.get((int)(difficultyScl * powerTurrets.size));
Turret bigTurret = (Turret) turrets.get(Mathf.clamp((int)((difficultyScl+0.2f+gen.random.range(0.2f)) * turrets.size), 0, turrets.size-1));
Turret turret1 = (Turret) turrets.get(Mathf.clamp((int)((difficultyScl+gen.random.range(0.2f)) * turrets.size), 0, turrets.size-1));
Turret turret2 = (Turret) turrets.get(Mathf.clamp((int)((difficultyScl+gen.random.range(0.2f)) * turrets.size), 0, turrets.size-1));
float placeChance = difficultyScl*0.75f+0.25f;
IntIntMap ammoPerType = new IntIntMap();
for(Block turret : turrets){
if(!(turret instanceof ItemTurret)) continue;
ItemTurret t = (ItemTurret)turret;
int size = t.getAmmoTypes().length;
ammoPerType.put(t.id, Mathf.clamp((int)(size* difficultyScl) + gen.random.range(1), 0, size - 1));
}
TriFunction<Tile, Block, Predicate<Tile>, Boolean> checker = (current, block, pred) -> {
for(Point2 point : Edges.getEdges(block.size)){
Tile tile = gen.tile(current.x + point.x, current.y + point.y);
if(tile != null){
tile = tile.target();
if(tile.getTeamID() == team.ordinal() && pred.test(tile)){
return true;
}
}
}
return false;
};
BiFunction<Block, Predicate<Tile>, IntPositionConsumer> seeder = (block, pred) -> (x, y) -> {
if(gen.canPlace(x, y, block) && ((block instanceof Wall && block.size == 1) || gen.random.chance(placeChance)) && checker.get(gen.tile(x, y), block, pred)){
gen.setBlock(x, y, block, team);
}
};
BiFunction<Block, Float, IntPositionConsumer> placer = (block, chance) -> (x, y) -> {
if(gen.canPlace(x, y, block) && gen.random.chance(chance)){
gen.setBlock(x, y, block, team);
}
};
Array<IntPositionConsumer> passes = Array.with(
//initial seeding solar panels
placer.get(PowerBlocks.largeSolarPanel, 0.001f),
//extra seeding
seeder.get(PowerBlocks.solarPanel, tile -> tile.block() == PowerBlocks.largeSolarPanel && gen.random.chance(0.3)),
//coal gens
seeder.get(PowerBlocks.combustionGenerator, tile -> tile.block() instanceof SolarGenerator && gen.random.chance(0.2)),
//water extractors
seeder.get(ProductionBlocks.waterExtractor, tile -> tile.block() instanceof NuclearReactor && gen.random.chance(0.5)),
//mend projectors
seeder.get(DefenseBlocks.mendProjector, tile -> tile.block() instanceof PowerGenerator && gen.random.chance(0.04)),
//power turrets
seeder.get(powerTurret, tile -> tile.block() instanceof PowerGenerator && gen.random.chance(0.04)),
//repair point
seeder.get(UnitBlocks.repairPoint, tile -> tile.block() instanceof PowerGenerator && gen.random.chance(0.1)),
//turrets1
seeder.get(turret1, tile -> tile.block() instanceof PowerBlock && gen.random.chance(0.22 - turret1.size*0.02)),
//turrets2
seeder.get(turret2, tile -> tile.block() instanceof PowerBlock && gen.random.chance(0.12 - turret2.size*0.02)),
//shields
seeder.get(DefenseBlocks.forceProjector, tile -> (tile.block() instanceof CoreBlock || tile.block() instanceof UnitFactory) && gen.random.chance(0.2 * dscl2)),
//unit pads (assorted)
seeder.get(UnitBlocks.daggerFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.3 * dscl2)),
//unit pads (assorted)
seeder.get(UnitBlocks.wraithFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.3 * dscl2)),
//unit pads (assorted)
seeder.get(UnitBlocks.titanFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.23 * dscl2)),
//unit pads (assorted)
seeder.get(UnitBlocks.ghoulFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.23 * dscl2)),
//vaults
seeder.get(StorageBlocks.vault, tile -> (tile.block() instanceof CoreBlock || tile.block() instanceof ForceProjector) && gen.random.chance(0.4)),
//big turrets
seeder.get(bigTurret, tile -> tile.block() instanceof StorageBlock && gen.random.chance(0.65)),
//walls
(x, y) -> {
if(!gen.canPlace(x, y, wall)) return;
for(Point2 point : Geometry.d8){
Tile tile = gen.tile(x + point.x, y + point.y);
if(tile != null){
tile = tile.target();
if(tile.getTeamID() == team.ordinal() && !(tile.block() instanceof Wall) && !(tile.block() instanceof UnitFactory)){
gen.setBlock(x, y, wall, team);
break;
}
}
}
},
//mines
placer.get(DefenseBlocks.shockMine, 0.02f * difficultyScl),
//fill up turrets w/ ammo
(x, y) -> {
Tile tile = gen.tile(x, y);
Block block = tile.block();
if(block instanceof PowerTurret){
tile.entity.power.satisfaction = 1.0f;
}else if(block instanceof ItemTurret){
ItemTurret turret = (ItemTurret)block;
AmmoType[] type = turret.getAmmoTypes();
int index = ammoPerType.get(block.id, 0);
block.handleStack(type[index].item, block.acceptStack(type[index].item, 1000, tile, null), tile, null);
}else if(block instanceof NuclearReactor){
tile.entity.items.add(Items.thorium, 30);
}else if(block instanceof LiquidTurret){
tile.entity.liquids.add(Liquids.water, tile.block().liquidCapacity);
}
}
);
for(IntPositionConsumer i : passes){
for(int x = 0; x < gen.width; x++){
for(int y = 0; y < gen.height; y++){
if(Mathf.dst(x, y, enemyX, enemyY) > coreDst){
continue;
}
i.accept(x, y);
}
}
}
}
Array<Block> find(Predicate<Block> pred){
Array<Block> out = new Array<>();
for(Block block : content.blocks()){
if(pred.test(block) && Recipe.getByResult(block) != null){
out.add(block);
}
}
return out;
}
}

View File

@ -1,106 +0,0 @@
package io.anuke.mindustry.maps.generation;
import io.anuke.arc.math.RandomXS128;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.production.Drill;
import io.anuke.arc.util.Structs;
public class Generation{
public final Sector sector;
public final Tile[][] tiles;
public final int width, height;
public final RandomXS128 random;
public Generation(Sector sector, Tile[][] tiles, int width, int height, RandomXS128 random){
this.sector = sector;
this.tiles = tiles;
this.width = width;
this.height = height;
this.random = random;
}
Tile tile(int x, int y){
if(!Structs.inBounds(x, y, tiles)){
return null;
}
return tiles[x][y];
}
Item drillItem(int x, int y, Drill block){
if(block.isMultiblock()){
Item result = null;
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!Structs.inBounds(worldx, worldy, tiles)){
return null;
}
if(!block.isValid(tiles[worldx][worldy]) || tiles[worldx][worldy].floor().drops == null) continue;
Item drop = tiles[worldx][worldy].floor().drops.item;
if(result == null || drop.id < result.id){
result = drop;
}
}
}
return result;
}else{
return tiles[x][y].floor().drops == null ? null : tiles[x][y].floor().drops.item;
}
}
public boolean canPlace(int x, int y, Block block){
if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!Structs.inBounds(worldx, worldy, tiles) || !tiles[worldx][worldy].block().alwaysReplace || tiles[worldx][worldy].floor().isLiquid){
return false;
}
}
}
return true;
}else{
return tiles[x][y].block().alwaysReplace && !tiles[x][y].floor().isLiquid;
}
}
public void setBlock(int x, int y, Block block, Team team){
tiles[x][y].setBlock(block, team);
if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!(worldx == x && worldy == y) && Structs.inBounds(worldx, worldy, tiles)){
Tile toplace = tiles[worldx][worldy];
if(toplace != null){
toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety));
toplace.setTeam(team);
}
}
}
}
}
}
}

View File

@ -1,30 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
/**A mission which simply runs a single action and is completed instantly.*/
public class ActionMission extends Mission{
protected Runnable runner;
public ActionMission(Runnable runner){
this.runner = runner;
}
public ActionMission(){
}
@Override
public void onComplete(){
runner.run();
}
@Override
public boolean isComplete(){
return true;
}
@Override
public String displayString(){
return Core.bundle.get("text.loading");
}
}

View File

@ -1,78 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.math.geom.Point2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.generation.FortressGenerator;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.defaultTeam;
import static io.anuke.mindustry.Vars.state;
public class BattleMission extends MissionWithStartingCore{
final int spacing = 30;
public static final int defaultXCorePos = 50;
public static final int defaultYCorePos = 50;
/** Creates a battle mission with the player core being at (@defaultXCorePos, @defaultYCorePos) */
public BattleMission(){
this(defaultXCorePos, defaultYCorePos);
}
/**
* Creates a wave survival with the player core being at a custom location.
* @param xCorePos The X coordinate of the custom core position.
* @param yCorePos The Y coordinate of the custom core position.
*/
public BattleMission(int xCorePos, int yCorePos){
super(xCorePos, yCorePos);
}
@Override
public String getIcon(){
return "icon-mission-battle";
}
@Override
public GameMode getMode(){
return GameMode.attack;
}
@Override
public String displayString(){
return Core.bundle.get("text.mission.battle");
}
@Override
public Array<Point2> getSpawnPoints(Generation gen){
return Array.with(new Point2(50, 50), new Point2(gen.width - 1 - spacing, gen.height - 1 - spacing));
}
@Override
public void generate(Generation gen){
generateCoreAtFirstSpawnPoint(gen, defaultTeam);
if(state.teams.get(defaultTeam).cores.size == 0){
return;
}
Tile core = state.teams.get(defaultTeam).cores.first();
int enx = gen.width - 1 - spacing;
int eny = gen.height - 1 - spacing;
new FortressGenerator().generate(gen, Team.red, core.x, core.y, enx, eny);
}
@Override
public boolean isComplete(){
for(Team team : Vars.state.teams.enemiesOf(Vars.defaultTeam)){
if(Vars.state.teams.isActive(team)){
return false;
}
}
return true;
}
}

View File

@ -1,70 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.Lines;
import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.world.Block;
import static io.anuke.mindustry.Vars.*;
public class BlockLocMission extends Mission{
private final Block block;
private final int x, y, rotation;
public BlockLocMission(Block block, int x, int y, int rotation){
this.block = block;
this.x = x;
this.y = y;
this.rotation = rotation;
}
public BlockLocMission(Block block, int x, int y){
this.block = block;
this.x = x;
this.y = y;
this.rotation = 0;
}
@Override
public void drawOverlay(){
Lines.stroke(2f);
Draw.color(Palette.accentBack);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1f, block.size * tilesize/2f + 1f+ Mathf.absin(Time.time(), 6f, 2f));
Draw.color(Palette.accent);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize/2f + 1f+ Mathf.absin(Time.time(), 6f, 2f));
if(block.rotate){
Draw.colorl(0.4f);
Draw.rect(Core.atlas.find("icon-arrow"), x * tilesize + block.offset(), y * tilesize + block.offset() - 1f, rotation*90);
Draw.colorl(0.6f);
Draw.rect(Core.atlas.find("icon-arrow"), x * tilesize + block.offset(), y * tilesize + block.offset(), rotation*90);
}
float rot = players[0].angleTo(x * tilesize + block.offset(), y * tilesize + block.offset());
float len = 12f;
Draw.color(Palette.accentBack);
Draw.rect(Core.atlas.find("icon-arrow"), players[0].x + Angles.trnsx(rot, len), players[0].y + Angles.trnsy(rot, len), rot);
Draw.color(Palette.accent);
Draw.rect(Core.atlas.find("icon-arrow"), players[0].x + Angles.trnsx(rot, len), players[0].y + Angles.trnsy(rot, len) + 1f, rot);
Draw.reset();
}
@Override
public boolean isComplete(){
return world.tile(x, y).block() == block && (!block.rotate || world.tile(x,y).getRotation() == rotation);
}
@Override
public String displayString(){
return Core.bundle.format("text.mission.block", block.formalName);
}
}

View File

@ -1,12 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block;
/**A mission in which the player must place a block somewhere.*/
public class BlockMission extends ContentMission{
public BlockMission(Block block) {
super(Recipe.getByResult(block));
}
}

View File

@ -1,29 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.UnitCommand;
public class CommandMission extends Mission{
private final UnitCommand command;
public CommandMission(UnitCommand command){
this.command = command;
}
@Override
public boolean isComplete(){
for(BaseUnit unit : Vars.unitGroups[Vars.defaultTeam.ordinal()].all()){
if(unit.isCommanded() && unit.getCommand() == command){
return true;
}
}
return false;
}
@Override
public String displayString(){
return Core.bundle.format("text.mission.command", command.localized());
}
}

View File

@ -1,23 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.function.BooleanProvider;
public class ConditionMission extends Mission{
private final BooleanProvider complete;
private final String display;
public ConditionMission(String display, BooleanProvider complete){
this.complete = complete;
this.display = display;
}
@Override
public boolean isComplete(){
return complete.get();
}
@Override
public String displayString(){
return display;
}
}

View File

@ -1,35 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.mindustry.game.UnlockableContent;
public class ContentMission extends Mission {
private final UnlockableContent content;
private boolean done;
public ContentMission(UnlockableContent content) {
this.content = content;
}
@Override
public void onContentUsed(UnlockableContent content) {
if(content == this.content){
done = true;
}
}
@Override
public boolean isComplete() {
return done;
}
@Override
public void reset() {
done = false;
}
@Override
public String displayString() {
return Core.bundle.format("text.mission.create", content.localizedName());
}
}

View File

@ -1,42 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.state;
/**A mission that is completed when the player obtains items in their core.*/
public class ItemMission extends Mission{
private final Item item;
private final int amount;
public ItemMission(Item item, int amount){
this.item = item;
this.amount = amount;
}
@Override
public boolean isComplete(){
for(Tile tile : state.teams.get(Vars.defaultTeam).cores){
if(tile.entity.items.has(item, amount)){
return true;
}
}
return false;
}
@Override
public String displayString(){
TileEntity core = Vars.players[0].getClosestCore();
if(core == null) return "imminent doom";
return Core.bundle.format("text.mission.resource", item.localizedName(), core.items.get(item), amount);
}
@Override
public String menuDisplayString(){
return Core.bundle.format("text.mission.resource.menu", item.localizedName(), amount);
}
}

View File

@ -1,46 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.collection.Array;
import io.anuke.arc.math.geom.Bresenham2;
import io.anuke.arc.math.geom.Point2;
import io.anuke.mindustry.world.Block;
public class LineBlockMission extends Mission{
private Array<BlockLocMission> points = new Array<>();
private int completeIndex;
public LineBlockMission(Block block, int x1, int y1, int x2, int y2, int rotation){
Array<Point2> points = new Bresenham2().line(x1, y1, x2, y2);
for(Point2 point : points){
this.points.add(new BlockLocMission(block, point.x, point.y, rotation));
}
}
@Override
public boolean isComplete(){
while(completeIndex < points.size && points.get(completeIndex).isComplete()){
completeIndex ++;
}
return completeIndex >= points.size;
}
@Override
public void drawOverlay(){
if(completeIndex < points.size){
points.get(completeIndex).drawOverlay();
}
}
@Override
public void reset(){
completeIndex = 0;
}
@Override
public String displayString(){
if(completeIndex < points.size){
return points.get(completeIndex).displayString();
}
return points.first().displayString();
}
}

View File

@ -1,29 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.type.Mech;
public class MechMission extends Mission{
private final Mech mech;
public MechMission(Mech mech){
this.mech = mech;
}
@Override
public boolean isComplete(){
for(Player player : Vars.playerGroup.all()){
if(player.mech == mech){
return true;
}
}
return false;
}
@Override
public String displayString(){
return Core.bundle.format("text.mission.mech", mech.localizedName());
}
}

View File

@ -1,102 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.generation.Generation;
import static io.anuke.mindustry.Vars.headless;
import static io.anuke.mindustry.Vars.ui;
public abstract class Mission{
private String extraMessage;
private boolean showComplete = true;
public abstract boolean isComplete();
/**Returns the string that is displayed in-game near the menu.*/
public abstract String displayString();
/**Returns the info string displayed in the sector dialog (menu)*/
public String menuDisplayString(){
return displayString();
}
public String getIcon(){
return "icon-mission-defense";
}
public GameMode getMode(){
return GameMode.attack;
}
/**Sets the message displayed on mission begin. Returns this mission for chaining.*/
public Mission setMessage(String message){
this.extraMessage = message;
return this;
}
public Mission setShowComplete(boolean complete){
this.showComplete = complete;
return this;
}
/**Called when a specified piece of content is 'used' by a block.*/
public void onContentUsed(UnlockableContent content){
}
/**Draw mission overlay.*/
public void drawOverlay(){
}
public void update(){
}
public void reset(){
}
/**Shows the unique sector message.*/
public void showMessage(){
if(!headless && extraMessage != null){
ui.hudfrag.showTextDialog(extraMessage);
}
}
public boolean hasMessage(){
return extraMessage != null;
}
public void onBegin(){
Time.runTask(60f, this::showMessage);
}
public void onComplete(){
if(showComplete && !headless){
ui.hudfrag.showToast("[LIGHT_GRAY]"+menuDisplayString() + ":\n" + Core.bundle.get("text.mission.complete"));
}
}
public void display(Table table){
table.add(displayString());
}
public Array<SpawnGroup> getWaves(Sector sector){
return new Array<>();
}
public Array<Point2> getSpawnPoints(Generation gen){
return Array.with();
}
public void generate(Generation gen){}
}

View File

@ -1,68 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.state;
public abstract class MissionWithStartingCore extends Mission{
/** Stores a custom starting location for the core, or null if the default calculation (map center) shall be used. */
private final Point2 customStartingPoint;
/** Default constructor. Missions created this way will have a player starting core in the center of the map. */
MissionWithStartingCore(){
this.customStartingPoint = null;
}
/**
* Creates a mission with a core on a non-default location.
* @param xCorePos The x coordinate of the custom core position.
* @param yCorePos The y coordinate of the custom core position.
*/
MissionWithStartingCore(int xCorePos, int yCorePos){
this.customStartingPoint = new Point2(xCorePos, yCorePos);
}
/**
* Generates a player core based on generation parameters.
* @param gen The generation parameters which provide the map size.
* @param team The team to generate the core for.
*/
public void generateCoreAtFirstSpawnPoint(Generation gen, Team team){
Array<Point2> spawnPoints = getSpawnPoints(gen);
if(spawnPoints == null || spawnPoints.size == 0){
throw new IllegalArgumentException("A MissionWithStartingCore subclass did not provide a spawn point in getSpawnPoints(). However, at least one point must always be provided.");
}
Tile startingCoreTile = gen.tiles[spawnPoints.first().x][spawnPoints.first().y];
startingCoreTile.setBlock(StorageBlocks.core);
startingCoreTile.setTeam(team);
state.teams.get(team).cores.add(startingCoreTile);
//makes sure there's a flat area around core
for(int dx = -2; dx <= 2; dx++){
for(int dy = -2; dy <= 2; dy++){
gen.tiles[startingCoreTile.x + dx][startingCoreTile.y + dy].setElevation(startingCoreTile.getElevation());
}
}
}
/**
* Retrieves the spawn point in the center of the map or at a custom location which was provided through the constructor.
* @param gen The generation parameters which provide the map size.
* @return The center of the map or a custom location.
* @implNote Must return an array with at least one entry.
*/
@Override
public Array<Point2> getSpawnPoints(Generation gen){
if(this.customStartingPoint == null){
return Array.with(new Point2(gen.width / 2, gen.height / 2));
}else{
return Array.with(this.customStartingPoint);
}
}
}

View File

@ -1,22 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block;
public class Missions{
/**Returns an array of missions to obtain the items needed to make this block.
* This array includes a mission to place this block.*/
public static Array<Mission> blockRecipe(Block block){
Recipe recipe = Recipe.getByResult(block);
Array<Mission> out = new Array<>();
for(ItemStack stack : recipe.requirements){
out.add(new ItemMission(stack.item, stack.amount));
}
out.add(new BlockMission(block));
return out;
}
}

View File

@ -1,29 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.UnitType;
public class UnitMission extends Mission{
private final UnitType type;
public UnitMission(UnitType type){
this.type = type;
}
@Override
public boolean isComplete(){
for(BaseUnit unit : Vars.unitGroups[Vars.defaultTeam.ordinal()].all()){
if(unit.getType() == type){
return true;
}
}
return false;
}
@Override
public String displayString(){
return Core.bundle.format("text.mission.unit", type.localizedName());
}
}

View File

@ -1,26 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.mindustry.game.GameMode;
import io.anuke.arc.scene.ui.layout.Table;
public class VictoryMission extends Mission{
@Override
public boolean isComplete(){
return false;
}
@Override
public String displayString(){
return "none";
}
@Override
public GameMode getMode(){
return GameMode.victory;
}
@Override
public void display(Table table){
}
}

View File

@ -1,85 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Waves;
import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.generation.Generation;
import static io.anuke.mindustry.Vars.*;
public class WaveMission extends MissionWithStartingCore{
private final int target;
/**
* Creates a wave survival mission with the player core being in the center of the map.
* @param target The number of waves to be survived.
*/
public WaveMission(int target){
super();
this.target = target;
}
/**
* Creates a wave survival with the player core being at a custom location.
* @param target The number of waves to be survived.
* @param xCorePos The X coordinate of the custom core position.
* @param yCorePos The Y coordinate of the custom core position.
*/
public WaveMission(int target, int xCorePos, int yCorePos){
super(xCorePos, yCorePos);
this.target = target;
}
@Override
public Array<SpawnGroup> getWaves(Sector sector){
return Waves.getSpawns();
}
@Override
public void generate(Generation gen){
generateCoreAtFirstSpawnPoint(gen, Team.blue);
}
@Override
public void onBegin(){
super.onBegin();
world.pathfinder.activateTeamPath(waveTeam);
}
@Override
public GameMode getMode(){
return GameMode.waves;
}
@Override
public String displayString(){
return state.wave > target ?
Core.bundle.format(
state.enemies() > 1 ?
"text.mission.wave.enemies" :
"text.mission.wave.enemy", target, target, state.enemies()) :
Core.bundle.format("text.mission.wave", state.wave, target, (int)(state.wavetime/60));
}
@Override
public String menuDisplayString(){
return Core.bundle.format("text.mission.wave.menu", target);
}
@Override
public void update(){
if(state.wave > target){
state.mode = GameMode.attack;
}
}
@Override
public boolean isComplete(){
return state.wave > target && state.enemies() == 0;
}
}

View File

@ -32,8 +32,6 @@ public class NetworkIO{
//--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode
stream.writeUTF(world.getMap().name); //map name
stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().pos()); //sector ID
stream.writeInt(world.getSector() == null ? 0 : world.getSector().completedMissions);
//write tags
ObjectMap<String, String> tags = world.getMap().meta.tags;
@ -126,16 +124,6 @@ public class NetworkIO{
//general state
byte mode = stream.readByte();
String map = stream.readUTF();
int sector = stream.readInt();
int missions = stream.readInt();
if(sector != invalidSector){
world.sectors.createSector(Pack.leftShort(sector), Pack.rightShort(sector));
world.setSector(world.sectors.get(sector));
world.getSector().completedMissions = missions;
}else{
world.setSector(null);
}
ObjectMap<String, String> tags = new ObjectMap<>();

View File

@ -14,7 +14,7 @@ public class Packets{
public enum KickReason{
kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick,
nameInUse, idInUse, nameEmpty, customClient, sectorComplete, serverClose;
nameInUse, idInUse, nameEmpty, customClient, serverClose;
public final boolean quiet;

View File

@ -15,7 +15,7 @@ import io.anuke.arc.scene.event.InputListener;
import io.anuke.arc.util.async.AsyncExecutor;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.generation.WorldGenerator.GenResult;
import io.anuke.mindustry.maps.WorldGenerator.GenResult;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.ColorMapper;

View File

@ -1,29 +0,0 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.maps.Sector;
public class MissionDialog extends FloatingDialog{
public MissionDialog(){
super("$text.mission.complete");
setFillParent(false);
}
public void show(Sector sector){
buttons().clear();
content().clear();
buttons().addButton("$text.nextmission", () -> {
hide();
Vars.ui.paused.runExitSave();
Vars.ui.sectors.show();
}).size(190f, 64f);
buttons().addButton("$text.continue", this::hide).size(190f, 64f);
content().add(Core.bundle.format("text.mission.complete.body", sector.x, sector.y)).pad(10);
show();
}
}

View File

@ -31,10 +31,6 @@ public class PausedDialog extends FloatingDialog{
void rebuild(){
missionTable.clear();
missionTable.background((Drawable) null);
if(world.getSector() != null){
missionTable.background("underline");
missionTable.add(Core.bundle.format("text.sector", world.getSector().x + ", " + world.getSector().y));
}
}
void setup(){
@ -58,7 +54,7 @@ public class PausedDialog extends FloatingDialog{
content().addButton("$text.settings", ui.settings::show);
content().row();
content().addButton("$text.savegame", save::show).disabled(s -> world.getSector() != null);
content().addButton("$text.savegame", save::show);
content().addButton("$text.loadgame", load::show).disabled(b -> Net.active());
content().row();
@ -79,11 +75,9 @@ public class PausedDialog extends FloatingDialog{
content().defaults().size(120f).pad(5);
float isize = 14f * 4;
content().addRowImageTextButton("$text.back", "icon-play-2", isize, () -> {
hide();
});
content().addRowImageTextButton("$text.back", "icon-play-2", isize, this::hide);
content().addRowImageTextButton("$text.settings", "icon-tools", isize, ui.settings::show);
content().addRowImageTextButton("$text.save", "icon-save", isize, save::show).disabled(b -> world.getSector() != null);
content().addRowImageTextButton("$text.save", "icon-save", isize, save::show);
content().row();

View File

@ -3,7 +3,6 @@ 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.maps.Sector;
import static io.anuke.mindustry.Vars.*;
@ -34,7 +33,7 @@ public class RestartDialog extends FloatingDialog{
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}else if(world.getSector() == null){
}else{
if(control.isHighScore()){
content().add("$text.highscore").pad(6);
content().row();
@ -46,19 +45,6 @@ public class RestartDialog extends FloatingDialog{
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
}else{
content().add("$text.sector.gameover");
buttons().addButton("$text.menu", () -> {
hide();
state.set(State.menu);
logic.reset();
}).size(130f, 60f);
buttons().addButton("$text.sector.retry", () -> {
Sector sector = world.getSector();
ui.loadLogic(() -> world.sectors.playSector(sector));
hide();
}).size(130f, 60f);
}
}
}

View File

@ -1,271 +0,0 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.input.KeyCode;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.scene.Element;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.event.InputEvent;
import io.anuke.arc.scene.event.InputListener;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.ui.layout.Cell;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.util.Align;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.maps.Sector;
import static io.anuke.mindustry.Vars.world;
public class SectorsDialog extends FloatingDialog{
private static final float sectorSize = Unit.dp.scl(32*5);
private Sector selected;
private Table table;
private SectorView view;
public SectorsDialog(){
super("");
table = new Table(){
@Override
public float getPrefWidth(){
return sectorSize*2f;
}
};
table.visible(() -> selected != null);
table.update(() -> {
if(selected != null){
int offsetX = (int)(view.panX / sectorSize);
int offsetY = (int)(view.panY / sectorSize);
float drawX = x + width/2f+ selected.x * (sectorSize-2) - offsetX * sectorSize - view.panX % sectorSize + sectorSize/2f;
float drawY = y + height/2f + selected.y * (sectorSize-2) - offsetY * sectorSize - view.panY % sectorSize + sectorSize/2f;
table.setPosition(drawX, drawY - sectorSize/2f + 1, Align.top);
}
});
Group container = new Group();
container.touchable(Touchable.childrenOnly);
container.addChild(table);
margin(0);
getTitleTable().clear();
clear();
stack(content(), container, buttons()).grow();
shown(this::setup);
}
void setup(){
selected = null;
table.clear();
content().clear();
buttons().clear();
buttons().bottom().margin(15);
addCloseButton();
content().add(view = new SectorView()).grow();
}
void selectSector(Sector sector){
selected = sector;
table.clear();
table.background("button").margin(5);
table.defaults().pad(3);
table.add(Core.bundle.format("text.sector", sector.x + ", " + sector.y));
table.row();
if(selected.completedMissions < selected.missions.size && !selected.complete){
table.labelWrap(Core.bundle.format("text.mission", selected.getDominantMission().menuDisplayString())).growX();
table.row();
}
if(selected.hasSave()){
table.labelWrap(Core.bundle.format("text.sector.time", selected.getSave().getPlayTime())).growX();
table.row();
}
table.table(t -> {
Cell<?> cell = t.addImageTextButton(sector.hasSave() ? "$text.sector.resume" : "$text.sector.deploy", "icon-play", 10*3, () -> {
hide();
Vars.ui.loadLogic(() -> world.sectors.playSector(selected));
}).height(60f);
if(selected.hasSave()){
t.addImageTextButton("$text.sector.abandon", "icon-cancel", 16 * 2, () ->
Vars.ui.showConfirm("$text.confirm", "$text.sector.abandon.confirm", () -> {
world.sectors.abandonSector(selected);
// Simulate a sector selection so the buttons get updated.
selectSector(selected);
})
).width(sectorSize / Unit.dp.scl(1f)).height(60f);
cell.width(sectorSize / Unit.dp.scl(1f));
}else{
cell.width(sectorSize*2f / Unit.dp.scl(1f));
}
}).pad(-5).growX().padTop(0);
table.pack();
table.act(Core.graphics.getDeltaTime());
}
public Sector getSelected(){
return selected;
}
class SectorView extends Element{
float lastX, lastY;
boolean clicked = false;
float panX = sectorSize/2f, panY = sectorSize/2f;
SectorView(){
addListener(new InputListener(){
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
if(pointer != 0) return false;
//Cursors.setHand();
lastX = x;
lastY = y;
return true;
}
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer){
if(pointer != 0) return;
panX -= x - lastX;
panY -= y - lastY;
lastX = x;
lastY = y;
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
if(pointer != 0) return;
//Cursors.restoreCursor();
}
});
clicked(() -> clicked = true);
this.focus();
}
private void focus(){
Sector focusSector = null;
long newestTimestamp = 0;
for(Sector sector : world.sectors.getSectors()){
if(sector.hasSave()){
long timestamp = sector.getSave().getTimestamp();
if(timestamp > newestTimestamp){
focusSector = sector;
newestTimestamp = timestamp;
}
}
}
if(focusSector != null) {
panX = (focusSector.x + 0.5f) * sectorSize;
panY = (focusSector.y + 0.5f) * sectorSize;
}
}
@Override
public void draw(){
Draw.alpha(parentAlpha);
int shownSectorsX = (int)(width/sectorSize);
int shownSectorsY = (int)(height/sectorSize);
int offsetX = (int)(panX / sectorSize);
int offsetY = (int)(panY / sectorSize);
Vector2 mouse = Core.input.mouse();
for(int x = -shownSectorsX; x <= shownSectorsX; x++){
for(int y = -shownSectorsY; y <= shownSectorsY; y++){
int sectorX = offsetX + x;
int sectorY = offsetY + y;
float drawX = x + width/2f+ sectorX * (sectorSize-2) - offsetX * sectorSize - panX % sectorSize + sectorSize/2f;
float drawY = y + height/2f + sectorY * (sectorSize-2) - offsetY * sectorSize - panY % sectorSize + sectorSize/2f;
Sector sector = world.sectors.get(sectorX, sectorY);
if(sector == null || sector.texture == null){
Draw.reset();
Draw.rect(("empty-sector"), drawX, drawY, sectorSize, sectorSize);
int i = 0;
for(Point2 point : Geometry.d4){
Sector other = world.sectors.get(sectorX + point.x, sectorY + point.y);
if(other != null){
Draw.rect(("sector-edge"), drawX, drawY, sectorSize, sectorSize, i*90);
}
i ++;
}
continue;
}
Draw.colorl(!sector.complete ? 0.3f : 1f);
Draw.rect(Draw.wrap(sector.texture), drawX, drawY, sectorSize, sectorSize);
if(sector.missions.size == 0) continue;
String region = sector.getDominantMission().getIcon();
if(sector.complete){
region = "icon-mission-done";
}
Color iconColor = Color.WHITE;
Color backColor = Color.BLACK;
Color selectColor = Color.CLEAR;
if(sector == selected){
selectColor = Palette.accent;
}else if(mouse.x > drawX - sectorSize / 2f && mouse.y > drawY - sectorSize / 2f
&& mouse.x < drawX + sectorSize / 2f && mouse.y < drawY + sectorSize / 2f){
if(clicked){
selectSector(sector);
}
selectColor = Color.WHITE;
}else if(sector.hasSave()){
iconColor = Palette.command;
}else{
iconColor = Color.GRAY;
}
if(sector.complete){
iconColor = backColor = Color.CLEAR;
}
Draw.color(selectColor);
Draw.rect(("sector-select"), drawX, drawY, sectorSize, sectorSize);
Draw.color(backColor);
Draw.alpha(0.75f * backColor.a);
Draw.rect(("icon-mission-background"), drawX, drawY, Unit.dp.scl(18f * 5), Unit.dp.scl(18f * 5));
float size = Unit.dp.scl(10f * 5);
Draw.color(iconColor);
Draw.rect((region), drawX, drawY, size, size);
}
}
Draw.reset();
clicked = false;
}
}
}

View File

@ -143,13 +143,6 @@ public class SettingsMenuDialog extends SettingsDialog{
dialog.setFillParent(false);
dialog.content().defaults().size(230f, 60f).pad(3);
dialog.addCloseButton();
dialog.content().addButton("$text.settings.clearsectors", () -> {
ui.showConfirm("$text.confirm", "$text.settings.clear.confirm", () -> {
world.sectors.clear();
dialog.hide();
});
});
dialog.content().row();
dialog.content().addButton("$text.settings.clearunlocks", () -> {
ui.showConfirm("$text.confirm", "$text.settings.clear.confirm", () -> {
control.unlocks.reset();

View File

@ -31,7 +31,6 @@ import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.ui.IntFormat;
import io.anuke.mindustry.ui.Minimap;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import static io.anuke.mindustry.Vars.*;
@ -370,7 +369,6 @@ public class HudFragment extends Fragment{
table.touchable(Touchable.enabled);
table.labelWrap(() ->
world.getSector() == null ?
(state.enemies() > 0 && state.mode.disableWaveTimer ?
wavef.get(state.wave) + "\n" + (state.enemies() == 1 ?
enemyf.get(state.enemies()) :
@ -378,17 +376,11 @@ public class HudFragment extends Fragment{
wavef.get(state.wave) + "\n" +
(!state.mode.disableWaveTimer ?
Core.bundle.format("text.wave.waiting", (int)(state.wavetime/60)) :
Core.bundle.get("text.waiting"))) :
Core.bundle.format("text.mission.display", world.getSector().currentMission().displayString())).growX().pad(8f);
Core.bundle.get("text.waiting")))
).growX().pad(8f);
table.clicked(() -> {
if(world.getSector() != null && world.getSector().currentMission().hasMessage()){
world.getSector().currentMission().showMessage();
}
});
table.setDisabled(() -> !(world.getSector() != null && world.getSector().currentMission().hasMessage()));
table.visible(() -> !((world.getSector() == null && state.mode.disableWaves) || !state.mode.showMission || (world.getSector() != null && world.getSector().complete)));
table.setDisabled(true);
table.visible(() -> !(state.mode.disableWaves || !state.mode.showMission));
}
private void addPlayButton(Table table){

View File

@ -148,7 +148,7 @@ public class MenuFragment extends Fragment{
dialog.content().add(new MenuButton("icon-play-2", "$text.sectors", () -> {
dialog.hide();
ui.sectors.show();
ui.showInfo("aaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa");
})).width(bw).colspan(2);
dialog.content().row();

View File

@ -23,7 +23,6 @@ import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.maps.TutorialSector;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
@ -206,7 +205,7 @@ public class CoreBlock extends StorageBlock{
}
}
if(!found && !TutorialSector.supressDrone()){
if(!found){
BaseUnit unit = droneType.create(tile.getTeam());
unit.setSpawner(tile);
unit.setDead(true);

View File

@ -48,7 +48,6 @@ public class ServerControl implements ApplicationListener{
private final FileHandle logFolder = Core.files.local("logs/");
private FileHandle currentLogFile;
private int gameOvers;
private boolean inExtraRound;
private Task lastTask;
@ -58,8 +57,6 @@ public class ServerControl implements ApplicationListener{
"shufflemode", "normal",
"bans", "",
"admins", "",
"sector_x", 2,
"sector_y", 1,
"shuffle", true,
"crashreport", false,
"port", port,
@ -128,57 +125,31 @@ public class ServerControl implements ApplicationListener{
warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lc-Pbuildversion=&lm<build>&ly.");
}
Events.on(SectorCompleteEvent.class, event -> {
info("Sector complete.");
world.sectors.completeSector(world.getSector().x, world.getSector().y);
world.sectors.save();
gameOvers = 0;
inExtraRound = true;
Core.settings.put("sector_x", world.getSector().x + 1);
Core.settings.save();
Call.onInfoMessage("[accent]Sector conquered![]\n" + roundExtraTime + " seconds until deployment in next sector.");
playSectorMap();
});
Events.on(GameOverEvent.class, event -> {
if(inExtraRound) return;
info("Game over!");
if(Core.settings.getBool("shuffle")){
if(world.getSector() == null){
if(world.maps.all().size > 0){
Array<Map> maps = world.maps.customMaps().size == 0 ? world.maps.defaultMaps() : world.maps.customMaps();
if(world.maps.all().size > 0){
Array<Map> maps = world.maps.customMaps().size == 0 ? world.maps.defaultMaps() : world.maps.customMaps();
Map previous = world.getMap();
Map map = previous;
if(maps.size > 1){
while(map == previous) map = maps.random();
}
Call.onInfoMessage((state.mode.isPvp
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
+ "\nNext selected map:[accent] "+map.name+"[]"
+ (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+
"\nNew game begins in " + roundExtraTime + " seconds.");
info("Selected next map to be {0}.", map.name);
Map fmap = map;
play(true, () -> world.loadMap(fmap));
Map previous = world.getMap();
Map map = previous;
if(maps.size > 1){
while(map == previous) map = maps.random();
}
}else{
Call.onInfoMessage("[SCARLET]Sector has been lost.[]\nRe-deploying in " + roundExtraTime + " seconds.");
if(gameOvers >= 2){
Core.settings.put("sector_y", Core.settings.getInt("sector_y") < 0 ? Core.settings.getInt("sector_y") + 1 : Core.settings.getInt("sector_y") - 1);
Core.settings.save();
gameOvers = 0;
}
gameOvers ++;
playSectorMap();
info("Re-trying sector map: {0} {1}", Core.settings.getInt("sector_x"), Core.settings.getInt("sector_y"));
Call.onInfoMessage((state.mode.isPvp
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
+ "\nNext selected map:[accent] "+map.name+"[]"
+ (map.meta.author() != null ? " by[accent] " + map.meta.author() + "[]" : "") + "."+
"\nNew game begins in " + roundExtraTime + " seconds.");
info("Selected next map to be {0}.", map.name);
Map fmap = map;
play(true, () -> world.loadMap(fmap));
}
}else{
netServer.kickAll(KickReason.gameover);
@ -259,8 +230,8 @@ public class ServerControl implements ApplicationListener{
logic.play();
}else{
info("&fiNo map specified. Loading sector {0}, {1}.", Core.settings.getInt("sector_x"), Core.settings.getInt("sector_y"));
playSectorMap(false);
//TODO
info("TODO play generated map");
}
info("Map loaded.");
@ -337,17 +308,6 @@ public class ServerControl implements ApplicationListener{
}
});
handler.register("setsector", "<x> <y>", "Sets the next sector to be played. Does not affect current game.", arg -> {
try{
Core.settings.put("sector_x", Integer.parseInt(arg[0]));
Core.settings.put("sector_y", Integer.parseInt(arg[1]));
Core.settings.save();
info("Sector position set.");
}catch(NumberFormatException e){
err("Invalid coordinates.");
}
});
handler.register("fillitems", "[team]", "Fill the core with 2000 items.", arg -> {
if(!state.is(State.playing)){
err("Not playing. Host first.");
@ -705,21 +665,6 @@ public class ServerControl implements ApplicationListener{
}
}
private void playSectorMap(){
playSectorMap(true);
}
private void playSectorMap(boolean wait){
int x = Core.settings.getInt("sector_x"), y = Core.settings.getInt("sector_y");
if(world.sectors.get(x, y) == null){
world.sectors.createSector(x, y);
}
world.sectors.get(x, y).completedMissions = 0;
play(wait, () -> world.loadSector(world.sectors.get(x, y)));
}
private void play(boolean wait, Runnable run){
inExtraRound = true;
Runnable r = () -> {

View File

@ -101,12 +101,6 @@ public class ApplicationTests{
assertTrue(content.getContentMap().length > 0);
}
@Test
void loadSector(){
world.sectors.createSector(0, 0);
world.sectors.playSector(world.sectors.get(0, 0));
}
@Test
void playMap(){
assertTrue(world.maps.all().size > 0);

View File

@ -1,54 +0,0 @@
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.ContentLoader;
import io.anuke.mindustry.maps.SectorPresets;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.maps.missions.Mission;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** This class is responsible for testing predefined sectors. */
public class SectorTests{
private SectorPresets presets;
private Generation fakeGen;
@BeforeAll
static void initializeDependencies(){
Vars.content = new ContentLoader();
Vars.content.load();
}
@BeforeEach
void initTest(){
this.presets = new SectorPresets();
// Fake away the Generation dependency
this.fakeGen = new Generation(null, null, 250, 250, null);
}
/** Returns true if at least one mission provides a spawn point. */
private boolean spawnPointIsDefined(Array<Mission> missions){
for(Mission mission : missions){
if(mission.getSpawnPoints(this.fakeGen).size > 0){
return true;
}
}
// No spawn point provided
return false;
}
/**
* Makes sure that every predefined sector has a position for the player core defined.
* This is achieved by adding at least one mission which defines a spawn point.
*/
@Test
void sectorHasACore(){
for(SectorPresets.SectorPreset preset : this.presets.getPresets().values()){
assertTrue(spawnPointIsDefined(preset.missions), "Sector at (" + preset.x + "|" + preset.y + ") contains no missions which define a spawn point. Add a battle or wave mission.");
}
}
}