Merge remote-tracking branch 'upstream/master'

This commit is contained in:
LeoDog896
2020-09-30 08:43:08 -04:00
85 changed files with 8552 additions and 8104 deletions

View File

@@ -19,7 +19,7 @@ assignees: ''
**Link(s) to mod(s) used**: *The mod repositories or zip files that are related to the issue, if applicable.* **Link(s) to mod(s) used**: *The mod repositories or zip files that are related to the issue, if applicable.*
**Save file**: *The save file you were playing on when the bug happened, if applicable.* **Save file**: *The save file you were playing on when the bug happened. REQUIRED for any issue that happens in-game.*
**Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.* **Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.*

View File

@@ -80,6 +80,7 @@ public class EntityProcess extends BaseProcessor{
//replace all self() invocations with this //replace all self() invocations with this
.replaceAll("this\\.<(.*)>self\\(\\)", "this") .replaceAll("this\\.<(.*)>self\\(\\)", "this")
.replaceAll("self\\(\\)", "this") .replaceAll("self\\(\\)", "this")
.replaceAll(" yield ", "")
); );
} }
} }

View File

@@ -67,7 +67,7 @@ public class LogicStatementProcessor extends BaseProcessor{
int index = 0; int index = 0;
for(Svar field : fields){ for(Svar field : fields){
if(field.is(Modifier.TRANSIENT)) continue; if(field.isAny(Modifier.TRANSIENT, Modifier.STATIC)) continue;
writer.addStatement("out.append(\" \")"); writer.addStatement("out.append(\" \")");
writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(), writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(),

View File

@@ -173,18 +173,29 @@ allprojects{
} }
tasks.withType(JavaCompile){ tasks.withType(JavaCompile){
sourceCompatibility = 1.8 targetCompatibility = 8
targetCompatibility = 1.8 sourceCompatibility = 14
options.encoding = "UTF-8" options.encoding = "UTF-8"
options.compilerArgs += ["-Xlint:deprecation"] options.compilerArgs += ["-Xlint:deprecation"]
} }
} }
//compile with java 8 compatibility for everything except the annotati project configure(project(":annotations")){
tasks.withType(JavaCompile){
targetCompatibility = 8
sourceCompatibility = 8
}
}
//compile with java 8 compatibility for everything except the annotation project
configure(subprojects - project(":annotations")){ configure(subprojects - project(":annotations")){
tasks.withType(JavaCompile){ tasks.withType(JavaCompile){
if(JavaVersion.current() != JavaVersion.VERSION_1_8){ if(JavaVersion.current() != JavaVersion.VERSION_1_8){
options.compilerArgs.addAll(['--release', '8']) options.compilerArgs.addAll(['--release', '8', '--enable-preview'])
}
doFirst{
options.compilerArgs = options.compilerArgs.findAll{it != '--enable-preview' }
} }
} }
@@ -288,6 +299,8 @@ project(":core"){
compileOnly project(":annotations") compileOnly project(":annotations")
annotationProcessor project(":annotations") annotationProcessor project(":annotations")
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.3.0'
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1118,6 +1118,7 @@ block.arc.name = Arc
block.rtg-generator.name = RTG Generator block.rtg-generator.name = RTG Generator
block.spectre.name = Spectre block.spectre.name = Spectre
block.meltdown.name = Meltdown block.meltdown.name = Meltdown
block.foreshadow.name = Foreshadow
block.container.name = Container block.container.name = Container
block.launch-pad.name = Launch Pad block.launch-pad.name = Launch Pad
block.launch-pad-large.name = Large Launch Pad block.launch-pad-large.name = Large Launch Pad

View File

@@ -311,3 +311,4 @@
63425=vela|unit-vela-medium 63425=vela|unit-vela-medium
63424=corvus|unit-corvus-medium 63424=corvus|unit-corvus-medium
63423=memory-bank|block-memory-bank-medium 63423=memory-bank|block-memory-bank-medium
63422=foreshadow|block-foreshadow-medium

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 815 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 KiB

After

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -45,7 +45,7 @@ public class GroundAI extends AIController{
} }
} }
if(unit.type().canBoost && unit.canPassOn()){ if(unit.type().canBoost && unit.tileOn() != null && !unit.tileOn().solid()){
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f); unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
} }

View File

@@ -74,7 +74,7 @@ public class Blocks implements ContentList{
coreShard, coreFoundation, coreNucleus, vault, container, unloader, coreShard, coreFoundation, coreNucleus, vault, container, unloader,
//turrets //turrets
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, segment, parallax, duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax,
//units //units
commandCenter, commandCenter,
@@ -209,6 +209,10 @@ public class Blocks implements ContentList{
isLiquid = true; isLiquid = true;
cacheLayer = CacheLayer.slag; cacheLayer = CacheLayer.slag;
attributes.set(Attribute.heat, 0.85f); attributes.set(Attribute.heat, 0.85f);
emitLight = true;
lightRadius = 40f;
lightColor = Color.orange.cpy().a(0.38f);
}}; }};
stone = new Floor("stone"); stone = new Floor("stone");
@@ -243,7 +247,7 @@ public class Blocks implements ContentList{
blendGroup = basalt; blendGroup = basalt;
emitLight = true; emitLight = true;
lightRadius = 60f; lightRadius = 50f;
lightColor = Color.orange.cpy().a(0.3f); lightColor = Color.orange.cpy().a(0.3f);
}}; }};
@@ -866,7 +870,8 @@ public class Blocks implements ContentList{
size = 2; size = 2;
reload = 250f; reload = 250f;
range = 85f; range = 85f;
healPercent = 14f; healPercent = 11f;
phaseBoost = 15f;
health = 80 * size * size; health = 80 * size * size;
consumes.item(Items.phasefabric).boost(); consumes.item(Items.phasefabric).boost();
}}; }};
@@ -1577,7 +1582,7 @@ public class Blocks implements ContentList{
health = 250 * size * size; health = 250 * size * size;
range = 140f; range = 140f;
hasPower = true; hasPower = true;
consumes.power(8f); consumes.powerCond(8f, (PointDefenseBuild b) -> b.target != null);
size = 2; size = 2;
shootLength = 5f; shootLength = 5f;
bulletDamage = 25f; bulletDamage = 25f;
@@ -1660,6 +1665,48 @@ public class Blocks implements ContentList{
health = 145 * size * size; health = 145 * size * size;
}}; }};
foreshadow = new ItemTurret("foreshadow"){{
float brange = range = 500f;
requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgealloy, 300, Items.plastanium, 175, Items.thorium, 350));
ammo(
Items.surgealloy, new PointBulletType(){{
shootEffect = Fx.instShoot;
hitEffect = Fx.instHit;
smokeEffect = Fx.smokeCloud;
trailEffect = Fx.instTrail;
despawnEffect = Fx.instBomb;
trailSpacing = 20f;
damage = 1300;
tileDamageMultiplier = 0.5f;
speed = brange;
hitShake = 6f;
ammoMultiplier = 1f;
}}
);
rotateSpeed = 2.5f;
reloadTime = 200f;
restitution = 0.2f;
ammoUseEffect = Fx.shellEjectBig;
recoilAmount = 5f;
restitution = 0.009f;
cooldown = 0.009f;
shootShake = 4f;
shots = 1;
size = 4;
shootCone = 2f;
shootSound = Sounds.shootBig;
unitSort = (u, x, y) -> -u.maxHealth;
coolantMultiplier = 0.09f;
health = 150 * size * size;
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true);
consumes.powerCond(10f, (TurretBuild entity) -> entity.target != null || (entity.logicControlled() && entity.logicShooting));
}};
spectre = new ItemTurret("spectre"){{ spectre = new ItemTurret("spectre"){{
requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250)); requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
ammo( ammo(
@@ -1682,7 +1729,7 @@ public class Blocks implements ContentList{
shootCone = 24f; shootCone = 24f;
shootSound = Sounds.shootBig; shootSound = Sounds.shootBig;
health = 155 * size * size; health = 160 * size * size;
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true); consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true);
}}; }};

