Merge branch 'master' into patch-4
|
|
@ -10,7 +10,7 @@ script:
|
||||||
- git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
|
- git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
|
||||||
- cd ../MindustryBuilds
|
- cd ../MindustryBuilds
|
||||||
- echo ${TRAVIS_TAG}
|
- echo ${TRAVIS_TAG}
|
||||||
- if [ -n "$TRAVIS_TAG" ]; then echo versionName=5-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi
|
- if [ -n "$TRAVIS_TAG" ]; then echo versionName=6-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi
|
||||||
- git tag ${TRAVIS_BUILD_NUMBER}
|
- git tag ${TRAVIS_BUILD_NUMBER}
|
||||||
- git config --global user.name "Build Uploader"
|
- git config --global user.name "Build Uploader"
|
||||||
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi
|
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ android{
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
|
|
||||||
versionName versionNameResult
|
versionName versionNameResult
|
||||||
versionCode vcode
|
versionCode = (System.getenv("TRAVIS_BUILD_ID") != null ? System.getenv("TRAVIS_BUILD_ID").toInteger() : vcode)
|
||||||
|
|
||||||
if(project.hasProperty("release")){
|
if(project.hasProperty("release")){
|
||||||
props['androidBuildCode'] = (vcode + 1).toString()
|
props['androidBuildCode'] = (vcode + 1).toString()
|
||||||
|
|
@ -98,15 +98,20 @@ android{
|
||||||
storePassword RELEASE_STORE_PASSWORD
|
storePassword RELEASE_STORE_PASSWORD
|
||||||
keyAlias RELEASE_KEY_ALIAS
|
keyAlias RELEASE_KEY_ALIAS
|
||||||
keyPassword RELEASE_KEY_PASSWORD
|
keyPassword RELEASE_KEY_PASSWORD
|
||||||
|
}else if(System.getenv("CI") == "true"){
|
||||||
|
storeFile = file("../../bekeystore.jks")
|
||||||
|
storePassword = System.getenv("keystore_password")
|
||||||
|
keyAlias = System.getenv("keystore_alias")
|
||||||
|
keyPassword = System.getenv("keystore_alias_password")
|
||||||
}else{
|
}else{
|
||||||
println("No keystore property found. Releases will be unsigned.")
|
println("No keystore property found. Releases will be unsigned.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(project.hasProperty("RELEASE_STORE_FILE")) {
|
if(project.hasProperty("RELEASE_STORE_FILE") || System.getenv("CI") == "true"){
|
||||||
buildTypes {
|
buildTypes{
|
||||||
release {
|
release{
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
core/assets-raw/sprites/blocks/environment/cliff0.png
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff1.png
Normal file
|
After Width: | Height: | Size: 351 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff2.png
Normal file
|
After Width: | Height: | Size: 429 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff3.png
Normal file
|
After Width: | Height: | Size: 377 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff4.png
Normal file
|
After Width: | Height: | Size: 416 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff5.png
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff6.png
Normal file
|
After Width: | Height: | Size: 365 B |
BIN
core/assets-raw/sprites/blocks/environment/cliff7.png
Normal file
|
After Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 256 B After Width: | Height: | Size: 389 B |
|
Before Width: | Height: | Size: 239 B After Width: | Height: | Size: 377 B |
BIN
core/assets-raw/sprites/blocks/environment/space.png
Normal file
|
After Width: | Height: | Size: 120 B |
|
|
@ -20,7 +20,7 @@ gameover = Game Over
|
||||||
gameover.pvp = The[accent] {0}[] team is victorious!
|
gameover.pvp = The[accent] {0}[] team is victorious!
|
||||||
highscore = [accent]New highscore!
|
highscore = [accent]New highscore!
|
||||||
copied = Copied.
|
copied = Copied.
|
||||||
indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
|
indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- SFX and music are unfinished/missing\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
|
||||||
indev.notready = This part of the game isn't ready yet
|
indev.notready = This part of the game isn't ready yet
|
||||||
|
|
||||||
load.sound = Sounds
|
load.sound = Sounds
|
||||||
|
|
@ -291,6 +291,8 @@ waiting = [lightgray]Waiting...
|
||||||
waiting.players = Waiting for players...
|
waiting.players = Waiting for players...
|
||||||
wave.enemies = [lightgray]{0} Enemies Remaining
|
wave.enemies = [lightgray]{0} Enemies Remaining
|
||||||
wave.enemy = [lightgray]{0} Enemy Remaining
|
wave.enemy = [lightgray]{0} Enemy Remaining
|
||||||
|
wave.guardianwarn = Guardian approaching in [accent]{0}[] waves.
|
||||||
|
wave.guardianwarn.one = Guardian approaching in [accent]{0}[] wave.
|
||||||
loadimage = Load Image
|
loadimage = Load Image
|
||||||
saveimage = Save Image
|
saveimage = Save Image
|
||||||
unknown = Unknown
|
unknown = Unknown
|
||||||
|
|
@ -329,6 +331,7 @@ editor.generation = Generation:
|
||||||
editor.ingame = Edit In-Game
|
editor.ingame = Edit In-Game
|
||||||
editor.publish.workshop = Publish On Workshop
|
editor.publish.workshop = Publish On Workshop
|
||||||
editor.newmap = New Map
|
editor.newmap = New Map
|
||||||
|
editor.center = Center
|
||||||
workshop = Workshop
|
workshop = Workshop
|
||||||
waves.title = Waves
|
waves.title = Waves
|
||||||
waves.remove = Remove
|
waves.remove = Remove
|
||||||
|
|
@ -572,6 +575,7 @@ info.title = Info
|
||||||
error.title = [scarlet]An error has occured
|
error.title = [scarlet]An error has occured
|
||||||
error.crashtitle = An error has occured
|
error.crashtitle = An error has occured
|
||||||
unit.nobuild = [scarlet]Unit can't build
|
unit.nobuild = [scarlet]Unit can't build
|
||||||
|
lastaccessed = [lightgray]Last Accessed: {0}
|
||||||
blocks.input = Input
|
blocks.input = Input
|
||||||
blocks.output = Output
|
blocks.output = Output
|
||||||
blocks.booster = Booster
|
blocks.booster = Booster
|
||||||
|
|
@ -627,6 +631,7 @@ bar.powerbalance = Power: {0}/s
|
||||||
bar.powerstored = Stored: {0}/{1}
|
bar.powerstored = Stored: {0}/{1}
|
||||||
bar.poweramount = Power: {0}
|
bar.poweramount = Power: {0}
|
||||||
bar.poweroutput = Power Output: {0}
|
bar.poweroutput = Power Output: {0}
|
||||||
|
bar.powerlines = Connections: {0}/{1}
|
||||||
bar.items = Items: {0}
|
bar.items = Items: {0}
|
||||||
bar.capacity = Capacity: {0}
|
bar.capacity = Capacity: {0}
|
||||||
bar.unitcap = {0} {1}/{2}
|
bar.unitcap = {0} {1}/{2}
|
||||||
|
|
@ -943,6 +948,7 @@ block.cliff.name = Cliff
|
||||||
block.sand-boulder.name = Sand Boulder
|
block.sand-boulder.name = Sand Boulder
|
||||||
block.grass.name = Grass
|
block.grass.name = Grass
|
||||||
block.slag.name = Slag
|
block.slag.name = Slag
|
||||||
|
block.space.name = Space
|
||||||
block.salt.name = Salt
|
block.salt.name = Salt
|
||||||
block.salt-wall.name = Salt Wall
|
block.salt-wall.name = Salt Wall
|
||||||
block.pebbles.name = Pebbles
|
block.pebbles.name = Pebbles
|
||||||
|
|
@ -988,6 +994,7 @@ block.darksand-water.name = Dark Sand Water
|
||||||
block.char.name = Char
|
block.char.name = Char
|
||||||
block.dacite.name = Dacite
|
block.dacite.name = Dacite
|
||||||
block.dacite-wall.name = Dacite Wall
|
block.dacite-wall.name = Dacite Wall
|
||||||
|
block.dacite-boulder.name = Dacite Boulder
|
||||||
block.ice-snow.name = Ice Snow
|
block.ice-snow.name = Ice Snow
|
||||||
block.stone-wall.name = Stone Wall
|
block.stone-wall.name = Stone Wall
|
||||||
block.ice-wall.name = Ice Wall
|
block.ice-wall.name = Ice Wall
|
||||||
|
|
@ -1261,7 +1268,7 @@ block.rotary-pump.description = An advanced pump. Pumps more liquid, but require
|
||||||
block.thermal-pump.description = The ultimate pump.
|
block.thermal-pump.description = The ultimate pump.
|
||||||
block.conduit.description = Basic liquid transport block. Moves liquids forward. Used in conjunction with pumps and other conduits.
|
block.conduit.description = Basic liquid transport block. Moves liquids forward. Used in conjunction with pumps and other conduits.
|
||||||
block.pulse-conduit.description = An advanced liquid transport block. Transports liquids faster and stores more than standard conduits.
|
block.pulse-conduit.description = An advanced liquid transport block. Transports liquids faster and stores more than standard conduits.
|
||||||
block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nLeaks less.
|
block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nDoes not leak.
|
||||||
block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets.
|
block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets.
|
||||||
block.liquid-tank.description = Stores a large amount of liquids. Use for creating buffers in situations with non-constant demand of materials or as a safeguard for cooling vital blocks.
|
block.liquid-tank.description = Stores a large amount of liquids. Use for creating buffers in situations with non-constant demand of materials or as a safeguard for cooling vital blocks.
|
||||||
block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations.
|
block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations.
|
||||||
|
|
|
||||||
|
|
@ -313,3 +313,4 @@
|
||||||
63423=memory-bank|block-memory-bank-medium
|
63423=memory-bank|block-memory-bank-medium
|
||||||
63422=foreshadow|block-foreshadow-medium
|
63422=foreshadow|block-foreshadow-medium
|
||||||
63421=tsunami|block-tsunami-medium
|
63421=tsunami|block-tsunami-medium
|
||||||
|
63420=space|block-space-medium
|
||||||
|
|
|
||||||
23
core/assets/shaders/space.frag
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#define HIGHP
|
||||||
|
#define NSCALE 2700.0
|
||||||
|
#define CAMSCALE (NSCALE*5.0)
|
||||||
|
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
uniform sampler2D u_stars;
|
||||||
|
|
||||||
|
uniform vec2 u_campos;
|
||||||
|
uniform vec2 u_ccampos;
|
||||||
|
uniform vec2 u_resolution;
|
||||||
|
uniform float u_time;
|
||||||
|
|
||||||
|
varying vec2 v_texCoords;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 c = v_texCoords.xy;
|
||||||
|
vec2 coords = vec2(c.x * u_resolution.x, c.y * u_resolution.y);
|
||||||
|
|
||||||
|
vec4 color = texture2D(u_texture, c);
|
||||||
|
color.rgb = texture2D(u_stars, coords/NSCALE + vec2(-0.1, -0.1) + u_ccampos / CAMSCALE).rgb;
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 819 B After Width: | Height: | Size: 825 B |
|
Before Width: | Height: | Size: 562 KiB After Width: | Height: | Size: 562 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 326 KiB After Width: | Height: | Size: 372 KiB |
|
Before Width: | Height: | Size: 428 KiB After Width: | Height: | Size: 429 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
BIN
core/assets/sprites/space.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 354 KiB |
|
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 426 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
|
@ -85,9 +85,9 @@ public class Vars implements Loadable{
|
||||||
/** range for moving items for logic units */
|
/** range for moving items for logic units */
|
||||||
public static final float logicItemTransferRange = 45f;
|
public static final float logicItemTransferRange = 45f;
|
||||||
/** duration of time between turns in ticks */
|
/** duration of time between turns in ticks */
|
||||||
public static final float turnDuration = 20 * Time.toMinutes;
|
public static final float turnDuration = 2 * Time.toMinutes;
|
||||||
/** turns needed to destroy a sector completely */
|
/** turns needed to destroy a sector completely */
|
||||||
public static final float sectorDestructionTurns = 3f;
|
public static final float sectorDestructionTurns = 2f;
|
||||||
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
||||||
public static final float minArmorDamage = 0.1f;
|
public static final float minArmorDamage = 0.1f;
|
||||||
/** launch animation duration */
|
/** launch animation duration */
|
||||||
|
|
@ -184,7 +184,7 @@ public class Vars implements Loadable{
|
||||||
public static GameState state;
|
public static GameState state;
|
||||||
public static EntityCollisions collisions;
|
public static EntityCollisions collisions;
|
||||||
public static DefaultWaves defaultWaves;
|
public static DefaultWaves defaultWaves;
|
||||||
public static mindustry.audio.LoopControl loops;
|
public static LoopControl loops;
|
||||||
public static Platform platform = new Platform(){};
|
public static Platform platform = new Platform(){};
|
||||||
public static Mods mods;
|
public static Mods mods;
|
||||||
public static Schematics schematics;
|
public static Schematics schematics;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import mindustry.game.*;
|
||||||
import mindustry.game.Schematic.*;
|
import mindustry.game.Schematic.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
|
import mindustry.world.blocks.environment.*;
|
||||||
import mindustry.world.blocks.production.*;
|
import mindustry.world.blocks.production.*;
|
||||||
import mindustry.world.blocks.sandbox.*;
|
import mindustry.world.blocks.sandbox.*;
|
||||||
import mindustry.world.blocks.storage.*;
|
import mindustry.world.blocks.storage.*;
|
||||||
|
|
@ -19,9 +20,13 @@ import java.io.*;
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class BaseRegistry{
|
public class BaseRegistry{
|
||||||
|
/** cores, sorted by tier */
|
||||||
public Seq<BasePart> cores = new Seq<>();
|
public Seq<BasePart> cores = new Seq<>();
|
||||||
|
/** parts with no requirement */
|
||||||
public Seq<BasePart> parts = new Seq<>();
|
public Seq<BasePart> parts = new Seq<>();
|
||||||
public ObjectMap<Content, Seq<BasePart>> reqParts = new ObjectMap<>();
|
public ObjectMap<Content, Seq<BasePart>> reqParts = new ObjectMap<>();
|
||||||
|
public ObjectMap<Item, OreBlock> ores = new ObjectMap<>();
|
||||||
|
public ObjectMap<Item, Floor> oreFloors = new ObjectMap<>();
|
||||||
|
|
||||||
public Seq<BasePart> forResource(Content item){
|
public Seq<BasePart> forResource(Content item){
|
||||||
return reqParts.get(item, Seq::new);
|
return reqParts.get(item, Seq::new);
|
||||||
|
|
@ -32,6 +37,15 @@ public class BaseRegistry{
|
||||||
parts.clear();
|
parts.clear();
|
||||||
reqParts.clear();
|
reqParts.clear();
|
||||||
|
|
||||||
|
//load ore types and corresponding items
|
||||||
|
for(Block block : content.blocks()){
|
||||||
|
if(block instanceof OreBlock && block.asFloor().itemDrop != null){
|
||||||
|
ores.put(block.asFloor().itemDrop, (OreBlock)block);
|
||||||
|
}else if(block.isFloor() && block.asFloor().itemDrop != null && !oreFloors.containsKey(block.asFloor().itemDrop)){
|
||||||
|
oreFloors.put(block.asFloor().itemDrop, block.asFloor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String[] names = Core.files.internal("basepartnames").readString().split("\n");
|
String[] names = Core.files.internal("basepartnames").readString().split("\n");
|
||||||
|
|
||||||
for(String name : names){
|
for(String name : names){
|
||||||
|
|
|
||||||
|
|
@ -77,14 +77,18 @@ public class WaveSpawner{
|
||||||
|
|
||||||
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
|
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
|
||||||
if(doShockwave){
|
if(doShockwave){
|
||||||
Time.run(20f, () -> Fx.spawnShockwave.at(spawnX, spawnY, state.rules.dropZoneRadius));
|
doShockwave(spawnX, spawnY);
|
||||||
Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Time.runTask(121f, () -> spawning = false);
|
Time.runTask(121f, () -> spawning = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void doShockwave(float x, float y){
|
||||||
|
Time.run(20f, () -> Fx.spawnShockwave.at(x, y, state.rules.dropZoneRadius));
|
||||||
|
Time.run(40f, () -> Damage.damage(state.rules.waveTeam, x, y, state.rules.dropZoneRadius, 99999999f, true));
|
||||||
|
}
|
||||||
|
|
||||||
private void eachGroundSpawn(SpawnConsumer cons){
|
private void eachGroundSpawn(SpawnConsumer cons){
|
||||||
for(Tile spawn : spawns){
|
for(Tile spawn : spawns){
|
||||||
cons.accept(spawn.worldx(), spawn.worldy(), true);
|
cons.accept(spawn.worldx(), spawn.worldy(), true);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public class CircleFormation extends FormationPattern{
|
||||||
float radius = spacing / (float)Math.sin(180f / slots * Mathf.degRad);
|
float radius = spacing / (float)Math.sin(180f / slots * Mathf.degRad);
|
||||||
outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle);
|
outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle);
|
||||||
}else{
|
}else{
|
||||||
outLocation.set(0, 0, 360f * slotNumber);
|
outLocation.set(0, spacing * 1.1f, 360f * slotNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
outLocation.z += angleOffset;
|
outLocation.z += angleOffset;
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,17 @@ public class BuilderAI extends AIController{
|
||||||
@Nullable Builderc following;
|
@Nullable Builderc following;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUnit(){
|
public void updateMovement(){
|
||||||
Builderc builder = (Builderc)unit;
|
Builderc builder = (Builderc)unit;
|
||||||
|
|
||||||
if(builder.moving()){
|
if(builder.moving()){
|
||||||
builder.lookAt(builder.vel().angle());
|
builder.lookAt(builder.vel().angle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(target != null && shouldShoot()){
|
||||||
|
unit.lookAt(target);
|
||||||
|
}
|
||||||
|
|
||||||
builder.updateBuilding(true);
|
builder.updateBuilding(true);
|
||||||
|
|
||||||
if(following != null){
|
if(following != null){
|
||||||
|
|
@ -95,13 +99,29 @@ public class BuilderAI extends AIController{
|
||||||
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid.
|
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid.
|
||||||
//add build request.
|
//add build request.
|
||||||
builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
|
builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
|
||||||
|
//shift build plan to tail so next unit builds something else.
|
||||||
|
blocks.addLast(blocks.removeFirst());
|
||||||
}else{
|
}else{
|
||||||
//shift head of queue to tail, try something else next time
|
//shift head of queue to tail, try something else next time
|
||||||
blocks.removeFirst();
|
blocks.removeFirst();
|
||||||
blocks.addLast(block);
|
blocks.addLast(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AIController fallback(){
|
||||||
|
return unit.type().flying ? new FlyingAI() : new GroundAI();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useFallback(){
|
||||||
|
return state.rules.waves && unit.team == state.rules.waveTeam && !unit.team.rules().ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldShoot(){
|
||||||
|
return !((Builderc)unit).isBuilding();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ public class LogicAI extends AIController{
|
||||||
public LUnitControl control = LUnitControl.stop;
|
public LUnitControl control = LUnitControl.stop;
|
||||||
public float moveX, moveY, moveRad;
|
public float moveX, moveY, moveRad;
|
||||||
public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer;
|
public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer;
|
||||||
|
@Nullable
|
||||||
public Building controller;
|
public Building controller;
|
||||||
public BuildPlan plan = new BuildPlan();
|
public BuildPlan plan = new BuildPlan();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,33 @@ package mindustry.ai.types;
|
||||||
|
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
import mindustry.world.blocks.ConstructBlock.*;
|
import mindustry.world.blocks.ConstructBlock.*;
|
||||||
|
|
||||||
//note that repair AI doesn't attack anything even if it theoretically can
|
|
||||||
public class RepairAI extends AIController{
|
public class RepairAI extends AIController{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateMovement(){
|
protected void updateMovement(){
|
||||||
boolean shoot = false;
|
if(target instanceof Building){
|
||||||
|
boolean shoot = false;
|
||||||
if(target != null){
|
|
||||||
if(!target.within(unit, unit.type().range * 0.8f)){
|
|
||||||
moveTo(target, unit.type().range * 0.8f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target.within(unit, unit.type().range)){
|
if(target.within(unit, unit.type().range)){
|
||||||
unit.aim(target);
|
unit.aim(target);
|
||||||
shoot = true;
|
shoot = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unit.controlWeapons(shoot);
|
||||||
|
}else if(target == null){
|
||||||
|
unit.controlWeapons(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
unit.controlWeapons(shoot);
|
if(target != null){
|
||||||
|
if(!target.within(unit, unit.type().range * 0.65f)){
|
||||||
|
moveTo(target, unit.type().range * 0.65f);
|
||||||
|
}
|
||||||
|
|
||||||
|
unit.lookAt(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -30,5 +36,10 @@ public class RepairAI extends AIController{
|
||||||
target = Units.findDamagedTile(unit.team, unit.x, unit.y);
|
target = Units.findDamagedTile(unit.team, unit.x, unit.y);
|
||||||
|
|
||||||
if(target instanceof ConstructBuild) target = null;
|
if(target instanceof ConstructBuild) target = null;
|
||||||
|
|
||||||
|
if(target == null){
|
||||||
|
super.updateTargeting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import mindustry.entities.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
|
import mindustry.world.blocks.distribution.*;
|
||||||
|
import mindustry.world.blocks.liquid.*;
|
||||||
import mindustry.world.meta.*;
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
public class SuicideAI extends GroundAI{
|
public class SuicideAI extends GroundAI{
|
||||||
|
|
@ -14,7 +16,7 @@ public class SuicideAI extends GroundAI{
|
||||||
@Override
|
@Override
|
||||||
public void updateUnit(){
|
public void updateUnit(){
|
||||||
|
|
||||||
if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){
|
if(Units.invalidateTarget(target, unit.team, unit.x, unit.y, Float.MAX_VALUE)){
|
||||||
target = null;
|
target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +28,7 @@ public class SuicideAI extends GroundAI{
|
||||||
|
|
||||||
boolean rotate = false, shoot = false, moveToTarget = false;
|
boolean rotate = false, shoot = false, moveToTarget = false;
|
||||||
|
|
||||||
if(!Units.invalidateTarget(target, unit, unit.range())){
|
if(!Units.invalidateTarget(target, unit, unit.range()) && unit.hasWeapons()){
|
||||||
rotate = true;
|
rotate = true;
|
||||||
shoot = unit.within(target, unit.type().weapons.first().bullet.range() +
|
shoot = unit.within(target, unit.type().weapons.first().bullet.range() +
|
||||||
(target instanceof Building ? ((Building)target).block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f));
|
(target instanceof Building ? ((Building)target).block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f));
|
||||||
|
|
@ -35,29 +37,36 @@ public class SuicideAI extends GroundAI{
|
||||||
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
||||||
}
|
}
|
||||||
|
|
||||||
blockedByBlock = false;
|
//do not move toward walls or transport blocks
|
||||||
|
if(!(target instanceof Building build && (
|
||||||
|
build.block.group == BlockGroup.walls ||
|
||||||
|
build.block.group == BlockGroup.liquids ||
|
||||||
|
build.block.group == BlockGroup.transportation
|
||||||
|
))){
|
||||||
|
blockedByBlock = false;
|
||||||
|
|
||||||
//raycast for target
|
//raycast for target
|
||||||
boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> {
|
boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> {
|
||||||
Tile tile = Vars.world.tile(x, y);
|
Tile tile = Vars.world.tile(x, y);
|
||||||
if(tile != null && tile.build == target) return false;
|
if(tile != null && tile.build == target) return false;
|
||||||
if(tile != null && tile.build != null && tile.build.team != unit.team()){
|
if(tile != null && tile.build != null && tile.build.team != unit.team()){
|
||||||
blockedByBlock = true;
|
blockedByBlock = true;
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
return tile == null || tile.solid();
|
return tile == null || tile.solid();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//shoot when there's an enemy block in the way
|
||||||
|
if(blockedByBlock){
|
||||||
|
shoot = true;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
//shoot when there's an enemy block in the way
|
if(!blocked){
|
||||||
if(blockedByBlock){
|
moveToTarget = true;
|
||||||
shoot = true;
|
//move towards target directly
|
||||||
}
|
unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed));
|
||||||
|
}
|
||||||
if(!blocked){
|
|
||||||
moveToTarget = true;
|
|
||||||
//move towards target directly
|
|
||||||
unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -78,4 +87,10 @@ public class SuicideAI extends GroundAI{
|
||||||
|
|
||||||
unit.controlWeapons(rotate, shoot);
|
unit.controlWeapons(rotate, shoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Teamc target(float x, float y, float range, boolean air, boolean ground){
|
||||||
|
return Units.closestTarget(unit.team, x, y, range, u -> u.checkTarget(air, ground), t -> ground &&
|
||||||
|
!(t.block instanceof Conveyor || t.block instanceof Conduit)); //do not target conveyors/conduits
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class Blocks implements ContentList{
|
||||||
public static Block
|
public static Block
|
||||||
|
|
||||||
//environment
|
//environment
|
||||||
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater,
|
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space,
|
||||||
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
||||||
iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt,
|
iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt,
|
||||||
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall,
|
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall,
|
||||||
|
|
@ -216,6 +216,13 @@ public class Blocks implements ContentList{
|
||||||
lightColor = Color.orange.cpy().a(0.38f);
|
lightColor = Color.orange.cpy().a(0.38f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
space = new Floor("space"){{
|
||||||
|
cacheLayer = CacheLayer.space;
|
||||||
|
placeableOn = false;
|
||||||
|
solid = true;
|
||||||
|
variants = 0;
|
||||||
|
}};
|
||||||
|
|
||||||
stone = new Floor("stone");
|
stone = new Floor("stone");
|
||||||
|
|
||||||
craters = new Floor("craters"){{
|
craters = new Floor("craters"){{
|
||||||
|
|
@ -695,7 +702,7 @@ public class Blocks implements ContentList{
|
||||||
drawer = new DrawAnimation();
|
drawer = new DrawAnimation();
|
||||||
|
|
||||||
consumes.item(Items.sporePod, 1);
|
consumes.item(Items.sporePod, 1);
|
||||||
consumes.power(0.60f);
|
consumes.power(0.7f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
pulverizer = new GenericCrafter("pulverizer"){{
|
pulverizer = new GenericCrafter("pulverizer"){{
|
||||||
|
|
@ -720,7 +727,7 @@ public class Blocks implements ContentList{
|
||||||
hasPower = hasItems = hasLiquids = true;
|
hasPower = hasItems = hasLiquids = true;
|
||||||
|
|
||||||
consumes.liquid(Liquids.oil, 0.1f);
|
consumes.liquid(Liquids.oil, 0.1f);
|
||||||
consumes.power(0.5f);
|
consumes.power(0.7f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
incinerator = new Incinerator("incinerator"){{
|
incinerator = new Incinerator("incinerator"){{
|
||||||
|
|
@ -822,27 +829,27 @@ public class Blocks implements ContentList{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
scrapWall = new Wall("scrap-wall"){{
|
scrapWall = new Wall("scrap-wall"){{
|
||||||
requirements(Category.defense, BuildVisibility.sandboxOnly, with());
|
requirements(Category.defense, BuildVisibility.sandboxOnly, with(Items.scrap, 6));
|
||||||
health = 60 * wallHealthMultiplier;
|
health = 60 * wallHealthMultiplier;
|
||||||
variants = 5;
|
variants = 5;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
scrapWallLarge = new Wall("scrap-wall-large"){{
|
scrapWallLarge = new Wall("scrap-wall-large"){{
|
||||||
requirements(Category.defense, BuildVisibility.sandboxOnly, with());
|
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 4));
|
||||||
health = 60 * 4 * wallHealthMultiplier;
|
health = 60 * 4 * wallHealthMultiplier;
|
||||||
size = 2;
|
size = 2;
|
||||||
variants = 4;
|
variants = 4;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
scrapWallHuge = new Wall("scrap-wall-huge"){{
|
scrapWallHuge = new Wall("scrap-wall-huge"){{
|
||||||
requirements(Category.defense, BuildVisibility.sandboxOnly, with());
|
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 9));
|
||||||
health = 60 * 9 * wallHealthMultiplier;
|
health = 60 * 9 * wallHealthMultiplier;
|
||||||
size = 3;
|
size = 3;
|
||||||
variants = 3;
|
variants = 3;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
scrapWallGigantic = new Wall("scrap-wall-gigantic"){{
|
scrapWallGigantic = new Wall("scrap-wall-gigantic"){{
|
||||||
requirements(Category.defense, BuildVisibility.sandboxOnly, with());
|
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 16));
|
||||||
health = 60 * 16 * wallHealthMultiplier;
|
health = 60 * 16 * wallHealthMultiplier;
|
||||||
size = 4;
|
size = 4;
|
||||||
}};
|
}};
|
||||||
|
|
@ -987,7 +994,7 @@ public class Blocks implements ContentList{
|
||||||
|
|
||||||
router = new Router("router"){{
|
router = new Router("router"){{
|
||||||
requirements(Category.distribution, with(Items.copper, 3));
|
requirements(Category.distribution, with(Items.copper, 3));
|
||||||
buildCostMultiplier = 2f;
|
buildCostMultiplier = 4f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
distributor = new Router("distributor"){{
|
distributor = new Router("distributor"){{
|
||||||
|
|
@ -1280,7 +1287,7 @@ public class Blocks implements ContentList{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
cultivator = new Cultivator("cultivator"){{
|
cultivator = new Cultivator("cultivator"){{
|
||||||
requirements(Category.production, with(Items.copper, 10, Items.lead, 25, Items.silicon, 10));
|
requirements(Category.production, with(Items.copper, 25, Items.lead, 25, Items.silicon, 10));
|
||||||
outputItem = new ItemStack(Items.sporePod, 1);
|
outputItem = new ItemStack(Items.sporePod, 1);
|
||||||
craftTime = 140;
|
craftTime = 140;
|
||||||
size = 2;
|
size = 2;
|
||||||
|
|
@ -1288,7 +1295,7 @@ public class Blocks implements ContentList{
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
|
|
||||||
consumes.power(0.80f);
|
consumes.power(0.9f);
|
||||||
consumes.liquid(Liquids.water, 0.2f);
|
consumes.liquid(Liquids.water, 0.2f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
@ -1334,6 +1341,7 @@ public class Blocks implements ContentList{
|
||||||
size = 4;
|
size = 4;
|
||||||
|
|
||||||
unitCapModifier = 14;
|
unitCapModifier = 14;
|
||||||
|
researchCostMultiplier = 0.04f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
coreNucleus = new CoreBlock("core-nucleus"){{
|
coreNucleus = new CoreBlock("core-nucleus"){{
|
||||||
|
|
@ -1345,20 +1353,19 @@ public class Blocks implements ContentList{
|
||||||
size = 5;
|
size = 5;
|
||||||
|
|
||||||
unitCapModifier = 20;
|
unitCapModifier = 20;
|
||||||
|
researchCostMultiplier = 0.06f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
vault = new StorageBlock("vault"){{
|
vault = new StorageBlock("vault"){{
|
||||||
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
|
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
|
||||||
size = 3;
|
size = 3;
|
||||||
itemCapacity = 1000;
|
itemCapacity = 1000;
|
||||||
group = BlockGroup.storage;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
container = new StorageBlock("container"){{
|
container = new StorageBlock("container"){{
|
||||||
requirements(Category.effect, with(Items.titanium, 100));
|
requirements(Category.effect, with(Items.titanium, 100));
|
||||||
size = 2;
|
size = 2;
|
||||||
itemCapacity = 300;
|
itemCapacity = 300;
|
||||||
group = BlockGroup.storage;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
unloader = new Unloader("unloader"){{
|
unloader = new Unloader("unloader"){{
|
||||||
|
|
@ -1527,9 +1534,9 @@ public class Blocks implements ContentList{
|
||||||
|
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
size = 2;
|
size = 2;
|
||||||
force = 4.5f;
|
force = 5f;
|
||||||
scaledForce = 5.5f;
|
scaledForce = 5.5f;
|
||||||
range = 110f;
|
range = 160f;
|
||||||
damage = 0.4f;
|
damage = 0.4f;
|
||||||
health = 160 * size * size;
|
health = 160 * size * size;
|
||||||
rotateSpeed = 10;
|
rotateSpeed = 10;
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,8 @@ public class Bullets implements ContentList{
|
||||||
width = 16f;
|
width = 16f;
|
||||||
height = 23f;
|
height = 23f;
|
||||||
shootEffect = Fx.shootBig;
|
shootEffect = Fx.shootBig;
|
||||||
|
pierceCap = 2;
|
||||||
|
pierceBuilding = true;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
standardIncendiaryBig = new BasicBulletType(7f, 60, "bullet"){{
|
standardIncendiaryBig = new BasicBulletType(7f, 60, "bullet"){{
|
||||||
|
|
@ -363,6 +365,8 @@ public class Bullets implements ContentList{
|
||||||
backColor = Pal.lightOrange;
|
backColor = Pal.lightOrange;
|
||||||
status = StatusEffects.burning;
|
status = StatusEffects.burning;
|
||||||
shootEffect = Fx.shootBig;
|
shootEffect = Fx.shootBig;
|
||||||
|
pierceCap = 2;
|
||||||
|
pierceBuilding = true;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
damageLightning = new BulletType(0.0001f, 0f){{
|
damageLightning = new BulletType(0.0001f, 0f){{
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public class StatusEffects implements ContentList{
|
||||||
|
|
||||||
freezing = new StatusEffect("freezing"){{
|
freezing = new StatusEffect("freezing"){{
|
||||||
speedMultiplier = 0.6f;
|
speedMultiplier = 0.6f;
|
||||||
armorMultiplier = 0.8f;
|
healthMultiplier = 0.8f;
|
||||||
effect = Fx.freezing;
|
effect = Fx.freezing;
|
||||||
|
|
||||||
init(() -> {
|
init(() -> {
|
||||||
|
|
@ -81,7 +81,7 @@ public class StatusEffects implements ContentList{
|
||||||
|
|
||||||
melting = new StatusEffect("melting"){{
|
melting = new StatusEffect("melting"){{
|
||||||
speedMultiplier = 0.8f;
|
speedMultiplier = 0.8f;
|
||||||
armorMultiplier = 0.8f;
|
healthMultiplier = 0.8f;
|
||||||
damage = 0.3f;
|
damage = 0.3f;
|
||||||
effect = Fx.melting;
|
effect = Fx.melting;
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ public class StatusEffects implements ContentList{
|
||||||
|
|
||||||
sapped = new StatusEffect("sapped"){{
|
sapped = new StatusEffect("sapped"){{
|
||||||
speedMultiplier = 0.7f;
|
speedMultiplier = 0.7f;
|
||||||
armorMultiplier = 0.8f;
|
healthMultiplier = 0.8f;
|
||||||
effect = Fx.sapped;
|
effect = Fx.sapped;
|
||||||
effectChance = 0.1f;
|
effectChance = 0.1f;
|
||||||
}};
|
}};
|
||||||
|
|
@ -115,7 +115,7 @@ public class StatusEffects implements ContentList{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
overdrive = new StatusEffect("overdrive"){{
|
overdrive = new StatusEffect("overdrive"){{
|
||||||
armorMultiplier = 0.95f;
|
healthMultiplier = 0.95f;
|
||||||
speedMultiplier = 1.15f;
|
speedMultiplier = 1.15f;
|
||||||
damageMultiplier = 1.4f;
|
damageMultiplier = 1.4f;
|
||||||
damage = -0.01f;
|
damage = -0.01f;
|
||||||
|
|
@ -132,13 +132,13 @@ public class StatusEffects implements ContentList{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
shielded = new StatusEffect("shielded"){{
|
shielded = new StatusEffect("shielded"){{
|
||||||
armorMultiplier = 3f;
|
healthMultiplier = 3f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
boss = new StatusEffect("boss"){{
|
boss = new StatusEffect("boss"){{
|
||||||
permanent = true;
|
permanent = true;
|
||||||
damageMultiplier = 1.5f;
|
damageMultiplier = 2f;
|
||||||
armorMultiplier = 1.5f;
|
healthMultiplier = 2f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
shocked = new StatusEffect("shocked");
|
shocked = new StatusEffect("shocked");
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,6 @@ public class TechTree implements ContentList{
|
||||||
|
|
||||||
node(Items.coal, with(Items.lead, 3000), () -> {
|
node(Items.coal, with(Items.lead, 3000), () -> {
|
||||||
node(Items.graphite, with(Items.coal, 1000), () -> {
|
node(Items.graphite, with(Items.coal, 1000), () -> {
|
||||||
node(illuminator, () -> {
|
|
||||||
});
|
|
||||||
|
|
||||||
node(graphitePress, () -> {
|
node(graphitePress, () -> {
|
||||||
node(Items.titanium, with(Items.graphite, 6000, Items.copper, 10000, Items.lead, 10000), () -> {
|
node(Items.titanium, with(Items.graphite, 6000, Items.copper, 10000, Items.lead, 10000), () -> {
|
||||||
|
|
@ -230,6 +228,9 @@ public class TechTree implements ContentList{
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
node(illuminator, () -> {
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,7 @@ public class UnitTypes implements ContentList{
|
||||||
public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela;
|
public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela;
|
||||||
|
|
||||||
//legs
|
//legs
|
||||||
public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus;
|
public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus, atrax;
|
||||||
|
|
||||||
//legs
|
|
||||||
public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax;
|
|
||||||
|
|
||||||
//legs + building
|
//legs + building
|
||||||
public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid;
|
public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid;
|
||||||
|
|
@ -164,7 +161,7 @@ public class UnitTypes implements ContentList{
|
||||||
y = 1f;
|
y = 1f;
|
||||||
x = 16f;
|
x = 16f;
|
||||||
shootY = 8f;
|
shootY = 8f;
|
||||||
reload = 50f;
|
reload = 45f;
|
||||||
recoil = 5f;
|
recoil = 5f;
|
||||||
shake = 2f;
|
shake = 2f;
|
||||||
ejectEffect = Fx.shellEjectBig;
|
ejectEffect = Fx.shellEjectBig;
|
||||||
|
|
@ -173,7 +170,7 @@ public class UnitTypes implements ContentList{
|
||||||
inaccuracy = 3f;
|
inaccuracy = 3f;
|
||||||
shotDelay = 4f;
|
shotDelay = 4f;
|
||||||
|
|
||||||
bullet = new BasicBulletType(7f, 45){{
|
bullet = new BasicBulletType(7f, 50){{
|
||||||
width = 11f;
|
width = 11f;
|
||||||
height = 20f;
|
height = 20f;
|
||||||
lifetime = 25f;
|
lifetime = 25f;
|
||||||
|
|
@ -182,7 +179,7 @@ public class UnitTypes implements ContentList{
|
||||||
lightningLength = 6;
|
lightningLength = 6;
|
||||||
lightningColor = Pal.surge;
|
lightningColor = Pal.surge;
|
||||||
//standard bullet damage is far too much for lightning
|
//standard bullet damage is far too much for lightning
|
||||||
lightningDamage = 25;
|
lightningDamage = 30;
|
||||||
}};
|
}};
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
|
@ -230,8 +227,9 @@ public class UnitTypes implements ContentList{
|
||||||
ejectEffect = Fx.shellEjectBig;
|
ejectEffect = Fx.shellEjectBig;
|
||||||
shootSound = Sounds.artillery;
|
shootSound = Sounds.artillery;
|
||||||
|
|
||||||
bullet = new BasicBulletType(13f, 55){{
|
bullet = new BasicBulletType(13f, 60){{
|
||||||
pierce = true;
|
pierce = true;
|
||||||
|
pierceCap = 10;
|
||||||
width = 14f;
|
width = 14f;
|
||||||
height = 33f;
|
height = 33f;
|
||||||
lifetime = 15f;
|
lifetime = 15f;
|
||||||
|
|
@ -250,6 +248,8 @@ public class UnitTypes implements ContentList{
|
||||||
width = 10f;
|
width = 10f;
|
||||||
height = 10f;
|
height = 10f;
|
||||||
pierce = true;
|
pierce = true;
|
||||||
|
pierceBuilding = true;
|
||||||
|
pierceCap = 3;
|
||||||
|
|
||||||
lifetime = 20f;
|
lifetime = 20f;
|
||||||
hitEffect = Fx.flakExplosion;
|
hitEffect = Fx.flakExplosion;
|
||||||
|
|
@ -514,7 +514,7 @@ public class UnitTypes implements ContentList{
|
||||||
crawler = new UnitType("crawler"){{
|
crawler = new UnitType("crawler"){{
|
||||||
defaultController = SuicideAI::new;
|
defaultController = SuicideAI::new;
|
||||||
|
|
||||||
speed = 0.92f;
|
speed = 1f;
|
||||||
hitSize = 8f;
|
hitSize = 8f;
|
||||||
health = 180;
|
health = 180;
|
||||||
mechSideSway = 0.25f;
|
mechSideSway = 0.25f;
|
||||||
|
|
@ -529,9 +529,9 @@ public class UnitTypes implements ContentList{
|
||||||
hitEffect = Fx.pulverize;
|
hitEffect = Fx.pulverize;
|
||||||
lifetime = 10f;
|
lifetime = 10f;
|
||||||
speed = 1f;
|
speed = 1f;
|
||||||
splashDamageRadius = 55f;
|
splashDamageRadius = 70f;
|
||||||
instantDisappear = true;
|
instantDisappear = true;
|
||||||
splashDamage = 60f;
|
splashDamage = 80f;
|
||||||
killShooter = true;
|
killShooter = true;
|
||||||
hittable = false;
|
hittable = false;
|
||||||
collidesAir = true;
|
collidesAir = true;
|
||||||
|
|
@ -1145,7 +1145,7 @@ public class UnitTypes implements ContentList{
|
||||||
speed = 1.9f;
|
speed = 1.9f;
|
||||||
rotateSpeed = 15f;
|
rotateSpeed = 15f;
|
||||||
accel = 0.1f;
|
accel = 0.1f;
|
||||||
range = 70f;
|
range = 130f;
|
||||||
health = 400;
|
health = 400;
|
||||||
buildSpeed = 0.5f;
|
buildSpeed = 0.5f;
|
||||||
engineOffset = 6.5f;
|
engineOffset = 6.5f;
|
||||||
|
|
@ -1187,8 +1187,6 @@ public class UnitTypes implements ContentList{
|
||||||
healPercent = 5.5f;
|
healPercent = 5.5f;
|
||||||
collidesTeam = true;
|
collidesTeam = true;
|
||||||
backColor = Pal.heal;
|
backColor = Pal.heal;
|
||||||
frontColor = Color.white;
|
|
||||||
backColor = Pal.heal;
|
|
||||||
trailColor = Pal.heal;
|
trailColor = Pal.heal;
|
||||||
}};
|
}};
|
||||||
}});
|
}});
|
||||||
|
|
@ -1233,7 +1231,7 @@ public class UnitTypes implements ContentList{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
quad = new UnitType("quad"){{
|
quad = new UnitType("quad"){{
|
||||||
armor = 4f;
|
armor = 8f;
|
||||||
health = 6000;
|
health = 6000;
|
||||||
speed = 1.2f;
|
speed = 1.2f;
|
||||||
rotateSpeed = 2f;
|
rotateSpeed = 2f;
|
||||||
|
|
@ -1256,7 +1254,7 @@ public class UnitTypes implements ContentList{
|
||||||
new Weapon(){{
|
new Weapon(){{
|
||||||
x = y = 0f;
|
x = y = 0f;
|
||||||
mirror = false;
|
mirror = false;
|
||||||
reload = 60f;
|
reload = 55f;
|
||||||
minShootVelocity = 0.01f;
|
minShootVelocity = 0.01f;
|
||||||
|
|
||||||
bullet = new BasicBulletType(){{
|
bullet = new BasicBulletType(){{
|
||||||
|
|
@ -1289,9 +1287,9 @@ public class UnitTypes implements ContentList{
|
||||||
speed = 0.001f;
|
speed = 0.001f;
|
||||||
collides = false;
|
collides = false;
|
||||||
|
|
||||||
healPercent = 10f;
|
healPercent = 15f;
|
||||||
splashDamage = 240f;
|
splashDamage = 320f;
|
||||||
splashDamageRadius = 115f;
|
splashDamageRadius = 120f;
|
||||||
}};
|
}};
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
|
|
@ -1546,7 +1544,7 @@ public class UnitTypes implements ContentList{
|
||||||
xRand = 8f;
|
xRand = 8f;
|
||||||
shotDelay = 1f;
|
shotDelay = 1f;
|
||||||
|
|
||||||
bullet = new MissileBulletType(4.2f, 25){{
|
bullet = new MissileBulletType(4.2f, 30){{
|
||||||
homingPower = 0.12f;
|
homingPower = 0.12f;
|
||||||
width = 8f;
|
width = 8f;
|
||||||
height = 8f;
|
height = 8f;
|
||||||
|
|
@ -1554,8 +1552,8 @@ public class UnitTypes implements ContentList{
|
||||||
drag = -0.003f;
|
drag = -0.003f;
|
||||||
homingRange = 80f;
|
homingRange = 80f;
|
||||||
keepVelocity = false;
|
keepVelocity = false;
|
||||||
splashDamageRadius = 25f;
|
splashDamageRadius = 30f;
|
||||||
splashDamage = 25f;
|
splashDamage = 35f;
|
||||||
lifetime = 56f;
|
lifetime = 56f;
|
||||||
trailColor = Pal.bulletYellowBack;
|
trailColor = Pal.bulletYellowBack;
|
||||||
backColor = Pal.bulletYellowBack;
|
backColor = Pal.bulletYellowBack;
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ public class Weathers implements ContentList{
|
||||||
if(tile != null && tile.floor().liquidDrop == Liquids.water){
|
if(tile != null && tile.floor().liquidDrop == Liquids.water){
|
||||||
Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(state.opacity()));
|
Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(state.opacity()));
|
||||||
Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
|
Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
|
||||||
}else{
|
}else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){
|
||||||
Draw.color(Color.royal, Color.white, 0.3f);
|
Draw.color(Color.royal, Color.white, 0.3f);
|
||||||
Draw.alpha(Mathf.slope(life) * state.opacity());
|
Draw.alpha(Mathf.slope(life) * state.opacity());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||||
}else{
|
}else{
|
||||||
net.reset();
|
net.reset();
|
||||||
logic.reset();
|
logic.reset();
|
||||||
|
sector.setSecondsPassed(0);
|
||||||
world.loadSector(sector);
|
world.loadSector(sector);
|
||||||
state.rules.sector = sector;
|
state.rules.sector = sector;
|
||||||
//assign origin when launching
|
//assign origin when launching
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import mindustry.game.EventType.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.game.Teams.*;
|
import mindustry.game.Teams.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.maps.*;
|
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
import mindustry.type.Weather.*;
|
import mindustry.type.Weather.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
|
|
@ -89,13 +88,16 @@ public class Logic implements ApplicationListener{
|
||||||
if(state.isCampaign()){
|
if(state.isCampaign()){
|
||||||
long seconds = state.rules.sector.getSecondsPassed();
|
long seconds = state.rules.sector.getSecondsPassed();
|
||||||
CoreBuild core = state.rules.defaultTeam.core();
|
CoreBuild core = state.rules.defaultTeam.core();
|
||||||
|
//THE WAVES NEVER END
|
||||||
|
state.rules.waves = true;
|
||||||
|
|
||||||
//apply fractional damage based on how many turns have passed for this sector
|
//apply fractional damage based on how many turns have passed for this sector
|
||||||
float turnsPassed = seconds / (turnDuration / 60f);
|
//float turnsPassed = seconds / (turnDuration / 60f);
|
||||||
|
|
||||||
if(state.rules.sector.hasWaves() && turnsPassed > 0 && state.rules.sector.hasBase()){
|
//TODO sector damage disabled for now
|
||||||
SectorDamage.apply(turnsPassed / sectorDestructionTurns);
|
//if(state.rules.sector.hasWaves() && turnsPassed > 0 && state.rules.sector.hasBase()){
|
||||||
}
|
// SectorDamage.apply(turnsPassed / sectorDestructionTurns);
|
||||||
|
//}
|
||||||
|
|
||||||
//add resources based on turns passed
|
//add resources based on turns passed
|
||||||
if(state.rules.sector.save != null && core != null){
|
if(state.rules.sector.save != null && core != null){
|
||||||
|
|
@ -197,6 +199,8 @@ public class Logic implements ApplicationListener{
|
||||||
state.rules.waves = false;
|
state.rules.waves = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO capturing is disabled
|
||||||
|
/*
|
||||||
//if there's a "win" wave and no enemies are present, win automatically
|
//if there's a "win" wave and no enemies are present, win automatically
|
||||||
if(state.rules.waves && state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()){
|
if(state.rules.waves && state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()){
|
||||||
//the sector has been conquered - waves get disabled
|
//the sector has been conquered - waves get disabled
|
||||||
|
|
@ -209,7 +213,7 @@ public class Logic implements ApplicationListener{
|
||||||
if(!headless){
|
if(!headless){
|
||||||
control.saves.saveSector(state.rules.sector);
|
control.saves.saveSector(state.rules.sector);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}else{
|
}else{
|
||||||
if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){
|
if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){
|
||||||
state.gameOver = true;
|
state.gameOver = true;
|
||||||
|
|
|
||||||
|
|
@ -329,8 +329,8 @@ public class NetServer implements ApplicationListener{
|
||||||
votes += d;
|
votes += d;
|
||||||
voted.addAll(player.uuid(), admins.getInfo(player.uuid()).lastIP);
|
voted.addAll(player.uuid(), admins.getInfo(player.uuid()).lastIP);
|
||||||
|
|
||||||
Call.sendMessage(Strings.format("[lightgray]A player has voted on kicking[orange] @[].[accent] (@/@)\n[lightgray]Type[orange] /vote <y/n>[] to agree.",
|
Call.sendMessage(Strings.format("[lightgray]@[lightgray] has voted on kicking[orange] @[].[accent] (@/@)\n[lightgray]Type[orange] /vote <y/n>[] to agree.",
|
||||||
target.name, votes, votesRequired()));
|
player.name, target.name, votes, votesRequired()));
|
||||||
|
|
||||||
checkPass();
|
checkPass();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ public class World{
|
||||||
return tile == null || tile.block().solid;
|
return tile == null || tile.block().solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean wallSolidFull(int x, int y){
|
||||||
|
Tile tile = tile(x, y);
|
||||||
|
return tile == null || (tile.block().solid && tile.block().fillsTile);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAccessible(int x, int y){
|
public boolean isAccessible(int x, int y){
|
||||||
return !wallSolid(x, y - 1) || !wallSolid(x, y + 1) || !wallSolid(x - 1, y) || !wallSolid(x + 1, y);
|
return !wallSolid(x, y - 1) || !wallSolid(x, y + 1) || !wallSolid(x - 1, y) || !wallSolid(x + 1, y);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ public abstract class UnlockableContent extends MappableContent{
|
||||||
/** Whether this content is always unlocked in the tech tree. */
|
/** Whether this content is always unlocked in the tech tree. */
|
||||||
public boolean alwaysUnlocked = false;
|
public boolean alwaysUnlocked = false;
|
||||||
/** Icons by Cicon ID.*/
|
/** Icons by Cicon ID.*/
|
||||||
protected TextureRegion[] cicons = new TextureRegion[mindustry.ui.Cicon.all.length];
|
protected TextureRegion[] cicons = new TextureRegion[Cicon.all.length];
|
||||||
/** Unlock state. Loaded from settings. Do not modify outside of the constructor. */
|
/** Unlock state. Loaded from settings. Do not modify outside of the constructor. */
|
||||||
protected boolean unlocked;
|
protected boolean unlocked;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class EditorTile extends Tile{
|
||||||
|
|
||||||
if(type instanceof OverlayFloor){
|
if(type instanceof OverlayFloor){
|
||||||
//don't place on liquids
|
//don't place on liquids
|
||||||
if(!floor.isLiquid){
|
if(floor.hasSurface()){
|
||||||
setOverlayID(type.id);
|
setOverlayID(type.id);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -96,7 +96,14 @@ public class EditorTile extends Tile{
|
||||||
super.recache();
|
super.recache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void changed(){
|
||||||
|
if(state.isGame()){
|
||||||
|
super.changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||||
if(skip()){
|
if(skip()){
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ public enum EditorTool{
|
||||||
if(editor.drawBlock.isOverlay()){
|
if(editor.drawBlock.isOverlay()){
|
||||||
Block dest = tile.overlay();
|
Block dest = tile.overlay();
|
||||||
if(dest == editor.drawBlock) return;
|
if(dest == editor.drawBlock) return;
|
||||||
tester = t -> t.overlay() == dest && !t.floor().isLiquid;
|
tester = t -> t.overlay() == dest && t.floor().hasSurface();
|
||||||
setter = t -> t.setOverlay(editor.drawBlock);
|
setter = t -> t.setOverlay(editor.drawBlock);
|
||||||
}else if(editor.drawBlock.isFloor()){
|
}else if(editor.drawBlock.isFloor()){
|
||||||
Block dest = tile.floor();
|
Block dest = tile.floor();
|
||||||
|
|
|
||||||
|
|
@ -557,6 +557,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||||
t.add(slider).width(size * 3f - 20).padTop(4f);
|
t.add(slider).width(size * 3f - 20).padTop(4f);
|
||||||
}).padTop(5).growX().top();
|
}).padTop(5).growX().top();
|
||||||
|
|
||||||
|
mid.row();
|
||||||
|
|
||||||
|
mid.table(t -> {
|
||||||
|
t.button("@editor.center", Icon.move, Styles.cleart, () -> view.center()).growX().margin(9f);
|
||||||
|
}).growX().top();
|
||||||
|
|
||||||
}).margin(0).left().growY();
|
}).margin(0).left().growY();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -417,7 +417,7 @@ public class MapGenerateDialog extends BaseDialog{
|
||||||
public void set(Block floor, Block wall, Block ore, Team team){
|
public void set(Block floor, Block wall, Block ore, Team team){
|
||||||
this.floor = floor.id;
|
this.floor = floor.id;
|
||||||
this.block = wall.id;
|
this.block = wall.id;
|
||||||
this.ore = floor.asFloor().isLiquid ? 0 : ore.id;
|
this.ore = !floor.asFloor().hasSurface() ? 0 : ore.id;
|
||||||
this.team = (byte)team.id;
|
this.team = (byte)team.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,10 @@ public class MapView extends Element implements GestureListener{
|
||||||
this.grid = grid;
|
this.grid = grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void center(){
|
||||||
|
offsetx = offsety = 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void act(float delta){
|
public void act(float delta){
|
||||||
super.act(delta);
|
super.act(delta);
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ public class Effect{
|
||||||
if(headless || region == null || !Core.atlas.isFound(region)) return;
|
if(headless || region == null || !Core.atlas.isFound(region)) return;
|
||||||
|
|
||||||
Tile tile = world.tileWorld(x, y);
|
Tile tile = world.tileWorld(x, y);
|
||||||
if(tile == null || tile.floor().isLiquid) return;
|
if(tile == null || !tile.floor().hasSurface()) return;
|
||||||
|
|
||||||
Decal decal = Decal.create();
|
Decal decal = Decal.create();
|
||||||
decal.set(x, y);
|
decal.set(x, y);
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ public class EntityCollisions{
|
||||||
|
|
||||||
public static boolean legsSolid(int x, int y){
|
public static boolean legsSolid(int x, int y){
|
||||||
Tile tile = world.tile(x, y);
|
Tile tile = world.tile(x, y);
|
||||||
return tile == null || tile.staticDarkness() >= 2;
|
return tile == null || tile.staticDarkness() >= 2 || tile.floor().solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean waterSolid(int x, int y){
|
public static boolean waterSolid(int x, int y){
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ public class Puddles{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(tile.floor().solid){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Puddle p = map.get(tile.pos());
|
Puddle p = map.get(tile.pos());
|
||||||
if(p == null){
|
if(p == null){
|
||||||
Puddle puddle = Puddle.create();
|
Puddle puddle = Puddle.create();
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public abstract class BulletType extends Content{
|
||||||
public float drawSize = 40f;
|
public float drawSize = 40f;
|
||||||
public float drag = 0f;
|
public float drag = 0f;
|
||||||
public boolean pierce, pierceBuilding;
|
public boolean pierce, pierceBuilding;
|
||||||
|
public int pierceCap = -1;
|
||||||
public Effect hitEffect, despawnEffect;
|
public Effect hitEffect, despawnEffect;
|
||||||
|
|
||||||
/** Effect created when shooting. */
|
/** Effect created when shooting. */
|
||||||
|
|
@ -235,6 +236,11 @@ public abstract class BulletType extends Content{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Bullet b){
|
public void init(Bullet b){
|
||||||
|
if(pierceCap >= 1) {
|
||||||
|
pierce = true;
|
||||||
|
//pierceBuilding is not enabled by default, because a bullet may want to *not* pierce buildings
|
||||||
|
}
|
||||||
|
|
||||||
if(killShooter && b.owner() instanceof Healthc){
|
if(killShooter && b.owner() instanceof Healthc){
|
||||||
((Healthc)b.owner()).kill();
|
((Healthc)b.owner()).kill();
|
||||||
}
|
}
|
||||||
|
|
@ -311,7 +317,7 @@ public abstract class BulletType extends Content{
|
||||||
bullet.data = data;
|
bullet.data = data;
|
||||||
bullet.drag = drag;
|
bullet.drag = drag;
|
||||||
bullet.hitSize = hitSize;
|
bullet.hitSize = hitSize;
|
||||||
bullet.damage = damage < 0 ? this.damage : damage;
|
bullet.damage = (damage < 0 ? this.damage : damage) * bullet.damageMultiplier();
|
||||||
bullet.add();
|
bullet.add();
|
||||||
|
|
||||||
if(keepVelocity && owner instanceof Velc) bullet.vel.add(((Velc)owner).vel().x, ((Velc)owner).vel().y);
|
if(keepVelocity && owner instanceof Velc) bullet.vel.add(((Velc)owner).vel().x, ((Velc)owner).vel().y);
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,6 @@ abstract class BuilderComp implements Unitc{
|
||||||
current.progress = entity.progress;
|
current.progress = entity.progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
|
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
|
||||||
void drawBuildRequests(){
|
void drawBuildRequests(){
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
transient Block block;
|
transient Block block;
|
||||||
transient Seq<Building> proximity = new Seq<>(8);
|
transient Seq<Building> proximity = new Seq<>(8);
|
||||||
transient boolean updateFlow;
|
transient boolean updateFlow;
|
||||||
transient byte dump;
|
transient byte cdump;
|
||||||
transient int rotation;
|
transient int rotation;
|
||||||
transient boolean enabled = true;
|
transient boolean enabled = true;
|
||||||
transient float enabledControlTime;
|
transient float enabledControlTime;
|
||||||
|
transient String lastAccessed;
|
||||||
|
|
||||||
PowerModule power;
|
PowerModule power;
|
||||||
ItemModule items;
|
ItemModule items;
|
||||||
|
|
@ -348,6 +349,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
//endregion
|
//endregion
|
||||||
//region handler methods
|
//region handler methods
|
||||||
|
|
||||||
|
/** Called when an unloader takes an item. */
|
||||||
|
public void itemTaken(Item item){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** Called when this block is dropped as a payload. */
|
/** Called when this block is dropped as a payload. */
|
||||||
public void dropped(){
|
public void dropped(){
|
||||||
|
|
||||||
|
|
@ -443,7 +449,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
public boolean dumpPayload(Payload todump){
|
public boolean dumpPayload(Payload todump){
|
||||||
if(proximity.size == 0) return false;
|
if(proximity.size == 0) return false;
|
||||||
|
|
||||||
int dump = this.dump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
Building other = proximity.get((i + dump) % proximity.size);
|
Building other = proximity.get((i + dump) % proximity.size);
|
||||||
|
|
@ -477,7 +483,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpLiquid(Liquid liquid){
|
public void dumpLiquid(Liquid liquid){
|
||||||
int dump = this.dump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
|
|
@ -507,15 +513,15 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float moveLiquidForward(float leakResistance, Liquid liquid){
|
public float moveLiquidForward(boolean leaks, Liquid liquid){
|
||||||
Tile next = tile.getNearby(rotation);
|
Tile next = tile.getNearby(rotation);
|
||||||
|
|
||||||
if(next == null) return 0;
|
if(next == null) return 0;
|
||||||
|
|
||||||
if(next.build != null){
|
if(next.build != null){
|
||||||
return moveLiquid(next.build, liquid);
|
return moveLiquid(next.build, liquid);
|
||||||
}else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){
|
}else if(leaks && !next.block().solid && !next.block().hasLiquids){
|
||||||
float leakAmount = liquids.get(liquid) / leakResistance;
|
float leakAmount = liquids.get(liquid) / 1.5f;
|
||||||
Puddles.deposit(next, tile, liquid, leakAmount);
|
Puddles.deposit(next, tile, liquid, leakAmount);
|
||||||
liquids.remove(liquid, leakAmount);
|
liquids.remove(liquid, leakAmount);
|
||||||
}
|
}
|
||||||
|
|
@ -577,7 +583,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
* containers, it gets added to the block's inventory.
|
* containers, it gets added to the block's inventory.
|
||||||
*/
|
*/
|
||||||
public void offload(Item item){
|
public void offload(Item item){
|
||||||
int dump = this.dump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
|
|
@ -595,7 +601,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
* Tries to put this item into a nearby container. Returns success. Unlike #offload(), this method does not change the block inventory.
|
* Tries to put this item into a nearby container. Returns success. Unlike #offload(), this method does not change the block inventory.
|
||||||
*/
|
*/
|
||||||
public boolean put(Item item){
|
public boolean put(Item item){
|
||||||
int dump = this.dump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
|
|
@ -621,7 +627,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
public boolean dump(Item todump){
|
public boolean dump(Item todump){
|
||||||
if(!block.hasItems || items.total() == 0 || (todump != null && !items.has(todump))) return false;
|
if(!block.hasItems || items.total() == 0 || (todump != null && !items.has(todump))) return false;
|
||||||
|
|
||||||
int dump = this.dump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
if(proximity.size == 0) return false;
|
if(proximity.size == 0) return false;
|
||||||
|
|
||||||
|
|
@ -656,7 +662,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementDump(int prox){
|
public void incrementDump(int prox){
|
||||||
dump = (byte)((dump + 1) % prox);
|
cdump = (byte)((cdump + 1) % prox);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used for dumping items. */
|
/** Used for dumping items. */
|
||||||
|
|
@ -874,6 +880,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
//null is of type void.class; anonymous classes use their superclass.
|
//null is of type void.class; anonymous classes use their superclass.
|
||||||
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
|
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
|
||||||
|
|
||||||
|
if(builder != null && builder.isPlayer()){
|
||||||
|
lastAccessed = builder.getPlayer().name;
|
||||||
|
}
|
||||||
|
|
||||||
if(block.configurations.containsKey(type)){
|
if(block.configurations.containsKey(type)){
|
||||||
block.configurations.get(type).get(this, value);
|
block.configurations.get(type).get(this, value);
|
||||||
}
|
}
|
||||||
|
|
@ -1038,6 +1048,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(net.active() && lastAccessed != null){
|
||||||
|
table.row();
|
||||||
|
table.add(Core.bundle.format("lastaccessed", lastAccessed)).growX().wrap().left();
|
||||||
|
}
|
||||||
|
|
||||||
table.marginBottom(-5);
|
table.marginBottom(-5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1165,10 +1180,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||||
proximity.add(tile);
|
proximity.add(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Building other : tmpTiles){
|
|
||||||
other.onProximityUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
onProximityAdded();
|
onProximityAdded();
|
||||||
onProximityUpdate();
|
onProximityUpdate();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,11 @@ import static mindustry.Vars.*;
|
||||||
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc{
|
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc{
|
||||||
@Import Team team;
|
@Import Team team;
|
||||||
@Import Entityc owner;
|
@Import Entityc owner;
|
||||||
@Import float x,y;
|
@Import float x, y, damage;
|
||||||
|
|
||||||
IntSeq collided = new IntSeq(6);
|
IntSeq collided = new IntSeq(6);
|
||||||
Object data;
|
Object data;
|
||||||
BulletType type;
|
BulletType type;
|
||||||
float damage;
|
|
||||||
float fdata;
|
float fdata;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -76,11 +75,6 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||||
return type.drawSize;
|
return type.drawSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public float damage(){
|
|
||||||
return damage * damageMultiplier();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Replace
|
@Replace
|
||||||
@Override
|
@Override
|
||||||
public boolean collides(Hitboxc other){
|
public boolean collides(Hitboxc other){
|
||||||
|
|
@ -150,6 +144,10 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(type.pierceCap != -1 && collided.size >= type.pierceCap) {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ import mindustry.annotations.Annotations.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class DamageComp{
|
abstract class DamageComp{
|
||||||
abstract float damage();
|
float damage;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,10 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(payload instanceof BuildPayload){
|
if(payload instanceof BuildPayload b){
|
||||||
return dropBlock((BuildPayload)payload);
|
return dropBlock(b);
|
||||||
}else if(payload instanceof UnitPayload){
|
}else if(payload instanceof UnitPayload p){
|
||||||
return dropUnit((UnitPayload)payload);
|
return dropUnit(p);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +126,8 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||||
int rot = (int)((rotation + 45f) / 90f) % 4;
|
int rot = (int)((rotation + 45f) / 90f) % 4;
|
||||||
payload.place(on, rot);
|
payload.place(on, rot);
|
||||||
|
|
||||||
|
if(isPlayer()) payload.build.lastAccessed = getPlayer().name;
|
||||||
|
|
||||||
Fx.unitDrop.at(tile);
|
Fx.unitDrop.at(tile);
|
||||||
Fx.placeBlock.at(on.drawx(), on.drawy(), on.block().size);
|
Fx.placeBlock.at(on.drawx(), on.drawy(), on.block().size);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,11 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||||
if(unit.isRemote()){
|
if(unit.isRemote()){
|
||||||
unit.snapInterpolation();
|
unit.snapInterpolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//reset selected block when switching units
|
||||||
|
if(!headless && isLocal()){
|
||||||
|
control.input.block = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.fire(new UnitChangeEvent(self(), unit));
|
Events.fire(new UnitChangeEvent(self(), unit));
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import static mindustry.Vars.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class ShieldComp implements Healthc, Posc{
|
abstract class ShieldComp implements Healthc, Posc{
|
||||||
@Import float health, hitTime, x, y;
|
@Import float health, hitTime, x, y, healthMultiplier;
|
||||||
@Import boolean dead;
|
@Import boolean dead;
|
||||||
|
|
||||||
/** Absorbs health damage. */
|
/** Absorbs health damage. */
|
||||||
|
|
@ -22,6 +22,7 @@ abstract class ShieldComp implements Healthc, Posc{
|
||||||
@Replace
|
@Replace
|
||||||
@Override
|
@Override
|
||||||
public void damage(float amount){
|
public void damage(float amount){
|
||||||
|
amount /= healthMultiplier;
|
||||||
//apply armor
|
//apply armor
|
||||||
amount = Math.max(amount - armor, minArmorDamage * amount);
|
amount = Math.max(amount - armor, minArmorDamage * amount);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||||
private Seq<StatusEntry> statuses = new Seq<>();
|
private Seq<StatusEntry> statuses = new Seq<>();
|
||||||
private transient Bits applied = new Bits(content.getBy(ContentType.status).size);
|
private transient Bits applied = new Bits(content.getBy(ContentType.status).size);
|
||||||
|
|
||||||
@ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, armorMultiplier = 1, reloadMultiplier = 1;
|
@ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1;
|
||||||
|
|
||||||
@Import UnitType type;
|
@Import UnitType type;
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||||
}
|
}
|
||||||
|
|
||||||
applied.clear();
|
applied.clear();
|
||||||
speedMultiplier = damageMultiplier = armorMultiplier = reloadMultiplier = 1f;
|
speedMultiplier = damageMultiplier = healthMultiplier = reloadMultiplier = 1f;
|
||||||
|
|
||||||
if(statuses.isEmpty()) return;
|
if(statuses.isEmpty()) return;
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||||
statuses.remove(index);
|
statuses.remove(index);
|
||||||
}else{
|
}else{
|
||||||
speedMultiplier *= entry.effect.speedMultiplier;
|
speedMultiplier *= entry.effect.speedMultiplier;
|
||||||
armorMultiplier *= entry.effect.armorMultiplier;
|
healthMultiplier *= entry.effect.healthMultiplier;
|
||||||
damageMultiplier *= entry.effect.damageMultiplier;
|
damageMultiplier *= entry.effect.damageMultiplier;
|
||||||
reloadMultiplier *= entry.effect.reloadMultiplier;
|
reloadMultiplier *= entry.effect.reloadMultiplier;
|
||||||
entry.effect.update(self(), entry.time);
|
entry.effect.update(self(), entry.time);
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
|
||||||
|
|
||||||
//update continuous state
|
//update continuous state
|
||||||
if(weapon.continuous && mount.bullet != null){
|
if(weapon.continuous && mount.bullet != null){
|
||||||
if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime){
|
if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime || mount.bullet.type != weapon.bullet){
|
||||||
mount.bullet = null;
|
mount.bullet = null;
|
||||||
}else{
|
}else{
|
||||||
mount.bullet.rotation(weaponRotation + 90);
|
mount.bullet.rotation(weaponRotation + 90);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ public class AIController implements UnitController{
|
||||||
|
|
||||||
protected Unit unit;
|
protected Unit unit;
|
||||||
protected Interval timer = new Interval(4);
|
protected Interval timer = new Interval(4);
|
||||||
|
protected AIController fallback;
|
||||||
|
|
||||||
/** main target that is being faced */
|
/** main target that is being faced */
|
||||||
protected Teamc target;
|
protected Teamc target;
|
||||||
|
|
@ -34,11 +35,27 @@ public class AIController implements UnitController{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUnit(){
|
public void updateUnit(){
|
||||||
|
//use fallback AI when possible
|
||||||
|
if(useFallback() && (fallback != null || (fallback = fallback()) != null)){
|
||||||
|
if(fallback.unit != unit) fallback.unit(unit);
|
||||||
|
fallback.updateUnit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateVisuals();
|
updateVisuals();
|
||||||
updateTargeting();
|
updateTargeting();
|
||||||
updateMovement();
|
updateMovement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected AIController fallback(){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean useFallback(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected UnitCommand command(){
|
protected UnitCommand command(){
|
||||||
return unit.team.data().command;
|
return unit.team.data().command;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mindustry.game;
|
package mindustry.game;
|
||||||
|
|
||||||
|
import arc.func.*;
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
|
@ -37,6 +38,7 @@ public class DefaultWaves{
|
||||||
unitScaling = 1.7f;
|
unitScaling = 1.7f;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
max = 4;
|
max = 4;
|
||||||
|
shieldScaling = 15f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(pulsar){{
|
new SpawnGroup(pulsar){{
|
||||||
|
|
@ -54,10 +56,12 @@ public class DefaultWaves{
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(dagger){{
|
new SpawnGroup(dagger){{
|
||||||
begin = 8;
|
begin = 12;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
unitAmount = 4;
|
unitAmount = 4;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
|
shieldScaling = 10f;
|
||||||
|
max = 20;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(mace){{
|
new SpawnGroup(mace){{
|
||||||
|
|
@ -65,12 +69,15 @@ public class DefaultWaves{
|
||||||
spacing = 3;
|
spacing = 3;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
end = 40;
|
end = 40;
|
||||||
|
shieldScaling = 20f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(mace){{
|
new SpawnGroup(spiroct){{
|
||||||
begin = 45;
|
begin = 45;
|
||||||
spacing = 3;
|
spacing = 3;
|
||||||
unitScaling = 2;
|
unitScaling = 1;
|
||||||
|
max = 10;
|
||||||
|
shieldScaling = 10f;
|
||||||
effect = StatusEffects.overdrive;
|
effect = StatusEffects.overdrive;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
|
@ -86,17 +93,19 @@ public class DefaultWaves{
|
||||||
begin = 16;
|
begin = 16;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
|
shieldScaling = 20f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(dagger){{
|
new SpawnGroup(quasar){{
|
||||||
begin = 82;
|
begin = 82;
|
||||||
spacing = 3;
|
spacing = 3;
|
||||||
unitAmount = 4;
|
unitAmount = 4;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
|
shieldScaling = 30f;
|
||||||
effect = StatusEffects.overdrive;
|
effect = StatusEffects.overdrive;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(dagger){{
|
new SpawnGroup(pulsar){{
|
||||||
begin = 41;
|
begin = 41;
|
||||||
spacing = 5;
|
spacing = 5;
|
||||||
unitAmount = 1;
|
unitAmount = 1;
|
||||||
|
|
@ -110,6 +119,7 @@ public class DefaultWaves{
|
||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 2;
|
unitScaling = 2;
|
||||||
max = 20;
|
max = 20;
|
||||||
|
shieldScaling = 30;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(dagger){{
|
new SpawnGroup(dagger){{
|
||||||
|
|
@ -135,6 +145,7 @@ public class DefaultWaves{
|
||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
unitScaling = 2;
|
unitScaling = 2;
|
||||||
|
shieldScaling = 20;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(flare){{
|
new SpawnGroup(flare){{
|
||||||
|
|
@ -142,6 +153,8 @@ public class DefaultWaves{
|
||||||
unitAmount = 4;
|
unitAmount = 4;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 5;
|
spacing = 5;
|
||||||
|
shields = 100f;
|
||||||
|
shieldScaling = 10f;
|
||||||
effect = StatusEffects.overdrive;
|
effect = StatusEffects.overdrive;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
|
@ -151,13 +164,15 @@ public class DefaultWaves{
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 5;
|
spacing = 5;
|
||||||
max = 16;
|
max = 16;
|
||||||
|
shieldScaling = 30;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(horizon){{
|
new SpawnGroup(nova){{
|
||||||
begin = 53;
|
begin = 53;
|
||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 4;
|
spacing = 4;
|
||||||
|
shieldScaling = 20;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(atrax){{
|
new SpawnGroup(atrax){{
|
||||||
|
|
@ -165,6 +180,7 @@ public class DefaultWaves{
|
||||||
unitAmount = 4;
|
unitAmount = 4;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 3;
|
spacing = 3;
|
||||||
|
shieldScaling = 5f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(scepter){{
|
new SpawnGroup(scepter){{
|
||||||
|
|
@ -172,6 +188,7 @@ public class DefaultWaves{
|
||||||
unitAmount = 1;
|
unitAmount = 1;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 30;
|
spacing = 30;
|
||||||
|
shieldScaling = 10f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(reign){{
|
new SpawnGroup(reign){{
|
||||||
|
|
@ -179,13 +196,32 @@ public class DefaultWaves{
|
||||||
unitAmount = 1;
|
unitAmount = 1;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 40;
|
spacing = 40;
|
||||||
|
shieldScaling = 20f;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(antumbra){{
|
new SpawnGroup(antumbra){{
|
||||||
begin = 131;
|
begin = 120;
|
||||||
unitAmount = 1;
|
unitAmount = 1;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 40;
|
spacing = 40;
|
||||||
|
shieldScaling = 20f;
|
||||||
|
}},
|
||||||
|
|
||||||
|
new SpawnGroup(vela){{
|
||||||
|
begin = 100;
|
||||||
|
unitAmount = 1;
|
||||||
|
unitScaling = 1;
|
||||||
|
spacing = 30;
|
||||||
|
shieldScaling = 20f;
|
||||||
|
}},
|
||||||
|
|
||||||
|
new SpawnGroup(corvus){{
|
||||||
|
begin = 145;
|
||||||
|
unitAmount = 1;
|
||||||
|
unitScaling = 1;
|
||||||
|
spacing = 35;
|
||||||
|
shieldScaling = 30f;
|
||||||
|
shields = 100;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(horizon){{
|
new SpawnGroup(horizon){{
|
||||||
|
|
@ -193,6 +229,17 @@ public class DefaultWaves{
|
||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 4;
|
spacing = 4;
|
||||||
|
shields = 40f;
|
||||||
|
shieldScaling = 20f;
|
||||||
|
}},
|
||||||
|
|
||||||
|
new SpawnGroup(atrax){{
|
||||||
|
begin = 210;
|
||||||
|
unitAmount = 1;
|
||||||
|
unitScaling = 1;
|
||||||
|
spacing = 35;
|
||||||
|
shields = 1000;
|
||||||
|
shieldScaling = 35f;
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +247,7 @@ public class DefaultWaves{
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO move elsewhere
|
//TODO move elsewhere
|
||||||
public static Seq<SpawnGroup> generate(){
|
public static Seq<SpawnGroup> generate(float difficulty){
|
||||||
UnitType[][] species = {
|
UnitType[][] species = {
|
||||||
{dagger, mace, fortress, scepter, reign},
|
{dagger, mace, fortress, scepter, reign},
|
||||||
{nova, pulsar, quasar, vela, corvus},
|
{nova, pulsar, quasar, vela, corvus},
|
||||||
|
|
@ -216,58 +263,72 @@ public class DefaultWaves{
|
||||||
Seq<SpawnGroup> out = new Seq<>();
|
Seq<SpawnGroup> out = new Seq<>();
|
||||||
|
|
||||||
//max reasonable wave, after which everything gets boring
|
//max reasonable wave, after which everything gets boring
|
||||||
int cap = 400;
|
int cap = 200;
|
||||||
|
|
||||||
//main sequence
|
float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f;
|
||||||
float shieldStart = 30, shieldsPerWave = 12;
|
|
||||||
UnitType[] curSpecies = Structs.random(species);
|
|
||||||
int curTier = 0;
|
|
||||||
|
|
||||||
for(int i = 0; i < cap;){
|
Intc createProgression = start -> {
|
||||||
int f = i;
|
//main sequence
|
||||||
int next = Mathf.random(15, 25);
|
UnitType[] curSpecies = Structs.random(species);
|
||||||
|
int curTier = 0;
|
||||||
|
|
||||||
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
|
for(int i = start; i < cap;){
|
||||||
|
int f = i;
|
||||||
|
int next = Mathf.random(8, 16);
|
||||||
|
|
||||||
//main progression
|
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
|
||||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
int space = start == 0 ? 1 : Mathf.random(1, 2);
|
||||||
unitAmount = f == 0 ? 1 : 10;
|
|
||||||
begin = f;
|
|
||||||
end = f + next >= cap ? never : f + next;
|
|
||||||
max = 16;
|
|
||||||
unitScaling = Mathf.random(1f, 2f);
|
|
||||||
shields = shieldAmount;
|
|
||||||
shieldScaling = shieldsPerWave;
|
|
||||||
}});
|
|
||||||
|
|
||||||
//extra progression that tails out, blends in
|
//main progression
|
||||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||||
unitAmount = 6;
|
unitAmount = f == 0 ? 1 : 10;
|
||||||
begin = f + next;
|
begin = f;
|
||||||
end = f + next + Mathf.random(8, 12);
|
end = f + next >= cap ? never : f + next;
|
||||||
max = 10;
|
max = 20;
|
||||||
unitScaling = Mathf.random(2f);
|
unitScaling = Mathf.random(1f, 2f);
|
||||||
spacing = Mathf.random(2, 3);
|
shields = shieldAmount;
|
||||||
shields = shieldAmount;
|
shieldScaling = shieldsPerWave;
|
||||||
shieldScaling = shieldsPerWave;
|
spacing = space;
|
||||||
}});
|
}});
|
||||||
|
|
||||||
i += next;
|
//extra progression that tails out, blends in
|
||||||
if(curTier < 3 || Mathf.chance(0.2)){
|
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||||
curTier ++;
|
unitAmount = 6;
|
||||||
|
begin = f + next;
|
||||||
|
end = f + next + Mathf.random(8, 12);
|
||||||
|
max = 14;
|
||||||
|
unitScaling = Mathf.random(2f);
|
||||||
|
spacing = Mathf.random(2, 3);
|
||||||
|
shields = shieldAmount;
|
||||||
|
shieldScaling = shieldsPerWave;
|
||||||
|
}});
|
||||||
|
|
||||||
|
i += next;
|
||||||
|
if(curTier < 3 || Mathf.chance(0.2)){
|
||||||
|
curTier ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do not spawn bosses
|
||||||
|
curTier = Math.min(curTier, 3);
|
||||||
|
|
||||||
|
//small chance to switch species
|
||||||
|
if(Mathf.chance(0.3)){
|
||||||
|
curSpecies = Structs.random(species);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//do not spawn bosses
|
createProgression.get(0);
|
||||||
curTier = Math.min(curTier, 3);
|
|
||||||
|
|
||||||
//small chance to switch species
|
int step = 5 + Mathf.random(3);
|
||||||
if(Mathf.chance(0.3)){
|
|
||||||
curSpecies = Structs.random(species);
|
while(step <= cap){
|
||||||
}
|
createProgression.get(step);
|
||||||
|
step += (int)(Mathf.random(12, 25) * Mathf.lerp(1f, 0.4f, difficulty));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bossWave = Mathf.random(30, 60);
|
int bossWave = (int)(Mathf.random(30, 60) * Mathf.lerp(1f, 0.7f, difficulty));
|
||||||
int bossSpacing = Mathf.random(30, 50);
|
int bossSpacing = (int)(Mathf.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty));
|
||||||
|
|
||||||
//main boss progression
|
//main boss progression
|
||||||
out.add(new SpawnGroup(Structs.random(species)[4]){{
|
out.add(new SpawnGroup(Structs.random(species)[4]){{
|
||||||
|
|
@ -283,7 +344,7 @@ public class DefaultWaves{
|
||||||
//alt boss progression
|
//alt boss progression
|
||||||
out.add(new SpawnGroup(Structs.random(species)[4]){{
|
out.add(new SpawnGroup(Structs.random(species)[4]){{
|
||||||
unitAmount = 1;
|
unitAmount = 1;
|
||||||
begin = bossWave + Mathf.random(4, 6) * bossSpacing;
|
begin = bossWave + Mathf.random(3, 5) * bossSpacing;
|
||||||
spacing = bossSpacing;
|
spacing = bossSpacing;
|
||||||
end = never;
|
end = never;
|
||||||
max = 16;
|
max = 16;
|
||||||
|
|
@ -291,6 +352,14 @@ public class DefaultWaves{
|
||||||
shieldScaling = shieldsPerWave;
|
shieldScaling = shieldsPerWave;
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
//shift back waves on higher difficulty for a harder start
|
||||||
|
int shift = Math.max((int)(difficulty * 15 - 5), 0);
|
||||||
|
|
||||||
|
for(SpawnGroup group : out){
|
||||||
|
group.begin -= shift;
|
||||||
|
group.end -= shift;
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ public class Objectives{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO fix
|
||||||
public static class SectorComplete extends SectorObjective{
|
public static class SectorComplete extends SectorObjective{
|
||||||
|
|
||||||
public SectorComplete(SectorPreset zone){
|
public SectorComplete(SectorPreset zone){
|
||||||
|
|
@ -38,12 +39,12 @@ public class Objectives{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean complete(){
|
public boolean complete(){
|
||||||
return preset.sector.isCaptured();
|
return preset.sector.save != null && preset.sector.save.meta.wave >= preset.sector.save.meta.rules.winWave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String display(){
|
public String display(){
|
||||||
return Core.bundle.format("requirement.capture", preset.localizedName);
|
return Core.bundle.format("requirement.wave", preset.sector.save == null ? "<unknown>" : preset.sector.save.meta.rules.winWave, preset.localizedName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
||||||
return tags.get("name", "unknown");
|
return tags.get("name", "unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String description(){
|
||||||
|
return tags.get("description", "");
|
||||||
|
}
|
||||||
|
|
||||||
public void save(){
|
public void save(){
|
||||||
schematics.saveChanges(this);
|
schematics.saveChanges(this);
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +94,7 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String steamDescription(){
|
public String steamDescription(){
|
||||||
return null;
|
return description();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import mindustry.world.*;
|
||||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||||
import mindustry.world.modules.*;
|
import mindustry.world.modules.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class SectorInfo{
|
public class SectorInfo{
|
||||||
|
|
@ -42,7 +44,15 @@ public class SectorInfo{
|
||||||
/** Counter refresh state. */
|
/** Counter refresh state. */
|
||||||
private transient Interval time = new Interval();
|
private transient Interval time = new Interval();
|
||||||
/** Core item storage to prevent spoofing. */
|
/** Core item storage to prevent spoofing. */
|
||||||
private transient int[] lastCoreItems;
|
private transient int[] coreItemCounts;
|
||||||
|
|
||||||
|
/** Handles core item changes. */
|
||||||
|
public void handleCoreItem(Item item, int amount){
|
||||||
|
if(coreItemCounts == null){
|
||||||
|
coreItemCounts = new int[content.items().size];
|
||||||
|
}
|
||||||
|
coreItemCounts[item.id] += amount;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return the real location items go when launched on this sector */
|
/** @return the real location items go when launched on this sector */
|
||||||
public Sector getRealDestination(){
|
public Sector getRealDestination(){
|
||||||
|
|
@ -105,12 +115,6 @@ public class SectorInfo{
|
||||||
universe.runTurn();
|
universe.runTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
//create last stored core items
|
|
||||||
if(lastCoreItems == null){
|
|
||||||
lastCoreItems = new int[content.items().size];
|
|
||||||
updateCoreDeltas();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreBuild ent = state.rules.defaultTeam.core();
|
CoreBuild ent = state.rules.defaultTeam.core();
|
||||||
|
|
||||||
//refresh throughput
|
//refresh throughput
|
||||||
|
|
@ -124,15 +128,16 @@ public class SectorInfo{
|
||||||
stat.loaded = true;
|
stat.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//how the resources changed - only interested in negative deltas, since that's what happens during spoofing
|
|
||||||
int coreDelta = Math.min(ent == null ? 0 : ent.items.get(item) - lastCoreItems[item.id], 0);
|
|
||||||
|
|
||||||
//add counter, subtract how many items were taken from the core during this time
|
//add counter, subtract how many items were taken from the core during this time
|
||||||
stat.means.add(Math.max(stat.counter + coreDelta, 0));
|
stat.means.add(Math.max(stat.counter, 0));
|
||||||
stat.counter = 0;
|
stat.counter = 0;
|
||||||
stat.mean = stat.means.rawMean();
|
stat.mean = stat.means.rawMean();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(coreItemCounts == null){
|
||||||
|
coreItemCounts = new int[content.items().size];
|
||||||
|
}
|
||||||
|
|
||||||
//refresh core items
|
//refresh core items
|
||||||
for(Item item : content.items()){
|
for(Item item : content.items()){
|
||||||
ExportStat stat = production.get(item, ExportStat::new);
|
ExportStat stat = production.get(item, ExportStat::new);
|
||||||
|
|
@ -143,21 +148,14 @@ public class SectorInfo{
|
||||||
|
|
||||||
//get item delta
|
//get item delta
|
||||||
//TODO is preventing negative production a good idea?
|
//TODO is preventing negative production a good idea?
|
||||||
int delta = Math.max((ent == null ? 0 : ent.items.get(item)) - lastCoreItems[item.id], 0);
|
int delta = Math.max(ent == null ? 0 : coreItemCounts[item.id], 0);
|
||||||
|
|
||||||
//store means
|
//store means
|
||||||
stat.means.add(delta);
|
stat.means.add(delta);
|
||||||
stat.mean = stat.means.rawMean();
|
stat.mean = stat.means.rawMean();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCoreDeltas();
|
Arrays.fill(coreItemCounts, 0);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCoreDeltas(){
|
|
||||||
CoreBuild ent = state.rules.defaultTeam.core();
|
|
||||||
for(int i = 0; i < lastCoreItems.length; i++){
|
|
||||||
lastCoreItems[i] = ent == null ? 0 : ent.items.get(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mindustry.game;
|
package mindustry.game;
|
||||||
|
|
||||||
|
import arc.util.*;
|
||||||
import arc.util.serialization.*;
|
import arc.util.serialization.*;
|
||||||
import arc.util.serialization.Json.*;
|
import arc.util.serialization.Json.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
|
|
@ -27,7 +28,7 @@ public class SpawnGroup implements Serializable{
|
||||||
/** The spacing, in waves, of spawns. For example, 2 = spawns every other wave */
|
/** The spacing, in waves, of spawns. For example, 2 = spawns every other wave */
|
||||||
public int spacing = 1;
|
public int spacing = 1;
|
||||||
/** Maximum amount of units that spawn */
|
/** Maximum amount of units that spawn */
|
||||||
public int max = 100;
|
public int max = 40;
|
||||||
/** How many waves need to pass before the amount of units spawned increases by 1 */
|
/** How many waves need to pass before the amount of units spawned increases by 1 */
|
||||||
public float unitScaling = never;
|
public float unitScaling = never;
|
||||||
/** Shield points that this unit has. */
|
/** Shield points that this unit has. */
|
||||||
|
|
@ -37,8 +38,10 @@ public class SpawnGroup implements Serializable{
|
||||||
/** Amount of enemies spawned initially, with no scaling */
|
/** Amount of enemies spawned initially, with no scaling */
|
||||||
public int unitAmount = 1;
|
public int unitAmount = 1;
|
||||||
/** Status effect applied to the spawned unit. Null to disable. */
|
/** Status effect applied to the spawned unit. Null to disable. */
|
||||||
|
@Nullable
|
||||||
public StatusEffect effect;
|
public StatusEffect effect;
|
||||||
/** Items this unit spawns with. Null to disable. */
|
/** Items this unit spawns with. Null to disable. */
|
||||||
|
@Nullable
|
||||||
public ItemStack items;
|
public ItemStack items;
|
||||||
|
|
||||||
public SpawnGroup(UnitType type){
|
public SpawnGroup(UnitType type){
|
||||||
|
|
@ -51,6 +54,7 @@ public class SpawnGroup implements Serializable{
|
||||||
|
|
||||||
/** Returns the amount of units spawned on a specific wave. */
|
/** Returns the amount of units spawned on a specific wave. */
|
||||||
public int getUnitsSpawned(int wave){
|
public int getUnitsSpawned(int wave){
|
||||||
|
if(spacing == 0) spacing = 1;
|
||||||
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -84,12 +88,12 @@ public class SpawnGroup implements Serializable{
|
||||||
if(begin != 0) json.writeValue("begin", begin);
|
if(begin != 0) json.writeValue("begin", begin);
|
||||||
if(end != never) json.writeValue("end", end);
|
if(end != never) json.writeValue("end", end);
|
||||||
if(spacing != 1) json.writeValue("spacing", spacing);
|
if(spacing != 1) json.writeValue("spacing", spacing);
|
||||||
//if(max != 40) json.writeValue("max", max);
|
if(max != 40) json.writeValue("max", max);
|
||||||
if(unitScaling != never) json.writeValue("scaling", unitScaling);
|
if(unitScaling != never) json.writeValue("scaling", unitScaling);
|
||||||
if(shields != 0) json.writeValue("shields", shields);
|
if(shields != 0) json.writeValue("shields", shields);
|
||||||
if(shieldScaling != 0) json.writeValue("shieldScaling", shieldScaling);
|
if(shieldScaling != 0) json.writeValue("shieldScaling", shieldScaling);
|
||||||
if(unitAmount != 1) json.writeValue("amount", unitAmount);
|
if(unitAmount != 1) json.writeValue("amount", unitAmount);
|
||||||
if(effect != null) json.writeValue("effect", effect.id);
|
if(effect != null) json.writeValue("effect", effect.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -101,12 +105,18 @@ public class SpawnGroup implements Serializable{
|
||||||
begin = data.getInt("begin", 0);
|
begin = data.getInt("begin", 0);
|
||||||
end = data.getInt("end", never);
|
end = data.getInt("end", never);
|
||||||
spacing = data.getInt("spacing", 1);
|
spacing = data.getInt("spacing", 1);
|
||||||
//max = data.getInt("max", 40);
|
max = data.getInt("max", 40);
|
||||||
unitScaling = data.getFloat("scaling", never);
|
unitScaling = data.getFloat("scaling", never);
|
||||||
shields = data.getFloat("shields", 0);
|
shields = data.getFloat("shields", 0);
|
||||||
shieldScaling = data.getFloat("shieldScaling", 0);
|
shieldScaling = data.getFloat("shieldScaling", 0);
|
||||||
unitAmount = data.getInt("amount", 1);
|
unitAmount = data.getInt("amount", 1);
|
||||||
effect = content.getByID(ContentType.status, data.getInt("effect", -1));
|
|
||||||
|
//old boss effect ID
|
||||||
|
if(data.has("effect") && data.get("effect").isNumber() && data.getInt("effect", -1) == 8){
|
||||||
|
effect = StatusEffects.boss;
|
||||||
|
}else{
|
||||||
|
effect = content.getByName(ContentType.status, data.has("effect") && data.get("effect").isString() ? data.getString("effect", "none") : "none");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,9 @@ public class Universe{
|
||||||
if(!sector.isBeingPlayed()){
|
if(!sector.isBeingPlayed()){
|
||||||
sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
|
sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
|
||||||
|
|
||||||
|
//TODO sector damage disabled for now
|
||||||
//check if the sector has been attacked too many times...
|
//check if the sector has been attacked too many times...
|
||||||
if(sector.hasBase() && sector.hasWaves() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){
|
/*if(sector.hasBase() && sector.hasWaves() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){
|
||||||
//fire event for losing the sector
|
//fire event for losing the sector
|
||||||
Events.fire(new SectorLoseEvent(sector));
|
Events.fire(new SectorLoseEvent(sector));
|
||||||
|
|
||||||
|
|
@ -151,17 +152,17 @@ public class Universe{
|
||||||
//clear recieved
|
//clear recieved
|
||||||
sector.setExtraItems(new ItemSeq());
|
sector.setExtraItems(new ItemSeq());
|
||||||
sector.save = null;
|
sector.save = null;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//export to another sector
|
//export to another sector
|
||||||
if(sector.save != null && sector.save.meta != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.destination != null){
|
if(sector.save != null && sector.save.meta != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.destination != null){
|
||||||
Sector to = sector.save.meta.secinfo.destination;
|
Sector to = sector.save.meta.secinfo.destination;
|
||||||
if(to.save != null){
|
if(to.save != null){
|
||||||
ItemSeq items = to.getExtraItems();
|
ItemSeq items = new ItemSeq();
|
||||||
//calculated exported items to this sector
|
//calculated exported items to this sector
|
||||||
sector.save.meta.secinfo.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed)));
|
sector.save.meta.secinfo.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed)));
|
||||||
to.setExtraItems(items);
|
to.addItems(items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,17 @@ public enum CacheLayer{
|
||||||
endShader(Shaders.slag);
|
endShader(Shaders.slag);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
space{
|
||||||
|
@Override
|
||||||
|
public void begin(){
|
||||||
|
beginShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end(){
|
||||||
|
endShader(Shaders.space);
|
||||||
|
}
|
||||||
|
},
|
||||||
normal(5),
|
normal(5),
|
||||||
walls(3);
|
walls(3);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import arc.math.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
|
import mindustry.ai.types.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.input.*;
|
import mindustry.input.*;
|
||||||
import mindustry.ui.*;
|
import mindustry.ui.*;
|
||||||
|
|
@ -151,6 +152,13 @@ public class OverlayRenderer{
|
||||||
|
|
||||||
input.drawOverSelect();
|
input.drawOverSelect();
|
||||||
|
|
||||||
|
if(ui.hudfrag.blockfrag.hover() instanceof Unit unit && unit.controller() instanceof LogicAI ai && ai.controller instanceof Building build){
|
||||||
|
Drawf.square(build.x, build.y, build.block.size * tilesize/2f + 2f);
|
||||||
|
if(!unit.within(build, unit.hitSize * 2f)){
|
||||||
|
Drawf.arrow(unit.x, unit.y, build.x, build.y, unit.hitSize *2f, 4f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//draw selection overlay when dropping item
|
//draw selection overlay when dropping item
|
||||||
if(input.isDroppingItem()){
|
if(input.isDroppingItem()){
|
||||||
Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ public class Shaders{
|
||||||
public static UnitBuild build;
|
public static UnitBuild build;
|
||||||
public static DarknessShader darkness;
|
public static DarknessShader darkness;
|
||||||
public static LightShader light;
|
public static LightShader light;
|
||||||
public static SurfaceShader water, mud, tar, slag;
|
public static SurfaceShader water, mud, tar, slag, space;
|
||||||
public static PlanetShader planet;
|
public static PlanetShader planet;
|
||||||
public static PlanetGridShader planetGrid;
|
public static PlanetGridShader planetGrid;
|
||||||
public static AtmosphereShader atmosphere;
|
public static AtmosphereShader atmosphere;
|
||||||
|
|
@ -44,6 +44,7 @@ public class Shaders{
|
||||||
mud = new SurfaceShader("mud");
|
mud = new SurfaceShader("mud");
|
||||||
tar = new SurfaceShader("tar");
|
tar = new SurfaceShader("tar");
|
||||||
slag = new SurfaceShader("slag");
|
slag = new SurfaceShader("slag");
|
||||||
|
space = new SpaceShader("space");
|
||||||
planet = new PlanetShader();
|
planet = new PlanetShader();
|
||||||
planetGrid = new PlanetGridShader();
|
planetGrid = new PlanetGridShader();
|
||||||
atmosphere = new AtmosphereShader();
|
atmosphere = new AtmosphereShader();
|
||||||
|
|
@ -196,6 +197,34 @@ public class Shaders{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//seed: 8kmfuix03fw
|
||||||
|
public static class SpaceShader extends SurfaceShader{
|
||||||
|
Texture texture;
|
||||||
|
|
||||||
|
public SpaceShader(String frag){
|
||||||
|
super(frag);
|
||||||
|
|
||||||
|
Core.assets.load("sprites/space.png", Texture.class).loaded = t -> {
|
||||||
|
texture = (Texture)t;
|
||||||
|
texture.setFilter(TextureFilter.linear);
|
||||||
|
texture.setWrap(TextureWrap.mirroredRepeat);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(){
|
||||||
|
setUniformf("u_campos", Core.camera.position.x, Core.camera.position.y);
|
||||||
|
setUniformf("u_ccampos", Core.camera.position);
|
||||||
|
setUniformf("u_resolution", Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||||
|
setUniformf("u_time", Time.time());
|
||||||
|
|
||||||
|
texture.bind(1);
|
||||||
|
renderer.effectBuffer.getTexture().bind(0);
|
||||||
|
|
||||||
|
setUniformi("u_stars", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class SurfaceShader extends LoadShader{
|
public static class SurfaceShader extends LoadShader{
|
||||||
|
|
||||||
public SurfaceShader(String frag){
|
public SurfaceShader(String frag){
|
||||||
|
|
@ -225,7 +254,7 @@ public class Shaders{
|
||||||
public static class LoadShader extends Shader{
|
public static class LoadShader extends Shader{
|
||||||
|
|
||||||
public LoadShader(String frag, String vert){
|
public LoadShader(String frag, String vert){
|
||||||
super(Core.files.internal("shaders/" + vert + ".vert").readString(), Core.files.internal("shaders/" + frag + ".frag").readString());
|
super(Core.files.internal("shaders/" + vert + ".vert"), Core.files.internal("shaders/" + frag + ".frag"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@ public class PlanetRenderer implements Disposable{
|
||||||
shadowColor = new Color(0, 0, 0, 0.7f);
|
shadowColor = new Color(0, 0, 0, 0.7f);
|
||||||
|
|
||||||
private static final Seq<Vec3> points = new Seq<>();
|
private static final Seq<Vec3> points = new Seq<>();
|
||||||
private static final PlanetInterfaceRenderer emptyRenderer = new PlanetInterfaceRenderer(){
|
|
||||||
@Override public void renderSectors(Planet planet){}
|
|
||||||
@Override public void renderProjections(){}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Camera direction relative to the planet. Length is determined by zoom. */
|
/** Camera direction relative to the planet. Length is determined by zoom. */
|
||||||
public final Vec3 camPos = new Vec3();
|
public final Vec3 camPos = new Vec3();
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ public class DesktopInput extends InputHandler{
|
||||||
public void update(){
|
public void update(){
|
||||||
super.update();
|
super.update();
|
||||||
|
|
||||||
if(net.active() && Core.input.keyTap(Binding.player_list) && (scene.getKeyboardFocus() == null || scene.getKeyboardFocus().isDescendantOf(ui.listfrag.content))){
|
if(net.active() && Core.input.keyTap(Binding.player_list) && (scene.getKeyboardFocus() == null || scene.getKeyboardFocus().isDescendantOf(ui.listfrag.content) || scene.getKeyboardFocus().isDescendantOf(ui.minimapfrag.elem))){
|
||||||
ui.listfrag.toggle();
|
ui.listfrag.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||||
|
|
||||||
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
||||||
public static void requestItem(Player player, Building tile, Item item, int amount){
|
public static void requestItem(Player player, Building tile, Item item, int amount){
|
||||||
if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange)) return;
|
if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange) || player.dead()) return;
|
||||||
amount = Math.min(player.unit().maxAccepted(item), amount);
|
amount = Math.min(player.unit().maxAccepted(item), amount);
|
||||||
int fa = amount;
|
int fa = amount;
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
|
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
|
||||||
public static void rotateBlock(Player player, Building tile, boolean direction){
|
public static void rotateBlock(@Nullable Player player, Building tile, boolean direction){
|
||||||
if(tile == null) return;
|
if(tile == null) return;
|
||||||
|
|
||||||
if(net.server() && (!Units.canInteract(player, tile) ||
|
if(net.server() && (!Units.canInteract(player, tile) ||
|
||||||
|
|
@ -264,6 +264,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||||
throw new ValidateException(player, "Player cannot rotate a block.");
|
throw new ValidateException(player, "Player cannot rotate a block.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(player != null) tile.lastAccessed = player.name;
|
||||||
tile.rotation = Mathf.mod(tile.rotation + Mathf.sign(direction), 4);
|
tile.rotation = Mathf.mod(tile.rotation + Mathf.sign(direction), 4);
|
||||||
tile.updateProximity();
|
tile.updateProximity();
|
||||||
tile.noSleep();
|
tile.noSleep();
|
||||||
|
|
@ -271,7 +272,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||||
|
|
||||||
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
||||||
public static void transferInventory(Player player, Building tile){
|
public static void transferInventory(Player player, Building tile){
|
||||||
if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null) return;
|
if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null || player.dead()) return;
|
||||||
|
|
||||||
if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) ||
|
if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) ||
|
||||||
!netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> {
|
!netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> {
|
||||||
|
|
@ -531,6 +532,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
lastSchematic.tags.put("name", text);
|
lastSchematic.tags.put("name", text);
|
||||||
|
lastSchematic.tags.put("description", "");
|
||||||
schematics.add(lastSchematic);
|
schematics.add(lastSchematic);
|
||||||
ui.showInfoFade("@schematic.saved");
|
ui.showInfoFade("@schematic.saved");
|
||||||
ui.schematics.showInfo(lastSchematic);
|
ui.schematics.showInfo(lastSchematic);
|
||||||
|
|
|
||||||
|
|
@ -290,12 +290,15 @@ public class TypeIO{
|
||||||
|
|
||||||
public static void writeController(Writes write, UnitController control){
|
public static void writeController(Writes write, UnitController control){
|
||||||
//no real unit controller state is written, only the type
|
//no real unit controller state is written, only the type
|
||||||
if(control instanceof Player){
|
if(control instanceof Player p){
|
||||||
write.b(0);
|
write.b(0);
|
||||||
write.i(((Player)control).id);
|
write.i(p.id);
|
||||||
}else if(control instanceof FormationAI){
|
}else if(control instanceof FormationAI form){
|
||||||
write.b(1);
|
write.b(1);
|
||||||
write.i(((FormationAI)control).leader.id);
|
write.i(form.leader.id);
|
||||||
|
}else if(control instanceof LogicAI logic && logic.controller != null){
|
||||||
|
write.b(3);
|
||||||
|
write.i(logic.controller.pos());
|
||||||
}else{
|
}else{
|
||||||
write.b(2);
|
write.b(2);
|
||||||
}
|
}
|
||||||
|
|
@ -312,6 +315,19 @@ public class TypeIO{
|
||||||
}else if(type == 1){ //formation controller
|
}else if(type == 1){ //formation controller
|
||||||
int id = read.i();
|
int id = read.i();
|
||||||
return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null);
|
return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null);
|
||||||
|
}else if(type == 3){
|
||||||
|
int pos = read.i();
|
||||||
|
if(prev instanceof LogicAI pai){
|
||||||
|
pai.controller = world.build(pos);
|
||||||
|
return pai;
|
||||||
|
}else{
|
||||||
|
//create new AI for assignment
|
||||||
|
LogicAI out = new LogicAI();
|
||||||
|
//instantly time out when updated.
|
||||||
|
out.controlTimer = LogicAI.logicControlTimeout;
|
||||||
|
out.controller = world.build(pos);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
//there are two cases here:
|
//there are two cases here:
|
||||||
//1: prev controller was not a player, carry on
|
//1: prev controller was not a player, carry on
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ public class LAssembler{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//used as a special value for any environmental solid block
|
||||||
|
putConst("@solid", Blocks.stoneWall);
|
||||||
|
|
||||||
putConst("@air", Blocks.air);
|
putConst("@air", Blocks.air);
|
||||||
|
|
||||||
for(UnitType type : Vars.content.units()){
|
for(UnitType type : Vars.content.units()){
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import arc.util.*;
|
||||||
import arc.util.noise.*;
|
import arc.util.noise.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.ai.types.*;
|
import mindustry.ai.types.*;
|
||||||
|
import mindustry.content.*;
|
||||||
import mindustry.ctype.*;
|
import mindustry.ctype.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
|
|
@ -251,6 +252,11 @@ public class LExecutor{
|
||||||
case spawn -> {
|
case spawn -> {
|
||||||
res = Geometry.findClosest(unit.x, unit.y, Vars.spawner.getSpawns());
|
res = Geometry.findClosest(unit.x, unit.y, Vars.spawner.getSpawns());
|
||||||
}
|
}
|
||||||
|
case damaged -> {
|
||||||
|
Building b = Units.findDamagedTile(unit.team, unit.x, unit.y);
|
||||||
|
res = b == null ? null : b.tile;
|
||||||
|
build = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(res != null && (!build || res.build != null)){
|
if(res != null && (!build || res.build != null)){
|
||||||
|
|
@ -390,7 +396,9 @@ public class LExecutor{
|
||||||
if(exec.bool(p1)){
|
if(exec.bool(p1)){
|
||||||
Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type().hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
|
Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type().hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
|
||||||
|
|
||||||
Call.pickedUnitPayload(unit, result);
|
if(result != null){
|
||||||
|
Call.pickedUnitPayload(unit, result);
|
||||||
|
}
|
||||||
}else{ //buildings
|
}else{ //buildings
|
||||||
Building tile = world.buildWorld(unit.x, unit.y);
|
Building tile = world.buildWorld(unit.x, unit.y);
|
||||||
|
|
||||||
|
|
@ -433,12 +441,16 @@ public class LExecutor{
|
||||||
}
|
}
|
||||||
case getBlock -> {
|
case getBlock -> {
|
||||||
float x = exec.numf(p1), y = exec.numf(p2);
|
float x = exec.numf(p1), y = exec.numf(p2);
|
||||||
if(unit.within(x, y, unit.range())){
|
float range = Math.max(unit.range(), buildingRange);
|
||||||
|
if(!unit.within(x, y, range)){
|
||||||
exec.setobj(p3, null);
|
exec.setobj(p3, null);
|
||||||
|
exec.setnum(p4, 0);
|
||||||
}else{
|
}else{
|
||||||
Tile tile = world.tileWorld(x, y);
|
Tile tile = world.tileWorld(x, y);
|
||||||
Block block = tile == null || !tile.synthetic() ? null : tile.block();
|
//any environmental solid block is returned as StoneWall, aka "@solid"
|
||||||
|
Block block = tile == null ? null : !tile.synthetic() ? (tile.solid() ? Blocks.stoneWall : Blocks.air) : tile.block();
|
||||||
exec.setobj(p3, block);
|
exec.setobj(p3, block);
|
||||||
|
exec.setnum(p4, tile != null && tile.build != null ? tile.build.rotation : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case itemDrop -> {
|
case itemDrop -> {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ package mindustry.logic;
|
||||||
public enum LLocate{
|
public enum LLocate{
|
||||||
ore,
|
ore,
|
||||||
building,
|
building,
|
||||||
spawn;
|
spawn,
|
||||||
|
damaged;
|
||||||
|
|
||||||
public static final LLocate[] all = values();
|
public static final LLocate[] all = values();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -889,7 +889,7 @@ public class LStatements{
|
||||||
table.row();
|
table.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
case spawn -> {
|
case spawn, damaged -> {
|
||||||
table.row();
|
table.row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public enum LUnitControl{
|
||||||
mine("x", "y"),
|
mine("x", "y"),
|
||||||
flag("value"),
|
flag("value"),
|
||||||
build("x", "y", "block", "rotation"),
|
build("x", "y", "block", "rotation"),
|
||||||
getBlock("x", "y", "result"),
|
getBlock("x", "y", "result", "resRot"),
|
||||||
within("x", "y", "radius", "result");
|
within("x", "y", "radius", "result");
|
||||||
|
|
||||||
public final String[] params;
|
public final String[] params;
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,9 @@ public class Map implements Comparable<Map>, Publishable{
|
||||||
|
|
||||||
public Rules rules(Rules base){
|
public Rules rules(Rules base){
|
||||||
try{
|
try{
|
||||||
Rules result = JsonIO.read(Rules.class, base, tags.get("rules", "{}"));
|
//this replacement is a MASSIVE hack but it fixes some incorrect overwriting of team-specific rules.
|
||||||
|
//may need to be tweaked later
|
||||||
|
Rules result = JsonIO.read(Rules.class, base, tags.get("rules", "{}").replace("teams:{2:{infiniteAmmo:true}},", ""));
|
||||||
if(result.spawns.isEmpty()) result.spawns = Vars.defaultWaves.get();
|
if(result.spawns.isEmpty()) result.spawns = Vars.defaultWaves.get();
|
||||||
return result;
|
return result;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|
|
||||||