mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-02-25 22:17:59 +07:00
Many campaign changes
This commit is contained in:
parent
d110fe5ea3
commit
bdbc8ab6d2
@ -266,11 +266,23 @@ public class Control implements ApplicationListener, Loadable{
|
||||
ui.planet.hide();
|
||||
SaveSlot slot = sector.save;
|
||||
if(slot != null && !clearSectors){
|
||||
|
||||
try{
|
||||
net.reset();
|
||||
slot.load();
|
||||
state.rules.sector = sector;
|
||||
|
||||
//if there is no base, simulate a new game and place the right loadout at the spawn position
|
||||
if(state.rules.defaultTeam.cores().isEmpty()){
|
||||
Tile spawn = world.tile(sector.getSpawnPosition());
|
||||
//TODO PLACE CORRECT LOADOUT
|
||||
Schematics.placeLoadout(Loadouts.advancedShard, spawn.x, spawn.y);
|
||||
|
||||
Events.fire(Trigger.newGame);
|
||||
}
|
||||
|
||||
state.set(State.playing);
|
||||
|
||||
}catch(SaveException e){
|
||||
Log.err(e);
|
||||
sector.save = null;
|
||||
|
@ -11,6 +11,7 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.maps.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.type.Weather.*;
|
||||
import mindustry.world.*;
|
||||
@ -94,6 +95,22 @@ public class Logic implements ApplicationListener{
|
||||
});
|
||||
|
||||
Events.on(LaunchItemEvent.class, e -> state.stats.handleItemExport(e.stack));
|
||||
|
||||
//when loading a 'damaged' sector, propagate the damage
|
||||
Events.on(WorldLoadEvent.class, e -> {
|
||||
if(state.isCampaign() && state.rules.sector.hasWaves() && state.rules.sector.getTurnsPassed() > 0){
|
||||
SectorDamage.apply(state.rules.sector.getTurnsPassed());
|
||||
state.rules.sector.setTurnsPassed(0);
|
||||
}
|
||||
});
|
||||
|
||||
//TODO this should be in the same place as launch handling code
|
||||
Events.on(GameOverEvent.class, e -> {
|
||||
//simulate a turn on a normal non-launch gameover
|
||||
if(state.isCampaign() && !state.launched){
|
||||
universe.runTurn();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles the event of content being used by either the player or some block. */
|
||||
@ -204,6 +221,7 @@ public class Logic implements ApplicationListener{
|
||||
ui.hudfrag.showLaunch();
|
||||
}
|
||||
|
||||
//TODO core launch effect
|
||||
for(Tilec tile : state.teams.playerCores()){
|
||||
Fx.launch.at(tile);
|
||||
}
|
||||
@ -213,6 +231,9 @@ public class Logic implements ApplicationListener{
|
||||
//state.getSector().setLaunched();
|
||||
}
|
||||
|
||||
Sector sector = state.rules.sector;
|
||||
|
||||
//TODO what about containers, do they get launched too?
|
||||
Time.runTask(30f, () -> {
|
||||
for(Tilec entity : state.teams.playerCores()){
|
||||
for(Item item : content.items()){
|
||||
@ -223,6 +244,16 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
state.launched = true;
|
||||
state.gameOver = true;
|
||||
|
||||
//save over the data w/o the cores
|
||||
sector.save.save();
|
||||
//TODO mark sector as not containing any cores
|
||||
|
||||
//run a turn, since launching takes up a turn
|
||||
universe.runTurn();
|
||||
//TODO needs extra damage to prevent player from landing immediately afterwards
|
||||
sector.setTurnsPassed(sector.getTurnsPassed() + 1);
|
||||
|
||||
Events.fire(new LaunchEvent());
|
||||
//manually fire game over event now
|
||||
Events.fire(new GameOverEvent(state.rules.defaultTeam));
|
||||
|
@ -215,6 +215,10 @@ public class World{
|
||||
|
||||
int size = sector.getSize();
|
||||
loadGenerator(size, size, tiles -> sector.planet.generator.generate(tiles, sector));
|
||||
|
||||
if(state.rules.defaultTeam.core() != null){
|
||||
sector.setSpawnPosition(state.rules.defaultTeam.core().pos());
|
||||
}
|
||||
}
|
||||
|
||||
private void setSectorRules(Sector sector){
|
||||
|
@ -34,7 +34,7 @@ public class Damage{
|
||||
}
|
||||
|
||||
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){
|
||||
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, -1f, Mathf.random(360f), 1, 1));
|
||||
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1));
|
||||
}
|
||||
|
||||
int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30);
|
||||
|
@ -55,9 +55,7 @@ public class Universe{
|
||||
turnCounter += Time.delta();
|
||||
|
||||
if(turnCounter >= turnDuration){
|
||||
turn ++;
|
||||
turnCounter = 0;
|
||||
onTurn();
|
||||
runTurn();
|
||||
}
|
||||
|
||||
if(state.hasSector()){
|
||||
@ -78,7 +76,7 @@ public class Universe{
|
||||
for(Sector sector : planet.sectors){
|
||||
|
||||
//ignore the current sector if the player is in it right now
|
||||
if(sector.hasSave() && (state.isMenu() || sector != state.rules.sector)){
|
||||
if(sector.hasSave() && !sector.isBeingPlayed()){
|
||||
SaveMeta meta = sector.save.meta;
|
||||
|
||||
for(Entry<Item> entry : meta.exportRates){
|
||||
@ -94,8 +92,28 @@ public class Universe{
|
||||
return exports;
|
||||
}
|
||||
|
||||
private void onTurn(){
|
||||
//TODO run waves on hostile sectors, damage them
|
||||
public void runTurns(int amount){
|
||||
for(int i = 0; i < amount; i++){
|
||||
runTurn();
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs a turn once. Resets turn counter. */
|
||||
public void runTurn(){
|
||||
turn ++;
|
||||
turnCounter = 0;
|
||||
|
||||
//TODO EVENTS
|
||||
|
||||
//increment turns passed for sectors with waves
|
||||
//TODO a turn passing may break the core; detect this, send an event and mark the sector as having no base!
|
||||
for(Planet planet : content.planets()){
|
||||
for(Sector sector : planet.sectors){
|
||||
if(!sector.isBeingPlayed() && sector.hasSave() && sector.hasWaves()){
|
||||
sector.setTurnsPassed(sector.getTurnsPassed() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//calculate passive item generation
|
||||
int[] exports = getTotalExports();
|
||||
|
@ -83,7 +83,8 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
"width", world.width(),
|
||||
"height", world.height(),
|
||||
"viewpos", Tmp.v1.set(player == null ? Vec2.ZERO : player).toString(),
|
||||
"controlledType", headless || control.input.controlledType == null ? "null" : control.input.controlledType.name
|
||||
"controlledType", headless || control.input.controlledType == null ? "null" : control.input.controlledType.name,
|
||||
"nocores", state.rules.defaultTeam.cores().isEmpty()
|
||||
).merge(tags));
|
||||
}
|
||||
|
||||
|
82
core/src/mindustry/maps/SectorDamage.java
Normal file
82
core/src/mindustry/maps/SectorDamage.java
Normal file
@ -0,0 +1,82 @@
|
||||
package mindustry.maps;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class SectorDamage{
|
||||
//direct damage is for testing only
|
||||
private static final boolean direct = false;
|
||||
|
||||
//TODO amount of damage could be related to wave spacing
|
||||
public static void apply(float turns){
|
||||
Tiles tiles = world.tiles;
|
||||
|
||||
Queue<Tile> frontier = new Queue<>();
|
||||
float[][] values = new float[tiles.width][tiles.height];
|
||||
float damage = turns*50;
|
||||
|
||||
//phase one: find all spawnpoints
|
||||
for(Tile tile : tiles){
|
||||
if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){
|
||||
frontier.add(tile);
|
||||
values[tile.x][tile.y] = damage;
|
||||
}
|
||||
}
|
||||
|
||||
float falloff = (damage) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2);
|
||||
int peak = 0;
|
||||
|
||||
//phase two: propagate the damage
|
||||
while(!frontier.isEmpty()){
|
||||
peak = Math.max(peak, frontier.size);
|
||||
Tile tile = frontier.removeFirst();
|
||||
float currDamage = values[tile.x][tile.y] - falloff;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
int cx = tile.x + Geometry.d4x[i], cy = tile.y + Geometry.d4y[i];
|
||||
|
||||
//propagate to new tiles
|
||||
if(tiles.in(cx, cy) && values[cx][cy] < currDamage){
|
||||
Tile other = tiles.getn(cx, cy);
|
||||
float resultDamage = currDamage;
|
||||
|
||||
//damage the tile if it's not friendly
|
||||
if(other.entity != null && other.team() != state.rules.waveTeam){
|
||||
resultDamage -= other.entity.health();
|
||||
|
||||
if(direct){
|
||||
other.entity.damage(currDamage);
|
||||
}else{ //indirect damage happens at game load time
|
||||
other.entity.health(other.entity.health() - currDamage);
|
||||
|
||||
//remove the block when destroyed
|
||||
if(other.entity.health() < 0){
|
||||
if(!other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){
|
||||
Effects.rubble(other.entity.x(), other.entity.y(), other.block().size);
|
||||
}
|
||||
|
||||
other.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}else if(other.solid() && !other.synthetic()){ //skip damage propagation through solid blocks
|
||||
continue;
|
||||
}
|
||||
|
||||
if(resultDamage > 0 && values[cx][cy] < resultDamage){
|
||||
frontier.addLast(other);
|
||||
values[cx][cy] = resultDamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package mindustry.maps.generators;
|
||||
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.*;
|
||||
@ -9,10 +10,40 @@ import mindustry.world.*;
|
||||
public class BaseGenerator{
|
||||
|
||||
public void generate(Tiles tiles, Array<Tile> cores, Tile spawn, Team team, Sector sector){
|
||||
//algorithm idea: make it spawn prefab turret setups and route resources to them with conveyors from chunks of ore drill setups
|
||||
|
||||
GridBits used = new GridBits(tiles.width, tiles.height);
|
||||
Queue<Tile> frontier = new Queue<>();
|
||||
for(Tile tile : cores){
|
||||
frontier.add(tile);
|
||||
}
|
||||
|
||||
int count = 2000;
|
||||
int total = 0;
|
||||
|
||||
while(total++ < count){
|
||||
Tile tile = frontier.removeFirst();
|
||||
for(int i = 0; i < 4; i++){
|
||||
int cx = tile.x + Geometry.d4x[i], cy = tile.y + Geometry.d4y[i];
|
||||
if(tiles.in(cx, cy) && !used.get(cx, cy)){
|
||||
Tile other = tiles.getn(cx, cy);
|
||||
|
||||
if(!other.solid()){
|
||||
frontier.addLast(other);
|
||||
}
|
||||
used.set(cx, cy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Tile tile : frontier){
|
||||
tile.setBlock(Blocks.copperWall, team);
|
||||
}
|
||||
|
||||
for(Tile tile : cores){
|
||||
tile.clearOverlay();
|
||||
tile.setBlock(Blocks.coreShard, team);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,9 +260,10 @@ public class TODOPlanetGenerator extends PlanetGenerator{
|
||||
}
|
||||
});
|
||||
|
||||
//TODO PLACE CORRECT LOADOUT
|
||||
Schematics.placeLoadout(Loadouts.advancedShard, spawn.x, spawn.y);
|
||||
|
||||
if(sector.hostility > 0.02f){
|
||||
if(sector.hasEnemyBase()){
|
||||
new BaseGenerator().generate(tiles, enemies.map(r -> tiles.getn(r.x, r.y)), tiles.get(spawn.x, spawn.y), state.rules.waveTeam, sector);
|
||||
|
||||
state.rules.attackMode = true;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
@ -11,6 +12,8 @@ import mindustry.game.Saves.*;
|
||||
import mindustry.graphics.g3d.PlanetGrid.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.world;
|
||||
|
||||
/** A small section of a planet. */
|
||||
public class Sector{
|
||||
public final SectorRect rect;
|
||||
@ -24,7 +27,7 @@ public class Sector{
|
||||
public @Nullable SaveSlot save;
|
||||
public boolean unlocked;
|
||||
|
||||
/** */
|
||||
/** Sector enemy hostility from 0 to 1 */
|
||||
public float hostility;
|
||||
|
||||
//TODO implement a dynamic (?) launch period
|
||||
@ -39,13 +42,33 @@ public class Sector{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/** @return whether the player has a base here. */
|
||||
public boolean hasBase(){
|
||||
return save != null && !save.meta.tags.getBool("nocores");
|
||||
}
|
||||
|
||||
/** @return whether the enemy has a generated base here. */
|
||||
public boolean hasEnemyBase(){
|
||||
return hostility >= 0.02f && (save == null || save.meta.rules.waves);
|
||||
}
|
||||
|
||||
public boolean isBeingPlayed(){
|
||||
//after the launch dialog, a sector is no longer considered being played
|
||||
return Vars.state.isGame() && Vars.state.rules.sector == this && !Vars.state.launched && !Vars.state.gameOver;
|
||||
}
|
||||
|
||||
/** @return whether waves are present, e.g. any bases here will be attacked. */
|
||||
public boolean hasWaves(){
|
||||
return save != null && save.meta.rules.waves;
|
||||
}
|
||||
|
||||
public boolean hasSave(){
|
||||
return save != null;
|
||||
}
|
||||
|
||||
public void generate(){
|
||||
//TODO use simplex and a seed
|
||||
hostility = Math.max(Noise.snoise3(tile.v.x, tile.v.y, tile.v.z, 1f, 0.5f), 0);
|
||||
hostility = Math.max(Noise.snoise3(tile.v.x, tile.v.y, tile.v.z, 0.5f, 0.5f), 0);
|
||||
}
|
||||
|
||||
public boolean locked(){
|
||||
@ -74,6 +97,32 @@ public class Sector{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpawnPosition(int position){
|
||||
put("spawn-position", position);
|
||||
}
|
||||
|
||||
/** Only valid after this sector has been landed on once. */
|
||||
//TODO move to sector data?
|
||||
public int getSpawnPosition(){
|
||||
return Core.settings.getInt(key("spawn-position"), Point2.pack(world.width() / 2, world.height() / 2));
|
||||
}
|
||||
|
||||
public void setTurnsPassed(int number){
|
||||
put("turns-passed", number);
|
||||
}
|
||||
|
||||
public int getTurnsPassed(){
|
||||
return Core.settings.getInt(key("turns-passed"));
|
||||
}
|
||||
|
||||
private String key(String key){
|
||||
return planet.name + "-s-" + id + "-" + key;
|
||||
}
|
||||
|
||||
private void put(String key, Object value){
|
||||
Core.settings.put(key(key), value);
|
||||
}
|
||||
|
||||
/** Projects this sector onto a 4-corner square for use in map gen.
|
||||
* Allocates a new object. Do not call in the main loop. */
|
||||
private SectorRect makeRect(){
|
||||
|
@ -281,9 +281,9 @@ public class PlanetDialog extends FloatingDialog{
|
||||
|
||||
if(selectAlpha > 0.01f){
|
||||
float stroke = 0.026f;
|
||||
if(sec.save != null){
|
||||
if(sec.hasBase()){
|
||||
drawSelection(sec, Tmp.c1.set(Team.sharded.color).a(selectAlpha), stroke, -0.01f);
|
||||
}else if(sec.hostility >= 0.02f){
|
||||
}else if(sec.hasEnemyBase()){
|
||||
drawSelection(sec, Tmp.c1.set(Team.crux.color).a(selectAlpha), stroke, -0.02f);
|
||||
}
|
||||
}
|
||||
@ -380,6 +380,13 @@ public class PlanetDialog extends FloatingDialog{
|
||||
});
|
||||
}
|
||||
|
||||
//disaply how many turns this sector has been attacked
|
||||
if(selected.getTurnsPassed() > 0){
|
||||
stable.row();
|
||||
|
||||
stable.add("[scarlet]" + Iconc.warning + " " + selected.getTurnsPassed() + "x attacks");
|
||||
}
|
||||
|
||||
stable.row();
|
||||
|
||||
stable.button("Launch", Styles.transt, () -> {
|
||||
|
@ -1,3 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=811e22ca49b8e5ad1cffb36a74199c1bec73ee87
|
||||
archash=4f93ba3aec02c10cb016f6fb2f5a80d5d7ba49e1
|
||||
|
Loading…
Reference in New Issue
Block a user