Merge branch 'unsector'

# Conflicts:
#	core/src/io/anuke/mindustry/maps/SectorPresets.java
#	core/src/io/anuke/mindustry/maps/Sectors.java
#	core/src/io/anuke/mindustry/maps/TutorialSector.java
#	core/src/io/anuke/mindustry/maps/generation/FortressGenerator.java
#	core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java
#	core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java
This commit is contained in:
Anuken
2019-01-08 22:28:13 -05:00
53 changed files with 68 additions and 2445 deletions

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,84 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.GridMap;
import io.anuke.mindustry.content.*;
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(Blocks.daggerFactory),
new UnitMission(UnitTypes.dagger),
//Missions.blockRecipe(Blocks.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 ? Blocks.alphaPad : Blocks.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(Blocks.cultivator),
Missions.blockRecipe(Blocks.waterExtractor),
new ContentMission(Items.biomatter),
Missions.blockRecipe(Blocks.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.graphite, 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.graphite, 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.graphite, 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.graphite, 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,122 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.content.Items;
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(Blocks.mechanicalDrill),
new ItemMission(Items.copper, 100),
new ItemMission(Items.lead, 50),
// new BlockMission(CraftingBlocks.smelter),
//new BlockMission(Blocks.smelter),
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), Blocks.core, waveTeam);
world.setBlock(world.tile(x - 1, y + 2), Blocks.daggerFactory, waveTeam);
world.setBlock(world.tile(x - 1, y - 3), Blocks.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;
@@ -13,11 +13,7 @@ import io.anuke.arc.util.noise.Simplex;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Blocks;
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;
@@ -139,13 +135,12 @@ public class WorldGenerator{
public void playRandomMap(){
ui.loadLogic(() -> {
world.setSector(null);
logic.reset();
int sx = (short)Mathf.range(Short.MAX_VALUE/2);
int sy = (short)Mathf.range(Short.MAX_VALUE/2);
int width = 380;
int height = 380;
int width = 512;
int height = 512;
Array<Point2> spawns = new Array<>();
Array<Item> ores = Item.getAllOres();
@@ -244,57 +239,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,221 +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.Blocks;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Liquids;
import io.anuke.mindustry.game.Team;
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, Blocks.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();
//todo implement
/*
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(Blocks.largeSolarPanel, 0.001f),
//extra seeding
seeder.get(Blocks.solarPanel, tile -> tile.block() == Blocks.largeSolarPanel && gen.random.chance(0.3)),
//coal gens
seeder.get(Blocks.combustionGenerator, tile -> tile.block() instanceof SolarGenerator && gen.random.chance(0.2)),
//water extractors
seeder.get(Blocks.waterExtractor, tile -> tile.block() instanceof NuclearReactor && gen.random.chance(0.5)),
//mend projectors
seeder.get(Blocks.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(Blocks.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(Blocks.forceProjector, tile -> (tile.block() instanceof CoreBlock || tile.block() instanceof UnitFactory) && gen.random.chance(0.2 * dscl2)),
//unit pads (assorted)
seeder.get(Blocks.daggerFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.3 * dscl2)),
//unit pads (assorted)
seeder.get(Blocks.wraithFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.3 * dscl2)),
//unit pads (assorted)
seeder.get(Blocks.titanFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.23 * dscl2)),
//unit pads (assorted)
seeder.get(Blocks.ghoulFactory, tile -> (tile.block() instanceof MendProjector || tile.block() instanceof ForceProjector) && gen.random.chance(0.23 * dscl2)),
//vaults
seeder.get(Blocks.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(Blocks.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;
//todo implement
/*}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;
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(Blocks.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;
}
}