Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features

 Conflicts:
	core/assets/logicids.dat
	core/src/mindustry/content/Blocks.java
	gradle.properties
This commit is contained in:
Anuken
2021-09-28 18:45:09 -04:00
53 changed files with 450 additions and 146 deletions
+3 -3
View File
@@ -17,9 +17,9 @@ jobs:
git tag ${BNUM} git tag ${BNUM}
git config --global user.name "Build Uploader" git config --global user.name "Build Uploader"
git push https://Anuken:${{ secrets.API_TOKEN_GITHUB }}@github.com/Anuken/MindustryBuilds ${BNUM} git push https://Anuken:${{ secrets.API_TOKEN_GITHUB }}@github.com/Anuken/MindustryBuilds ${BNUM}
- name: Set up JDK 16 - name: Set up JDK 17
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 16 java-version: 17
- name: Run unit tests - name: Run unit tests
run: ./gradlew clean cleanTest test run: ./gradlew clean cleanTest test --stacktrace
@@ -0,0 +1 @@
{version:6,fields:[{name:color,type:arc.graphics.Color},{name:data,type:java.lang.Object},{name:effect,type:mindustry.entities.Effect},{name:lifetime,type:float},{name:offsetPos,type:float},{name:offsetRot,type:float},{name:offsetX,type:float},{name:offsetY,type:float},{name:parent,type:mindustry.gen.Posc},{name:rotWithParent,type:boolean},{name:rotation,type:float},{name:time,type:float},{name:x,type:float},{name:y,type:float}]}
+3 -3
View File
@@ -23,8 +23,8 @@ buildscript{
} }
plugins{ plugins{
id 'org.jetbrains.kotlin.jvm' version '1.5.21' id 'org.jetbrains.kotlin.jvm' version '1.5.31'
id "org.jetbrains.kotlin.kapt" version "1.5.21" id "org.jetbrains.kotlin.kapt" version "1.5.31"
} }
allprojects{ allprojects{
@@ -375,7 +375,7 @@ project(":core"){
if(localArc() && debugged()) api arcModule("extensions:recorder") if(localArc() && debugged()) api arcModule("extensions:recorder")
if(localArc()) api arcModule(":extensions:packer") if(localArc()) api arcModule(":extensions:packer")
annotationProcessor 'com.github.Anuken:jabel:34e4c172e65b3928cd9eabe1993654ea79c409cd' annotationProcessor 'com.github.Anuken:jabel:0.6.0'
compileOnly project(":annotations") compileOnly project(":annotations")
kapt project(":annotations") kapt project(":annotations")
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

+5 -1
View File
@@ -379,6 +379,9 @@ 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 editor.center = Center
editor.search = Search Maps...
editor.filters = Filter Maps
editor.showAll = Show Default Maps
workshop = Workshop workshop = Workshop
waves.title = Waves waves.title = Waves
waves.remove = Remove waves.remove = Remove
@@ -1133,6 +1136,7 @@ block.sand-boulder.name = Sand Boulder
block.basalt-boulder.name = Basalt Boulder block.basalt-boulder.name = Basalt Boulder
block.grass.name = Grass block.grass.name = Grass
block.molten-slag.name = Slag block.molten-slag.name = Slag
block.pooled-cryofluid.name = Cryofluid
block.space.name = Space block.space.name = Space
block.salt.name = Salt block.salt.name = Salt
block.salt-wall.name = Salt Wall block.salt-wall.name = Salt Wall
@@ -1613,7 +1617,7 @@ unit.omura.description = Fires a long-range piercing railgun bolt at enemies. Co
unit.alpha.description = Defends the Shard core from enemies. Builds structures. unit.alpha.description = Defends the Shard core from enemies. Builds structures.
unit.beta.description = Defends the Foundation core from enemies. Builds structures. unit.beta.description = Defends the Foundation core from enemies. Builds structures.
unit.gamma.description = Defends the Nucleus core from enemies. Builds structures. unit.gamma.description = Defends the Nucleus core from enemies. Builds structures.
unit.retusa.description = Places proximity mines. Repairs allied units. unit.retusa.description = Fires homing torpedos at nearby enemies. Repairs allied units.
unit.oxynoe.description = Fires structure-repairing streams of flame at nearby enemies. Targets nearby enemy projectiles with a point defense turret. unit.oxynoe.description = Fires structure-repairing streams of flame at nearby enemies. Targets nearby enemy projectiles with a point defense turret.
unit.cyerce.description = Fires seeking cluster-missiles at enemies. Repairs allied units. unit.cyerce.description = Fires seeking cluster-missiles at enemies. Repairs allied units.
unit.aegires.description = Shocks all enemy units and structures that enter its energy field. Repairs all allies. unit.aegires.description = Shocks all enemy units and structures that enter its energy field. Repairs all allies.
+1
View File
@@ -360,3 +360,4 @@
63348=molten-slag|block-molten-slag-ui 63348=molten-slag|block-molten-slag-ui
63347=crater-stone|block-crater-stone-ui 63347=crater-stone|block-crater-stone-ui
63346=deep-tainted-water|block-deep-tainted-water-ui 63346=deep-tainted-water|block-deep-tainted-water-ui
63345=pooled-cryofluid|block-pooled-cryofluid-ui
Binary file not shown.
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
#define HIGHP
//shades of cryofluid
#define S1 vec3(53.0, 83.0, 93.0) / 100.0
#define S2 vec3(68.0, 90.0, 97.0) / 100.0
#define NSCALE 100.0 / 2.0
uniform sampler2D u_texture;
uniform sampler2D u_noise;
uniform vec2 u_campos;
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 + u_campos.x, c.y * u_resolution.y + u_campos.y);
float btime = u_time / 5000.0;
float wave = abs(sin(coords.x * 1.1 + coords.y) + 0.1 * sin(2.5 * coords.x) + 0.15 * sin(3.0 * coords.y)) / 30.0;
float noise = wave + (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.2, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0;
vec4 color = texture2D(u_texture, c);
if(noise > 0.54 && noise < 0.57){
color.rgb = S2;
}else if (noise > 0.49 && noise < 0.62){
color.rgb = S1;
}
gl_FragColor = color;
}
+1 -1
View File
@@ -18,7 +18,7 @@ void main(){
vec2 c = v_texCoords.xy; vec2 c = v_texCoords.xy;
vec2 coords = vec2(c.x * u_resolution.x + u_campos.x, c.y * u_resolution.y + u_campos.y); vec2 coords = vec2(c.x * u_resolution.x + u_campos.x, c.y * u_resolution.y + u_campos.y);
float btime = u_time / 4000.0; float btime = u_time / 5000.0;
float noise = (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0; float noise = (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0;
vec4 color = texture2D(u_texture, c); vec4 color = texture2D(u_texture, c);
+12 -5
View File
@@ -6,6 +6,8 @@ import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.world.*; import mindustry.world.*;
import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Astar{ public class Astar{
@@ -13,7 +15,7 @@ public class Astar{
private static final Seq<Tile> out = new Seq<>(); private static final Seq<Tile> out = new Seq<>();
private static final PQueue<Tile> queue = new PQueue<>(200 * 200 / 4, (a, b) -> 0); private static final PQueue<Tile> queue = new PQueue<>(200 * 200 / 4, (a, b) -> 0);
private static final IntFloatMap costs = new IntFloatMap(); private static float[] costs;
private static byte[][] rotations; private static byte[][] rotations;
public static Seq<Tile> pathfind(Tile from, Tile to, TileHueristic th, Boolf<Tile> passable){ public static Seq<Tile> pathfind(Tile from, Tile to, TileHueristic th, Boolf<Tile> passable){
@@ -32,9 +34,14 @@ public class Astar{
GridBits closed = new GridBits(tiles.width, tiles.height); GridBits closed = new GridBits(tiles.width, tiles.height);
costs.clear(); if(costs == null || costs.length != tiles.width * tiles.height){
costs = new float[tiles.width * tiles.height];
}
Arrays.fill(costs, 0);
queue.clear(); queue.clear();
queue.comparator = Structs.comparingFloat(a -> costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y)); queue.comparator = Structs.comparingFloat(a -> costs[a.array()] + dh.cost(a.x, a.y, end.x, end.y));
queue.add(start); queue.add(start);
if(rotations == null || rotations.length != world.width() || rotations[0].length != world.height()){ if(rotations == null || rotations.length != world.width() || rotations[0].length != world.height()){
rotations = new byte[world.width()][world.height()]; rotations = new byte[world.width()][world.height()];
@@ -43,7 +50,7 @@ public class Astar{
boolean found = false; boolean found = false;
while(!queue.empty()){ while(!queue.empty()){
Tile next = queue.poll(); Tile next = queue.poll();
float baseCost = costs.get(next.pos(), 0f); float baseCost = costs[next.array()];
if(next == end){ if(next == end){
found = true; found = true;
break; break;
@@ -58,7 +65,7 @@ public class Astar{
if(!closed.get(child.x, child.y)){ if(!closed.get(child.x, child.y)){
closed.set(child.x, child.y); closed.set(child.x, child.y);
rotations[child.x][child.y] = child.relativeTo(next.x, next.y); rotations[child.x][child.y] = child.relativeTo(next.x, next.y);
costs.put(child.pos(), newCost); costs[child.array()] = newCost;
queue.add(child); queue.add(child);
} }
} }
@@ -76,6 +76,8 @@ public class SoundControl{
sound.setBus(uiBus); sound.setBus(uiBus);
} }
} }
Events.fire(new MusicRegisterEvent());
} }
public void loop(Sound sound, float volume){ public void loop(Sound sound, float volume){
+18 -1
View File
@@ -35,7 +35,7 @@ public class Blocks implements ContentList{
public static Block public static Block
//environment //environment
air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty, air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
dacite, rhyolite, rhyoliteCrater, regolith, yellowStone, redIce, dacite, rhyolite, rhyoliteCrater, regolith, yellowStone, redIce,
redmat, bluemat, redmat, bluemat,
stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
@@ -210,6 +210,22 @@ public class Blocks implements ContentList{
cacheLayer = CacheLayer.tar; cacheLayer = CacheLayer.tar;
}}; }};
cryofluid = new Floor("pooled-cryofluid"){{
drownTime = 150f;
status = StatusEffects.freezing;
statusDuration = 240f;
speedMultiplier = 0.5f;
variants = 0;
liquidDrop = Liquids.cryofluid;
liquidMultiplier = 0.5f;
isLiquid = true;
cacheLayer = CacheLayer.cryofluid;
emitLight = true;
lightRadius = 25f;
lightColor = Color.cyan.cpy().a(0.19f);
}};
slag = new Floor("molten-slag"){{ slag = new Floor("molten-slag"){{
drownTime = 230f; drownTime = 230f;
status = StatusEffects.melting; status = StatusEffects.melting;
@@ -1060,6 +1076,7 @@ public class Blocks implements ContentList{
}}; }};
thruster = new Thruster("thruster"){{ thruster = new Thruster("thruster"){{
requirements(Category.defense, BuildVisibility.sandboxOnly, with(Items.scrap, 96));
health = 55 * 16 * wallHealthMultiplier; health = 55 * 16 * wallHealthMultiplier;
size = 4; size = 4;
}}; }};
+4 -4
View File
@@ -369,13 +369,13 @@ public class Fx{
Fill.circle(e.x, e.y, e.fin() * 10); Fill.circle(e.x, e.y, e.fin() * 10);
Drawf.light(e.x, e.y, e.fin() * 20f, Pal.heal, 0.7f); Drawf.light(e.x, e.y, e.fin() * 20f, Pal.heal, 0.7f);
}).followParent(true), }).followParent(true).rotWithParent(true),
greenLaserChargeSmall = new Effect(40f, 100f, e -> { greenLaserChargeSmall = new Effect(40f, 100f, e -> {
color(Pal.heal); color(Pal.heal);
stroke(e.fin() * 2f); stroke(e.fin() * 2f);
Lines.circle(e.x, e.y, e.fout() * 50f); Lines.circle(e.x, e.y, e.fout() * 50f);
}).followParent(true), }).followParent(true).rotWithParent(true),
greenCloud = new Effect(80f, e -> { greenCloud = new Effect(80f, e -> {
color(Pal.heal); color(Pal.heal);
@@ -1975,7 +1975,7 @@ public class Fx{
} }
Lines.endLine(); Lines.endLine();
}).followParent(false), }).followParent(false).rotWithParent(false),
chainEmp = new Effect(30f, 300f, e -> { chainEmp = new Effect(30f, 300f, e -> {
if(!(e.data instanceof Position p)) return; if(!(e.data instanceof Position p)) return;
@@ -2012,5 +2012,5 @@ public class Fx{
} }
Lines.endLine(); Lines.endLine();
}).followParent(false); }).followParent(false).rotWithParent(false);
} }
+18 -9
View File
@@ -1787,7 +1787,6 @@ public class UnitTypes implements ContentList{
//endregion //endregion
//region naval support //region naval support
retusa = new UnitType("retusa"){{ retusa = new UnitType("retusa"){{
defaultController = HugAI::new;
speed = 0.9f; speed = 0.9f;
targetAir = false; targetAir = false;
drag = 0.14f; drag = 0.14f;
@@ -1821,15 +1820,17 @@ public class UnitTypes implements ContentList{
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
mirror = false; mirror = false;
reload = 80f; rotate = true;
reload = 90f;
shots = 3; shots = 3;
shotDelay = 7f; shotDelay = 7f;
x = y = shootX = shootY = 0f; x = y = shootX = shootY = 0f;
shootSound = Sounds.mineDeploy; shootSound = Sounds.mineDeploy;
rotateSpeed = 180f;
bullet = new BasicBulletType(){{ bullet = new BasicBulletType(){{
sprite = "mine-bullet"; sprite = "mine-bullet";
width = height = 11f; width = height = 8f;
layer = Layer.scorch; layer = Layer.scorch;
shootEffect = smokeEffect = Fx.none; shootEffect = smokeEffect = Fx.none;
@@ -1843,23 +1844,31 @@ public class UnitTypes implements ContentList{
hitSound = Sounds.plasmaboom; hitSound = Sounds.plasmaboom;
shootCone = 360f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
hitSize = 22f; hitSize = 22f;
collidesAir = false; collidesAir = false;
lifetime = 500f; lifetime = 87f;
hitEffect = new MultiEffect(Fx.blastExplosion, Fx.greenCloud); hitEffect = new MultiEffect(Fx.blastExplosion, Fx.greenCloud);
keepVelocity = false; keepVelocity = false;
shrinkX = shrinkY = 0f; shrinkX = shrinkY = 0f;
speed = 0f; inaccuracy = 2f;
weaveMag = 5f;
weaveScale = 4f;
speed = 0.7f;
drag = -0.017f;
homingPower = 0.05f;
collideFloor = true;
trailColor = Pal.heal;
trailWidth = 3f;
trailLength = 8;
splashDamage = 55f; splashDamage = 33f;
splashDamageRadius = 45f; splashDamageRadius = 32f;
}}; }};
}}); }});
}}; }};
@@ -1934,7 +1943,7 @@ public class UnitTypes implements ContentList{
shootEffect = Fx.sparkShoot; shootEffect = Fx.sparkShoot;
hitEffect = Fx.pointHit; hitEffect = Fx.pointHit;
maxRange = 100f; maxRange = 100f;
damage = 15f; damage = 17f;
}}; }};
}}); }});
+2
View File
@@ -16,6 +16,8 @@ public class GameState{
public int wave = 1; public int wave = 1;
/** Wave countdown in ticks. */ /** Wave countdown in ticks. */
public float wavetime; public float wavetime;
/** Logic tick. */
public double tick;
/** Whether the game is in game over state. */ /** Whether the game is in game over state. */
public boolean gameOver = false, serverPaused = false; public boolean gameOver = false, serverPaused = false;
/** Server ticks/second. Only valid in multiplayer. */ /** Server ticks/second. Only valid in multiplayer. */
+3
View File
@@ -370,6 +370,9 @@ public class Logic implements ApplicationListener{
} }
if(!state.isPaused()){ if(!state.isPaused()){
float delta = Core.graphics.getDeltaTime();
state.tick += Float.isNaN(delta) || Float.isInfinite(delta) ? 0f : delta * 60f;
state.teams.updateTeamStats(); state.teams.updateTeamStats();
if(state.isCampaign()){ if(state.isCampaign()){
+7 -1
View File
@@ -19,6 +19,7 @@ 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.logic.*;
import mindustry.net.Administration.*; import mindustry.net.Administration.*;
import mindustry.net.*; import mindustry.net.*;
import mindustry.net.Packets.*; import mindustry.net.Packets.*;
@@ -452,7 +453,7 @@ public class NetClient implements ApplicationListener{
} }
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, byte tps, byte[] coreData){ public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, byte tps, long rand0, long rand1, byte[] coreData){
try{ try{
if(wave > state.wave){ if(wave > state.wave){
state.wave = wave; state.wave = wave;
@@ -466,6 +467,11 @@ public class NetClient implements ApplicationListener{
state.serverPaused = paused; state.serverPaused = paused;
state.serverTps = tps & 0xff; state.serverTps = tps & 0xff;
//note that this is far from a guarantee that random state is synced - tiny changes in delta and ping can throw everything off again.
//syncing will only make much of a difference when rand() is called infrequently
GlobalConstants.rand.seed0 = rand0;
GlobalConstants.rand.seed1 = rand1;
universe.updateNetSeconds(timeData); universe.updateNetSeconds(timeData);
netClient.byteStream.setBytes(coreData); netClient.byteStream.setBytes(coreData);
+3 -1
View File
@@ -19,6 +19,7 @@ import mindustry.game.*;
import mindustry.game.Teams.*; import mindustry.game.Teams.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.net.*; import mindustry.net.*;
import mindustry.net.Administration.*; import mindustry.net.Administration.*;
import mindustry.net.Packets.*; import mindustry.net.Packets.*;
@@ -867,7 +868,8 @@ public class NetServer implements ApplicationListener{
dataStream.close(); dataStream.close();
//write basic state data. //write basic state data.
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, universe.seconds(), tps, syncStream.toByteArray()); Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver,
universe.seconds(), tps, GlobalConstants.rand.seed0, GlobalConstants.rand.seed1, syncStream.toByteArray());
syncStream.reset(); syncStream.reset();
+19 -2
View File
@@ -30,8 +30,12 @@ public class Effect{
public float lifetime = 50f; public float lifetime = 50f;
/** Clip size. */ /** Clip size. */
public float clip; public float clip;
/** Amount added to rotation */
public float baseRotation;
/** If true, parent unit is data are followed. */ /** If true, parent unit is data are followed. */
public boolean followParent; public boolean followParent;
/** If this and followParent are true, the effect will offset and rotate with the parent's rotation. */
public boolean rotWithParent;
public float layer = Layer.effect; public float layer = Layer.effect;
public float layerDuration; public float layerDuration;
@@ -61,11 +65,21 @@ public class Effect{
return this; return this;
} }
public Effect rotWithParent(boolean follow){
rotWithParent = follow;
return this;
}
public Effect layer(float l){ public Effect layer(float l){
layer = l; layer = l;
return this; return this;
} }
public Effect baseRotation(float d){
baseRotation = d;
return this;
}
public Effect layer(float l, float duration){ public Effect layer(float l, float duration){
layer = l; layer = l;
this.layerDuration = duration; this.layerDuration = duration;
@@ -156,12 +170,15 @@ public class Effect{
EffectState entity = EffectState.create(); EffectState entity = EffectState.create();
entity.effect = effect; entity.effect = effect;
entity.rotation = rotation; entity.rotation = effect.baseRotation + rotation;
entity.data = data; entity.data = data;
entity.lifetime = effect.lifetime; entity.lifetime = effect.lifetime;
entity.set(x, y); entity.set(x, y);
entity.color.set(color); entity.color.set(color);
if(effect.followParent && data instanceof Posc p) entity.parent = p; if(effect.followParent && data instanceof Posc p){
entity.parent = p;
entity.rotWithParent = effect.rotWithParent;
}
entity.add(); entity.add();
} }
} }
@@ -1,6 +1,7 @@
package mindustry.entities.abilities; package mindustry.entities.abilities;
import arc.*; import arc.*;
import arc.math.*;
import arc.util.*; import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
@@ -12,6 +13,7 @@ public class StatusFieldAbility extends Ability{
public float duration = 60, reload = 100, range = 20; public float duration = 60, reload = 100, range = 20;
public Effect applyEffect = Fx.none; public Effect applyEffect = Fx.none;
public Effect activeEffect = Fx.overdriveWave; public Effect activeEffect = Fx.overdriveWave;
public float effectX, effectY;
public boolean parentizeEffects; public boolean parentizeEffects;
protected float timer; protected float timer;
@@ -40,7 +42,8 @@ public class StatusFieldAbility extends Ability{
applyEffect.at(other, parentizeEffects); applyEffect.at(other, parentizeEffects);
}); });
activeEffect.at(unit, parentizeEffects); float x = unit.x + Angles.trnsx(unit.rotation, effectY, effectX), y = unit.y + Angles.trnsy(unit.rotation, effectY, effectX);
activeEffect.at(x, y, unit.rotation, parentizeEffects ? unit : null);
timer = 0f; timer = 0f;
} }
@@ -91,6 +91,10 @@ public class BulletType extends Content implements Cloneable{
public boolean collidesAir = true, collidesGround = true; public boolean collidesAir = true, collidesGround = true;
/** Whether this bullet types collides with anything at all. */ /** Whether this bullet types collides with anything at all. */
public boolean collides = true; public boolean collides = true;
/** If true, this projectile collides with non-surface floors. */
public boolean collideFloor = false;
/** If true, this projectile collides with static walls */
public boolean collideTerrain = false;
/** Whether velocity is inherited from the shooter. */ /** Whether velocity is inherited from the shooter. */
public boolean keepVelocity = true; public boolean keepVelocity = true;
/** Whether to scale lifetime (not actually velocity!) to disappear at the target position. Used for artillery. */ /** Whether to scale lifetime (not actually velocity!) to disappear at the target position. Used for artillery. */
@@ -1037,7 +1037,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
int amount = Math.min(items.get(item), explosionItemCap()); int amount = Math.min(items.get(item), explosionItemCap());
explosiveness += item.explosiveness * amount; explosiveness += item.explosiveness * amount;
flammability += item.flammability * amount; flammability += item.flammability * amount;
power += item.charge * amount * 100f; power += item.charge * Mathf.pow(amount, 1.1f) * 150f;
} }
} }
@@ -6,12 +6,15 @@ import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.core.*; import mindustry.core.*;
import mindustry.entities.bullet.*; import mindustry.entities.bullet.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.game.Teams.*; import mindustry.game.Teams.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.world.*;
import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -137,6 +140,20 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
while(x >= 0 && y >= 0 && x < ww && y < wh){ while(x >= 0 && y >= 0 && x < ww && y < wh){
Building build = world.build(x, y); Building build = world.build(x, y);
if(type.collideFloor || type.collideTerrain){
Tile tile = world.tile(x, y);
if(
type.collideFloor && (tile == null || tile.floor().hasSurface() || tile.block() != Blocks.air) ||
type.collideTerrain && tile != null && tile.block() instanceof StaticWall
){
type.despawned(self());
remove();
hit = true;
return;
}
}
if(build != null && isAdded() && build.collide(self()) && type.testCollision(self(), build) if(build != null && isAdded() && build.collide(self()) && type.testCollision(self(), build)
&& !build.dead() && (type.collidesTeam || build.team != team) && !(type.pierceBuilding && hasCollided(build.id))){ && !build.dead() && (type.collidesTeam || build.team != team) && !(type.pierceBuilding && hasCollided(build.id))){
@@ -1,29 +1,41 @@
package mindustry.entities.comp; package mindustry.entities.comp;
import arc.math.*;
import arc.util.*; import arc.util.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.gen.*; import mindustry.gen.*;
@Component @Component
abstract class ChildComp implements Posc{ abstract class ChildComp implements Posc, Rotc{
@Import float x, y; @Import float x, y, rotation;
@Nullable Posc parent; @Nullable Posc parent;
float offsetX, offsetY; boolean rotWithParent;
float offsetX, offsetY, offsetPos, offsetRot;
@Override @Override
public void add(){ public void add(){
if(parent != null){ if(parent != null){
offsetX = x - parent.getX(); offsetX = x - parent.getX();
offsetY = y - parent.getY(); offsetY = y - parent.getY();
if(rotWithParent && parent instanceof Rotc r){
offsetPos = -r.rotation();
offsetRot = rotation - r.rotation();
}
} }
} }
@Override @Override
public void update(){ public void update(){
if(parent != null){ if(parent != null){
x = parent.getX() + offsetX; if(rotWithParent && parent instanceof Rotc r){
y = parent.getY() + offsetY; x = parent.getX() + Angles.trnsx(r.rotation() + offsetPos, offsetX, offsetY);
y = parent.getY() + Angles.trnsy(r.rotation() + offsetPos, offsetX, offsetY);
rotation = r.rotation() + offsetRot;
}else{
x = parent.getX() + offsetX;
y = parent.getY() + offsetY;
}
} }
} }
} }
@@ -482,7 +482,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f; float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f;
float flammability = item().flammability * stack().amount / 1.9f; float flammability = item().flammability * stack().amount / 1.9f;
float power = item().charge * stack().amount * 150f; float power = item().charge * Mathf.pow(stack().amount, 1.11f) * 160f;
if(!spawnedByCore){ if(!spawnedByCore){
Damage.dynamicExplosion(x, y, flammability, explosiveness, power, bounds() / 2f, state.rules.damageExplosions, item().flammability > 1, team, type.deathExplosionEffect); Damage.dynamicExplosion(x, y, flammability, explosiveness, power, bounds() / 2f, state.rules.damageExplosions, item().flammability > 1, team, type.deathExplosionEffect);
+2
View File
@@ -70,6 +70,8 @@ public class EventType{
public static class ContentInitEvent{} public static class ContentInitEvent{}
/** Called when the client game is first loaded. */ /** Called when the client game is first loaded. */
public static class ClientLoadEvent{} public static class ClientLoadEvent{}
/** Called after SoundControl registers its music. */
public static class MusicRegisterEvent{}
/** Called *after* all the modded files have been added into Vars.tree */ /** Called *after* all the modded files have been added into Vars.tree */
public static class FileTreeInitEvent{} public static class FileTreeInitEvent{}
/** Called when a game begins and the world is loaded. */ /** Called when a game begins and the world is loaded. */
@@ -117,10 +117,30 @@ public class BlockRenderer{
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
} }
invalidateTile(event.tile);
recordIndex(event.tile); recordIndex(event.tile);
}); });
} }
public void invalidateTile(Tile tile){
int avgx = (int)(camera.position.x / tilesize);
int avgy = (int)(camera.position.y / tilesize);
int rangex = (int)(camera.width / tilesize / 2) + 3;
int rangey = (int)(camera.height / tilesize / 2) + 3;
if(Math.abs(avgx - tile.x) <= rangex && Math.abs(avgy - tile.y) <= rangey){
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
}
}
public void removeFloorIndex(Tile tile){
if(indexFloor(tile)) floorTree.remove(tile);
}
public void addFloorIndex(Tile tile){
if(indexFloor(tile)) floorTree.insert(tile);
}
boolean indexBlock(Tile tile){ boolean indexBlock(Tile tile){
var block = tile.block(); var block = tile.block();
return tile.isCenter() && block != Blocks.air && block.cacheLayer == CacheLayer.normal; return tile.isCenter() && block != Blocks.air && block.cacheLayer == CacheLayer.normal;
+2 -1
View File
@@ -10,7 +10,7 @@ import static mindustry.Vars.*;
public class CacheLayer{ public class CacheLayer{
public static CacheLayer public static CacheLayer
water, mud, tar, slag, space, normal, walls; water, mud, cryofluid, tar, slag, space, normal, walls;
public static CacheLayer[] all = {}; public static CacheLayer[] all = {};
@@ -37,6 +37,7 @@ public class CacheLayer{
mud = new ShaderLayer(Shaders.mud), mud = new ShaderLayer(Shaders.mud),
tar = new ShaderLayer(Shaders.tar), tar = new ShaderLayer(Shaders.tar),
slag = new ShaderLayer(Shaders.slag), slag = new ShaderLayer(Shaders.slag),
cryofluid = new ShaderLayer(Shaders.cryofluid),
space = new ShaderLayer(Shaders.space), space = new ShaderLayer(Shaders.space),
normal = new CacheLayer(), normal = new CacheLayer(),
walls = new CacheLayer() walls = new CacheLayer()
+2 -1
View File
@@ -21,7 +21,7 @@ public class Shaders{
public static UnitBuildShader build; public static UnitBuildShader build;
public static DarknessShader darkness; public static DarknessShader darkness;
public static LightShader light; public static LightShader light;
public static SurfaceShader water, mud, tar, slag, space, caustics; public static SurfaceShader water, mud, tar, slag, cryofluid, space, caustics;
public static PlanetShader planet; public static PlanetShader planet;
public static CloudShader clouds; public static CloudShader clouds;
public static PlanetGridShader planetGrid; public static PlanetGridShader planetGrid;
@@ -48,6 +48,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");
cryofluid = new SurfaceShader("cryofluid");
space = new SpaceShader("space"); space = new SpaceShader("space");
caustics = new SurfaceShader("caustics"){ caustics = new SurfaceShader("caustics"){
@Override @Override
+2
View File
@@ -92,6 +92,7 @@ public abstract class SaveVersion extends SaveFileReader{
"build", Version.build, "build", Version.build,
"mapname", state.map.name(), "mapname", state.map.name(),
"wave", state.wave, "wave", state.wave,
"tick", state.tick,
"wavetime", state.wavetime, "wavetime", state.wavetime,
"stats", JsonIO.write(state.stats), "stats", JsonIO.write(state.stats),
"rules", JsonIO.write(state.rules), "rules", JsonIO.write(state.rules),
@@ -110,6 +111,7 @@ public abstract class SaveVersion extends SaveFileReader{
state.wave = map.getInt("wave"); state.wave = map.getInt("wave");
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing); state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
state.tick = map.getFloat("tick");
state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}")); state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}"));
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
if(state.rules.spawns.isEmpty()) state.rules.spawns = waves.get(); if(state.rules.spawns.isEmpty()) state.rules.spawns = waves.get();
@@ -2,6 +2,7 @@ package mindustry.logic;
import arc.*; import arc.*;
import arc.files.*; import arc.files.*;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.*; import mindustry.*;
@@ -18,6 +19,8 @@ import java.io.*;
public class GlobalConstants{ public class GlobalConstants{
public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3; public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3;
public static final ContentType[] lookableContent = {ContentType.block, ContentType.unit, ContentType.item, ContentType.liquid}; public static final ContentType[] lookableContent = {ContentType.block, ContentType.unit, ContentType.item, ContentType.liquid};
/** Global random state. */
public static final Rand rand = new Rand();
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>(); private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
private Seq<Var> vars = new Seq<>(Var.class); private Seq<Var> vars = new Seq<>(Var.class);
+6 -4
View File
@@ -1,6 +1,7 @@
package mindustry.logic; package mindustry.logic;
import arc.*; import arc.*;
import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
@@ -56,9 +57,10 @@ public class LExecutor{
/** Runs a single instruction. */ /** Runs a single instruction. */
public void runOnce(){ public void runOnce(){
//set time //set up time; note that @time is now only updated once every invocation and directly based off of @tick.
vars[varTime].numval = Time.millis(); //having time be based off of user system time was a very bad idea.
vars[varTick].numval = Time.time; vars[varTime].numval = state.tick / 60.0 * 1000.0;
vars[varTick].numval = state.tick;
//reset to start //reset to start
if(vars[varCounter].numval >= instructions.length || vars[varCounter].numval < 0){ if(vars[varCounter].numval >= instructions.length || vars[varCounter].numval < 0){
@@ -449,7 +451,7 @@ public class LExecutor{
case build -> { case build -> {
if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block && block.canBeBuilt()){ if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block && block.canBeBuilt()){
int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize); int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize);
int rot = exec.numi(p4); int rot = Mathf.mod(exec.numi(p4), 4);
//reset state of last request when necessary //reset state of last request when necessary
if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || unit.plans.isEmpty()){ if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || unit.plans.isEmpty()){
+2 -2
View File
@@ -34,13 +34,13 @@ public enum LogicOp{
angle("angle", true, (x, y) -> Angles.angle((float)x, (float)y)), angle("angle", true, (x, y) -> Angles.angle((float)x, (float)y)),
len("len", true, (x, y) -> Mathf.dst((float)x, (float)y)), len("len", true, (x, y) -> Mathf.dst((float)x, (float)y)),
noise("noise", true, (x, y) -> Simplex.raw2d(0, x, y)), noise("noise", true, (x, y) -> Simplex.raw2d(0, x, y)),
abs("abs", a -> Math.abs(a)), abs("abs", a -> Math.abs(a)), //not a method reference because it fails to compile for some reason
log("log", Math::log), log("log", Math::log),
log10("log10", Math::log10), log10("log10", Math::log10),
floor("floor", Math::floor), floor("floor", Math::floor),
ceil("ceil", Math::ceil), ceil("ceil", Math::ceil),
sqrt("sqrt", Math::sqrt), sqrt("sqrt", Math::sqrt),
rand("rand", d -> Mathf.rand.nextDouble() * d), rand("rand", d -> GlobalConstants.rand.nextDouble() * d),
sin("sin", d -> Math.sin(d * Mathf.doubleDegRad)), sin("sin", d -> Math.sin(d * Mathf.doubleDegRad)),
cos("cos", d -> Math.cos(d * Mathf.doubleDegRad)), cos("cos", d -> Math.cos(d * Mathf.doubleDegRad)),
@@ -262,9 +262,36 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
for(Room room : roomseq){ for(Room room : roomseq){
spawn.connect(room); spawn.connect(room);
} }
Room fspawn = spawn; Room fspawn = spawn;
cells(1); cells(1);
//shoreline setup
int deepRadius = 4;
pass((x, y) -> {
if(floor.asFloor().isLiquid && !floor.asFloor().isDeep()){
for(int cx = -deepRadius; cx <= deepRadius; cx++){
for(int cy = -deepRadius; cy <= deepRadius; cy++){
if((cx) * (cx) + (cy) * (cy) <= deepRadius * deepRadius){
int wx = cx + x, wy = cy + y;
Tile tile = tiles.get(wx, wy);
if(tile != null && (!tile.floor().isLiquid || tile.block() != Blocks.air)){
//found something solid, skip replacing anything
return;
}
}
}
}
floor = floor == Blocks.darksandTaintedWater ? Blocks.taintedWater : Blocks.water;
}
});
distort(10f, 6f); distort(10f, 6f);
//rivers //rivers
@@ -286,7 +313,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
floor = spore ? floor = spore ?
(deep ? Blocks.taintedWater : Blocks.darksandTaintedWater) : (deep ? Blocks.taintedWater : Blocks.darksandTaintedWater) :
(deep ? Blocks.water : (deep ? Blocks.water :
(floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandWater)); (floor == Blocks.sand || floor == Blocks.salt ? Blocks.sandWater : Blocks.darksandWater));
} }
} }
}); });
+7
View File
@@ -9,6 +9,7 @@ import mindustry.ctype.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.logic.*;
import mindustry.maps.Map; import mindustry.maps.Map;
import mindustry.net.Administration.*; import mindustry.net.Administration.*;
@@ -40,6 +41,9 @@ public class NetworkIO{
stream.writeInt(state.wave); stream.writeInt(state.wave);
stream.writeFloat(state.wavetime); stream.writeFloat(state.wavetime);
stream.writeDouble(state.tick);
stream.writeLong(GlobalConstants.rand.seed0);
stream.writeLong(GlobalConstants.rand.seed1);
stream.writeInt(player.id); stream.writeInt(player.id);
player.write(Writes.get(stream)); player.write(Writes.get(stream));
@@ -61,6 +65,9 @@ public class NetworkIO{
state.wave = stream.readInt(); state.wave = stream.readInt();
state.wavetime = stream.readFloat(); state.wavetime = stream.readFloat();
state.tick = stream.readDouble();
GlobalConstants.rand.seed0 = stream.readLong();
GlobalConstants.rand.seed1 = stream.readLong();
Groups.clear(); Groups.clear();
int id = stream.readInt(); int id = stream.readInt();
@@ -166,6 +166,7 @@ public class GameService{
if(campaign()){ if(campaign()){
if(unitsBuilt.add(e.unit.type.name)){ if(unitsBuilt.add(e.unit.type.name)){
SStat.unitTypesBuilt.set(content.units().count(u -> unitsBuilt.contains(u.name) && !u.isHidden())); SStat.unitTypesBuilt.set(content.units().count(u -> unitsBuilt.contains(u.name) && !u.isHidden()));
save();
} }
if(t5s.contains(e.unit.type)){ if(t5s.contains(e.unit.type)){
+3 -1
View File
@@ -33,6 +33,8 @@ public class StatusEffect extends UnlockableContent{
public float damage; public float damage;
/** Chance of effect appearing. */ /** Chance of effect appearing. */
public float effectChance = 0.15f; public float effectChance = 0.15f;
/** Should the effect be given a parent */
public boolean parentizeEffect;
/** If true, the effect never disappears. */ /** If true, the effect never disappears. */
public boolean permanent; public boolean permanent;
/** If true, this effect will only react with other effects and cannot be applied. */ /** If true, this effect will only react with other effects and cannot be applied. */
@@ -120,7 +122,7 @@ public class StatusEffect extends UnlockableContent{
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){ if(effect != Fx.none && Mathf.chanceDelta(effectChance)){
Tmp.v1.rnd(Mathf.range(unit.type.hitSize/2f)); Tmp.v1.rnd(Mathf.range(unit.type.hitSize/2f));
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, color); effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, 0, color, parentizeEffect ? unit : null);
} }
} }
+15 -15
View File
@@ -200,6 +200,18 @@ public class Weapon implements Cloneable{
boolean can = unit.canShoot(); boolean can = unit.canShoot();
mount.reload = Math.max(mount.reload - Time.delta * unit.reloadMultiplier, 0); mount.reload = Math.max(mount.reload - Time.delta * unit.reloadMultiplier, 0);
//rotate if applicable
if(rotate && (mount.rotate || mount.shoot) && can){
float axisX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
axisY = unit.y + Angles.trnsy(unit.rotation - 90, x, y);
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - unit.rotation;
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, rotateSpeed * Time.delta);
}else if(!rotate){
mount.rotation = 0;
mount.targetRotation = unit.angleTo(mount.aimX, mount.aimY);
}
float float
weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0), weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0),
mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y), mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
@@ -256,7 +268,7 @@ public class Weapon implements Cloneable{
} }
}else{ }else{
//heat decreases when not firing //heat decreases when not firing
mount.heat = Math.max(mount.heat - Time.delta * unit.reloadMultiplier / mount.weapon.cooldownTime, 0); mount.heat = Math.max(mount.heat - Time.delta * unit.reloadMultiplier / cooldownTime, 0);
if(mount.sound != null){ if(mount.sound != null){
mount.sound.update(bulletX, bulletY, false); mount.sound.update(bulletX, bulletY, false);
@@ -270,26 +282,14 @@ public class Weapon implements Cloneable{
mount.side = !mount.side; mount.side = !mount.side;
} }
//rotate if applicable
if(rotate && (mount.rotate || mount.shoot) && can){
float axisX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
axisY = unit.y + Angles.trnsy(unit.rotation - 90, x, y);
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - unit.rotation;
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, rotateSpeed * Time.delta);
}else if(!rotate){
mount.rotation = 0;
mount.targetRotation = unit.angleTo(mount.aimX, mount.aimY);
}
//shoot if applicable //shoot if applicable
if(mount.shoot && //must be shooting if(mount.shoot && //must be shooting
can && //must be able to shoot can && //must be able to shoot
(!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo (!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo
(!alternate || mount.side == flipSprite) && (!alternate || mount.side == flipSprite) &&
unit.vel.len() >= mount.weapon.minShootVelocity && //check velocity requirements unit.vel.len() >= minShootVelocity && //check velocity requirements
mount.reload <= 0.0001f && //reload has to be 0 mount.reload <= 0.0001f && //reload has to be 0
Angles.within(rotate ? mount.rotation : unit.rotation, mount.targetRotation, mount.weapon.shootCone) //has to be within the cone Angles.within(rotate ? mount.rotation : unit.rotation, mount.targetRotation, shootCone) //has to be within the cone
){ ){
shoot(unit, mount, bulletX, bulletY, mount.aimX, mount.aimY, mountX, mountY, shootAngle, Mathf.sign(x)); shoot(unit, mount, bulletX, bulletY, mount.aimX, mount.aimY, mountX, mountY, shootAngle, Mathf.sign(x));
+96 -14
View File
@@ -2,11 +2,14 @@ package mindustry.ui.dialogs;
import arc.*; import arc.*;
import arc.graphics.*; import arc.graphics.*;
import arc.scene.style.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.*; import mindustry.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.io.*; import mindustry.io.*;
@@ -17,6 +20,12 @@ import static mindustry.Vars.*;
public class MapsDialog extends BaseDialog{ public class MapsDialog extends BaseDialog{
private BaseDialog dialog; private BaseDialog dialog;
private String searchString;
private Seq<Gamemode> modes = new Seq<>();
private Table mapTable = new Table();
private TextField searchField;
private boolean showAll = Core.settings.getBool("editorShowAllMaps", true);
public MapsDialog(){ public MapsDialog(){
super("@maps"); super("@maps");
@@ -37,8 +46,10 @@ public class MapsDialog extends BaseDialog{
void setup(){ void setup(){
buttons.clearChildren(); buttons.clearChildren();
searchString = null;
if(Core.graphics.isPortrait()){ if(Core.graphics.isPortrait()){
buttons.button("@back", Icon.left, this::hide).size(210f*2f, 64f).colspan(2); buttons.button("@back", Icon.left, this::hide).size(210f * 2f, 64f).colspan(2);
buttons.row(); buttons.row();
}else{ }else{
buttons.button("@back", Icon.left, this::hide).size(210f, 64f); buttons.button("@back", Icon.left, this::hide).size(210f, 64f);
@@ -108,26 +119,58 @@ public class MapsDialog extends BaseDialog{
}); });
}).size(210f, 64f); }).size(210f, 64f);
cont.clear(); cont.clear();
Table maps = new Table(); rebuildMaps();
maps.marginRight(24);
ScrollPane pane = new ScrollPane(maps); ScrollPane pane = new ScrollPane(mapTable);
pane.setFadeScrollBars(false); pane.setFadeScrollBars(false);
Table search = new Table();
search.image(Icon.zoom);
searchField = search.field("", t -> {
searchString = t.length() > 0 ? t.toLowerCase() : null;
rebuildMaps();
}).maxTextLength(50).growX().get();
searchField.setMessageText("@editor.search");
search.button(Icon.filter, Styles.emptyi, this::showMapFilters);
cont.add(search).growX();
cont.row();
cont.add(pane).uniformX().growY();
cont.row();
cont.add(buttons).growX();
}
void rebuildMaps(){
mapTable.clear();
mapTable.marginRight(24);
int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1); int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1);
float mapsize = 200f; float mapsize = 200f;
boolean noMapsShown = true;
int i = 0; int i = 0;
for(Map map : Vars.maps.all()){
if(i % maxwidth == 0){ Seq<Map> mapList = showAll ? Vars.maps.all() : Vars.maps.customMaps();
maps.row(); for(Map map : mapList){
boolean invalid = false;
for(Gamemode mode : modes){
invalid |= !mode.valid(map);
}
if(invalid || (searchString != null && !Strings.stripColors(map.name()).toLowerCase().contains(searchString))){
continue;
} }
TextButton button = maps.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get(); noMapsShown = false;
if(i % maxwidth == 0){
mapTable.row();
}
TextButton button = mapTable.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get();
button.clearChildren(); button.clearChildren();
button.margin(9); button.margin(9);
button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true); button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true);
@@ -141,13 +184,41 @@ public class MapsDialog extends BaseDialog{
i++; i++;
} }
if(Vars.maps.all().size == 0){ if(noMapsShown){
maps.add("@maps.none"); mapTable.add("@maps.none");
} }
}
cont.add(buttons).growX(); void showMapFilters(){
cont.row(); dialog = new BaseDialog("@editor.filters");
cont.add(pane).uniformX(); dialog.addCloseButton();
dialog.setFillParent(false);
dialog.cont.table(Tex.button, t -> {
int i = 0;
for(Gamemode mode : Gamemode.all){
TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name()));
if(Core.atlas.isFound(icon.getRegion())){
t.button(mode.name(), icon, Styles.clearTogglet, () -> {
if(modes.contains(mode)){
modes.remove(mode);
}else{
modes.add(mode);
}
rebuildMaps();
}).size(150f, 60f).marginLeft(6f).checked(modes.contains(mode));
if(++i % 3 == 0) t.row();
}
}
t.row();
t.button("@editor.showAll", Styles.clearTogglet, () -> {
showAll = !showAll;
Core.settings.put("editorShowAllMaps", showAll);
Core.settings.forceSave();
rebuildMaps();
}).checked(b -> showAll).colspan(3).growX().height(40f);
});
dialog.show();
} }
void showMapInfo(Map map){ void showMapInfo(Map map){
@@ -213,4 +284,15 @@ public class MapsDialog extends BaseDialog{
dialog.show(); dialog.show();
} }
@Override
public Dialog show(){
super.show();
if(Core.app.isDesktop() && searchField != null){
Core.scene.setKeyboardFocus(searchField);
}
return this;
}
} }
@@ -381,7 +381,7 @@ public class ModsDialog extends BaseDialog{
}).tooltip(c.localizedName); }).tooltip(c.localizedName);
if(++i % Math.min(Core.graphics.getWidth() / Scl.scl(110), 14) == 0) cs.row(); if(++i % (int)Math.min(Core.graphics.getWidth() / Scl.scl(110), 14) == 0) cs.row();
} }
}).grow(); }).grow();
d.addCloseButton(); d.addCloseButton();
@@ -35,7 +35,7 @@ public class SchematicsDialog extends BaseDialog{
private String search = ""; private String search = "";
private TextField searchField; private TextField searchField;
private Runnable rebuildPane = () -> {}, rebuildTags = () -> {}; private Runnable rebuildPane = () -> {}, rebuildTags = () -> {};
private Pattern ignoreSymbols = Pattern.compile("[`~!@#$%^&*()-_=+{}|;:'\",<.>/?]"); private Pattern ignoreSymbols = Pattern.compile("[`~!@#$%^&*()\\-_=+{}|;:'\",<.>/?]");
private Seq<String> tags, selectedTags = new Seq<>(); private Seq<String> tags, selectedTags = new Seq<>();
private boolean checkedTags; private boolean checkedTags;
@@ -334,12 +334,6 @@ public class SchematicsDialog extends BaseDialog{
dialog.show(); dialog.show();
} }
public void focusSearchField(){
if(searchField == null) return;
Core.scene.setKeyboardFocus(searchField);
}
//adds all new tags to the global list of tags //adds all new tags to the global list of tags
//alternatively, unknown tags could be discarded on import? //alternatively, unknown tags could be discarded on import?
@@ -635,8 +629,8 @@ public class SchematicsDialog extends BaseDialog{
public Dialog show(){ public Dialog show(){
super.show(); super.show();
if(Core.app.isDesktop()){ if(Core.app.isDesktop() && searchField != null){
focusSearchField(); Core.scene.setKeyboardFocus(searchField);
} }
return this; return this;
@@ -17,7 +17,6 @@ import arc.util.*;
import arc.util.io.*; import arc.util.io.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.content.TechTree.*; import mindustry.content.TechTree.*;
import mindustry.core.GameState.*;
import mindustry.core.*; import mindustry.core.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
@@ -32,7 +31,7 @@ import java.util.zip.*;
import static arc.Core.*; import static arc.Core.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class SettingsMenuDialog extends Dialog{ public class SettingsMenuDialog extends BaseDialog{
public SettingsTable graphics; public SettingsTable graphics;
public SettingsTable game; public SettingsTable game;
public SettingsTable sound; public SettingsTable sound;
@@ -48,39 +47,20 @@ public class SettingsMenuDialog extends Dialog{
addCloseButton(); addCloseButton();
cont.add(main = new SettingsTable()); cont.add(main = new SettingsTable());
shouldPause = true;
hidden(() -> {
Sounds.back.play();
if(state.isGame()){
if(!wasPaused || net.active())
state.set(State.playing);
}
});
shown(() -> { shown(() -> {
back(); back();
if(state.isGame()){
wasPaused = state.is(State.paused);
state.set(State.paused);
}
rebuildMenu(); rebuildMenu();
}); });
Events.on(ResizeEvent.class, event -> { onResize(() -> {
if(isShown() && Core.scene.getDialog() == this){ graphics.rebuild();
graphics.rebuild(); sound.rebuild();
sound.rebuild(); game.rebuild();
game.rebuild(); updateScrollFocus();
updateScrollFocus();
}
}); });
setFillParent(true);
title.setAlignment(Align.center);
titleTable.row();
titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent);
cont.clearChildren(); cont.clearChildren();
cont.remove(); cont.remove();
buttons.remove(); buttons.remove();
@@ -177,9 +177,7 @@ public class HintsFragment extends Fragment{
&& state.rules.defaultTeam.core().items.has(Blocks.coreFoundation.requirements), && state.rules.defaultTeam.core().items.has(Blocks.coreFoundation.requirements),
() -> ui.hints.placedBlocks.contains(Blocks.coreFoundation)), () -> ui.hints.placedBlocks.contains(Blocks.coreFoundation)),
presetLaunch(() -> state.isCampaign() presetLaunch(() -> state.isCampaign()
&& state.getSector().preset == null && state.getSector().preset == null,
&& SectorPresets.frozenForest.unlocked()
&& SectorPresets.frozenForest.sector.save == null,
() -> state.isCampaign() && state.getSector().preset == SectorPresets.frozenForest), () -> state.isCampaign() && state.getSector().preset == SectorPresets.frozenForest),
presetDifficulty(() -> state.isCampaign() presetDifficulty(() -> state.isCampaign()
&& state.getSector().preset == null && state.getSector().preset == null
+8 -2
View File
@@ -205,10 +205,16 @@ public class Block extends UnlockableContent{
public int outlinedIcon = -1; public int outlinedIcon = -1;
/** Whether this block has a shadow under it. */ /** Whether this block has a shadow under it. */
public boolean hasShadow = true; public boolean hasShadow = true;
/** Sounds made when this block is destroyed.*/ /** Should the sound made when this block is built change in pitch. */
public Sound destroySound = Sounds.boom; public boolean placePitchChange = true;
/** Should the sound made when this block is deconstructed change in pitch. */
public boolean breakPitchChange = true;
/** Sound made when this block is built. */
public Sound placeSound = Sounds.place;
/** Sound made when this block is deconstructed. */ /** Sound made when this block is deconstructed. */
public Sound breakSound = Sounds.breaks; public Sound breakSound = Sounds.breaks;
/** Sounds made when this block is destroyed.*/
public Sound destroySound = Sounds.boom;
/** How reflective this block is. */ /** How reflective this block is. */
public float albedo = 0f; public float albedo = 0f;
/** Environmental passive light color. */ /** Environmental passive light color. */
+11
View File
@@ -62,6 +62,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return Point2.pack(x, y); return Point2.pack(x, y);
} }
/** @return this tile's position, packed to the world width - for use in width*height arrays. */
public int array(){
return x + y * world.tiles.width;
}
public byte relativeTo(Tile tile){ public byte relativeTo(Tile tile){
return relativeTo(tile.x, tile.y); return relativeTo(tile.x, tile.y);
} }
@@ -269,6 +274,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{
this.floor = type; this.floor = type;
this.overlay = (Floor)Blocks.air; this.overlay = (Floor)Blocks.air;
if(!headless && !world.isGenerating()){
renderer.blocks.removeFloorIndex(this);
}
recache(); recache();
if(build != null){ if(build != null){
build.onProximityUpdate(); build.onProximityUpdate();
@@ -305,6 +314,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{
if(!headless && !world.isGenerating()){ if(!headless && !world.isGenerating()){
renderer.blocks.floor.recacheTile(this); renderer.blocks.floor.recacheTile(this);
renderer.minimap.update(this); renderer.minimap.update(this);
renderer.blocks.invalidateTile(this);
renderer.blocks.addFloorIndex(this);
//update neighbor tiles as well //update neighbor tiles as well
for(int i = 0; i < 8; i++){ for(int i = 0; i < 8; i++){
Tile other = world.tile(x + Geometry.d8[i].x, y + Geometry.d8[i].y); Tile other = world.tile(x + Geometry.d8[i].x, y + Geometry.d8[i].y);
@@ -58,7 +58,7 @@ public class ConstructBlock extends Block{
block.breakEffect.at(tile.drawx(), tile.drawy(), block.size, block.mapColor); block.breakEffect.at(tile.drawx(), tile.drawy(), block.size, block.mapColor);
Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null)); Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null));
tile.remove(); tile.remove();
if(shouldPlay()) block.breakSound.at(tile, calcPitch(false)); if(shouldPlay()) block.breakSound.at(tile, block.breakPitchChange ? calcPitch(false) : 1f);
} }
@Remote(called = Loc.server) @Remote(called = Loc.server)
@@ -97,7 +97,7 @@ public class ConstructBlock extends Block{
} }
Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size); Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size);
if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); if(shouldPlay()) block.placeSound.at(tile, block.placePitchChange ? calcPitch(true) : 1f);
Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config));
} }
@@ -67,7 +67,7 @@ public class LaserTurret extends PowerTurret{
Liquid liquid = liquids.current(); Liquid liquid = liquids.current();
float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount; float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount;
float used = (cheating() ? maxUsed * Time.delta : Math.min(liquids.get(liquid), maxUsed * Time.delta)); float used = (cheating() ? maxUsed : Math.min(liquids.get(liquid), maxUsed)) * Time.delta;
reload -= used * liquid.heatCapacity * coolantMultiplier; reload -= used * liquid.heatCapacity * coolantMultiplier;
liquids.remove(liquid, used); liquids.remove(liquid, used);
@@ -127,24 +127,32 @@ public class GenericCrafter extends Block{
} }
if(progress >= 1f){ if(progress >= 1f){
consume(); craft();
if(outputItems != null){
for(ItemStack output : outputItems){
for(int i = 0; i < output.amount; i++){
offload(output.item);
}
}
}
if(outputLiquid != null){
handleLiquid(this, outputLiquid.liquid, outputLiquid.amount);
}
craftEffect.at(x, y);
progress %= 1f;
} }
dumpOutputs();
}
public void craft(){
consume();
if(outputItems != null){
for(ItemStack output : outputItems){
for(int i = 0; i < output.amount; i++){
offload(output.item);
}
}
}
if(outputLiquid != null){
handleLiquid(this, outputLiquid.liquid, outputLiquid.amount);
}
craftEffect.at(x, y);
progress %= 1f;
}
public void dumpOutputs(){
if(outputItems != null && timer(timerDump, dumpTime / timeScale)){ if(outputItems != null && timer(timerDump, dumpTime / timeScale)){
for(ItemStack output : outputItems){ for(ItemStack output : outputItems){
dump(output.item); dump(output.item);
+17 -4
View File
@@ -1,5 +1,18 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m --illegal-access=permit org.gradle.jvmargs=-Xms256m -Xmx1024m \
--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
--add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED
# Multithreaded # Multithreaded
kapt.use.worker.api=true kapt.use.worker.api=true
# Compilation avoidance (see https://kotlinlang.org/docs/kapt.html#compile-avoidance-for-kapt-since-1-3-20) # Compilation avoidance (see https://kotlinlang.org/docs/kapt.html#compile-avoidance-for-kapt-since-1-3-20)
@@ -9,6 +22,6 @@ kotlin.stdlib.default.dependency=false
#needed for android compilation #needed for android compilation
android.useAndroidX=true android.useAndroidX=true
#used for slow jitpack builds; TODO see if this actually works #used for slow jitpack builds; TODO see if this actually works
http.socketTimeout=80000 org.gradle.internal.http.socketTimeout=100000
http.connectionTimeout=80000 org.gradle.internal.http.connectionTimeout=100000
archash=b631e4ed8d93513a52ebee6f7e612f7d603062c8 archash=57b15a1b73cf0d6f19a50d2111f43d993e57c7f1
+5 -1
View File
@@ -21,7 +21,7 @@
}, },
{ {
"name": "DarkDustry", "name": "DarkDustry",
"address": ["darkdustry.ml", "darkdustry.ml:3000", "darkdustry.ml:7000", "darkdustry.ml:8000"] "address": ["darkdustry.ml", "darkdustry.ml:6000", "darkdustry.ml:7000", "darkdustry.ml:8000", "darkdustry.ml:9000"]
}, },
{ {
"name": "Chaotic Neutral", "name": "Chaotic Neutral",
@@ -46,5 +46,9 @@
{ {
"name": "SubZero", "name": "SubZero",
"address": ["minty-server.ddns.net"] "address": ["minty-server.ddns.net"]
},
{
"name": "Shiza Minigames",
"address": ["shizashizashiza.ml"]
} }
] ]
+2 -2
View File
@@ -17,7 +17,7 @@ def doAntialias = !project.hasProperty("disableAntialias")
def colorMap = new IntMap<List<Color>>(), colorIndexMap = new IntIntMap() def colorMap = new IntMap<List<Color>>(), colorIndexMap = new IntIntMap()
//on my machine, I have a native Nim AA implementation that is ~10x faster //on my machine, I have a native Nim AA implementation that is ~10x faster
//it's not compiled for other platforms so they don't get it //it's not compiled for other platforms so they don't get it
def useFastAA = System.getProperty("user.name") == "anuke" def useFastAA = project.hasProperty("fastAA") || System.getProperty("user.name") == "anuke"
def transformColors = { List<List<String>> list -> def transformColors = { List<List<String>> list ->
list.each{ colors -> list.each{ colors ->
@@ -282,4 +282,4 @@ task updateScripts(dependsOn: classes, type: JavaExec){
classpath = sourceSets.main.runtimeClasspath classpath = sourceSets.main.runtimeClasspath
standardInput = System.in standardInput = System.in
workingDir = "../" workingDir = "../"
} }