View File

@@ -455,6 +455,79 @@ public class Fx{
}), }),
instBomb = new Effect(15f, 100f, e -> {
color(Pal.bulletYellowBack);
stroke(e.fout() * 4f);
Lines.circle(e.x, e.y, 4f + e.finpow() * 20f);
for(int i = 0; i < 4; i++){
Drawf.tri(e.x, e.y, 6f, 80f * e.fout(), i*90 + 45);
}
color();
for(int i = 0; i < 4; i++){
Drawf.tri(e.x, e.y, 3f, 30f * e.fout(), i*90 + 45);
}
}),
instTrail = new Effect(30, e -> {
for(int i = 0; i < 2; i++){
color(i == 0 ? Pal.bulletYellowBack : Pal.bulletYellow);
float m = i == 0 ? 1f : 0.5f;
float rot = e.rotation + 180f;
float w = 15f * e.fout() * m;
Drawf.tri(e.x, e.y, w, (30f + Mathf.randomSeedRange(e.id, 15f)) * m, rot);
Drawf.tri(e.x, e.y, w, 10f * m, rot + 180f);
}
}),
instShoot = new Effect(24f, e -> {
e.scaled(10f, b -> {
color(Color.white, Pal.bulletYellowBack, b.fin());
stroke(b.fout() * 3f + 0.2f);
Lines.circle(b.x, b.y, b.fin() * 50f);
});
color(Pal.bulletYellowBack);
for(int i : Mathf.signs){
Drawf.tri(e.x, e.y, 13f * e.fout(), 85f, e.rotation + 90f * i);
Drawf.tri(e.x, e.y, 13f * e.fout(), 50f, e.rotation + 20f * i);
}
}),
instHit = new Effect(20f, 200f, e -> {
color(Pal.bulletYellowBack);
for(int i = 0; i < 2; i++){
color(i == 0 ? Pal.bulletYellowBack : Pal.bulletYellow);
float m = i == 0 ? 1f : 0.5f;
for(int j = 0; j < 5; j++){
float rot = e.rotation + Mathf.randomSeedRange(e.id + j, 50f);
float w = 23f * e.fout() * m;
Drawf.tri(e.x, e.y, w, (80f + Mathf.randomSeedRange(e.id + j, 40f)) * m, rot);
Drawf.tri(e.x, e.y, w, 20f * m, rot + 180f);
}
}
e.scaled(10f, c -> {
color(Pal.bulletYellow);
stroke(c.fout() * 2f + 0.2f);
Lines.circle(e.x, e.y, c.fin() * 30f);
});
e.scaled(12f, c -> {
color(Pal.bulletYellowBack);
randLenVectors(e.id, 25, 5f + e.fin() * 80f, e.rotation, 60f, (x, y) -> {
Fill.square(e.x + x, e.y + y, c.fout() * 3f, 45f);
});
});
}),
hitLaser = new Effect(8, e -> { hitLaser = new Effect(8, e -> {
color(Color.white, Pal.heal, e.fin()); color(Color.white, Pal.heal, e.fin());
stroke(0.5f + e.fout()); stroke(0.5f + e.fout());
@@ -1074,28 +1147,11 @@ public class Fx{
}), }),
railHit = new Effect(18f, 200f, e -> { railHit = new Effect(18f, 200f, e -> {
if(true){ color(Pal.orangeSpark);
color(Pal.orangeSpark);
for(int i : Mathf.signs){ for(int i : Mathf.signs){
Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i); Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i);
}
}else{
e.scaled(7f, b -> {
color(Color.white, Color.lightGray, b.fin());
stroke(b.fout() * 2f + 0.2f);
Lines.circle(b.x, b.y, b.fin() * 28f);
});
color(Pal.orangeSpark);
float rot = e.rotation + Mathf.randomSeedRange(e.id, 20f);
float w = 9f * e.fout();
Drawf.tri(e.x, e.y, w, 100f, rot);
Drawf.tri(e.x, e.y, w, 10f, rot + 180f);
} }
}), }),
lancerLaserShoot = new Effect(21f, e -> { lancerLaserShoot = new Effect(21f, e -> {
@@ -1109,7 +1165,7 @@ public class Fx{
lancerLaserShootSmoke = new Effect(26f, e -> { lancerLaserShootSmoke = new Effect(26f, e -> {
color(Color.white); color(Color.white);
float length = e.data == null || !(e.data instanceof Float) ? 70f : (Float)e.data; float length = !(e.data instanceof Float) ? 70f : (Float)e.data;
randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> { randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> {
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);

View File

@@ -109,6 +109,9 @@ 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), () -> {
node(pneumaticDrill, () -> { node(pneumaticDrill, () -> {
@@ -347,8 +350,10 @@ public class TechTree implements ContentList{
}); });
node(lancer, () -> { node(lancer, () -> {
node(meltdown, () -> { node(foreshadow, () -> {
node(meltdown, () -> {
});
}); });
node(shockMine, () -> { node(shockMine, () -> {

View File

@@ -419,7 +419,7 @@ public class UnitTypes implements ContentList{
continuous = true; continuous = true;
cooldownTime = 200f; cooldownTime = 200f;
bullet = new ContinuousLaserBulletType(17){{ bullet = new ContinuousLaserBulletType(20){{
length = 150f; length = 150f;
hitEffect = Fx.hitMeltHeal; hitEffect = Fx.hitMeltHeal;
drawSize = 420f; drawSize = 420f;
@@ -430,7 +430,7 @@ public class UnitTypes implements ContentList{
shootEffect = Fx.greenLaserChargeSmall; shootEffect = Fx.greenLaserChargeSmall;
incendChance = 0.02f; incendChance = 0.05f;
incendSpread = 5f; incendSpread = 5f;
incendAmount = 1; incendAmount = 1;
@@ -446,7 +446,7 @@ public class UnitTypes implements ContentList{
mineTier = 1; mineTier = 1;
hitSize = 29f; hitSize = 29f;
itemCapacity = 80; itemCapacity = 80;
health = 19000f; health = 18000f;
buildSpeed = 1.7f; buildSpeed = 1.7f;
armor = 9f; armor = 9f;
landShake = 1.5f; landShake = 1.5f;
@@ -488,8 +488,8 @@ public class UnitTypes implements ContentList{
firstShotDelay = Fx.greenLaserCharge.lifetime; firstShotDelay = Fx.greenLaserCharge.lifetime;
bullet = new LaserBulletType(){{ bullet = new LaserBulletType(){{
length = 500f; length = 460f;
damage = 520f; damage = 550f;
width = 75f; width = 75f;
lifetime = 65f; lifetime = 65f;

View File

@@ -52,7 +52,7 @@ public class GameState{
/** @return whether the player is in a campaign and they are out of sector time */ /** @return whether the player is in a campaign and they are out of sector time */
public boolean isOutOfTime(){ public boolean isOutOfTime(){
return isCampaign() && isGame() && getSector().getTimeSpent() >= turnDuration; return isCampaign() && isGame() && getSector().getTimeSpent() >= turnDuration && !net.active();
} }
public boolean hasSector(){ public boolean hasSector(){

View File

@@ -112,7 +112,7 @@ public class EditorTile extends Tile{
Block block = block(); Block block = block();
if(block.hasEntity()){ if(block.hasBuilding()){
build = entityprov.get().init(this, team, false, rotation); build = entityprov.get().init(this, team, false, rotation);
build.cons = new ConsumeModule(build); build.cons = new ConsumeModule(build);
if(block.hasItems) build.items = new ItemModule(); if(block.hasItems) build.items = new ItemModule();

View File

@@ -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 = ore.id; this.ore = floor.asFloor().isLiquid ? 0 : ore.id;
this.team = (byte)team.id; this.team = (byte)team.id;
} }

View File

@@ -175,6 +175,18 @@ public class Units{
} }
} }
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static Teamc bestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred, Boolf<Building> tilePred, Sortf sort){
if(team == Team.derelict) return null;
Unit unit = bestEnemy(team, x, y, range, unitPred, sort);
if(unit != null){
return unit;
}else{
return findEnemyTile(team, x, y, range, tilePred);
}
}
/** Returns the closest enemy of this team. Filter by predicate. */ /** Returns the closest enemy of this team. Filter by predicate. */
public static Unit closestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate){ public static Unit closestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate){
if(team == Team.derelict) return null; if(team == Team.derelict) return null;
@@ -195,6 +207,26 @@ public class Units{
return result; return result;
} }
/** Returns the closest enemy of this team using a custom comparison function. Filter by predicate. */
public static Unit bestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate, Sortf sort){
if(team == Team.derelict) return null;
result = null;
cdist = 0f;
nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> {
if(e.dead() || !predicate.get(e)) return;
float dst2 = sort.cost(e, x, y);
if(dst2 < range*range && (result == null || dst2 < cdist)){
result = e;
cdist = dst2;
}
});
return result;
}
/** Returns the closest ally of this team. Filter by predicate. No range. */ /** Returns the closest ally of this team. Filter by predicate. No range. */
public static Unit closest(Team team, float x, float y, Boolf<Unit> predicate){ public static Unit closest(Team team, float x, float y, Boolf<Unit> predicate){
result = null; result = null;
@@ -297,4 +329,7 @@ public class Units{
nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons); nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons);
} }
public interface Sortf{
float cost(Unit unit, float x, float y);
}
} }

View File

@@ -71,6 +71,9 @@ public abstract class BulletType extends Content{
public boolean hittable = true; public boolean hittable = true;
/** Whether this bullet can be reflected. */ /** Whether this bullet can be reflected. */
public boolean reflectable = true; public boolean reflectable = true;
/** Whether to move the bullet back depending on delta to fix some delta-time realted issues.
* Do not change unless you know what you're doing. */
public boolean backMove = true;
/** Bullet range override. */ /** Bullet range override. */
public float range = -1f; public float range = -1f;
@@ -212,7 +215,7 @@ public abstract class BulletType extends Content{
} }
if(instantDisappear){ if(instantDisappear){
b.time(lifetime); b.time = lifetime;
} }
} }
@@ -274,7 +277,11 @@ public abstract class BulletType extends Content{
bullet.owner = owner; bullet.owner = owner;
bullet.team = team; bullet.team = team;
bullet.vel.trns(angle, speed * velocityScl); bullet.vel.trns(angle, speed * velocityScl);
bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta); if(backMove){
bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta);
}else{
bullet.set(x, y);
}
bullet.lifetime = lifetime * lifetimeScl; bullet.lifetime = lifetime * lifetimeScl;
bullet.data = data; bullet.data = data;
bullet.drag = drag; bullet.drag = drag;

View File

@@ -0,0 +1,70 @@
package mindustry.entities.bullet;
import arc.math.geom.*;
import arc.util.*;
import mindustry.*;
import mindustry.entities.*;
import mindustry.gen.*;
public class PointBulletType extends BulletType{
private static float cdist = 0f;
private static Unit result;
public float trailSpacing = 10f;
public PointBulletType(){
scaleVelocity = true;
lifetime = 100f;
collides = false;
keepVelocity = false;
backMove = false;
}
@Override
public void init(Bullet b){
super.init(b);
float px = b.x + b.lifetime * b.vel.x,
py = b.y + b.lifetime * b.vel.y,
rot = b.rotation();
Geometry.iterateLine(0f, b.x, b.y, px, py, trailSpacing, (x, y) -> {
trailEffect.at(x, y, rot);
});
b.time = b.lifetime;
b.set(px, py);
//calculate hit entity
cdist = 0f;
result = null;
float range = 1f;
Units.nearbyEnemies(b.team, px - range, py - range, range*2f, range*2f, e -> {
if(e.dead()) return;
e.hitbox(Tmp.r1);
if(!Tmp.r1.contains(px, py)) return;
float dst = e.dst(px, py) - e.hitSize;
if((result == null || dst < cdist)){
result = e;
cdist = dst;
}
});
if(result != null){
b.collision(result, px, py);
}else{
Building build = Vars.world.buildWorld(px, py);
if(build != null && build.team != b.team){
build.collision(b);
}
}
b.remove();
b.vel.setZero();
}
}

View File

@@ -1213,31 +1213,35 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
@Override @Override
public double sense(LAccess sensor){ public double sense(LAccess sensor){
if(sensor == LAccess.x) return x; return switch(sensor){
if(sensor == LAccess.y) return y; case x -> x;
if(sensor == LAccess.team) return team.id; case y -> y;
if(sensor == LAccess.health) return health; case team -> team.id;
if(sensor == LAccess.maxHealth) return maxHealth(); case health -> health;
if(sensor == LAccess.efficiency) return efficiency(); case maxHealth -> maxHealth();
if(sensor == LAccess.rotation) return rotation; case efficiency -> efficiency();
if(sensor == LAccess.totalItems && items != null) return items.total(); case rotation -> rotation;
if(sensor == LAccess.totalLiquids && liquids != null) return liquids.total(); case totalItems -> items == null ? 0 : items.total();
if(sensor == LAccess.totalPower && power != null && block.consumes.hasPower()) return power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f); case totalLiquids -> liquids == null ? 0 : liquids.total();
if(sensor == LAccess.itemCapacity) return block.itemCapacity; case totalPower -> power == null || !block.consumes.hasPower() ? 0 : power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
if(sensor == LAccess.liquidCapacity) return block.liquidCapacity; case itemCapacity -> block.itemCapacity;
if(sensor == LAccess.powerCapacity) return block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f; case liquidCapacity -> block.liquidCapacity;
if(sensor == LAccess.powerNetIn && power != null) return power.graph.getLastScaledPowerIn() * 60; case powerCapacity -> block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
if(sensor == LAccess.powerNetOut && power != null) return power.graph.getLastScaledPowerOut() * 60; case powerNetIn -> power == null ? 0 : power.graph.getLastScaledPowerIn() * 60;
if(sensor == LAccess.powerNetStored && power != null) return power.graph.getLastPowerStored(); case powerNetOut -> power == null ? 0 : power.graph.getLastScaledPowerOut() * 60;
if(sensor == LAccess.powerNetCapacity && power != null) return power.graph.getLastCapacity(); case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored();
return 0; case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity();
default -> 0;
};
} }
@Override @Override
public Object senseObject(LAccess sensor){ public Object senseObject(LAccess sensor){
if(sensor == LAccess.type) return block; return switch(sensor){
case type -> block;
default -> noSensed;
};
return noSensed;
} }
@Override @Override

View File

@@ -25,7 +25,7 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
@Override @Override
public void update(){ public void update(){
//trigger animation only when walking manually //trigger animation only when walking manually
if(walked){ if(walked || net.client()){
float len = deltaLen(); float len = deltaLen();
baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta); baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta);
walkTime += len; walkTime += len;

View File

@@ -122,7 +122,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
Building tile = payload.entity; Building tile = payload.entity;
int tx = Vars.world.toTile(x - tile.block.offset), ty = Vars.world.toTile(y - tile.block.offset); int tx = Vars.world.toTile(x - tile.block.offset), ty = Vars.world.toTile(y - tile.block.offset);
Tile on = Vars.world.tile(tx, ty); Tile on = Vars.world.tile(tx, ty);
if(on != null && Build.validPlace(tile.block, tile.team, tx, ty, tile.rotation)){ if(on != null && Build.validPlace(tile.block, tile.team, tx, ty, tile.rotation, false)){
int rot = (int)((rotation + 45f) / 90f) % 4; int rot = (int)((rotation + 45f) / 90f) % 4;
payload.place(on, rot); payload.place(on, rot);

View File

@@ -75,24 +75,28 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Override @Override
public double sense(LAccess sensor){ public double sense(LAccess sensor){
if(sensor == LAccess.totalItems) return stack().amount; return switch(sensor){
if(sensor == LAccess.rotation) return rotation; case totalItems -> stack().amount;
if(sensor == LAccess.health) return health; case rotation -> rotation;
if(sensor == LAccess.maxHealth) return maxHealth; case health -> health;
if(sensor == LAccess.x) return x; case maxHealth -> maxHealth;
if(sensor == LAccess.y) return y; case x -> x;
if(sensor == LAccess.team) return team.id; case y -> y;
if(sensor == LAccess.shooting) return isShooting() ? 1 : 0; case team -> team.id;
if(sensor == LAccess.shootX) return aimX(); case shooting -> isShooting() ? 1 : 0;
if(sensor == LAccess.shootY) return aimY(); case shootX -> aimX();
return 0; case shootY -> aimY();
default -> 0;
};
} }
@Override @Override
public Object senseObject(LAccess sensor){ public Object senseObject(LAccess sensor){
if(sensor == LAccess.type) return type; return switch(sensor){
case type -> type;
default -> noSensed;
};
return noSensed;
} }
@Override @Override
@@ -417,7 +421,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
dead = true; dead = true;
//don't waste time when the unit is already on the ground, just destroy it //don't waste time when the unit is already on the ground, just destroy it
if(isGrounded()){ if(!type.flying){
destroy(); destroy();
} }
} }

View File

@@ -18,8 +18,6 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
@Import Vec2 vel; @Import Vec2 vel;
@Import UnitType type; @Import UnitType type;
/** minimum cursor distance from unit, fixes 'cross-eyed' shooting */
static final float minAimDst = 18f;
/** temporary weapon sequence number */ /** temporary weapon sequence number */
static int sequenceNum = 0; static int sequenceNum = 0;
@@ -67,7 +65,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
/** Aim at something. This will make all mounts point at it. */ /** Aim at something. This will make all mounts point at it. */
void aim(float x, float y){ void aim(float x, float y){
Tmp.v1.set(x, y).sub(this.x, this.y); Tmp.v1.set(x, y).sub(this.x, this.y);
if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst); if(Tmp.v1.len() < type.aimDst) Tmp.v1.setLength(type.aimDst);
x = Tmp.v1.x + this.x; x = Tmp.v1.x + this.x;
y = Tmp.v1.y + this.y; y = Tmp.v1.y + this.y;

View File

@@ -1,6 +1,8 @@
package mindustry.game; package mindustry.game;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.type.*; import mindustry.type.*;
@@ -197,7 +199,8 @@ public class DefaultWaves{
return spawns == null ? new Seq<>() : spawns; return spawns == null ? new Seq<>() : spawns;
} }
private static void generate(){ //TODO move elsewhere
public static Seq<SpawnGroup> generate(){
UnitType[][] species = { UnitType[][] species = {
{dagger, mace, fortress, scepter, reign}, {dagger, mace, fortress, scepter, reign},
{nova, pulsar, quasar, vela, corvus}, {nova, pulsar, quasar, vela, corvus},
@@ -208,16 +211,63 @@ public class DefaultWaves{
}; };
//required progression: //required progression:
//- main progression of units, up to wave ~20
//- changes from
//- extra periodic patterns //- extra periodic patterns
Seq<SpawnGroup> out = new Seq<>();
//max reasonable wave, after which everything gets boring //max reasonable wave, after which everything gets boring
int cap = 300; int cap = 400;
for(int i = 0; i < cap; i++){
//main sequence
float shieldStart = 30, shieldsPerWave = 12;
UnitType[] curSpecies = Structs.random(species);
int curTier = 0;
for(int i = 0; i < cap;){
int f = i;
int next = Mathf.random(15, 25);
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
//main progression
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
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
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
unitAmount = 6;
begin = f + next;
end = f + next + Mathf.random(8, 12);
max = 10;
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.2)){
curSpecies = Structs.random(species);
}
} }
return out;
} }
} }

View File

@@ -35,7 +35,7 @@ public class BlockRenderer implements Disposable{
private FrameBuffer dark = new FrameBuffer(); private FrameBuffer dark = new FrameBuffer();
private Seq<Building> outArray2 = new Seq<>(); private Seq<Building> outArray2 = new Seq<>();
private Seq<Tile> shadowEvents = new Seq<>(); private Seq<Tile> shadowEvents = new Seq<>();
private IntSet processedEntities = new IntSet(); private IntSet processedEntities = new IntSet(), processedLinks = new IntSet();
private boolean displayStatus = false; private boolean displayStatus = false;
public BlockRenderer(){ public BlockRenderer(){
@@ -180,6 +180,7 @@ public class BlockRenderer implements Disposable{
tileview.clear(); tileview.clear();
lightview.clear(); lightview.clear();
processedEntities.clear(); processedEntities.clear();
processedLinks.clear();
int minx = Math.max(avgx - rangex - expandr, 0); int minx = Math.max(avgx - rangex - expandr, 0);
int miny = Math.max(avgy - rangey - expandr, 0); int miny = Math.max(avgy - rangey - expandr, 0);
@@ -196,10 +197,15 @@ public class BlockRenderer implements Disposable{
tile = tile.build.tile; tile = tile.build.tile;
} }
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id()))){ if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id))){
if(block.expanded || !expanded){ if(block.expanded || !expanded){
tileview.add(tile); if(tile.build == null || processedLinks.add(tile.build.id)){
if(tile.build != null) processedEntities.add(tile.build.id()); tileview.add(tile);
if(tile.build != null){
processedEntities.add(tile.build.id);
processedLinks.add(tile.build.id);
}
}
} }
//lights are drawn even in the expanded range //lights are drawn even in the expanded range
@@ -209,7 +215,7 @@ public class BlockRenderer implements Disposable{
if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){ if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){
for(Building other : tile.build.getPowerConnections(outArray2)){ for(Building other : tile.build.getPowerConnections(outArray2)){
if(other.block instanceof PowerNode){ //TODO need a generic way to render connections! if(other.block instanceof PowerNode && processedLinks.add(other.id)){ //TODO need a generic way to render connections!
tileview.add(other.tile); tileview.add(other.tile);
} }
} }

View File

@@ -20,7 +20,7 @@ public class FloorRenderer implements Disposable{
//TODO find out number with best performance //TODO find out number with best performance
private static final int chunksize = mobile ? 16 : 32; private static final int chunksize = mobile ? 16 : 32;
private Chunk[][] cache; private int[][][] cache;
private MultiCacheBatch cbatch; private MultiCacheBatch cbatch;
private IntSet drawnLayerSet = new IntSet(); private IntSet drawnLayerSet = new IntSet();
private IntSet recacheSet = new IntSet(); private IntSet recacheSet = new IntSet();
@@ -63,11 +63,11 @@ public class FloorRenderer implements Disposable{
if(!Structs.inBounds(worldx, worldy, cache)) if(!Structs.inBounds(worldx, worldy, cache))
continue; continue;
Chunk chunk = cache[worldx][worldy]; int[] chunk = cache[worldx][worldy];
//loop through all layers, and add layer index if it exists //loop through all layers, and add layer index if it exists
for(int i = 0; i < layers; i++){ for(int i = 0; i < layers; i++){
if(chunk.caches[i] != -1 && i != CacheLayer.walls.ordinal()){ if(chunk[i] != -1 && i != CacheLayer.walls.ordinal()){
drawnLayerSet.add(i); drawnLayerSet.add(i);
} }
} }
@@ -154,9 +154,9 @@ public class FloorRenderer implements Disposable{
continue; continue;
} }
Chunk chunk = cache[worldx][worldy]; int[] chunk = cache[worldx][worldy];
if(chunk.caches[layer.ordinal()] == -1) continue; if(chunk[layer.ordinal()] == -1) continue;
cbatch.drawCache(chunk.caches[layer.ordinal()]); cbatch.drawCache(chunk[layer.ordinal()]);
} }
} }
@@ -165,7 +165,7 @@ public class FloorRenderer implements Disposable{
private void cacheChunk(int cx, int cy){ private void cacheChunk(int cx, int cy){
used.clear(); used.clear();
Chunk chunk = cache[cx][cy]; int[] chunk = cache[cx][cy];
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize && tilex < world.width(); tilex++){ for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize && tilex < world.width(); tilex++){
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize && tiley < world.height(); tiley++){ for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize && tiley < world.height(); tiley++){
@@ -184,15 +184,15 @@ public class FloorRenderer implements Disposable{
} }
} }
private void cacheChunkLayer(int cx, int cy, Chunk chunk, CacheLayer layer){ private void cacheChunkLayer(int cx, int cy, int[] chunk, CacheLayer layer){
Batch current = Core.batch; Batch current = Core.batch;
Core.batch = cbatch; Core.batch = cbatch;
//begin a new cache //begin a new cache
if(chunk.caches[layer.ordinal()] == -1){ if(chunk[layer.ordinal()] == -1){
cbatch.beginCache(); cbatch.beginCache();
}else{ }else{
cbatch.beginCache(chunk.caches[layer.ordinal()]); cbatch.beginCache(chunk[layer.ordinal()]);
} }
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){ for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
@@ -218,7 +218,7 @@ public class FloorRenderer implements Disposable{
Core.batch = current; Core.batch = current;
cbatch.reserve(layer.capacity * chunksize * chunksize); cbatch.reserve(layer.capacity * chunksize * chunksize);
chunk.caches[layer.ordinal()] = cbatch.endCache(); chunk[layer.ordinal()] = cbatch.endCache();
} }
public void clearTiles(){ public void clearTiles(){
@@ -227,15 +227,14 @@ public class FloorRenderer implements Disposable{
recacheSet.clear(); recacheSet.clear();
int chunksx = Mathf.ceil((float)(world.width()) / chunksize), int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
chunksy = Mathf.ceil((float)(world.height()) / chunksize); chunksy = Mathf.ceil((float)(world.height()) / chunksize);
cache = new Chunk[chunksx][chunksy]; cache = new int[chunksx][chunksy][CacheLayer.all.length];
cbatch = new MultiCacheBatch(chunksize * chunksize * 8); cbatch = new MultiCacheBatch(chunksize * chunksize * 9);
Time.mark(); Time.mark();
for(int x = 0; x < chunksx; x++){ for(int x = 0; x < chunksx; x++){
for(int y = 0; y < chunksy; y++){ for(int y = 0; y < chunksy; y++){
cache[x][y] = new Chunk(); Arrays.fill(cache[x][y], -1);
Arrays.fill(cache[x][y].caches, -1);
cacheChunk(x, y); cacheChunk(x, y);
} }
@@ -251,13 +250,4 @@ public class FloorRenderer implements Disposable{
cbatch = null; cbatch = null;
} }
} }
private static class Chunk{
/** Maps cache layer ID to cache ID in the batch.
* -1 means that this cache is unoccupied. */
int[] caches = new int[CacheLayer.all.length];
Chunk(){
}
}
} }

View File

@@ -257,7 +257,7 @@ public abstract class SaveVersion extends SaveFileReader{
if(hadEntity){ if(hadEntity){
if(isCenter){ //only read entity for center blocks if(isCenter){ //only read entity for center blocks
if(block.hasEntity()){ if(block.hasBuilding()){
try{ try{
readChunk(stream, true, in -> { readChunk(stream, true, in -> {
byte revision = in.readByte(); byte revision = in.readByte();

View File

@@ -61,7 +61,7 @@ public abstract class LegacySaveVersion extends SaveVersion{
tile.setBlock(block); tile.setBlock(block);
} }
if(block.hasEntity()){ if(block.hasBuilding()){
try{ try{
readChunk(stream, true, in -> { readChunk(stream, true, in -> {
byte version = in.readByte(); byte version = in.readByte();

View File

@@ -6,7 +6,8 @@ public enum ConditionOp{
lessThan("<", (a, b) -> a < b), lessThan("<", (a, b) -> a < b),
lessThanEq("<=", (a, b) -> a <= b), lessThanEq("<=", (a, b) -> a <= b),
greaterThan(">", (a, b) -> a > b), greaterThan(">", (a, b) -> a > b),
greaterThanEq(">=", (a, b) -> a >= b); greaterThanEq(">=", (a, b) -> a >= b),
always("always", (a, b) -> true);
public static final ConditionOp[] all = values(); public static final ConditionOp[] all = values();

View File

@@ -1,6 +1,7 @@
package mindustry.logic; package mindustry.logic;
import arc.func.*; import arc.func.*;
import arc.graphics.*;
import arc.scene.style.*; import arc.scene.style.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
@@ -633,6 +634,8 @@ public class LStatements{
@RegisterStatement("jump") @RegisterStatement("jump")
public static class JumpStatement extends LStatement{ public static class JumpStatement extends LStatement{
private static Color last = new Color();
public transient StatementElem dest; public transient StatementElem dest;
public int destIndex; public int destIndex;
@@ -644,19 +647,30 @@ public class LStatements{
public void build(Table table){ public void build(Table table){
table.add("if ").padLeft(4); table.add("if ").padLeft(4);
field(table, value, str -> value = str); last = table.color;
table.table(this::rebuild);
table.button(b -> {
b.label(() -> op.symbol);
b.clicked(() -> showSelect(b, ConditionOp.all, op, o -> op = o));
}, Styles.logict, () -> {}).size(48f, 40f).pad(4f).color(table.color);
field(table, compare, str -> compare = str);
table.add().growX(); table.add().growX();
table.add(new JumpButton(() -> dest, s -> dest = s)).size(30).right().padLeft(-8); table.add(new JumpButton(() -> dest, s -> dest = s)).size(30).right().padLeft(-8);
} }
void rebuild(Table table){
table.clearChildren();
table.setColor(last);
if(op != ConditionOp.always) field(table, value, str -> value = str);
table.button(b -> {
b.label(() -> op.symbol);
b.clicked(() -> showSelect(b, ConditionOp.all, op, o -> {
op = o;
rebuild(table);
}));
}, Styles.logict, () -> {}).size(op == ConditionOp.always ? 80f : 48f, 40f).pad(4f).color(table.color);
if(op != ConditionOp.always) field(table, compare, str -> compare = str);
}
//elements need separate conversion logic //elements need separate conversion logic
@Override @Override
public void setupUI(){ public void setupUI(){

View File

@@ -25,15 +25,15 @@ import static mindustry.Vars.net;
public class CrashSender{ public class CrashSender{
public static String createReport(String error){ public static String createReport(String error){
String report = "Oh no, Mindustry crashed!\n"; String report = "Mindustry has crashed. How unforunate.\n";
if(mods.list().size == 0){ if(mods.list().size == 0 && Version.build != -1){
report += "Please report this at " + Vars.reportIssueURL + "\n\n"; report += "Report this at " + Vars.reportIssueURL + "\n\n";
} }
return report + "Version: " + Version.combined() + (Vars.headless ? " (Server)" : "") + "\n" return report + "Version: " + Version.combined() + (Vars.headless ? " (Server)" : "") + "\n"
+ "OS: " + System.getProperty("os.name") + " x" + (OS.is64Bit ? "64" : "32") + "\n" + "OS: " + System.getProperty("os.name") + " x" + (OS.is64Bit ? "64" : "32") + "\n"
+ "Java Version: " + System.getProperty("java.version") + "\n" + "Java Version: " + System.getProperty("java.version") + "\n"
+ "Java Architecture: " + System.getProperty("sun.arch.data.model") + "\n" + "Java Architecture: " + System.getProperty("sun.arch.data.model") + "\n"
+ mods.list().size + " Mods: " + (mods.list().isEmpty() ? "none" : mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version)) + mods.list().size + " Mods" + (mods.list().isEmpty() ? "" : ": " + mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version))
+ "\n\n" + error; + "\n\n" + error;
} }

View File

@@ -51,6 +51,7 @@ public class UnitType extends UnlockableContent{
public boolean destructibleWreck = true; public boolean destructibleWreck = true;
public float groundLayer = Layer.groundUnit; public float groundLayer = Layer.groundUnit;
public float payloadCapacity = 8; public float payloadCapacity = 8;
public float aimDst = -1f;
public int commandLimit = 24; public int commandLimit = 24;
public float visualElevation = -1f; public float visualElevation = -1f;
public boolean allowLegStep = false; public boolean allowLegStep = false;
@@ -218,6 +219,10 @@ public class UnitType extends UnlockableContent{
mechStride = 4f + (hitSize -8f)/2.1f; mechStride = 4f + (hitSize -8f)/2.1f;
} }
if(aimDst < 0){
aimDst = weapons.contains(w -> !w.rotate) ? hitSize * 2f : hitSize / 2f;
}
if(mechStepShake < 0){ if(mechStepShake < 0){
mechStepShake = Mathf.round((hitSize - 11f) / 9f); mechStepShake = Mathf.round((hitSize - 11f) / 9f);
mechStepParticles = hitSize > 15f; mechStepParticles = hitSize > 15f;

View File

@@ -17,7 +17,7 @@ import java.util.*;
public class FileChooser extends BaseDialog{ public class FileChooser extends BaseDialog{
private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath()); private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
static Fi lastDirectory = homeDirectory; static Fi lastDirectory = Core.files.absolute(Core.settings.getString("lastDirectory", homeDirectory.absolutePath()));
private Table files; private Table files;
Fi directory = lastDirectory; Fi directory = lastDirectory;
@@ -108,7 +108,7 @@ public class FileChooser extends BaseDialog{
ImageButton home = new ImageButton(Icon.home); ImageButton home = new ImageButton(Icon.home);
home.clicked(() -> { home.clicked(() -> {
directory = homeDirectory; directory = homeDirectory;
lastDirectory = directory; setLastDirectory(directory);
updateFiles(true); updateFiles(true);
}); });
@@ -187,7 +187,7 @@ public class FileChooser extends BaseDialog{
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet); TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
upbutton.clicked(() -> { upbutton.clicked(() -> {
directory = directory.parent(); directory = directory.parent();
lastDirectory = directory; setLastDirectory(directory);
updateFiles(true); updateFiles(true);
}); });
@@ -217,7 +217,7 @@ public class FileChooser extends BaseDialog{
updateFileFieldStatus(); updateFileFieldStatus();
}else{ }else{
directory = directory.child(filename); directory = directory.child(filename);
lastDirectory = directory; setLastDirectory(directory);
updateFiles(true); updateFiles(true);
} }
}); });
@@ -242,6 +242,11 @@ public class FileChooser extends BaseDialog{
if(open) filefield.clearText(); if(open) filefield.clearText();
} }
public static void setLastDirectory(Fi directory){
lastDirectory = directory;
Core.settings.put("lastDirectory", directory.absolutePath());
}
private String shorten(String string){ private String shorten(String string){
int max = 30; int max = 30;
if(string.length() <= max){ if(string.length() <= max){
@@ -269,14 +274,14 @@ public class FileChooser extends BaseDialog{
if(!canBack()) return; if(!canBack()) return;
index--; index--;
directory = history.get(index - 1); directory = history.get(index - 1);
lastDirectory = directory; setLastDirectory(directory);
updateFiles(false); updateFiles(false);
} }
public void forward(){ public void forward(){
if(!canForward()) return; if(!canForward()) return;
directory = history.get(index); directory = history.get(index);
lastDirectory = directory; setLastDirectory(directory);
index++; index++;
updateFiles(false); updateFiles(false);
} }

View File

@@ -703,7 +703,7 @@ public class HudFragment extends Fragment{
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad); t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f); t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f);
t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> { t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> {
b.color.set(player.displayAmmo() ? player.dead() ? Pal.ammo : player.unit().type().ammoType.color : Pal.health); b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type().ammoType.color : Pal.health);
}); });
t.getChildren().get(1).toFront(); t.getChildren().get(1).toFront();

View File

@@ -209,6 +209,7 @@ public class Block extends UnlockableContent{
public @Load("@-team") TextureRegion teamRegion; public @Load("@-team") TextureRegion teamRegion;
public TextureRegion[] teamRegions; public TextureRegion[] teamRegions;
//TODO make this not static
public static TextureRegion[][] cracks; public static TextureRegion[][] cracks;
protected static final Seq<Tile> tempTiles = new Seq<>(); protected static final Seq<Tile> tempTiles = new Seq<>();
protected static final Seq<Building> tempTileEnts = new Seq<>(); protected static final Seq<Building> tempTileEnts = new Seq<>();
@@ -499,7 +500,7 @@ public class Block extends UnlockableContent{
return variantRegions; return variantRegions;
} }
public boolean hasEntity(){ public boolean hasBuilding(){
return destructible || update; return destructible || update;
} }

View File

@@ -68,8 +68,13 @@ public class Build{
/** Returns whether a tile can be placed at this location by this team. */ /** Returns whether a tile can be placed at this location by this team. */
public static boolean validPlace(Block type, Team team, int x, int y, int rotation){ public static boolean validPlace(Block type, Team team, int x, int y, int rotation){
return validPlace(type, team, x, y, rotation, true);
}
/** Returns whether a tile can be placed at this location by this team. */
public static boolean validPlace(Block type, Team team, int x, int y, int rotation, boolean checkVisible){
//the wave team can build whatever they want as long as it's visible - banned blocks are not applicable //the wave team can build whatever they want as long as it's visible - banned blocks are not applicable
if(type == null || (!type.isPlaceable() && !(state.rules.waves && team == state.rules.waveTeam && type.isVisible()))){ if(type == null || (checkVisible && (!type.isPlaceable() && !(state.rules.waves && team == state.rules.waveTeam && type.isVisible())))){
return false; return false;
} }

View File

@@ -26,7 +26,7 @@ public class CachedTile extends Tile{
Block block = block(); Block block = block();
if(block.hasEntity()){ if(block.hasBuilding()){
Building n = entityprov.get(); Building n = entityprov.get();
n.cons(new ConsumeModule(build)); n.cons(new ConsumeModule(build));
n.tile(this); n.tile(this);

View File

@@ -508,7 +508,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
} }
} }
if(block.hasEntity()){ if(block.hasBuilding()){
build = entityprov.get().init(this, team, block.update && !state.isEditor(), rotation); build = entityprov.get().init(this, team, block.update && !state.isEditor(), rotation);
} }
} }

View File

@@ -129,6 +129,11 @@ public class LaunchPad extends Block{
@Override @Override
public void buildConfiguration(Table table){ public void buildConfiguration(Table table){
if(!state.isCampaign()){
deselect();
return;
}
table.button(Icon.upOpen, Styles.clearTransi, () -> { table.button(Icon.upOpen, Styles.clearTransi, () -> {
ui.planet.showSelect(state.rules.sector, other -> state.secinfo.destination = other); ui.planet.showSelect(state.rules.sector, other -> state.secinfo.destination = other);
deselect(); deselect();

View File

@@ -14,6 +14,7 @@ import arc.util.io.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.entities.Units.*;
import mindustry.entities.bullet.*; import mindustry.entities.bullet.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
@@ -67,6 +68,7 @@ public abstract class Turret extends Block{
public float coolantMultiplier = 5f; public float coolantMultiplier = 5f;
/** Effect displayed when coolant is used. */ /** Effect displayed when coolant is used. */
public Effect coolEffect = Fx.fuelburn; public Effect coolEffect = Fx.fuelburn;
public Sortf unitSort = Unit::dst2;
protected Vec2 tr = new Vec2(); protected Vec2 tr = new Vec2();
protected Vec2 tr2 = new Vec2(); protected Vec2 tr2 = new Vec2();
@@ -306,9 +308,9 @@ public abstract class Turret extends Block{
protected void findTarget(){ protected void findTarget(){
if(targetAir && !targetGround){ if(targetAir && !targetGround){
target = Units.closestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded()); target = Units.bestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded(), unitSort);
}else{ }else{
target = Units.closestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround)); target = Units.bestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround), b -> true, unitSort);
} }
} }
@@ -397,7 +399,7 @@ public abstract class Turret extends Block{
} }
protected void bullet(BulletType type, float angle){ protected void bullet(BulletType type, float angle){
float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, targetPos.x, targetPos.y) / type.range(), minRange / type.range(), range / type.range()) : 1f; float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(x + tr.x, y + tr.y, targetPos.x, targetPos.y) / type.range(), minRange / type.range(), range / type.range()) : 1f;
type.create(this, team, x + tr.x, y + tr.y, angle, 1f + Mathf.range(velocityInaccuracy), lifeScl); type.create(this, team, x + tr.x, y + tr.y, angle, 1f + Mathf.range(velocityInaccuracy), lifeScl);
} }

View File

@@ -37,7 +37,6 @@ public class PowerNode extends PowerBlock{
public PowerNode(String name){ public PowerNode(String name){
super(name); super(name);
expanded = true;
configurable = true; configurable = true;
consumesPower = false; consumesPower = false;
outputsPower = false; outputsPower = false;
@@ -392,7 +391,7 @@ public class PowerNode extends PowerBlock{
if(!linkValid(this, link)) continue; if(!linkValid(this, link)) continue;
if(link.block instanceof PowerNode && !(link.pos() < tile.pos())) continue; if(link.block instanceof PowerNode && link.id >= id) continue;
drawLaser(team, x, y, link.x, link.y, size, link.block.size); drawLaser(team, x, y, link.x, link.y, size, link.block.size);
} }

View File

@@ -101,7 +101,7 @@ public class CoreBlock extends StorageBlock{
CoreBuild core = team.core(); CoreBuild core = team.core();
//must have all requirements //must have all requirements
if(core == null || (!state.rules.infiniteResources && !core.items.has(requirements))) return false; if(core == null || (!state.rules.infiniteResources && !core.items.has(requirements))) return false;
return canReplace(tile.block()); return tile.block() instanceof CoreBlock && size > tile.block().size;
} }
@Override @Override

View File

@@ -45,6 +45,8 @@ task run(dependsOn: classes, type: JavaExec){
jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true") jvmArgs("-XstartOnFirstThread", "-Djava.awt.headless=true")
} }
jvmArgs += "-XX:+ShowCodeDetailsInExceptionMessages"
/*spriteHashFile.parentFile.mkdirs() /*spriteHashFile.parentFile.mkdirs()
String spriteHash = hashDirectory() String spriteHash = hashDirectory()
if(spriteHashFile.exists() && spriteHashFile.text != spriteHash){ if(spriteHashFile.exists() && spriteHashFile.text != spriteHash){

View File

@@ -0,0 +1,9 @@
This is a small update. Not much new content, mostly bugfixes.
The next planned update will focus on the campaign, and will likely take much longer.
- Bugfixes
- Added team color for command center (Contributed by Voz-Duh)
- Cleaned up certain sprites to match V6 style (Partially contributed by Voz-Duh)
- Added support for Java-based mods on Android (mostly undocumented for now)
- Added 2x2 high capacity memory bank for logic processors
- Balancing